techkaczynski.dev / code

summaryrefslogtreecommitdiff
path: root/editor.c
diff options
context:
space:
mode:
Diffstat (limited to 'editor.c')
-rw-r--r--editor.c672
1 files changed, 545 insertions, 127 deletions
diff --git a/editor.c b/editor.c
index 9f5eb21..ab70611 100644
--- a/editor.c
+++ b/editor.c
@@ -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();