From 38f0e0bad726c1a2b5185a7b753163d86db1025d Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Fri, 23 Jan 2026 16:01:41 -0500 Subject: [PATCH] Convert spacecraft and maneuver markers to screen-space rendering Replace 3D billboard rendering with 2D screen-space overlays using GetWorldToScreen() and DrawTexturePro() for constant visibility. Changes: - Rename render functions to *_screen_space suffix - Use GetWorldToScreen() to transform 3D positions to screen coordinates - Replace DrawBillboard/DrawBillboardPro() with DrawTexturePro() for 2D rendering - Use constant pixel sizes (40px spacecraft, 20-60px markers) - Add off-screen culling to skip rendering outside viewport - Update render order: 3D scene first, then 2D overlays - Update documentation to reflect screen-space approach Benefits: - Markers remain visible at all zoom levels (constant screen size) - Simplified sizing with pixel values instead of world-space math - Better performance with off-screen culling - Clearer separation: 3D scene vs UI indicators --- docs/rendering.md | 22 +++++++------ src/renderer.cpp | 84 +++++++++++++++++++++++++++++++---------------- src/renderer.h | 4 +-- 3 files changed, 70 insertions(+), 40 deletions(-) diff --git a/docs/rendering.md b/docs/rendering.md index b3bf9c3..11e6ca4 100644 --- a/docs/rendering.md +++ b/docs/rendering.md @@ -103,18 +103,20 @@ float scale_radius(double radius, double scale) { ### Spacecraft **Rendering:** -- Fixed-size wireframe spheres (5.0 units) +- Screen-space 2D overlay using `DrawTexturePro()` +- Constant screen size: 40 pixels (independent of camera zoom) - Cyan color (0, 255, 255) -- Position scaled and transformed +- Rotated to face velocity direction +- Off-screen culling (skips rendering if outside viewport) -**Purpose:** Visual marker for spacecraft tracking at solar system distances +**Purpose:** UI indicator for spacecraft that remains visible at all zoom levels ### Maneuver Markers **Rendering:** -- Cubes (`DrawCube`) colored by burn direction -- Size based on delta-v magnitude (2-10 units, clamped) +- Screen-space 2D overlay using `DrawTexturePro()` +- Size based on delta-v magnitude (20-60 pixels, clamped) - Only shown for unexecuted maneuvers -- Positioned at spacecraft location +- Off-screen culling (skips rendering if outside viewport) **Color Coding:** - PROGRADE: Green (0, 255, 0) @@ -125,7 +127,7 @@ float scale_radius(double radius, double scale) { - RADIAL_OUT: Cyan (0, 255, 255) - CUSTOM: White (255, 255, 255) -**Render Order:** Top layer, after spacecraft +**Render Order:** Top layer, after spacecraft (rendered as 2D overlays after 3D scene) ## Orbit Rendering @@ -270,9 +272,9 @@ float scale_radius(double radius, double scale) { #### Rendering - `render_body(body, render_state)` - Draw single celestial body -- `render_spacecraft(craft, render_state)` - Draw spacecraft marker -- `render_maneuver_marker(craft, maneuver, render_state)` - Draw burn indicator -- `render_simulation(sim, render_state)` - Full scene rendering (3D only) +- `render_spacecraft_screen_space(craft, render_state)` - Draw spacecraft marker as 2D overlay +- `render_maneuver_marker_screen_space(craft, maneuver, render_state)` - Draw burn indicator as 2D overlay +- `render_simulation(sim, render_state)` - Full scene rendering (3D + 2D overlays) #### Scaling - `scale_position(pos, scale)` - Transform simulation to render position diff --git a/src/renderer.cpp b/src/renderer.cpp index ada2c2e..892c9d9 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -268,36 +268,58 @@ void render_body(CelestialBody* body, RenderState* render_state) { DrawSphereWires(position, radius, 16, 16, color); } -void render_spacecraft(Spacecraft* craft, RenderState* render_state) { +void render_spacecraft_screen_space(Spacecraft* craft, RenderState* render_state) { + Vector3 render_pos = sim_to_render(craft->position, render_state->distance_scale); + Vector2 screen_pos = GetWorldToScreen(render_pos, render_state->camera); + + int screen_width = GetScreenWidth(); + int screen_height = GetScreenHeight(); + + if (screen_pos.x < -50 || screen_pos.x > screen_width + 50 || + screen_pos.y < -50 || screen_pos.y > screen_height + 50) { + return; + } + ensure_textures_loaded(render_state); - Vector3 position = sim_to_render(craft->position, render_state->distance_scale); - float billboard_size = 20.0f; + float screen_size = 40.0f; Color spacecraft_color = { 0, 255, 255, 255 }; float angle = calculate_spacecraft_angle(craft->local_velocity, render_state->camera); - DrawBillboardPro(render_state->camera, - render_state->spacecraft_texture, - (Rectangle){0, 0, 64, 64}, - position, - (Vector3){0, 1, 0}, - (Vector2){billboard_size, billboard_size}, - (Vector2){billboard_size/2, billboard_size/2}, - angle, - spacecraft_color); + Rectangle source = {0, 0, 64, 64}; + Rectangle dest = { + screen_pos.x - screen_size/2, + screen_pos.y - screen_size/2, + screen_size, + screen_size + }; + Vector2 origin = {screen_size/2, screen_size/2}; + + DrawTexturePro(render_state->spacecraft_texture, + source, dest, origin, angle, spacecraft_color); } -void render_maneuver_marker(Spacecraft* craft, Maneuver* maneuver, RenderState* render_state) { +void render_maneuver_marker_screen_space(Spacecraft* craft, Maneuver* maneuver, RenderState* render_state) { if (maneuver->executed) { return; } + Vector3 render_pos = sim_to_render(craft->position, render_state->distance_scale); + Vector2 screen_pos = GetWorldToScreen(render_pos, render_state->camera); + + int screen_width = GetScreenWidth(); + int screen_height = GetScreenHeight(); + + if (screen_pos.x < -50 || screen_pos.x > screen_width + 50 || + screen_pos.y < -50 || screen_pos.y > screen_height + 50) { + return; + } + ensure_textures_loaded(render_state); - Vector3 position = sim_to_render(craft->position, render_state->distance_scale); - float marker_size = (float)(maneuver->delta_v / 100.0f); - if (marker_size < 4.0f) marker_size = 4.0f; - if (marker_size > 12.0f) marker_size = 12.0f; + float screen_size = (float)(maneuver->delta_v / 50.0f); + if (screen_size < 20.0f) screen_size = 20.0f; + if (screen_size > 60.0f) screen_size = 60.0f; int texture_index; switch (maneuver->direction) { @@ -324,11 +346,17 @@ void render_maneuver_marker(Spacecraft* craft, Maneuver* maneuver, RenderState* break; } - DrawBillboard(render_state->camera, - render_state->maneuver_textures[texture_index], - position, - marker_size, - WHITE); + Rectangle source = {0, 0, 32, 32}; + Rectangle dest = { + screen_pos.x - screen_size/2, + screen_pos.y - screen_size/2, + screen_size, + screen_size + }; + Vector2 origin = {screen_size/2, screen_size/2}; + + DrawTexturePro(render_state->maneuver_textures[texture_index], + source, dest, origin, 0, WHITE); } struct OrbitalBasis { @@ -533,21 +561,21 @@ void render_simulation(SimulationState* sim, RenderState* render_state) { render_body(&sim->bodies[i], render_state); } - // Render all spacecraft (after bodies for visibility) + EndMode3D(); + + // Render spacecraft as screen-space overlays for (int i = 0; i < sim->craft_count; i++) { - render_spacecraft(&sim->spacecraft[i], render_state); + render_spacecraft_screen_space(&sim->spacecraft[i], render_state); } - // Render maneuver markers (top layer) + // Render maneuver markers as screen-space overlays for (int i = 0; i < sim->maneuver_count; i++) { Maneuver* maneuver = &sim->maneuvers[i]; if (!maneuver->executed && maneuver->craft_index >= 0 && maneuver->craft_index < sim->craft_count) { Spacecraft* craft = &sim->spacecraft[maneuver->craft_index]; - render_maneuver_marker(craft, maneuver, render_state); + render_maneuver_marker_screen_space(craft, maneuver, render_state); } } - EndMode3D(); - EndDrawing(); } diff --git a/src/renderer.h b/src/renderer.h index 9e3bc0c..8b48543 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -43,8 +43,8 @@ void update_camera(RenderState* render_state, SimulationState* sim); // Rendering functions void render_body(CelestialBody* body, RenderState* render_state); -void render_spacecraft(Spacecraft* craft, RenderState* render_state); -void render_maneuver_marker(Spacecraft* craft, Maneuver* maneuver, RenderState* render_state); +void render_spacecraft_screen_space(Spacecraft* craft, RenderState* render_state); +void render_maneuver_marker_screen_space(Spacecraft* craft, Maneuver* maneuver, RenderState* render_state); void render_simulation(SimulationState* sim, RenderState* render_state); // Scaling functions