Implemented rotation tool logic

dev
Shariq Shah 6 years ago
parent 4a6a108d06
commit a8dd4b581c
  1. 189
      src/game/editor.c
  2. 4
      src/game/editor.h
  3. 8
      todo.txt

@ -58,7 +58,8 @@ enum Editor_Axis
EDITOR_AXIS_XZ = 0, EDITOR_AXIS_XZ = 0,
EDITOR_AXIS_X, EDITOR_AXIS_X,
EDITOR_AXIS_Y, EDITOR_AXIS_Y,
EDITOR_AXIS_Z EDITOR_AXIS_Z,
EDITOR_AXIS_NONE
}; };
static struct Debug_Variable* debug_vars_list = NULL; static struct Debug_Variable* debug_vars_list = NULL;
@ -69,7 +70,8 @@ static int window_flags = NK_WINDOW_BORDER |
NK_WINDOW_SCROLL_AUTO_HIDE | NK_WINDOW_SCROLL_AUTO_HIDE |
NK_WINDOW_SCALABLE; NK_WINDOW_SCALABLE;
static void editor_on_mousebutton(const struct Event* event); static void editor_on_mousebutton_press(const struct Event* event);
static void editor_on_mousebutton_release(const struct Event* event);
static void editor_on_mousemotion(const struct Event* event); static void editor_on_mousemotion(const struct Event* event);
static void editor_on_key_release(const struct Event* event); static void editor_on_key_release(const struct Event* event);
static void editor_on_key_press(const struct Event* event); static void editor_on_key_press(const struct Event* event);
@ -120,8 +122,12 @@ void editor_init(struct Editor* editor)
editor->tool_mesh_draw_enabled = 1; editor->tool_mesh_draw_enabled = 1;
editor->tool_snap_enabled = 1; editor->tool_snap_enabled = 1;
editor->tool_rotate_arc_radius = 10.f; editor->tool_rotate_arc_radius = 10.f;
editor->tool_rotate_arc_segments = 20.f; editor->tool_rotate_arc_segments = 50.f;
editor->tool_rotate_axis_selection_enabled = true;
editor->axis_line_length = 500.f; editor->axis_line_length = 500.f;
editor->picking_enabled = true;
vec3_fill(&editor->tool_scale_amount, 0.f, 0.f, 0.f);
vec3_fill(&editor->tool_mesh_position, 0.f, 0.f, 0.f); vec3_fill(&editor->tool_mesh_position, 0.f, 0.f, 0.f);
vec4_fill(&editor->tool_mesh_color, 0.f, 1.f, 1.f, 1.f); vec4_fill(&editor->tool_mesh_color, 0.f, 1.f, 1.f, 1.f);
vec4_fill(&editor->selected_entity_colour, 0.96, 0.61, 0.17, 1.f); vec4_fill(&editor->selected_entity_colour, 0.96, 0.61, 0.17, 1.f);
@ -133,11 +139,11 @@ void editor_init(struct Editor* editor)
empty_indices = array_new(int); empty_indices = array_new(int);
struct Event_Manager* event_manager = game_state_get()->event_manager; struct Event_Manager* event_manager = game_state_get()->event_manager;
event_manager_subscribe(event_manager, EVT_MOUSEBUTTON_PRESSED, &editor_on_mousebutton); event_manager_subscribe(event_manager, EVT_MOUSEBUTTON_PRESSED, &editor_on_mousebutton_press);
event_manager_subscribe(event_manager, EVT_MOUSEBUTTON_RELEASED, &editor_on_mousebutton_release);
event_manager_subscribe(event_manager, EVT_MOUSEMOTION, &editor_on_mousemotion); event_manager_subscribe(event_manager, EVT_MOUSEMOTION, &editor_on_mousemotion);
event_manager_subscribe(event_manager, EVT_MOUSEBUTTON_RELEASED, &editor_on_mousebutton);
event_manager_subscribe(event_manager, EVT_KEY_RELEASED, &editor_on_key_release);
event_manager_subscribe(event_manager, EVT_KEY_PRESSED, &editor_on_key_press); event_manager_subscribe(event_manager, EVT_KEY_PRESSED, &editor_on_key_press);
event_manager_subscribe(event_manager, EVT_KEY_RELEASED, &editor_on_key_release);
} }
void editor_init_camera(struct Editor* editor, struct Hashmap* cvars) void editor_init_camera(struct Editor* editor, struct Hashmap* cvars)
@ -351,7 +357,7 @@ void editor_update(struct Editor* editor, float dt)
} }
nk_layout_row_push(context, 0.1f); nk_layout_row_push(context, 0.1f);
static const char* editor_axes[] = { "Axis: XZ", "Axis: X", "Axis: Y", "Axis: Z" }; static const char* editor_axes[] = { "Axis: XZ", "Axis: X", "Axis: Y", "Axis: Z", "Axis: None" };
if(nk_combo_begin_label(context, editor_axes[editor->current_axis], nk_vec2(160, 125))) if(nk_combo_begin_label(context, editor_axes[editor->current_axis], nk_vec2(160, 125)))
{ {
nk_layout_row_dynamic(context, row_height, 1); nk_layout_row_dynamic(context, row_height, 1);
@ -388,7 +394,19 @@ void editor_update(struct Editor* editor, float dt)
nk_layout_row_begin(context, NK_DYNAMIC, editor->top_panel_height - 5, 8); nk_layout_row_begin(context, NK_DYNAMIC, editor->top_panel_height - 5, 8);
nk_layout_row_push(context, 0.12f); nk_layout_row_push(context, 0.12f);
nk_labelf(context, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, "Cursor: %.1f %.1f %.1f", editor->tool_mesh_position.x, editor->tool_mesh_position.y, editor->tool_mesh_position.z); switch(editor->current_mode)
{
case EDITOR_MODE_NORMAL:
case EDITOR_MODE_TRANSLATE:
nk_labelf(context, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, "Position at: %.1f %.1f %.1f", editor->tool_mesh_position.x, editor->tool_mesh_position.y, editor->tool_mesh_position.z);
break;
case EDITOR_MODE_ROTATE:
nk_labelf(context, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, "Rotation by: %.1f", editor->tool_rotate_amount);
break;
case EDITOR_MODE_SCALE:
nk_labelf(context, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, "Scale to: %.1f %.1f %.1f", editor->tool_scale_amount.x, editor->tool_scale_amount.y, editor->tool_scale_amount.z);
break;
}
nk_layout_row_push(context, 0.1f); nk_layout_row_push(context, 0.1f);
nk_checkbox_label(context, "Snap to grid ", &editor->tool_snap_enabled); nk_checkbox_label(context, "Snap to grid ", &editor->tool_snap_enabled);
@ -460,10 +478,35 @@ void editor_update(struct Editor* editor, float dt)
case EDITOR_MODE_ROTATE: case EDITOR_MODE_ROTATE:
{ {
quat rotation = { 0.f, 0.f, 0.f, 1.f }; quat rotation = { 0.f, 0.f, 0.f, 1.f };
quat_axis_angle(&rotation, &UNIT_X, -90.f);
vec3 scale = { 1.f, 1.f, 1.f }; vec3 scale = { 1.f, 1.f, 1.f };
//im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, editor->axis_color_x, 3); im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, editor->axis_color_z, 3);
im_arc(editor->tool_rotate_arc_radius, 0.f, 90.f, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, editor->axis_color_y, 3); //im_arc(editor->tool_rotate_arc_radius, 0.f, 90.f, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, editor->axis_color_z, 3);
quat_axis_angle(&rotation, &UNIT_X, -90.f);
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, editor->axis_color_y, 3);
//im_arc(editor->tool_rotate_arc_radius, 90.f, 180.f, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, editor->axis_color_y, 3);
quat_identity(&rotation);
quat_axis_angle(&rotation, &UNIT_Y, -90.f);
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, editor->axis_color_x, 3);
//im_arc(editor->tool_rotate_arc_radius, 0.f, 90.f, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, editor->axis_color_x, 3);
if(editor->current_axis != EDITOR_AXIS_NONE)
{
quat_identity(&rotation);
vec4 arc_color = { 1.f, 1.f, 1.f, 1.f };
switch(editor->current_axis)
{
case EDITOR_AXIS_X: quat_axis_angle(&rotation, &UNIT_Y, -90.f); vec4_assign(&arc_color, &editor->axis_color_x); break;
case EDITOR_AXIS_Y: quat_axis_angle(&rotation, &UNIT_X, -90.f); vec4_assign(&arc_color, &editor->axis_color_y) ;break;
case EDITOR_AXIS_Z: vec4_assign(&arc_color, &editor->axis_color_z); break;
}
if(editor->tool_rotate_amount == 0.f)
im_arc(editor->tool_rotate_arc_radius / 2.f, 0.f, 1.f, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, arc_color, 2);
else
im_arc(editor->tool_rotate_arc_radius / 2.f, 0.f, editor->tool_rotate_amount, editor->tool_rotate_arc_segments, editor->tool_mesh_position, rotation, arc_color, 3);
}
} }
break; break;
@ -471,20 +514,20 @@ void editor_update(struct Editor* editor, float dt)
} }
} }
void editor_on_mousebutton(const struct Event* event) void editor_on_mousebutton_release(const struct Event* event)
{ {
assert(event->type == EVT_MOUSEBUTTON_PRESSED || event->type == EVT_MOUSEBUTTON_RELEASED);
struct Game_State* game_state = game_state_get(); struct Game_State* game_state = game_state_get();
struct Editor* editor = game_state->editor; struct Editor* editor = game_state->editor;
struct Gui* gui = game_state->gui; struct Gui* gui = game_state->gui;
if(game_state->game_mode != GAME_MODE_EDITOR) if(game_state->game_mode != GAME_MODE_EDITOR)
return; return;
if(event->mousebutton.button == MSB_LEFT && if(event->mousebutton.button == MSB_LEFT &&
event->type == EVT_MOUSEBUTTON_RELEASED &&
!editor->camera_looking_around && !editor->camera_looking_around &&
nk_item_is_any_active(&gui->context) == 0) nk_item_is_any_active(&gui->context) == 0)
{
if(editor->picking_enabled)
{ {
log_message("Editor Picking"); log_message("Editor Picking");
struct Camera* editor_camera = &game_state_get()->scene->cameras[CAM_EDITOR]; struct Camera* editor_camera = &game_state_get()->scene->cameras[CAM_EDITOR];
@ -504,23 +547,67 @@ void editor_on_mousebutton(const struct Event* event)
} }
else else
{ {
if(editor->selected_entity) //Deselect the currently selected entity if nothing was found
if(editor->current_axis == EDITOR_AXIS_NONE)
editor_entity_select(editor, NULL);
}
}
}
if(editor->selected_entity && event->mousebutton.button == MSB_LEFT)
{ {
if(editor->current_mode == EDITOR_MODE_TRANSLATE) if(editor->current_mode == EDITOR_MODE_TRANSLATE)
{ {
//transform_set_position(editor->selected_entity, &editor->tool_mesh_position); if(editor->current_axis != EDITOR_AXIS_NONE)
{
vec3 translation = { 0.f, 0.f, 0.f }; vec3 translation = { 0.f, 0.f, 0.f };
vec3 current_position = { 0.f, 0.f, 0.f }; vec3 current_position = { 0.f, 0.f, 0.f };
transform_get_absolute_position(editor->selected_entity, &current_position); transform_get_absolute_position(editor->selected_entity, &current_position);
vec3_sub(&translation, &editor->tool_mesh_position, &current_position); vec3_sub(&translation, &editor->tool_mesh_position, &current_position);
//transform_translate(editor->selected_entity, &translation, editor->current_transform_space);
transform_translate(editor->selected_entity, &translation, TS_WORLD); transform_translate(editor->selected_entity, &translation, TS_WORLD);
} }
else }
else if(editor->current_mode == EDITOR_MODE_ROTATE)
{ {
//Deselect the currently selected entity if nothing was found if(!editor->tool_rotate_axis_selection_enabled)
editor_entity_select(editor, NULL); {
editor->tool_rotate_axis_selection_enabled = true;
editor->picking_enabled = true;
if(editor->tool_rotate_amount != 0.f)
{
vec3 axis = { 0.f, 0.f, 0.f };
switch(editor->current_axis)
{
case EDITOR_AXIS_X: vec3_assign(&axis, &UNIT_X); break;
case EDITOR_AXIS_Y: vec3_assign(&axis, &UNIT_Y); break;
case EDITOR_AXIS_Z: vec3_assign(&axis, &UNIT_Z); break;
} }
transform_rotate(editor->selected_entity, &axis, editor->tool_rotate_amount, TS_WORLD);
editor->tool_rotate_amount = 0.f;
}
}
}
}
}
void editor_on_mousebutton_press(const struct Event* event)
{
struct Game_State* game_state = game_state_get();
struct Editor* editor = game_state->editor;
struct Gui* gui = game_state->gui;
if(game_state->game_mode != GAME_MODE_EDITOR)
return;
if(event->mousebutton.button == MSB_LEFT && event->type == EVT_MOUSEBUTTON_PRESSED && editor->selected_entity)
{
if(editor->current_mode == EDITOR_MODE_ROTATE)
{
if(editor->tool_rotate_axis_selection_enabled)
{
editor->tool_rotate_axis_selection_enabled = false;
editor->picking_enabled = false;
} }
} }
} }
@ -581,6 +668,54 @@ void editor_on_mousemotion(const struct Event* event)
} }
} }
break; break;
case EDITOR_MODE_ROTATE:
{
/* Select Axis to rotate on */
if(editor->selected_entity && editor->tool_rotate_axis_selection_enabled)
{
struct Camera* editor_camera = &game_state->scene->cameras[CAM_EDITOR];
vec3 position = { 0.f };
transform_get_absolute_position(editor->selected_entity, &position);
struct Ray cam_ray;
cam_ray = camera_screen_coord_to_ray(editor_camera, event->mousemotion.x, event->mousemotion.y);
struct Bounding_Sphere gizmo_sphere;
//vec3_assign(&gizmo_sphere.center, &position);
gizmo_sphere.center = (vec3) { 0.f, 0.f, 0.f };
gizmo_sphere.radius = editor->tool_rotate_arc_radius;
if(bv_intersect_sphere_ray(&gizmo_sphere, &position, &cam_ray))
{
Plane ground_plane;
plane_init(&ground_plane, &UNIT_X, &position);
float distance_x = bv_distance_ray_plane(&cam_ray, &ground_plane);
plane_init(&ground_plane, &UNIT_Y, &position);
float distance_y = bv_distance_ray_plane(&cam_ray, &ground_plane);
plane_init(&ground_plane, &UNIT_Z, &position);
float distance_z = bv_distance_ray_plane(&cam_ray, &ground_plane);
//Determine the closest plane
log_message("X: %.3f Y: %.3f Z: %.3f", distance_x, distance_y, distance_z);
float shortest_distance = distance_x < distance_y ? distance_x : distance_y;
shortest_distance = shortest_distance < distance_z ? shortest_distance : distance_z;
if(shortest_distance == distance_x) editor->current_axis = EDITOR_AXIS_X;
if(shortest_distance == distance_y) editor->current_axis = EDITOR_AXIS_Y;
if(shortest_distance == distance_z) editor->current_axis = EDITOR_AXIS_Z;
}
else
{
editor->current_axis = EDITOR_AXIS_NONE;
}
}
else /* Rotate on selected axis */
{
editor->tool_rotate_amount += editor->current_axis == EDITOR_AXIS_X ? event->mousemotion.xrel / 2 : -event->mousemotion.xrel / 2;
}
}
break;
default: break; default: break;
} }
} }
@ -648,6 +783,14 @@ void editor_mode_set(struct Editor* editor, int mode)
transform_get_absolute_position(editor->selected_entity, &editor->tool_mesh_position); transform_get_absolute_position(editor->selected_entity, &editor->tool_mesh_position);
else else
vec3_fill(&editor->tool_mesh_position, 0.f, 0.f, 0.f); vec3_fill(&editor->tool_mesh_position, 0.f, 0.f, 0.f);
editor->tool_rotate_amount = 0.f;
editor->tool_rotate_axis_selection_enabled = true;
editor->picking_enabled = true;
if(mode == EDITOR_MODE_TRANSLATE)
editor_axis_set(editor, EDITOR_AXIS_XZ);
else
editor_axis_set(editor, EDITOR_AXIS_NONE);
} }
void editor_entity_select(struct Editor* editor, struct Entity* entity) void editor_entity_select(struct Editor* editor, struct Entity* entity)
@ -865,8 +1008,8 @@ void editor_widget_color_combov4(struct nk_context* context, vec4* color, int wi
void editor_cleanup(struct Editor* editor) void editor_cleanup(struct Editor* editor)
{ {
event_manager_unsubscribe(game_state_get()->event_manager, EVT_MOUSEBUTTON_PRESSED, &editor_on_mousebutton); event_manager_unsubscribe(game_state_get()->event_manager, EVT_MOUSEBUTTON_PRESSED, &editor_on_mousebutton_press);
event_manager_unsubscribe(game_state_get()->event_manager, EVT_MOUSEBUTTON_RELEASED, &editor_on_mousebutton); event_manager_unsubscribe(game_state_get()->event_manager, EVT_MOUSEBUTTON_RELEASED, &editor_on_mousebutton_press);
for(int i = 0; i < array_len(debug_vars_list); i++) for(int i = 0; i < array_len(debug_vars_list); i++)
editor_debugvar_slot_remove(i); editor_debugvar_slot_remove(i);
array_free(debug_vars_list); array_free(debug_vars_list);

@ -36,10 +36,14 @@ struct Editor
int tool_mesh_draw_enabled; int tool_mesh_draw_enabled;
float tool_rotate_arc_radius; float tool_rotate_arc_radius;
int tool_rotate_arc_segments; int tool_rotate_arc_segments;
bool tool_rotate_axis_selection_enabled;
float tool_rotate_amount;
vec3 tool_scale_amount;
float axis_line_length; float axis_line_length;
vec4 axis_color_x; vec4 axis_color_x;
vec4 axis_color_y; vec4 axis_color_y;
vec4 axis_color_z; vec4 axis_color_z;
bool picking_enabled;
}; };
void editor_init(struct Editor* editor_state); void editor_init(struct Editor* editor_state);

@ -1,13 +1,21 @@
Todo: Todo:
- Impement im_filled_circle
- Draw rotation gizmo using filled circles to better reflect the underlying logic
- Match amount to be rotate with actual axes and the gizmo arc being drawn
- Handle negative values in im_arc
- Rotate mode tool widget - Rotate mode tool widget
- Complete rotate mode - Complete rotate mode
- Handle all other axes combinations
- Better, more accurate picking - Better, more accurate picking
- Highlight if we are about to select an entity or perform the tool action like translate when mouse is hovered and an entity can be selected at that location - Highlight if we are about to select an entity or perform the tool action like translate when mouse is hovered and an entity can be selected at that location
- Display the projected position if we perform the action for example display what the new location would be right next to the tool mesh - Display the projected position if we perform the action for example display what the new location would be right next to the tool mesh
? Disable entity picking when tool is in use or only allow picking when pressing ALT
- Disable editor event recievers on game mode change
- Editor Undo - Editor Undo
- Scale Mode - Scale Mode
- Color picker - Color picker
- Color palette, picker and dropper - Color palette, picker and dropper
- Mouse warp to opposite side of the window when it reaches bounds
- Add other axis combinations like YZ and XY to transform tool - Add other axis combinations like YZ and XY to transform tool
- Transformation space selection for translation, rotation and scale. - Transformation space selection for translation, rotation and scale.
- Use actual selected entity's mesh for tool mesh when the entity already has a mesh and use a placeholder like a sphere when there is not mesh - Use actual selected entity's mesh for tool mesh when the entity already has a mesh and use a placeholder like a sphere when there is not mesh

Loading…
Cancel
Save