@ -3,6 +3,10 @@
# include <cmath>
# include <cmath>
# include <cstdio>
# include <cstdio>
// raygui implementation (header-only library)
# define RAYGUI_IMPLEMENTATION
# include "raygui.h"
// Initialize raylib window
// Initialize raylib window
void init_renderer ( int width , int height , const char * title ) {
void init_renderer ( int width , int height , const char * title ) {
InitWindow ( width , height , title ) ;
InitWindow ( width , height , title ) ;
@ -68,6 +72,11 @@ void update_camera(RenderState* render_state) {
if ( IsKeyPressed ( KEY_I ) ) {
if ( IsKeyPressed ( KEY_I ) ) {
render_state - > show_info = ! render_state - > show_info ;
render_state - > show_info = ! render_state - > show_info ;
}
}
// Toggle body list with B key
if ( IsKeyPressed ( KEY_B ) ) {
render_state - > show_body_list = ! render_state - > show_body_list ;
}
}
}
// Transform from simulation coordinates (XY plane) to render coordinates (XZ plane)
// Transform from simulation coordinates (XY plane) to render coordinates (XZ plane)
@ -316,6 +325,10 @@ void render_simulation(SimulationState* sim, RenderState* render_state) {
render_info ( sim , " solar_system.txt " ) ;
render_info ( sim , " solar_system.txt " ) ;
}
}
// Render UI panels
render_body_list_ui ( sim , render_state ) ;
render_body_info_ui ( sim , render_state ) ;
EndDrawing ( ) ;
EndDrawing ( ) ;
}
}
@ -350,3 +363,133 @@ void render_info(SimulationState* sim, const char* config_name) {
DrawText ( " I: Toggle info " , 10 , 210 , 14 , LIGHTGRAY ) ;
DrawText ( " I: Toggle info " , 10 , 210 , 14 , LIGHTGRAY ) ;
DrawText ( " ESC: Quit " , 10 , 230 , 14 , LIGHTGRAY ) ;
DrawText ( " ESC: Quit " , 10 , 230 , 14 , LIGHTGRAY ) ;
}
}
// Render body list UI panel
void render_body_list_ui ( SimulationState * sim , RenderState * render_state ) {
if ( ! render_state - > show_body_list ) return ;
// Panel dimensions
int panel_width = 200 ;
int panel_height = 400 ;
int panel_x = 10 ;
int panel_y = 10 ;
Rectangle panel_bounds = { ( float ) panel_x , ( float ) panel_y , ( float ) panel_width , ( float ) panel_height } ;
// Create body list for raygui
const char * * body_names = ( const char * * ) malloc ( sim - > body_count * sizeof ( char * ) ) ;
if ( ! body_names ) return ;
for ( int i = 0 ; i < sim - > body_count ; i + + ) {
body_names [ i ] = sim - > bodies [ i ] . name ;
}
// Draw window
if ( GuiWindowBox ( panel_bounds , " Bodies " ) ) {
render_state - > show_body_list = false ;
}
// Draw list view (inside window, leave space for title bar)
Rectangle list_bounds = {
( float ) panel_x + 4 ,
( float ) panel_y + 25 ,
( float ) panel_width - 8 ,
( float ) panel_height - 29
} ;
int focus = 0 ;
int active = 0 ;
if ( render_state - > selected_body_index > = 0 & & render_state - > selected_body_index < sim - > body_count ) {
focus = render_state - > selected_body_index ; // 0-based indexing for scroll
active = 1 ; // Mark as active
}
int result = GuiListView ( list_bounds , ( const char * ) body_names , & focus , & active ) ;
if ( result > = 0 & & result < sim - > body_count ) {
render_state - > selected_body_index = result ;
render_state - > show_body_info = true ;
}
free ( body_names ) ;
}
// Render body information UI panel
void render_body_info_ui ( SimulationState * sim , RenderState * render_state ) {
if ( ! render_state - > show_body_info | | render_state - > selected_body_index < 0 | |
render_state - > selected_body_index > = sim - > body_count ) return ;
// Panel dimensions
int panel_width = 250 ;
int panel_height = 300 ;
int panel_x = GetScreenWidth ( ) - panel_width - 10 ;
int panel_y = 10 ;
Rectangle panel_bounds = { ( float ) panel_x , ( float ) panel_y , ( float ) panel_width , ( float ) panel_height } ;
CelestialBody * body = & sim - > bodies [ render_state - > selected_body_index ] ;
// Draw window
if ( GuiWindowBox ( panel_bounds , body - > name ) ) {
render_state - > show_body_info = false ;
}
// Prepare info text
char info_text [ 1024 ] ;
char temp_buffer [ 256 ] ;
snprintf ( info_text , sizeof ( info_text ) , " Name: %s " , body - > name ) ;
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " Mass: %.2e kg " , body - > mass ) ;
strcat ( info_text , " \n " ) ;
strcat ( info_text , temp_buffer ) ;
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " Radius: %.2e m " , body - > radius ) ;
strcat ( info_text , " \n " ) ;
strcat ( info_text , temp_buffer ) ;
// Position
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " Position: (%.2e, %.2e, %.2e) " ,
body - > position . x , body - > position . y , body - > position . z ) ;
strcat ( info_text , " \n " ) ;
strcat ( info_text , temp_buffer ) ;
// Velocity
double vel_mag = vec3_magnitude ( body - > velocity ) ;
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " Velocity: %.2f m/s " , vel_mag ) ;
strcat ( info_text , " \n " ) ;
strcat ( info_text , temp_buffer ) ;
// Orbital elements
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " Eccentricity: %.3f " , body - > eccentricity ) ;
strcat ( info_text , " \n " ) ;
strcat ( info_text , temp_buffer ) ;
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " Semi-major axis: %.2e m " , body - > semi_major_axis ) ;
strcat ( info_text , " \n " ) ;
strcat ( info_text , temp_buffer ) ;
// Parent body
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " Parent: %s " , sim - > bodies [ body - > parent_index ] . name ) ;
} else {
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " Parent: None " ) ;
}
strcat ( info_text , " \n " ) ;
strcat ( info_text , temp_buffer ) ;
// SOI
snprintf ( temp_buffer , sizeof ( temp_buffer ) , " SOI radius: %.2e m " , body - > soi_radius ) ;
strcat ( info_text , " \n " ) ;
strcat ( info_text , temp_buffer ) ;
// Draw info text (inside window, leave space for title bar)
Rectangle text_bounds = {
( float ) panel_x + 8 ,
( float ) panel_y + 25 ,
( float ) panel_width - 16 ,
( float ) panel_height - 29
} ;
GuiLabel ( text_bounds , info_text ) ;
}