132 InitWindow(1200, 800,
"SPH 3D -- Hose Demo");
146 float cam_yaw = kPI * 0.75f;
147 float cam_pitch = 0.45f;
148 const float CAM_DIST = 2.1f;
149 const float ROT_SPEED = 1.6f;
150 const Vector3 center = {0.4f, 0.4f, 0.4f};
153 Hose cold_hose, hot_hose;
154 cold_hose.
init({0.77f, 0.76f, 0.02f}, center, 5.0f, 1.8f, kPI / 36.0f);
156 hot_hose .
init({0.03f, 0.76f, 0.02f}, center, 80.0f, 1.8f, kPI / 36.0f);
160 camera.projection = CAMERA_PERSPECTIVE;
161 camera.target = center;
163 auto apply_camera = [&]() {
164 float cp = cosf(cam_pitch), sp = sinf(cam_pitch);
165 float cy = cosf(cam_yaw), sy = sinf(cam_yaw);
167 center.x + CAM_DIST * cp * sy,
168 center.y + CAM_DIST * sp,
169 center.z + CAM_DIST * cp * cy
172 camera.up = { -sy * sp, cp, -cy * sp };
175 auto apply_gravity = [&]() {
176 float cp = cosf(cam_pitch), sp = sinf(cam_pitch);
177 float cy = cosf(cam_yaw), sy = sinf(cam_yaw);
179 pm.
gx = kG * sy * sp;
181 pm.gz = kG * cy * sp;
190 while (!WindowShouldClose()) {
191 const float dt_frame = GetFrameTime();
194 if (IsKeyPressed(KEY_SPACE)) paused = !paused;
195 if (IsKeyPressed(KEY_R)) solver.
clear();
196 if (IsKeyPressed(KEY_H)) hot_hose.
active = !hot_hose.
active;
197 if (IsKeyPressed(KEY_C)) cold_hose.
active = !cold_hose.
active;
199 if (IsKeyPressed(KEY_EQUAL) || IsKeyPressed(KEY_KP_ADD))
200 substeps = std::min(substeps + 1, 20);
201 if (IsKeyPressed(KEY_MINUS) || IsKeyPressed(KEY_KP_SUBTRACT))
202 substeps = std::max(substeps - 1, 1);
205 bool rotated =
false;
206 if (IsKeyDown(KEY_LEFT)) { cam_yaw -= ROT_SPEED * dt_frame; rotated =
true; }
207 if (IsKeyDown(KEY_RIGHT)) { cam_yaw += ROT_SPEED * dt_frame; rotated =
true; }
208 if (IsKeyDown(KEY_UP)) { cam_pitch += ROT_SPEED * dt_frame; rotated =
true; }
209 if (IsKeyDown(KEY_DOWN)) { cam_pitch -= ROT_SPEED * dt_frame; rotated =
true; }
210 cam_pitch = (cam_pitch < -kPI * 0.44f) ? -kPI * 0.44f
211 : (cam_pitch > kPI * 0.44f) ? kPI * 0.44f : cam_pitch;
213 if (rotated) { apply_camera(); apply_gravity(); }
217 cold_hose.
emit(solver, 2);
218 hot_hose .
emit(solver, 2);
219 for (
int s = 0; s < substeps; ++s)
224 const float T_min = solver.
min_temp();
225 const float T_max = solver.
max_temp();
228 ClearBackground(Color{18, 18, 28, 255});
232 DrawCubeWires({0.4f, 0.4f, 0.4f}, 0.8f, 0.8f, 0.8f, Color{60, 60, 80, 200});
235 DrawSphere(cold_hose.
pos(), 0.022f, cold_hose.
active ? SKYBLUE : Color{40,40,100,180});
236 DrawSphere(hot_hose .pos(), 0.022f, hot_hose.
active ? ORANGE : Color{100,40,20,180});
240 Color c = temp_color(p.temperature, T_min, T_max);
241 DrawSphere({p.x, p.y, p.z}, 0.016f, c);
248 DrawText(TextFormat(
"Particles: %d / 1800", (
int)solver.
particles().size()),
250 DrawText(TextFormat(
"Substeps/frame: %d (%.2fx realtime)",
251 substeps, substeps * solver.
params().
dt * 60.0f),
252 10, 60, 18, LIGHTGRAY);
253 DrawText(TextFormat(
"T range: %.1f - %.1f degC", T_min, T_max),
254 10, 84, 18, LIGHTGRAY);
257 const auto& pm = solver.
params();
258 DrawText(TextFormat(
"g = (%.2f, %.2f, %.2f) m/s^2", pm.gx, pm.gy, pm.gz),
259 10, 108, 16, Color{160, 160, 160, 255});
262 DrawText(
"H = HOT hose:", 10, 136, 18, LIGHTGRAY);
263 DrawText(hot_hose.
active ?
"ON" :
"off",
264 170, 136, 18, hot_hose.
active ? ORANGE : GRAY);
265 DrawText(
"C = COLD hose:", 10, 158, 18, LIGHTGRAY);
266 DrawText(cold_hose.
active ?
"ON" :
"off",
267 170, 158, 18, cold_hose.
active ? SKYBLUE : GRAY);
270 DrawRectangle(0, 0, 1200, 800, Color{0, 0, 0, 100});
271 DrawText(
"PAUSED", 1200/2 - 60, 800/2 - 20, 40, YELLOW);
275 DrawRectangle(0, 770, 1200, 30, Color{0, 0, 0, 180});
276 DrawText(
"H=hot C=cold Arrows=rotate scene SPACE=pause R=reset +/-=speed ESC=quit",
277 8, 778, 14, Color{180, 180, 180, 255});