109 DrawText(TextFormat(
"%.0f degC", T_max), BAR_X + BAR_W + 4, BAR_Y, 16, WHITE);
112 DrawText(TextFormat(
"%.0f degC", T_min), BAR_X + BAR_W + 4, BAR_Y + BAR_H - 16, 16, WHITE);
118 InitWindow(SCR_W, SCR_H,
"SPH Fluid + Heat Transfer");
123 params.
rho0 = 1000.0f;
127 params.
mass = params.
rho0 * (0.8f * params.
h) * (0.8f * params.
h);
131 params.
xmin = 0.0f; params.
xmax = DOM_W;
132 params.
ymin = 0.0f; params.
ymax = DOM_H;
142 bool add_hot =
false;
144 while (!WindowShouldClose()) {
145 if (IsKeyPressed(KEY_SPACE)) paused = !paused;
146 if (IsKeyPressed(KEY_R)) setup(solver);
147 if (IsKeyPressed(KEY_EQUAL) || IsKeyPressed(KEY_KP_ADD))
148 substeps = std::min(substeps + 1, 20);
149 if (IsKeyPressed(KEY_MINUS) || IsKeyPressed(KEY_KP_SUBTRACT))
150 substeps = std::max(substeps - 1, 1);
151 if (IsKeyPressed(KEY_G)) {
157 if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) {
158 add_hot = IsMouseButtonDown(MOUSE_BUTTON_RIGHT);
159 Vector2 mp = GetMousePosition();
162 const float T = add_hot ? 85.0f : 15.0f;
164 for (
int k = 0; k < 4; ++k) {
165 float ox = 0.01f * ((k % 3) - 1);
166 float oy = 0.01f * ((k / 3) - 0);
167 float nx = sx + ox, ny = sy + oy;
168 if (nx > params.
xmin && nx < params.
xmax &&
169 ny > params.
ymin && ny < params.
ymax) {
176 for (
int s = 0; s < substeps; ++s) {
180 if (b.is_heat_source) { }
186 ClearBackground(Color{18, 18, 28, 255});
189 DrawRectangleLines(0, 0, SCR_W, SCR_H, Color{60, 60, 80, 255});
191 const float T_min = solver.
min_temp();
192 const float T_max = solver.
max_temp();
197 float r = body.radius * SCALE;
198 Color fc = temp_color(body.temperature, T_min, T_max);
200 DrawCircleV(pos, r, fc);
201 DrawCircleLines(
static_cast<int>(pos.x),
static_cast<int>(pos.y),
202 r, Color{220, 220, 220, 230});
205 const char* label = (body.temperature > 50.0f) ?
"HOT" :
"COLD";
207 static_cast<int>(pos.x) - 12,
208 static_cast<int>(pos.y) - 8, 14,
209 (body.temperature > 50.0f) ? RED : SKYBLUE);
216 Color c = temp_color(p.temperature, T_min, T_max);
217 DrawCircleV({px, py}, PRAD_PX, c);
222 DrawText(TextFormat(
"Particles: %d", (
int)solver.
particles().size()),
224 DrawText(TextFormat(
"Substeps/frame: %d (sim rate: %.2fx)",
225 substeps, substeps * params.
dt * 60.0f),
226 10, 60, 18, LIGHTGRAY);
227 DrawText(TextFormat(
"T range: %.1f degC - %.1f degC", T_min, T_max),
228 10, 84, 18, LIGHTGRAY);
231 DrawRectangle(0, SCR_H - 30, SCR_W, 30, Color{0,0,0,180});
232 DrawText(
"SPACE=pause R=reset G=drop bodies LMB=cold water RMB=hot water +/-=speed ESC=quit",
233 8, SCR_H - 22, 14, Color{180, 180, 180, 255});
237 DrawRectangle(0, 0, SCR_W, SCR_H, Color{0, 0, 0, 100});
238 DrawText(
"PAUSED", SCR_W / 2 - 60, SCR_H / 2 - 20, 40, YELLOW);
242 draw_legend(T_min, T_max);
Vector2 sim_to_screen(float sx, float sy)
void screen_to_sim(float px, float py, float &sx, float &sy)
A single SPH fluid particle (float precision for performance)
A rigid spherical body that interacts with fluid particles.