Dock
This commit is contained in:
@@ -372,7 +372,7 @@ pub fn beginDraw() bool {
|
|||||||
// Window is probably hidden
|
// Window is probably hidden
|
||||||
if (Graphics.render_target == null) return false;
|
if (Graphics.render_target == null) return false;
|
||||||
|
|
||||||
Graphics.render_pass = sdl.BeginGPURenderPass(Graphics.command_buffer, &.{
|
Graphics.render_pass = sdl.BeginGPURenderPass(Graphics.command_buffer.?, &.{
|
||||||
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
||||||
.cycle = false,
|
.cycle = false,
|
||||||
.load_op = sdl.GPU_LOADOP_CLEAR,
|
.load_op = sdl.GPU_LOADOP_CLEAR,
|
||||||
@@ -396,11 +396,35 @@ pub fn beginDraw() bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawMesh(mesh: Mesh, texture: Assets.Texture, matrix: Transform.TMatrix) void {
|
pub fn clearDepth() void {
|
||||||
|
sdl.EndGPURenderPass(Graphics.render_pass.?);
|
||||||
|
|
||||||
|
Graphics.render_pass = sdl.BeginGPURenderPass(Graphics.command_buffer.?, &.{
|
||||||
|
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
||||||
|
.cycle = false,
|
||||||
|
.load_op = sdl.GPU_LOADOP_LOAD,
|
||||||
|
.store_op = sdl.GPU_STOREOP_STORE,
|
||||||
|
.mip_level = 0,
|
||||||
|
.texture = Graphics.fsaa_target,
|
||||||
|
}, 1, &.{
|
||||||
|
.clear_depth = 1.0,
|
||||||
|
.load_op = sdl.GPU_LOADOP_CLEAR,
|
||||||
|
.store_op = sdl.GPU_STOREOP_DONT_CARE,
|
||||||
|
.stencil_load_op = sdl.GPU_STOREOP_DONT_CARE,
|
||||||
|
.stencil_store_op = sdl.GPU_STOREOP_DONT_CARE,
|
||||||
|
.texture = Graphics.depth_texture,
|
||||||
|
}) orelse err.sdl();
|
||||||
|
|
||||||
|
sdl.BindGPUGraphicsPipeline(Graphics.render_pass, Graphics.pipeline);
|
||||||
|
sdl.BindGPUVertexBuffers(Graphics.render_pass, 0, &.{ .offset = 0, .buffer = Graphics.vertex_buffer }, 1);
|
||||||
|
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 0, &Graphics.camera.matrix, 16 * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawMesh(mesh: Mesh, texture: Assets.Texture, transform: Transform) void {
|
||||||
if (Graphics.render_pass == null) return;
|
if (Graphics.render_pass == null) return;
|
||||||
const asset_texture = Assets.get(texture) orelse return;
|
const asset_texture = Assets.get(texture) orelse return;
|
||||||
|
|
||||||
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 1, &matrix, 16 * 4);
|
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 1, &transform.matrix(), 16 * 4);
|
||||||
sdl.BindGPUFragmentSamplers(Graphics.render_pass, 0, &sdl.GPUTextureSamplerBinding{
|
sdl.BindGPUFragmentSamplers(Graphics.render_pass, 0, &sdl.GPUTextureSamplerBinding{
|
||||||
.texture = asset_texture.texture,
|
.texture = asset_texture.texture,
|
||||||
.sampler = asset_texture.sampler,
|
.sampler = asset_texture.sampler,
|
||||||
@@ -496,13 +520,15 @@ pub fn getHeight() u32 {
|
|||||||
return @max(1, Graphics.window_size[1]);
|
return @max(1, Graphics.window_size[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generatePlane(x0: f32, y0: f32, x1: f32, y1: f32) [30]f32 {
|
pub fn generatePlane(x0: f32, y0: f32, x1: f32, y1: f32, w: f32, h: f32) [30]f32 {
|
||||||
|
const hw = w * 0.5;
|
||||||
|
const hh = h * 0.5;
|
||||||
return .{
|
return .{
|
||||||
-0.5, -0.5, 0, x0, y1,
|
-hw, -hh, 0, x0, y1,
|
||||||
0.5, 0.5, 0, x1, y0,
|
hw, hh, 0, x1, y0,
|
||||||
-0.5, 0.5, 0, x0, y0,
|
-hw, hh, 0, x0, y0,
|
||||||
0.5, 0.5, 0, x1, y0,
|
hw, hh, 0, x1, y0,
|
||||||
-0.5, -0.5, 0, x0, y1,
|
-hw, -hh, 0, x0, y1,
|
||||||
0.5, -0.5, 0, x1, y1,
|
hw, -hh, 0, x1, y1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -52,16 +52,18 @@ pub fn to_screen(camera: Camera, position: Transform.Position) @Vector(2, f32) {
|
|||||||
return .{ x * wmod, y * wmod };
|
return .{ x * wmod, y * wmod };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouse_in_quad(camera: Camera, mouse: @Vector(2, f32), quad_transform: Transform) bool {
|
pub fn mouse_in_quad(camera: Camera, mouse: @Vector(2, f32), quad_transform: Transform, width: f32, height: f32) bool {
|
||||||
@setFloatMode(.optimized);
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
const matrix = Transform.multiplyMatrix(camera.matrix, quad_transform.matrix());
|
const matrix = Transform.multiplyMatrix(camera.matrix, quad_transform.matrix());
|
||||||
|
|
||||||
|
const hw = width * 0.5;
|
||||||
|
const hh = height * 0.5;
|
||||||
const pi: [4]@Vector(2, f32) = .{
|
const pi: [4]@Vector(2, f32) = .{
|
||||||
.{ -0.5, -0.5 },
|
.{ -hw, -hh },
|
||||||
.{ -0.5, 0.5 },
|
.{ -hw, hh },
|
||||||
.{ 0.5, 0.5 },
|
.{ hw, hh },
|
||||||
.{ 0.5, -0.5 },
|
.{ hw, -hh },
|
||||||
};
|
};
|
||||||
var po: [4]@Vector(2, f32) = undefined;
|
var po: [4]@Vector(2, f32) = undefined;
|
||||||
for (0..4) |i| {
|
for (0..4) |i| {
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const math = @import("../math.zig");
|
||||||
const Transform = @This();
|
const Transform = @This();
|
||||||
|
|
||||||
pub const TMatrix = @Vector(16, f32);
|
pub const TMatrix = @Vector(16, f32);
|
||||||
|
|
||||||
pub const Position = @Vector(3, f32);
|
pub const Position = @Vector(3, f32);
|
||||||
pub const Rotation = @Vector(4, f32);
|
pub const Rotation = @Vector(4, f32);
|
||||||
pub const Scale = @Vector(3, f32);
|
pub const Scale = f32;
|
||||||
|
|
||||||
position: Position = @splat(0.0),
|
position: Position = @splat(0.0),
|
||||||
rotation: Rotation = .{ 1.0, 0.0, 0.0, 0.0 },
|
rotation: Rotation = .{ 1.0, 0.0, 0.0, 0.0 },
|
||||||
scale: Scale = @splat(1.0),
|
scale: Scale = 1.0,
|
||||||
|
|
||||||
pub fn matrix(transform: Transform) TMatrix {
|
pub fn matrix(transform: Transform) TMatrix {
|
||||||
@setFloatMode(.optimized);
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
const r = rotationMatrix(transform.rotation);
|
const r = rotationMatrix(transform.rotation) * @as(@Vector(9, f32), @splat(transform.scale));
|
||||||
const sx, const sy, const sz = transform.scale;
|
|
||||||
return .{
|
return .{
|
||||||
sx * r[0], sy * r[1], sz * r[2], transform.position[0],
|
r[0], r[1], r[2], transform.position[0],
|
||||||
sx * r[3], sy * r[4], sz * r[5], transform.position[1],
|
r[3], r[4], r[5], transform.position[1],
|
||||||
sx * r[6], sy * r[7], sz * r[8], transform.position[2],
|
r[6], r[7], r[8], transform.position[2],
|
||||||
0.0, 0.0, 0.0, 1.0,
|
0.0, 0.0, 0.0, 1.0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -27,24 +27,12 @@ pub fn matrix(transform: Transform) TMatrix {
|
|||||||
pub fn inverseMatrix(transform: Transform) TMatrix {
|
pub fn inverseMatrix(transform: Transform) TMatrix {
|
||||||
@setFloatMode(.optimized);
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
const r = rotationMatrix(flipRotation(transform.rotation));
|
const r = rotationMatrix(flipRotation(transform.rotation)) * @as(@Vector(9, f32), @splat(1.0 / transform.scale));
|
||||||
const tx, const ty, const tz = transform.position;
|
const tx, const ty, const tz = transform.position;
|
||||||
const sx = 1.0 / transform.scale[0];
|
|
||||||
const sy = 1.0 / transform.scale[1];
|
|
||||||
const sz = 1.0 / transform.scale[2];
|
|
||||||
const r0 = r[0] * sx;
|
|
||||||
const r1 = r[1] * sx;
|
|
||||||
const r2 = r[2] * sx;
|
|
||||||
const r3 = r[3] * sy;
|
|
||||||
const r4 = r[4] * sy;
|
|
||||||
const r5 = r[5] * sy;
|
|
||||||
const r6 = r[6] * sz;
|
|
||||||
const r7 = r[7] * sz;
|
|
||||||
const r8 = r[8] * sz;
|
|
||||||
return .{
|
return .{
|
||||||
r0, r1, r2, -(r0 * tx + r1 * ty + r2 * tz),
|
r[0], r[1], r[2], -(r[0] * tx + r[1] * ty + r[2] * tz),
|
||||||
r3, r4, r5, -(r3 * tx + r4 * ty + r5 * tz),
|
r[3], r[4], r[5], -(r[3] * tx + r[4] * ty + r[5] * tz),
|
||||||
r6, r7, r8, -(r6 * tx + r7 * ty + r8 * tz),
|
r[6], r[7], r[8], -(r[6] * tx + r[7] * ty + r[8] * tz),
|
||||||
0.0, 0.0, 0.0, 1.0,
|
0.0, 0.0, 0.0, 1.0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -94,6 +82,7 @@ pub fn rotateVector(vector: Position, rotation: Rotation) Position {
|
|||||||
pub fn rotate(transform: *Transform, rotation: Rotation) void {
|
pub fn rotate(transform: *Transform, rotation: Rotation) void {
|
||||||
@setFloatMode(.optimized);
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
// Also rotate `Position` around the origin?
|
||||||
transform.rotation = normalizeRotation(combineRotations(transform.rotation, rotation));
|
transform.rotation = normalizeRotation(combineRotations(transform.rotation, rotation));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +137,8 @@ pub fn normalizeRotation(r: Rotation) Rotation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// a: Child `Rotation`
|
||||||
|
/// b: Parent `Rotation`
|
||||||
pub fn combineRotations(a: Rotation, b: Rotation) Rotation {
|
pub fn combineRotations(a: Rotation, b: Rotation) Rotation {
|
||||||
@setFloatMode(.optimized);
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
@@ -230,3 +221,31 @@ pub fn multiplyMatrix(a: TMatrix, b: TMatrix) TMatrix {
|
|||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// a: Child `Transform`
|
||||||
|
/// b: Parent `Transform`
|
||||||
|
pub fn combineTransforms(a: Transform, b: Transform) Transform {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
return Transform{
|
||||||
|
.position = rotateVector(a.position, b.rotation) * @as(Position, @splat(b.scale)) + b.position,
|
||||||
|
.rotation = combineRotations(a.rotation, b.rotation),
|
||||||
|
.scale = a.scale * b.scale,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lerpTransformTimeLn(a: Transform, b: Transform, t: f32, lnf: f32) Transform {
|
||||||
|
return lerpTransform(b, a, @exp(lnf * t));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lerpTransform(a: Transform, b: Transform, f: f32) Transform {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
return Transform{
|
||||||
|
.position = math.lerp(a.position, b.position, f),
|
||||||
|
.rotation = math.slerp(a.rotation, b.rotation, f),
|
||||||
|
.scale = math.lerp(a.scale, b.scale, f),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ZERO = Transform{};
|
||||||
|
23
src/math.zig
23
src/math.zig
@@ -36,15 +36,21 @@ pub inline fn slerpTime(a: anytype, b: anytype, t: f32, comptime f: f32) @TypeOf
|
|||||||
pub fn slerpTimeLn(a: anytype, b: anytype, t: f32, lnf: f32) @TypeOf(a, b) {
|
pub fn slerpTimeLn(a: anytype, b: anytype, t: f32, lnf: f32) @TypeOf(a, b) {
|
||||||
@setFloatMode(.optimized);
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
return slerp(b, a, @exp(lnf * t));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn slerp(a: anytype, b: anytype, f: f32) @TypeOf(a, b) {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
const cos = @reduce(.Add, a * b);
|
const cos = @reduce(.Add, a * b);
|
||||||
if (cos > 0.999) {
|
if (cos > 0.999) {
|
||||||
return lerpTimeLn(a, b, t, lnf);
|
return lerp(a, b, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
const angle = std.math.acos(cos);
|
const angle = std.math.acos(cos);
|
||||||
|
|
||||||
const a_angle_factor = @exp(lnf * t);
|
const a_angle_factor = 1 - f;
|
||||||
const b_angle_factor = 1.0 - a_angle_factor;
|
const b_angle_factor = f;
|
||||||
|
|
||||||
const rev_angle_sin = 1.0 / std.math.sin(angle);
|
const rev_angle_sin = 1.0 / std.math.sin(angle);
|
||||||
const a_sin = std.math.sin(a_angle_factor * angle);
|
const a_sin = std.math.sin(a_angle_factor * angle);
|
||||||
@@ -165,3 +171,14 @@ pub fn limit(vector: anytype, value: f32) @TypeOf(vector) {
|
|||||||
else
|
else
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn norm(vector: anytype) @TypeOf(vector) {
|
||||||
|
const len = length(vector);
|
||||||
|
if (len < 1.01 and len > 0.99) return vector;
|
||||||
|
if (len < 1e-10) {
|
||||||
|
var output = @as(@TypeOf(vector), @splat(0));
|
||||||
|
output[@typeInfo(@TypeOf(vector)).vector.len - 1] = 1;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
return vector * @as(@TypeOf(vector), @splat(1.0 / len));
|
||||||
|
}
|
||||||
|
252
src/world.zig
252
src/world.zig
@@ -11,40 +11,69 @@ const Order = i32;
|
|||||||
|
|
||||||
pub var object_map: std.AutoHashMapUnmanaged(Id, usize) = .{};
|
pub var object_map: std.AutoHashMapUnmanaged(Id, usize) = .{};
|
||||||
pub var objects: std.ArrayListUnmanaged(Object) = .{};
|
pub var objects: std.ArrayListUnmanaged(Object) = .{};
|
||||||
|
|
||||||
pub var plane_mesh: Graphics.Mesh = undefined;
|
pub var plane_mesh: Graphics.Mesh = undefined;
|
||||||
pub var cube_mesh: Graphics.Mesh = undefined;
|
pub var cube_mesh: Graphics.Mesh = undefined;
|
||||||
pub var table_mesh: Graphics.Mesh = undefined;
|
pub var table_mesh: Graphics.Mesh = undefined;
|
||||||
pub var texture: Assets.Texture = undefined;
|
pub var texture: Assets.Texture = undefined;
|
||||||
pub var hand_texture: Assets.Texture = undefined;
|
pub var hand_texture: Assets.Texture = undefined;
|
||||||
|
|
||||||
pub var camera_position: @Vector(2, f32) = @splat(0);
|
pub var camera_position: @Vector(2, f32) = @splat(0);
|
||||||
pub var hover: ?Id = null;
|
|
||||||
pub var hand_transform: Graphics.Transform = .{};
|
pub var hand_transform: Graphics.Transform = .{};
|
||||||
pub var panning = false;
|
pub var dock_transform: Graphics.Transform = .{};
|
||||||
pub var zoom: i32 = 0;
|
pub var zoom: i32 = 0;
|
||||||
|
|
||||||
|
pub var hover: ?Id = null;
|
||||||
|
pub var panning = false;
|
||||||
pub var hand_objects: u32 = 0;
|
pub var hand_objects: u32 = 0;
|
||||||
|
pub var hand_scale: f32 = 0;
|
||||||
|
pub var dock_objects: u32 = 0;
|
||||||
|
pub var dock_last_width: f32 = 0;
|
||||||
|
pub var dock_focused: bool = false;
|
||||||
|
pub var dock_spacing: f32 = 0;
|
||||||
pub var min_order: Order = undefined;
|
pub var min_order: Order = undefined;
|
||||||
pub var max_order: Order = undefined;
|
pub var max_order: Order = undefined;
|
||||||
|
|
||||||
const Object = struct {
|
const Object = struct {
|
||||||
transform: Graphics.Transform = .{},
|
transform: Graphics.Transform = .{},
|
||||||
target_transform: Graphics.Transform = .{},
|
target_transform: Graphics.Transform = .{},
|
||||||
scale: Graphics.Transform.Scale,
|
width: f32,
|
||||||
|
height: f32,
|
||||||
mesh: Graphics.Mesh,
|
mesh: Graphics.Mesh,
|
||||||
texture: Assets.Texture,
|
texture: Assets.Texture,
|
||||||
order: Order,
|
order: Order,
|
||||||
id: Id,
|
id: Id,
|
||||||
index: u32,
|
index: u32,
|
||||||
parent: enum {
|
parent: Parent = .none,
|
||||||
none,
|
parent_index: u32 = 0,
|
||||||
hand,
|
|
||||||
} = .none,
|
|
||||||
hand_index: u32 = 0,
|
|
||||||
influence: f32 = 0,
|
influence: f32 = 0,
|
||||||
|
|
||||||
|
const Parent = enum {
|
||||||
|
none,
|
||||||
|
hand,
|
||||||
|
dock,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn reparent(self: *@This(), new_parent: Parent) void {
|
||||||
|
self.transform = self.drawingTransform();
|
||||||
|
self.influence = 0;
|
||||||
|
self.parent = new_parent;
|
||||||
|
}
|
||||||
pub fn drawingTransform(self: @This()) Graphics.Transform {
|
pub fn drawingTransform(self: @This()) Graphics.Transform {
|
||||||
var transform = self.transform;
|
const transform = self.transform;
|
||||||
transform.position += @as(@Vector(3, f32), @splat(self.influence)) * World.hand_transform.position;
|
const parent_transform = switch (self.parent) {
|
||||||
return transform;
|
.hand => World.hand_transform,
|
||||||
|
.dock => World.dock_transform,
|
||||||
|
else => return transform,
|
||||||
|
};
|
||||||
|
return Graphics.Transform.combineTransforms(
|
||||||
|
transform,
|
||||||
|
Graphics.Transform.lerpTransform(
|
||||||
|
.{},
|
||||||
|
parent_transform,
|
||||||
|
self.influence,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,13 +81,9 @@ const World = @This();
|
|||||||
pub fn initDebug() void {
|
pub fn initDebug() void {
|
||||||
for (0..10) |i| {
|
for (0..10) |i| {
|
||||||
(World.objects.addOne(Game.alloc) catch err.oom()).* = .{
|
(World.objects.addOne(Game.alloc) catch err.oom()).* = .{
|
||||||
.scale = @splat(0.5),
|
.width = 0.5,
|
||||||
.mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane(
|
.height = 0.5,
|
||||||
15.0 / 16.0,
|
.mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane(15.0 / 16.0, @as(f32, @floatFromInt(i)) / 16.0, 16.0 / 16.0, @as(f32, @floatFromInt(i + 1)) / 16.0, 0.5, 0.5))),
|
||||||
@as(f32, @floatFromInt(i)) / 16.0,
|
|
||||||
16.0 / 16.0,
|
|
||||||
@as(f32, @floatFromInt(i + 1)) / 16.0,
|
|
||||||
))),
|
|
||||||
.texture = Assets.load(.texture, "data/yakuza.png"),
|
.texture = Assets.load(.texture, "data/yakuza.png"),
|
||||||
.order = @intCast(i),
|
.order = @intCast(i),
|
||||||
.id = @intCast(i),
|
.id = @intCast(i),
|
||||||
@@ -66,18 +91,24 @@ pub fn initDebug() void {
|
|||||||
};
|
};
|
||||||
World.object_map.put(Game.alloc, @intCast(i), i) catch err.oom();
|
World.object_map.put(Game.alloc, @intCast(i), i) catch err.oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
World.plane_mesh = Graphics.loadMesh(@ptrCast(&PLANE_MESH_DATA));
|
World.plane_mesh = Graphics.loadMesh(@ptrCast(&PLANE_MESH_DATA));
|
||||||
World.cube_mesh = Graphics.loadMesh(@ptrCast(&CUBE_MESH_DATA));
|
World.cube_mesh = Graphics.loadMesh(@ptrCast(&CUBE_MESH_DATA));
|
||||||
World.table_mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane(0, 0, 0.5, 0.5)));
|
World.table_mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane(0, 0, 0.5, 0.5, 8, 8)));
|
||||||
World.texture = Assets.load(.texture, "data/yakuza.png");
|
World.texture = Assets.load(.texture, "data/yakuza.png");
|
||||||
World.hand_texture = Assets.load(.texture, "data/hand.png");
|
World.hand_texture = Assets.load(.texture, "data/hand.png");
|
||||||
|
|
||||||
World.camera_position = @splat(0);
|
World.camera_position = @splat(0);
|
||||||
World.hover = null;
|
World.hand_transform = .{};
|
||||||
World.hand_transform = .{
|
World.hand_scale = 0.5;
|
||||||
.scale = @splat(0.5),
|
World.dock_transform = .{
|
||||||
|
.position = .{ 0, 0, 4 },
|
||||||
};
|
};
|
||||||
World.panning = false;
|
World.dock_spacing = 0.2;
|
||||||
World.zoom = 0;
|
World.zoom = 0;
|
||||||
|
|
||||||
|
World.panning = false;
|
||||||
|
World.dock_focused = false;
|
||||||
World.min_order = 0;
|
World.min_order = 0;
|
||||||
World.max_order = 9;
|
World.max_order = 9;
|
||||||
}
|
}
|
||||||
@@ -97,16 +128,34 @@ pub fn deinit() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(delta: f32) void {
|
pub fn update(delta: f32) void {
|
||||||
World.updateOrder();
|
World.updateCamera(delta);
|
||||||
|
{
|
||||||
|
World.dock_transform = Graphics.Transform.lerpTransformTimeLn(
|
||||||
|
World.dock_transform,
|
||||||
|
Graphics.Transform.combineTransforms(.{ .position = .{
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
-1 / Graphics.camera.lens,
|
||||||
|
} }, Graphics.camera.transform),
|
||||||
|
delta,
|
||||||
|
-128,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
{
|
||||||
const hand_target = Graphics.camera.raycast(.{ Game.mouse.x_norm, Game.mouse.y_norm }, .{ 0, 0, 1, 0 });
|
const hand_target = Graphics.camera.raycast(.{ Game.mouse.x_norm, Game.mouse.y_norm }, .{ 0, 0, 1, 0 });
|
||||||
World.hand_transform.position = math.lerpTimeLn(
|
World.hand_transform.position = math.lerpTimeLn(
|
||||||
World.hand_transform.position,
|
World.hand_transform.position,
|
||||||
hand_target + @Vector(3, f32){ World.hand_transform.scale[0] * 0.5, -World.hand_transform.scale[1] * 0.5, 0.2 },
|
hand_target + @Vector(3, f32){ 0, 0, 0.2 },
|
||||||
delta,
|
delta,
|
||||||
-24,
|
-24,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
World.updateOrder();
|
||||||
|
|
||||||
World.hover = null;
|
World.hover = null;
|
||||||
World.hand_objects = 0;
|
World.hand_objects = 0;
|
||||||
|
World.dock_objects = 0;
|
||||||
for (World.objects.items) |*object| {
|
for (World.objects.items) |*object| {
|
||||||
updateHover(object);
|
updateHover(object);
|
||||||
}
|
}
|
||||||
@@ -114,7 +163,6 @@ pub fn update(delta: f32) void {
|
|||||||
updateObject(object, delta);
|
updateObject(object, delta);
|
||||||
}
|
}
|
||||||
World.updateControls();
|
World.updateControls();
|
||||||
World.updateCamera(delta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateControls() void {
|
pub fn updateControls() void {
|
||||||
@@ -151,104 +199,154 @@ pub fn updateControls() void {
|
|||||||
}
|
}
|
||||||
World.zoom = std.math.clamp(World.zoom + Game.mouse.wheel, -4, 8);
|
World.zoom = std.math.clamp(World.zoom + Game.mouse.wheel, -4, 8);
|
||||||
}
|
}
|
||||||
|
if (Game.mouse.y_norm <= -0.8) {
|
||||||
|
World.dock_focused = true;
|
||||||
|
}
|
||||||
|
if (Game.mouse.y_norm >= -0.6) {
|
||||||
|
World.dock_focused = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tryPick() bool {
|
pub fn tryPick() bool {
|
||||||
const hover_id = World.hover orelse return false;
|
const hover_id = World.hover orelse return false;
|
||||||
const object = World.getObject(hover_id) orelse return false;
|
const object = World.getObject(hover_id) orelse return false;
|
||||||
World.panning = false;
|
World.panning = false;
|
||||||
object.parent = .hand;
|
object.reparent(.hand);
|
||||||
World.bringToTop(object);
|
World.bringToTop(object);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
pub fn tryRelease() bool {
|
pub fn tryRelease() bool {
|
||||||
var last: ?*Object = null;
|
const object = blk: {
|
||||||
for (World.objects.items) |*object| {
|
var i = World.objects.items.len - 1;
|
||||||
if (object.parent != .hand) continue;
|
while (true) {
|
||||||
last = object;
|
const object = &World.objects.items[i];
|
||||||
}
|
if (object.parent == .hand) {
|
||||||
if (last) |object| {
|
break :blk object;
|
||||||
object.transform = object.drawingTransform();
|
|
||||||
object.target_transform.position = World.hand_transform.position + @Vector(3, f32){
|
|
||||||
-World.hand_transform.scale[0] * 0.5,
|
|
||||||
World.hand_transform.scale[1] * 0.5,
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
object.influence = 0;
|
|
||||||
object.parent = .none;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
if (i > 0)
|
||||||
|
i -= 1
|
||||||
|
else
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
object.target_transform.position = World.hand_transform.position;
|
||||||
|
World.bringToTop(object);
|
||||||
|
if (World.dock_focused)
|
||||||
|
object.reparent(.dock)
|
||||||
|
else
|
||||||
|
object.reparent(.none);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateHover(object: *Object) void {
|
pub fn updateHover(object: *Object) void {
|
||||||
if (object.parent == .hand) {
|
switch (object.parent) {
|
||||||
object.hand_index = World.hand_objects;
|
.none => {
|
||||||
World.hand_objects += 1;
|
if (!World.dock_focused and Graphics.camera.mouse_in_quad(.{ Game.mouse.x_norm, Game.mouse.y_norm }, object.transform, object.width, object.height)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Graphics.camera.mouse_in_quad(.{ Game.mouse.x_norm, Game.mouse.y_norm }, object.target_transform)) {
|
|
||||||
if (World.hover == null or World.getObject(World.hover.?).?.index < object.index) {
|
if (World.hover == null or World.getObject(World.hover.?).?.index < object.index) {
|
||||||
World.hover = object.id;
|
World.hover = object.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
.hand => {
|
||||||
|
object.parent_index = World.hand_objects;
|
||||||
|
World.hand_objects += 1;
|
||||||
|
},
|
||||||
|
.dock => {
|
||||||
|
object.parent_index = World.dock_objects;
|
||||||
|
World.dock_last_width = object.width * object.target_transform.scale;
|
||||||
|
World.dock_objects += 1;
|
||||||
|
if (World.dock_focused and Graphics.camera.mouse_in_quad(.{ Game.mouse.x_norm, Game.mouse.y_norm }, object.transform.combineTransforms(World.dock_transform), object.width, object.height)) {
|
||||||
|
if (World.hover == null or World.getObject(World.hover.?).?.index < object.index) {
|
||||||
|
World.hover = object.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateObject(object: *Object, delta: f32) void {
|
pub fn updateObject(object: *Object, delta: f32) void {
|
||||||
switch (object.parent) {
|
switch (object.parent) {
|
||||||
.none => {
|
.none => {
|
||||||
object.target_transform.position[2] = if (World.hover == object.id) @as(f32, 0.1) else @as(f32, 0.001) * @as(f32, @floatFromInt(object.index + 1));
|
object.target_transform.position[2] = if (World.hover == object.id) @as(f32, 0.1) else @as(f32, 0.001) * @as(f32, @floatFromInt(object.index + 1));
|
||||||
object.target_transform.scale = object.scale;
|
object.target_transform.scale = 1.0;
|
||||||
},
|
},
|
||||||
.hand => {
|
.hand => {
|
||||||
var target_position = @as(@Vector(3, f32), @splat(0));
|
var target_position = @as(@Vector(3, f32), @splat(0));
|
||||||
var target_scale = object.scale;
|
var target_scale: f32 = 1.0;
|
||||||
target_position[2] -= 0.001;
|
target_position[2] -= 0.001;
|
||||||
const hand_order = hand_objects - object.hand_index - 1;
|
const hand_order = hand_objects - object.parent_index - 1;
|
||||||
switch (hand_order) {
|
switch (hand_order) {
|
||||||
0 => {
|
0 => {},
|
||||||
target_position[0] -= World.hand_transform.scale[0] * 0.5;
|
|
||||||
target_position[1] += World.hand_transform.scale[1] * 0.5;
|
|
||||||
},
|
|
||||||
else => |i| {
|
else => |i| {
|
||||||
target_position[0] += World.hand_transform.scale[0] * if (i & 2 == 0) @as(f32, 0.5) else @as(f32, 1);
|
target_position[0] += World.hand_scale * if (i & 2 == 0) @as(f32, 1) else @as(f32, 1.5);
|
||||||
target_position[1] += World.hand_transform.scale[1] * if ((i - 1) & 2 == 0) @as(f32, 0.25) else @as(f32, -0.25);
|
target_position[1] += World.hand_scale * if ((i - 1) & 2 == 0) @as(f32, -0.25) else @as(f32, -0.75);
|
||||||
target_position[2] -= @as(f32, @floatFromInt((hand_order - 1) / 4)) * 0.001;
|
target_position[2] -= @as(f32, @floatFromInt((hand_order - 1) / 4)) * 0.001;
|
||||||
target_scale = math.limit(target_scale, World.hand_transform.scale[1] * 0.5);
|
target_scale = 0.5;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
object.target_transform.position = target_position;
|
object.target_transform.position = target_position;
|
||||||
object.target_transform.scale = target_scale;
|
object.target_transform.scale = target_scale;
|
||||||
},
|
},
|
||||||
|
.dock => {
|
||||||
|
var topleft_x = -World.dock_last_width * 0.5 + World.dock_spacing * (@as(f32, @floatFromInt(object.parent_index)) - @as(f32, @floatFromInt(World.dock_objects - 1)) * 0.5);
|
||||||
|
const total_w = @as(f32, @floatFromInt(World.dock_objects - 1)) * World.dock_spacing + World.dock_last_width;
|
||||||
|
if (total_w > Graphics.camera.aspect * 2) {
|
||||||
|
topleft_x += math.lerp(0, Graphics.camera.aspect - total_w * 0.5, Game.mouse.x_norm);
|
||||||
}
|
}
|
||||||
if (object.parent == .hand) {
|
const hit = World.hover == object.id;
|
||||||
|
const topleft_y = if (World.dock_focused) if (hit) @as(f32, 0.5) else @as(f32, 0.3) else @as(f32, 0.2);
|
||||||
|
object.target_transform.position = .{
|
||||||
|
topleft_x + object.width * 0.5 * object.target_transform.scale,
|
||||||
|
topleft_y - object.height * 0.5 * object.target_transform.scale,
|
||||||
|
if (hit) @as(f32, 0.02) else @as(f32, 0),
|
||||||
|
};
|
||||||
|
object.target_transform.rotation = if (hit)
|
||||||
|
Graphics.Transform.ZERO.rotation
|
||||||
|
else
|
||||||
|
Graphics.Transform.rotationByAxis(.{ 0, 1, 0 }, 0.001);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if (object.parent != .none) {
|
||||||
object.influence = math.lerpTimeLn(
|
object.influence = math.lerpTimeLn(
|
||||||
object.influence,
|
object.influence,
|
||||||
1.0,
|
1.0,
|
||||||
delta,
|
delta,
|
||||||
-8,
|
-24,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
object.transform.position = math.lerpTimeLn(
|
object.transform = Graphics.Transform.lerpTransformTimeLn(
|
||||||
object.transform.position,
|
object.transform,
|
||||||
object.target_transform.position,
|
object.target_transform,
|
||||||
delta,
|
delta,
|
||||||
-8,
|
-24,
|
||||||
);
|
|
||||||
object.transform.scale = math.lerpTimeLn(
|
|
||||||
object.transform.scale,
|
|
||||||
object.target_transform.scale,
|
|
||||||
delta,
|
|
||||||
-8,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw() void {
|
pub fn draw() void {
|
||||||
Graphics.drawMesh(World.table_mesh, World.texture, Graphics.Transform.matrix(.{ .scale = @splat(8) }));
|
Graphics.drawMesh(World.table_mesh, World.texture, .{});
|
||||||
|
|
||||||
for (World.objects.items) |*object| {
|
for (World.objects.items) |*object| {
|
||||||
Graphics.drawMesh(object.mesh, object.texture, object.drawingTransform().matrix());
|
if (object.parent != .dock)
|
||||||
|
Graphics.drawMesh(object.mesh, object.texture, object.drawingTransform());
|
||||||
|
}
|
||||||
|
|
||||||
|
Graphics.drawMesh(
|
||||||
|
World.plane_mesh,
|
||||||
|
World.hand_texture,
|
||||||
|
Graphics.Transform.combineTransforms(
|
||||||
|
.{
|
||||||
|
.position = .{ World.hand_scale * 0.5, -World.hand_scale * 0.5, 0 },
|
||||||
|
.scale = World.hand_scale,
|
||||||
|
},
|
||||||
|
World.hand_transform,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Graphics.clearDepth();
|
||||||
|
for (World.objects.items) |*object| {
|
||||||
|
if (object.parent == .dock)
|
||||||
|
Graphics.drawMesh(object.mesh, object.texture, object.drawingTransform());
|
||||||
}
|
}
|
||||||
Graphics.drawMesh(World.plane_mesh, World.hand_texture, World.hand_transform.matrix());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateCamera(delta: f32) void {
|
pub fn updateCamera(delta: f32) void {
|
||||||
@@ -381,3 +479,11 @@ const PLANE_MESH_DATA = [_]f32{
|
|||||||
-0.5, -0.5, 0, 0.0, 1.0,
|
-0.5, -0.5, 0, 0.0, 1.0,
|
||||||
0.5, -0.5, 0, 1.0, 1.0,
|
0.5, -0.5, 0, 1.0, 1.0,
|
||||||
};
|
};
|
||||||
|
const PLANE_MESH_DATA_HALF = [_]f32{
|
||||||
|
-0.25, -0.25, 0, 0.0, 1.0,
|
||||||
|
0.25, 0.25, 0, 1.0, 0.0,
|
||||||
|
-0.25, 0.25, 0, 0.0, 0.0,
|
||||||
|
0.25, 0.25, 0, 1.0, 0.0,
|
||||||
|
-0.25, -0.25, 0, 0.0, 1.0,
|
||||||
|
0.25, -0.25, 0, 1.0, 1.0,
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user