Skip to content

Commit

Permalink
Group gizmos (#564)
Browse files Browse the repository at this point in the history
* scene: Add scene_transform_rotate_around util

* debug: Fix incorrect gizmo center calculation

* scene: Add scene_transform_scale_around util

* game: Fix invalid cmd group position

* debug: Refactor destroy tool

* debug: Move tool update into func

* debug: Add group tool logic

* debug: Add duplicate tool

* debug: Add select-all tool
  • Loading branch information
BastianBlokland authored Aug 4, 2023
1 parent 9990045 commit 7db5217
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 57 deletions.
9 changes: 4 additions & 5 deletions apps/game/src/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,15 @@ static void cmd_group_update_position(CmdGroup* group, EcsWorld* world) {
EcsIterator* transformItr = ecs_view_itr(transformView);
DynArray* entities = &group->entities;

group->position = geo_vector(0);
u32 count = 0;
dynarray_for_t(entities, EcsEntityId, object) {
if (ecs_view_maybe_jump(transformItr, *object)) {
const GeoVector pos = ecs_view_read_t(transformItr, SceneTransformComp)->position;
group->position = geo_vector_add(group->position, pos);
group->position = count ? geo_vector_add(group->position, pos) : pos;
++count;
}
}
if (dynarray_size(entities)) {
group->position = geo_vector_div(group->position, dynarray_size(entities));
}
group->position = count ? geo_vector_div(group->position, count) : geo_vector(0);
}

static bool cmd_is_player_owned(EcsIterator* itr) {
Expand Down
14 changes: 14 additions & 0 deletions assets/global/debug-input.imp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,20 @@
{ "type": "Pressed", "key": "Delete" }
]
},
{
"name": "DebugInspectorDuplicate",
"blockers": [ "TextInput" ],
"bindings": [
{ "type": "Pressed", "key": "D", "requiredModifiers": [ "Control" ] }
]
},
{
"name": "DebugInspectorSelectAll",
"blockers": [ "TextInput" ],
"bindings": [
{ "type": "Pressed", "key": "A", "requiredModifiers": [ "Control" ] }
]
},
{
"name": "DebugInspectorToolTranslation",
"blockers": [ "TextInput" ],
Expand Down
6 changes: 3 additions & 3 deletions libs/debug/src/gizmo.c
Original file line number Diff line number Diff line change
Expand Up @@ -635,14 +635,14 @@ ecs_system_define(DebugGizmoUpdateSys) {
const SceneTerrainComp* terrain = ecs_view_read_t(globalItr, SceneTerrainComp);

// Register all gizmos that where active in the last frame.
GeoVector center = {0};
GeoVector center;
geo_query_env_clear(gizmo->queryEnv);
for (u32 i = 0; i != gizmo->entries.size; ++i) {
const DebugGizmoEntry* entry = gizmo_entry(gizmo, i);
gizmo_register(gizmo, entry);
center = geo_vector_add(center, entry->pos);
center = i ? geo_vector_add(center, entry->pos) : entry->pos;
}
center = geo_vector_div(center, gizmo->entries.size ? gizmo->entries.size : 1.0f);
center = gizmo->entries.size ? geo_vector_div(center, gizmo->entries.size) : geo_vector(0);

// Update the editor.
EcsView* cameraView = ecs_world_view_t(world, CameraView);
Expand Down
235 changes: 186 additions & 49 deletions libs/debug/src/inspector.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "core_alloc.h"
#include "core_array.h"
#include "core_bits.h"
#include "core_float.h"
Expand Down Expand Up @@ -127,7 +128,7 @@ ecs_view_define(PanelUpdateView) {

ecs_view_define(GlobalToolUpdateView) {
ecs_access_read(InputManagerComp);
ecs_access_read(SceneSelectionComp);
ecs_access_write(SceneSelectionComp);
ecs_access_write(DebugGizmoComp);
ecs_access_write(DebugInspectorSettingsComp);
ecs_access_write(DebugStatsGlobalComp);
Expand Down Expand Up @@ -168,14 +169,6 @@ ecs_view_define(SubjectView) {

ecs_view_define(TransformView) { ecs_access_read(SceneTransformComp); }

static void inspector_notify_tool(DebugInspectorSettingsComp* set, DebugStatsGlobalComp* stats) {
debug_stats_notify(stats, string_lit("Tool"), g_toolNames[set->tool]);
}

static void inspector_notify_destroy(DebugStatsGlobalComp* stats) {
debug_stats_notify(stats, string_lit("Tool"), string_lit("Destroy"));
}

static void inspector_notify_vis(
DebugInspectorSettingsComp* set, DebugStatsGlobalComp* stats, const DebugInspectorVis vis) {
debug_stats_notify(
Expand Down Expand Up @@ -671,7 +664,7 @@ static void inspector_panel_draw_settings(
ui_label(canvas, string_lit("Tool"));
ui_table_next_column(canvas, table);
if (ui_select(canvas, (i32*)&settings->tool, g_toolNames, array_elems(g_toolNames))) {
inspector_notify_tool(settings, stats);
debug_stats_notify(stats, string_lit("Tool"), g_toolNames[settings->tool]);
}

inspector_panel_next(canvas, panelComp, table);
Expand Down Expand Up @@ -801,79 +794,223 @@ ecs_system_define(DebugInspectorUpdatePanelSys) {
}

static void
debug_inspector_toggle_tool(DebugInspectorSettingsComp* set, const DebugInspectorTool tool) {
debug_inspector_tool_toggle(DebugInspectorSettingsComp* set, const DebugInspectorTool tool) {
if (set->tool != tool) {
set->tool = tool;
} else {
set->tool = DebugInspectorTool_None;
}
}

ecs_system_define(DebugInspectorToolUpdateSys) {
EcsView* globalView = ecs_world_view_t(world, GlobalToolUpdateView);
EcsIterator* globalItr = ecs_view_maybe_at(globalView, ecs_world_global(world));
if (!globalItr) {
return;
static void debug_inspector_tool_destroy(EcsWorld* world, const SceneSelectionComp* sel) {
for (const EcsEntityId* e = scene_selection_begin(sel); e != scene_selection_end(sel); ++e) {
if (ecs_world_exists(world, *e)) {
ecs_world_entity_destroy(world, *e);
}
}
const InputManagerComp* input = ecs_view_read_t(globalItr, InputManagerComp);
const SceneSelectionComp* sel = ecs_view_read_t(globalItr, SceneSelectionComp);
DebugGizmoComp* gizmo = ecs_view_write_t(globalItr, DebugGizmoComp);
DebugInspectorSettingsComp* set = ecs_view_write_t(globalItr, DebugInspectorSettingsComp);
DebugStatsGlobalComp* stats = ecs_view_write_t(globalItr, DebugStatsGlobalComp);
}

if (!input_layer_active(input, string_hash_lit("Debug"))) {
set->tool = DebugInspectorTool_None;
static void debug_inspector_tool_duplicate(EcsWorld* world, SceneSelectionComp* sel) {
DynArray newEntities = dynarray_create_t(g_alloc_heap, EcsEntityId, 64);
EcsIterator* itr = ecs_view_itr(ecs_world_view_t(world, SubjectView));
for (const EcsEntityId* e = scene_selection_begin(sel); e != scene_selection_end(sel); ++e) {
if (!ecs_view_maybe_jump(itr, *e)) {
continue; // Selected entity is missing required components.
}
const SceneTransformComp* transComp = ecs_view_read_t(itr, SceneTransformComp);
const SceneScaleComp* scaleComp = ecs_view_read_t(itr, SceneScaleComp);
const SceneFactionComp* factionComp = ecs_view_read_t(itr, SceneFactionComp);
const ScenePrefabInstanceComp* prefabInstComp = ecs_view_read_t(itr, ScenePrefabInstanceComp);
if (!prefabInstComp) {
continue; // Only prefab instances can be duplicated.
}
const EcsEntityId duplicatedEntity = scene_prefab_spawn(
world,
&(ScenePrefabSpec){
.id = prefabInstComp->id,
.prefabId = prefabInstComp->prefabId,
.faction = factionComp ? factionComp->id : SceneFaction_None,
.scale = scaleComp ? scaleComp->scale : 1.0f,
.position = transComp->position,
.rotation = transComp->rotation,
});
*dynarray_push_t(&newEntities, EcsEntityId) = duplicatedEntity;
}
if (input_triggered_lit(input, "DebugInspectorToolTranslation")) {
debug_inspector_toggle_tool(set, DebugInspectorTool_Translation);
inspector_notify_tool(set, stats);

// Select the newly created entities.
scene_selection_clear(sel);
dynarray_for_t(&newEntities, EcsEntityId, e) { scene_selection_add(sel, *e); }
dynarray_destroy(&newEntities);
}

ecs_comp_extern(SceneCameraComp);

static void debug_inspector_tool_select_all(EcsWorld* world, SceneSelectionComp* sel) {
const u32 compCount = ecs_def_comp_count(ecs_world_def(world));
const BitSet ignoredCompMask = mem_stack(bits_to_bytes(compCount) + 1);

// Setup ignored components.
bitset_clear_all(ignoredCompMask);
bitset_set(ignoredCompMask, ecs_comp_id(SceneCameraComp));

scene_selection_clear(sel);
EcsView* subjectView = ecs_world_view_t(world, SubjectView);
for (EcsIterator* itr = ecs_view_itr(subjectView); ecs_view_walk(itr);) {
const EcsEntityId e = ecs_view_entity(itr);
const EcsArchetypeId archetype = ecs_world_entity_archetype(world, e);
if (bitset_any_of(ecs_world_component_mask(world, archetype), ignoredCompMask)) {
continue;
}
scene_selection_add(sel, e);
}
if (input_triggered_lit(input, "DebugInspectorToolRotation")) {
debug_inspector_toggle_tool(set, DebugInspectorTool_Rotation);
inspector_notify_tool(set, stats);
}

static GeoVector debug_inspector_tool_pivot(EcsWorld* world, const SceneSelectionComp* sel) {
EcsIterator* itr = ecs_view_itr(ecs_world_view_t(world, SubjectView));
GeoVector pivot;
u32 count = 0;
for (const EcsEntityId* e = scene_selection_begin(sel); e != scene_selection_end(sel); ++e) {
if (ecs_view_maybe_jump(itr, *e)) {
const SceneTransformComp* transComp = ecs_view_read_t(itr, SceneTransformComp);
pivot = count ? geo_vector_add(pivot, transComp->position) : transComp->position;
++count;
}
}
if (input_triggered_lit(input, "DebugInspectorToolScale")) {
debug_inspector_toggle_tool(set, DebugInspectorTool_Scale);
inspector_notify_tool(set, stats);
return count ? geo_vector_div(pivot, count) : geo_vector(0);
}

static void debug_inspector_tool_group_update(
EcsWorld* world,
DebugInspectorSettingsComp* set,
const SceneSelectionComp* sel,
DebugGizmoComp* gizmo) {
EcsIterator* itr = ecs_view_itr(ecs_world_view_t(world, SubjectView));
if (!ecs_view_maybe_jump(itr, scene_selection_main(sel))) {
return; // No main selected entity or its missing required components.
}
const SceneTransformComp* mainTrans = ecs_view_read_t(itr, SceneTransformComp);
const SceneScaleComp* mainScale = ecs_view_read_t(itr, SceneScaleComp);

const GeoVector pos = debug_inspector_tool_pivot(world, sel);
const GeoQuat rot = mainTrans->rotation;
const f32 scale = mainScale ? mainScale->scale : 1.0f;

static const DebugGizmoId g_groupGizmoId = 1234567890;

GeoVector posEdit = pos;
GeoQuat rotEdit = rot;
f32 scaleEdit = scale;
switch (set->tool) {
case DebugInspectorTool_Translation:
debug_gizmo_translation(gizmo, g_groupGizmoId, &posEdit, rot);
break;
case DebugInspectorTool_Rotation:
debug_gizmo_rotation(gizmo, g_groupGizmoId, pos, &rotEdit);
break;
case DebugInspectorTool_Scale:
debug_gizmo_scale_uniform(gizmo, g_groupGizmoId, pos, &scaleEdit);
break;
default:
break;
}

EcsIterator* subjectItr = ecs_view_itr(ecs_world_view_t(world, SubjectView));
for (const EcsEntityId* e = scene_selection_begin(sel); e != scene_selection_end(sel); ++e) {
if (ecs_view_maybe_jump(subjectItr, *e)) {
const GeoVector posDelta = geo_vector_sub(posEdit, pos);
const GeoQuat rotDelta = geo_quat_from_to(rot, rotEdit);
const f32 scaleDelta = scaleEdit / scale;

if (input_triggered_lit(input, "DebugInspectorDestroy")) {
ecs_world_entity_destroy(world, *e);
inspector_notify_destroy(stats);
for (const EcsEntityId* e = scene_selection_begin(sel); e != scene_selection_end(sel); ++e) {
if (ecs_view_maybe_jump(itr, *e)) {
SceneTransformComp* transform = ecs_view_write_t(itr, SceneTransformComp);
SceneScaleComp* scaleComp = ecs_view_write_t(itr, SceneScaleComp);
transform->position = geo_vector_add(transform->position, posDelta);
scene_transform_rotate_around(transform, pos, rotDelta);
if (scaleComp) {
scene_transform_scale_around(transform, scaleComp, pos, scaleDelta);
}
}
}
}

const DebugGizmoId gizmoId = (DebugGizmoId)ecs_view_entity(subjectItr);
SceneTransformComp* transform = ecs_view_write_t(subjectItr, SceneTransformComp);
SceneScaleComp* scaleComp = ecs_view_write_t(subjectItr, SceneScaleComp);
static void debug_inspector_tool_individual_update(
EcsWorld* world,
DebugInspectorSettingsComp* set,
const SceneSelectionComp* sel,
DebugGizmoComp* gizmo) {
EcsIterator* itr = ecs_view_itr(ecs_world_view_t(world, SubjectView));
for (const EcsEntityId* e = scene_selection_begin(sel); e != scene_selection_end(sel); ++e) {
if (ecs_view_maybe_jump(itr, *e)) {
const DebugGizmoId gizmoId = (DebugGizmoId)ecs_view_entity(itr);
SceneTransformComp* transform = ecs_view_write_t(itr, SceneTransformComp);
SceneScaleComp* scaleComp = ecs_view_write_t(itr, SceneScaleComp);
switch (set->tool) {
case DebugInspectorTool_Translation:
if (transform) {
debug_gizmo_translation(gizmo, gizmoId, &transform->position, transform->rotation);
}
debug_gizmo_translation(gizmo, gizmoId, &transform->position, transform->rotation);
break;
case DebugInspectorTool_Rotation:
if (transform) {
debug_gizmo_rotation(gizmo, gizmoId, transform->position, &transform->rotation);
}
debug_gizmo_rotation(gizmo, gizmoId, transform->position, &transform->rotation);
break;
case DebugInspectorTool_Scale:
if (scaleComp) {
const GeoVector position = transform ? transform->position : geo_vector(0);
debug_gizmo_scale_uniform(gizmo, gizmoId, position, &scaleComp->scale);
}
break;
case DebugInspectorTool_None:
case DebugInspectorTool_Count:
default:
break;
}
}
}
}

ecs_system_define(DebugInspectorToolUpdateSys) {
EcsView* globalView = ecs_world_view_t(world, GlobalToolUpdateView);
EcsIterator* globalItr = ecs_view_maybe_at(globalView, ecs_world_global(world));
if (!globalItr) {
return;
}
const InputManagerComp* input = ecs_view_read_t(globalItr, InputManagerComp);
SceneSelectionComp* sel = ecs_view_write_t(globalItr, SceneSelectionComp);
DebugGizmoComp* gizmo = ecs_view_write_t(globalItr, DebugGizmoComp);
DebugInspectorSettingsComp* set = ecs_view_write_t(globalItr, DebugInspectorSettingsComp);
DebugStatsGlobalComp* stats = ecs_view_write_t(globalItr, DebugStatsGlobalComp);

if (!input_layer_active(input, string_hash_lit("Debug"))) {
set->tool = DebugInspectorTool_None;
}
if (input_triggered_lit(input, "DebugInspectorToolTranslation")) {
debug_inspector_tool_toggle(set, DebugInspectorTool_Translation);
debug_stats_notify(stats, string_lit("Tool"), g_toolNames[set->tool]);
}
if (input_triggered_lit(input, "DebugInspectorToolRotation")) {
debug_inspector_tool_toggle(set, DebugInspectorTool_Rotation);
debug_stats_notify(stats, string_lit("Tool"), g_toolNames[set->tool]);
}
if (input_triggered_lit(input, "DebugInspectorToolScale")) {
debug_inspector_tool_toggle(set, DebugInspectorTool_Scale);
debug_stats_notify(stats, string_lit("Tool"), g_toolNames[set->tool]);
}
if (input_triggered_lit(input, "DebugInspectorDestroy")) {
debug_inspector_tool_destroy(world, sel);
debug_stats_notify(stats, string_lit("Tool"), string_lit("Destroy"));
}
if (input_triggered_lit(input, "DebugInspectorDuplicate")) {
debug_inspector_tool_duplicate(world, sel);
debug_stats_notify(stats, string_lit("Tool"), string_lit("Duplicate"));
}
if (input_triggered_lit(input, "DebugInspectorSelectAll")) {
debug_inspector_tool_select_all(world, sel);
debug_stats_notify(stats, string_lit("Tool"), string_lit("Select all"));
}

if (set->tool != DebugInspectorTool_None) {
if (input_modifiers(input) & InputModifier_Control) {
debug_inspector_tool_individual_update(world, set, sel, gizmo);
} else {
debug_inspector_tool_group_update(world, set, sel, gizmo);
}
}
}

static void inspector_vis_draw_locomotion(
DebugShapeComp* shape,
const SceneLocomotionComp* loco,
Expand Down
4 changes: 4 additions & 0 deletions libs/scene/include/scene_transform.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ ecs_comp_extern_public(SceneVelocityComp) {
GeoVector velocityAvg;
};

void scene_transform_rotate_around(SceneTransformComp*, GeoVector pivot, GeoQuat);
void scene_transform_scale_around(
SceneTransformComp*, SceneScaleComp*, GeoVector pivot, f32 scaleDelta);

GeoMatrix scene_transform_matrix(const SceneTransformComp*);
GeoMatrix scene_transform_matrix_inv(const SceneTransformComp*);

Expand Down
Loading

0 comments on commit 7db5217

Please sign in to comment.