diff --git a/src/main.cpp b/src/main.cpp index 313d242..576edd8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,6 +45,8 @@ void run_gui_simulation(SimulationState* sim) { ui_state.maneuver_list_scroll = 0; ui_state.selected_maneuver_index = -1; + ui_state_init_buffers(&ui_state); + ui_state.maneuver_dialog.open = false; ui_state.maneuver_dialog.active_tab = MD_TAB_CREATE; ui_state.maneuver_dialog.craft_index = -1; @@ -175,6 +177,7 @@ void run_gui_simulation(SimulationState* sim) { } close_renderer(&render_state); + ui_state_free_buffers(&ui_state); printf("\nSimulation ended. Final time: %.2f days\n", sim->time / 86400.0); } diff --git a/src/maneuver.cpp b/src/maneuver.cpp index f2aafa1..da8f08c 100644 --- a/src/maneuver.cpp +++ b/src/maneuver.cpp @@ -252,6 +252,7 @@ int add_maneuver_to_simulation(SimulationState* sim, Maneuver* maneuver) { sim->maneuvers[new_idx].executed = false; sim->maneuvers[new_idx].executed_time = 0.0; sim->maneuver_count++; + increment_sim_version(sim); return new_idx; } @@ -268,6 +269,7 @@ bool remove_maneuver_by_index(SimulationState* sim, int index) { } sim->maneuver_count--; + increment_sim_version(sim); return true; } diff --git a/src/simulation.cpp b/src/simulation.cpp index 32454bd..061d62b 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -64,6 +64,7 @@ int add_spacecraft(SimulationState* sim, Spacecraft* craft) { int new_idx = sim->craft_count; sim->spacecraft[new_idx] = *craft; sim->craft_count++; + increment_sim_version(sim); return new_idx; } @@ -98,6 +99,7 @@ int add_body_to_simulation(SimulationState* sim, CelestialBody* body) { sim->bodies[new_idx].global_position = body->global_position; sim->bodies[new_idx].global_velocity = body->global_velocity; + increment_sim_version(sim); return new_idx; } @@ -393,3 +395,7 @@ OrbitalAnalysis calculate_orbital_elements(CelestialBody* body, CelestialBody* p return elem; } + +void increment_sim_version(SimulationState* sim) { + sim->version++; +} diff --git a/src/simulation.h b/src/simulation.h index c8714b6..ca54591 100644 --- a/src/simulation.h +++ b/src/simulation.h @@ -46,11 +46,13 @@ struct SimulationState { double time; double dt; char config_name[256]; + int version; }; // Simulation management functions SimulationState* create_simulation(int max_bodies, int max_craft, int max_maneuvers, double time_step); void destroy_simulation(SimulationState* sim); +void increment_sim_version(SimulationState* sim); // Dynamic body management int add_body_to_simulation(SimulationState* sim, CelestialBody* body); diff --git a/src/ui_renderer.cpp b/src/ui_renderer.cpp index 95d1361..cd1249d 100644 --- a/src/ui_renderer.cpp +++ b/src/ui_renderer.cpp @@ -94,28 +94,43 @@ void render_body_list_ui(SimulationState* sim, RenderState* render_state, UIStat // Create list string for raygui (NULL-terminated) // Include both bodies and spacecraft int total_items = sim->body_count + sim->craft_count; - int buffer_size = total_items * (64 + 3 + 1) + 1; // Extra space for "🚀 " prefix - char* list_text = (char*)malloc(buffer_size); - if (!list_text) return; - - list_text[0] = '\0'; - int offset = 0; - int item_index = 0; - - // Add bodies to list - for (int i = 0; i < sim->body_count; i++) { - if (item_index > 0) { - offset += snprintf(list_text + offset, buffer_size - offset, ";"); + + // Check if buffer needs rebuilding + bool needs_rebuild = (ui_state->sim_version != sim->version) || (ui_state->body_list_buffer == NULL); + + if (needs_rebuild) { + int buffer_size = total_items * (64 + 3 + 1) + 1; + + if (ui_state->body_list_buffer == NULL || ui_state->body_list_buffer_size < buffer_size) { + if (ui_state->body_list_buffer != NULL) { + free(ui_state->body_list_buffer); + } + ui_state->body_list_buffer = (char*)malloc(buffer_size); + if (!ui_state->body_list_buffer) return; + ui_state->body_list_buffer_size = buffer_size; } - offset += snprintf(list_text + offset, buffer_size - offset, "%s", sim->bodies[i].name); - item_index++; - } - // Add spacecraft to list with "🚀 " prefix - for (int i = 0; i < sim->craft_count; i++) { - offset += snprintf(list_text + offset, buffer_size - offset, ";"); - offset += snprintf(list_text + offset, buffer_size - offset, "🚀 %s", sim->spacecraft[i].name); - item_index++; + ui_state->body_list_buffer[0] = '\0'; + int offset = 0; + int item_index = 0; + + // Add bodies to list + for (int i = 0; i < sim->body_count; i++) { + if (item_index > 0) { + offset += snprintf(ui_state->body_list_buffer + offset, ui_state->body_list_buffer_size - offset, ";"); + } + offset += snprintf(ui_state->body_list_buffer + offset, ui_state->body_list_buffer_size - offset, "%s", sim->bodies[i].name); + item_index++; + } + + // Add spacecraft to list with "🚀 " prefix + for (int i = 0; i < sim->craft_count; i++) { + offset += snprintf(ui_state->body_list_buffer + offset, ui_state->body_list_buffer_size - offset, ";"); + offset += snprintf(ui_state->body_list_buffer + offset, ui_state->body_list_buffer_size - offset, "🚀 %s", sim->spacecraft[i].name); + item_index++; + } + + ui_state->sim_version = sim->version; } // Draw window (no close button - panels always shown) @@ -130,7 +145,7 @@ void render_body_list_ui(SimulationState* sim, RenderState* render_state, UIStat }; int previous_active = ui_state->body_list_active; - GuiListView(list_bounds, list_text, &ui_state->body_list_scroll, &ui_state->body_list_active); + GuiListView(list_bounds, ui_state->body_list_buffer, &ui_state->body_list_scroll, &ui_state->body_list_active); // Check if an item was selected if (ui_state->body_list_active >= 0 && ui_state->body_list_active != previous_active) { @@ -150,8 +165,6 @@ void render_body_list_ui(SimulationState* sim, RenderState* render_state, UIStat } } } - - free(list_text); } // Render body information UI panel @@ -381,25 +394,45 @@ void render_maneuver_list_ui(SimulationState* sim, RenderState* render_state, UI return; } - int buffer_size = craft_maneuver_count * (64 + 10 + 1) + 1; - char* maneuver_list_text = (char*)malloc(buffer_size); - if (!maneuver_list_text) return; - - maneuver_list_text[0] = '\0'; - int offset = 0; int maneuver_indices[craft_maneuver_count]; int maneuver_index_count = 0; for (int i = 0; i < sim->maneuver_count; i++) { if (sim->maneuvers[i].craft_index == ui_state->selected_craft_index) { maneuver_indices[maneuver_index_count++] = i; - if (offset > 0) { - offset += snprintf(maneuver_list_text + offset, buffer_size - offset, ";"); + } + } + + // Check if buffer needs rebuilding + bool needs_rebuild = (ui_state->sim_version != sim->version) || (ui_state->maneuver_list_buffer == NULL); + + if (needs_rebuild) { + int buffer_size = craft_maneuver_count * (64 + 10 + 1) + 1; + + if (ui_state->maneuver_list_buffer == NULL || ui_state->maneuver_list_buffer_size < buffer_size) { + if (ui_state->maneuver_list_buffer != NULL) { + free(ui_state->maneuver_list_buffer); + } + ui_state->maneuver_list_buffer = (char*)malloc(buffer_size); + if (!ui_state->maneuver_list_buffer) return; + ui_state->maneuver_list_buffer_size = buffer_size; + } + + ui_state->maneuver_list_buffer[0] = '\0'; + int offset = 0; + + for (int i = 0; i < sim->maneuver_count; i++) { + if (sim->maneuvers[i].craft_index == ui_state->selected_craft_index) { + if (offset > 0) { + offset += snprintf(ui_state->maneuver_list_buffer + offset, ui_state->maneuver_list_buffer_size - offset, ";"); + } + const char* status_char = sim->maneuvers[i].executed ? "[DONE]" : "[PENDING]"; + offset += snprintf(ui_state->maneuver_list_buffer + offset, ui_state->maneuver_list_buffer_size - offset, "%s %s", + status_char, sim->maneuvers[i].name); } - const char* status_char = sim->maneuvers[i].executed ? "[DONE]" : "[PENDING]"; - offset += snprintf(maneuver_list_text + offset, buffer_size - offset, "%s %s", - status_char, sim->maneuvers[i].name); } + + ui_state->sim_version = sim->version; } Rectangle list_bounds = { @@ -410,7 +443,7 @@ void render_maneuver_list_ui(SimulationState* sim, RenderState* render_state, UI }; int previous_active = ui_state->maneuver_list_active; - GuiListView(list_bounds, maneuver_list_text, &ui_state->maneuver_list_scroll, &ui_state->maneuver_list_active); + GuiListView(list_bounds, ui_state->maneuver_list_buffer, &ui_state->maneuver_list_scroll, &ui_state->maneuver_list_active); if (ui_state->maneuver_list_active >= 0 && ui_state->maneuver_list_active != previous_active) { if (ui_state->maneuver_list_active >= 0 && ui_state->maneuver_list_active < maneuver_index_count) { @@ -527,8 +560,6 @@ void render_maneuver_list_ui(SimulationState* sim, RenderState* render_state, UI } } } - - free(maneuver_list_text); } void render_maneuver_create_tab(SimulationState* sim, UIState* ui_state, int x, int y, int width, int height) { @@ -713,6 +744,50 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x, } } + if (ui_state->sim_version != sim->version) { + int craft_buffer_size = sim->craft_count * 64 + 1; + + if (ui_state->craft_list_buffer == NULL || ui_state->craft_list_buffer_size < craft_buffer_size) { + if (ui_state->craft_list_buffer != NULL) { + free(ui_state->craft_list_buffer); + } + ui_state->craft_list_buffer = (char*)malloc(craft_buffer_size); + if (!ui_state->craft_list_buffer) return; + ui_state->craft_list_buffer_size = craft_buffer_size; + } + + ui_state->craft_list_buffer[0] = '\0'; + int offset = 0; + for (int i = 0; i < sim->craft_count; i++) { + if (i > 0) { + offset += snprintf(ui_state->craft_list_buffer + offset, ui_state->craft_list_buffer_size - offset, ";"); + } + offset += snprintf(ui_state->craft_list_buffer + offset, ui_state->craft_list_buffer_size - offset, "%s", sim->spacecraft[i].name); + } + + int body_buffer_size = sim->body_count * 64 + 1; + + if (ui_state->body_dropdown_buffer == NULL || ui_state->body_dropdown_buffer_size < body_buffer_size) { + if (ui_state->body_dropdown_buffer != NULL) { + free(ui_state->body_dropdown_buffer); + } + ui_state->body_dropdown_buffer = (char*)malloc(body_buffer_size); + if (!ui_state->body_dropdown_buffer) return; + ui_state->body_dropdown_buffer_size = body_buffer_size; + } + + ui_state->body_dropdown_buffer[0] = '\0'; + offset = 0; + for (int i = 0; i < sim->body_count; i++) { + if (i > 0) { + offset += snprintf(ui_state->body_dropdown_buffer + offset, ui_state->body_dropdown_buffer_size - offset, ";"); + } + offset += snprintf(ui_state->body_dropdown_buffer + offset, ui_state->body_dropdown_buffer_size - offset, "%s", sim->bodies[i].name); + } + + ui_state->sim_version = sim->version; + } + GuiLabel({(float)x, (float)current_y, (float)width, 25}, "Calculate optimal Hohmann transfer between orbits"); current_y += 30; @@ -721,25 +796,11 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x, if (sim->craft_count > 0) { static bool edit_mode_spacecraft = false; - int craft_buffer_size = sim->craft_count * 64 + 1; - char* craft_list = (char*)malloc(craft_buffer_size); - if (craft_list) { - craft_list[0] = '\0'; - int offset = 0; - for (int i = 0; i < sim->craft_count; i++) { - if (i > 0) { - offset += snprintf(craft_list + offset, craft_buffer_size - offset, ";"); - } - offset += snprintf(craft_list + offset, craft_buffer_size - offset, "%s", sim->spacecraft[i].name); - } - - if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, - craft_list, &ui_state->maneuver_dialog.craft_index, edit_mode_spacecraft)) { - edit_mode_spacecraft = !edit_mode_spacecraft; - } - free(craft_list); - if (edit_mode_spacecraft) return; + if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, + ui_state->craft_list_buffer, &ui_state->maneuver_dialog.craft_index, edit_mode_spacecraft)) { + edit_mode_spacecraft = !edit_mode_spacecraft; } + if (edit_mode_spacecraft) return; } current_y += 35; @@ -748,25 +809,11 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x, if (sim->body_count > 0) { static bool edit_mode_transfer_parent = false; - int body_buffer_size = sim->body_count * 64 + 1; - char* body_list = (char*)malloc(body_buffer_size); - if (body_list) { - body_list[0] = '\0'; - int offset = 0; - for (int i = 0; i < sim->body_count; i++) { - if (i > 0) { - offset += snprintf(body_list + offset, body_buffer_size - offset, ";"); - } - offset += snprintf(body_list + offset, body_buffer_size - offset, "%s", sim->bodies[i].name); - } - - if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, - body_list, &ui_state->maneuver_dialog.transfer_body_index, edit_mode_transfer_parent)) { - edit_mode_transfer_parent = !edit_mode_transfer_parent; - } - free(body_list); - if (edit_mode_transfer_parent) return; + if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, + ui_state->body_dropdown_buffer, &ui_state->maneuver_dialog.transfer_body_index, edit_mode_transfer_parent)) { + edit_mode_transfer_parent = !edit_mode_transfer_parent; } + if (edit_mode_transfer_parent) return; } current_y += 35; @@ -775,25 +822,11 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x, if (sim->body_count > 0) { static bool edit_mode_current_body = false; - int body_buffer_size = sim->body_count * 64 + 1; - char* body_list = (char*)malloc(body_buffer_size); - if (body_list) { - body_list[0] = '\0'; - int offset = 0; - for (int i = 0; i < sim->body_count; i++) { - if (i > 0) { - offset += snprintf(body_list + offset, body_buffer_size - offset, ";"); - } - offset += snprintf(body_list + offset, body_buffer_size - offset, "%s", sim->bodies[i].name); - } - - if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, - body_list, &ui_state->maneuver_dialog.current_body_index, edit_mode_current_body)) { - edit_mode_current_body = !edit_mode_current_body; - } - free(body_list); - if (edit_mode_current_body) return; + if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, + ui_state->body_dropdown_buffer, &ui_state->maneuver_dialog.current_body_index, edit_mode_current_body)) { + edit_mode_current_body = !edit_mode_current_body; } + if (edit_mode_current_body) return; } current_y += 35; @@ -802,25 +835,11 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x, if (sim->body_count > 0) { static bool edit_mode_target_body = false; - int body_buffer_size = sim->body_count * 64 + 1; - char* body_list = (char*)malloc(body_buffer_size); - if (body_list) { - body_list[0] = '\0'; - int offset = 0; - for (int i = 0; i < sim->body_count; i++) { - if (i > 0) { - offset += snprintf(body_list + offset, body_buffer_size - offset, ";"); - } - offset += snprintf(body_list + offset, body_buffer_size - offset, "%s", sim->bodies[i].name); - } - - if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, - body_list, &ui_state->maneuver_dialog.target_body_index, edit_mode_target_body)) { - edit_mode_target_body = !edit_mode_target_body; - } - free(body_list); - if (edit_mode_target_body) return; + if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, + ui_state->body_dropdown_buffer, &ui_state->maneuver_dialog.target_body_index, edit_mode_target_body)) { + edit_mode_target_body = !edit_mode_target_body; } + if (edit_mode_target_body) return; } current_y += 35; @@ -1409,3 +1428,41 @@ void delete_maneuver_from_dialog(SimulationState* sim, UIState* ui_state) { ui_state->maneuver_dialog.open = false; } } + +void ui_state_init_buffers(UIState* ui_state) { + ui_state->sim_version = 0; + ui_state->body_list_buffer_size = 0; + ui_state->body_list_buffer = NULL; + ui_state->craft_list_buffer_size = 0; + ui_state->craft_list_buffer = NULL; + ui_state->body_dropdown_buffer_size = 0; + ui_state->body_dropdown_buffer = NULL; + ui_state->maneuver_list_buffer_size = 0; + ui_state->maneuver_list_buffer = NULL; +} + +void ui_state_free_buffers(UIState* ui_state) { + if (ui_state->body_list_buffer != NULL) { + free(ui_state->body_list_buffer); + ui_state->body_list_buffer = NULL; + } + ui_state->body_list_buffer_size = 0; + + if (ui_state->craft_list_buffer != NULL) { + free(ui_state->craft_list_buffer); + ui_state->craft_list_buffer = NULL; + } + ui_state->craft_list_buffer_size = 0; + + if (ui_state->body_dropdown_buffer != NULL) { + free(ui_state->body_dropdown_buffer); + ui_state->body_dropdown_buffer = NULL; + } + ui_state->body_dropdown_buffer_size = 0; + + if (ui_state->maneuver_list_buffer != NULL) { + free(ui_state->maneuver_list_buffer); + ui_state->maneuver_list_buffer = NULL; + } + ui_state->maneuver_list_buffer_size = 0; +} diff --git a/src/ui_renderer.h b/src/ui_renderer.h index ea55a25..defb680 100644 --- a/src/ui_renderer.h +++ b/src/ui_renderer.h @@ -50,6 +50,16 @@ struct UIState { int maneuver_list_active; int maneuver_list_scroll; int selected_maneuver_index; + + int sim_version; + int body_list_buffer_size; + char* body_list_buffer; + int craft_list_buffer_size; + char* craft_list_buffer; + int body_dropdown_buffer_size; + char* body_dropdown_buffer; + int maneuver_list_buffer_size; + char* maneuver_list_buffer; }; void gui_init(); @@ -73,5 +83,7 @@ void calculate_hohmann_for_dialog(SimulationState* sim, UIState* ui_state); void create_hohmann_burns(SimulationState* sim, UIState* ui_state, bool create_both_burns); void load_maneuver_into_dialog(SimulationState* sim, UIState* ui_state, int maneuver_index); void delete_maneuver_from_dialog(SimulationState* sim, UIState* ui_state); +void ui_state_init_buffers(UIState* ui_state); +void ui_state_free_buffers(UIState* ui_state); #endif