Browse Source

Refactor to billboard rendering

- Replace wireframe spheres with proper billboard textures
- Spacecraft rendered as cyan circle with arrow (64x64 texture)
- Maneuver markers as directional arrow billboards
- Spacecraft billboards rotate to show velocity direction
- Programmatic texture generation (no external assets)
- Lazy texture loading when spacecraft/maneuvers present
- Proper texture cleanup on renderer shutdown
main
cinnaboot 6 months ago
parent
commit
42f4b12cfc
  1. 2
      src/main.cpp
  2. 132
      src/renderer.cpp
  3. 16
      src/renderer.h

2
src/main.cpp

@ -96,7 +96,7 @@ void run_gui_simulation(SimulationState* sim) {
render_simulation(sim, &render_state);
}
close_renderer();
close_renderer(&render_state);
printf("\nSimulation ended. Final time: %.2f days\n", sim->time / 86400.0);
}

132
src/renderer.cpp

@ -17,10 +17,71 @@ void init_renderer(int width, int height, const char* title) {
}
// Close raylib
void close_renderer() {
void close_renderer(RenderState* render_state) {
if (render_state->texture_loaded) {
UnloadTexture(render_state->spacecraft_texture);
for (int i = 0; i < 6; i++) {
UnloadTexture(render_state->maneuver_textures[i]);
}
render_state->texture_loaded = false;
}
CloseWindow();
}
Texture2D generate_spacecraft_texture() {
Image img = GenImageColor(64, 64, BLANK);
ImageDrawCircle(&img, 32, 32, 28, (Color){0, 255, 255, 255});
ImageDrawLine(&img, 32, 10, 32, 50, (Color){0, 0, 0, 255});
ImageDrawLine(&img, 32, 10, 25, 17, (Color){0, 0, 0, 255});
ImageDrawLine(&img, 32, 10, 39, 17, (Color){0, 0, 0, 255});
Texture2D tex = LoadTextureFromImage(img);
UnloadImage(img);
return tex;
}
Texture2D generate_maneuver_marker_texture(Color color) {
Image img = GenImageColor(32, 32, BLANK);
ImageDrawTriangle(&img,
(Vector2){16, 4},
(Vector2){4, 28},
(Vector2){28, 28},
color);
Texture2D tex = LoadTextureFromImage(img);
UnloadImage(img);
return tex;
}
void ensure_textures_loaded(RenderState* render_state) {
if (render_state->texture_loaded) return;
render_state->spacecraft_texture = generate_spacecraft_texture();
render_state->maneuver_textures[0] = generate_maneuver_marker_texture((Color){0, 255, 0, 200});
render_state->maneuver_textures[1] = generate_maneuver_marker_texture((Color){255, 0, 0, 200});
render_state->maneuver_textures[2] = generate_maneuver_marker_texture((Color){255, 255, 0, 200});
render_state->maneuver_textures[3] = generate_maneuver_marker_texture((Color){255, 165, 0, 200});
render_state->maneuver_textures[4] = generate_maneuver_marker_texture((Color){255, 0, 255, 200});
render_state->maneuver_textures[5] = generate_maneuver_marker_texture((Color){0, 255, 255, 200});
render_state->texture_loaded = true;
}
float calculate_spacecraft_angle(Vec3 velocity, Camera3D camera) {
if (vec3_magnitude(velocity) < 0.01) return 0.0f;
Vector3 render_vel = sim_to_render(velocity, 1.0);
Vector2 vel_2d = (Vector2){render_vel.x, render_vel.z};
Vector2 cam_2d = (Vector2){camera.position.x, camera.position.z};
return Vector2Angle(vel_2d, cam_2d);
}
// Setup the 3D camera
void setup_camera(RenderState* render_state) {
render_state->camera.position = (Vector3){ 0.0f, 50.0f, 100.0f };
@ -29,9 +90,14 @@ void setup_camera(RenderState* render_state) {
render_state->camera.fovy = 45.0f;
render_state->camera.projection = CAMERA_PERSPECTIVE;
// Set scaling factors (same scale for distances and sizes)
render_state->distance_scale = 1e-9; // Meters to scaled units (1 unit = 1 billion meters)
render_state->size_scale = 1e-9; // Same scale for body sizes (minimum size still applies)
render_state->distance_scale = 1e-9;
render_state->size_scale = 1e-9;
render_state->texture_loaded = false;
render_state->spacecraft_texture = (Texture2D){0, 0, 0, 0, 0};
for (int i = 0; i < 6; i++) {
render_state->maneuver_textures[i] = (Texture2D){0, 0, 0, 0, 0};
}
}
// Update camera with keyboard/mouse controls
@ -206,57 +272,67 @@ void render_body(CelestialBody* body, RenderState* render_state) {
DrawSphereWires(position, radius, 16, 16, color);
}
// Render a single spacecraft as a simple geometric marker
void render_spacecraft(Spacecraft* craft, RenderState* render_state) {
Vector3 position = sim_to_render(craft->position, render_state->distance_scale);
ensure_textures_loaded(render_state);
// Fixed size for visibility at solar system distances
float marker_radius = 5.0f;
Color spacecraft_color = { 0, 255, 255, 255 }; // Cyan
DrawSphereWires(position, marker_radius, 8, 8, spacecraft_color);
Vector3 position = sim_to_render(craft->position, render_state->distance_scale);
float billboard_size = 20.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);
}
// Render a maneuver marker for a spacecraft
void render_maneuver_marker(Spacecraft* craft, Maneuver* maneuver, RenderState* render_state) {
if (maneuver->executed) {
return; // Don't show markers for executed maneuvers
return;
}
Vector3 position = sim_to_render(craft->position, render_state->distance_scale);
ensure_textures_loaded(render_state);
// Size based on delta-v magnitude
float marker_size = (float)(maneuver->delta_v / 100.0f); // Scale by delta-v
if (marker_size < 2.0f) marker_size = 2.0f;
if (marker_size > 10.0f) marker_size = 10.0f;
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;
// Color based on direction
Color marker_color;
int texture_index;
switch (maneuver->direction) {
case BURN_PROGRADE:
marker_color = (Color){ 0, 255, 0, 200 }; // Green
texture_index = 0;
break;
case BURN_RETROGRADE:
marker_color = (Color){ 255, 0, 0, 200 }; // Red
texture_index = 1;
break;
case BURN_NORMAL:
marker_color = (Color){ 255, 255, 0, 200 }; // Yellow
texture_index = 2;
break;
case BURN_ANTINORMAL:
marker_color = (Color){ 255, 165, 0, 200 }; // Orange
texture_index = 3;
break;
case BURN_RADIAL_IN:
marker_color = (Color){ 255, 0, 255, 200 }; // Magenta
texture_index = 4;
break;
case BURN_RADIAL_OUT:
marker_color = (Color){ 0, 255, 255, 200 }; // Cyan
texture_index = 5;
break;
default:
marker_color = (Color){ 255, 255, 255, 200 }; // White
texture_index = 0;
break;
}
DrawCube(position, marker_size, marker_size, marker_size, marker_color);
DrawBillboard(render_state->camera,
render_state->maneuver_textures[texture_index],
position,
marker_size,
WHITE);
}
struct OrbitalBasis {

16
src/renderer.h

@ -19,11 +19,25 @@ struct RenderState {
bool camera_follow_body; // Whether camera follows selected body
Vector3 camera_offset; // Offset from target when following body
bool was_following_body; // Previous frame follow state
Texture2D spacecraft_texture; // Shared texture for all spacecraft
Texture2D maneuver_textures[6]; // One per burn direction
bool texture_loaded;
};
// Renderer initialization and cleanup
void init_renderer(int width, int height, const char* title);
void close_renderer();
void close_renderer(RenderState* render_state);
// Texture generation
Texture2D generate_spacecraft_texture();
Texture2D generate_maneuver_marker_texture(Color color);
// Texture management
void ensure_textures_loaded(RenderState* render_state);
// Angle calculation
float calculate_spacecraft_angle(Vec3 velocity, Camera3D camera);
// Camera setup and control
void setup_camera(RenderState* render_state);

Loading…
Cancel
Save