added camera panning and lots of input stuff
parent
91251651b7
commit
274cfb471b
130
src/Camera.zig
130
src/Camera.zig
|
|
@ -11,6 +11,12 @@ const Color = @import("Color.zig");
|
||||||
const Vec2i = @import("geometry/Vec2i.zig");
|
const Vec2i = @import("geometry/Vec2i.zig");
|
||||||
const Vec2f = @import("geometry/Vec2f.zig");
|
const Vec2f = @import("geometry/Vec2f.zig");
|
||||||
const Recti = @import("geometry/Recti.zig");
|
const Recti = @import("geometry/Recti.zig");
|
||||||
|
const Rectf = @import("geometry/Rectf.zig");
|
||||||
|
const shaders = @import("shaders.zig");
|
||||||
|
const c = @cImport({
|
||||||
|
@cInclude("glad/glad.h");
|
||||||
|
@cInclude("GLFW/glfw3.h");
|
||||||
|
});
|
||||||
|
|
||||||
// focus: Vec2i = Vec2i.EAST.scale(100),
|
// focus: Vec2i = Vec2i.EAST.scale(100),
|
||||||
focus: Vec2f = Vec2f.ZERO,
|
focus: Vec2f = Vec2f.ZERO,
|
||||||
|
|
@ -18,6 +24,39 @@ tile_size: i32 = 16,
|
||||||
window_size_offset_x: i32 = 0,
|
window_size_offset_x: i32 = 0,
|
||||||
window_size_offset_y: i32 = 0,
|
window_size_offset_y: i32 = 0,
|
||||||
|
|
||||||
|
drag_pos: ?Vec2i = null,
|
||||||
|
drag_focus: ?Vec2f = null,
|
||||||
|
|
||||||
|
fn draw_line_vec2i(a: Vec2i, b: Vec2i, layer: Layer, color: Color) void {
|
||||||
|
shaders.disable_textures();
|
||||||
|
|
||||||
|
c.glBegin(c.GL_LINES);
|
||||||
|
{
|
||||||
|
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||||
|
c.glVertex3i(a.x, a.y, layer.z_index);
|
||||||
|
|
||||||
|
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||||
|
c.glVertex3i(b.x, b.y, layer.z_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
c.glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_line_vec2f(a: Vec2f, b: Vec2f, layer: Layer, color: Color) void {
|
||||||
|
shaders.disable_textures();
|
||||||
|
|
||||||
|
c.glBegin(c.GL_LINES);
|
||||||
|
{
|
||||||
|
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||||
|
c.glVertex3f(a.x, a.y, @as(f32, @floatFromInt(layer.z_index)));
|
||||||
|
|
||||||
|
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||||
|
c.glVertex3f(b.x, b.y, @as(f32, @floatFromInt(layer.z_index)));
|
||||||
|
}
|
||||||
|
|
||||||
|
c.glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create() !*Camera {
|
pub fn create() !*Camera {
|
||||||
const self = Camera {};
|
const self = Camera {};
|
||||||
return try Scene.EntityPool.allocate(self);
|
return try Scene.EntityPool.allocate(self);
|
||||||
|
|
@ -38,26 +77,81 @@ pub fn entity(self: *Camera) Entity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Camera, _: f32) void {
|
||||||
|
if (self.drag_pos != null and self.drag_focus != null and Engine.mouse_pos != null) {
|
||||||
|
// new focus = OG focus + difference between drag start and drag now
|
||||||
|
const drag_start_world = self.screen_to_world_vec2i(self.drag_pos.?);
|
||||||
|
const drag_current_world = self.screen_to_world_vec2i(Engine.mouse_pos.?);
|
||||||
|
|
||||||
|
self.focus = Vec2f {
|
||||||
|
.x = self.drag_focus.?.x + (drag_start_world.x - drag_current_world.x),
|
||||||
|
.y = self.drag_focus.?.y + (drag_start_world.y - drag_current_world.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *const Camera) void {
|
||||||
|
if (Engine.Debug.CAMERA and self.drag_pos != null and self.drag_focus != null) {
|
||||||
|
if(Engine.mouse_pos != null) {
|
||||||
|
draw_line_vec2i(self.drag_pos.?, Engine.mouse_pos.?, Layer.CAMERA, Color.WHITE);
|
||||||
|
Engine.mouse_pos.?.draw(4, Layer.CAMERA, Color.CYAN);
|
||||||
|
}
|
||||||
|
self.drag_pos.?.draw(4, Layer.CAMERA, Color.RED);
|
||||||
|
|
||||||
|
const start_focus_screen = self.world_to_screen_vec2f(self.drag_focus.?);
|
||||||
|
const current_focus_screen = self.world_to_screen_vec2f(self.focus);
|
||||||
|
|
||||||
|
draw_line_vec2i(start_focus_screen, current_focus_screen, Layer.CAMERA, Color.BLUE);
|
||||||
|
start_focus_screen.draw(4, Layer.CAMERA, Color.ORANGE);
|
||||||
|
current_focus_screen.draw(4, Layer.CAMERA, Color.LIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline fn world_to_screen_vec2i(self: *const Camera, coords: Vec2i) Vec2i {
|
inline fn world_to_screen_vec2i(self: *const Camera, coords: Vec2i) Vec2i {
|
||||||
const tile_size_f: f32 = @floatFromInt(self.tile_size);
|
const tile_size_f: f32 = @floatFromInt(self.tile_size);
|
||||||
const focus_x_screen: i32 = @intFromFloat(self.focus.x * tile_size_f);
|
const focus_x_screen: i32 = @intFromFloat(self.focus.x * tile_size_f);
|
||||||
const focus_y_screen: i32 = @intFromFloat(self.focus.y * tile_size_f);
|
const focus_y_screen: i32 = @intFromFloat(self.focus.y * tile_size_f);
|
||||||
|
|
||||||
return Vec2i.create(
|
return Vec2i.create(
|
||||||
self.tile_size * coords.x - focus_x_screen + self.window_size_offset_x,
|
@as(i32, @intFromFloat(tile_size_f * coords.x)) - focus_x_screen + self.window_size_offset_x,
|
||||||
self.tile_size * coords.y - focus_y_screen + self.window_size_offset_y
|
@as(i32, @intFromFloat(tile_size_f * coords.y)) - focus_y_screen + self.window_size_offset_y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn world_to_screen_recti(self: *const Camera, box: Recti) Recti {
|
inline fn world_to_screen_vec2f(self: *const Camera, coords: Vec2f) Vec2i {
|
||||||
|
const tile_size_f: f32 = @floatFromInt(self.tile_size);
|
||||||
|
const focus_x_screen: i32 = @intFromFloat(self.focus.x * tile_size_f);
|
||||||
|
const focus_y_screen: i32 = @intFromFloat(self.focus.y * tile_size_f);
|
||||||
|
|
||||||
|
return Vec2i.create(
|
||||||
|
@as(i32, @intFromFloat(tile_size_f * coords.x)) - focus_x_screen + self.window_size_offset_x,
|
||||||
|
@as(i32, @intFromFloat(tile_size_f * coords.y)) - focus_y_screen + self.window_size_offset_y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn screen_to_world_vec2i(self: *const Camera, coords: Vec2i) Vec2f {
|
||||||
|
const tile_size_f: f32 = @floatFromInt(self.tile_size);
|
||||||
|
const focus_x_screen: i32 = @intFromFloat(self.focus.x * tile_size_f);
|
||||||
|
const focus_y_screen: i32 = @intFromFloat(self.focus.y * tile_size_f);
|
||||||
|
|
||||||
|
const pre_x: f32 = @floatFromInt(coords.x + focus_x_screen - self.window_size_offset_x);
|
||||||
|
const pre_y: f32 = @floatFromInt(coords.y + focus_y_screen - self.window_size_offset_y);
|
||||||
|
|
||||||
|
return Vec2f {
|
||||||
|
.x = pre_x / tile_size_f,
|
||||||
|
.y = pre_y / tile_size_f,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn world_to_screen_recti(self: *const Camera, box: Rectf) Recti {
|
||||||
return Recti.from_ab(
|
return Recti.from_ab(
|
||||||
self.world_to_screen_vec2i(box.a),
|
self.world_to_screen_vec2f(box.a),
|
||||||
self.world_to_screen_vec2i(box.b),
|
self.world_to_screen_vec2f(box.b),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_sprite_i(self: *const Camera, sprite: *const Sprite, world_pos: Recti, layer: Layer, color: Color) void {
|
pub fn draw_sprite_i(self: *const Camera, sprite: *const Sprite, world_pos: Recti, layer: Layer, color: Color) void {
|
||||||
const screen_pos = self.world_to_screen_recti(world_pos);
|
const screen_pos = self.world_to_screen_recti(world_pos.to_rectf());
|
||||||
sprite.draw(screen_pos, layer, color);
|
sprite.draw(screen_pos, layer, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,6 +159,28 @@ pub fn set_focus(self: *Camera, f: Vec2f) void {
|
||||||
self.focus = f;
|
self.focus = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus_layer(_: *const Camera) Layer {
|
pub fn mouse_layer(_: *const Camera) Layer {
|
||||||
return Layer.CAMERA;
|
return Layer.CAMERA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mouse_area(_: *const Camera) Recti {
|
||||||
|
return Recti.from_xywh(0, 0, 10_000, 10_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_down(self: *Camera, button: i32) bool {
|
||||||
|
// middle mouse
|
||||||
|
if (button == 2) {
|
||||||
|
if (Engine.mouse_pos == null) return false;
|
||||||
|
self.drag_pos = Engine.mouse_pos.?;
|
||||||
|
self.drag_focus = self.focus;
|
||||||
|
return true;
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_up(self: *Camera, button: i32) bool {
|
||||||
|
if (self.drag_pos == null) return false;
|
||||||
|
if (button != 2) return false;
|
||||||
|
self.drag_pos = null;
|
||||||
|
self.drag_focus = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const Layer = @import("Layer.zig");
|
||||||
const Color = @import("Color.zig");
|
const Color = @import("Color.zig");
|
||||||
const Scene = @import("Scene.zig");
|
const Scene = @import("Scene.zig");
|
||||||
const assets = @import("assets.zig");
|
const assets = @import("assets.zig");
|
||||||
|
const Vec2i = @import("geometry/Vec2i.zig");
|
||||||
|
|
||||||
const c = @cImport({
|
const c = @cImport({
|
||||||
@cInclude("glad/glad.h");
|
@cInclude("glad/glad.h");
|
||||||
|
|
@ -22,6 +23,10 @@ const Error = error {
|
||||||
AlreadyRunning
|
AlreadyRunning
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Debug = struct {
|
||||||
|
pub var CAMERA = true;
|
||||||
|
};
|
||||||
|
|
||||||
var mouse_x: i32 = 0;
|
var mouse_x: i32 = 0;
|
||||||
var mouse_y: i32 = 0;
|
var mouse_y: i32 = 0;
|
||||||
var hovered: bool = true;
|
var hovered: bool = true;
|
||||||
|
|
@ -29,6 +34,7 @@ var window: ?*c.GLFWwindow = null;
|
||||||
var current_scene: ?Scene = null;
|
var current_scene: ?Scene = null;
|
||||||
var next_scene: ?Scene = null;
|
var next_scene: ?Scene = null;
|
||||||
var projection: Matrix4f = undefined;
|
var projection: Matrix4f = undefined;
|
||||||
|
pub var mouse_pos: ?Vec2i = null;
|
||||||
|
|
||||||
fn glfw_on_error(err: c_int, desc_c: [*c]const u8) callconv(.C) void {
|
fn glfw_on_error(err: c_int, desc_c: [*c]const u8) callconv(.C) void {
|
||||||
const desc: *const u8 = @ptrCast(desc_c);
|
const desc: *const u8 = @ptrCast(desc_c);
|
||||||
|
|
@ -46,6 +52,7 @@ fn glfw_on_resize(_: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) v
|
||||||
fn glfw_on_mouse_move(_: ?*c.GLFWwindow, fx: f64, fy: f64) callconv(.C) void {
|
fn glfw_on_mouse_move(_: ?*c.GLFWwindow, fx: f64, fy: f64) callconv(.C) void {
|
||||||
const x: i32 = @intFromFloat(fx);
|
const x: i32 = @intFromFloat(fx);
|
||||||
const y: i32 = @intFromFloat(fy);
|
const y: i32 = @intFromFloat(fy);
|
||||||
|
mouse_pos = Vec2i { .x = x, .y = y };
|
||||||
if (current_scene != null and hovered) {
|
if (current_scene != null and hovered) {
|
||||||
current_scene.?.mouse_move(x, y);
|
current_scene.?.mouse_move(x, y);
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +60,18 @@ fn glfw_on_mouse_move(_: ?*c.GLFWwindow, fx: f64, fy: f64) callconv(.C) void {
|
||||||
|
|
||||||
fn glfw_on_mouse_enter(_: ?*c.GLFWwindow, mouse_within: c_int) callconv(.C) void {
|
fn glfw_on_mouse_enter(_: ?*c.GLFWwindow, mouse_within: c_int) callconv(.C) void {
|
||||||
hovered = mouse_within == c.GLFW_TRUE;
|
hovered = mouse_within == c.GLFW_TRUE;
|
||||||
|
if (!hovered) mouse_pos = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn glfw_on_mouse_button(_: ?*c.GLFWwindow, button: i32, pressed: i32, _: i32) callconv(.C) void {
|
||||||
|
// std.debug.print("[Engine:glfw_on_mouse_button] {}, {}, {}\n", .{ x, y, z });
|
||||||
|
if (current_scene != null) {
|
||||||
|
if (pressed == c.GLFW_TRUE) {
|
||||||
|
current_scene.?.mouse_down(button);
|
||||||
|
} else {
|
||||||
|
current_scene.?.mouse_up(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_window_size() struct { i32, i32 } {
|
fn get_window_size() struct { i32, i32 } {
|
||||||
|
|
@ -83,7 +102,7 @@ pub fn setup() !void {
|
||||||
// c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE);
|
// c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
|
||||||
// create the window & cleanup
|
// create the window & cleanup
|
||||||
window = c.glfwCreateWindow(1920, 1080, "My Title", null, null) orelse {
|
window = c.glfwCreateWindow(1920, 1080, "Hadean, maybe", null, null) orelse {
|
||||||
std.log.err("Failed to open window", .{});
|
std.log.err("Failed to open window", .{});
|
||||||
return error.Initialization;
|
return error.Initialization;
|
||||||
};
|
};
|
||||||
|
|
@ -105,6 +124,7 @@ pub fn setup() !void {
|
||||||
_ = c.glfwSetWindowSizeCallback(window, glfw_on_resize);
|
_ = c.glfwSetWindowSizeCallback(window, glfw_on_resize);
|
||||||
_ = c.glfwSetCursorPosCallback(window, glfw_on_mouse_move);
|
_ = c.glfwSetCursorPosCallback(window, glfw_on_mouse_move);
|
||||||
_ = c.glfwSetCursorEnterCallback(window, glfw_on_mouse_enter);
|
_ = c.glfwSetCursorEnterCallback(window, glfw_on_mouse_enter);
|
||||||
|
_ = c.glfwSetMouseButtonCallback(window, glfw_on_mouse_button);
|
||||||
|
|
||||||
const clearBrightness: f32 = 0.09;
|
const clearBrightness: f32 = 0.09;
|
||||||
c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0);
|
c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0);
|
||||||
|
|
|
||||||
174
src/Entity.zig
174
src/Entity.zig
|
|
@ -14,18 +14,25 @@ const EntityOptions = struct {
|
||||||
|
|
||||||
ptr: *anyopaque,
|
ptr: *anyopaque,
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
|
|
||||||
|
_name: *const fn(*const anyopaque) []const u8,
|
||||||
_destroy: *const fn(*const anyopaque) void,
|
_destroy: *const fn(*const anyopaque) void,
|
||||||
_update: *const fn(*anyopaque, f32) void,
|
_update: *const fn(*anyopaque, f32) void,
|
||||||
_draw: *const fn(*const anyopaque) void,
|
_draw: *const fn(*const anyopaque) void,
|
||||||
_draw_opacity: *const fn(*const anyopaque) void,
|
_draw_opacity: *const fn(*const anyopaque) void,
|
||||||
_start: *const fn(*anyopaque, *Scene) void,
|
_start: *const fn(*anyopaque, *Scene) void,
|
||||||
_resize: *const fn(*anyopaque, i32, i32) void,
|
_resize: *const fn(*anyopaque, i32, i32) void,
|
||||||
_focusable: *const fn(*const anyopaque) bool,
|
|
||||||
_focus_layer: *const fn(*const anyopaque) Layer,
|
// mouse functions
|
||||||
_focus_area: *const fn(*const anyopaque) Recti,
|
_mouse_ready: *const fn(*const anyopaque) bool,
|
||||||
|
_mouse_enabled: *const fn(*const anyopaque) bool,
|
||||||
|
_mouse_area: *const fn(*const anyopaque) Recti,
|
||||||
|
_mouse_layer: *const fn(*const anyopaque) Layer,
|
||||||
_mouse_move: *const fn(*anyopaque, i32, i32) void,
|
_mouse_move: *const fn(*anyopaque, i32, i32) void,
|
||||||
_focus: *const fn(*anyopaque) void,
|
_mouse_in: *const fn(*anyopaque) void,
|
||||||
_blur: *const fn(*anyopaque) void,
|
_mouse_out: *const fn(*anyopaque) void,
|
||||||
|
_mouse_down: *const fn(*anyopaque, i32) bool,
|
||||||
|
_mouse_up: *const fn(*anyopaque, i32) bool,
|
||||||
|
|
||||||
const ArrayTruthState = enum {
|
const ArrayTruthState = enum {
|
||||||
TRUE,
|
TRUE,
|
||||||
|
|
@ -49,10 +56,10 @@ fn bool_array_state(arr: []const bool) ArrayTruthState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
||||||
std.debug.print("[Entity:init] creating entity {s} with tag \"{s}\"\n", .{
|
// std.debug.print("[Entity:init] creating entity {s} with tag \"{s}\"\n", .{
|
||||||
@typeName(@typeInfo(@TypeOf(ptr)).Pointer.child),
|
// @typeName(@typeInfo(@TypeOf(ptr)).Pointer.child),
|
||||||
options.tag.type
|
// options.tag.type
|
||||||
});
|
// });
|
||||||
const MutablePointer = @TypeOf(ptr);
|
const MutablePointer = @TypeOf(ptr);
|
||||||
// @compileLog("Compiling Entity type for " ++ @typeName(MutablePointer));
|
// @compileLog("Compiling Entity type for " ++ @typeName(MutablePointer));
|
||||||
|
|
||||||
|
|
@ -69,22 +76,23 @@ pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
comptime var input_ready = ArrayTruthState.FALSE;
|
comptime var input_ready = ArrayTruthState.FALSE;
|
||||||
comptime {
|
// comptime {
|
||||||
input_ready = bool_array_state(&[_]bool {
|
input_ready = comptime bool_array_state(&[_]bool {
|
||||||
@hasDecl(type_info.Pointer.child, "focus_area"),
|
@hasDecl(type_info.Pointer.child, "mouse_enabled"),
|
||||||
@hasDecl(type_info.Pointer.child, "focus_layer"),
|
@hasDecl(type_info.Pointer.child, "mouse_area"),
|
||||||
@hasDecl(type_info.Pointer.child, "focus"),
|
@hasDecl(type_info.Pointer.child, "mouse_layer"),
|
||||||
@hasDecl(type_info.Pointer.child, "blur"),
|
@hasDecl(type_info.Pointer.child, "mouse_in"),
|
||||||
|
@hasDecl(type_info.Pointer.child, "mouse_out"),
|
||||||
@hasDecl(type_info.Pointer.child, "mouse_move"),
|
@hasDecl(type_info.Pointer.child, "mouse_move"),
|
||||||
});
|
});
|
||||||
|
|
||||||
switch(input_ready) {
|
// switch(input_ready) {
|
||||||
.TRUE => {},
|
// .TRUE => {},
|
||||||
.FALSE => {},
|
// .FALSE => {},
|
||||||
.EMPTY => {},
|
// .EMPTY => {},
|
||||||
.MIXED => @compileError(@typeName(type_info.Pointer.child) ++ " does not defien all methods required for input focus"),
|
// .MIXED => @compileError(@typeName(type_info.Pointer.child) ++ " does not define all methods required for input focus"),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @compileLog(MutablePointer);
|
// @compileLog(MutablePointer);
|
||||||
// @compileLog(input_ready);
|
// @compileLog(input_ready);
|
||||||
|
|
@ -95,47 +103,69 @@ pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
||||||
// @compileLog("const pointer type: " ++ @typeName(ConstPointer));
|
// @compileLog("const pointer type: " ++ @typeName(ConstPointer));
|
||||||
|
|
||||||
const gen = struct {
|
const gen = struct {
|
||||||
pub fn _focusable(_: *const anyopaque) bool {
|
// mouse functions
|
||||||
return input_ready == ArrayTruthState.TRUE;
|
pub fn _mouse_ready(_: *const anyopaque) bool {
|
||||||
|
return input_ready != ArrayTruthState.FALSE;
|
||||||
}
|
}
|
||||||
pub fn _focus_layer(pointer: *const anyopaque) Layer {
|
pub fn _mouse_enabled(pointer: *const anyopaque) bool {
|
||||||
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||||
switch (input_ready) {
|
if (@hasDecl(type_info.Pointer.child, "mouse_enabled")) {
|
||||||
.TRUE => return type_info.Pointer.child.focus_layer(self),
|
type_info.Pointer.child.mouse_enabled(self);
|
||||||
else => unreachable,
|
} else {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn _focus_area(pointer: *const anyopaque) Recti {
|
pub fn _mouse_layer(pointer: *const anyopaque) Layer {
|
||||||
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||||
switch(input_ready) {
|
if (@hasDecl(type_info.Pointer.child, "mouse_layer")) {
|
||||||
.TRUE => return type_info.Pointer.child.focus_area(self),
|
return type_info.Pointer.child.mouse_layer(self);
|
||||||
else => unreachable,
|
} else {
|
||||||
|
return Layer.HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn _mouse_area(pointer: *const anyopaque) Recti {
|
||||||
|
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||||
|
if (@hasDecl(type_info.Pointer.child, "mouse_area")) {
|
||||||
|
return type_info.Pointer.child.mouse_area(self);
|
||||||
|
} else {
|
||||||
|
return Recti.from_xywh(-10, -10, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn _mouse_move(pointer: *anyopaque, x: i32, y: i32) void {
|
pub fn _mouse_move(pointer: *anyopaque, x: i32, y: i32) void {
|
||||||
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||||
switch(input_ready) {
|
if (@hasDecl(type_info.Pointer.child, "mouse_move")) {
|
||||||
.TRUE => type_info.Pointer.child.mouse_move(self, x, y),
|
type_info.Pointer.child.mouse_move(self, x, y);
|
||||||
else => unreachable,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn _focus(pointer: *anyopaque) void {
|
pub fn _mouse_in(pointer: *anyopaque) void {
|
||||||
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||||
switch(input_ready) {
|
if (@hasDecl(type_info.Pointer.child, "mouse_in")) {
|
||||||
.TRUE => type_info.Pointer.child.focus(self),
|
type_info.Pointer.child.mouse_in(self);
|
||||||
else => unreachable,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn _blur(pointer: *anyopaque) void {
|
pub fn _mouse_out(pointer: *anyopaque) void {
|
||||||
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||||
switch(input_ready) {
|
if (@hasDecl(type_info.Pointer.child, "mouse_out")) {
|
||||||
.TRUE => type_info.Pointer.child.blur(self),
|
type_info.Pointer.child.mouse_out(self);
|
||||||
else => unreachable,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn _mouse_down(pointer: *anyopaque, button: i32) bool {
|
||||||
|
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||||
|
if (@hasDecl(type_info.Pointer.child, "mouse_down")) {
|
||||||
|
return type_info.Pointer.child.mouse_down(self, button);
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
pub fn _mouse_up(pointer: *anyopaque, button: i32) bool {
|
||||||
|
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||||
|
if (@hasDecl(type_info.Pointer.child, "mouse_up")) {
|
||||||
|
return type_info.Pointer.child.mouse_up(self, button);
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// general methods
|
||||||
pub fn _name(_: *const anyopaque) []const u8 {
|
pub fn _name(_: *const anyopaque) []const u8 {
|
||||||
// const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
// const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||||
return type_info.Pointer.child;
|
return @typeName(type_info.Pointer.child);
|
||||||
}
|
}
|
||||||
pub fn _destroy(pointer: *const anyopaque) void {
|
pub fn _destroy(pointer: *const anyopaque) void {
|
||||||
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||||
|
|
@ -176,18 +206,24 @@ pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
||||||
return Entity {
|
return Entity {
|
||||||
.ptr = ptr,
|
.ptr = ptr,
|
||||||
.tag = options.tag,
|
.tag = options.tag,
|
||||||
|
._name = gen._name,
|
||||||
._destroy = gen._destroy,
|
._destroy = gen._destroy,
|
||||||
._start = gen._start,
|
._start = gen._start,
|
||||||
._resize = gen._resize,
|
._resize = gen._resize,
|
||||||
._update = gen._update,
|
._update = gen._update,
|
||||||
._draw = gen._draw,
|
._draw = gen._draw,
|
||||||
._draw_opacity = gen._draw_opacity,
|
._draw_opacity = gen._draw_opacity,
|
||||||
._focusable = gen._focusable,
|
|
||||||
._focus_layer = gen._focus_layer,
|
// mouse stuff
|
||||||
._focus_area = gen._focus_area,
|
._mouse_ready = gen._mouse_ready,
|
||||||
|
._mouse_enabled = gen._mouse_enabled,
|
||||||
|
._mouse_layer = gen._mouse_layer,
|
||||||
|
._mouse_area = gen._mouse_area,
|
||||||
._mouse_move = gen._mouse_move,
|
._mouse_move = gen._mouse_move,
|
||||||
._focus = gen._focus,
|
._mouse_in = gen._mouse_in,
|
||||||
._blur = gen._blur,
|
._mouse_out = gen._mouse_out,
|
||||||
|
._mouse_down = gen._mouse_down,
|
||||||
|
._mouse_up = gen._mouse_up,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,33 +251,47 @@ pub fn resize(self: *const Entity, width: i32, height: i32) void {
|
||||||
self._resize(self.ptr, width, height);
|
self._resize(self.ptr, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus(self: *const Entity) void {
|
pub fn name(self: *const Entity) []const u8 {
|
||||||
self._focus(self.ptr);
|
return self._name(self.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blur(self: *const Entity) void {
|
// -=- mouse related items
|
||||||
self._blur(self.ptr);
|
pub fn mouse_ready(self: *const Entity) bool {
|
||||||
|
return self._mouse_ready(self.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -=- focus related items
|
pub fn mouse_enabled(self: *const Entity) bool {
|
||||||
|
return self._mouse_enabled(self.ptr);
|
||||||
// defines if the entity has functions to define its focus area
|
|
||||||
pub fn focusable(self: *const Entity) bool {
|
|
||||||
return self._focusable(self.ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus_layer(self: *const Entity) Layer {
|
pub fn mouse_layer(self: *const Entity) Layer {
|
||||||
return self._focus_layer(self.ptr);
|
return self._mouse_layer(self.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus_area(self: *const Entity) Recti {
|
pub fn mouse_area(self: *const Entity) Recti {
|
||||||
return self._focus_area(self.ptr);
|
return self._mouse_area(self.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouse_move(self: *const Entity, x: i32, y: i32) void {
|
pub fn mouse_move(self: *const Entity, x: i32, y: i32) void {
|
||||||
return self._mouse_move(self.ptr, x, y);
|
return self._mouse_move(self.ptr, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mouse_in(self: *const Entity) void {
|
||||||
|
self._mouse_in(self.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_out(self: *const Entity) void {
|
||||||
|
self._mouse_out(self.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_down(self: *const Entity, button: i32) bool {
|
||||||
|
return self._mouse_down(self.ptr, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_up(self: *const Entity, button: i32) bool {
|
||||||
|
return self._mouse_up(self.ptr, button);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn allocate_array(comptime T: type, size: usize, default: T) ![]T {
|
pub fn allocate_array(comptime T: type, size: usize, default: T) ![]T {
|
||||||
const ptr = try std.heap.page_allocator.alloc(T, size);
|
const ptr = try std.heap.page_allocator.alloc(T, size);
|
||||||
for (0..size) |idx| {
|
for (0..size) |idx| {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ fn layer(z_index: i32) Layer {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const HIDDEN = layer(-1);
|
||||||
pub const FLOOR = layer(0);
|
pub const FLOOR = layer(0);
|
||||||
pub const ENTITIES = layer(1);
|
pub const ENTITIES = layer(1);
|
||||||
pub const CAMERA = layer(2);
|
pub const CAMERA = layer(2);
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,17 @@ const AutoHashMap = std.AutoHashMap;
|
||||||
|
|
||||||
// cache and list bothe store entities. treat entities as fat pointers.
|
// cache and list bothe store entities. treat entities as fat pointers.
|
||||||
// Pointers into an arraylist WILL become invalid.
|
// Pointers into an arraylist WILL become invalid.
|
||||||
focus_items: ArrayList(Entity) = undefined,
|
mouse_ready_entities: ArrayList(Entity) = undefined,
|
||||||
entities: ArrayList(Entity) = undefined,
|
entities: ArrayList(Entity) = undefined,
|
||||||
tagged_entities: AutoHashMap(Tag.ID, Entity) = undefined,
|
tagged_entities: AutoHashMap(Tag.ID, Entity) = undefined,
|
||||||
mouse_inside: bool = false,
|
mouse_inside: bool = false,
|
||||||
current_focus_item: ?Entity = null,
|
current_hover_item: ?Entity = null,
|
||||||
mouse_pos: ?Vec2i = null,
|
mouse_pos: ?Vec2i = null,
|
||||||
|
|
||||||
pub fn create() Scene {
|
pub fn create() Scene {
|
||||||
var self = Scene {};
|
var self = Scene {};
|
||||||
self.entities = ArrayList(Entity).init(std.heap.page_allocator);
|
self.entities = ArrayList(Entity).init(std.heap.page_allocator);
|
||||||
self.focus_items = ArrayList(Entity).init(std.heap.page_allocator);
|
self.mouse_ready_entities = ArrayList(Entity).init(std.heap.page_allocator);
|
||||||
self.tagged_entities = AutoHashMap(Tag.ID, Entity).init(std.heap.page_allocator);
|
self.tagged_entities = AutoHashMap(Tag.ID, Entity).init(std.heap.page_allocator);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
@ -39,11 +39,15 @@ pub fn destroy(self: *Scene) void {
|
||||||
pub fn start(self: *Scene) !void {
|
pub fn start(self: *Scene) !void {
|
||||||
std.debug.print("[Scene:start] Scene starting...\n", .{});
|
std.debug.print("[Scene:start] Scene starting...\n", .{});
|
||||||
std.debug.print("[Scene:start] entities: {}\n", .{ self.entities.items.len });
|
std.debug.print("[Scene:start] entities: {}\n", .{ self.entities.items.len });
|
||||||
std.debug.print("[Scene:start] tagged entities: {}\n", .{ self.tagged_entities.count() });
|
|
||||||
var tagged_entities_iterator = self.tagged_entities.iterator();
|
for (self.entities.items) |*entity| {
|
||||||
while (tagged_entities_iterator.next()) |entry| {
|
if (entity.tag.id == Tag.NONE.id) {
|
||||||
std.debug.print("[Scene:start] - {s}: {*}\n", .{ entry.key_ptr.*, entry.value_ptr });
|
std.debug.print("[Scene:start] - {s}\n", .{ entity.name() });
|
||||||
|
} else {
|
||||||
|
std.debug.print("[Scene:start] - {s} [{s}]\n", .{ entity.name(), entity.tag.type });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.entities.items) |entity| {
|
for (self.entities.items) |entity| {
|
||||||
entity.start(self);
|
entity.start(self);
|
||||||
}
|
}
|
||||||
|
|
@ -84,13 +88,15 @@ pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
||||||
if (entity.tag.id != Tag.NONE.id) {
|
if (entity.tag.id != Tag.NONE.id) {
|
||||||
try self.tagged_entities.put(entity.tag.id, entity);
|
try self.tagged_entities.put(entity.tag.id, entity);
|
||||||
}
|
}
|
||||||
if (entity.focusable()) {
|
|
||||||
try self.focus_items.append(entity);
|
if (entity.mouse_ready()) {
|
||||||
|
try self.mouse_ready_entities.append(entity);
|
||||||
|
std.mem.sort(Entity, self.mouse_ready_entities.items, {}, entity_layer_less_than);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn entity_layer_less_than(_: void, lhs: Entity, rhs: Entity) bool {
|
fn entity_layer_less_than(_: void, lhs: Entity, rhs: Entity) bool {
|
||||||
return lhs.focus_layer().z_index < rhs.focus_layer().z_index;
|
return lhs.mouse_layer().z_index < rhs.mouse_layer().z_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(self: *Scene, dt: f32) void {
|
pub fn update(self: *Scene, dt: f32) void {
|
||||||
|
|
@ -99,38 +105,37 @@ pub fn update(self: *Scene, dt: f32) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this whole operation is wildly stupid and could be amde more efficient.
|
// this whole operation is wildly stupid and could be amde more efficient.
|
||||||
std.mem.sort(Entity, self.focus_items.items, {}, entity_layer_less_than);
|
|
||||||
if (self.mouse_pos) |mouse| {
|
if (self.mouse_pos) |mouse| {
|
||||||
var top_hovered: ?Entity = null;
|
var top_hovered: ?Entity = null;
|
||||||
|
|
||||||
for (self.focus_items.items) |item| {
|
for (self.mouse_ready_entities.items) |item| {
|
||||||
if (item.focusable() and item.focus_area().contains(mouse)) {
|
if (item.mouse_ready() and item.mouse_area().contains(mouse)) {
|
||||||
top_hovered = item;
|
top_hovered = item;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (top_hovered != null) {
|
if (top_hovered != null) {
|
||||||
if (self.current_focus_item != null) {
|
if (self.current_hover_item != null) {
|
||||||
// if we're changing hover target from something to something
|
// if we're changing hover target from something to something
|
||||||
if (self.current_focus_item.?.ptr != top_hovered.?.ptr) {
|
if (self.current_hover_item.?.ptr != top_hovered.?.ptr) {
|
||||||
self.current_focus_item.?.blur();
|
self.current_hover_item.?.mouse_out();
|
||||||
self.current_focus_item = top_hovered;
|
self.current_hover_item = top_hovered;
|
||||||
self.current_focus_item.?.focus();
|
self.current_hover_item.?.mouse_in();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// we are hovering something, and werent before.
|
// we are hovering something, and werent before.
|
||||||
self.current_focus_item = top_hovered.?;
|
self.current_hover_item = top_hovered.?;
|
||||||
self.current_focus_item.?.focus();
|
self.current_hover_item.?.mouse_in();
|
||||||
}
|
}
|
||||||
} else if (self.current_focus_item != null) {
|
} else if (self.current_hover_item != null) {
|
||||||
// here we were hovering something, but now are not.
|
// here we were hovering something, but now are not.
|
||||||
self.current_focus_item.?.blur();
|
self.current_hover_item.?.mouse_out();
|
||||||
self.current_focus_item = null;
|
self.current_hover_item = null;
|
||||||
}
|
}
|
||||||
} else if (self.current_focus_item != null) {
|
} else if (self.current_hover_item != null) {
|
||||||
self.current_focus_item.?.blur();
|
self.current_hover_item.?.mouse_out();
|
||||||
self.current_focus_item = null;
|
self.current_hover_item = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -142,8 +147,12 @@ pub fn draw(self: *Scene) void {
|
||||||
for (self.entities.items) |entity| {
|
for (self.entities.items) |entity| {
|
||||||
entity.draw_opacity();
|
entity.draw_opacity();
|
||||||
}
|
}
|
||||||
for (self.focus_items.items) |item| {
|
for (self.mouse_ready_entities.items) |item| {
|
||||||
item.focus_area().draw(item.focus_layer(), Color.WHITE.with_opacity(0.3));
|
if (self.current_hover_item != null and item.ptr == self.current_hover_item.?.ptr) {
|
||||||
|
item.mouse_area().draw(item.mouse_layer(), Color.LIME.with_opacity(0.3));
|
||||||
|
} else {
|
||||||
|
item.mouse_area().draw(item.mouse_layer(), Color.WHITE.with_opacity(0.3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,7 +166,7 @@ pub fn mouse_move(self: *Scene, x: i32, y: i32) void {
|
||||||
// std.debug.print("[Scene:mouse_move] {} {} {}\n", .{ self, x, y });
|
// std.debug.print("[Scene:mouse_move] {} {} {}\n", .{ self, x, y });
|
||||||
self.mouse_pos = Vec2i { .x = x, .y = y };
|
self.mouse_pos = Vec2i { .x = x, .y = y };
|
||||||
self.mouse_inside = true;
|
self.mouse_inside = true;
|
||||||
for (self.focus_items.items) |item| {
|
for (self.mouse_ready_entities.items) |item| {
|
||||||
item.mouse_move(x, y);
|
item.mouse_move(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,6 +180,25 @@ pub fn mouse_leave(self: *Scene) void {
|
||||||
self.mouse_pos = null;
|
self.mouse_pos = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mouse_down(self: *Scene, button: i32) void {
|
||||||
|
// std.debug.print("[Scene:mouse_down] {?}\n", .{ self.mouse_pos });
|
||||||
|
if (self.mouse_pos == null) return;
|
||||||
|
for (self.mouse_ready_entities.items) |entity| {
|
||||||
|
if (entity.mouse_area().contains(self.mouse_pos.?)) {
|
||||||
|
if (entity.mouse_down(button)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_up(self: *Scene, button: i32) void {
|
||||||
|
if (self.mouse_pos == null) return;
|
||||||
|
for (self.mouse_ready_entities.items) |entity| {
|
||||||
|
if (entity.mouse_area().contains(self.mouse_pos.?)) {
|
||||||
|
if (entity.mouse_up(button)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- helpfer functions for entities themselves
|
// --- helpfer functions for entities themselves
|
||||||
pub const EntityPool = struct {
|
pub const EntityPool = struct {
|
||||||
// an entity can choose to allocate itself however it pleases, but these
|
// an entity can choose to allocate itself however it pleases, but these
|
||||||
|
|
|
||||||
|
|
@ -30,23 +30,21 @@ pub fn destroy(self: *const Selection) void {
|
||||||
Scene.EntityPool.deallocate(self);
|
Scene.EntityPool.deallocate(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus_area(_: *const Selection) Recti {
|
pub fn mouse_area(_: *const Selection) Recti {
|
||||||
// return Recti.from_xywh(0, 0, std.math.maxInt(i16), std.math.maxInt(i16));
|
// return Recti.from_xywh(0, 0, std.math.maxInt(i16), std.math.maxInt(i16));
|
||||||
return Recti.from_xywh(0, 0, 300, 1000);
|
return Recti.from_xywh(0, 0, 300, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus_layer(_: *const Selection) Layer {
|
pub fn mouse_layer(_: *const Selection) Layer {
|
||||||
return Layer.ENTITIES;
|
return Layer.SELECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus(self: *Selection) void {
|
pub fn mouse_in(self: *Selection) void {
|
||||||
self.focused = true;
|
self.focused = true;
|
||||||
std.debug.print("[Selection:focus] Focused\n", .{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blur(self: *Selection) void {
|
pub fn mouse_out(self: *Selection) void {
|
||||||
self.focused = false;
|
self.focused = false;
|
||||||
std.debug.print("[Selection:focus] Blurred\n", .{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouse_move(_: *Selection, _: i32, _: i32) void {
|
pub fn mouse_move(_: *Selection, _: i32, _: i32) void {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,23 @@ pub fn from_xywh(x: f32, y: f32, w: f32, h: f32) Rectf {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_ab(a: Vec2f, b: Vec2f) Rectf {
|
||||||
|
const tlx = @min(a.x, b.x);
|
||||||
|
const tly = @min(a.y, b.y);
|
||||||
|
const brx = @max(a.x, b.x);
|
||||||
|
const bry = @max(a.y, b.y);
|
||||||
|
const width = brx - tlx;
|
||||||
|
const height = bry - tly;
|
||||||
|
return .{
|
||||||
|
.x = tlx,
|
||||||
|
.y = tly,
|
||||||
|
.w = width,
|
||||||
|
.h = height,
|
||||||
|
.a = Vec2f.create(tlx, tly),
|
||||||
|
.b = Vec2f.create(brx, bry),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_recti(self: *const Rectf) Recti {
|
pub fn to_recti(self: *const Rectf) Recti {
|
||||||
return Recti.from_xywh(
|
return Recti.from_xywh(
|
||||||
@intCast(self.x),
|
@intCast(self.x),
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,9 @@ pub fn contains(self: *const Recti, point: Vec2i) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_rectf(self: *const Recti) Rectf {
|
pub fn to_rectf(self: *const Recti) Rectf {
|
||||||
return Rectf.from_xywh(
|
return Rectf.from_ab(
|
||||||
@intCast(self.x),
|
self.a.to_vec2f(),
|
||||||
@intCast(self.y),
|
self.b.to_vec2f()
|
||||||
@intCast(self.w),
|
|
||||||
@intCast(self.h),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,53 @@
|
||||||
|
|
||||||
const Vec2f = @This();
|
const Vec2f = @This();
|
||||||
|
const Vec2i = @import("Vec2i.zig");
|
||||||
|
const Layer = @import("../Layer.zig");
|
||||||
|
const Color = @import("../Color.zig");
|
||||||
|
const shaders = @import("../shaders.zig");
|
||||||
|
const std = @import("std");
|
||||||
|
const c = @cImport({
|
||||||
|
@cInclude("glad/glad.h");
|
||||||
|
@cInclude("GLFW/glfw3.h");
|
||||||
|
});
|
||||||
|
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
|
|
||||||
pub fn create(x: f32, y: f32) Vec2f {
|
pub fn create(x: f32, y: f32) Vec2f {
|
||||||
return .{
|
return Vec2f {
|
||||||
.x = x,
|
.x = x,
|
||||||
.y = y,
|
.y = y,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_vec2i(self: *const Vec2f) Vec2i {
|
||||||
|
return Vec2i {
|
||||||
|
.x = @intFromFloat(self.x),
|
||||||
|
.y = @intFromFloat(self.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *const Vec2f, radius: f32, layer: Layer, color: Color) void {
|
||||||
|
shaders.disable_textures();
|
||||||
|
|
||||||
|
const segments = 8;
|
||||||
|
|
||||||
|
c.glBegin(c.GL_POLYGON);
|
||||||
|
{
|
||||||
|
for (0..segments) |segment| {
|
||||||
|
const theta = (2.0 * std.math.pi * @as(f32, @floatFromInt(segment))) / segments;
|
||||||
|
const x = radius * std.math.cos(theta);
|
||||||
|
const y = radius * std.math.sin(theta);
|
||||||
|
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||||
|
c.glVertex3f(
|
||||||
|
self.x + x,
|
||||||
|
self.y + y,
|
||||||
|
@as(f32, @floatFromInt(layer.z_index))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
pub const ZERO = create(0, 0);
|
pub const ZERO = create(0, 0);
|
||||||
pub const ONE = create(1, 1);
|
pub const ONE = create(1, 1);
|
||||||
pub const NORTH = create(0, -1);
|
pub const NORTH = create(0, -1);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
const Vec2i = @This();
|
const Vec2i = @This();
|
||||||
|
|
||||||
const Recti = @import("Recti.zig");
|
const Recti = @import("Recti.zig");
|
||||||
|
const Vec2f = @import("Vec2f.zig");
|
||||||
|
const Layer = @import("../Layer.zig");
|
||||||
|
const Color = @import("../Color.zig");
|
||||||
|
const shaders = @import("../shaders.zig");
|
||||||
|
const std = @import("std");
|
||||||
|
const c = @cImport({
|
||||||
|
@cInclude("glad/glad.h");
|
||||||
|
@cInclude("GLFW/glfw3.h");
|
||||||
|
});
|
||||||
|
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
|
|
@ -23,6 +32,36 @@ pub fn to_unit_recti(self: *const Vec2i) Recti {
|
||||||
return Recti.from_xywh(self.x, self.y, 1, 1);
|
return Recti.from_xywh(self.x, self.y, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *const Vec2i, radius: f32, layer: Layer, color: Color) void {
|
||||||
|
shaders.disable_textures();
|
||||||
|
|
||||||
|
const segments = 8;
|
||||||
|
|
||||||
|
c.glBegin(c.GL_POLYGON);
|
||||||
|
{
|
||||||
|
for (0..segments) |segment| {
|
||||||
|
const theta = (2.0 * std.math.pi * @as(f32, @floatFromInt(segment))) / segments;
|
||||||
|
const x = radius * std.math.cos(theta);
|
||||||
|
const y = radius * std.math.sin(theta);
|
||||||
|
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||||
|
c.glVertex3f(
|
||||||
|
@as(f32, @floatFromInt(self.x)) + x,
|
||||||
|
@as(f32, @floatFromInt(self.y)) + y,
|
||||||
|
@as(f32, @floatFromInt(layer.z_index))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_vec2f(self: *const Vec2i) Vec2f {
|
||||||
|
return Vec2f {
|
||||||
|
.x = @floatFromInt(self.x),
|
||||||
|
.y = @floatFromInt(self.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub const ZERO = create(0, 0);
|
pub const ZERO = create(0, 0);
|
||||||
pub const ONE = create(1, 1);
|
pub const ONE = create(1, 1);
|
||||||
pub const NORTH = create(0, -1);
|
pub const NORTH = create(0, -1);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue