Browse Source

Implement UIState buffer caching to eliminate per-frame malloc/free calls

main
cinnaboot 5 months ago
parent
commit
b37497a504
  1. 3
      src/main.cpp
  2. 2
      src/maneuver.cpp
  3. 6
      src/simulation.cpp
  4. 2
      src/simulation.h
  5. 221
      src/ui_renderer.cpp
  6. 12
      src/ui_renderer.h

3
src/main.cpp

@ -45,6 +45,8 @@ void run_gui_simulation(SimulationState* sim) {
ui_state.maneuver_list_scroll = 0; ui_state.maneuver_list_scroll = 0;
ui_state.selected_maneuver_index = -1; ui_state.selected_maneuver_index = -1;
ui_state_init_buffers(&ui_state);
ui_state.maneuver_dialog.open = false; ui_state.maneuver_dialog.open = false;
ui_state.maneuver_dialog.active_tab = MD_TAB_CREATE; ui_state.maneuver_dialog.active_tab = MD_TAB_CREATE;
ui_state.maneuver_dialog.craft_index = -1; ui_state.maneuver_dialog.craft_index = -1;
@ -175,6 +177,7 @@ void run_gui_simulation(SimulationState* sim) {
} }
close_renderer(&render_state); close_renderer(&render_state);
ui_state_free_buffers(&ui_state);
printf("\nSimulation ended. Final time: %.2f days\n", sim->time / 86400.0); printf("\nSimulation ended. Final time: %.2f days\n", sim->time / 86400.0);
} }

2
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 = false;
sim->maneuvers[new_idx].executed_time = 0.0; sim->maneuvers[new_idx].executed_time = 0.0;
sim->maneuver_count++; sim->maneuver_count++;
increment_sim_version(sim);
return new_idx; return new_idx;
} }
@ -268,6 +269,7 @@ bool remove_maneuver_by_index(SimulationState* sim, int index) {
} }
sim->maneuver_count--; sim->maneuver_count--;
increment_sim_version(sim);
return true; return true;
} }

6
src/simulation.cpp

@ -64,6 +64,7 @@ int add_spacecraft(SimulationState* sim, Spacecraft* craft) {
int new_idx = sim->craft_count; int new_idx = sim->craft_count;
sim->spacecraft[new_idx] = *craft; sim->spacecraft[new_idx] = *craft;
sim->craft_count++; sim->craft_count++;
increment_sim_version(sim);
return new_idx; 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_position = body->global_position;
sim->bodies[new_idx].global_velocity = body->global_velocity; sim->bodies[new_idx].global_velocity = body->global_velocity;
increment_sim_version(sim);
return new_idx; return new_idx;
} }
@ -393,3 +395,7 @@ OrbitalAnalysis calculate_orbital_elements(CelestialBody* body, CelestialBody* p
return elem; return elem;
} }
void increment_sim_version(SimulationState* sim) {
sim->version++;
}

2
src/simulation.h

@ -46,11 +46,13 @@ struct SimulationState {
double time; double time;
double dt; double dt;
char config_name[256]; char config_name[256];
int version;
}; };
// Simulation management functions // Simulation management functions
SimulationState* create_simulation(int max_bodies, int max_craft, int max_maneuvers, double time_step); SimulationState* create_simulation(int max_bodies, int max_craft, int max_maneuvers, double time_step);
void destroy_simulation(SimulationState* sim); void destroy_simulation(SimulationState* sim);
void increment_sim_version(SimulationState* sim);
// Dynamic body management // Dynamic body management
int add_body_to_simulation(SimulationState* sim, CelestialBody* body); int add_body_to_simulation(SimulationState* sim, CelestialBody* body);

221
src/ui_renderer.cpp

@ -94,30 +94,45 @@ void render_body_list_ui(SimulationState* sim, RenderState* render_state, UIStat
// Create list string for raygui (NULL-terminated) // Create list string for raygui (NULL-terminated)
// Include both bodies and spacecraft // Include both bodies and spacecraft
int total_items = sim->body_count + sim->craft_count; 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'; // 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;
}
ui_state->body_list_buffer[0] = '\0';
int offset = 0; int offset = 0;
int item_index = 0; int item_index = 0;
// Add bodies to list // Add bodies to list
for (int i = 0; i < sim->body_count; i++) { for (int i = 0; i < sim->body_count; i++) {
if (item_index > 0) { if (item_index > 0) {
offset += snprintf(list_text + offset, buffer_size - offset, ";"); offset += snprintf(ui_state->body_list_buffer + offset, ui_state->body_list_buffer_size - offset, ";");
} }
offset += snprintf(list_text + offset, buffer_size - offset, "%s", sim->bodies[i].name); offset += snprintf(ui_state->body_list_buffer + offset, ui_state->body_list_buffer_size - offset, "%s", sim->bodies[i].name);
item_index++; item_index++;
} }
// Add spacecraft to list with "🚀 " prefix // Add spacecraft to list with "🚀 " prefix
for (int i = 0; i < sim->craft_count; i++) { for (int i = 0; i < sim->craft_count; i++) {
offset += snprintf(list_text + offset, buffer_size - offset, ";"); offset += snprintf(ui_state->body_list_buffer + offset, ui_state->body_list_buffer_size - offset, ";");
offset += snprintf(list_text + offset, buffer_size - offset, "🚀 %s", sim->spacecraft[i].name); offset += snprintf(ui_state->body_list_buffer + offset, ui_state->body_list_buffer_size - offset, "🚀 %s", sim->spacecraft[i].name);
item_index++; item_index++;
} }
ui_state->sim_version = sim->version;
}
// Draw window (no close button - panels always shown) // Draw window (no close button - panels always shown)
GuiWindowBox(panel_bounds, "Objects"); GuiWindowBox(panel_bounds, "Objects");
@ -130,7 +145,7 @@ void render_body_list_ui(SimulationState* sim, RenderState* render_state, UIStat
}; };
int previous_active = ui_state->body_list_active; 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 // Check if an item was selected
if (ui_state->body_list_active >= 0 && ui_state->body_list_active != previous_active) { 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 // Render body information UI panel
@ -381,27 +394,47 @@ void render_maneuver_list_ui(SimulationState* sim, RenderState* render_state, UI
return; 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_indices[craft_maneuver_count];
int maneuver_index_count = 0; int maneuver_index_count = 0;
for (int i = 0; i < sim->maneuver_count; i++) { for (int i = 0; i < sim->maneuver_count; i++) {
if (sim->maneuvers[i].craft_index == ui_state->selected_craft_index) { if (sim->maneuvers[i].craft_index == ui_state->selected_craft_index) {
maneuver_indices[maneuver_index_count++] = i; maneuver_indices[maneuver_index_count++] = i;
}
}
// 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) { if (offset > 0) {
offset += snprintf(maneuver_list_text + offset, buffer_size - offset, ";"); 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]"; const char* status_char = sim->maneuvers[i].executed ? "[DONE]" : "[PENDING]";
offset += snprintf(maneuver_list_text + offset, buffer_size - offset, "%s %s", offset += snprintf(ui_state->maneuver_list_buffer + offset, ui_state->maneuver_list_buffer_size - offset, "%s %s",
status_char, sim->maneuvers[i].name); status_char, sim->maneuvers[i].name);
} }
} }
ui_state->sim_version = sim->version;
}
Rectangle list_bounds = { Rectangle list_bounds = {
(float)panel_x + 4, (float)panel_x + 4,
(float)panel_y + 25, (float)panel_y + 25,
@ -410,7 +443,7 @@ void render_maneuver_list_ui(SimulationState* sim, RenderState* render_state, UI
}; };
int previous_active = ui_state->maneuver_list_active; 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 != previous_active) {
if (ui_state->maneuver_list_active >= 0 && ui_state->maneuver_list_active < maneuver_index_count) { 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) { void render_maneuver_create_tab(SimulationState* sim, UIState* ui_state, int x, int y, int width, int height) {
@ -713,34 +744,64 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x,
} }
} }
GuiLabel({(float)x, (float)current_y, (float)width, 25}, "Calculate optimal Hohmann transfer between orbits"); if (ui_state->sim_version != sim->version) {
current_y += 30; int craft_buffer_size = sim->craft_count * 64 + 1;
GuiLabel({(float)x, (float)current_y, 120, 25}, "Spacecraft:"); if (ui_state->craft_list_buffer == NULL || ui_state->craft_list_buffer_size < craft_buffer_size) {
current_y += 35; 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;
}
if (sim->craft_count > 0) { ui_state->craft_list_buffer[0] = '\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; int offset = 0;
for (int i = 0; i < sim->craft_count; i++) { for (int i = 0; i < sim->craft_count; i++) {
if (i > 0) { if (i > 0) {
offset += snprintf(craft_list + offset, craft_buffer_size - offset, ";"); 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(craft_list + offset, craft_buffer_size - offset, "%s", sim->spacecraft[i].name); 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;
GuiLabel({(float)x, (float)current_y, 120, 25}, "Spacecraft:");
current_y += 35;
if (sim->craft_count > 0) {
static bool edit_mode_spacecraft = false;
if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25}, if (GuiDropdownBox({(float)x + 120, (float)(current_y - 35), (float)(width - 130), 25},
craft_list, &ui_state->maneuver_dialog.craft_index, edit_mode_spacecraft)) { ui_state->craft_list_buffer, &ui_state->maneuver_dialog.craft_index, edit_mode_spacecraft)) {
edit_mode_spacecraft = !edit_mode_spacecraft; edit_mode_spacecraft = !edit_mode_spacecraft;
} }
free(craft_list);
if (edit_mode_spacecraft) return; if (edit_mode_spacecraft) return;
} }
}
current_y += 35; current_y += 35;
GuiLabel({(float)x, (float)current_y, 120, 25}, "Transfer Parent:"); GuiLabel({(float)x, (float)current_y, 120, 25}, "Transfer Parent:");
@ -748,26 +809,12 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x,
if (sim->body_count > 0) { if (sim->body_count > 0) {
static bool edit_mode_transfer_parent = false; 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}, 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)) { ui_state->body_dropdown_buffer, &ui_state->maneuver_dialog.transfer_body_index, edit_mode_transfer_parent)) {
edit_mode_transfer_parent = !edit_mode_transfer_parent; edit_mode_transfer_parent = !edit_mode_transfer_parent;
} }
free(body_list);
if (edit_mode_transfer_parent) return; if (edit_mode_transfer_parent) return;
} }
}
current_y += 35; current_y += 35;
GuiLabel({(float)x, (float)current_y, 120, 25}, "Current Body:"); GuiLabel({(float)x, (float)current_y, 120, 25}, "Current Body:");
@ -775,26 +822,12 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x,
if (sim->body_count > 0) { if (sim->body_count > 0) {
static bool edit_mode_current_body = false; 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}, 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)) { ui_state->body_dropdown_buffer, &ui_state->maneuver_dialog.current_body_index, edit_mode_current_body)) {
edit_mode_current_body = !edit_mode_current_body; edit_mode_current_body = !edit_mode_current_body;
} }
free(body_list);
if (edit_mode_current_body) return; if (edit_mode_current_body) return;
} }
}
current_y += 35; current_y += 35;
GuiLabel({(float)x, (float)current_y, 120, 25}, "Target Body:"); GuiLabel({(float)x, (float)current_y, 120, 25}, "Target Body:");
@ -802,26 +835,12 @@ void render_maneuver_hohmann_tab(SimulationState* sim, UIState* ui_state, int x,
if (sim->body_count > 0) { if (sim->body_count > 0) {
static bool edit_mode_target_body = false; 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}, 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)) { ui_state->body_dropdown_buffer, &ui_state->maneuver_dialog.target_body_index, edit_mode_target_body)) {
edit_mode_target_body = !edit_mode_target_body; edit_mode_target_body = !edit_mode_target_body;
} }
free(body_list);
if (edit_mode_target_body) return; if (edit_mode_target_body) return;
} }
}
current_y += 35; current_y += 35;
Rectangle calculate_btn = {(float)x, (float)current_y, (float)width, 30}; Rectangle calculate_btn = {(float)x, (float)current_y, (float)width, 30};
@ -1409,3 +1428,41 @@ void delete_maneuver_from_dialog(SimulationState* sim, UIState* ui_state) {
ui_state->maneuver_dialog.open = false; 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;
}

12
src/ui_renderer.h

@ -50,6 +50,16 @@ struct UIState {
int maneuver_list_active; int maneuver_list_active;
int maneuver_list_scroll; int maneuver_list_scroll;
int selected_maneuver_index; 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(); 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 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 load_maneuver_into_dialog(SimulationState* sim, UIState* ui_state, int maneuver_index);
void delete_maneuver_from_dialog(SimulationState* sim, UIState* ui_state); 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 #endif

Loading…
Cancel
Save