Implemented camera rotation and zooming
This commit is contained in:
parent
68ccaf8b68
commit
d537d89819
10 changed files with 153 additions and 18 deletions
|
|
@ -3,6 +3,11 @@ const Allocator = std.mem.Allocator;
|
|||
|
||||
const Input = @This();
|
||||
|
||||
pub const ScrollDirection = enum {
|
||||
up,
|
||||
down
|
||||
};
|
||||
|
||||
pub const KeyCode = enum(u32) {
|
||||
space = 32,
|
||||
apostrophe = 39,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub const components = @import("components.zig");
|
||||
pub const entities = @import("entities.zig");
|
||||
pub const Input = @import("Input.zig");
|
||||
|
|
@ -11,3 +13,31 @@ pub const Pool = entities.Pool;
|
|||
pub const Resources = entities.Resources;
|
||||
pub const System = *const fn (*Pool) anyerror!void;
|
||||
pub const SystemGroup = []const System;
|
||||
|
||||
pub const hooks = struct {
|
||||
pub const Scroll = *const fn (*Pool, direction: Input.ScrollDirection) anyerror!void;
|
||||
pub const Key = *const fn (*Pool, key: Input.KeyCode) anyerror!void;
|
||||
|
||||
pub var key: std.ArrayList(Key) = undefined;
|
||||
pub var scroll: std.ArrayList(Scroll) = undefined;
|
||||
|
||||
pub const Layer = enum {
|
||||
key,
|
||||
scroll
|
||||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) !void {
|
||||
key = std.ArrayList(Key).init(allocator);
|
||||
scroll = std.ArrayList(Scroll).init(allocator);
|
||||
}
|
||||
|
||||
pub fn addHook(comptime layer: Layer, hook: anytype) !void {
|
||||
var list = comptime switch (layer) {
|
||||
.key => &key,
|
||||
.scroll => &scroll,
|
||||
};
|
||||
|
||||
try list.append(hook);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ const Camera = rendering.Camera;
|
|||
const ecs = @import("ecs.zig");
|
||||
const Input = ecs.Input;
|
||||
|
||||
pub const System = ecs.System;
|
||||
|
||||
pub const System = *const fn (*Pool) anyerror!void;
|
||||
pub const SystemGroup = []const System;
|
||||
pub const SyncGroup = []const System;
|
||||
|
||||
|
|
|
|||
24
src/ecs/hooks.zig
Normal file
24
src/ecs/hooks.zig
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub var key: std.ArrayList(ecs.System) = undefined;
|
||||
pub var scroll: std.ArrayList(ecs.System) = undefined;
|
||||
|
||||
pub const Layer = enum {
|
||||
key,
|
||||
scroll
|
||||
};
|
||||
|
||||
pub fn init(allocator: Allocator) !void {
|
||||
key = std.ArrayList(ecs.System).init(allocator);
|
||||
scroll = std.ArrayList(ecs.System).init(allocator);
|
||||
}
|
||||
|
||||
pub fn addHook(layer: Layer, hook: ecs.System) !void {
|
||||
var list = switch (layer) {
|
||||
.key => &key,
|
||||
.scroll => &scroll,
|
||||
};
|
||||
|
||||
list.append(hook);
|
||||
}
|
||||
32
src/math.zig
32
src/math.zig
|
|
@ -3,6 +3,7 @@ pub const tan = std.math.tan;
|
|||
pub const cos = std.math.cos;
|
||||
pub const sin = std.math.sin;
|
||||
pub const rad = std.math.degreesToRadians;
|
||||
pub const deg = std.math.radiansToDegrees;
|
||||
pub const sqrt = std.math.sqrt;
|
||||
|
||||
pub const Axis = struct {
|
||||
|
|
@ -190,6 +191,31 @@ pub const Quaternion = extern struct {
|
|||
};
|
||||
}
|
||||
|
||||
//pub fn rotateVector(q: Quaternion, v: @Vector(3, f32)) @Vector(3, f32) {
|
||||
// const quaternion = q.normalize();
|
||||
// const u = @Vector(3, f32){quaternion.x, quaternion.y, quaternion.z};
|
||||
// const s = quaternion.w;
|
||||
//
|
||||
// return scaleVector(u, 2.0 * dot(u, v))
|
||||
// + scaleVector(v, s*s - dot(u, u))
|
||||
// + scaleVector(cross(u, v), 2.0 * s);
|
||||
//}
|
||||
|
||||
pub fn rotateVector(self: Quaternion, vec: @Vector(3, f32)) @Vector(3, f32) {
|
||||
const vec_quat: Quaternion = .{ .w = 0, .x = vec[0], .y = vec[1], .z = vec[2] };
|
||||
|
||||
const conj: Quaternion = .{
|
||||
.w = self.w,
|
||||
.x = -self.x,
|
||||
.y = -self.y,
|
||||
.z = -self.z,
|
||||
};
|
||||
|
||||
const rotated = self.mul(vec_quat).mul(conj);
|
||||
|
||||
return @Vector(3, f32){ rotated.x, rotated.y, rotated.z };
|
||||
}
|
||||
|
||||
|
||||
inline fn mul(a: Quaternion, b: Quaternion) Quaternion {
|
||||
return .{
|
||||
|
|
@ -210,7 +236,7 @@ pub const Quaternion = extern struct {
|
|||
};
|
||||
}
|
||||
|
||||
fn matrix(q: Quaternion) Matrix {
|
||||
pub fn matrix(q: Quaternion) Matrix {
|
||||
const x2 = q.x + q.x;
|
||||
const y2 = q.y + q.y;
|
||||
const z2 = q.z + q.z;
|
||||
|
|
@ -247,3 +273,7 @@ pub fn cross(a: @Vector(3, f32), b: @Vector(3, f32)) @Vector(3, f32) {
|
|||
pub fn normalize(a: @Vector(3, f32)) @Vector(3, f32) {
|
||||
return a / @as(@Vector(3, f32), @splat(@sqrt(dot(a, a))));
|
||||
}
|
||||
|
||||
pub inline fn scaleVector(a: @Vector(3, f32), s: f32) @Vector(3, f32) {
|
||||
return a * @as(@Vector(3, f32), @splat(s));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,38 +14,44 @@ pub const Uniform = struct {
|
|||
position: @Vector(3, f32),
|
||||
target: @Vector(3, f32) = .{ 0.0, 0.0, -1.0 },
|
||||
up: @Vector(3, f32) = .{ 0.0, 1.0, 0.0 },
|
||||
speed: f32 = 5,
|
||||
speed: f32 = 10,
|
||||
pitch: f32 = -45,
|
||||
yaw: f32 = 0,
|
||||
distance: f32 = 5.0,
|
||||
|
||||
pub fn getProjection(width: usize, height: usize) math.Matrix {
|
||||
return math.Matrix.perspective(math.rad(45.0), (@as(f32, @floatFromInt(width)) / @as(f32, @floatFromInt(height))), 0.1, 100.0);
|
||||
}
|
||||
|
||||
pub fn getView(self: *Camera) math.Matrix {
|
||||
_ = self.getTarget();
|
||||
return math.Matrix.lookAt(self.position, math.rad(self.yaw), math.rad(self.pitch));
|
||||
}
|
||||
|
||||
pub fn getTarget(self: *Camera) @Vector(3, f32) {
|
||||
const direction: @Vector(3, f32) = .{
|
||||
pub inline fn getDirection(self: *Camera) @Vector(3, f32) {
|
||||
return .{
|
||||
math.sin(math.rad(self.yaw)) * math.cos(math.rad(self.pitch)),
|
||||
math.sin(math.rad(self.pitch)),
|
||||
math.cos(math.rad(self.yaw)) * math.cos(math.rad(self.pitch)),
|
||||
};
|
||||
}
|
||||
|
||||
const t = (self.position[1] - (self.position[1] - self.distance)) / direction[1];
|
||||
pub fn getTarget(self: *Camera) @Vector(3, f32) {
|
||||
const direction = self.getDirection();
|
||||
|
||||
const t = self.position[1] / direction[1];
|
||||
const target: @Vector(3, f32) = .{
|
||||
self.position[0] + (t*direction[0]),
|
||||
(self.position[1] - self.distance),
|
||||
self.position[2] + (t*direction[2]),
|
||||
0.0,
|
||||
self.position[2] - (t*direction[2]),
|
||||
};
|
||||
|
||||
//target[2] = 0.0;
|
||||
|
||||
std.debug.print("{} {} {}\n", .{direction, t, target});
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
pub fn rotateAround(self: *Camera, pivot: @Vector(3, f32), angle: f32) void {
|
||||
self.yaw -= math.deg(angle);
|
||||
var rotation = math.Quaternion.fromAxisAngle(.{0.0, 1.0, 0.0}, angle);
|
||||
self.position = rotation.rotateVector(self.position - pivot) + pivot;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,8 @@ export fn sideros_init(init: api.GameInit) callconv(.c) void {
|
|||
.input = &input,
|
||||
};
|
||||
|
||||
ecs.hooks.init(allocator) catch @panic("TODO: handle this");
|
||||
ecs.hooks.addHook(.scroll, systems.zoomCamera) catch @panic("TODO handle this");
|
||||
pool = ecs.Pool.init(allocator, &resources) catch @panic("TODO: Gracefully handle error");
|
||||
// TODO(ernesto): I think this @ptrCast are unavoidable but maybe not?
|
||||
renderer = Renderer.init(allocator, @ptrCast(init.instance), @ptrCast(init.surface)) catch @panic("TODO: Gracefully handle error");
|
||||
|
|
@ -178,3 +180,9 @@ export fn sideros_key_callback(key: u32, release: bool) callconv(.c) void {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export fn sideros_scroll_callback(up: bool) callconv(.c) void {
|
||||
for (ecs.hooks.scroll.items) |hook| {
|
||||
hook(&pool, if (up) .up else .down) catch @panic("TODO: actually handle this");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,4 +13,5 @@ typedef struct {
|
|||
void sideros_init(GameInit init);
|
||||
void sideros_update(GameUpdate state);
|
||||
void sideros_key_callback(unsigned int key, bool release);
|
||||
void sideros_scroll_callback(bool up);
|
||||
void sideros_cleanup(void);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
const ecs = @import("ecs");
|
||||
const math = @import("math");
|
||||
const std = @import("std");
|
||||
const Input = ecs.Input;
|
||||
|
||||
pub fn render(pool: *ecs.Pool) anyerror!void {
|
||||
var renderer = pool.resources.renderer;
|
||||
|
|
@ -32,17 +33,38 @@ pub fn moveCamera(pool: *ecs.Pool) !void {
|
|||
const input = pool.resources.input;
|
||||
var camera = pool.resources.camera;
|
||||
const mul = @as(@Vector(3, f32), @splat(camera.speed * pool.resources.delta_time));
|
||||
var forward = camera.getDirection();
|
||||
forward[0] = -forward[0];
|
||||
forward[1] = 0.0;
|
||||
const left = math.cross(forward, camera.up);
|
||||
|
||||
if (input.isKeyDown(.w)) {
|
||||
camera.position += @as(@Vector(3, f32), .{0.0, 0.0, 1.0}) * mul;
|
||||
camera.position += forward * mul;
|
||||
}
|
||||
if (input.isKeyDown(.s)) {
|
||||
camera.position += @as(@Vector(3, f32), .{0.0, 0.0, -1.0}) * mul;
|
||||
camera.position -= forward * mul;
|
||||
}
|
||||
if (input.isKeyDown(.a)) {
|
||||
camera.position -= @as(@Vector(3, f32), .{1.0, 0.0, 0.0}) * mul;
|
||||
camera.position += left * mul;
|
||||
}
|
||||
if (input.isKeyDown(.d)) {
|
||||
camera.position += @as(@Vector(3, f32), .{1.0, 0.0, 0.0}) * mul;
|
||||
camera.position -= left * mul;
|
||||
}
|
||||
if (input.isKeyDown(.q)) {
|
||||
camera.rotateAround(camera.getTarget(), math.rad(100.0 * pool.resources.delta_time));
|
||||
}
|
||||
if (input.isKeyDown(.e)) {
|
||||
camera.rotateAround(camera.getTarget(), math.rad(-100.0 * pool.resources.delta_time));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zoomCamera(pool: *ecs.Pool, direction: Input.ScrollDirection) !void {
|
||||
var camera = pool.resources.camera;
|
||||
var camera_direction = camera.getDirection();
|
||||
camera_direction[0] = -camera_direction[0];
|
||||
if (direction == .up) {
|
||||
camera.position += camera_direction;
|
||||
} else {
|
||||
camera.position -= camera_direction;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
src/xorg.zig
10
src/xorg.zig
|
|
@ -154,7 +154,7 @@ pub fn main() !void {
|
|||
const screen = iter.data;
|
||||
|
||||
const mask = c.XCB_CW_EVENT_MASK;
|
||||
const value = c.XCB_EVENT_MASK_EXPOSURE | c.XCB_EVENT_MASK_KEY_PRESS | c.XCB_EVENT_MASK_KEY_RELEASE;
|
||||
const value = c.XCB_EVENT_MASK_EXPOSURE | c.XCB_EVENT_MASK_KEY_PRESS | c.XCB_EVENT_MASK_KEY_RELEASE | c.XCB_EVENT_MASK_BUTTON_PRESS;
|
||||
|
||||
const window = c.xcb_generate_id(connection);
|
||||
_ = c.xcb_create_window(connection, c.XCB_COPY_FROM_PARENT, window, screen.*.root, 0, 0, 800, 600, 10, c.XCB_WINDOW_CLASS_INPUT_OUTPUT, screen.*.root_visual, mask, &value);
|
||||
|
|
@ -190,6 +190,14 @@ pub fn main() !void {
|
|||
const key = c.xcb_key_symbols_get_keysym(keysyms, ev.detail, 0);
|
||||
sideros.sideros_key_callback(mapKeysym(key), true);
|
||||
},
|
||||
c.XCB_BUTTON_PRESS => {
|
||||
const ev: *c.xcb_button_press_event_t = @ptrCast(e);
|
||||
switch (ev.detail) {
|
||||
4 => sideros.sideros_scroll_callback(true),
|
||||
5 => sideros.sideros_scroll_callback(false),
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
std.c.free(e);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue