Gizmo_Space :: enum { LOCAL; WORLD; } Transform_Axis :: enum { NONE; UP; FORWARD; RIGHT; CENTER; } Transform_Type :: enum { TRANSLATION; ROTATION; SCALE; } Editor_Undo_Type :: enum { TRANSFORM_CHANGE; } Editor_Undo :: struct { type: Editor_Undo_Type; entity: *Entity; union { transform : struct { position: Vector3; rotation: Quaternion; scale: Vector3; }; } } push_transform_undo :: (e: *Entity) { undo: Editor_Undo; undo.type = .TRANSFORM_CHANGE; undo.entity = e; undo.transform.position = e.transform.position; undo.transform.scale = e.transform.scale; undo.transform.rotation = e.transform.orientation; array_add(*engine.editor.undo_stack, undo); } undo :: () { if engine.editor.undo_stack.count == 0 return; print("UNDO!\n"); undo := engine.editor.undo_stack[engine.editor.undo_stack.count-1]; if undo.type == { case .TRANSFORM_CHANGE; { set_position_rotation_scale(undo.entity, undo.transform.position, undo.transform.rotation, undo.transform.scale); } } engine.editor.undo_stack.count -= 1; } Buffer_Info :: struct { buffer: Buffer_Handle; vertex_count: u32; } Transform_Gizmo :: struct { active: bool = false; transform_type: Transform_Type = .TRANSLATION; space: Gizmo_Space; selected_axis: Transform_Axis; first_hit_position: Vector3; actual_entity_position: Vector3; // The actual position of the selected entity. Used for snapping actual_entity_scale: Vector3; // The actual position of the selected entity. Used for snapping last_circle_dir: Vector3; // Settings snap_to_grid: bool; clicked: bool; transform: Transform; can_use: bool = true; center_model_buffer: Buffer_Handle; up_model_buffer: Buffer_Handle; forward_model_buffer: Buffer_Handle; right_model_buffer: Buffer_Handle; color_center: Color; color_up: Color; color_forward: Color; color_right: Color; color_center_buffer: Buffer_Handle; color_up_buffer: Buffer_Handle; color_forward_buffer: Buffer_Handle; color_right_buffer: Buffer_Handle; pipeline: Pipeline_State_Handle; uniform_gizmo_scale: float; } Editor :: struct { focused_widget: *UI_Box; show_menu: bool; should_check_entities: bool; camera: Camera; transform_gizmo: Transform_Gizmo; selected_entities: [..] *Entity; mouse_viewport_state: Interaction_State; last_right_mouse_click_time: float; menu_position: Vector2; hide_ui: bool; icons : struct { play: Texture_Handle; stop: Texture_Handle; } undo_stack: [..] Editor_Undo; } init_editor :: () { aspect_ratio := cast(float)engine.renderer.render_target_width / cast(float)engine.renderer.render_target_height; engine.editor.camera = create_perspective_camera(.{0, 10, -10}, yaw=0, pitch=-40, roll=0.0, fov=40, aspect=aspect_ratio); init_transform_gizmo(); engine.editor.icons.play = create_texture(engine.renderer, "../modules/Coven/assets/textures/ui_icons/play.png", false); engine.editor.icons.stop = create_texture(engine.renderer, "../modules/Coven/assets/textures/ui_icons/stop.png", false); } init_transform_gizmo :: () { gizmo : Transform_Gizmo; gizmo.selected_axis = .NONE; gizmo.transform = create_identity_transform(); gizmo.center_model_buffer = create_constant_buffer(engine.renderer, null, size_of(Matrix4), mappable=true); gizmo.up_model_buffer = create_constant_buffer(engine.renderer, null, size_of(Matrix4), mappable=true); gizmo.forward_model_buffer = create_constant_buffer(engine.renderer, null, size_of(Matrix4), mappable=true); gizmo.right_model_buffer = create_constant_buffer(engine.renderer, null, size_of(Matrix4), mappable=true); gizmo.color_center = Color.{1,1,1,1}; gizmo.color_up = Color.{0,1,0,1}; gizmo.color_forward = Color.{0,0,1,1}; gizmo.color_right = Color.{1,0,0,1}; gizmo.color_center_buffer = create_constant_buffer(engine.renderer, *gizmo.color_center, size_of(Vector4), mappable=true); gizmo.color_up_buffer = create_constant_buffer(engine.renderer, *gizmo.color_up, size_of(Vector4), mappable=true); gizmo.color_forward_buffer = create_constant_buffer(engine.renderer, *gizmo.color_forward, size_of(Vector4), mappable=true); gizmo.color_right_buffer = create_constant_buffer(engine.renderer, *gizmo.color_right, size_of(Vector4), mappable=true); engine.editor.transform_gizmo = gizmo; // Transform gizmo shader { vs := create_vertex_shader_from_source(engine.renderer, "Transform Gizmo", TRANSFORM_GIZMO_SHADER, "VS", mesh_data_types = .[.POSITION]); ps := create_pixel_shader_from_source(engine.renderer, "Transform Gizmo", TRANSFORM_GIZMO_SHADER, "PS"); engine.editor.transform_gizmo.pipeline = create_pipeline_state2(engine.renderer, vs, ps, blend_type=.OPAQUE); } } update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool { if engine.editor.selected_entities.count != 1 return false; selected_entity := engine.editor.selected_entities[0]; if key_down(.TAB) { if engine.editor.transform_gizmo.space == { case .WORLD; engine.editor.transform_gizmo.space = .LOCAL; case .LOCAL; engine.editor.transform_gizmo.space = .WORLD; } } if engine.editor.transform_gizmo.space == { case .WORLD; set_rotation(*engine.editor.transform_gizmo.transform, .{0,0,0,1}); case .LOCAL; set_rotation(*engine.editor.transform_gizmo.transform, selected_entity.transform.orientation); } if engine.editor.transform_gizmo.transform_type == { case .TRANSLATION; if !key_pressed(.MOUSE_LEFT) { selected_axis, t := intersect_translation_gizmo(ray); engine.editor.transform_gizmo.selected_axis = selected_axis; } else if engine.editor.transform_gizmo.can_use && engine.editor.transform_gizmo.selected_axis != .NONE { first_update := key_down(.MOUSE_LEFT); if first_update { engine.editor.transform_gizmo.actual_entity_position = selected_entity.transform.position; push_transform_undo(engine.editor.selected_entities[0]); } // Move the currently selected entity along the selected axis axis_vec : Vector3; if engine.editor.transform_gizmo.selected_axis == { case .UP; axis_vec.y = 1; case .FORWARD; axis_vec.z = 1; case .RIGHT; axis_vec.x = 1; } r1 : Ray; r1.origin = selected_entity.transform.position; r1.direction = rotate(axis_vec, engine.editor.transform_gizmo.transform.orientation); r2 := normalized_screen_to_ray_v2(*engine.editor.camera, mouse_position); d, t1, t2 := closest_distance_between_rays(r1, r2); new_position := r1.origin + r1.direction * t1; if first_update { engine.editor.transform_gizmo.first_hit_position = new_position; } position_change := new_position - engine.editor.transform_gizmo.first_hit_position; entity_position := engine.editor.transform_gizmo.actual_entity_position + position_change; if engine.editor.transform_gizmo.snap_to_grid { snap_interval := Vector3.{1,1,1}; entity_position.x -= fmod_cycling(entity_position.x - selected_entity.snap_offset.x, snap_interval.x);// + selected_entity.snap_offset.x; entity_position.y -= fmod_cycling(entity_position.y - selected_entity.snap_offset.y, snap_interval.y);// + selected_entity.snap_offset.y; entity_position.z -= fmod_cycling(entity_position.z - selected_entity.snap_offset.z, snap_interval.z);// + selected_entity.snap_offset.z; } else if selected_entity.flags & Entity_Flags.SNAP_TO_GRID { entity_position.x -= fmod_cycling(entity_position.x - selected_entity.snap_offset.x, selected_entity.snap_intervals.x);// + selected_entity.snap_offset.x; entity_position.y -= fmod_cycling(entity_position.y - selected_entity.snap_offset.y, selected_entity.snap_intervals.y);// + selected_entity.snap_offset.y; entity_position.z -= fmod_cycling(entity_position.z - selected_entity.snap_offset.z, selected_entity.snap_intervals.z);// + selected_entity.snap_offset.z; } selected_entity.transform.position = entity_position; selected_entity.transform.dirty = true; set_position(*engine.editor.transform_gizmo.transform, entity_position); } color_up := engine.editor.transform_gizmo.color_up; color_forward := engine.editor.transform_gizmo.color_forward; color_right := engine.editor.transform_gizmo.color_right; if engine.editor.transform_gizmo.selected_axis == { case .NONE; case .UP; color_up = Color.{1,1,0,1}; case .FORWARD; color_forward = Color.{1,1,0,1}; case .RIGHT; color_right = Color.{1,1,0,1}; } upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_up_buffer, *color_up, size_of(Color)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_forward_buffer, *color_forward, size_of(Color)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_right_buffer, *color_right, size_of(Color)); case .ROTATION; selected_entity := engine.editor.selected_entities[0]; if !engine.editor.transform_gizmo.clicked { selected_axis, point := intersect_rotation_gizmo(ray); engine.editor.transform_gizmo.selected_axis = selected_axis; if engine.editor.transform_gizmo.selected_axis != .NONE && key_down(.MOUSE_LEFT) { engine.editor.transform_gizmo.clicked = true; engine.editor.transform_gizmo.last_circle_dir = normalize(point - selected_entity.transform.position); } } else if !key_pressed(.MOUSE_LEFT) { engine.editor.transform_gizmo.clicked = false; } else { if key_down(.MOUSE_LEFT) { push_transform_undo(engine.editor.selected_entities[0]); } direction : Vector3; if engine.editor.transform_gizmo.selected_axis == { case .UP; direction = .{0,1,0}; case .FORWARD; direction = .{0,0,1}; case .RIGHT; direction = .{1,0,0}; } direction = rotate(direction, engine.editor.transform_gizmo.transform.orientation); // Find the rotation circle : Circle; circle.radius = engine.editor.transform_gizmo.uniform_gizmo_scale; circle.center = selected_entity.transform.position; circle.orientation = direction; distance, point := closest_distance_ray_circle(ray, circle); new_dir := normalize(point - selected_entity.transform.position); dotp := dot(engine.editor.transform_gizmo.last_circle_dir, new_dir); angle := acos(clamp(dotp, -1.0, 1.0)); cp := cross(engine.editor.transform_gizmo.last_circle_dir, new_dir); if dot(direction, cp) < 0 { angle *= -1.0; } q : Quaternion; set_from_axis_and_angle(*q, direction, angle); selected_entity.transform.orientation = q * selected_entity.transform.orientation; update_matrix(*selected_entity.transform); set_rotation(*engine.editor.transform_gizmo.transform, selected_entity.transform.orientation); engine.editor.transform_gizmo.last_circle_dir = new_dir; } color_up := engine.editor.transform_gizmo.color_up; color_forward := engine.editor.transform_gizmo.color_forward; color_right := engine.editor.transform_gizmo.color_right; if engine.editor.transform_gizmo.selected_axis == { case .NONE; case .UP; color_up = Color.{1,1,0,1}; case .FORWARD; color_forward = Color.{1,1,0,1}; case .RIGHT; color_right = Color.{1,1,0,1}; } upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_up_buffer, *color_up, size_of(Color)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_forward_buffer, *color_forward, size_of(Color)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_right_buffer, *color_right, size_of(Color)); case .SCALE; if !key_pressed(.MOUSE_LEFT) { selected_axis, t := intersect_scale_gizmo(ray); engine.editor.transform_gizmo.selected_axis = selected_axis; } else if engine.editor.transform_gizmo.selected_axis != .NONE { selected_entity := engine.editor.selected_entities[0]; first_update := key_down(.MOUSE_LEFT); if first_update { push_transform_undo(engine.editor.selected_entities[0]); engine.editor.transform_gizmo.actual_entity_position = selected_entity.transform.position; engine.editor.transform_gizmo.actual_entity_scale = selected_entity.transform.scale; } // Move the currently selected entity along the selected axis axis_vec : Vector3; if engine.editor.transform_gizmo.selected_axis == { case .UP; axis_vec.y = 1; case .FORWARD; axis_vec.z = -1; case .RIGHT; axis_vec.x = 1; case .CENTER; axis_vec = .{1,1,1}; } r1 : Ray; r1.origin = selected_entity.transform.position; r1.direction = rotate(axis_vec, engine.editor.transform_gizmo.transform.orientation); // Shoot a ray from screen to world mouse_position : Vector2; mouse_position.x = xx engine.input.mouse.x; mouse_position.y = xx engine.input.mouse.y; screen_size : Vector2; screen_size.x = cast(float)engine.window.width; screen_size.y = cast(float)engine.window.height; r2 := screen_to_ray_v2(*engine.editor.camera, mouse_position, screen_size); d, t1, t2 := closest_distance_between_rays(r1, r2); new_position := r1.origin + r1.direction * t1; if first_update { engine.editor.transform_gizmo.first_hit_position = new_position; } position_change := new_position - engine.editor.transform_gizmo.first_hit_position; // @Robustness: Why though? position_change.z *= -1.0; position_change.y *= -1.0; scale_speed := ifx key_pressed(.SHIFT) then 4.0 else 1.0; if selected_entity.flags & .UNIFORM_SCALE { current_scale := selected_entity.transform.scale; if engine.editor.transform_gizmo.selected_axis == { case .UP; { current_scale.y = engine.editor.transform_gizmo.actual_entity_scale.y + position_change.y * scale_speed; position_change.x = 0; position_change.z = 0; } case .FORWARD; { current_scale.z = engine.editor.transform_gizmo.actual_entity_scale.z + position_change.z * scale_speed; position_change.x = 0; position_change.y = 0; } case .RIGHT; { current_scale.x = engine.editor.transform_gizmo.actual_entity_scale.x + position_change.x * scale_speed; position_change.y = 0; position_change.z = 0; } case .CENTER; { current_scale.x = engine.editor.transform_gizmo.actual_entity_scale.x + position_change.x * scale_speed; current_scale.y = current_scale.x; // @Incomplete: This is most definitely wrong! current_scale.z = current_scale.x; position_change.y = 0; position_change.z = 0; } } set_scale(*selected_entity.transform, current_scale); } else { if engine.editor.transform_gizmo.selected_axis == { case .UP; position_change.x = 0; position_change.z = 0; case .FORWARD; position_change.x = 0; position_change.y = 0; case .RIGHT; position_change.y = 0; position_change.z = 0; } entity_scale := engine.editor.transform_gizmo.actual_entity_scale + position_change * scale_speed; set_scale(*selected_entity.transform, entity_scale); } } color_up := engine.editor.transform_gizmo.color_up; color_forward := engine.editor.transform_gizmo.color_forward; color_right := engine.editor.transform_gizmo.color_right; color_center := Color.{1,1,1,1}; if engine.editor.transform_gizmo.selected_axis == { case .NONE; case .UP; color_up = Color.{1,1,0,1}; case .FORWARD; color_forward = Color.{1,1,0,1}; case .RIGHT; color_right = Color.{1,1,0,1}; case .CENTER; color_center = Color.{1,1,0,1}; } upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_center_buffer, *color_center, size_of(Color)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_up_buffer, *color_up, size_of(Color)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_forward_buffer, *color_forward, size_of(Color)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.color_right_buffer, *color_right, size_of(Color)); } return engine.editor.transform_gizmo.selected_axis != .NONE; } intersect_translation_gizmo :: (ray: Ray) -> Transform_Axis, float { transform := engine.editor.transform_gizmo.transform; origin := transform.position; orientation := transform.orientation; up_ray: Ray; up_ray.origin = origin; up_ray.direction = rotate(.{0,1,0}, orientation); right_ray: Ray; right_ray.origin = origin; right_ray.direction = rotate(.{1,0,0}, orientation); forward_ray: Ray; forward_ray.origin = origin; forward_ray.direction = rotate(.{0,0,1}, orientation); max_dist :: 0.5; axis : Transform_Axis = .NONE; closest := 100000000.0; t := 0.0; GIZMO_LENGTH := 1.3 * engine.editor.transform_gizmo.uniform_gizmo_scale; du, tu1, tu2 := closest_distance_between_rays(ray, up_ray); if du <= max_dist && du < closest && tu1 >= 0.0 && tu2 < GIZMO_LENGTH { // Make sure that the point is not behind the gizmo if dot(up_ray.direction, normalize((ray.origin + ray.direction * tu1) - origin)) >= 0.0 { closest = du; t = tu1; axis = .UP; } } dr, tr1, tr2 := closest_distance_between_rays(ray, right_ray); if dr <= max_dist && dr < closest && tr1 >= 0.0 && tr2 < GIZMO_LENGTH { // Make sure that the point is not behind the gizmo if dot(right_ray.direction, normalize((ray.origin + ray.direction * tr1) - origin)) >= 0.0 { closest = dr; t = tr1; axis = .RIGHT; } } df, tf1, tf2 := closest_distance_between_rays(ray, forward_ray); if df <= max_dist && df < closest && tf1 >= 0.0 && tf2 < GIZMO_LENGTH { // Make sure that the point is not behind the gizmo if dot(forward_ray.direction, normalize((ray.origin + ray.direction * tf1) - origin)) >= 0.0 { closest = df; t = tf1; axis = .FORWARD; } } return axis, t; } intersect_scale_gizmo :: (ray: Ray) -> Transform_Axis, float { transform := engine.editor.transform_gizmo.transform; origin := transform.position; orientation := transform.orientation; radius := engine.editor.transform_gizmo.uniform_gizmo_scale * 0.15; if ray_sphere_intersect(ray, origin, radius) { return .CENTER, 0.0; } up_ray: Ray; up_ray.origin = origin; up_ray.direction = rotate(.{0,1,0}, orientation); right_ray: Ray; right_ray.origin = origin; right_ray.direction = rotate(.{1,0,0}, orientation); forward_ray: Ray; forward_ray.origin = origin; forward_ray.direction = rotate(.{0,0,1}, orientation); max_dist :: 0.5; axis : Transform_Axis = .NONE; closest := 100000000.0; t := 0.0; du, tu1, tu2 := closest_distance_between_rays(ray, up_ray); if du <= max_dist && du < closest && tu1 >= 0.0 { // Make sure that the point is not behind the gizmo if dot(up_ray.direction, normalize((ray.origin + ray.direction * tu1) - origin)) >= 0.0 { closest = du; t = tu1; axis = .UP; } } dr, tr1, tr2 := closest_distance_between_rays(ray, right_ray); if dr <= max_dist && dr < closest && tr1 >= 0.0 { // Make sure that the point is not behind the gizmo if dot(right_ray.direction, normalize((ray.origin + ray.direction * tr1) - origin)) >= 0.0 { closest = dr; t = tr1; axis = .RIGHT; } } df, tf1, tf2 := closest_distance_between_rays(ray, forward_ray); if df <= max_dist && df < closest && tf1 >= 0.0 { // Make sure that the point is not behind the gizmo if dot(forward_ray.direction, normalize((ray.origin + ray.direction * tf1) - origin)) >= 0.0 { closest = df; t = tf1; axis = .FORWARD; } } return axis, t; } Circle :: struct { center: Vector3; radius: float; orientation: Vector3; } closest_distance_ray_circle :: (r: Ray, c: Circle) -> float, Vector3 { plane_p := c.center; plane_orientation := c.orientation; success, t := ray_plane_intersection(r, plane_p, plane_orientation); if success { // get the ray's intersection point on the plane which // contains the circle on_plane := r.origin + t * r.direction; // project that point on to the circle's circumference point := c.center + c.radius * normalize(on_plane - c.center); return length(on_plane - point), point; } else { // the required point on the circle is the one closest to the camera origin point := c.radius * normalize(reject(r.origin - c.center, c.orientation)); return distance_from_ray_to_point(r, point), point; } } intersect_rotation_gizmo :: (ray: Ray) -> Transform_Axis, Vector3 { selected_entity := engine.editor.selected_entities[0]; orientation := selected_entity.transform.orientation; radius := engine.editor.transform_gizmo.uniform_gizmo_scale; up: Circle; up.radius = radius; up.center = engine.editor.transform_gizmo.transform.position; up.orientation = rotate(.{0,1,0}, orientation); right: Circle; right.radius = radius; right.center = engine.editor.transform_gizmo.transform.position; right.orientation = rotate(.{1,0,0}, orientation); forward: Circle; forward.radius = radius; forward.center = engine.editor.transform_gizmo.transform.position; forward.orientation = rotate(.{0,0,1}, orientation); min_dist :: 0.4; axis : Transform_Axis = .NONE; closest := 100000000.0; p : Vector3; du, pu := closest_distance_ray_circle(ray, up); if du <= min_dist && du < closest { closest = du; axis = .UP; p = pu; } dr, pr := closest_distance_ray_circle(ray, right); if dr <= min_dist && dr < closest { closest = dr; axis = .RIGHT; p = pr; } df, pf := closest_distance_ray_circle(ray, forward); if df <= min_dist && df < closest { closest = df; axis = .FORWARD; p = pf; } return axis, p; } update_gizmo_buffers :: () { entity := engine.editor.selected_entities[0]; engine.editor.transform_gizmo.transform.position = entity.transform.position; engine.editor.transform_gizmo.transform.orientation = ifx engine.editor.transform_gizmo.space == .LOCAL then entity.transform.orientation else .{0,0,0,1}; update_matrix(*engine.editor.transform_gizmo.transform); up_rotation := rotation_matrix(Matrix3, euler_to_quaternion(degrees_to_radians(90), degrees_to_radians(90), degrees_to_radians(0))); right_rotation := rotation_matrix(Matrix3, euler_to_quaternion(degrees_to_radians(90), degrees_to_radians(0), degrees_to_radians(90))); up_model := engine.editor.transform_gizmo.transform.model_matrix * up_rotation; right_model := engine.editor.transform_gizmo.transform.model_matrix * right_rotation; center_scale := make_scale_matrix4(.{0.15, 0.15, 0.15}); center_model := engine.editor.transform_gizmo.transform.model_matrix * center_scale; upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.center_model_buffer, *center_model, size_of(Matrix4)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.up_model_buffer, *up_model, size_of(Matrix4)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.forward_model_buffer, *engine.editor.transform_gizmo.transform.model_matrix, size_of(Matrix4)); upload_data_to_buffer(engine.renderer, engine.editor.transform_gizmo.right_model_buffer, *right_model, size_of(Matrix4)); } render_transform_gizmo :: () { if engine.editor.selected_entities.count == 1 { update_gizmo_buffers(); renderer := engine.renderer; push_cmd_set_draw_mode(renderer, .FILL); push_cmd_set_depth_write(renderer, false); push_cmd_set_pipeline_state(renderer, engine.editor.transform_gizmo.pipeline); push_cmd_set_constant_buffer(engine.renderer, 0, engine.camera_buffer,.VERTEX); render_gizmo :: (mesh: *Mesh) { renderer := engine.renderer; vb := get_mesh_vb(mesh, engine.editor.transform_gizmo.pipeline); // RIGHT push_cmd_set_constant_buffer(engine.renderer, 1, engine.editor.transform_gizmo.right_model_buffer, .VERTEX); push_cmd_set_constant_buffer(engine.renderer, 2, engine.editor.transform_gizmo.color_right_buffer, .PIXEL); push_cmd_set_vertex_buffer(renderer, vb); push_cmd_set_index_buffer(renderer, mesh.ib); push_cmd_draw_indexed(renderer, mesh.indices.count); // FORWARD push_cmd_set_constant_buffer(engine.renderer, 1, engine.editor.transform_gizmo.forward_model_buffer, .VERTEX); push_cmd_set_constant_buffer(engine.renderer, 2, engine.editor.transform_gizmo.color_forward_buffer, .PIXEL); push_cmd_set_vertex_buffer(renderer, vb); push_cmd_set_index_buffer(renderer, mesh.ib); push_cmd_draw_indexed(renderer, mesh.indices.count); // UP push_cmd_set_constant_buffer(engine.renderer, 1, engine.editor.transform_gizmo.up_model_buffer, .VERTEX); push_cmd_set_constant_buffer(engine.renderer, 2, engine.editor.transform_gizmo.color_up_buffer, .PIXEL); push_cmd_set_vertex_buffer(renderer, vb); push_cmd_set_index_buffer(renderer, mesh.ib); push_cmd_draw_indexed(renderer, mesh.indices.count); } if engine.editor.transform_gizmo.transform_type == { case .TRANSLATION; { mesh := parray_get(*engine.renderer.meshes, engine.renderer.default_meshes.translation_gizmo); render_gizmo(mesh); } case .SCALE; { mesh := parray_get(*engine.renderer.meshes, engine.renderer.default_meshes.scale_gizmo); render_gizmo(mesh); center_mesh := parray_get(*engine.renderer.meshes, engine.renderer.default_meshes.cube); push_cmd_set_constant_buffer(engine.renderer, 1, engine.editor.transform_gizmo.center_model_buffer, .VERTEX); push_cmd_set_constant_buffer(engine.renderer, 2, engine.editor.transform_gizmo.color_center_buffer, .PIXEL); vb := get_mesh_vb(mesh, engine.editor.transform_gizmo.pipeline); push_cmd_set_vertex_buffer(renderer, vb); push_cmd_set_index_buffer(renderer, center_mesh.ib); push_cmd_draw_indexed(renderer, center_mesh.indices.count); } case .ROTATION; { mesh := parray_get(*engine.renderer.meshes, engine.renderer.default_meshes.rotation_gizmo); render_gizmo(mesh); } } } } #load "editor_ui.jai"; #load "../renderer/shaders.jai";