You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2506 lines
102 KiB
2506 lines
102 KiB
#include "editor.h"
|
|
#include "renderer.h"
|
|
#include "gl_load.h"
|
|
#include "../common/log.h"
|
|
#include "camera.h"
|
|
#include "model.h"
|
|
#include "texture.h"
|
|
#include "framebuffer.h"
|
|
#include "../common/array.h"
|
|
#include "../common/hashmap.h"
|
|
#include "shader.h"
|
|
#include "../common/num_types.h"
|
|
#include "light.h"
|
|
#include "entity.h"
|
|
#include "transform.h"
|
|
#include "game.h"
|
|
#include "gui.h"
|
|
#include "../common/array.h"
|
|
#include "../common/variant.h"
|
|
#include "../common/num_types.h"
|
|
#include "../common/string_utils.h"
|
|
#include "bounding_volumes.h"
|
|
#include "input.h"
|
|
#include "scene.h"
|
|
#include "../system/file_io.h"
|
|
#include "../system/config_vars.h"
|
|
#include "../system/platform.h"
|
|
#include "event.h"
|
|
#include "im_render.h"
|
|
#include "geometry.h"
|
|
#include "gui.h"
|
|
#include "console.h"
|
|
#include "debug_vars.h"
|
|
#include "../common/version.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
|
|
#define LABEL_FLAGS_ALIGN_LEFT NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_LEFT
|
|
#define LABEL_FLAGS_ALIGN_RIGHT NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_RIGHT
|
|
|
|
enum Editor_Tool
|
|
{
|
|
EDITOR_TOOL_NORMAL = 0,
|
|
EDITOR_TOOL_TRANSLATE,
|
|
EDITOR_TOOL_ROTATE,
|
|
EDITOR_TOOL_SCALE,
|
|
EDITOR_TOOL_MAX
|
|
};
|
|
|
|
enum Editor_Axis
|
|
{
|
|
EDITOR_AXIS_NONE = 0,
|
|
EDITOR_AXIS_X,
|
|
EDITOR_AXIS_Y,
|
|
EDITOR_AXIS_Z,
|
|
EDITOR_AXIS_XZ,
|
|
EDITOR_AXIS_XY,
|
|
EDITOR_AXIS_YZ,
|
|
};
|
|
|
|
static int window_flags = NK_WINDOW_BORDER |
|
|
NK_WINDOW_CLOSABLE |
|
|
NK_WINDOW_MOVABLE |
|
|
NK_WINDOW_SCROLL_AUTO_HIDE |
|
|
NK_WINDOW_SCALABLE;
|
|
|
|
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_key_release(const struct Event* event);
|
|
static void editor_on_key_press(const struct Event* event);
|
|
static void editor_camera_update(struct Editor* editor, float dt);
|
|
static void editor_show_entity_in_list(struct Editor* editor, struct nk_context* context, struct Scene* scene, struct Entity* entity);
|
|
static void editor_widget_color_combov3(struct nk_context* context, vec3* color, int width, int height);
|
|
static void editor_widget_color_combov4(struct nk_context* context, vec4* color, int width, int height);
|
|
static bool editor_widget_v3(struct nk_context* context,
|
|
vec3* value,
|
|
const char* name_x,
|
|
const char* name_y,
|
|
const char* name_z,
|
|
float min,
|
|
float max,
|
|
float step,
|
|
float inc_per_pixel,
|
|
int row_height);
|
|
static bool editor_widget_v2(struct nk_context* context,
|
|
vec2* value,
|
|
const char* name_x,
|
|
const char* name_y,
|
|
float min,
|
|
float max,
|
|
float step,
|
|
float inc_per_pixel,
|
|
int row_height);
|
|
|
|
static void editor_window_scene_hierarchy(struct nk_context* context, struct Editor* editor, struct Game_State* game_state);
|
|
static void editor_window_property_inspector(struct nk_context* context, struct Editor* editor, struct Game_State* game_state);
|
|
static void editor_window_renderer_settings(struct nk_context* context, struct Editor* editor, struct Game_State* game_state);
|
|
static void editor_window_settings_editor(struct nk_context* context, struct Editor* editor, struct Game_State* game_state);
|
|
static void editor_axis_set(struct Editor* editor, int axis);
|
|
static void editor_entity_select(struct Editor* editor, struct Entity* entity);
|
|
static void editor_tool_set(struct Editor* editor, int mode);
|
|
static void editor_tool_reset(struct Editor* editor);
|
|
static void editor_scene_dialog(struct Editor* editor, struct nk_context* context);
|
|
static void editor_entity_dialog(struct Editor* editor, struct nk_context* context);
|
|
|
|
void editor_init(struct Editor* editor)
|
|
{
|
|
editor->window_settings_renderer = 0;
|
|
editor->window_settings_editor = 0;
|
|
editor->window_property_inspector = 0;
|
|
editor->window_scene_heirarchy = 0;
|
|
editor->window_scene_dialog = 0;
|
|
editor->window_entity_dialog = 0;
|
|
editor->camera_looking_around = 0;
|
|
editor->selected_entity = NULL;
|
|
editor->hovered_entity = NULL;
|
|
editor->top_panel_height = 30;
|
|
editor->camera_turn_speed = 90.f;
|
|
editor->camera_move_speed = 20.f;
|
|
editor->camera_sprint_multiplier = 2.f;
|
|
editor->current_tool = EDITOR_TOOL_NORMAL;
|
|
editor->current_axis = EDITOR_AXIS_NONE;
|
|
editor->previous_axis = EDITOR_AXIS_NONE;
|
|
editor->grid_enabled = 1;
|
|
editor->grid_relative = 1;
|
|
editor->grid_num_lines = 100;
|
|
editor->grid_scale = 1.f;
|
|
editor->tool_mesh_draw_enabled = 1;
|
|
editor->tool_snap_enabled = 1;
|
|
editor->tool_rotate_amount = 0.f;
|
|
editor->tool_rotate_increment = 5.f;
|
|
editor->tool_rotate_arc_radius = 5.f;
|
|
editor->tool_rotate_arc_segments = 20.f;
|
|
editor->tool_rotate_starting_rotation = 0.f;
|
|
editor->tool_rotate_rotation_started = false;
|
|
editor->tool_rotate_allowed = false;
|
|
editor->axis_line_length = 500.f;
|
|
editor->picking_enabled = true;
|
|
editor->draw_cursor_entity = false;
|
|
editor->tool_scale_started = false;
|
|
editor->tool_translate_allowed = false;
|
|
editor->entity_operation_save = false;
|
|
editor->scene_operation_save = false;
|
|
|
|
vec4_fill(&editor->cursor_entity_color, 0.f, 1.f, 1.f, 0.5f);
|
|
vec4_fill(&editor->hovered_entity_color, 0.53, 0.87, 0.28, 0.2f);
|
|
vec4_fill(&editor->selected_entity_color, 0.96, 0.61, 0.17, 0.5f);
|
|
vec4_fill(&editor->grid_color, 0.3f, 0.3f, 0.3f, 0.7f);
|
|
vec4_fill(&editor->axis_color_x, 0.87, 0.32, 0.40, 0.8f);
|
|
vec4_fill(&editor->axis_color_y, 0.53, 0.67, 0.28, 0.8f);
|
|
vec4_fill(&editor->axis_color_z, 0.47, 0.67, 0.89, 0.8f);
|
|
vec3_fill(&editor->tool_scale_amount, 1.f, 1.f, 1.f);
|
|
|
|
struct Event_Manager* event_manager = game_state_get()->event_manager;
|
|
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_KEY_PRESSED, &editor_on_key_press);
|
|
event_manager_subscribe(event_manager, EVT_KEY_RELEASED, &editor_on_key_release);
|
|
}
|
|
|
|
void editor_init_entities(struct Editor* editor)
|
|
{
|
|
editor->selected_entity = NULL;
|
|
editor->cursor_entity = scene_static_mesh_create(game_state_get()->scene, "EDITOR_SELECTED_ENTITY_WIREFRAME", NULL, "sphere.symbres", MAT_UNSHADED);
|
|
editor->cursor_entity->base.flags |= EF_TRANSIENT | EF_SKIP_RENDER | EF_HIDE_IN_EDITOR_SCENE_HIERARCHY | EF_IGNORE_RAYCAST;
|
|
}
|
|
|
|
void editor_camera_init(struct Editor* editor, struct Hashmap* cvars)
|
|
{
|
|
struct Camera* editor_camera = &game_state_get()->scene->cameras[CAM_EDITOR];
|
|
entity_rename(editor_camera, "Editor_Camera");
|
|
editor_camera->base.flags |= EF_ACTIVE | EF_TRANSIENT | EF_IGNORE_RAYCAST;
|
|
editor_camera->clear_color.x = 0.3f;
|
|
editor_camera->clear_color.y = 0.6f;
|
|
editor_camera->clear_color.z = 0.9f;
|
|
editor_camera->clear_color.w = 1.f;
|
|
|
|
//if(editor_camera->fbo == -1)
|
|
//{
|
|
// int render_width = hashmap_int_get(cvars, "render_width");
|
|
// int render_height = hashmap_int_get(cvars, "render_height");
|
|
// window_get_drawable_size(game_state_get()->window, &render_width, &render_height);
|
|
// camera_attach_fbo(editor_camera, render_width, render_height, true, true, true);
|
|
//}
|
|
|
|
vec3 cam_pos = {5.f, 20.f, 50.f};
|
|
transform_translate(editor_camera, &cam_pos, TS_WORLD);
|
|
}
|
|
|
|
void editor_render(struct Editor* editor, struct Camera * active_camera)
|
|
{
|
|
struct Game_State* game_state = game_state_get();
|
|
struct Renderer* renderer = game_state->renderer;
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LEQUAL);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_BLEND);
|
|
|
|
if(game_state->editor->selected_entity)
|
|
{
|
|
/* Visualize entity specific state */
|
|
vec3 abs_pos;
|
|
quat abs_rot;
|
|
transform_get_absolute_position(editor->selected_entity, &abs_pos);
|
|
transform_get_absolute_rot(editor->selected_entity, &abs_rot);
|
|
switch(editor->selected_entity->type)
|
|
{
|
|
case ET_LIGHT:
|
|
{
|
|
struct Light* light = (struct Light*)editor->selected_entity;
|
|
if(light->type != LT_POINT)
|
|
{
|
|
struct Ray light_ray;
|
|
vec3_assign(&light_ray.origin, &abs_pos);
|
|
transform_get_absolute_forward(light, &light_ray.direction);
|
|
im_ray(&light_ray, 5.f, editor->cursor_entity_color, 3);
|
|
}
|
|
|
|
if(light->type != LT_DIR)
|
|
{
|
|
quat rotation = editor->selected_entity->transform.rotation;
|
|
vec3 axis = { 1.f, 0.f, 0.f };
|
|
quat_axis_angle(&rotation, &axis, 90.f);
|
|
im_circle(light->radius, 30, false, abs_pos, rotation, editor->cursor_entity_color, 3);
|
|
|
|
if(light->type == LT_SPOT)
|
|
{
|
|
float yaw = quat_get_yaw(&abs_rot);
|
|
float half_outer_angle = light->outer_angle / 2.f;
|
|
float half_inner_angle = light->inner_angle / 2.f;
|
|
im_arc(light->radius, yaw - half_outer_angle, yaw + half_outer_angle, 15, false, abs_pos, rotation, editor->selected_entity_color, 3);
|
|
im_arc(light->radius, yaw - half_inner_angle, yaw + half_inner_angle, 15, false, abs_pos, rotation, editor->cursor_entity_color, 4);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Draw bounding box for selected entity */
|
|
static vec3 vertices[24];
|
|
bv_bounding_box_vertices_get_line_visualization(&editor->selected_entity->derived_bounding_box, vertices);
|
|
for(int i = 0; i <= 22; i += 2)
|
|
im_line(vertices[i], vertices[i + 1], (vec3) { 0.f, 0.f, 0.f }, (quat) { 0.f, 0.f, 0.f, 1.f }, editor->cursor_entity_color, 3);
|
|
|
|
/* Draw selected entity with projected transformation applied */
|
|
if(editor->draw_cursor_entity)
|
|
{
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
shader_bind(renderer->debug_shader);
|
|
{
|
|
static mat4 mvp;
|
|
shader_set_uniform_vec4(renderer->debug_shader, "debug_color", &editor->cursor_entity_color);
|
|
struct Static_Mesh* mesh = editor->cursor_entity;
|
|
struct Model* model = editor->selected_entity->type == ET_STATIC_MESH ? &((struct Static_Mesh*)editor->selected_entity)->model : &mesh->model;
|
|
struct Transform* transform = &mesh->base.transform;
|
|
int geometry = model->geometry_index;
|
|
mat4_identity(&mvp);
|
|
mat4_mul(&mvp, &active_camera->view_proj_mat, &transform->trans_mat);
|
|
shader_set_uniform_mat4(renderer->debug_shader, "mvp", &mvp);
|
|
geom_render(geometry, GDM_TRIANGLES);
|
|
}
|
|
shader_unbind();
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
}
|
|
}
|
|
|
|
/* If cursor is hovering over an entity, draw it*/
|
|
if(editor->hovered_entity)
|
|
{
|
|
if(editor->hovered_entity->type == ET_STATIC_MESH)
|
|
{
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
shader_bind(renderer->debug_shader);
|
|
{
|
|
static mat4 mvp;
|
|
shader_set_uniform_vec4(renderer->debug_shader, "debug_color", &editor->hovered_entity_color);
|
|
struct Static_Mesh* mesh = editor->hovered_entity;
|
|
struct Model* model = &mesh->model;
|
|
struct Transform* transform = &mesh->base.transform;
|
|
int geometry = model->geometry_index;
|
|
mat4_identity(&mvp);
|
|
mat4_mul(&mvp, &active_camera->view_proj_mat, &transform->trans_mat);
|
|
shader_set_uniform_mat4(renderer->debug_shader, "mvp", &mvp);
|
|
geom_render(geometry, GDM_TRIANGLES);
|
|
}
|
|
shader_unbind();
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
}
|
|
else
|
|
{
|
|
vec3 abs_pos;
|
|
quat abs_rot;
|
|
transform_get_absolute_position(editor->hovered_entity, &abs_pos);
|
|
transform_get_absolute_rot(editor->hovered_entity, &abs_rot);
|
|
im_sphere(1.f, abs_pos, abs_rot, editor->hovered_entity_color, GDM_TRIANGLES, 4);
|
|
}
|
|
}
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_BLEND);
|
|
|
|
|
|
vec3 position = { 0.f, 0.f, 0.f };
|
|
quat rotation = { 0.f, 0.f, 0.f, 1.f };
|
|
vec3 scale = { 1.f, 1.f, 1.f };
|
|
|
|
float half_axis_line_length = editor->axis_line_length / 2.f;
|
|
|
|
im_line((vec3) { -half_axis_line_length, 0.f, 0.f }, (vec3) { half_axis_line_length, 0.f, 0.f }, position, rotation, editor->axis_color_x, 1); // X Axis
|
|
im_line((vec3) { 0.f, -half_axis_line_length, 0.f }, (vec3) { 0.f, half_axis_line_length, 0.f }, position, rotation, editor->axis_color_y, 1); // Y Axis
|
|
im_line((vec3) { 0.f, 0.f, -half_axis_line_length }, (vec3) { 0.f, 0.f, half_axis_line_length }, position, rotation, editor->axis_color_z, 1); // Z Axis
|
|
|
|
//Draw Grid
|
|
if(editor->grid_enabled)
|
|
{
|
|
if(editor->grid_relative && editor->selected_entity)
|
|
{
|
|
transform_get_absolute_position(editor->selected_entity, &position);
|
|
}
|
|
|
|
im_begin(position, rotation, scale, editor->grid_color, GDM_LINES, 0);
|
|
|
|
float half_grid = editor->grid_num_lines * editor->grid_scale / 2.f;
|
|
for(float i = 0; i <= editor->grid_num_lines * editor->grid_scale; i += editor->grid_scale)
|
|
{
|
|
im_pos(-half_grid, 0.f, -half_grid + i); im_pos(half_grid, 0.f, -half_grid + i); // X
|
|
im_pos(-half_grid + i, 0.f, -half_grid); im_pos(-half_grid + i, 0.f, half_grid); // Z
|
|
}
|
|
|
|
im_end();
|
|
}
|
|
}
|
|
|
|
void editor_update(struct Editor* editor, float dt)
|
|
{
|
|
editor_camera_update(editor, dt);
|
|
|
|
struct Game_State* game_state = game_state_get();
|
|
struct nk_context* context = &game_state->gui->context;
|
|
int win_width = 0, win_height = 0;
|
|
window_get_drawable_size(game_state->window, &win_width, &win_height);
|
|
int half_width = win_width / 2, half_height = win_height / 2;
|
|
|
|
/* Top Panel */
|
|
if(nk_begin(context, "Top Panel", nk_recti(0, 0, win_width, editor->top_panel_height), NK_WINDOW_NO_SCROLLBAR))
|
|
{
|
|
const int row_height = 25.f;
|
|
nk_menubar_begin(context);
|
|
|
|
nk_layout_row_begin(context, NK_DYNAMIC, editor->top_panel_height - 5, 8);
|
|
nk_layout_row_push(context, 0.03f);
|
|
if(nk_menu_begin_label(context, "File", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, nk_vec2(150, 150)))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
if(nk_menu_item_label(context, "New Scene", NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_LEFT))
|
|
{
|
|
struct Scene* scene = game_state->scene;
|
|
scene_destroy(scene);
|
|
scene_post_update(scene);
|
|
scene_init(scene);
|
|
}
|
|
|
|
if(nk_menu_item_label(context, "Load Scene", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE))
|
|
{
|
|
editor->window_scene_dialog = editor->window_scene_dialog == 0 ? 1 : 0;
|
|
editor->scene_operation_save = false;
|
|
}
|
|
|
|
if(nk_menu_item_label(context, "Save Scene", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE))
|
|
{
|
|
editor->window_scene_dialog = editor->window_scene_dialog == 0 ? 1 : 0;
|
|
editor->scene_operation_save = true;
|
|
}
|
|
|
|
if(nk_menu_item_label(context, "Load Entity", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE))
|
|
{
|
|
editor->window_entity_dialog = editor->window_entity_dialog == 0 ? 1 : 0;
|
|
editor->entity_operation_save = false;
|
|
}
|
|
|
|
if(nk_menu_item_label(context, "Save Entity", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE))
|
|
{
|
|
editor->window_entity_dialog = editor->window_entity_dialog == 0 ? 1 : 0;
|
|
editor->entity_operation_save = true;
|
|
}
|
|
|
|
if(nk_menu_item_label(context, "Back to Game", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE))
|
|
{
|
|
game_state->game_mode = GAME_MODE_GAME;
|
|
game_state->scene->active_camera_index = CAM_GAME;
|
|
}
|
|
nk_menu_end(context);
|
|
}
|
|
|
|
nk_layout_row_push(context, 0.05f);
|
|
if(nk_menu_begin_label(context, "Settings", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, nk_vec2(150, 100)))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
if(nk_menu_item_label(context, "Editor Settings", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE)) editor->window_settings_editor = !editor->window_settings_editor;
|
|
if(nk_menu_item_label(context, "Render Settings", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE)) editor->window_settings_renderer = !editor->window_settings_renderer;
|
|
nk_menu_end(context);
|
|
}
|
|
|
|
nk_layout_row_push(context, 0.05f);
|
|
if(nk_menu_begin_label(context, "Windows", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, nk_vec2(180, 100)))
|
|
{
|
|
struct Debug_Vars* debug_vars = game_state->debug_vars;
|
|
int debug_vars_visible = debug_vars->visible;
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_checkbox_label(context, "Scene Heirarchy", &editor->window_scene_heirarchy);
|
|
|
|
|
|
nk_checkbox_label(context, "Property Inspector", &editor->window_property_inspector);
|
|
nk_checkbox_label(context, "Debug Variables", &debug_vars_visible);
|
|
if(debug_vars_visible != (int)debug_vars->visible)
|
|
debug_vars->visible = (bool)debug_vars_visible;
|
|
nk_menu_end(context);
|
|
}
|
|
|
|
nk_layout_row_push(context, 0.45f);
|
|
nk_spacing(context, 1);
|
|
|
|
nk_layout_row_push(context, 0.15f);
|
|
static const char* editor_transformation_tools[] = { "Tool: Normal", "Tool: Translate", "Tool: Rotate", "Tool: Scale" };
|
|
if(nk_combo_begin_label(context, editor_transformation_tools[editor->current_tool], nk_vec2(160, 125)))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
int tool = editor->current_tool;
|
|
tool = nk_option_label(context, "Normal", tool == EDITOR_TOOL_NORMAL) ? EDITOR_TOOL_NORMAL : tool;
|
|
tool = nk_option_label(context, "Translate", tool == EDITOR_TOOL_TRANSLATE) ? EDITOR_TOOL_TRANSLATE : tool;
|
|
tool = nk_option_label(context, "Rotate", tool == EDITOR_TOOL_ROTATE) ? EDITOR_TOOL_ROTATE : tool;
|
|
tool = nk_option_label(context, "Scale", tool == EDITOR_TOOL_SCALE) ? EDITOR_TOOL_SCALE : tool;
|
|
editor_tool_set(editor, tool);
|
|
nk_combo_end(context);
|
|
}
|
|
|
|
nk_layout_row_push(context, 0.1f);
|
|
static const char* editor_axes[] = { "Axis: None", "Axis: X", "Axis: Y", "Axis: Z", "Axis: XZ", "Axis: XY", "Axis: YZ" };
|
|
if(nk_combo_begin_label(context, editor_axes[editor->current_axis], nk_vec2(160, 125)))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
int axis = editor->current_axis;
|
|
axis = nk_option_label(context, "X", axis == EDITOR_AXIS_X) ? EDITOR_AXIS_X : axis;
|
|
axis = nk_option_label(context, "Y", axis == EDITOR_AXIS_Y) ? EDITOR_AXIS_Y : axis;
|
|
axis = nk_option_label(context, "Z", axis == EDITOR_AXIS_Z) ? EDITOR_AXIS_Z : axis;
|
|
if(editor->current_tool != EDITOR_TOOL_ROTATE)
|
|
{
|
|
axis = nk_option_label(context, "XZ", axis == EDITOR_AXIS_XZ) ? EDITOR_AXIS_XZ : axis;
|
|
axis = nk_option_label(context, "XY", axis == EDITOR_AXIS_XY) ? EDITOR_AXIS_XY : axis;
|
|
axis = nk_option_label(context, "YZ", axis == EDITOR_AXIS_YZ) ? EDITOR_AXIS_YZ : axis;
|
|
}
|
|
axis = nk_option_label(context, "None", axis == EDITOR_AXIS_NONE) ? EDITOR_AXIS_NONE : axis;
|
|
if(axis != editor->current_axis) editor_axis_set(editor, axis);
|
|
nk_combo_end(context);
|
|
}
|
|
|
|
nk_layout_row_push(context, 0.17f);
|
|
vec3 camera_position = { 0.f, 0.f, 0.f };
|
|
transform_get_absolute_position(&game_state->scene->cameras[CAM_EDITOR], &camera_position);
|
|
static char position_text[32];
|
|
snprintf(position_text, 32, "Camera: %.1f %.1f %.1f", camera_position.x, camera_position.y, camera_position.z);
|
|
if(nk_combo_begin_label(context, position_text, nk_vec2(200, 125)))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
editor->camera_move_speed = nk_propertyf(context, "Move Speed", 1.f, editor->camera_move_speed, 100.f, 1.f, 0.5f);
|
|
editor->camera_turn_speed = nk_propertyf(context, "Turn Speed", 5.f, editor->camera_turn_speed, 200.f, 1.f, 0.5f);
|
|
|
|
nk_combo_end(context);
|
|
}
|
|
|
|
nk_menubar_end(context);
|
|
|
|
/* Tooltip for current action or entity being hovered */
|
|
if(!nk_window_is_any_hovered(context))
|
|
{
|
|
nk_byte previous_opacity = context->style.window.background.a;
|
|
context->style.window.background.a = 150;
|
|
nk_flags alignment_flags_left = NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_LEFT;
|
|
nk_flags alignment_flags_right = NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_RIGHT;
|
|
nk_flags alignment_flags_center = NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_CENTERED;
|
|
float tooltip_width = 250.f;
|
|
|
|
if(editor->hovered_entity)
|
|
{
|
|
if(nk_tooltip_begin(context, tooltip_width))
|
|
{
|
|
nk_layout_row_dynamic(context, 20, 2);
|
|
nk_label(context, "Hovered Entity: ", alignment_flags_left); nk_label_colored(context, editor->hovered_entity->name, alignment_flags_right, nk_rgba_fv(&editor->hovered_entity_color));
|
|
nk_label(context, "Hovered Entity Type: ", alignment_flags_left); nk_label_colored(context, entity_type_name_get(editor->hovered_entity), alignment_flags_right, nk_rgba_fv(&editor->hovered_entity_color));
|
|
nk_tooltip_end(context);
|
|
}
|
|
}
|
|
|
|
if(editor->selected_entity && editor->current_axis != EDITOR_AXIS_NONE)
|
|
{
|
|
switch(editor->current_tool)
|
|
{
|
|
case EDITOR_TOOL_TRANSLATE:
|
|
{
|
|
if(nk_tooltip_begin(context, tooltip_width))
|
|
{
|
|
vec3 abs_pos_selected = { 0.f, 0.f, 0.f };
|
|
vec3 abs_pos_cursor = { 0.f, 0.f, 0.f };
|
|
transform_get_absolute_position(editor->selected_entity, &abs_pos_selected);
|
|
transform_get_absolute_position(editor->cursor_entity, &abs_pos_cursor);
|
|
nk_layout_row_dynamic(context, 20, 2);
|
|
nk_label(context, "Current Position: ", alignment_flags_left); nk_labelf_colored(context, alignment_flags_right, nk_rgba_fv(&editor->selected_entity_color), "%.1f %.1f %.1f", abs_pos_selected.x, abs_pos_selected.y, abs_pos_selected.z);
|
|
nk_label(context, "New Position: ", alignment_flags_left); nk_labelf_colored(context, alignment_flags_right, nk_rgba_fv(&editor->cursor_entity_color), "%.1f %.1f %.1f", abs_pos_cursor.x, abs_pos_cursor.y, abs_pos_cursor.z);
|
|
nk_tooltip_end(context);
|
|
}
|
|
}
|
|
break;
|
|
case EDITOR_TOOL_ROTATE:
|
|
{
|
|
if(editor->tool_rotate_rotation_started)
|
|
{
|
|
if(nk_tooltip_begin(context, tooltip_width))
|
|
{
|
|
nk_layout_row_dynamic(context, 20, 2);
|
|
nk_label(context, "Axis: ", alignment_flags_left);
|
|
switch(editor->current_axis)
|
|
{
|
|
case EDITOR_AXIS_X: nk_label_colored(context, "X", alignment_flags_right, nk_rgba_fv(&editor->axis_color_x)); break;
|
|
case EDITOR_AXIS_Y: nk_label_colored(context, "Y", alignment_flags_right, nk_rgba_fv(&editor->axis_color_y)); break;
|
|
case EDITOR_AXIS_Z: nk_label_colored(context, "Z", alignment_flags_right, nk_rgba_fv(&editor->axis_color_z)); break;
|
|
}
|
|
nk_label(context, "Current Rotation: ", alignment_flags_left); nk_labelf_colored(context, alignment_flags_right, nk_rgba_fv(&editor->selected_entity_color), "%.3f", editor->tool_rotate_starting_rotation);
|
|
nk_label(context, "New Rotation: ", alignment_flags_left); nk_labelf_colored(context, alignment_flags_right, nk_rgba_fv(&editor->cursor_entity_color), "%.3f", editor->tool_rotate_total_rotation);
|
|
nk_tooltip_end(context);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EDITOR_TOOL_SCALE:
|
|
{
|
|
if(editor->tool_scale_started)
|
|
{
|
|
if(nk_tooltip_begin(context, tooltip_width))
|
|
{
|
|
nk_layout_row_dynamic(context, 20, 4);
|
|
nk_label(context, "Axis: ", alignment_flags_left);
|
|
bool x_enabled = editor->current_axis == EDITOR_AXIS_X || editor->current_axis == EDITOR_AXIS_XZ || editor->current_axis == EDITOR_AXIS_XY ? true : false;
|
|
bool y_enabled = editor->current_axis == EDITOR_AXIS_Y || editor->current_axis == EDITOR_AXIS_XY || editor->current_axis == EDITOR_AXIS_YZ ? true : false;
|
|
bool z_enabled = editor->current_axis == EDITOR_AXIS_Z || editor->current_axis == EDITOR_AXIS_XZ || editor->current_axis == EDITOR_AXIS_YZ ? true : false;
|
|
nk_label_colored(context, "X", alignment_flags_right, nk_rgba_f(editor->axis_color_x.x, editor->axis_color_x.y, editor->axis_color_x.z, x_enabled ? 1.f : 0.2f));
|
|
nk_label_colored(context, "Y", alignment_flags_right, nk_rgba_f(editor->axis_color_y.x, editor->axis_color_y.y, editor->axis_color_y.z, y_enabled ? 1.f : 0.2f));
|
|
nk_label_colored(context, "Z", alignment_flags_right, nk_rgba_f(editor->axis_color_z.x, editor->axis_color_z.y, editor->axis_color_z.z, z_enabled ? 1.f : 0.2f));
|
|
|
|
nk_layout_row_dynamic(context, 20, 2);
|
|
vec3 current_scale = { 1.f, 1.f, 1.f };
|
|
vec3 cursor_entity_scale = { 1.f, 1.f, 1.f };
|
|
vec3_assign(¤t_scale, &editor->selected_entity->transform.scale);
|
|
vec3_assign(&cursor_entity_scale, &editor->cursor_entity->base.transform.scale);
|
|
nk_label(context, "Current Scale: ", alignment_flags_left); nk_labelf_colored(context, alignment_flags_right, nk_rgba_fv(&editor->selected_entity_color), "%.1f %.1f %.1f", current_scale.x, current_scale.y, current_scale.z);
|
|
nk_label(context, "New Scale: ", alignment_flags_left); nk_labelf_colored(context, alignment_flags_right, nk_rgba_fv(&editor->cursor_entity_color), "%.1f %.1f %.1f", cursor_entity_scale.x, cursor_entity_scale.y, cursor_entity_scale.z);
|
|
nk_tooltip_end(context);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
context->style.window.background.a = previous_opacity;
|
|
}
|
|
}
|
|
nk_end(context);
|
|
|
|
/* Status Bar */
|
|
if(nk_begin(context, "Status Bar", nk_recti(0, win_height - editor->top_panel_height, win_width, editor->top_panel_height), NK_WINDOW_NO_SCROLLBAR))
|
|
{
|
|
nk_layout_row_begin(context, NK_DYNAMIC, editor->top_panel_height - 5, 8);
|
|
|
|
nk_layout_row_push(context, 0.06f);
|
|
nk_label(context, "Selected: ", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
|
|
nk_layout_row_push(context, 0.06f);
|
|
nk_label_colored(context, editor->selected_entity ? editor->selected_entity->name : "None", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, nk_rgba_fv(&editor->selected_entity_color));
|
|
|
|
nk_layout_row_push(context, 0.1f);
|
|
nk_checkbox_label(context, "Snap to grid ", &editor->tool_snap_enabled);
|
|
|
|
nk_layout_row_push(context, 0.1f);
|
|
nk_checkbox_label(context, "Relative grid ", &editor->grid_relative);
|
|
|
|
nk_layout_row_push(context, 0.1f);
|
|
nk_labelf(context, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, "Grid Scale: %.1f", editor->grid_scale);
|
|
|
|
nk_layout_row_push(context, 0.1f);
|
|
nk_labelf(context, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, "Grid Length: %d", editor->grid_num_lines);
|
|
|
|
nk_layout_row_push(context, 0.34f);
|
|
nk_spacing(context, 1);
|
|
|
|
nk_layout_row_push(context, 0.04f);
|
|
nk_labelf(context, NK_TEXT_ALIGN_RIGHT | NK_TEXT_ALIGN_MIDDLE, "v%d.%d.%d-%s", SYMMETRY_VERSION_MAJOR, SYMMETRY_VERSION_MINOR, SYMMETRY_VERSION_REVISION, SYMMETRY_VERSION_BRANCH);
|
|
|
|
nk_layout_row_push(context, 0.1f);
|
|
static int frames = 0;
|
|
static int fps = 0;
|
|
static float seconds = 0.f;
|
|
seconds += dt;
|
|
frames++;
|
|
if(seconds >= 1.f)
|
|
{
|
|
fps = frames;
|
|
seconds = 0.f;
|
|
frames = 0;
|
|
}
|
|
nk_labelf(context, NK_TEXT_ALIGN_RIGHT | NK_TEXT_ALIGN_MIDDLE, "FPS : %.d", fps);
|
|
}
|
|
nk_end(context);
|
|
|
|
if(editor->window_scene_heirarchy) editor_window_scene_hierarchy(context, editor, game_state);
|
|
if(editor->window_property_inspector) editor_window_property_inspector(context, editor, game_state);
|
|
if(editor->window_settings_renderer) editor_window_renderer_settings(context, editor, game_state);
|
|
if(editor->window_settings_editor) editor_window_settings_editor(context, editor, game_state);
|
|
|
|
if(editor->tool_mesh_draw_enabled && editor->selected_entity)
|
|
{
|
|
switch(editor->current_tool)
|
|
{
|
|
case EDITOR_TOOL_SCALE:
|
|
case EDITOR_TOOL_TRANSLATE:
|
|
{
|
|
quat rotation = { 0.f, 0.f, 0.f, 1.f };
|
|
vec3 scale = { 1.f, 1.f, 1.f };
|
|
vec3 position = { editor->cursor_entity->base.transform.position.x, editor->cursor_entity->base.transform.position.y, editor->cursor_entity->base.transform.position.z };
|
|
|
|
//Draw Axes
|
|
switch(editor->current_axis)
|
|
{
|
|
case EDITOR_AXIS_Y:
|
|
im_line((vec3) { 0.f, -editor->axis_line_length, 0.f }, (vec3) { 0.f, editor->axis_line_length, 0.f }, position, rotation, editor->axis_color_y, 3);
|
|
break;
|
|
case EDITOR_AXIS_X:
|
|
im_line((vec3) { -editor->axis_line_length, 0.f, 0.f }, (vec3) { editor->axis_line_length, 0.f, 0.f }, position, rotation, editor->axis_color_x, 3);
|
|
break;
|
|
case EDITOR_AXIS_Z:
|
|
im_line((vec3) { 0.f, 0.f, -editor->axis_line_length }, (vec3) { 0.f, 0.f, editor->axis_line_length }, position, rotation, editor->axis_color_z, 3);
|
|
break;
|
|
case EDITOR_AXIS_XZ:
|
|
im_line((vec3) { -editor->axis_line_length, 0.f, 0.f }, (vec3) { editor->axis_line_length, 0.f, 0.f }, position, rotation, editor->axis_color_x, 3);
|
|
im_line((vec3) { 0.f, 0.f, -editor->axis_line_length }, (vec3) { 0.f, 0.f, editor->axis_line_length }, position, rotation, editor->axis_color_z, 3);
|
|
break;
|
|
case EDITOR_AXIS_XY:
|
|
im_line((vec3) { -editor->axis_line_length, 0.f, 0.f }, (vec3) { editor->axis_line_length, 0.f, 0.f }, position, rotation, editor->axis_color_x, 3);
|
|
im_line((vec3) { 0.f, -editor->axis_line_length, 0.f }, (vec3) { 0.f, editor->axis_line_length, 0.f }, position, rotation, editor->axis_color_y, 3);
|
|
break;
|
|
case EDITOR_AXIS_YZ:
|
|
im_line((vec3) { 0.f, -editor->axis_line_length, 0.f }, (vec3) { 0.f, editor->axis_line_length, 0.f }, position, rotation, editor->axis_color_y, 3);
|
|
im_line((vec3) { 0.f, 0.f, -editor->axis_line_length }, (vec3) { 0.f, 0.f, editor->axis_line_length }, position, rotation, editor->axis_color_z, 3);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case EDITOR_TOOL_ROTATE:
|
|
{
|
|
quat rotation = { 0.f, 0.f, 0.f, 1.f };
|
|
vec3 scale = { 1.f, 1.f, 1.f };
|
|
vec3 position = { editor->cursor_entity->base.transform.position.x, editor->cursor_entity->base.transform.position.y, editor->cursor_entity->base.transform.position.z };
|
|
switch(editor->current_axis)
|
|
{
|
|
case EDITOR_AXIS_X:
|
|
quat_axis_angle(&rotation, &UNIT_Y, -90.f);
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_x, 5);
|
|
break;
|
|
case EDITOR_AXIS_Y:
|
|
quat_axis_angle(&rotation, &UNIT_X, -90.f);
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_y, 5);
|
|
break;
|
|
case EDITOR_AXIS_Z:
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_z, 5);
|
|
break;
|
|
case EDITOR_AXIS_XZ:
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_z, 5);
|
|
quat_axis_angle(&rotation, &UNIT_Y, -90.f);
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_x, 5);
|
|
break;
|
|
case EDITOR_AXIS_XY:
|
|
quat_axis_angle(&rotation, &UNIT_Y, -90.f);
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_x, 5);
|
|
quat_identity(&rotation);
|
|
quat_axis_angle(&rotation, &UNIT_X, -90.f);
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_y, 5);
|
|
break;
|
|
case EDITOR_AXIS_YZ:
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_z, 5);
|
|
quat_axis_angle(&rotation, &UNIT_X, -90.f);
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, false, position, rotation, editor->axis_color_y, 5);
|
|
break;
|
|
}
|
|
|
|
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: quat_axis_angle(&rotation, &UNIT_Y, 180.f); vec4_assign(&arc_color, &editor->axis_color_z); break;
|
|
}
|
|
|
|
if(editor->tool_rotate_allowed)
|
|
{
|
|
arc_color.w = 0.1f;
|
|
im_circle(editor->tool_rotate_arc_radius, editor->tool_rotate_arc_segments, true, position, rotation, arc_color, 2);
|
|
}
|
|
|
|
if(editor->tool_rotate_total_rotation != 0.f)
|
|
{
|
|
arc_color.w = 0.5f;
|
|
im_arc(editor->tool_rotate_arc_radius / 2.f, editor->tool_rotate_starting_rotation, editor->tool_rotate_total_rotation, editor->tool_rotate_arc_segments, true, position, rotation, arc_color, 4);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if(editor->window_scene_dialog) editor_scene_dialog(editor, context);
|
|
if(editor->window_entity_dialog) editor_entity_dialog(editor, context);
|
|
}
|
|
|
|
void editor_scene_dialog(struct Editor* editor, struct nk_context* context)
|
|
{
|
|
struct Game_State* game_state = game_state_get();
|
|
struct Scene* scene = game_state->scene;
|
|
bool save = editor->scene_operation_save;
|
|
int row_height = 25;
|
|
int popup_x = 0;
|
|
int popup_y = 0;
|
|
int popup_width = 300;
|
|
int popup_height = 200;
|
|
int display_width = 0;
|
|
int display_height = 0;
|
|
int popup_flags = NK_WINDOW_TITLE | NK_WINDOW_BORDER;
|
|
window_get_drawable_size(game_state_get()->window, &display_width, &display_height);
|
|
popup_x = (display_width / 2) - (popup_width / 2);
|
|
popup_y = (display_height / 2) - (popup_height / 2);
|
|
|
|
int background_window_flags = NK_WINDOW_BACKGROUND;
|
|
int previous_opacity = context->style.window.fixed_background.data.color.a;
|
|
context->style.window.fixed_background.data.color.a = 120;
|
|
if(nk_begin(context, save ? "Scene Save" : "Scene Load", nk_recti(0, 0, display_width, display_height), background_window_flags))
|
|
{
|
|
nk_window_set_focus(context, save ? "Scene Save" : "Scene Load");
|
|
if(nk_popup_begin(context, NK_POPUP_DYNAMIC, save ? "Save Scene" : "Load Scene", popup_flags, nk_recti(popup_x, popup_y, popup_width, popup_height)))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_label(context, "Enter the name of the scene:", NK_TEXT_ALIGN_CENTERED | NK_TEXT_ALIGN_MIDDLE);
|
|
|
|
static char scene_filename[MAX_FILENAME_LEN];
|
|
static bool copy_scene_filename = true;
|
|
|
|
if(copy_scene_filename)
|
|
{
|
|
memset(scene_filename, '\0', MAX_FILENAME_LEN);
|
|
strncpy(scene_filename, scene->filename, MAX_FILENAME_LEN);
|
|
}
|
|
|
|
int scene_filename_flags = NK_EDIT_SIG_ENTER | NK_EDIT_FIELD | NK_EDIT_AUTO_SELECT | NK_EDIT_SELECTABLE | NK_EDIT_GOTO_END_ON_ACTIVATE;
|
|
nk_edit_focus(context, scene_filename_flags);
|
|
int scene_filename_state = nk_edit_string_zero_terminated(context, scene_filename_flags, scene_filename, MAX_FILENAME_LEN, NULL);
|
|
if(scene_filename_state & NK_EDIT_ACTIVATED || scene_filename_state & NK_EDIT_ACTIVE)
|
|
{
|
|
copy_scene_filename = false;
|
|
}
|
|
|
|
if(scene_filename_state & NK_EDIT_COMMITED)
|
|
{
|
|
if(save)
|
|
scene_save(scene, scene_filename, DIRT_INSTALL);
|
|
else
|
|
scene_load(scene, scene_filename, DIRT_INSTALL);
|
|
copy_scene_filename = true;
|
|
editor->window_scene_dialog = 0;
|
|
nk_popup_close(context);
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 3);
|
|
if(nk_button_label(context, "OK"))
|
|
{
|
|
if(save)
|
|
scene_save(scene, scene_filename, DIRT_INSTALL);
|
|
else
|
|
scene_load(scene, scene_filename, DIRT_INSTALL);
|
|
copy_scene_filename = true;
|
|
editor->window_scene_dialog = 0;
|
|
nk_popup_close(context);
|
|
}
|
|
|
|
nk_spacing(context, 1);
|
|
|
|
if(nk_button_label(context, "Cancel"))
|
|
{
|
|
copy_scene_filename = true;
|
|
editor->window_scene_dialog = 0;
|
|
nk_popup_close(context);
|
|
}
|
|
|
|
nk_popup_end(context);
|
|
}
|
|
nk_end(context);
|
|
}
|
|
else
|
|
{
|
|
editor->window_scene_dialog = 0;
|
|
}
|
|
context->style.window.fixed_background.data.color.a = previous_opacity;
|
|
}
|
|
|
|
void editor_on_mousebutton_release(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 || game_state->console->visible)
|
|
return;
|
|
|
|
if(editor->camera_looking_around)
|
|
{
|
|
input_mouse_mode_set(MM_NORMAL);
|
|
int width = 0, height = 0;
|
|
window_get_drawable_size(game_state_get()->window, &width, &height);
|
|
platform_mouse_position_set(game_state_get()->window, width / 2, height / 2);
|
|
editor->camera_looking_around = false;
|
|
|
|
if(editor->selected_entity && editor->current_tool == EDITOR_TOOL_ROTATE && editor->previous_axis != EDITOR_AXIS_NONE)
|
|
editor_axis_set(editor, editor->previous_axis);
|
|
}
|
|
|
|
if(nk_window_is_any_hovered(&gui->context))
|
|
return;
|
|
|
|
if(event->mousebutton.button == MSB_LEFT &&
|
|
!editor->camera_looking_around &&
|
|
nk_item_is_any_active(&gui->context) == 0)
|
|
{
|
|
if(editor->picking_enabled)
|
|
{
|
|
log_message("Editor Picking");
|
|
struct Camera* editor_camera = &game_state_get()->scene->cameras[CAM_EDITOR];
|
|
int mouse_x = 0, mouse_y = 0;
|
|
platform_mouse_position_get(&mouse_x, &mouse_y);
|
|
struct Ray ray = camera_screen_coord_to_ray(editor_camera, mouse_x, mouse_y);
|
|
|
|
struct Scene* scene = game_state_get()->scene;
|
|
struct Entity* intersected_entity = scene_ray_intersect_closest(scene, &ray, ERM_ALL);
|
|
if(intersected_entity)
|
|
{
|
|
if(intersected_entity != editor->selected_entity)
|
|
editor_entity_select(editor, intersected_entity);
|
|
}
|
|
else
|
|
{
|
|
//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 && nk_item_is_any_active(&gui->context) == 0)
|
|
{
|
|
switch(editor->current_tool)
|
|
{
|
|
case EDITOR_TOOL_TRANSLATE:
|
|
if(editor->tool_translate_allowed)
|
|
{
|
|
//editor->picking_enabled = true;
|
|
//editor->tool_translate_allowed = false;
|
|
transform_copy(editor->selected_entity, editor->cursor_entity, false);
|
|
//editor->draw_cursor_entity = false;
|
|
}
|
|
break;
|
|
case EDITOR_TOOL_ROTATE:
|
|
if(editor->tool_rotate_rotation_started)
|
|
{
|
|
//editor->picking_enabled = true;
|
|
editor->tool_rotate_rotation_started = false;
|
|
transform_copy(editor->selected_entity, editor->cursor_entity, false);
|
|
editor->tool_rotate_total_rotation = 0.f;
|
|
editor->tool_rotate_starting_rotation = 0.f;
|
|
editor->draw_cursor_entity = false;
|
|
}
|
|
break;
|
|
case EDITOR_TOOL_SCALE:
|
|
if(editor->tool_scale_started)
|
|
{
|
|
//editor->picking_enabled = true;
|
|
editor->tool_scale_started = false;
|
|
transform_copy(editor->selected_entity, editor->cursor_entity, false);
|
|
vec3_fill(&editor->tool_scale_amount, 1.f, 1.f, 1.f);
|
|
editor->draw_cursor_entity = false;
|
|
}
|
|
else
|
|
{
|
|
if(editor->current_axis != EDITOR_AXIS_NONE)
|
|
{
|
|
editor->tool_scale_started = true;
|
|
editor->picking_enabled = false;
|
|
editor->draw_cursor_entity = true;
|
|
vec3_assign(&editor->tool_scale_amount, &editor->cursor_entity->base.transform.scale);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 || nk_window_is_any_hovered(&gui->context) || game_state->console->visible)
|
|
return;
|
|
|
|
if(event->mousebutton.button == MSB_LEFT && editor->selected_entity)
|
|
{
|
|
if(editor->current_tool == EDITOR_TOOL_ROTATE && editor->tool_rotate_allowed)
|
|
{
|
|
editor->picking_enabled = false;
|
|
editor->tool_rotate_rotation_started = true;
|
|
editor->tool_rotate_total_rotation = 0.f;
|
|
editor->draw_cursor_entity = true;
|
|
switch(editor->current_axis)
|
|
{
|
|
case EDITOR_AXIS_X: editor->tool_rotate_starting_rotation = roundf(quat_get_pitch(&editor->cursor_entity->base.transform.rotation)); break;
|
|
case EDITOR_AXIS_Y: editor->tool_rotate_starting_rotation = roundf(quat_get_yaw(&editor->cursor_entity->base.transform.rotation)); break;
|
|
case EDITOR_AXIS_Z: editor->tool_rotate_starting_rotation = roundf(quat_get_roll(&editor->cursor_entity->base.transform.rotation)); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Cancel rotation on right mouse press */
|
|
if(event->mousebutton.button == MSB_RIGHT && editor->selected_entity && editor->current_tool == EDITOR_TOOL_ROTATE)
|
|
editor_tool_reset(editor);
|
|
}
|
|
|
|
void editor_on_mousemotion(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 || nk_window_is_any_hovered(&gui->context) || game_state->console->visible)
|
|
return;
|
|
|
|
switch(editor->current_tool)
|
|
{
|
|
case EDITOR_TOOL_NORMAL:
|
|
{
|
|
|
|
}
|
|
break;
|
|
case EDITOR_TOOL_TRANSLATE:
|
|
{
|
|
if(editor->selected_entity && editor->tool_translate_allowed)
|
|
{
|
|
struct Camera* editor_camera = &game_state->scene->cameras[CAM_EDITOR];
|
|
vec3 current_position = { 0.f, 0.f, 0.f };
|
|
vec3 cursor_entity_position;
|
|
vec3_assign(&cursor_entity_position, &editor->cursor_entity->base.transform.position);
|
|
transform_get_absolute_position(editor->selected_entity, ¤t_position);
|
|
struct Ray cam_ray;
|
|
cam_ray = camera_screen_coord_to_ray(editor_camera, event->mousemotion.x, event->mousemotion.y);
|
|
|
|
switch(editor->current_axis)
|
|
{
|
|
case EDITOR_AXIS_X: cursor_entity_position.x += event->mousemotion.xrel / 2; break;
|
|
case EDITOR_AXIS_Y: cursor_entity_position.y += -event->mousemotion.xrel / 2; break;
|
|
case EDITOR_AXIS_Z: cursor_entity_position.z += -event->mousemotion.xrel / 2; break;
|
|
case EDITOR_AXIS_XZ:
|
|
{
|
|
Plane ground_plane;
|
|
plane_init(&ground_plane, &(vec3){0.f, 1.f, 0.f}, ¤t_position);
|
|
|
|
float distance = bv_distance_ray_plane(&cam_ray, &ground_plane);
|
|
if(distance < INFINITY && distance > -INFINITY)
|
|
{
|
|
vec3 abs_cam_pos, projected_point, cam_forward;
|
|
transform_get_absolute_position(editor_camera, &abs_cam_pos);
|
|
transform_get_absolute_forward(editor_camera, &cam_forward);
|
|
vec3_scale(&projected_point, &cam_ray.direction, distance);
|
|
vec3_add(¤t_position, &projected_point, &abs_cam_pos);
|
|
vec3_assign(&cursor_entity_position, ¤t_position);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(editor->tool_snap_enabled)
|
|
{
|
|
cursor_entity_position.x = roundf(cursor_entity_position.x / editor->grid_scale) * editor->grid_scale;
|
|
cursor_entity_position.y = roundf(cursor_entity_position.y / editor->grid_scale) * editor->grid_scale;
|
|
cursor_entity_position.z = roundf(cursor_entity_position.z / editor->grid_scale) * editor->grid_scale;
|
|
transform_set_position(editor->cursor_entity, &cursor_entity_position);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EDITOR_TOOL_ROTATE:
|
|
{
|
|
if(editor->selected_entity && editor->current_axis < EDITOR_AXIS_XZ)
|
|
{
|
|
struct Camera* editor_camera = &game_state->scene->cameras[CAM_EDITOR];
|
|
vec3 position = { 0.f, 0.f, 0.f };
|
|
vec3 scale = {1.f, 1.f, 1.f};
|
|
transform_get_absolute_position(editor->selected_entity, &position);
|
|
//transform_get_absolute_scale(editor->selected_entity, &scale);
|
|
struct Ray cam_ray;
|
|
cam_ray = camera_screen_coord_to_ray(editor_camera, event->mousemotion.x, event->mousemotion.y);
|
|
|
|
|
|
/* Instead of using a spehre intersection, get the point where the ray intersects the plane
|
|
then check if the distance of that point from the selected entity is less than or equal to
|
|
the radius of the circle/disc, if it is, then we are inside the circle and can rotate */
|
|
|
|
|
|
|
|
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, &scale, &cam_ray) == IT_INTERSECT)
|
|
{
|
|
//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->tool_rotate_axis = EDITOR_AXIS_X;
|
|
//if(shortest_distance == distance_y) editor->tool_rotate_axis = EDITOR_AXIS_Y;
|
|
//if(shortest_distance == distance_z) editor->tool_rotate_axis = EDITOR_AXIS_Z;
|
|
editor->tool_rotate_allowed = true;
|
|
}
|
|
else
|
|
{
|
|
editor->tool_rotate_allowed = false;
|
|
}
|
|
|
|
if(editor->current_axis != EDITOR_AXIS_NONE && editor->tool_rotate_rotation_started)
|
|
{
|
|
if(editor->tool_snap_enabled)
|
|
editor->tool_rotate_amount += editor->grid_scale * editor->tool_rotate_increment * ((float)event->mousemotion.xrel / 2.f);
|
|
else
|
|
editor->tool_rotate_amount += event->mousemotion.xrel / 2;
|
|
|
|
if(editor->tool_rotate_amount > 360.f)
|
|
editor->tool_rotate_amount = editor->tool_rotate_amount - 360.f;
|
|
else if(editor->tool_rotate_amount < -360.f)
|
|
editor->tool_rotate_amount = editor->tool_rotate_amount + 360.f;
|
|
|
|
if(editor->tool_rotate_amount != 0.f)
|
|
{
|
|
switch(editor->current_axis)
|
|
{
|
|
case EDITOR_AXIS_X:
|
|
transform_rotate(editor->cursor_entity, &UNIT_X, editor->tool_rotate_amount, TS_WORLD);
|
|
editor->tool_rotate_total_rotation = roundf(quat_get_pitch(&editor->cursor_entity->base.transform.rotation));
|
|
break;
|
|
case EDITOR_AXIS_Y:
|
|
transform_rotate(editor->cursor_entity, &UNIT_Y, editor->tool_rotate_amount, TS_WORLD);
|
|
editor->tool_rotate_total_rotation = roundf(quat_get_yaw(&editor->cursor_entity->base.transform.rotation));
|
|
break;
|
|
case EDITOR_AXIS_Z:
|
|
transform_rotate(editor->cursor_entity, &UNIT_Z, editor->tool_rotate_amount, TS_WORLD);
|
|
editor->tool_rotate_total_rotation = roundf(quat_get_roll(&editor->cursor_entity->base.transform.rotation));
|
|
break;
|
|
}
|
|
editor->tool_rotate_amount = 0.f;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
case EDITOR_TOOL_SCALE:
|
|
{
|
|
if(editor->current_axis != EDITOR_AXIS_NONE && editor->tool_scale_started)
|
|
{
|
|
switch(editor->current_axis)
|
|
{
|
|
case EDITOR_AXIS_X: editor->tool_scale_amount.x += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; break;
|
|
case EDITOR_AXIS_Y: editor->tool_scale_amount.y += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; break;
|
|
case EDITOR_AXIS_Z: editor->tool_scale_amount.z += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; break;
|
|
case EDITOR_AXIS_XZ: editor->tool_scale_amount.x += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; editor->tool_scale_amount.z += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; break;
|
|
case EDITOR_AXIS_XY: editor->tool_scale_amount.x += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; editor->tool_scale_amount.y += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; break;
|
|
case EDITOR_AXIS_YZ: editor->tool_scale_amount.y += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; editor->tool_scale_amount.z += (float)(event->mousemotion.xrel / 2) * editor->grid_scale; break;
|
|
}
|
|
transform_scale(editor->cursor_entity, &editor->tool_scale_amount);
|
|
}
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
/* Check if we're hovering over an entity */
|
|
if(editor->picking_enabled)
|
|
{
|
|
struct Scene* scene = game_state->scene;
|
|
struct Camera* editor_camera = &scene->cameras[CAM_EDITOR];
|
|
struct Ray ray = camera_screen_coord_to_ray(editor_camera, event->mousemotion.x, event->mousemotion.y);
|
|
struct Entity* intersected_entity = scene_ray_intersect_closest(scene, &ray, ERM_ALL);
|
|
if(intersected_entity)
|
|
{
|
|
if(intersected_entity != editor->hovered_entity)
|
|
editor->hovered_entity = intersected_entity;
|
|
}
|
|
else
|
|
{
|
|
if(editor->hovered_entity)
|
|
editor->hovered_entity = NULL;
|
|
}
|
|
}
|
|
else if(editor->hovered_entity)
|
|
{
|
|
editor->hovered_entity = NULL;
|
|
}
|
|
}
|
|
|
|
void editor_on_key_release(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 || game_state->console->visible)
|
|
return;
|
|
|
|
/* Valid shortcuts when a ui element is hovered */
|
|
if(event->key.key == KEY_ESCAPE)
|
|
{
|
|
if(editor->window_entity_dialog == 1)
|
|
editor->window_entity_dialog = 0;
|
|
else if(editor->window_scene_dialog == 1)
|
|
editor->window_scene_dialog = 0;
|
|
else
|
|
editor_entity_select(editor, NULL);
|
|
}
|
|
|
|
if(nk_window_is_any_hovered(&gui->context))
|
|
return;
|
|
|
|
/* All other shortcuts*/
|
|
/* Tool Cycle */
|
|
if(event->key.key == KEY_TAB)
|
|
{
|
|
int tool = editor->current_tool;
|
|
if(++tool == EDITOR_TOOL_MAX)
|
|
tool = EDITOR_TOOL_NORMAL;
|
|
editor_tool_set(editor, tool);
|
|
}
|
|
|
|
/* Tool Select */
|
|
if(!editor->camera_looking_around)
|
|
{
|
|
if(event->key.key == KEY_Q) editor_tool_set(editor, EDITOR_TOOL_NORMAL);
|
|
if(event->key.key == KEY_W) editor_tool_set(editor, EDITOR_TOOL_TRANSLATE);
|
|
if(event->key.key == KEY_E) editor_tool_set(editor, EDITOR_TOOL_ROTATE);
|
|
if(event->key.key == KEY_R) editor_tool_set(editor, EDITOR_TOOL_SCALE);
|
|
}
|
|
|
|
/* Axis select */
|
|
int selected_axis = editor->current_axis;
|
|
if(event->key.key == KEY_X) editor_axis_set(editor, EDITOR_AXIS_X);
|
|
if(event->key.key == KEY_Y) editor_axis_set(editor, EDITOR_AXIS_Y);
|
|
if(event->key.key == KEY_Z) editor_axis_set(editor, EDITOR_AXIS_Z);
|
|
if(event->key.key == KEY_X && input_is_key_pressed(KEY_LSHIFT)) editor_axis_set(editor, EDITOR_AXIS_YZ);
|
|
if(event->key.key == KEY_Y && input_is_key_pressed(KEY_LSHIFT)) editor_axis_set(editor, EDITOR_AXIS_XZ);
|
|
if(event->key.key == KEY_Z && input_is_key_pressed(KEY_LSHIFT)) editor_axis_set(editor, EDITOR_AXIS_XY);
|
|
if(event->key.key == KEY_ALT && editor->current_tool == EDITOR_TOOL_TRANSLATE && editor->current_axis == EDITOR_AXIS_Y)
|
|
{
|
|
if(editor->previous_axis != EDITOR_AXIS_Y)
|
|
editor_axis_set(editor, editor->previous_axis);
|
|
else
|
|
editor_axis_set(editor, EDITOR_AXIS_NONE);
|
|
editor->previous_axis = EDITOR_AXIS_NONE;
|
|
}
|
|
|
|
/* Grid Scale select */
|
|
if(event->key.key == KEY_1) editor->grid_scale = 1.f;
|
|
if(event->key.key == KEY_2) editor->grid_scale = 2.f;
|
|
if(event->key.key == KEY_3) editor->grid_scale = 3.f;
|
|
if(event->key.key == KEY_4) editor->grid_scale = 4.f;
|
|
if(event->key.key == KEY_5) editor->grid_scale = 5.f;
|
|
if(event->key.key == KEY_6) editor->grid_scale = 6.f;
|
|
if(event->key.key == KEY_7) editor->grid_scale = 7.f;
|
|
if(event->key.key == KEY_8) editor->grid_scale = 8.f;
|
|
if(event->key.key == KEY_9) editor->grid_scale = 9.f;
|
|
if(event->key.key == KEY_0) editor->grid_scale = 0.5f;
|
|
|
|
if(event->key.key == KEY_G) editor->grid_enabled = !editor->grid_enabled;
|
|
|
|
if(event->key.key == KEY_DELETE && editor->selected_entity)
|
|
{
|
|
editor->selected_entity->flags |= EF_MARKED_FOR_DELETION;
|
|
editor_entity_select(editor, NULL);
|
|
if(editor->hovered_entity == editor->selected_entity)
|
|
editor->hovered_entity = NULL;
|
|
}
|
|
|
|
if(event->key.key == KEY_D && input_is_key_pressed(KEY_LCTRL) && editor->selected_entity && !editor->camera_looking_around)
|
|
{
|
|
struct Entity* new_entity = scene_entity_duplicate(game_state->scene, editor->selected_entity);
|
|
if(new_entity)
|
|
{
|
|
editor_entity_select(editor, new_entity);
|
|
}
|
|
}
|
|
|
|
if(event->key.key == KEY_S && input_is_key_pressed(KEY_LCTRL) && !editor->camera_looking_around)
|
|
{
|
|
struct Scene* scene = game_state->scene;
|
|
scene_save(scene, scene->filename, DIRT_INSTALL);
|
|
}
|
|
|
|
if(event->key.key == KEY_O && input_is_key_pressed(KEY_LCTRL) && !editor->camera_looking_around && editor->window_entity_dialog != 1)
|
|
{
|
|
editor->scene_operation_save = false;
|
|
editor->window_scene_dialog = 1;
|
|
}
|
|
|
|
if(event->key.key == KEY_A && input_is_key_pressed(KEY_LSHIFT) && !editor->camera_looking_around && editor->window_scene_dialog != 1)
|
|
{
|
|
editor->entity_operation_save = false;
|
|
editor->window_entity_dialog = 1;
|
|
}
|
|
}
|
|
|
|
void editor_tool_set(struct Editor* editor, int tool)
|
|
{
|
|
if(editor->current_tool != tool)
|
|
{
|
|
editor->current_tool = tool;
|
|
if(editor->current_tool == EDITOR_TOOL_TRANSLATE)
|
|
editor->draw_cursor_entity = true;
|
|
else
|
|
editor->draw_cursor_entity = false;
|
|
editor->previous_axis = editor->current_axis;
|
|
editor_tool_reset(editor);
|
|
}
|
|
}
|
|
|
|
void editor_entity_select(struct Editor* editor, struct Entity* entity)
|
|
{
|
|
if(!entity && editor->selected_entity) // Deselect
|
|
{
|
|
editor->selected_entity->flags &= ~EF_SELECTED_IN_EDITOR;
|
|
editor->selected_entity = NULL;
|
|
editor_tool_reset(editor);
|
|
}
|
|
else if(entity) // Select
|
|
{
|
|
// Deselect already selected entity
|
|
if(editor->selected_entity && editor->selected_entity != entity)
|
|
{
|
|
editor->selected_entity->flags &= ~EF_SELECTED_IN_EDITOR;
|
|
editor->selected_entity = NULL;
|
|
}
|
|
|
|
if(editor->current_tool == EDITOR_TOOL_TRANSLATE)
|
|
{
|
|
if(editor->current_axis == EDITOR_AXIS_NONE)
|
|
editor_axis_set(editor, EDITOR_AXIS_XZ);
|
|
editor->draw_cursor_entity = true;
|
|
}
|
|
entity->flags |= EF_SELECTED_IN_EDITOR;
|
|
editor->selected_entity = entity;
|
|
transform_copy(editor->cursor_entity, editor->selected_entity, false);
|
|
}
|
|
}
|
|
|
|
void editor_tool_reset(struct Editor* editor)
|
|
{
|
|
if(editor->selected_entity)
|
|
transform_copy(editor->cursor_entity, editor->selected_entity, false);
|
|
else
|
|
transform_reset(editor->cursor_entity);
|
|
|
|
switch(editor->current_tool)
|
|
{
|
|
case EDITOR_TOOL_NORMAL:
|
|
editor->draw_cursor_entity = false;
|
|
break;
|
|
case EDITOR_TOOL_TRANSLATE:
|
|
editor->draw_cursor_entity = false;
|
|
editor->tool_translate_allowed = false;
|
|
editor_axis_set(editor, EDITOR_AXIS_NONE);
|
|
break;
|
|
case EDITOR_TOOL_ROTATE:
|
|
editor->tool_rotate_amount = 0.f;
|
|
editor->tool_rotate_total_rotation = 0.f;
|
|
editor->tool_rotate_allowed = false;
|
|
editor->tool_rotate_rotation_started = false;
|
|
editor->draw_cursor_entity = false;
|
|
editor_axis_set(editor, EDITOR_AXIS_NONE);
|
|
break;
|
|
case EDITOR_TOOL_SCALE:
|
|
vec3_fill(&editor->tool_scale_amount, 1.f, 1.f, 1.f);
|
|
editor->tool_scale_started = false;
|
|
editor->draw_cursor_entity = false;
|
|
editor_axis_set(editor, EDITOR_AXIS_NONE);
|
|
break;
|
|
}
|
|
|
|
editor->picking_enabled = true;
|
|
}
|
|
|
|
void editor_on_key_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 || nk_window_is_any_hovered(&gui->context) || game_state->console->visible)
|
|
return;
|
|
|
|
if(!nk_window_is_any_hovered(&game_state_get()->gui->context))
|
|
{
|
|
if(event->key.key == KEY_ALT && editor->current_tool == EDITOR_TOOL_TRANSLATE && editor->current_axis != EDITOR_AXIS_Y) editor_axis_set(editor, EDITOR_AXIS_Y);
|
|
}
|
|
}
|
|
|
|
void editor_axis_set(struct Editor* editor, int axis)
|
|
{
|
|
if(editor->current_axis != axis)
|
|
{
|
|
editor->previous_axis = editor->current_axis;
|
|
editor->current_axis = axis;
|
|
|
|
/* Reset tool position after axis has changed */
|
|
if(editor->selected_entity)
|
|
transform_copy(editor->cursor_entity, editor->selected_entity, false);
|
|
|
|
if(editor->current_tool == EDITOR_TOOL_ROTATE)
|
|
{
|
|
// Assign rotation axis only if it is a single axis since we don't want to rotate on multiple axes at the same time
|
|
if(axis >= EDITOR_AXIS_XZ)
|
|
{
|
|
editor->previous_axis = EDITOR_AXIS_NONE;
|
|
editor->current_axis = EDITOR_AXIS_NONE;
|
|
editor->tool_rotate_allowed = false;
|
|
editor->tool_rotate_amount = 0.f;
|
|
}
|
|
else
|
|
{
|
|
if(axis != EDITOR_AXIS_NONE)
|
|
editor->picking_enabled = false;
|
|
else if(axis == EDITOR_AXIS_NONE && !editor->picking_enabled)
|
|
editor->picking_enabled = true;
|
|
}
|
|
}
|
|
|
|
if(editor->current_tool == EDITOR_TOOL_SCALE && axis != EDITOR_AXIS_NONE)
|
|
{
|
|
editor->tool_scale_started = true;
|
|
editor->picking_enabled = false;
|
|
editor->draw_cursor_entity = true;
|
|
vec3_assign(&editor->tool_scale_amount, &editor->cursor_entity->base.transform.scale);
|
|
}
|
|
|
|
if(editor->current_tool == EDITOR_TOOL_TRANSLATE && axis != EDITOR_AXIS_NONE)
|
|
{
|
|
editor->tool_translate_allowed = true;
|
|
editor->picking_enabled = false;
|
|
editor->draw_cursor_entity = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(axis == EDITOR_AXIS_NONE)
|
|
return;
|
|
/* De-select axis */
|
|
editor->previous_axis = editor->current_axis;
|
|
editor->current_axis = EDITOR_AXIS_NONE;
|
|
|
|
if(editor->selected_entity)
|
|
transform_copy(editor->cursor_entity, editor->selected_entity, false);
|
|
|
|
if(editor->current_tool == EDITOR_TOOL_SCALE)
|
|
{
|
|
editor->picking_enabled = true;
|
|
editor->tool_scale_started = false;
|
|
vec3_fill(&editor->tool_scale_amount, 1.f, 1.f, 1.f);
|
|
editor->draw_cursor_entity = false;
|
|
}
|
|
|
|
if(editor->current_tool == EDITOR_TOOL_ROTATE)
|
|
{
|
|
editor->tool_rotate_amount = 0.f;
|
|
editor->tool_rotate_total_rotation = 0.f;
|
|
editor->tool_rotate_allowed = false;
|
|
editor->tool_rotate_rotation_started = false;
|
|
editor->draw_cursor_entity = false;
|
|
editor->picking_enabled = true;
|
|
}
|
|
|
|
if(editor->current_tool == EDITOR_TOOL_TRANSLATE)
|
|
{
|
|
editor->picking_enabled = true;
|
|
editor->tool_translate_allowed = false;
|
|
editor->draw_cursor_entity = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void editor_camera_update(struct Editor* editor, float dt)
|
|
{
|
|
struct Game_State* game_state = game_state_get();
|
|
struct Gui* gui = game_state->gui;
|
|
if(game_state->console->visible || nk_item_is_any_active(&gui->context))
|
|
return;
|
|
|
|
struct Camera* editor_camera = &game_state->scene->cameras[CAM_EDITOR];
|
|
static float total_up_down_rot = 0.f;
|
|
float move_speed = editor->camera_move_speed, turn_speed = editor->camera_turn_speed;
|
|
float turn_up_down = 0.f;
|
|
float turn_left_right = 0.f;
|
|
float max_up_down = 60.f;
|
|
vec3 offset = { 0, 0, 0 };
|
|
vec3 rot_axis_up_down = { 1, 0, 0 };
|
|
vec3 rot_axis_left_right = { 0, 1, 0 };
|
|
|
|
/* Look around */
|
|
if(input_map_state_get("Turn_Up", KS_PRESSED)) turn_up_down += turn_speed;
|
|
if(input_map_state_get("Turn_Down", KS_PRESSED)) turn_up_down -= turn_speed;
|
|
if(input_map_state_get("Turn_Right", KS_PRESSED)) turn_left_right += turn_speed;
|
|
if(input_map_state_get("Turn_Left", KS_PRESSED)) turn_left_right -= turn_speed;
|
|
|
|
if(input_mousebutton_state_get(MSB_RIGHT, KS_PRESSED) && !nk_item_is_any_active(&gui->context))
|
|
{
|
|
const float scale = 0.5f;
|
|
int cursor_lr, cursor_ud;
|
|
input_mouse_delta_get(&cursor_lr, &cursor_ud);
|
|
editor->camera_looking_around = true;
|
|
if(input_mouse_mode_get() != MM_RELATIVE)
|
|
{
|
|
input_mouse_mode_set(MM_RELATIVE);
|
|
cursor_lr = cursor_ud = 0;
|
|
}
|
|
|
|
turn_up_down = -cursor_ud * turn_speed * dt * scale;
|
|
turn_left_right = cursor_lr * turn_speed * dt * scale;
|
|
}
|
|
else
|
|
{
|
|
turn_up_down *= dt;
|
|
turn_left_right *= dt;
|
|
}
|
|
|
|
total_up_down_rot += turn_up_down;
|
|
if(total_up_down_rot >= max_up_down)
|
|
{
|
|
total_up_down_rot = max_up_down;
|
|
turn_up_down = 0.f;
|
|
}
|
|
else if(total_up_down_rot <= -max_up_down)
|
|
{
|
|
total_up_down_rot = -max_up_down;
|
|
turn_up_down = 0.f;
|
|
}
|
|
|
|
if(turn_left_right != 0.f)
|
|
{
|
|
transform_rotate(editor_camera, &rot_axis_left_right, -turn_left_right, TS_WORLD);
|
|
}
|
|
|
|
if(turn_up_down != 0.f)
|
|
{
|
|
//transform_rotate(editor_camera, &rot_axis_up_down, turn_up_down, TS_LOCAL);
|
|
transform_rotate(editor_camera, &rot_axis_up_down, turn_up_down, TS_LOCAL);
|
|
}
|
|
|
|
/* Movement */
|
|
if(editor->camera_looking_around)
|
|
{
|
|
if(input_map_state_get("Sprint", KS_PRESSED)) move_speed *= editor->camera_sprint_multiplier;
|
|
if(input_map_state_get("Move_Forward", KS_PRESSED)) offset.z -= move_speed;
|
|
if(input_map_state_get("Move_Backward", KS_PRESSED)) offset.z += move_speed;
|
|
if(input_map_state_get("Move_Left", KS_PRESSED)) offset.x -= move_speed;
|
|
if(input_map_state_get("Move_Right", KS_PRESSED)) offset.x += move_speed;
|
|
if(input_map_state_get("Move_Up", KS_PRESSED)) offset.y += move_speed;
|
|
if(input_map_state_get("Move_Down", KS_PRESSED)) offset.y -= move_speed;
|
|
|
|
vec3_scale(&offset, &offset, dt);
|
|
if(offset.x != 0 || offset.y != 0 || offset.z != 0)
|
|
{
|
|
transform_translate(editor_camera, &offset, TS_LOCAL);
|
|
//log_message("Position : %s", tostr_vec3(&transform->position));
|
|
}
|
|
}
|
|
|
|
debug_vars_show_color_rgba("Editor Cam Clear Color", &editor_camera->clear_color);
|
|
}
|
|
|
|
void editor_widget_color_combov3(struct nk_context* context, vec3* color, int width, int height)
|
|
{
|
|
struct nk_color temp_color = nk_rgba_f(color->x, color->y, color->z, 1.f);
|
|
if(nk_combo_begin_color(context, temp_color, nk_vec2(width, height)))
|
|
{
|
|
enum color_mode { COL_RGB, COL_HSV };
|
|
static int col_mode = COL_RGB;
|
|
nk_layout_row_dynamic(context, 25, 2);
|
|
col_mode = nk_option_label(context, "RGB", col_mode == COL_RGB) ? COL_RGB : col_mode;
|
|
col_mode = nk_option_label(context, "HSV", col_mode == COL_HSV) ? COL_HSV : col_mode;
|
|
nk_layout_row_dynamic(context, 120, 1);
|
|
struct nk_colorf temp_colorf = nk_color_cf(temp_color);
|
|
temp_colorf = nk_color_picker(context, temp_colorf, NK_RGB);
|
|
temp_color = nk_rgba_cf(temp_colorf);
|
|
|
|
nk_layout_row_dynamic(context, 25, 1);
|
|
if(col_mode == COL_RGB)
|
|
{
|
|
temp_color.r = (nk_byte)nk_propertyi(context, "#R:", 0, temp_color.r, 255, 1, 1);
|
|
temp_color.g = (nk_byte)nk_propertyi(context, "#G:", 0, temp_color.g, 255, 1, 1);
|
|
temp_color.b = (nk_byte)nk_propertyi(context, "#B:", 0, temp_color.b, 255, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
nk_byte tmp[4];
|
|
nk_color_hsva_bv(tmp, temp_color);
|
|
tmp[0] = (nk_byte)nk_propertyi(context, "#H:", 0, tmp[0], 255, 1, 1);
|
|
tmp[1] = (nk_byte)nk_propertyi(context, "#S:", 0, tmp[1], 255, 1, 1);
|
|
tmp[2] = (nk_byte)nk_propertyi(context, "#V:", 0, tmp[2], 255, 1, 1);
|
|
temp_color = nk_hsva_bv(tmp);
|
|
}
|
|
float empty = 1.f;
|
|
nk_color_f(&color->x, &color->y, &color->z, &empty, temp_color);
|
|
nk_combo_end(context);
|
|
}
|
|
}
|
|
|
|
void editor_widget_color_combov4(struct nk_context* context, vec4* color, int width, int height)
|
|
{
|
|
struct nk_color temp_color = nk_rgba_f(color->x, color->y, color->z, color->w);
|
|
if(nk_combo_begin_color(context, temp_color, nk_vec2(width, height)))
|
|
{
|
|
enum color_mode { COL_RGB, COL_HSV };
|
|
static int col_mode = COL_RGB;
|
|
nk_layout_row_dynamic(context, 25, 2);
|
|
col_mode = nk_option_label(context, "RGB", col_mode == COL_RGB) ? COL_RGB : col_mode;
|
|
col_mode = nk_option_label(context, "HSV", col_mode == COL_HSV) ? COL_HSV : col_mode;
|
|
nk_layout_row_dynamic(context, 120, 1);
|
|
struct nk_colorf temp_colorf = nk_color_cf(temp_color);
|
|
temp_colorf = nk_color_picker(context, temp_colorf, NK_RGBA);
|
|
temp_color = nk_rgba_cf(temp_colorf);
|
|
|
|
nk_layout_row_dynamic(context, 25, 1);
|
|
if(col_mode == COL_RGB)
|
|
{
|
|
temp_color.r = (nk_byte)nk_propertyi(context, "#R:", 0, temp_color.r, 255, 1, 1);
|
|
temp_color.g = (nk_byte)nk_propertyi(context, "#G:", 0, temp_color.g, 255, 1, 1);
|
|
temp_color.b = (nk_byte)nk_propertyi(context, "#B:", 0, temp_color.b, 255, 1, 1);
|
|
temp_color.a = (nk_byte)nk_propertyi(context, "#A:", 0, temp_color.a, 255, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
nk_byte tmp[4];
|
|
nk_color_hsva_bv(tmp, temp_color);
|
|
tmp[0] = (nk_byte)nk_propertyi(context, "#H:", 0, tmp[0], 255, 1, 1);
|
|
tmp[1] = (nk_byte)nk_propertyi(context, "#S:", 0, tmp[1], 255, 1, 1);
|
|
tmp[2] = (nk_byte)nk_propertyi(context, "#V:", 0, tmp[2], 255, 1, 1);
|
|
tmp[3] = (nk_byte)nk_propertyi(context, "#A:", 0, tmp[3], 255, 1, 1);
|
|
temp_color = nk_hsva_bv(tmp);
|
|
}
|
|
nk_color_f(&color->x, &color->y, &color->z, &color->w, temp_color);
|
|
nk_combo_end(context);
|
|
}
|
|
}
|
|
|
|
void editor_cleanup(struct Editor* editor)
|
|
{
|
|
struct Event_Manager* event_manager = game_state_get()->event_manager;
|
|
event_manager_unsubscribe(event_manager, EVT_MOUSEBUTTON_PRESSED, &editor_on_mousebutton_press);
|
|
event_manager_unsubscribe(event_manager, EVT_MOUSEBUTTON_RELEASED, &editor_on_mousebutton_release);
|
|
event_manager_unsubscribe(event_manager, EVT_MOUSEMOTION, &editor_on_mousemotion);
|
|
event_manager_unsubscribe(event_manager, EVT_KEY_PRESSED, &editor_on_key_press);
|
|
event_manager_unsubscribe(event_manager, EVT_KEY_RELEASED, &editor_on_key_release);
|
|
}
|
|
|
|
|
|
|
|
bool editor_widget_v3(struct nk_context* context, vec3* value, const char* name_x, const char* name_y, const char* name_z, float min, float max, float step, float inc_per_pixel, int row_height)
|
|
{
|
|
bool changed = false;
|
|
vec3 val_copy = {0.f, 0.f, 0.f};
|
|
vec3_assign(&val_copy, value);
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_property_float(context, name_x, min, &value->x, max, step, inc_per_pixel);
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_property_float(context, name_y, min, &value->y, max, step, inc_per_pixel);
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_property_float(context, name_z, min, &value->z, max, step, inc_per_pixel);
|
|
if(!vec3_equals(&val_copy, value)) changed = true;
|
|
return changed;
|
|
}
|
|
|
|
bool editor_widget_v2(struct nk_context* context, vec2* value, const char* name_x, const char* name_y, float min, float max, float step, float inc_per_pixel, int row_height)
|
|
{
|
|
bool changed = false;
|
|
vec2 val_copy = {0.f, 0.f};
|
|
vec2_assign(&val_copy, value);
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_property_float(context, name_x, min, &value->x, max, step, inc_per_pixel);
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_property_float(context, name_y, min, &value->y, max, step, inc_per_pixel);
|
|
if(!vec2_equals(&val_copy, value)) changed = true;
|
|
return changed;
|
|
}
|
|
|
|
void editor_show_entity_in_list(struct Editor* editor, struct nk_context* context, struct Scene* scene, struct Entity* entity)
|
|
{
|
|
if(!(entity->flags & EF_ACTIVE) || (entity->flags & EF_HIDE_IN_EDITOR_SCENE_HIERARCHY)) return;
|
|
|
|
struct nk_rect bounds = nk_widget_bounds(context);
|
|
nk_layout_row_dynamic(context, 20, 1);
|
|
int selected = entity->flags & EF_SELECTED_IN_EDITOR;
|
|
if(nk_selectable_label(context, entity->name, NK_TEXT_ALIGN_LEFT, &selected))
|
|
{
|
|
if(selected)
|
|
entity->flags |= EF_SELECTED_IN_EDITOR;
|
|
else
|
|
entity->flags &= ~EF_SELECTED_IN_EDITOR;
|
|
|
|
if(editor->selected_entity && editor->selected_entity != entity)
|
|
editor_entity_select(editor, entity);
|
|
else if(editor->selected_entity && editor->selected_entity == entity && !(entity->flags & EF_SELECTED_IN_EDITOR))
|
|
editor_entity_select(editor, NULL);
|
|
|
|
|
|
if(entity->flags & EF_SELECTED_IN_EDITOR)
|
|
{
|
|
//editor->selected_entity = entity;
|
|
editor_entity_select(editor, entity);
|
|
if(!editor->window_property_inspector) editor->window_property_inspector = true;
|
|
}
|
|
}
|
|
|
|
|
|
if(nk_contextual_begin(context, 0, nk_vec2(200, 120), bounds))
|
|
{
|
|
nk_layout_row_dynamic(context, 20, 1);
|
|
if(nk_contextual_item_label(context, "Delete", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE))
|
|
{
|
|
entity->flags |= EF_MARKED_FOR_DELETION;
|
|
editor_entity_select(editor, NULL);
|
|
if(editor->hovered_entity == entity)
|
|
editor->hovered_entity = NULL;
|
|
}
|
|
|
|
if(nk_contextual_item_label(context, "Save", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE))
|
|
{
|
|
if(!(entity->flags & EF_SELECTED_IN_EDITOR))
|
|
editor_entity_select(editor, entity);
|
|
|
|
editor->window_entity_dialog = 1;
|
|
editor->entity_operation_save = true;
|
|
}
|
|
nk_contextual_end(context);
|
|
}
|
|
}
|
|
|
|
void editor_window_scene_hierarchy(struct nk_context* context, struct Editor* editor, struct Game_State* game_state)
|
|
{
|
|
if(nk_begin(context, "Scene Heirarchy", nk_recti(0, editor->top_panel_height, 250, 450), window_flags))
|
|
{
|
|
struct Scene* scene = game_state_get()->scene;
|
|
nk_layout_row_dynamic(context, 380, 1);
|
|
if(nk_group_begin(context, "Entity Name", NK_WINDOW_SCROLL_AUTO_HIDE))
|
|
{
|
|
editor_show_entity_in_list(editor, context, scene, &scene->player);
|
|
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Cameras", NK_MAXIMIZED))
|
|
{
|
|
for(int i = 0; i < MAX_SCENE_CAMERAS; i++)
|
|
editor_show_entity_in_list(editor, context, scene, &scene->cameras[i]);
|
|
nk_tree_pop(context);
|
|
}
|
|
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Lights", NK_MAXIMIZED))
|
|
{
|
|
for(int i = 0; i < MAX_SCENE_LIGHTS; i++)
|
|
editor_show_entity_in_list(editor, context, scene, &scene->lights[i]);
|
|
nk_tree_pop(context);
|
|
}
|
|
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Static Meshes", NK_MAXIMIZED))
|
|
{
|
|
for(int i = 0; i < MAX_SCENE_STATIC_MESHES; i++)
|
|
editor_show_entity_in_list(editor, context, scene, &scene->static_meshes[i]);
|
|
nk_tree_pop(context);
|
|
}
|
|
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Sound Sources", NK_MAXIMIZED))
|
|
{
|
|
for(int i = 0; i < MAX_SCENE_SOUND_SOURCES; i++)
|
|
editor_show_entity_in_list(editor, context, scene, &scene->sound_sources[i]);
|
|
nk_tree_pop(context);
|
|
}
|
|
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Enemies", NK_MAXIMIZED))
|
|
{
|
|
for(int i = 0; i < MAX_SCENE_ENEMIES; i++)
|
|
editor_show_entity_in_list(editor, context, scene, &scene->enemies[i]);
|
|
nk_tree_pop(context);
|
|
}
|
|
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Entities", NK_MAXIMIZED))
|
|
{
|
|
for(int i = 0; i < MAX_SCENE_ENTITIES; i++)
|
|
editor_show_entity_in_list(editor, context, scene, &scene->entities[i]);
|
|
nk_tree_pop(context);
|
|
}
|
|
|
|
nk_group_end(context);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
editor->window_scene_heirarchy = false;
|
|
}
|
|
nk_end(context);
|
|
}
|
|
|
|
void editor_window_property_inspector(struct nk_context* context, struct Editor* editor, struct Game_State* game_state)
|
|
{
|
|
int win_width = 0, win_height = 0;
|
|
window_get_drawable_size(game_state->window, &win_width, &win_height);
|
|
if(nk_begin(context, "Properties", nk_recti(win_width - 300, editor->top_panel_height, 300, 600), window_flags))
|
|
{
|
|
const int row_height = 20;
|
|
if(editor->selected_entity)
|
|
{
|
|
struct Scene* scene = game_state_get()->scene;
|
|
struct Entity* entity = editor->selected_entity;
|
|
|
|
struct Entity* parent_ent = entity->transform.parent;
|
|
nk_layout_row_dynamic(context, row_height + 5, 2);
|
|
nk_label(context, "Name", NK_TEXT_ALIGN_LEFT);
|
|
static char entity_name[MAX_ENTITY_NAME_LEN];
|
|
static bool copy_entity_name = true;
|
|
|
|
if(copy_entity_name)
|
|
{
|
|
memset(entity_name, '\0', MAX_ENTITY_NAME_LEN);
|
|
strncpy(entity_name, entity->name, MAX_ENTITY_NAME_LEN);
|
|
}
|
|
|
|
int rename_edit_flags = NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_SIG_ENTER;
|
|
int rename_edit_state = nk_edit_string_zero_terminated(context, rename_edit_flags, entity_name, MAX_ENTITY_NAME_LEN, NULL);
|
|
if(rename_edit_state & NK_EDIT_COMMITED)
|
|
{
|
|
entity_rename(entity, entity_name);
|
|
nk_edit_unfocus(context);
|
|
copy_entity_name = true;
|
|
}
|
|
else if(rename_edit_state & NK_EDIT_ACTIVATED)
|
|
{
|
|
copy_entity_name = false;
|
|
}
|
|
else if(rename_edit_state & NK_EDIT_DEACTIVATED)
|
|
{
|
|
copy_entity_name = true;
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2); nk_label(context, "ID", NK_TEXT_ALIGN_LEFT); nk_labelf(context, NK_TEXT_ALIGN_RIGHT, "%d", entity->id);
|
|
nk_layout_row_dynamic(context, row_height, 2); nk_label(context, "Selected", NK_TEXT_ALIGN_LEFT); nk_labelf(context, NK_TEXT_ALIGN_RIGHT, "%s", (entity->flags & EF_SELECTED_IN_EDITOR) ? "True" : "False");
|
|
nk_layout_row_dynamic(context, row_height, 2); nk_label(context, "Entity Type", NK_TEXT_ALIGN_LEFT); nk_labelf(context, NK_TEXT_ALIGN_RIGHT, "%s", entity_type_name_get(entity));
|
|
nk_layout_row_dynamic(context, row_height, 2); nk_label(context, "Archetype", NK_TEXT_ALIGN_LEFT); nk_label(context, entity->archetype_index == -1 ? "None" : scene->entity_archetypes[entity->archetype_index], NK_TEXT_ALIGN_RIGHT);
|
|
nk_layout_row_dynamic(context, row_height + 5, 2);
|
|
nk_label(context, "Parent Name", NK_TEXT_ALIGN_LEFT);
|
|
static char parent_name[MAX_ENTITY_NAME_LEN];
|
|
static bool copy_parent_name = true;
|
|
|
|
if(copy_parent_name)
|
|
{
|
|
memset(parent_name, '\0', MAX_ENTITY_NAME_LEN);
|
|
strncpy(parent_name, parent_ent->name, MAX_ENTITY_NAME_LEN);
|
|
}
|
|
|
|
int rename_parent_edit_flags = NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_SIG_ENTER;
|
|
int rename_parent_edit_state = nk_edit_string_zero_terminated(context, rename_parent_edit_flags, parent_name, MAX_ENTITY_NAME_LEN, NULL);
|
|
if(rename_parent_edit_state & NK_EDIT_ACTIVATED)
|
|
{
|
|
copy_parent_name = false;
|
|
}
|
|
else if(rename_parent_edit_state & NK_EDIT_DEACTIVATED)
|
|
{
|
|
copy_parent_name = true;
|
|
}
|
|
else if(rename_parent_edit_state & NK_EDIT_COMMITED)
|
|
{
|
|
if(strncmp(parent_name, "NONE", MAX_ENTITY_NAME_LEN) == 0 || strncmp(parent_name, "ROOT", MAX_ENTITY_NAME_LEN) == 0)
|
|
{
|
|
scene_entity_parent_reset(scene, entity);
|
|
}
|
|
else
|
|
{
|
|
struct Entity* new_parent = scene_find(scene, parent_name);
|
|
if(new_parent)
|
|
scene_entity_parent_set(scene, entity, new_parent);
|
|
else
|
|
log_warning("Could not find new parent %s for %s", parent_name, entity->name);
|
|
}
|
|
copy_parent_name = true;
|
|
nk_edit_unfocus(context);
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Children", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
nk_labelf(context, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE, "%d", array_len(entity->transform.children));
|
|
|
|
/* Transform */
|
|
{
|
|
if(nk_widget_is_hovered(context))
|
|
nk_tooltip(context, "Resets the local transformations for this entity without changing the entity's parent");
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
if(nk_button_label(context, "Reset Transform"))
|
|
{
|
|
vec3_fill(&entity->transform.position, 0.f, 0.f, 0.f);
|
|
vec3_fill(&entity->transform.scale, 1.f, 1.f, 1.f);
|
|
quat_fill(&entity->transform.rotation, 0.f, 0.f, 0.f, 1.f);
|
|
transform_update_transmat(entity);
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_label(context, "Position", NK_TEXT_ALIGN_CENTERED);
|
|
vec3 abs_pos = { 0.f, 0.f, 0.f };
|
|
transform_get_absolute_position(entity, &abs_pos);
|
|
if(editor_widget_v3(context, &abs_pos, "#X", "#Y", "#Z", -FLT_MAX, FLT_MAX, 1.f, 1.f, row_height)) transform_set_position(entity, &abs_pos);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_label(context, "Rotation", NK_TEXT_ALIGN_CENTERED);
|
|
quat abs_rot = { 0.f, 0.f, 0.f, 1.f };
|
|
transform_get_absolute_rot(entity, &abs_rot);
|
|
vec3 rot_angles = { 0.f, 0.f, 0.f };
|
|
rot_angles.x = quat_get_pitch(&abs_rot);
|
|
rot_angles.y = quat_get_yaw(&abs_rot);
|
|
rot_angles.z = quat_get_roll(&abs_rot);
|
|
vec3 curr_rot = { rot_angles.x, rot_angles.y, rot_angles.z };
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_property_float(context, "#X", -FLT_MAX, &curr_rot.x, FLT_MAX, 5.f, 1.f);
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_property_float(context, "#Y", -FLT_MAX, &curr_rot.y, FLT_MAX, 5.f, 1.f);
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_property_float(context, "#Z", -FLT_MAX, &curr_rot.z, FLT_MAX, 5.f, 1.f);
|
|
|
|
vec3 delta = { 0.f, 0.f, 0.f };
|
|
vec3_sub(&delta, &rot_angles, &curr_rot);
|
|
|
|
vec3 AXIS_X = { 1.f, 0.f, 0.f };
|
|
vec3 AXIS_Y = { 0.f, 1.f, 0.f };
|
|
vec3 AXIS_Z = { 0.f, 0.f, 1.f };
|
|
|
|
const float epsilon = 0.0001f;
|
|
if(fabsf(delta.x) > epsilon) transform_rotate(entity, &AXIS_X, delta.x, TS_WORLD);
|
|
if(fabsf(delta.y) > epsilon) transform_rotate(entity, &AXIS_Y, delta.y, TS_WORLD);
|
|
if(fabsf(delta.z) > epsilon) transform_rotate(entity, &AXIS_Z, delta.z, TS_WORLD);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_label(context, "Scale", NK_TEXT_ALIGN_CENTERED);
|
|
vec3 abs_scale = { 0.f, 0.f, 0.f };
|
|
transform_get_absolute_scale(entity, &abs_scale);
|
|
if(editor_widget_v3(context, &abs_scale, "#X", "#Y", "#Z", 0.1f, FLT_MAX, 1.f, 0.1f, row_height))
|
|
{
|
|
entity->transform.scale = abs_scale;
|
|
transform_update_transmat(entity);
|
|
}
|
|
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Bounding Box", NK_MINIMIZED))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_label(context, "Base", NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_CENTERED);
|
|
|
|
nk_label(context, "Min", NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_CENTERED);
|
|
if(editor_widget_v3(context, &entity->bounding_box.min, "#X", "#Y", "#Z", -FLT_MAX, FLT_MAX, 0.5f, 0.5f, row_height)) entity_update_derived_bounding_box(entity);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_label(context, "Max", NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_CENTERED);
|
|
if(editor_widget_v3(context, &entity->bounding_box.max, "#X", "#Y", "#Z", -FLT_MAX, FLT_MAX, 0.5f, 0.5f, row_height)) entity_update_derived_bounding_box(entity);
|
|
|
|
struct Bounding_Box* derived_box = &entity->derived_bounding_box;
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_label(context, "Derived", NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_CENTERED);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Min", NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_LEFT);
|
|
nk_labelf(context, NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_RIGHT, "%.1f %.1f %.1f", derived_box->min.x, derived_box->min.y, derived_box->min.z);
|
|
nk_label(context, "Max", NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_LEFT);
|
|
nk_labelf(context, NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_RIGHT, "%.1f %.1f %.1f", derived_box->max.x, derived_box->max.y, derived_box->max.z);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
if(nk_button_label(context, "Reset to Default"))
|
|
entity_bounding_box_reset(entity, true);
|
|
|
|
nk_tree_pop(context);
|
|
}
|
|
}
|
|
|
|
/* Light */
|
|
if(entity->type == ET_LIGHT)
|
|
{
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Light", NK_MAXIMIZED))
|
|
{
|
|
struct Light* light = (struct Light*)entity;
|
|
if(light->type > LT_POINT)
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_label(context, "Invalid light type!", NK_TEXT_ALIGN_CENTERED);
|
|
}
|
|
else
|
|
{
|
|
static const char* light_types[] = { "Spot", "Directional", "Point" };
|
|
float combo_width = nk_widget_width(context), combo_height = row_height * (LT_MAX);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Light Type", NK_TEXT_ALIGN_LEFT);
|
|
nk_combobox(context, light_types, LT_MAX - 1, &light->type, row_height, nk_vec2(combo_width, combo_height));
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_label(context, "Light Color", NK_TEXT_ALIGN_CENTERED);
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
editor_widget_color_combov3(context, &light->color, 200, 300);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_property_float(context, "Intensity", 0.f, &light->intensity, 100.f, 0.1f, 0.05f);
|
|
|
|
if(light->type != LT_DIR)
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
light->outer_angle = nk_propertyf(context, "Outer Angle", light->inner_angle, light->outer_angle, 360, 1.f, 0.5f);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
light->inner_angle = nk_propertyf(context, "Inner Angle", 1.f, light->inner_angle, light->outer_angle, 1.f, 0.5f);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_property_int(context, "Radius", 1, &light->radius, INT_MAX, 1, 1);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_property_float(context, "Falloff", 0.f, &light->falloff, 100.f, 0.1f, 0.05f);
|
|
}
|
|
}
|
|
nk_tree_pop(context);
|
|
}
|
|
}
|
|
|
|
/* Camera */
|
|
if(entity->type == ET_CAMERA)
|
|
{
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Camera", NK_MAXIMIZED))
|
|
{
|
|
bool update = false;
|
|
struct Camera* camera = (struct Camera*)entity;
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Orthographic", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
bool ortho = nk_check_label(context, "", camera->ortho);
|
|
if(ortho != camera->ortho)
|
|
{
|
|
camera->ortho = ortho;
|
|
update = true;
|
|
}
|
|
|
|
if(!camera->ortho)
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
float new_fov = nk_propertyf(context, "Fov", 30.f, camera->fov, 90.f, 0.1f, 1.f);
|
|
if(new_fov != camera->fov)
|
|
{
|
|
camera->fov = new_fov;
|
|
update = true;
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Aspect Ratio", NK_TEXT_ALIGN_LEFT); nk_labelf(context, NK_TEXT_ALIGN_RIGHT, "%.5f", camera->aspect_ratio);
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1); nk_label(context, "Clear Color", NK_TEXT_ALIGN_CENTERED);
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
editor_widget_color_combov4(context, &camera->clear_color, 200, 300);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
float new_zoom = nk_propertyf(context, "Zoom", 1.f, camera->zoom, FLT_MAX, 0.1f, 1.f);
|
|
if(new_zoom != camera->zoom)
|
|
{
|
|
camera->zoom = new_zoom;
|
|
update = true;
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
float new_near_z = nk_propertyf(context, "NearZ", -FLT_MAX, camera->nearz, camera->farz, 0.1f, 1.f);
|
|
if(new_near_z != camera->nearz)
|
|
{
|
|
camera->nearz = new_near_z;
|
|
update = true;
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
float new_far_z = nk_propertyf(context, "FarZ", camera->nearz, camera->farz, FLT_MAX, 0.1f, 2.f);
|
|
if(new_far_z != camera->farz)
|
|
{
|
|
camera->farz = new_far_z;
|
|
update = true;
|
|
}
|
|
|
|
if(update)
|
|
{
|
|
camera_update_view(entity);
|
|
camera_update_proj(entity);
|
|
}
|
|
nk_tree_pop(context);
|
|
}
|
|
}
|
|
|
|
/* Sound Source */
|
|
if(entity->type == ET_SOUND_SOURCE)
|
|
{
|
|
struct Sound* sound = game_state->sound;
|
|
struct Sound_Source* sound_source = (struct Sound_Source*)entity;
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Sound Source", NK_MAXIMIZED))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Playing", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
int is_playing = sound_source_instance_is_paused(sound, sound_source->source_instance);
|
|
int playing = nk_check_label(context, "", is_playing);
|
|
if(is_playing && !playing)
|
|
sound_source_instance_pause(sound, sound_source->source_instance);
|
|
else if(!is_playing && playing)
|
|
sound_source_instance_play(sound, sound_source->source_instance);
|
|
|
|
|
|
nk_label(context, "Loop", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
int is_looping = sound_source_instance_loop_get(sound, sound_source->source_instance);
|
|
int looping = nk_check_label(context, "", is_looping);
|
|
if(is_looping != looping)
|
|
sound_source_instance_loop_set(sound, sound_source->source_instance, looping);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
float volume = sound_source_instance_volume_get(sound, sound_source->source_instance);
|
|
volume = nk_propertyf(context, "Volume", 0.f, volume, 10.f, 0.5f, 0.1f);
|
|
sound_source_instance_volume_set(sound, sound_source->source_instance, volume);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
static char sound_source_filename_buffer[MAX_FILENAME_LEN];
|
|
static bool sound_source_filename_copied = false;
|
|
if(!sound_source_filename_copied)
|
|
{
|
|
strncpy(sound_source_filename_buffer, sound_source->source_buffer->filename, MAX_FILENAME_LEN);
|
|
sound_source_filename_copied = true;
|
|
}
|
|
nk_label(context, "File", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
struct nk_rect sound_source_filename_bounds = nk_widget_bounds(context);
|
|
nk_button_label(context, sound_source->source_buffer->filename);
|
|
if(nk_input_is_mouse_hovering_rect(context, sound_source_filename_bounds))
|
|
nk_tooltip(context, "Right-click to change");
|
|
|
|
if(nk_contextual_begin(context, 0, nk_vec2(200, 120), sound_source_filename_bounds))
|
|
{
|
|
nk_layout_row_dynamic(context, 28, 1);
|
|
int edit_flags = NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_SIG_ENTER;
|
|
int edit_state = nk_edit_string_zero_terminated(context, edit_flags, sound_source_filename_buffer, MAX_FILENAME_LEN, NULL);
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
if(edit_state & NK_EDIT_COMMITED || nk_button_label(context, "OK"))
|
|
{
|
|
if(strncmp(sound_source_filename_buffer, sound_source->source_buffer->filename, MAX_FILENAME_LEN) != 0)
|
|
{
|
|
struct Sound_Source_Buffer* new_source_buffer = sound_source_buffer_create(sound, sound_source_filename_buffer, ST_WAV_STREAM);
|
|
if(new_source_buffer)
|
|
{
|
|
sound_source_buffer_stop_all(sound, sound_source->source_buffer);
|
|
sound_source_instance_destroy(sound, sound_source->source_instance);
|
|
sound_source->source_instance = sound_source_instance_create(sound, new_source_buffer, true);
|
|
sound_source->source_buffer = new_source_buffer;
|
|
sound_source->base.transform.is_modified = true; // Fake a transformation so that post-update the new sound source position is updated
|
|
if(playing)
|
|
sound_source_instance_play(sound, sound_source->source_instance);
|
|
}
|
|
}
|
|
sound_source_filename_copied = false;
|
|
nk_contextual_close(context);
|
|
}
|
|
nk_contextual_end(context);
|
|
}
|
|
|
|
nk_tree_pop(context);
|
|
}
|
|
|
|
}
|
|
|
|
/* Static Mesh */
|
|
if(entity->type == ET_STATIC_MESH)
|
|
{
|
|
struct Static_Mesh* mesh = (struct Static_Mesh*)entity;
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Static Mesh", NK_MAXIMIZED))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Geometry", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
|
|
static char geometry_filename_buffer[MAX_FILENAME_LEN];
|
|
static bool geometry_name_copied = false;
|
|
struct Geometry* geometry = geom_get(mesh->model.geometry_index);
|
|
|
|
if(!geometry_name_copied)
|
|
{
|
|
strncpy(geometry_filename_buffer, geometry->filename, MAX_FILENAME_LEN);
|
|
geometry_name_copied = true;
|
|
}
|
|
|
|
struct nk_rect geometry_name_bounds = nk_widget_bounds(context);
|
|
nk_button_label(context, geometry->filename);
|
|
if(nk_input_is_mouse_hovering_rect(context, geometry_name_bounds))
|
|
nk_tooltip(context, "Right-click to change");
|
|
|
|
if(nk_contextual_begin(context, 0, nk_vec2(250, 120), geometry_name_bounds))
|
|
{
|
|
nk_layout_row_dynamic(context, 28, 1);
|
|
int edit_flags = NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_SIG_ENTER;
|
|
int geometry_buffer_edit_state = nk_edit_string_zero_terminated(context, edit_flags, geometry_filename_buffer, MAX_FILENAME_LEN, NULL);
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
if(geometry_buffer_edit_state & NK_EDIT_COMMITED || nk_button_label(context, "OK"))
|
|
{
|
|
if(strncmp(geometry->filename, geometry_filename_buffer, MAX_FILENAME_LEN) != 0)
|
|
{
|
|
model_geometry_set(&mesh->model, &geometry_filename_buffer);
|
|
}
|
|
geometry_name_copied = false;
|
|
nk_contextual_close(context);
|
|
}
|
|
nk_contextual_end(context);
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Material", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
static const char* material_types[] = { "Blinn", "Unshaded" };
|
|
int selected_material = nk_combo(context, material_types, 2, mesh->model.material->type, row_height, nk_vec2(180, 180));
|
|
if(selected_material != mesh->model.material->type)
|
|
{
|
|
material_unregister_static_mesh(mesh->model.material, mesh);
|
|
struct Material* new_material = &game_state_get()->renderer->materials[selected_material];
|
|
if(!material_register_static_mesh(new_material, mesh))
|
|
{
|
|
log_error("editor:update", "Failed to register mesh with material");
|
|
}
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Diffuse Color", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
editor_widget_color_combov4(context, &mesh->model.material_params[MMP_DIFFUSE_COL].val_vec4, 200, 300);
|
|
|
|
nk_layout_row_dynamic(context, row_height * 4, 2);
|
|
const char* diffuse_texture_name = texture_get_name(mesh->model.material_params[MMP_DIFFUSE_TEX].val_int);
|
|
nk_label(context, "Diffuse Texture", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
static char diffuse_tex_filename_buffer[MAX_FILENAME_LEN];
|
|
static bool diffuse_texture_name_copied = false;
|
|
if(!diffuse_texture_name_copied)
|
|
{
|
|
strncpy(diffuse_tex_filename_buffer, diffuse_texture_name, MAX_FILENAME_LEN);
|
|
diffuse_texture_name_copied = true;
|
|
}
|
|
|
|
struct nk_rect diffuse_texture_bounds = nk_widget_bounds(context);
|
|
nk_button_image(context, nk_image_id(mesh->model.material_params[MMP_DIFFUSE_TEX].val_int));
|
|
if(nk_input_is_mouse_hovering_rect(context, diffuse_texture_bounds))
|
|
nk_tooltip(context, "Right-click to change");
|
|
if(nk_contextual_begin(context, 0, nk_vec2(250, 120), diffuse_texture_bounds))
|
|
{
|
|
nk_layout_row_dynamic(context, 26, 1);
|
|
int edit_flags = NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_SIG_ENTER;
|
|
int diffuse_texture_buffer_edit_state = nk_edit_string_zero_terminated(context, edit_flags, diffuse_tex_filename_buffer, MAX_FILENAME_LEN, NULL);
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
if(diffuse_texture_buffer_edit_state & NK_EDIT_COMMITED || nk_button_label(context, "OK"))
|
|
{
|
|
if(strncmp(diffuse_texture_name, diffuse_tex_filename_buffer, MAX_FILENAME_LEN) != 0)
|
|
{
|
|
int new_diffuse_texture = texture_create_from_file(&diffuse_tex_filename_buffer, TU_DIFFUSE);
|
|
if(new_diffuse_texture != -1)
|
|
{
|
|
mesh->model.material_params[MMP_DIFFUSE_TEX].val_int = new_diffuse_texture;
|
|
}
|
|
}
|
|
diffuse_texture_name_copied = false;
|
|
nk_contextual_close(context);
|
|
}
|
|
nk_contextual_end(context);
|
|
}
|
|
|
|
if(mesh->model.material->type == MAT_BLINN)
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
mesh->model.material_params[MMP_DIFFUSE].val_float = nk_propertyf(context, "Diffuse", 0.f, mesh->model.material_params[MMP_DIFFUSE].val_float, 10.f, 0.5f, 0.1f);
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
mesh->model.material_params[MMP_SPECULAR].val_float = nk_propertyf(context, "Specular", 0.f, mesh->model.material_params[MMP_SPECULAR].val_float, 10.f, 0.5f, 0.1f);
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
mesh->model.material_params[MMP_SPECULAR_STRENGTH].val_float = nk_propertyf(context, "Specular Strength", 0.f, mesh->model.material_params[MMP_SPECULAR_STRENGTH].val_float, 100.f, 0.5f, 0.1f);
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_label(context, "UV Scale", NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_CENTERED);
|
|
editor_widget_v2(context, &mesh->model.material_params[MMP_UV_SCALE].val_vec2, "U", "V", 0.f, FLT_MAX, 0.1f, 0.1f, row_height);
|
|
|
|
nk_tree_pop(context);
|
|
}
|
|
}
|
|
|
|
|
|
/* Enemy */
|
|
if(entity->type == ET_ENEMY)
|
|
{
|
|
struct Enemy* enemy = (struct Enemy*)entity;
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Enemy", NK_MAXIMIZED))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_property_int(context, "Damage", -INT_MAX, &enemy->damage, INT_MAX, 1, 1);
|
|
nk_property_int(context, "Health", 0, &enemy->health, INT_MAX, 1, 1);
|
|
|
|
switch(enemy->type)
|
|
{
|
|
case ENEMY_TURRET:
|
|
{
|
|
nk_property_float(context, "Turn Speed Default", 0.f, &enemy->Turret.turn_speed_default, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Turn Speed Targetting", 0.f, &enemy->Turret.turn_speed_when_targetting, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Turn Speed Current", 0.f, &enemy->Turret.turn_speed_current, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Max Yaw", 0.f, &enemy->Turret.max_yaw, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Target Yaw", 0.f, &enemy->Turret.target_yaw, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Pulsate Speed Scale", 0.f, &enemy->Turret.pulsate_speed_scale, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Pulsate Height", 0.f, &enemy->Turret.pulsate_height, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Attack Cooldown", 0.f, &enemy->Turret.attack_cooldown, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Time since attack", 0.f, &enemy->Turret.time_elapsed_since_attack, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Time since alert", 0.f, &enemy->Turret.time_elapsed_since_alert, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Alert Cooldown", 0.f, &enemy->Turret.alert_cooldown, FLT_MAX, 0.5f, 0.1f);
|
|
nk_property_float(context, "Vision Range", 0.f, &enemy->Turret.vision_range, FLT_MAX, 0.5f, 0.1f);
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Yaw Positive", LABEL_FLAGS_ALIGN_LEFT); nk_labelf(context, LABEL_FLAGS_ALIGN_LEFT, "%s", enemy->Turret.yaw_direction_positive ? "True" : "False");
|
|
nk_label(context, "Pulsate", LABEL_FLAGS_ALIGN_LEFT); nk_labelf(context, LABEL_FLAGS_ALIGN_LEFT, "%s", enemy->Turret.pulsate ? "True" : "False");
|
|
nk_label(context, "Scan", LABEL_FLAGS_ALIGN_LEFT); nk_labelf(context, LABEL_FLAGS_ALIGN_LEFT, "%s", enemy->Turret.scan ? "True" : "False");
|
|
nk_label(context, "Default Color", LABEL_FLAGS_ALIGN_LEFT); editor_widget_color_combov4(context, &enemy->Turret.color_default, 50, row_height * 2);
|
|
nk_label(context, "Alert Color", LABEL_FLAGS_ALIGN_LEFT); editor_widget_color_combov4(context, &enemy->Turret.color_alert, 50, row_height * 2);
|
|
nk_label(context, "Attack Color", LABEL_FLAGS_ALIGN_LEFT); editor_widget_color_combov4(context, &enemy->Turret.color_attack, 50, row_height * 2);
|
|
}
|
|
break;
|
|
}
|
|
nk_tree_pop(context);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nk_label(context, "No Entity Selected", NK_TEXT_ALIGN_CENTERED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
editor->window_property_inspector = false;
|
|
}
|
|
nk_end(context);
|
|
}
|
|
|
|
void editor_window_renderer_settings(struct nk_context* context, struct Editor* editor, struct Game_State* game_state)
|
|
{
|
|
int win_width = 0, win_height = 0;
|
|
window_get_drawable_size(game_state->window, &win_width, &win_height);
|
|
int half_width = win_width / 2, half_height = win_height / 2;
|
|
|
|
const int row_height = 25;
|
|
if(nk_begin_titled(context, "Renderer_Settings_Window", "Renderer Settings", nk_rect(half_width, half_height, 300, 350), window_flags))
|
|
{
|
|
struct Render_Settings* render_settings = &game_state->renderer->settings;
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Debug", NK_MAXIMIZED))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Debug Draw", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
render_settings->debug_draw_enabled = nk_check_label(context, "", render_settings->debug_draw_enabled);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Debug Draw Mode", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
static const char* draw_modes[] = { "Triangles", "Lines", "Points" };
|
|
render_settings->debug_draw_mode = nk_combo(context, draw_modes, 3, render_settings->debug_draw_mode, 20, nk_vec2(180, 100));
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Debug Color", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
editor_widget_color_combov4(context, &render_settings->debug_draw_color, 200, 400);
|
|
nk_tree_pop(context);
|
|
}
|
|
|
|
if(nk_tree_push(context, NK_TREE_TAB, "Fog", NK_MAXIMIZED))
|
|
{
|
|
static const char* fog_modes[] = { "None", "Linear", "Exponential", "Exponential Squared" };
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Color", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
editor_widget_color_combov3(context, &render_settings->fog.color, 200, 400);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Fog Mode", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
render_settings->fog.mode = nk_combo(context,
|
|
fog_modes,
|
|
4,
|
|
render_settings->fog.mode,
|
|
20,
|
|
nk_vec2(180, 100));
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Density", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
struct nk_rect bounds = nk_widget_bounds(context);
|
|
nk_slider_float(context, 0.f, &render_settings->fog.density, 1.f, 0.005);
|
|
if(nk_input_is_mouse_hovering_rect(&context->input, bounds))
|
|
{
|
|
if(nk_tooltip_begin(context, 100))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_labelf(context, NK_TEXT_ALIGN_CENTERED, "%.3f", render_settings->fog.density);
|
|
nk_tooltip_end(context);
|
|
}
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_property_float(context,
|
|
"Start Distance",
|
|
0.f,
|
|
&render_settings->fog.start_dist,
|
|
render_settings->fog.max_dist,
|
|
5.f, 10.f);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_property_float(context,
|
|
"Max Distance",
|
|
render_settings->fog.start_dist,
|
|
&render_settings->fog.max_dist,
|
|
10000.f,
|
|
5.f, 10.f);
|
|
|
|
nk_tree_pop(context);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
editor->window_settings_renderer = 0;
|
|
}
|
|
nk_end(context);
|
|
}
|
|
|
|
void editor_window_settings_editor(struct nk_context* context, struct Editor* editor, struct Game_State* game_state)
|
|
{
|
|
int win_width = 0, win_height = 0;
|
|
window_get_drawable_size(game_state->window, &win_width, &win_height);
|
|
int half_width = win_width / 2, half_height = win_height / 2;
|
|
|
|
const int row_height = 25;
|
|
if(nk_begin_titled(context, "Window_Settings_Editor", "Editor Settings", nk_rect(half_width, half_height, 300, 350), window_flags))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Grid Enabled", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
nk_checkbox_label(context, "", &editor->grid_enabled);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 2);
|
|
nk_label(context, "Grid Color", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
|
|
editor_widget_color_combov4(context, &editor->grid_color, 200, 400);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_property_int(context, "Grid Lines", 10, &editor->grid_num_lines, 200, 1, 1);
|
|
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
nk_property_float(context, "Grid Scale", 0.25f, &editor->grid_scale, 10.f, 1, 0.25f);
|
|
}
|
|
else
|
|
{
|
|
editor->window_settings_editor = 0;
|
|
}
|
|
nk_end(context);
|
|
}
|
|
|
|
void editor_entity_dialog(struct Editor* editor, struct nk_context* context)
|
|
{
|
|
struct Game_State* game_state = game_state_get();
|
|
struct Scene* scene = game_state->scene;
|
|
bool save = editor->entity_operation_save;
|
|
int row_height = 25;
|
|
int popup_x = 0;
|
|
int popup_y = 0;
|
|
int popup_width = 300;
|
|
int popup_height = 200;
|
|
int display_width = 0;
|
|
int display_height = 0;
|
|
int popup_flags = NK_WINDOW_TITLE | NK_WINDOW_BORDER;
|
|
window_get_drawable_size(game_state_get()->window, &display_width, &display_height);
|
|
popup_x = (display_width / 2) - (popup_width / 2);
|
|
popup_y = (display_height / 2) - (popup_height / 2);
|
|
|
|
int background_window_flags = NK_WINDOW_BACKGROUND;
|
|
int previous_opacity = context->style.window.fixed_background.data.color.a;
|
|
context->style.window.fixed_background.data.color.a = 120;
|
|
if(nk_begin(context, save ? "Entity Save" : "Entity Load", nk_recti(0, 0, display_width, display_height), background_window_flags))
|
|
{
|
|
nk_window_set_focus(context, save ? "Entity Save" : "Entity Load");
|
|
if(nk_popup_begin(context, NK_POPUP_DYNAMIC, save ? "Save Entity" : "Load Entity", popup_flags, nk_recti(popup_x, popup_y, popup_width, popup_height)))
|
|
{
|
|
nk_layout_row_dynamic(context, row_height, 1);
|
|
if(save && !editor->selected_entity)
|
|
{
|
|
nk_label_colored(context, "Please select an entity first in order to save it", NK_TEXT_ALIGN_CENTERED | NK_TEXT_ALIGN_MIDDLE, nk_rgb_f(1.f, 1.f, 0.f));
|
|
if(nk_button_label(context, "OK"))
|
|
{
|
|
editor->window_entity_dialog = 0;
|
|
nk_popup_close(context);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nk_label(context, "Enter the name of the entity:", NK_TEXT_ALIGN_CENTERED | NK_TEXT_ALIGN_MIDDLE);
|
|
|
|
static char entity_filename[MAX_FILENAME_LEN];
|
|
static bool copy_entity_filename = true;
|
|
|
|
if(copy_entity_filename)
|
|
{
|
|
memset(entity_filename, '\0', MAX_FILENAME_LEN);
|
|
if(save && editor->selected_entity->archetype_index != -1)
|
|
strncpy(entity_filename, scene->entity_archetypes[editor->selected_entity->archetype_index], MAX_FILENAME_LEN);
|
|
}
|
|
|
|
int entity_filename_flags = NK_EDIT_SIG_ENTER | NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_ALWAYS_INSERT_MODE;
|
|
nk_edit_focus(context, entity_filename_flags);
|
|
int entity_filename_state = nk_edit_string_zero_terminated(context, entity_filename_flags, entity_filename, MAX_FILENAME_LEN, NULL);
|
|
debug_vars_show_int("Edit State", entity_filename_state);
|
|
if(entity_filename_state & NK_EDIT_ACTIVATED || entity_filename_state & NK_EDIT_ACTIVE)
|
|
{
|
|
copy_entity_filename = false;
|
|
}
|
|
|
|
if(entity_filename_state & NK_EDIT_COMMITED)
|
|
{
|
|
if(save)
|
|
{
|
|
entity_save(editor->selected_entity, entity_filename, DIRT_INSTALL);
|
|
}
|
|
else
|
|
{
|
|
struct Entity* new_entity = entity_load(entity_filename, DIRT_INSTALL, true);
|
|
if(new_entity)
|
|
{
|
|
editor_entity_select(editor, new_entity);
|
|
}
|
|
}
|
|
copy_entity_filename = true;
|
|
editor->window_entity_dialog = 0;
|
|
nk_popup_close(context);
|
|
}
|
|
|
|
nk_layout_row_dynamic(context, row_height, 3);
|
|
if(nk_button_label(context, "OK"))
|
|
{
|
|
if(save)
|
|
{
|
|
entity_save(editor->selected_entity, entity_filename, DIRT_INSTALL);
|
|
}
|
|
else
|
|
{
|
|
struct Entity* new_entity = entity_load(entity_filename, DIRT_INSTALL, true);
|
|
if(new_entity)
|
|
{
|
|
editor_entity_select(editor, new_entity);
|
|
}
|
|
}
|
|
copy_entity_filename = true;
|
|
editor->window_entity_dialog = 0;
|
|
nk_popup_close(context);
|
|
}
|
|
|
|
nk_spacing(context, 1);
|
|
|
|
if(nk_button_label(context, "Cancel"))
|
|
{
|
|
copy_entity_filename = true;
|
|
editor->window_entity_dialog = 0;
|
|
nk_popup_close(context);
|
|
}
|
|
}
|
|
|
|
nk_popup_end(context);
|
|
}
|
|
nk_end(context);
|
|
}
|
|
else
|
|
{
|
|
editor->window_entity_dialog = 0;
|
|
}
|
|
context->style.window.fixed_background.data.color.a = previous_opacity;
|
|
}
|
|
|
|
void editor_post_update(struct Editor* editor)
|
|
{
|
|
if(editor->hovered_entity && !(editor->hovered_entity->flags & EF_ACTIVE))
|
|
editor->hovered_entity = NULL;
|
|
}
|
|
|
|
|