diff options
Diffstat (limited to 'editor.c')
| -rw-r--r-- | editor.c | 672 |
1 files changed, 545 insertions, 127 deletions
@@ -39,18 +39,45 @@ EditorInfo ed = { }; typedef enum { - MDL_PICK_COMP_ADD, - MDL_PICK_COMP_UPDATE, - MDL_PICK_ENT_CREATE, -} ModelPickerMode; + ASSET_PICK_MDL_COMP_ADD, + ASSET_PICK_MDL_COMP_UPDATE, + ASSET_PICK_MDL_ENT_CREATE, + ASSET_PICK_MAT_TEX, +} AssetPickerMode; + +typedef struct { + cstr key; + int score; + Asset *asset; + bool tried_loading; +} AssetChoice; + +static struct { + RenderTexture preview; + AssetChoice *items; + int item_cnt, match_cnt, sel_idx, scroll; + AssetTag tag; + AssetPickerMode mode; + u32 mat_idx; // material index dummy + char query[128]; +} asset_picker; + +static const cstr material_shader_keys[] = { + "model", + "model_cutoff" +}; + +static const char material_shader_labels[] = + "Model;Model (cutoff)"; /* forward decl */ static bool selection_root(Entity *ent); static void action_apply(EditorAction*, bool); static void action_free(EditorAction*); -static void model_picker_open(ModelPickerMode mode); -static void model_picker_close(void); +static void asset_picker_open(AssetTag tag, AssetPickerMode mode); +static void asset_picker_close(void); static void physics_pick(void); +static void editor_set_material(cstr key, u32 mat_idx, MaterialProperty prop); static void history_push(EditorAction action) { @@ -200,11 +227,16 @@ action_begin(EditorActionTag tag, bool roots_only) { return action; case ED_ACTION_DELETE: + case ED_ACTION_DUPLICATE: recursive = true; break; case ED_ACTION_RENAME: + break; + case ED_ACTION_MODEL: + break; + case ED_ACTION_PHYSICS: break; @@ -267,14 +299,16 @@ action_begin(EditorActionTag tag, bool roots_only) { break; } + case ED_ACTION_DUPLICATE: + break; + case ED_ACTION_RENAME: - // Name ownership will transfer when the rename is submitted. + // Name ownership will transfer when the rename is + // submitted. break; case ED_ACTION_MODEL: - before->model = ent->mdl; - before->model.key = ent->mdl.key ? - strdup(ent->mdl.key) : NULL; + before->model = entity_model_copy(&ent->mdl); break; case ED_ACTION_PHYSICS: @@ -317,6 +351,7 @@ action_apply(EditorAction *action, bool undo) { break; case ED_ACTION_CREATE: + case ED_ACTION_DUPLICATE: if (undo) { action_entity_extract(action); } else { @@ -381,6 +416,7 @@ action_free(EditorAction *action) { case ED_ACTION_CREATE: case ED_ACTION_DELETE: + case ED_ACTION_DUPLICATE: for (u32 i = 0; i < action->item_cnt; ++i) { entity_clean(&action->item[i].before.stored.ent); } @@ -394,7 +430,7 @@ action_free(EditorAction *action) { case ED_ACTION_MODEL: for (u32 i = 0; i < action->item_cnt; ++i) { - free(action->item[i].before.model.key); + entity_model_free(&action->item[i].before.model); } break; @@ -446,6 +482,7 @@ action_commit(EditorAction *action) { case ED_ACTION_CREATE: case ED_ACTION_DELETE: + case ED_ACTION_DUPLICATE: changed = action->item_cnt != 0; break; @@ -479,6 +516,27 @@ action_commit(EditorAction *action) { strcmp(before->key ? before->key : "", after->key ? after->key : "") != 0; + if (before->mat_cnt != after->mat_cnt) { + changed = true; + continue; + } + + for (u32 j = 0; j < before->mat_cnt; ++j) { + const MaterialOverride *a, *b; + a = &before->materials[j]; + b = &after->materials[j]; + + changed |= strcmp(a->tex_key ? + a->tex_key : "", + b->tex_key ? + b->tex_key : "") != 0; + + changed |= strcmp(a->shader_key ? + a->shader_key : "", + b->shader_key ? + b->shader_key : + "") != 0; + } } break; @@ -532,7 +590,7 @@ editor_init(void) { void editor_exit(void) { - model_picker_close(); + asset_picker_close(); free(rot_record); action_free(&tr_action); tr_action = (EditorAction){0}; @@ -621,6 +679,86 @@ editor_focus_selection(void) { cam_focus(center, distance, view_height); } +static void +editor_duplicate(void) { + EditorAction action; + action = action_begin(ED_ACTION_DUPLICATE, true); + + if (!action.item_cnt) { + action_free(&action); + return; + } + + u64 *copies = calloc(action.item_cnt, sizeof(*copies)); + if (!copies) { + perror("editor_duplicate: alloc failed."); + exit(1); + } + + for (u32 i = 0; i < action.item_cnt; ++i) { + copies[i] = entity_create(false); + + /* Creation may reallocate the entity array. */ + u64 source_id = entity_id_from_pid(action.item[i].pid); + Entity *source = entity_get(source_id); + Entity *copy = entity_get(copies[i]); + + free(copy->name); + copy->name = source->name ? strdup(source->name) : NULL; + + copy->tr.pos = source->tr.pos; + copy->tr.rot = source->tr.rot; + copy->tr.scale = source->tr.scale; + + copy->mdl = entity_model_copy(&source->mdl); + copy->phys = entity_physics_copy(&source->phys); + + copy->ed.selected = source->ed.selected; + source->ed.selected = false; + } + + /* + * Collection visits children first. Linking in reverse order + * preserves sibling order when set_parent prepends children. + */ + for (u32 n = action.item_cnt; n > 0; --n) { + u32 i = n - 1; + u64 source_id = entity_id_from_pid(action.item[i].pid); + Entity *source = entity_get(source_id); + + u64 parent_id = source->tr.parent; + Entity *parent = entity_get(parent_id); + u64 parent_pid = parent ? parent->pid : 0; + + for (u32 j = 0; j < action.item_cnt; ++j) { + if (action.item[j].pid == parent_pid) { + parent_id = copies[j]; + break; + } + } + + entity_set_parent(copies[i], parent_id); + } + + /* Record the completed hierarchy for undo and redo. */ + for (u32 i = 0; i < action.item_cnt; ++i) { + Entity *copy = entity_get(copies[i]); + Entity *parent = entity_get(copy->tr.parent); + Entity *prev = entity_get(copy->tr.prev); + Entity *next = entity_get(copy->tr.next); + + EditorActionData *data = &action.item[i].before; + + action.item[i].pid = copy->pid; + data->stored.parent = parent ? parent->pid : 0; + data->stored.prev = prev ? prev->pid : 0; + data->stored.next = next ? next->pid : 0; + } + + free(copies); + action_commit(&action); +} + void editor_update(void) { bool ctrl = IsKeyDown(KEY_LEFT_CONTROL); @@ -663,8 +801,8 @@ case ED_INTERACT_NONE: } if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) || - (main_cam.state == CAM_MODE_EDIT_ORBIT && - IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))) { + (main_cam.state == CAM_MODE_EDIT_ORBIT && + IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))) { ed.interact = ED_INTERACT_CAMERA; main_cam.update = false; DisableCursor(); @@ -682,6 +820,9 @@ case ED_INTERACT_NONE: break; } + if (!ctrl && !shift && !alt && IsKeyPressed(KEY_C)) { + ed.draw_physics = !ed.draw_physics; + } if (!ctrl && IsKeyPressed(KEY_F)) { editor_focus_selection(); @@ -728,6 +869,12 @@ case ED_INTERACT_NONE: } } + if (ctrl && IsKeyPressed(KEY_D) && ed.sel_cnt) { + editor_duplicate(); + ed.interact = ED_INTERACT_MOVE; + break; + } + if (IsKeyPressed(KEY_DELETE)) { if (!ctrl && ed.sel_cnt) { EditorAction action = action_begin(ED_ACTION_DELETE, true); @@ -1101,8 +1248,11 @@ editor_move(void) { } } + bool reset = false; + if (IsKeyPressed(KEY_L)) { main_cam.local_space = !main_cam.local_space; + reset = true; } bool local = main_cam.local_space && ed.sel_cnt == 1; @@ -1113,6 +1263,7 @@ editor_move(void) { continue; } + reset = true; bool plane = IsKeyDown(KEY_LEFT_SHIFT); if (ed.move_axis == i && ed.move_plane == plane) { @@ -1155,11 +1306,17 @@ editor_move(void) { bool use_local = local && ed.move_axis >= 0 && !IsKeyDown(KEY_LEFT_ALT); - if (!Vector3Equals(axis, previous_axis) || - plane != previous_plane || use_local != previous_local) { + if (reset || !Vector3Equals(axis, previous_axis) || + plane != previous_plane || + use_local != previous_local) { + if (reset) { + action_apply(&tr_action, true); + } + previous_axis = axis; previous_plane = plane; previous_local = use_local; + raw_pivot = selected_pivot(); ed.move_snap_origin = raw_pivot; started = false; @@ -2012,6 +2169,12 @@ panel_properties(EditorPanelContainer container, bool input) { static PanelEdit edit; static bool add_open; static int add_choice; + static int mat_idx; + static bool shader_open; + + Rect shader_bounds = {0}; + bool shader_visible = false; + int shader_choice = 0; Rect bounds = ed.panel[container].bounds; int state = GuiGetState(); @@ -2026,10 +2189,11 @@ panel_properties(EditorPanelContainer container, bool input) { if (!input) { add_open = false; edit.focus = 0; + shader_open = false; GuiSetState(STATE_DISABLED); } - if (add_open) { + if (add_open || shader_open) { GuiLock(); } @@ -2217,8 +2381,27 @@ panel_properties(EditorPanelContainer container, bool input) { goto physics_comp; } + int material_count = 0; + int first_material = 0; + + if (ent) { + Asset *asset = asset_get(model->key); + if (asset) { + Model *mdl = &asset->mdl; + material_count = mdl->materialCount; + first_material = 1; + + for (int i = 0; i < mdl->meshCount; ++i) { + if (mdl->meshMaterial[i] == 0) { + first_material = 0; + break; + } + } + } + } + group.y = next_y; - group.height = 80; + group.height = material_count ? 170 : 80; GuiGroupBox(group, "Model"); row = (Rect){ @@ -2230,8 +2413,7 @@ panel_properties(EditorPanelContainer container, bool input) { GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); if (GuiButton((Rect){ - group.x, group.y + group.height + pad, - 120, 20 + group.x, group.y + group.height + pad, 120, 20 }, "Remove Model")) { edit.focus = 0; @@ -2242,8 +2424,7 @@ panel_properties(EditorPanelContainer container, bool input) { entity_id_from_pid(action.item[i].pid) ); - free(target->mdl.key); - target->mdl = (ModelCmp){0}; + entity_model_free(&target->mdl); } action_commit(&action); @@ -2257,7 +2438,7 @@ panel_properties(EditorPanelContainer container, bool input) { (Rect){row.x + 40, row.y, row.width - 40, row.height}, key_mixed ? "<multiple>" : GetFileName(model->key))) { edit.focus = 0; - model_picker_open(MDL_PICK_COMP_UPDATE); + asset_picker_open(ASSET_TAG_MODEL, ASSET_PICK_MDL_COMP_UPDATE); } row.y += 30; @@ -2278,6 +2459,97 @@ panel_properties(EditorPanelContainer container, bool input) { action_commit(&action); } + if (!material_count) { + goto model_end; + } + + row.y += 30; + + GuiLabel((Rect){ + row.x, row.y, 64, row.height + }, "Material"); + + Rect control = { + row.x + 72, row.y, + row.width - 72, row.height + }; + + int previous = mat_idx; + GuiSpinner(control, NULL, &mat_idx, first_material, + material_count - 1, false); + + if (mat_idx != previous) { + edit.focus = 0; + } + + cstr texture_key = NULL; + + if ((u32)mat_idx < model->mat_cnt) { + texture_key = model->materials[mat_idx].tex_key; + } + + cstr texture_label = "<model texture>"; + if (texture_key) { + texture_label = GetFileName(texture_key); + } + + row.y += 30; + control.y = row.y; + + GuiLabel((Rect){ + row.x, row.y, 64, row.height + }, "Texture"); + + Rect texture_button = control; + texture_button.width -= 56; + + Rect reset_button = { + control.x + control.width - 52, + control.y, 52, control.height + }; + + if (GuiButton(texture_button, texture_label)) { + edit.focus = 0; + asset_picker_open(ASSET_TAG_TEXTURE, + ASSET_PICK_MAT_TEX); + asset_picker.mat_idx = mat_idx; + } + + if (GuiButton(reset_button, "Reset")) { + edit.focus = 0; + editor_set_material(NULL, mat_idx, MAT_PROP_TEXTURE); + } + + row.y += 30; + control.y = row.y; + + GuiLabel((Rect){ + row.x, row.y, 64, row.height + }, "Shader"); + + cstr shader_key = "model"; + + if ((u32)mat_idx < model->mat_cnt) { + cstr key = model->materials[mat_idx].shader_key; + if (key) { + shader_key = key; + } + } + + int shader_count = sizeof(material_shader_keys) / + sizeof(material_shader_keys[0]); + + for (int i = 0; i < shader_count; ++i) { + if (strcmp(shader_key, material_shader_keys[i]) == 0) { + shader_choice = i; + break; + } + } + + shader_bounds = control; + shader_visible = true; + + model_end: next_y = group.y + group.height + pad + 20 + 16; physics_comp: @@ -2362,7 +2634,9 @@ panel_properties(EditorPanelContainer container, bool input) { next_y = group.y + group.height + pad + 20 + 16; comp_add: - GuiUnlock(); + if (!shader_open) { + GuiUnlock(); + } row = (Rect){ bounds.x + pad, @@ -2415,7 +2689,7 @@ panel_properties(EditorPanelContainer container, bool input) { add_choice = 0; if (choice == model_choice) { - model_picker_open(MDL_PICK_COMP_ADD); + asset_picker_open(ASSET_TAG_MODEL, ASSET_PICK_MDL_COMP_ADD); goto reset; } @@ -2441,11 +2715,37 @@ panel_properties(EditorPanelContainer container, bool input) { reset: GuiUnlock(); + + if (!shader_visible) { + shader_open = false; + } else { + if (add_open) { + GuiLock(); + } + + int previous = shader_choice; + + if (GuiDropdownBox(shader_bounds, material_shader_labels, + &shader_choice, shader_open)) { + shader_open = !shader_open; + edit.focus = 0; + + if (!shader_open && shader_choice != previous) { + cstr key = material_shader_keys[shader_choice]; + + editor_set_material(key, mat_idx, + MAT_PROP_SHADER); + } + } + + GuiUnlock(); + } + GuiSetState(state); GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); if (input && container != ED_PNL_CENTER) { ed.focus_captured = edit.focus != 0 || - add_open || + add_open || shader_open || ed.panel[ED_PNL_CENTER].enabled; } } @@ -2491,23 +2791,9 @@ panel_space(EditorPanelContainer container) { } /* model picker */ -typedef struct { - cstr key; - int score; - Asset *asset; - bool tried_loading; -} ModelChoice; - -static struct { - RenderTexture preview; - ModelChoice *items; - int item_cnt, match_cnt, sel_idx, scroll; - ModelPickerMode mode; - char query[128]; -} model_picker; static bool -editor_set_model(cstr key, ModelPickerMode mode) { +editor_set_model(cstr key, AssetPickerMode mode) { Asset *asset = asset_get(key); if (!asset || asset->tag != ASSET_TAG_MODEL) { return false; @@ -2519,29 +2805,94 @@ editor_set_model(cstr key, ModelPickerMode mode) { u64 id = entity_id_from_pid(action.item[i].pid); Entity *ent = entity_get(id); - if ((mode == MDL_PICK_COMP_ADD && ent->mdl.has) || - (mode == MDL_PICK_COMP_UPDATE && !ent->mdl.has)) { + if ((mode == ASSET_PICK_MDL_COMP_ADD&& ent->mdl.has) || + (mode == ASSET_PICK_MDL_COMP_UPDATE && + !ent->mdl.has)) { continue; } - free(ent->mdl.key); + bool draw = ent->mdl.has ? ent->mdl.draw : true; + entity_model_free(&ent->mdl); ent->mdl = (ModelCmp){ - .key = strdup(key), - .mdl = &asset->mdl, - .has = true, - .draw = ent->mdl.has ? ent->mdl.draw : true, - }; + .key = strdup(key), + .mdl = &asset->mdl, + .has = true, + .draw = draw, + }; } action_commit(&action); return true; } +static void +editor_set_material(cstr key, u32 mat_idx, MaterialProperty prop) { + EditorAction action = action_begin(ED_ACTION_MODEL, false); + + for (u32 i = 0; i < action.item_cnt; ++i) { + u64 id = entity_id_from_pid(action.item[i].pid); + Entity *ent = entity_get(id); + ModelCmp *model = &ent->mdl; + + if (!model->has) { + continue; + } + + if (!key && mat_idx >= model->mat_cnt) { + continue; + } + + if (!model->mdl) { + Asset *asset = asset_get(model->key); + if (!asset) { + continue; + } + model->mdl = &asset->mdl; + } + + if (mat_idx >= (u32)model->mdl->materialCount) { + continue; + } + + if (mat_idx >= model->mat_cnt) { + u32 count = model->mdl->materialCount; + MaterialOverride *materials; + + materials = realloc(model->materials, + count * sizeof(*materials)); + + if (!materials) { + perror("editor_set_texture: alloc failed."); + exit(1); + } + + memset(materials + model->mat_cnt, 0, + (count - model->mat_cnt) * + sizeof(*materials)); + + model->materials = materials; + model->mat_cnt = count; + } + + MaterialOverride *material; + material = &model->materials[mat_idx]; + + char **field = prop == MAT_PROP_TEXTURE ? + &material->tex_key : &material->shader_key; + + char *replacement = key ? strdup(key) : NULL; + free(*field); + *field = replacement; + } + + action_commit(&action); +} + /* qsort compare func */ static int model_choice_compare(const void *a, const void *b) { - const ModelChoice *left = a; - const ModelChoice *right = b; + const AssetChoice *left = a; + const AssetChoice *right = b; if (left->score > right->score) { return -1; @@ -2560,12 +2911,12 @@ model_choice_compare(const void *a, const void *b) { } static void -model_picker_close(void) { - if (model_picker.preview.id) { - UnloadRenderTexture(model_picker.preview); +asset_picker_close(void) { + if (asset_picker.preview.id) { + UnloadRenderTexture(asset_picker.preview); } - free(model_picker.items); - memset(&model_picker, 0, sizeof(model_picker)); + free(asset_picker.items); + memset(&asset_picker, 0, sizeof(asset_picker)); ed.panel[ED_PNL_CENTER].enabled = false; ed.focus = ED_PNL_NULL; @@ -2573,31 +2924,33 @@ model_picker_close(void) { } static void -model_picker_open(ModelPickerMode mode) { - model_picker.mode = mode; - char **keys = asset_mdl_keys(&model_picker.item_cnt); - - if (model_picker.item_cnt) { - model_picker.items = calloc(model_picker.item_cnt, - sizeof(*model_picker.items)); - if (!model_picker.items) { - perror("model_picker_open: alloc failed."); +asset_picker_open(AssetTag tag, AssetPickerMode mode) { + asset_picker.tag = tag; + asset_picker.mode = mode; + + char **keys = asset_type_keys(tag, &asset_picker.item_cnt); + if (asset_picker.item_cnt) { + asset_picker.items = calloc(asset_picker.item_cnt, + sizeof(*asset_picker.items)); + if (!asset_picker.items) { + perror("asset_picker_open: alloc failed."); exit(1); } } - for (int i = 0; i < model_picker.item_cnt; ++i) { - model_picker.items[i].key = keys[i]; + for (int i = 0; i < asset_picker.item_cnt; ++i) { + asset_picker.items[i].key = keys[i]; } free(keys); - model_picker.match_cnt = model_picker.item_cnt; - if (model_picker.item_cnt > 1) { - qsort(model_picker.items, model_picker.item_cnt, - sizeof(*model_picker.items), model_choice_compare); + + asset_picker.match_cnt = asset_picker.item_cnt; + if (asset_picker.item_cnt > 1) { + qsort(asset_picker.items, asset_picker.item_cnt, + sizeof(*asset_picker.items), model_choice_compare); } - ed.panel[ED_PNL_CENTER].type = ED_PNL_TYPE_MODEL_PICKER; + ed.panel[ED_PNL_CENTER].type = ED_PNL_TYPE_ASSET_PICKER; ed.panel[ED_PNL_CENTER].enabled = true; ed.focus = ED_PNL_CENTER; ed.focus_captured = true; @@ -2605,13 +2958,13 @@ model_picker_open(ModelPickerMode mode) { static void model_picker_preview(Rect bounds, Model mdl) { - if (model_picker.preview.texture.width != bounds.width || - model_picker.preview.texture.height != bounds.height) { - if (model_picker.preview.texture.id) { - UnloadRenderTexture(model_picker.preview); + if (asset_picker.preview.texture.width != bounds.width || + asset_picker.preview.texture.height != bounds.height) { + if (asset_picker.preview.texture.id) { + UnloadRenderTexture(asset_picker.preview); } - model_picker.preview = + asset_picker.preview = LoadRenderTexture(bounds.width, bounds.height); } @@ -2649,7 +3002,7 @@ model_picker_preview(Rect bounds, Model mdl) { .projection = CAMERA_PERSPECTIVE, }; - BeginTextureMode(model_picker.preview); + BeginTextureMode(asset_picker.preview); ClearBackground((Color){ 35, 35, 40, 255 }); BeginMode3D(cam); @@ -2666,20 +3019,41 @@ model_picker_preview(Rect bounds, Model mdl) { EndMode3D(); EndTextureMode(); - DrawTexturePro(model_picker.preview.texture, (Rect) { + DrawTexturePro(asset_picker.preview.texture, (Rect) { 0, 0, bounds.width, -bounds.height, }, bounds, (Vec2){0}, 0, WHITE); } +static void +texture_picker_preview(Rect bounds, Texture tex) { + if (bounds.width <= 0 || bounds.height <= 0) { + return; + } + + f32 scale = fminf(bounds.width / tex.width, + bounds.height / tex.height); + + Rect dest = { + .width = tex.width * scale, + .height = tex.height * scale, + }; + + dest.x = bounds.x + (bounds.width - dest.width) * 0.5f; + dest.y = bounds.y + (bounds.height - dest.height) * 0.5f; + + DrawTexturePro(tex, + (Rect){0, 0, tex.width, tex.height}, + dest, (Vec2){0}, 0, WHITE); +} static cstr -panel_model_picker(Rect bounds, bool input) { +panel_asset_picker(Rect bounds, bool input) { if (input && IsKeyPressed(KEY_ESCAPE)) { - model_picker_close(); + asset_picker_close(); return NULL; } - GuiPanel(bounds, "Choose Model"); + GuiPanel(bounds, "Choose asset"); f32 left_width = floorf((bounds.width - 24) * 0.45f); @@ -2699,40 +3073,40 @@ panel_model_picker(Rect bounds, bool input) { bounds.height - 38, }; - char previous[sizeof(model_picker.query)]; - memcpy(previous, model_picker.query, sizeof(previous)); + char previous[sizeof(asset_picker.query)]; + memcpy(previous, asset_picker.query, sizeof(previous)); /* Ignore the toggle result: the search always keeps text focus. */ - GuiTextBox(search, model_picker.query, - sizeof(model_picker.query), input); + GuiTextBox(search, asset_picker.query, + sizeof(asset_picker.query), input); - if (strcmp(previous, model_picker.query) != 0) { - model_picker.match_cnt = 0; + if (strcmp(previous, asset_picker.query) != 0) { + asset_picker.match_cnt = 0; - for (int i = 0; i < model_picker.item_cnt; ++i) { - ModelChoice *item = &model_picker.items[i]; + for (int i = 0; i < asset_picker.item_cnt; ++i) { + AssetChoice *item = &asset_picker.items[i]; item->score = - fuzzy_match(model_picker.query, + fuzzy_match(asset_picker.query, GetFileName(item->key)); if (item->score != INT32_MIN) { - model_picker.match_cnt++; + asset_picker.match_cnt++; } } - if (model_picker.item_cnt > 1) { - qsort(model_picker.items, - model_picker.item_cnt, - sizeof(*model_picker.items), + if (asset_picker.item_cnt > 1) { + qsort(asset_picker.items, + asset_picker.item_cnt, + sizeof(*asset_picker.items), model_choice_compare); } - model_picker.sel_idx = 0; - model_picker.scroll = 0; + asset_picker.sel_idx = 0; + asset_picker.scroll = 0; } - if (input && model_picker.match_cnt) { + if (input && asset_picker.match_cnt) { int step = 0; if (IsKeyPressed(KEY_UP)) { @@ -2745,29 +3119,29 @@ panel_model_picker(Rect bounds, bool input) { step = backwards ? -1 : 1; } - model_picker.sel_idx = - (model_picker.sel_idx + step + - model_picker.match_cnt) % - model_picker.match_cnt; + asset_picker.sel_idx = + (asset_picker.sel_idx + step + + asset_picker.match_cnt) % + asset_picker.match_cnt; } int visible = MAX(1, (int)(list.height / 24)); - if (model_picker.sel_idx < model_picker.scroll) { - model_picker.scroll = model_picker.sel_idx; + if (asset_picker.sel_idx < asset_picker.scroll) { + asset_picker.scroll = asset_picker.sel_idx; } - if (model_picker.sel_idx >= model_picker.scroll + visible) { - model_picker.scroll = model_picker.sel_idx - visible + 1; + if (asset_picker.sel_idx >= asset_picker.scroll + visible) { + asset_picker.scroll = asset_picker.sel_idx - visible + 1; } BeginScissorMode((int)list.x, (int)list.y, (int)list.width, (int)list.height); for (int row = 0; row < visible; ++row) { - int index = model_picker.scroll + row; + int index = asset_picker.scroll + row; - if (index >= model_picker.match_cnt) { + if (index >= asset_picker.match_cnt) { break; } @@ -2776,34 +3150,34 @@ panel_model_picker(Rect bounds, bool input) { list.width, 24, }; - if (index == model_picker.sel_idx) { + if (index == asset_picker.sel_idx) { DrawRectangleRec(item_box, GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED))); } - GuiLabel(item_box, GetFileName(model_picker.items[index].key)); + GuiLabel(item_box, GetFileName(asset_picker.items[index].key)); } - if (!model_picker.match_cnt) { + if (!asset_picker.match_cnt) { GuiLabel((Rect) { list.x, list.y, list.width, 24 - }, "No matching models"); + }, "No matching assets"); } EndScissorMode(); GuiPanel(preview, NULL); - if (model_picker.match_cnt) { - ModelChoice *item = &model_picker.items[model_picker.sel_idx]; + if (asset_picker.match_cnt) { + AssetChoice *item = &asset_picker.items[asset_picker.sel_idx]; if (!item->tried_loading) { item->asset = asset_get(item->key); item->tried_loading = true; } - /* model preview */ + /* preview */ if (item->asset) { Rect image = { preview.x + 1, @@ -2811,7 +3185,20 @@ panel_model_picker(Rect bounds, bool input) { preview.width - 2, preview.height - 35, }; - model_picker_preview(image, item->asset->mdl); + switch (asset_picker.tag) { + case ASSET_TAG_MODEL: + model_picker_preview(image, item->asset->mdl); + break; + + case ASSET_TAG_TEXTURE: + texture_picker_preview(image, + item->asset->tex); + break; + + default: + GuiLabel(image, "No preview available"); + break; + } } GuiLabel((Rect){ @@ -2819,7 +3206,7 @@ panel_model_picker(Rect bounds, bool input) { preview.width - 16, 24, }, item->asset ? GetFileName(item->key) : - "Could not load model"); + "Could not load asset"); if (input && item->asset && IsKeyPressed(KEY_ENTER)) { return item->key; @@ -3730,27 +4117,33 @@ panel_draw(EditorPanelContainer container) { GuiPanel(bounds, "Command Menu"); break; - case ED_PNL_TYPE_MODEL_PICKER: - {} - cstr key = panel_model_picker(bounds, input); + case ED_PNL_TYPE_ASSET_PICKER: { + cstr key = panel_asset_picker(bounds, input); if (!key) { break; } - switch (model_picker.mode) { - case MDL_PICK_COMP_ADD: - case MDL_PICK_COMP_UPDATE: - if (editor_set_model(key, model_picker.mode)) { - model_picker_close(); + switch (asset_picker.mode) { + case ASSET_PICK_MDL_COMP_ADD: + case ASSET_PICK_MDL_COMP_UPDATE: + if (editor_set_model(key, asset_picker.mode)) { + asset_picker_close(); } break; - case MDL_PICK_ENT_CREATE: + case ASSET_PICK_MDL_ENT_CREATE: /* TODO: */ break; + + case ASSET_PICK_MAT_TEX: + editor_set_material(key, asset_picker.mat_idx, + MAT_PROP_TEXTURE); + asset_picker_close(); + break; } break; + } case ED_PNL_TYPE_PHYSICS_ELEMENTS: panel_physics_elements(container); @@ -3793,6 +4186,31 @@ editor_draw_ui(void) { panel_draw(ED_PNL_LEFT); panel_draw(ED_PNL_RIGHT); + if (ed.mode == ED_MODE_SCENE && + !ed.panel[ED_PNL_RIGHT].enabled) { + char stats[4][64]; + + snprintf(stats[0], sizeof(stats[0]), "%i FPS | %.2f ms", + GetFPS(), app.frame_time_ms); + snprintf(stats[1], sizeof(stats[1]), "Entities: %u", + entity_count()); + snprintf(stats[2], sizeof(stats[2]), "Selected: %i", + ed.sel_cnt); + snprintf(stats[3], sizeof(stats[3]), "Colliders: %s [C]", + ed.draw_physics ? "on" : "off"); + + for (int i = 0; i < 4; ++i) { + f32 width = editor_label_w(stats[i]); + + GuiLabel((Rect){ + screen_w - margin - width, + margin + i * 22.0f, + width, + 22.0f + }, stats[i]); + } + } + if (ed.interact == ED_INTERACT_SELECT) { if (started && sel_dist > 20) { sel_rec_draw(); |
