-
-
Save cosinekitty/e8f4f3cf34019bb873ad2d7f552d7fa6 to your computer and use it in GitHub Desktop.
| #include <cstdio> | |
| #include <cmath> | |
| #include <string> | |
| #include "raylib.h" | |
| #include "waterpool.hpp" | |
| const int WIDTH = 160; | |
| const int HEIGHT = 160; | |
| using PoolType = Sapphire::WaterPool<WIDTH, HEIGHT>; | |
| const int PIXELS_PER_CELL = 4; | |
| struct RenderContext | |
| { | |
| const int screenWidth = WIDTH * PIXELS_PER_CELL; | |
| const int screenHeight = HEIGHT * PIXELS_PER_CELL; | |
| float zoom = 8000.0f; // pixels per meter | |
| float xCenter = 0.05f; | |
| float yCenter = 0.00f; | |
| int xScreen(float x) const | |
| { | |
| return (screenWidth/2) + static_cast<int>(round(zoom * (x - xCenter))); | |
| } | |
| int yScreen(float y) const | |
| { | |
| return (screenHeight/2) - static_cast<int>(round(zoom * (y - yCenter))); | |
| } | |
| int scale(float r) const | |
| { | |
| return static_cast<int>(round(zoom * r)); | |
| } | |
| static Color cellColor(const Sapphire::WaterCell& cell) | |
| { | |
| using namespace Sapphire; | |
| if (cell.wet == 0.0f) | |
| return WHITE; | |
| float g = 128.0f * (cell.pos + 1.0f); | |
| if (g > 255.0f) | |
| g = 255.0f; | |
| else if (g < 0.0f) | |
| g = 0.0f; | |
| return CLITERAL(Color){0, static_cast<unsigned char>(g), 32, 255}; | |
| } | |
| void draw(const PoolType& pool) | |
| { | |
| using namespace Sapphire; | |
| for (int i = 0; i < WIDTH; ++i) | |
| { | |
| for (int j = 0; j < HEIGHT; ++j) | |
| { | |
| const WaterCell& cell = pool.getCell(i, j); | |
| Color color = cellColor(cell); | |
| DrawRectangle(i*PIXELS_PER_CELL, j*PIXELS_PER_CELL, PIXELS_PER_CELL, PIXELS_PER_CELL, color); | |
| } | |
| } | |
| } | |
| }; | |
| int main(int argc, const char *argv[]) | |
| { | |
| using namespace Sapphire; | |
| float dt = 1.0f / 48000.0f; | |
| float halflife = 0.07f; | |
| float c = 2.0f; // speed of waves in meters/second | |
| float s = 0.001f; // grid spacing in meters | |
| float k = (c*c) / (s*s); // propagation constant [second^(-2)] | |
| PoolType pool; | |
| RenderContext render; | |
| for (int i = 0; i < 3; ++i) | |
| { | |
| for (int j = 0; j < 3; ++j) | |
| { | |
| int r = 1 + i*i + j*j; | |
| pool.getCell(i + WIDTH/5, j + HEIGHT/2).vel = +20000.0f / r; | |
| } | |
| } | |
| // Create reflective barriers. | |
| for (int i = 30; i+10 < WIDTH; ++i) | |
| { | |
| pool.getCell(i, HEIGHT/2-7).wet = 0.0f; | |
| pool.getCell(i-13, HEIGHT/2+17).wet = 0.0f; | |
| } | |
| InitWindow(render.screenWidth, render.screenHeight, "Water Simulation by Don Cross"); | |
| SetTargetFPS(240); | |
| while (!WindowShouldClose()) | |
| { | |
| BeginDrawing(); | |
| ClearBackground(BLACK); | |
| render.draw(pool); | |
| EndDrawing(); | |
| pool.update(dt, halflife, k); | |
| } | |
| CloseWindow(); | |
| return 0; | |
| } |
| /* | |
| waterpool.hpp - Don Cross - 2023-06-26 | |
| Simulation of waves moving on the surface of water. | |
| Based on ideas from the video | |
| "How to write a Height-Field Water Simulator with 100 lines of code" | |
| by Matthias Müller / Ten Minute Physics: | |
| https://www.youtube.com/watch?v=hswBi5wcqAA | |
| */ | |
| #ifndef __COSINEKITTY_WATERPOOL_HPP | |
| #define __COSINEKITTY_WATERPOOL_HPP | |
| #include <vector> | |
| #include <cmath> | |
| namespace Sapphire | |
| { | |
| struct WaterCell | |
| { | |
| float wet {1.0f}; | |
| float pos {0.0f}; | |
| float vel {0.0f}; | |
| float acc {0.0f}; | |
| }; | |
| template <int WIDTH, int HEIGHT> | |
| class WaterPool | |
| { | |
| private: | |
| static_assert(WIDTH > 0, "Width must be a positive integer."); | |
| static_assert(HEIGHT > 0, "Height must be a positive integer."); | |
| static const int SIZE = WIDTH * HEIGHT; | |
| std::vector<WaterCell> cell { SIZE }; | |
| static constexpr int index(int i, int j) | |
| { | |
| // Use border-wraparound logic. | |
| // Tolerate -1, but not arbitrarily negative integers. | |
| return ((i + WIDTH)%WIDTH) + WIDTH*((j + HEIGHT)%HEIGHT); | |
| } | |
| float acceleration(const WaterCell& h, int i, int j) const | |
| { | |
| const WaterCell& o = cell[index(i, j)]; | |
| return o.wet*(o.pos - h.pos); | |
| } | |
| public: | |
| const WaterCell& getCell(int i, int j) const | |
| { | |
| return cell.at(index(i, j)); | |
| } | |
| WaterCell& getCell(int i, int j) | |
| { | |
| return cell.at(index(i, j)); | |
| } | |
| void update(float dt, float halflife, float k) | |
| { | |
| const float damp = pow(0.5, dt/halflife); | |
| // Calculate acceleration of each water cell. | |
| for (int i = 0; i < WIDTH; ++i) | |
| { | |
| for (int j = 0; j < HEIGHT; ++j) | |
| { | |
| WaterCell& h = cell[index(i, j)]; | |
| if (h.wet > 0.0f) | |
| { | |
| h.acc = k * ( | |
| acceleration(h, i, j+1) + | |
| acceleration(h, i, j-1) + | |
| acceleration(h, i-1, j) + | |
| acceleration(h, i+1, j) | |
| ); | |
| } | |
| } | |
| } | |
| // Use accelerations to update position and velocity of each water cell. | |
| for (int i = 0; i < WIDTH; ++i) | |
| { | |
| for (int j = 0; j < HEIGHT; ++j) | |
| { | |
| WaterCell& h = cell[index(i, j)]; | |
| if (h.wet > 0.0f) | |
| { | |
| h.vel = (damp * h.vel) + (dt * h.acc); | |
| h.pos += (dt * h.vel); | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| } | |
| #endif // __COSINEKITTY_WATERPOOL_HPP |
Great work, this follows the video right?
Yes, this is the exact code that was used to create the video at https://www.youtube.com/watch?v=9YV2043cfO0
Where can I find "raylib.h" and "waterpool.hpp"? Sorry for my ignorance if I am missing something trivial.
Where can I find "raylib.h" and "waterpool.hpp"? Sorry for my ignorance if I am missing something trivial.
Hi @satyam-bhardwaj, the file waterpool.hpp is inside this gist. You just need to scroll down below animate.cpp. The file raylib.h is available separately in the raylib project. I hope this helps.
Where can I find "raylib.h" and "waterpool.hpp"? Sorry for my ignorance if I am missing something trivial.
Hi @satyam-bhardwaj, the file waterpool.hpp is inside this gist. You just need to scroll down below animate.cpp. The file raylib.h is available separately in the raylib project. I hope this helps.
Thank you for your kind and quick reply!
How do I compile this?
How do I compile this?
Here is the bash script I used to build and run the program on Linux, using gcc 12.2.0:
#!/bin/bash
g++ -Wall -Werror -O3 -o animate animate.cpp -l raylib -l pthread -l dl || exit 1
./animate $1 || exit 1
exit 0How do I compile this?
Here is the bash script I used to build and run the program on Linux, using gcc 12.2.0:
#!/bin/bash g++ -Wall -Werror -O3 -o animate animate.cpp -l raylib -l pthread -l dl || exit 1 ./animate $1 || exit 1 exit 0
Oh , thanks a lot
Works 👍
Thanks for making the video , learnt good things ❤️
Excited for more
Great work, this follows the video right?