Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dbartolini committed Nov 10, 2024
1 parent 3243ab2 commit f9dfee2
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 28 deletions.
10 changes: 5 additions & 5 deletions samples/core/editors/level_editor/camera.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ local function camera_tumble(self, x, y)
local camera_forward = Matrix4x4.z(camera_pose)

local rotation_up = Quaternion.from_axis_angle(Vector3.up(), drag_delta.x * self._rotation_speed)
local rotation_right = Quaternion.from_axis_angle(camera_right, drag_delta.y * self._rotation_speed)
local rotation_right = Quaternion.from_axis_angle(camera_right, -drag_delta.y * self._rotation_speed)
local rotate_delta = Matrix4x4.from_quaternion(Quaternion.multiply(rotation_up, rotation_right))

local target_position = camera_position + (camera_forward * self._target_distance)
Expand Down Expand Up @@ -58,9 +58,9 @@ local function camera_track(self, x, y)
end

local delta = (drag_delta.y * pan_speed) * camera_up
- (drag_delta.x * pan_speed) * camera_right
+ (drag_delta.x * pan_speed) * camera_right
local tr = SceneGraph.instance(self._sg, self._unit)
SceneGraph.set_local_position(self._sg, tr, camera_position + delta)
SceneGraph.set_local_position(self._sg, tr, camera_position - delta)
end

local function camera_dolly(self, x, y)
Expand All @@ -70,15 +70,15 @@ local function camera_dolly(self, x, y)
-- Zoom speed is proportional to initial orthographic size
local zoom_speed = self._drag_start_orthographic_size / 400
local zoom_delta = drag_delta.y * zoom_speed
self._orthographic_size = math.max(1, self._drag_start_orthographic_size + zoom_delta)
self._orthographic_size = math.max(1, self._drag_start_orthographic_size - zoom_delta)

World.camera_set_orthographic_size(self._world, self:camera(), self._orthographic_size)
else
-- Speed is proportional to initial distance from target
local move_speed = self._drag_start_target_distance / 400
local mouse_delta = drag_delta.y * move_speed

self._target_distance = math.max(1, self._drag_start_target_distance + mouse_delta)
self._target_distance = math.max(1, self._drag_start_target_distance - mouse_delta)
local move_delta = self._target_distance - self._drag_start_target_distance

local camera_pose = self._drag_start_camera_pose:unbox()
Expand Down
162 changes: 150 additions & 12 deletions samples/core/editors/level_editor/level_editor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ function dot_alpha(dot, fadeout_threshold, hidden_threshold)
-- | |
-- 00000fffff11111
--
if dot < h0 then -- The axis is parallel to the viewer.
if dot < h0 then
-- The axis is parallel to the viewer.
return 0
elseif dot < f0 then -- The axis is starting to get perpendicular to the viewer.
elseif dot < f0 then
-- The axis is starting to get perpendicular to the viewer.
return (dot - h0) / (f0 - h0)
end

Expand Down Expand Up @@ -452,10 +454,10 @@ function SelectTool:mouse_move(x, y)
-- | |
-- | |
-- p0 ---- p1
local p0, rd0 = LevelEditor:camera():camera_ray(rect_start.x, rect_end.y)
local p1, rd1 = LevelEditor:camera():camera_ray(rect_end.x , rect_end.y)
local p2, rd2 = LevelEditor:camera():camera_ray(rect_end.x , rect_start.y)
local p3, rd3 = LevelEditor:camera():camera_ray(rect_start.x, rect_start.y)
local p0, rd0 = LevelEditor:camera():camera_ray(rect_start.x, rect_start.y)
local p1, rd1 = LevelEditor:camera():camera_ray(rect_end.x, rect_start.y)
local p2, rd2 = LevelEditor:camera():camera_ray(rect_end.x, rect_end.y)
local p3, rd3 = LevelEditor:camera():camera_ray(rect_start.x, rect_end.y)

local camera_near = LevelEditor:camera():near_clip_distance()
local camera_far = LevelEditor:camera():far_clip_distance()
Expand Down Expand Up @@ -500,9 +502,7 @@ function SelectTool:mouse_move(x, y)
-- Draw the selection rectangle.
local fill_color = Color4(140, 140, 140, 20)
local border_color = Color4(180, 180, 180, 200)
-- Invert y-coord due to Gui having origin at bottom-left corner.
local resol_x, resol_y = Device.resolution()
local gui_rect_start = Vector3(rect_start.x, resol_y - rect_start.y - rect_size.y, 0)
local gui_rect_start = Vector3(rect_start.x, rect_start.y, 0)
Gui.rect(LevelEditor._screen_gui
, gui_rect_start
, rect_size
Expand Down Expand Up @@ -1495,6 +1495,141 @@ function LevelEditor:update(dt)
self._camera:mouse_wheel(self._mouse.wheel.delta)
self._camera:update(dt, self._mouse.dx, self._mouse.dy, self._keyboard, self._mouse)

-- Draw origin axes.
local camera_pose = self._camera:local_pose()
local camera_position = Matrix4x4.translation(camera_pose)
local camera_forward = Matrix4x4.z(camera_pose)
local axis_len = 40
local axis_tip_radius = 8
local gizmo_margin_right = 8
local len = self._camera:screen_length_to_world_length(camera_position + camera_forward, axis_len)
local x_screen = World.camera_world_to_screen(self._world, self._camera:camera(), camera_position + camera_forward + len*Vector3(1, 0, 0))
local y_screen = World.camera_world_to_screen(self._world, self._camera:camera(), camera_position + camera_forward + len*Vector3(0, 1, 0))
local z_screen = World.camera_world_to_screen(self._world, self._camera:camera(), camera_position + camera_forward + len*Vector3(0, 0, 1))
local o_screen = World.camera_world_to_screen(self._world, self._camera:camera(), camera_position + camera_forward)
local neg_x_screen = World.camera_world_to_screen(self._world, self._camera:camera(), camera_position + camera_forward + len*Vector3(-1, 0, 0))
local neg_y_screen = World.camera_world_to_screen(self._world, self._camera:camera(), camera_position + camera_forward + len*Vector3(0, -1, 0))
local neg_z_screen = World.camera_world_to_screen(self._world, self._camera:camera(), camera_position + camera_forward + len*Vector3(0, 0, -1))
local resol_x, resol_y = Device.resolution()
local gizmo_origin_x = resol_x * 0.5 - (axis_len + axis_tip_radius + gizmo_margin_right)
local gizmo_origin_y = resol_y * 0.5 - (axis_len + axis_tip_radius + gizmo_margin_right)
local screen_translation = Vector2(gizmo_origin_x, gizmo_origin_y)

local x_axis_alpha = math.max(0.6, 1 - (1 + Vector3.dot(Vector3(1, 0, 0), camera_forward)) * 0.5)
local y_axis_alpha = math.max(0.6, 1 - (1 + Vector3.dot(Vector3(0, 1, 0), camera_forward)) * 0.5)
local z_axis_alpha = math.max(0.6, 1 - (1 + Vector3.dot(Vector3(0, 0, 1), camera_forward)) * 0.5)
local neg_x_axis_alpha = math.max(0.4, 1 - (1 + Vector3.dot(Vector3(-1, 0, 0), camera_forward)) * 0.5)
local neg_y_axis_alpha = math.max(0.4, 1 - (1 + Vector3.dot(Vector3(0, -1, 0), camera_forward)) * 0.5)
local neg_z_axis_alpha = math.max(0.4, 1 - (1 + Vector3.dot(Vector3(0, 0, -1), camera_forward)) * 0.5)

function draw_circle(gui, center, radius, color)
local segments = 36
for i=1,segments do
local x0 = math.cos(2 * math.pi * ((i - 1) / segments)) * radius
local y0 = math.sin(2 * math.pi * ((i - 1) / segments)) * radius
local x1 = math.cos(2 * math.pi * ((i - 0) / segments)) * radius
local y1 = math.sin(2 * math.pi * ((i - 0) / segments)) * radius

Gui.triangle(gui
, center
, center + Vector2(x0, y0)
, center + Vector2(x1, y1)
, color
, center.z
)
end
end

local x_axis_color = Color4.lerp_alpha(Colors.axis_x(), x_axis_alpha)
local y_axis_color = Color4.lerp_alpha(Colors.axis_y(), y_axis_alpha)
local z_axis_color = Color4.lerp_alpha(Colors.axis_z(), z_axis_alpha)
local neg_x_axis_color = Color4.lerp_alpha(Colors.axis_x(), neg_x_axis_alpha)
local neg_y_axis_color = Color4.lerp_alpha(Colors.axis_y(), neg_y_axis_alpha)
local neg_z_axis_color = Color4.lerp_alpha(Colors.axis_z(), neg_z_axis_alpha)

-- Draw tips.
draw_circle(self._screen_gui, x_screen + screen_translation, axis_tip_radius, x_axis_color)
draw_circle(self._screen_gui, y_screen + screen_translation, axis_tip_radius, y_axis_color)
draw_circle(self._screen_gui, z_screen + screen_translation, axis_tip_radius, z_axis_color)
draw_circle(self._screen_gui, neg_x_screen + screen_translation, axis_tip_radius, neg_x_axis_color)
draw_circle(self._screen_gui, neg_y_screen + screen_translation, axis_tip_radius, neg_y_axis_color)
draw_circle(self._screen_gui, neg_z_screen + screen_translation, axis_tip_radius, neg_z_axis_color)

function draw_segment(gui, a, b, depth, color)
local thickness = 1
local ab_segment = a - b
local ab_normal = Vector3.normalize(Vector2(ab_segment.y, -ab_segment.x))

-- Draw segment top-half.
Gui.triangle(gui
, a + ab_normal * thickness
, a - ab_normal * thickness
, b + ab_normal * thickness
, color
, depth
)
-- Draw segment bottom-half.
Gui.triangle(gui
, a - ab_normal * thickness
, b - ab_normal * thickness
, b + ab_normal * thickness
, color
, depth
)
end

-- Draw axes.
draw_segment(self._screen_gui
, o_screen + screen_translation
, x_screen + screen_translation + Vector3.normalize(o_screen - x_screen) * axis_tip_radius
, x_screen.z
, x_axis_color
)
draw_segment(self._screen_gui
, o_screen + screen_translation
, y_screen + screen_translation + Vector3.normalize(o_screen - y_screen) * axis_tip_radius
, y_screen.z
, y_axis_color
)
draw_segment(self._screen_gui
, o_screen + screen_translation
, z_screen + screen_translation + Vector3.normalize(o_screen - z_screen) * axis_tip_radius
, z_screen.z
, z_axis_color
)

-- Draw labels.
Gui.text(self._screen_gui
, x_screen + screen_translation - Vector2(axis_tip_radius * 0.5, axis_tip_radius * 0.5)
, 14
, "X"
, "core/game/hud/debug"
, "core/game/hud/debug"
, Color4.black()
)
Gui.text(self._screen_gui
, y_screen + screen_translation - Vector2(axis_tip_radius * 0.5, axis_tip_radius * 0.5)
, 14
, "Y"
, "core/game/hud/debug"
, "core/game/hud/debug"
, Color4.black()
)
Gui.text(self._screen_gui
, z_screen + screen_translation - Vector2(axis_tip_radius * 0.5, axis_tip_radius * 0.5)
, 14
, "Z"
, "core/game/hud/debug"
, "core/game/hud/debug"
, Color4.black()
)

local old_world = Vector3(20, 30, 12)
local screen = World.camera_world_to_screen(self._world, self._camera:camera(), old_world)
local new_world = World.camera_screen_to_world(self._world, self._camera:camera(), screen)
print(Vector3.elements(old_world))
print(Vector3.elements(new_world))

if self._camera:is_idle() then
self.tool:mouse_move(self._mouse.x, self._mouse.y)
end
Expand Down Expand Up @@ -1536,8 +1671,9 @@ function LevelEditor:reset()
end

function LevelEditor:set_mouse_state(x, y, left, middle, right)
local resol_x, resol_y = Device.resolution()
self._mouse.x = x
self._mouse.y = y
self._mouse.y = resol_y - y
self._mouse.left = left
self._mouse.middle = middle
self._mouse.right = right
Expand All @@ -1548,14 +1684,16 @@ function LevelEditor:mouse_wheel(delta)
end

function LevelEditor:mouse_down(x, y)
local resol_x, resol_y = Device.resolution()
if self._camera:is_idle() then
self.tool:mouse_down(x, y)
self.tool:mouse_down(x, resol_y - y)
end
end

function LevelEditor:mouse_up(x, y)
local resol_x, resol_y = Device.resolution()
if self._camera:is_idle() then
self.tool:mouse_up(x, y)
self.tool:mouse_up(x, resol_y - y)
end
end

Expand Down
28 changes: 17 additions & 11 deletions src/world/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,9 @@ void World::camera_set_viewport_metrics(CameraInstance camera, u16 x, u16 y, u16

Vector3 World::camera_screen_to_world(CameraInstance camera, const Vector3 &pos)
{
const f32 w = _camera[camera.i].view_width;
const f32 h = _camera[camera.i].view_height;

TransformInstance ti = _scene_graph->instance(_camera[camera.i].unit);

Matrix4x4 projection = camera_projection_matrix(camera);
Expand All @@ -429,12 +432,9 @@ Vector3 World::camera_screen_to_world(CameraInstance camera, const Vector3 &pos)
const bgfx::Caps *caps = bgfx::getCaps();

Vector4 ndc;
ndc.x = (2.0f * (pos.x - 0.0f)) / _camera[camera.i].view_width - 1.0f;
ndc.y = (2.0f * (_camera[camera.i].view_height - pos.y)) / _camera[camera.i].view_height - 1.0f;
ndc.z = caps->homogeneousDepth
? (2.0f * pos.z) - 1.0f
: pos.z
;
ndc.x = (2.0f * pos.x) / w - 1.0f;
ndc.y = (2.0f * pos.y) / h - 1.0f;
ndc.z = caps->homogeneousDepth ? (2.0f * pos.z) - 1.0f : pos.z;
ndc.w = 1.0f;

Vector4 tmp = ndc * mvp;
Expand All @@ -445,6 +445,11 @@ Vector3 World::camera_screen_to_world(CameraInstance camera, const Vector3 &pos)

Vector3 World::camera_world_to_screen(CameraInstance camera, const Vector3 &pos)
{
const f32 x = _camera[camera.i].view_x;
const f32 y = _camera[camera.i].view_y;
const f32 w = _camera[camera.i].view_width;
const f32 h = _camera[camera.i].view_height;

TransformInstance ti = _scene_graph->instance(_camera[camera.i].unit);

Matrix4x4 projection = camera_projection_matrix(camera);
Expand All @@ -460,13 +465,14 @@ Vector3 World::camera_world_to_screen(CameraInstance camera, const Vector3 &pos)
Vector4 clip = xyzw * (world_inv * projection);

Vector4 ndc;
ndc.x = clip.x / clip.w;
ndc.y = clip.y / clip.w;
ndc = clip * (1.0f / clip.w);

const bgfx::Caps *caps = bgfx::getCaps();

Vector3 screen;
screen.x = (_camera[camera.i].view_x + _camera[camera.i].view_width * (ndc.x + 1.0f)) / 2.0f;
screen.y = (_camera[camera.i].view_y + _camera[camera.i].view_height * (1.0f - ndc.y)) / 2.0f;
screen.z = 0.0f;
screen.x = (x + w * (ndc.x + 1.0f)) / 2.0f;
screen.y = h - (y + h * (1.0f - ndc.y)) / 2.0f;
screen.z = caps->homogeneousDepth ? (ndc.z + 1.0f) / 2.0f : ndc.z;

return screen;
}
Expand Down

0 comments on commit f9dfee2

Please sign in to comment.