asd
parent
fb4b881def
commit
91251651b7
|
|
@ -20,7 +20,7 @@ window_size_offset_y: i32 = 0,
|
|||
|
||||
pub fn create() !*Camera {
|
||||
const self = Camera {};
|
||||
return try Scene.allocate(self);
|
||||
return try Scene.EntityPool.allocate(self);
|
||||
}
|
||||
|
||||
pub fn resize(self: *Camera, width: i32, height: i32) void {
|
||||
|
|
@ -29,7 +29,7 @@ pub fn resize(self: *Camera, width: i32, height: i32) void {
|
|||
}
|
||||
|
||||
pub fn destroy(self: *const Camera) void {
|
||||
Scene.deallocate(self);
|
||||
Scene.EntityPool.deallocate(self);
|
||||
}
|
||||
|
||||
pub fn entity(self: *Camera) Entity {
|
||||
|
|
@ -64,3 +64,7 @@ pub fn draw_sprite_i(self: *const Camera, sprite: *const Sprite, world_pos: Rect
|
|||
pub fn set_focus(self: *Camera, f: Vec2f) void {
|
||||
self.focus = f;
|
||||
}
|
||||
|
||||
pub fn focus_layer(_: *const Camera) Layer {
|
||||
return Layer.CAMERA;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub fn with_opacity(self: *const Color, a: f32) Color {
|
|||
.r = self.r,
|
||||
.g = self.g,
|
||||
.b = self.b,
|
||||
.a = a
|
||||
.a = a * self.a,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ const Error = error {
|
|||
AlreadyRunning
|
||||
};
|
||||
|
||||
var mouse_x: i32 = 0;
|
||||
var mouse_y: i32 = 0;
|
||||
var hovered: bool = true;
|
||||
var window: ?*c.GLFWwindow = null;
|
||||
var current_scene: ?Scene = null;
|
||||
var next_scene: ?Scene = null;
|
||||
|
|
@ -29,18 +32,30 @@ var projection: Matrix4f = undefined;
|
|||
|
||||
fn glfw_on_error(err: c_int, desc_c: [*c]const u8) callconv(.C) void {
|
||||
const desc: *const u8 = @ptrCast(desc_c);
|
||||
std.log.err("[Engine:glfw_on_error] glfw error {x:0>8}: {s}", .{ err, desc });
|
||||
std.log.err("[Engine:glfw_on_error] glfw error {x:0>8}: {s}\n", .{ err, desc });
|
||||
}
|
||||
|
||||
fn glfw_on_resize (_: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void {
|
||||
std.debug.print("[Engine:glfw_on_resize] {?}: {d} x {d}\n", .{ window, width, height });
|
||||
fn glfw_on_resize(_: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void {
|
||||
std.debug.print("[Engine:glfw_on_resize] {d} x {d}\n", .{ width, height });
|
||||
c.glViewport(0, 0, width, height);
|
||||
projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100);
|
||||
shaders.set_projection_matrix(&projection);
|
||||
if (current_scene != null) current_scene.?.resize(width, height);
|
||||
}
|
||||
|
||||
fn get_size() struct { i32, i32 } {
|
||||
fn glfw_on_mouse_move(_: ?*c.GLFWwindow, fx: f64, fy: f64) callconv(.C) void {
|
||||
const x: i32 = @intFromFloat(fx);
|
||||
const y: i32 = @intFromFloat(fy);
|
||||
if (current_scene != null and hovered) {
|
||||
current_scene.?.mouse_move(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
fn glfw_on_mouse_enter(_: ?*c.GLFWwindow, mouse_within: c_int) callconv(.C) void {
|
||||
hovered = mouse_within == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
fn get_window_size() struct { i32, i32 } {
|
||||
var width: c_int = undefined;
|
||||
var height: c_int = undefined;
|
||||
c.glfwGetFramebufferSize(window, @ptrCast(&width), @ptrCast(&height));
|
||||
|
|
@ -88,6 +103,8 @@ pub fn setup() !void {
|
|||
try assets.load();
|
||||
|
||||
_ = c.glfwSetWindowSizeCallback(window, glfw_on_resize);
|
||||
_ = c.glfwSetCursorPosCallback(window, glfw_on_mouse_move);
|
||||
_ = c.glfwSetCursorEnterCallback(window, glfw_on_mouse_enter);
|
||||
|
||||
const clearBrightness: f32 = 0.09;
|
||||
c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0);
|
||||
|
|
@ -99,7 +116,7 @@ pub fn setup() !void {
|
|||
c.glDepthFunc(c.GL_LEQUAL);
|
||||
c.glDepthMask(c.GL_TRUE);
|
||||
|
||||
const width, const height = get_size();
|
||||
const width, const height = get_window_size();
|
||||
c.glViewport(0, 0, width, height);
|
||||
projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100);
|
||||
shaders.set_projection_matrix(&projection);
|
||||
|
|
@ -129,8 +146,12 @@ pub fn run() Error!void {
|
|||
// start our scene
|
||||
try current_scene.?.start();
|
||||
// and send it the appropriate resize.
|
||||
const width, const height = get_size();
|
||||
const width, const height = get_window_size();
|
||||
current_scene.?.resize(width, height);
|
||||
if(hovered) {
|
||||
current_scene.?.mouse_enter();
|
||||
current_scene.?.mouse_move(mouse_x, mouse_y);
|
||||
}
|
||||
}
|
||||
// setup for drawing
|
||||
c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT);
|
||||
|
|
|
|||
125
src/Entity.zig
125
src/Entity.zig
|
|
@ -20,6 +20,33 @@ _draw: *const fn(*const anyopaque) void,
|
|||
_draw_opacity: *const fn(*const anyopaque) void,
|
||||
_start: *const fn(*anyopaque, *Scene) void,
|
||||
_resize: *const fn(*anyopaque, i32, i32) void,
|
||||
_focusable: *const fn(*const anyopaque) bool,
|
||||
_focus_layer: *const fn(*const anyopaque) Layer,
|
||||
_focus_area: *const fn(*const anyopaque) Recti,
|
||||
_mouse_move: *const fn(*anyopaque, i32, i32) void,
|
||||
_focus: *const fn(*anyopaque) void,
|
||||
_blur: *const fn(*anyopaque) void,
|
||||
|
||||
const ArrayTruthState = enum {
|
||||
TRUE,
|
||||
MIXED,
|
||||
FALSE,
|
||||
EMPTY,
|
||||
};
|
||||
|
||||
fn bool_array_state(arr: []const bool) ArrayTruthState {
|
||||
var any = false;
|
||||
var all = true;
|
||||
for (arr) |item| {
|
||||
any = any or item;
|
||||
all = all and item;
|
||||
}
|
||||
if (any and all) return .TRUE;
|
||||
if (any and !all) return .MIXED;
|
||||
if (!any and all) return .EMPTY;
|
||||
if (!any and !all) return .FALSE;
|
||||
return .FALSE;
|
||||
}
|
||||
|
||||
pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
||||
std.debug.print("[Entity:init] creating entity {s} with tag \"{s}\"\n", .{
|
||||
|
|
@ -41,12 +68,75 @@ pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
|||
else => @compileError("Entity pointer must point to a struct or opaque type"),
|
||||
}
|
||||
|
||||
comptime var input_ready = ArrayTruthState.FALSE;
|
||||
comptime {
|
||||
input_ready = bool_array_state(&[_]bool {
|
||||
@hasDecl(type_info.Pointer.child, "focus_area"),
|
||||
@hasDecl(type_info.Pointer.child, "focus_layer"),
|
||||
@hasDecl(type_info.Pointer.child, "focus"),
|
||||
@hasDecl(type_info.Pointer.child, "blur"),
|
||||
@hasDecl(type_info.Pointer.child, "mouse_move"),
|
||||
});
|
||||
|
||||
switch(input_ready) {
|
||||
.TRUE => {},
|
||||
.FALSE => {},
|
||||
.EMPTY => {},
|
||||
.MIXED => @compileError(@typeName(type_info.Pointer.child) ++ " does not defien all methods required for input focus"),
|
||||
}
|
||||
}
|
||||
|
||||
// @compileLog(MutablePointer);
|
||||
// @compileLog(input_ready);
|
||||
|
||||
// also take the const pointer type, as we will use both mutable an immutable pointers.
|
||||
// some entities mutate and some do not
|
||||
const ConstPointer = *const @typeInfo(MutablePointer).Pointer.child;
|
||||
// @compileLog("const pointer type: " ++ @typeName(ConstPointer));
|
||||
|
||||
const gen = struct {
|
||||
pub fn _focusable(_: *const anyopaque) bool {
|
||||
return input_ready == ArrayTruthState.TRUE;
|
||||
}
|
||||
pub fn _focus_layer(pointer: *const anyopaque) Layer {
|
||||
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||
switch (input_ready) {
|
||||
.TRUE => return type_info.Pointer.child.focus_layer(self),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
pub fn _focus_area(pointer: *const anyopaque) Recti {
|
||||
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||
switch(input_ready) {
|
||||
.TRUE => return type_info.Pointer.child.focus_area(self),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
pub fn _mouse_move(pointer: *anyopaque, x: i32, y: i32) void {
|
||||
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||
switch(input_ready) {
|
||||
.TRUE => type_info.Pointer.child.mouse_move(self, x, y),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
pub fn _focus(pointer: *anyopaque) void {
|
||||
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||
switch(input_ready) {
|
||||
.TRUE => type_info.Pointer.child.focus(self),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
pub fn _blur(pointer: *anyopaque) void {
|
||||
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||
switch(input_ready) {
|
||||
.TRUE => type_info.Pointer.child.blur(self),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
pub fn _name(_: *const anyopaque) []const u8 {
|
||||
// const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||
return type_info.Pointer.child;
|
||||
}
|
||||
pub fn _destroy(pointer: *const anyopaque) void {
|
||||
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||
type_info.Pointer.child.destroy(self);
|
||||
|
|
@ -83,7 +173,7 @@ pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
|||
}
|
||||
};
|
||||
|
||||
return .{
|
||||
return Entity {
|
||||
.ptr = ptr,
|
||||
.tag = options.tag,
|
||||
._destroy = gen._destroy,
|
||||
|
|
@ -92,6 +182,12 @@ pub fn init(ptr: anytype, options: EntityOptions) Entity {
|
|||
._update = gen._update,
|
||||
._draw = gen._draw,
|
||||
._draw_opacity = gen._draw_opacity,
|
||||
._focusable = gen._focusable,
|
||||
._focus_layer = gen._focus_layer,
|
||||
._focus_area = gen._focus_area,
|
||||
._mouse_move = gen._mouse_move,
|
||||
._focus = gen._focus,
|
||||
._blur = gen._blur,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -119,6 +215,33 @@ pub fn resize(self: *const Entity, width: i32, height: i32) void {
|
|||
self._resize(self.ptr, width, height);
|
||||
}
|
||||
|
||||
pub fn focus(self: *const Entity) void {
|
||||
self._focus(self.ptr);
|
||||
}
|
||||
|
||||
pub fn blur(self: *const Entity) void {
|
||||
self._blur(self.ptr);
|
||||
}
|
||||
|
||||
// -=- focus related items
|
||||
|
||||
// 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 {
|
||||
return self._focus_layer(self.ptr);
|
||||
}
|
||||
|
||||
pub fn focus_area(self: *const Entity) Recti {
|
||||
return self._focus_area(self.ptr);
|
||||
}
|
||||
|
||||
pub fn mouse_move(self: *const Entity, x: i32, y: i32) void {
|
||||
return self._mouse_move(self.ptr, x, y);
|
||||
}
|
||||
|
||||
pub fn allocate_array(comptime T: type, size: usize, default: T) ![]T {
|
||||
const ptr = try std.heap.page_allocator.alloc(T, size);
|
||||
for (0..size) |idx| {
|
||||
|
|
|
|||
|
|
@ -10,3 +10,5 @@ fn layer(z_index: i32) Layer {
|
|||
|
||||
pub const FLOOR = layer(0);
|
||||
pub const ENTITIES = layer(1);
|
||||
pub const CAMERA = layer(2);
|
||||
pub const SELECTION = layer(3);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ pub fn random() !*Pawn {
|
|||
@intFromFloat(@floor(prng.random().float(f32) * @as(f32, @floatFromInt(Terrain.CHUNK_SIZE)))),
|
||||
@intFromFloat(@floor(prng.random().float(f32) * @as(f32, @floatFromInt(Terrain.CHUNK_SIZE))))
|
||||
);
|
||||
return try Scene.allocate(self);
|
||||
return try Scene.EntityPool.allocate(self);
|
||||
}
|
||||
|
||||
pub fn create() !*Pawn {
|
||||
|
|
@ -34,7 +34,7 @@ pub fn start(self: *Pawn, scene: *const Scene) void {
|
|||
}
|
||||
|
||||
pub fn destroy(self: *const Pawn) void {
|
||||
Scene.deallocate(self);
|
||||
Scene.EntityPool.deallocate(self);
|
||||
}
|
||||
|
||||
pub fn entity(self: *Pawn) Entity {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ const Layer = @import("Layer.zig");
|
|||
const Color = @import("Color.zig");
|
||||
const Entity = @import("Entity.zig");
|
||||
const Terrain = @import("Terrain.zig");
|
||||
const Vec2i = @import("geometry/Vec2i.zig");
|
||||
const Tag = @import("Tag.zig");
|
||||
const std = @import("std");
|
||||
const ArrayList = std.ArrayList;
|
||||
|
|
@ -13,12 +14,17 @@ const AutoHashMap = std.AutoHashMap;
|
|||
|
||||
// cache and list bothe store entities. treat entities as fat pointers.
|
||||
// Pointers into an arraylist WILL become invalid.
|
||||
focus_items: ArrayList(Entity) = undefined,
|
||||
entities: ArrayList(Entity) = undefined,
|
||||
tagged_entities: AutoHashMap(Tag.ID, Entity) = undefined,
|
||||
mouse_inside: bool = false,
|
||||
current_focus_item: ?Entity = null,
|
||||
mouse_pos: ?Vec2i = null,
|
||||
|
||||
pub fn create() Scene {
|
||||
var self = Scene {};
|
||||
self.entities = ArrayList(Entity).init(std.heap.page_allocator);
|
||||
self.focus_items = ArrayList(Entity).init(std.heap.page_allocator);
|
||||
self.tagged_entities = AutoHashMap(Tag.ID, Entity).init(std.heap.page_allocator);
|
||||
return self;
|
||||
}
|
||||
|
|
@ -60,7 +66,7 @@ pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
|||
@compileError(
|
||||
"Cannot add to scene type " ++
|
||||
@typeName(instance_ptr_type) ++
|
||||
"Must be a mutable pointer\n"
|
||||
". Must be a mutable pointer\n"
|
||||
);
|
||||
if (instance_ptr_type_info.Pointer.size != .One)
|
||||
@compileError("Pointer size must be One");
|
||||
|
|
@ -78,12 +84,55 @@ pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
|||
if (entity.tag.id != Tag.NONE.id) {
|
||||
try self.tagged_entities.put(entity.tag.id, entity);
|
||||
}
|
||||
if (entity.focusable()) {
|
||||
try self.focus_items.append(entity);
|
||||
}
|
||||
}
|
||||
|
||||
fn entity_layer_less_than(_: void, lhs: Entity, rhs: Entity) bool {
|
||||
return lhs.focus_layer().z_index < rhs.focus_layer().z_index;
|
||||
}
|
||||
|
||||
pub fn update(self: *Scene, dt: f32) void {
|
||||
for (self.entities.items) |entity| {
|
||||
entity.update(dt);
|
||||
}
|
||||
|
||||
// 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| {
|
||||
var top_hovered: ?Entity = null;
|
||||
|
||||
for (self.focus_items.items) |item| {
|
||||
if (item.focusable() and item.focus_area().contains(mouse)) {
|
||||
top_hovered = item;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (top_hovered != null) {
|
||||
if (self.current_focus_item != null) {
|
||||
// if we're changing hover target from something to something
|
||||
if (self.current_focus_item.?.ptr != top_hovered.?.ptr) {
|
||||
self.current_focus_item.?.blur();
|
||||
self.current_focus_item = top_hovered;
|
||||
self.current_focus_item.?.focus();
|
||||
}
|
||||
} else {
|
||||
// we are hovering something, and werent before.
|
||||
self.current_focus_item = top_hovered.?;
|
||||
self.current_focus_item.?.focus();
|
||||
}
|
||||
} else if (self.current_focus_item != null) {
|
||||
// here we were hovering something, but now are not.
|
||||
self.current_focus_item.?.blur();
|
||||
self.current_focus_item = null;
|
||||
}
|
||||
} else if (self.current_focus_item != null) {
|
||||
self.current_focus_item.?.blur();
|
||||
self.current_focus_item = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn draw(self: *Scene) void {
|
||||
|
|
@ -93,6 +142,9 @@ pub fn draw(self: *Scene) void {
|
|||
for (self.entities.items) |entity| {
|
||||
entity.draw_opacity();
|
||||
}
|
||||
for (self.focus_items.items) |item| {
|
||||
item.focus_area().draw(item.focus_layer(), Color.WHITE.with_opacity(0.3));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize(self: *Scene, width: i32, height: i32) void {
|
||||
|
|
@ -101,16 +153,35 @@ pub fn resize(self: *Scene, width: i32, height: i32) void {
|
|||
}
|
||||
}
|
||||
|
||||
// --- helpfer functions for entities themselves
|
||||
pub fn mouse_move(self: *Scene, x: i32, y: i32) void {
|
||||
// std.debug.print("[Scene:mouse_move] {} {} {}\n", .{ self, x, y });
|
||||
self.mouse_pos = Vec2i { .x = x, .y = y };
|
||||
self.mouse_inside = true;
|
||||
for (self.focus_items.items) |item| {
|
||||
item.mouse_move(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// an entity can choose to allocate itself however it pleases, but these
|
||||
// are good default functions that just throw things on the heap.
|
||||
pub fn allocate(instance: anytype) !*@TypeOf(instance) {
|
||||
pub fn mouse_enter(self: *Scene) void {
|
||||
self.mouse_inside = true;
|
||||
}
|
||||
|
||||
pub fn mouse_leave(self: *Scene) void {
|
||||
self.mouse_inside = false;
|
||||
self.mouse_pos = null;
|
||||
}
|
||||
|
||||
// --- helpfer functions for entities themselves
|
||||
pub const EntityPool = struct {
|
||||
// an entity can choose to allocate itself however it pleases, but these
|
||||
// are good default functions that just throw things on the heap.
|
||||
pub fn allocate(instance: anytype) !*@TypeOf(instance) {
|
||||
const ptr = try std.heap.page_allocator.create(@TypeOf(instance));
|
||||
ptr.* = instance;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deallocate(instance: anytype) void {
|
||||
pub fn deallocate(instance: anytype) void {
|
||||
std.heap.page_allocator.destroy(instance);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
const Selection = @This();
|
||||
|
||||
const Scene = @import("./Scene.zig");
|
||||
const Entity = @import("./Entity.zig");
|
||||
const Tag = @import("./Tag.zig");
|
||||
const Layer = @import("./Layer.zig");
|
||||
const Engine = @import("./Engine.zig");
|
||||
const Recti = @import("./geometry/Recti.zig");
|
||||
const std = @import("std");
|
||||
|
||||
const TAG = Tag.create(Selection);
|
||||
|
||||
selection: std.ArrayList(Selectable),
|
||||
focused: bool = false,
|
||||
|
||||
pub fn create() !*Selection {
|
||||
return try Scene.EntityPool.allocate(Selection {
|
||||
.selection = std.ArrayList(Selectable).init(std.heap.page_allocator),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn entity(self: *Selection) Entity {
|
||||
return Entity.init(self, .{
|
||||
.tag = TAG,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn destroy(self: *const Selection) void {
|
||||
self.selection.deinit();
|
||||
Scene.EntityPool.deallocate(self);
|
||||
}
|
||||
|
||||
pub fn focus_area(_: *const Selection) Recti {
|
||||
// return Recti.from_xywh(0, 0, std.math.maxInt(i16), std.math.maxInt(i16));
|
||||
return Recti.from_xywh(0, 0, 300, 1000);
|
||||
}
|
||||
|
||||
pub fn focus_layer(_: *const Selection) Layer {
|
||||
return Layer.ENTITIES;
|
||||
}
|
||||
|
||||
pub fn focus(self: *Selection) void {
|
||||
self.focused = true;
|
||||
std.debug.print("[Selection:focus] Focused\n", .{});
|
||||
}
|
||||
|
||||
pub fn blur(self: *Selection) void {
|
||||
self.focused = false;
|
||||
std.debug.print("[Selection:focus] Blurred\n", .{});
|
||||
}
|
||||
|
||||
pub fn mouse_move(_: *Selection, _: i32, _: i32) void {
|
||||
// std.debug.print("[Selection:mouse_move] {}, {}\n", .{ x, y });
|
||||
}
|
||||
|
||||
const Selectable = struct {
|
||||
ptr: *anyopaque,
|
||||
|
||||
pub fn init(item: anytype) Selectable {
|
||||
// const target_type = @typeInfo(@TypeOf(item));
|
||||
// const MutablePointer = @typeInfo(@TypeOf(item));
|
||||
|
||||
return Selectable {
|
||||
.ptr = item
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
@ -26,6 +26,7 @@ pub fn create(tex: *const Texture, rect: Recti) Sprite {
|
|||
|
||||
pub fn draw(self: *const Sprite, screen_pos: Recti, layer: Layer, color: Color) void {
|
||||
self.texture.bind(c.GL_TEXTURE0);
|
||||
shaders.enable_textures();
|
||||
c.glBegin(c.GL_QUADS);
|
||||
{
|
||||
c.glVertexAttrib2f(shaders.TEXCOORD_ATTRIBUTE_ID, self.texture_area.a.x, self.texture_area.a.y);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ fn generate_tiles(self: *Terrain) void {
|
|||
}
|
||||
|
||||
pub fn create(seed: i64) !*Terrain {
|
||||
var self: *Terrain = try Scene.allocate(Terrain {
|
||||
var self: *Terrain = try Scene.EntityPool.allocate(Terrain {
|
||||
.tiles = try Entity.allocate_array(Tile, CHUNK_LENGTH, Tile.NULL),
|
||||
.growth_noise = Noise.create(seed, 10, 0.03),
|
||||
.texture_noise = Noise.create(seed + 1, 1, 3),
|
||||
|
|
@ -134,7 +134,7 @@ pub fn destroy(self: *const Terrain) void {
|
|||
self.stone_color_noise.destroy();
|
||||
|
||||
Entity.free_array(self.tiles);
|
||||
Scene.deallocate(self);
|
||||
Scene.EntityPool.deallocate(self);
|
||||
}
|
||||
|
||||
fn chance(percent: f32) bool {
|
||||
|
|
@ -173,6 +173,7 @@ pub fn update(self: *Terrain, dt: f32) void {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn draw(self: *const Terrain) void {
|
||||
for(0..CHUNK_LENGTH) |idx| {
|
||||
const tile = self.tiles[idx];
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@ const Vec2i = @import("./Vec2i.zig");
|
|||
const Vec2f = @import("./Vec2f.zig");
|
||||
const Rectf = @import("./Rectf.zig");
|
||||
const std = @import("std");
|
||||
const c = @cImport({
|
||||
@cInclude("glad/glad.h");
|
||||
@cInclude("GLFW/glfw3.h");
|
||||
});
|
||||
|
||||
const Recti = @This();
|
||||
|
||||
|
|
@ -40,6 +44,13 @@ pub fn from_ab(a: Vec2i, b: Vec2i) Recti {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn contains(self: *const Recti, point: Vec2i) bool {
|
||||
return point.x >= self.a.x
|
||||
and point.x < self.b.x
|
||||
and point.y >= self.a.y
|
||||
and point.y < self.b.y;
|
||||
}
|
||||
|
||||
pub fn to_rectf(self: *const Recti) Rectf {
|
||||
return Rectf.from_xywh(
|
||||
@intCast(self.x),
|
||||
|
|
@ -57,3 +68,72 @@ pub fn scalef(self: *const Recti, scale: Vec2f) Rectf {
|
|||
@as(f32, @floatFromInt(self.h)) / scale.y,
|
||||
);
|
||||
}
|
||||
|
||||
const Color = @import("../Color.zig");
|
||||
const Layer = @import("../Layer.zig");
|
||||
const shaders = @import("../shaders.zig");
|
||||
const assets = @import("../assets.zig");
|
||||
|
||||
pub fn draw(self: *const Recti, layer: Layer, color: Color) void {
|
||||
self.draw_filled(layer, color.with_opacity(0.2));
|
||||
self.draw_outline(layer, color);
|
||||
}
|
||||
|
||||
pub fn draw_filled(self: *const Recti, layer: Layer, color: Color) void {
|
||||
shaders.disable_textures();
|
||||
|
||||
c.glBegin(c.GL_QUADS);
|
||||
|
||||
{
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.a.x, self.a.y, layer.z_index);
|
||||
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.b.x, self.a.y, layer.z_index);
|
||||
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.b.x, self.b.y, layer.z_index);
|
||||
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.a.x, self.b.y, layer.z_index);
|
||||
}
|
||||
|
||||
c.glEnd();
|
||||
}
|
||||
|
||||
pub fn draw_outline(self: *const Recti, layer: Layer, color: Color) void {
|
||||
|
||||
shaders.disable_textures();
|
||||
|
||||
c.glBegin(c.GL_LINES);
|
||||
{
|
||||
// top
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.a.x, self.a.y, layer.z_index);
|
||||
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.b.x, self.a.y, layer.z_index);
|
||||
|
||||
// right
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.b.x, self.a.y, layer.z_index);
|
||||
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.b.x, self.b.y, layer.z_index);
|
||||
|
||||
// bottom
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.b.x, self.b.y, layer.z_index);
|
||||
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.a.x, self.b.y, layer.z_index);
|
||||
|
||||
// left
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.a.x, self.b.y, layer.z_index);
|
||||
|
||||
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
|
||||
c.glVertex3i(self.a.x, self.a.y, layer.z_index);
|
||||
}
|
||||
c.glEnd();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
const Button = struct {
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ const Scene = @import("Scene.zig");
|
|||
const Terrain = @import("Terrain.zig");
|
||||
const Pawn = @import("Pawn.zig");
|
||||
const Camera = @import("Camera.zig");
|
||||
|
||||
const Selection = @import("Selection.zig");
|
||||
|
||||
pub fn game() !Scene {
|
||||
var scene = Scene.create();
|
||||
|
|
@ -10,6 +10,7 @@ pub fn game() !Scene {
|
|||
// second try is for allocating terrain on the heap...
|
||||
try scene.add(try Camera.create());
|
||||
try scene.add(try Terrain.create(123));
|
||||
try scene.add(try Selection.create());
|
||||
for (0..5) |_| {
|
||||
try scene.add(try Pawn.random());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ const VERT_SHADER_TEXT =
|
|||
const FRAG_SHADER_TEXT =
|
||||
\\ #version 330
|
||||
\\ uniform sampler2D uTexture0;
|
||||
\\ uniform bool uNoTexture;
|
||||
\\
|
||||
\\ in vec4 vColor;
|
||||
\\ in vec2 vTexCoord;
|
||||
|
|
@ -40,15 +41,19 @@ const FRAG_SHADER_TEXT =
|
|||
\\ out vec4 color;
|
||||
\\
|
||||
\\ void main() {
|
||||
\\ if (!uNoTexture) {
|
||||
\\ vec4 texColor = color = texture(uTexture0, vTexCoord);
|
||||
\\ if(texColor == vec4(1, 0, 1, 1) || texColor == vec4(1, 0, 0, 1) || texColor.w == 0.0) {
|
||||
\\ discard;
|
||||
\\ return;
|
||||
\\ }
|
||||
\\ color = texColor * vColor;
|
||||
\\ // color = vColor;
|
||||
\\ } else {
|
||||
\\ color = vColor;
|
||||
\\ // color = vec4(1, 1, 1, 1);
|
||||
\\ // color = vec4(vTexCoord.x, vTexCoord.y, 0, 1);
|
||||
\\ }
|
||||
\\ }
|
||||
;
|
||||
|
||||
pub const POSITION_ATTRIBUTE_ID = 0;
|
||||
|
|
@ -56,12 +61,13 @@ pub const COLOR_ATTRIBUTE_ID = 1;
|
|||
pub const TEXCOORD_ATTRIBUTE_ID = 2;
|
||||
|
||||
var flat: Shader = undefined;
|
||||
var active_shader: *const Shader = undefined;
|
||||
var active_shader: *Shader = undefined;
|
||||
|
||||
pub fn load() !void {
|
||||
// if (active_shader != undefined) return Error.AlreadyInitialized;
|
||||
flat = try Shader.compile(VERT_SHADER_TEXT, FRAG_SHADER_TEXT);
|
||||
flat.enable();
|
||||
flat.enable_textures();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -70,20 +76,31 @@ pub fn set_projection_matrix(matrix: *const Matrix4f) void {
|
|||
active_shader.set_projection_matrix(matrix);
|
||||
}
|
||||
|
||||
pub fn enable_textures() void {
|
||||
active_shader.enable_textures();
|
||||
}
|
||||
|
||||
pub fn disable_textures() void {
|
||||
active_shader.disable_textures();
|
||||
}
|
||||
|
||||
const Shader = struct {
|
||||
vertex_shader: c.GLuint,
|
||||
fragment_shader: c.GLuint,
|
||||
program_handle: c.GLuint,
|
||||
|
||||
textures_enabled: bool = false,
|
||||
|
||||
const Error = error {
|
||||
CompilationFailed
|
||||
};
|
||||
|
||||
fn enable(self: *const Shader) void {
|
||||
fn enable(self: *Shader) void {
|
||||
c.glUseProgram(self.program_handle);
|
||||
active_shader = self;
|
||||
|
||||
c.glUniform1i(c.glGetUniformLocation(self.program_handle, "uTexture0"), 0);
|
||||
self.enable_textures();
|
||||
}
|
||||
|
||||
fn compile(vert_shader_text: []const u8, frag_shader_text: []const u8) !Shader {
|
||||
|
|
@ -148,6 +165,20 @@ const Shader = struct {
|
|||
const attribute_id: c.GLint = self.get_uniform_id("uProjection");
|
||||
c.glUniformMatrix4fv(attribute_id, 1, c.GL_FALSE, @ptrCast(&matrix.values));
|
||||
}
|
||||
|
||||
fn enable_textures(self: *Shader) void {
|
||||
if (self.textures_enabled) return;
|
||||
self.textures_enabled = true;
|
||||
const attr_id: c.GLint = self.get_uniform_id("uNoTexture");
|
||||
c.glUniform1i(attr_id, c.GL_FALSE);
|
||||
}
|
||||
|
||||
fn disable_textures(self: *Shader) void {
|
||||
if (!self.textures_enabled) return;
|
||||
self.textures_enabled = false;
|
||||
const attr_id: c.GLint = self.get_uniform_id("uNoTexture");
|
||||
c.glUniform1i(attr_id, c.GL_TRUE);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue