A 3D game engine from scratch.
at main 274 lines 9.4 kB view raw
1// (c) 2020 Vlad-Stefan Harbuz <vlad@vladh.net> 2 3#include "debug_ui.hpp" 4#include "entities.hpp" 5#include "engine.hpp" 6#include "intrinsics.hpp" 7 8 9void debug_ui::render_debug_ui() { 10 engine::State *engine_state = engine::debug_get_engine_state(); 11 12 WindowSize *window_size = core::get_window_size(); 13 14 char debug_text[1 << 14]; 15 size_t dt_size = sizeof(debug_text); 16 17 renderer::start_drawing_gui(); 18 19 gui::tick_heading(); 20 21 { 22 strcpy(debug_text, "Peony debug info: "); 23 strcat(debug_text, engine_state->current_scene_name); 24 gui::Container *container = gui::make_container(debug_text, v2(25.0f, 25.0f)); 25 26 snprintf(debug_text, dt_size, "%ux%u", window_size->width, window_size->height); 27 gui::draw_named_value(container, "screen size", debug_text); 28 29 snprintf(debug_text, dt_size, "%ux%u", 30 window_size->screencoord_width, window_size->screencoord_height); 31 gui::draw_named_value(container, "window size", debug_text); 32 33 snprintf(debug_text, dt_size, "%u fps", engine_state->perf_counters.last_fps); 34 gui::draw_named_value(container, "fps", debug_text); 35 36 snprintf(debug_text, dt_size, "%.2f ms", engine_state->perf_counters.dt_average * 1000.0f); 37 gui::draw_named_value(container, "dt", debug_text); 38 39 snprintf(debug_text, dt_size, "%.2f", 1.0f + engine_state->timescale_diff); 40 gui::draw_named_value(container, "ts", debug_text); 41 42 snprintf(debug_text, dt_size, engine_state->is_world_loaded ? "yes" : "no"); 43 gui::draw_named_value(container, "is_world_loaded", debug_text); 44 45 snprintf(debug_text, dt_size, "%u", mats::get_n_materials()); 46 gui::draw_named_value(container, "materials.length", debug_text); 47 48 snprintf(debug_text, dt_size, "%u", entities::get_n_entities()); 49 gui::draw_named_value(container, "entities.length", debug_text); 50 51 snprintf(debug_text, dt_size, "%u", engine_state->model_loaders.length); 52 gui::draw_named_value(container, "model_loaders.length", debug_text); 53 54 snprintf(debug_text, dt_size, "%u", engine_state->n_valid_model_loaders); 55 gui::draw_named_value(container, "n_valid_model_loaders", debug_text); 56 57 snprintf(debug_text, dt_size, "%u", engine_state->entity_loaders.length); 58 gui::draw_named_value(container, "entities.length", debug_text); 59 60 snprintf(debug_text, dt_size, "%u", engine_state->n_valid_entity_loaders); 61 gui::draw_named_value(container, "n_valid_entity_loaders", debug_text); 62 63 if (gui::draw_toggle(container, "Wireframe mode", renderer::should_use_wireframe())) { 64 renderer::set_should_use_wireframe(!renderer::should_use_wireframe()); 65 if (renderer::should_use_wireframe()) { 66 gui::set_heading("Wireframe mode on.", 1.0f, 1.0f, 1.0f); 67 } else { 68 gui::set_heading("Wireframe mode off.", 1.0f, 1.0f, 1.0f); 69 } 70 } 71 72 if (gui::draw_toggle(container, "FPS limit", engine_state->should_limit_fps)) { 73 engine_state->should_limit_fps = !engine_state->should_limit_fps; 74 if (engine_state->should_limit_fps) { 75 gui::set_heading("FPS limit enabled.", 1.0f, 1.0f, 1.0f); 76 } else { 77 gui::set_heading("FPS limit disabled.", 1.0f, 1.0f, 1.0f); 78 } 79 } 80 81 if (gui::draw_toggle(container, "Manual frame advance", engine_state->is_manual_frame_advance_enabled)) { 82 engine_state->is_manual_frame_advance_enabled = !engine_state->is_manual_frame_advance_enabled; 83 if (engine_state->is_manual_frame_advance_enabled) { 84 gui::set_heading("Manual frame advance enabled.", 1.0f, 1.0f, 1.0f); 85 } else { 86 gui::set_heading("Manual frame advance disabled.", 1.0f, 1.0f, 1.0f); 87 } 88 } 89 90 if (gui::draw_toggle(container, "Pause", engine_state->should_pause)) { 91 engine_state->should_pause = !engine_state->should_pause; 92 if (engine_state->should_pause) { 93 gui::set_heading("Pause enabled.", 1.0f, 1.0f, 1.0f); 94 } else { 95 gui::set_heading("Pause disabled.", 1.0f, 1.0f, 1.0f); 96 } 97 } 98 99 if (gui::draw_button(container, "Reload shaders")) { 100 mats::reload_shaders(); 101 gui::set_heading("Shaders reloaded.", 1.0f, 1.0f, 1.0f); 102 } 103 104 if (gui::draw_button(container, "Delete PBO")) { 105 mats::delete_persistent_pbo(); 106 gui::set_heading("PBO deleted.", 1.0f, 1.0f, 1.0f); 107 } 108 } 109 110 { 111 gui::Container *container = gui::make_container("Entities", v2(window_size->width - 400.0f, 25.0f)); 112 get_scene_text_representation(debug_text); 113 gui::draw_body_text(container, debug_text); 114 } 115 116 { 117 gui::Container *container = gui::make_container("Materials", v2(window_size->width - 600.0f, 25.0f)); 118 get_materials_text_representation(debug_text); 119 gui::draw_body_text(container, debug_text); 120 } 121 122 gui::draw_console(input::get_text_input()); 123 renderer::render_gui(); 124 gui::update(); 125} 126 127 128void 129debug_ui::get_entity_text_representation(char *text, entities::Entity *entity, u8 depth) 130{ 131 entities::Handle handle = entity->handle; 132 spatial::Component *spatial_component = spatial::get_component(handle); 133 134 // Children will be drawn under their parents. 135 if ( 136 depth == 0 && 137 spatial::is_spatial_component_valid(spatial_component) && 138 spatial_component->parent_entity_handle != entities::NO_ENTITY_HANDLE 139 ) { 140 return; 141 } 142 143 bool has_spatial_component = spatial::is_spatial_component_valid(spatial_component); 144 bool has_drawable_component = drawable::is_component_valid( 145 drawable::get_component(handle)); 146 bool has_light_component = lights::is_light_component_valid( 147 lights::get_component(handle)); 148 bool has_behavior_component = behavior::is_behavior_component_valid( 149 behavior::get_component(handle)); 150 bool has_animation_component = anim::is_animation_component_valid( 151 anim::get_component(handle)); 152 153 for (u8 level = 0; level < depth; level++) { 154 strcat(text, " "); 155 } 156 157 strcat(text, "- "); 158 strcat(text, entity->debug_name); 159 160 strcat(text, "@"); 161 sprintf(text + strlen(text), "%d", entity->handle); 162 163 if ( 164 !has_spatial_component && 165 !has_drawable_component && 166 !has_light_component && 167 !has_behavior_component && 168 !has_animation_component 169 ) { 170 strcat(text, " (orphan)"); 171 } 172 173 if (has_spatial_component) { 174 strcat(text, " +S"); 175 } 176 if (has_drawable_component) { 177 strcat(text, " +D"); 178 } 179 if (has_light_component) { 180 strcat(text, " +L"); 181 } 182 if (has_behavior_component) { 183 strcat(text, " +B"); 184 } 185 if (has_animation_component) { 186 strcat(text, " +A"); 187 } 188 189 if (spatial::is_spatial_component_valid(spatial_component)) { 190 // NOTE: This is super slow lol. 191 u32 n_children_found = 0; 192 each (child_spatial_component, *spatial::get_components()) { 193 if ( 194 child_spatial_component->parent_entity_handle == 195 spatial_component->entity_handle 196 ) { 197 n_children_found++; 198 if (n_children_found > 5) { 199 continue; 200 } 201 entities::Handle child_handle = child_spatial_component->entity_handle; 202 entities::Entity *child_entity = entities::get_entity(child_handle); 203 204 if (text[strlen(text) - 1] != '\n') { 205 strcat(text, "\n"); 206 } 207 get_entity_text_representation(text, child_entity, depth + 1); 208 } 209 } 210 if (n_children_found > 5) { 211 for (u8 level = 0; level < (depth + 1); level++) { 212 strcat(text, " "); 213 } 214 strcat(text, "(and "); 215 sprintf(text + strlen(text), "%d", n_children_found - 5); 216 strcat(text, " more)"); 217 } 218 } 219 220 if (text[strlen(text) - 1] != '\n') { 221 strcat(text, "\n"); 222 } 223} 224 225 226void 227debug_ui::get_scene_text_representation(char *text) 228{ 229 text[0] = '\0'; 230 231 constexpr u32 const MAX_N_SHOWN_ENTITIES = 35; 232 u32 idx_entity = 0; 233 each (entity, *entities::get_entities()) { 234 if (idx_entity > MAX_N_SHOWN_ENTITIES) { 235 sprintf(text + strlen(text), 236 "...and %d more\n", 237 entities::get_n_entities() - idx_entity); 238 break;; 239 } 240 get_entity_text_representation(text, entity, 0); 241 idx_entity++; 242 } 243 244 if (text[strlen(text) - 1] == '\n') { 245 text[strlen(text) - 1] = '\0'; 246 } 247} 248 249 250void 251debug_ui::get_materials_text_representation(char *text) 252{ 253 text[0] = '\0'; 254 255 strcat(text, "Internal:\n"); 256 257 bool have_seen_non_internal = false; 258 259 u32 idx = 0; 260 each (material, *mats::get_materials()) { 261 strcat(text, "- "); 262 strcat(text, material->name); 263 strcat(text, "\n"); 264 if (mats::is_material_at_idx_internal(idx) && !have_seen_non_internal) { 265 have_seen_non_internal = true; 266 strcat(text, "Non-internal: \n"); 267 } 268 idx++; 269 } 270 271 if (text[strlen(text) - 1] == '\n') { 272 text[strlen(text) - 1] = '\0'; 273 } 274}