noise, cameras, logging, idfk
parent
05dfdca6c6
commit
4a21ff6ef1
|
|
@ -54,6 +54,12 @@ pub fn build(b: *std.Build) void {
|
||||||
.file = b.path(glad_folder ++ "/src/glad.c")
|
.file = b.path(glad_folder ++ "/src/glad.c")
|
||||||
});
|
});
|
||||||
exe.addIncludePath(b.path(glad_folder ++ "/include"));
|
exe.addIncludePath(b.path(glad_folder ++ "/include"));
|
||||||
|
|
||||||
|
exe.addCSourceFile(.{
|
||||||
|
.file = b.path("open-simplex/src/OpenSimplex2F.c")
|
||||||
|
});
|
||||||
|
exe.addIncludePath(b.path("open-simplex/include"));
|
||||||
|
|
||||||
exe.linkLibC();
|
exe.linkLibC();
|
||||||
exe.linkSystemLibrary("glfw");
|
exe.linkSystemLibrary("glfw");
|
||||||
exe.linkSystemLibrary("GL");
|
exe.linkSystemLibrary("GL");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
#ifndef OpenSimplex2F_h__
|
||||||
|
#define OpenSimplex2F_h__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* K.jpg's OpenSimplex 2, faster variant
|
||||||
|
*
|
||||||
|
* - 2D is standard simplex implemented using a lookup table.
|
||||||
|
* - 3D is "Re-oriented 4-point BCC noise" which constructs a
|
||||||
|
* congruent BCC lattice in a much different way than usual.
|
||||||
|
* - 4D constructs the lattice as a union of five copies of its
|
||||||
|
* reciprocal. It successively finds the closest point on each.
|
||||||
|
*
|
||||||
|
* Multiple versions of each function are provided. See the
|
||||||
|
* documentation above each, for more info.
|
||||||
|
*
|
||||||
|
* Ported from Java to C by Stephen M. Cameron
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct OpenSimplex2F_context {
|
||||||
|
int16_t *perm;
|
||||||
|
struct Grad2 *permGrad2;
|
||||||
|
struct Grad3 *permGrad3;
|
||||||
|
struct Grad4 *permGrad4;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Allocate and initialize OpenSimplex2F context */
|
||||||
|
int OpenSimplex2F(int64_t seed, struct OpenSimplex2F_context **ctx);
|
||||||
|
|
||||||
|
/* Free OpenSimplex2F context */
|
||||||
|
void OpenSimplex2F_free(struct OpenSimplex2F_context * ctx);
|
||||||
|
|
||||||
|
/* Free singleton lattice point data */
|
||||||
|
void OpenSimplex2F_shutdown(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2D Simplex noise, standard lattice orientation.
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise2(struct OpenSimplex2F_context *ctx, double x, double y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2D Simplex noise, with Y pointing down the main diagonal.
|
||||||
|
* Might be better for a 2D sandbox style game, where Y is vertical.
|
||||||
|
* Probably slightly less optimal for heightmaps or continent maps.
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise2_XBeforeY(struct OpenSimplex2F_context *ctx, double x, double y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3D Re-oriented 4-point BCC noise, classic orientation.
|
||||||
|
* Proper substitute for 3D Simplex in light of Forbidden Formulae.
|
||||||
|
* Use noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate.
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise3_Classic(struct OpenSimplex2F_context *ctx, double x, double y, double z);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3D Re-oriented 4-point BCC noise, with better visual isotropy in (X, Y).
|
||||||
|
* Recommended for 3D terrain and time-varied animations.
|
||||||
|
* The Z coordinate should always be the "different" coordinate in your use case.
|
||||||
|
* If Y is vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use noise3_XZBeforeY.
|
||||||
|
* If Z is vertical in world coordinates, call noise3_XYBeforeZ(x, y, Z).
|
||||||
|
* For a time varied animation, call noise3_XYBeforeZ(x, y, T).
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise3_XYBeforeZ(struct OpenSimplex2F_context *ctx, double x, double y, double z);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3D Re-oriented 4-point BCC noise, with better visual isotropy in (X, Z).
|
||||||
|
* Recommended for 3D terrain and time-varied animations.
|
||||||
|
* The Y coordinate should always be the "different" coordinate in your use case.
|
||||||
|
* If Y is vertical in world coordinates, call noise3_XZBeforeY(x, Y, z).
|
||||||
|
* If Z is vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use noise3_XYBeforeZ.
|
||||||
|
* For a time varied animation, call noise3_XZBeforeY(x, T, y) or use noise3_XYBeforeZ.
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise3_XZBeforeY(struct OpenSimplex2F_context *ctx, double x, double y, double z);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4D OpenSimplex2F noise, classic lattice orientation.
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise4_Classic(struct OpenSimplex2F_context *ctx, double x, double y, double z, double w);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4D OpenSimplex2F noise, with XY and ZW forming orthogonal triangular-based planes.
|
||||||
|
* Recommended for 3D terrain, where X and Y (or Z and W) are horizontal.
|
||||||
|
* Recommended for noise(x, y, sin(time), cos(time)) trick.
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise4_XYBeforeZW(struct OpenSimplex2F_context *ctx, double x, double y, double z, double w);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4D OpenSimplex2F noise, with XZ and YW forming orthogonal triangular-based planes.
|
||||||
|
* Recommended for 3D terrain, where X and Z (or Y and W) are horizontal.
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise4_XZBeforeYW(struct OpenSimplex2F_context *ctx, double x, double y, double z, double w);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4D OpenSimplex2F noise, with XYZ oriented like noise3_Classic,
|
||||||
|
* and W for an extra degree of freedom. W repeats eventually.
|
||||||
|
* Recommended for time-varied animations which texture a 3D object (W=time)
|
||||||
|
*/
|
||||||
|
double OpenSimplex2F_noise4_XYZBeforeW(struct OpenSimplex2F_context *ctx, double x, double y, double z, double w);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -137,13 +137,6 @@ static struct LatticePoint4D *new_LatticePoint4D(int xsv, int ysv, int zsv, int
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OpenSimplex2F_context {
|
|
||||||
int16_t *perm;
|
|
||||||
struct Grad2 *permGrad2;
|
|
||||||
struct Grad3 *permGrad3;
|
|
||||||
struct Grad4 *permGrad4;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0]))
|
#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
||||||
static struct Grad2 GRADIENTS_2D[PSIZE];
|
static struct Grad2 GRADIENTS_2D[PSIZE];
|
||||||
|
|
@ -918,3 +911,4 @@ double OpenSimplex2F_noise4_XYZBeforeW(struct OpenSimplex2F_context *ctx, double
|
||||||
return noise4_Base(ctx, xs, ys, zs, ws);
|
return noise4_Base(ctx, xs, ys, zs, ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
const Camera = @This();
|
||||||
|
pub const TAG = @import("Tag.zig").create(Camera);
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Entity = @import("Entity.zig");
|
||||||
|
const Scene = @import("Scene.zig");
|
||||||
|
const Engine = @import("Engine.zig");
|
||||||
|
const Sprite = @import("Sprite.zig");
|
||||||
|
const Layer = @import("Layer.zig");
|
||||||
|
const Color = @import("Color.zig");
|
||||||
|
const Vec2i = @import("geometry/Vec2i.zig");
|
||||||
|
const Vec2f = @import("geometry/Vec2f.zig");
|
||||||
|
const Recti = @import("geometry/Recti.zig");
|
||||||
|
|
||||||
|
// focus: Vec2i = Vec2i.EAST.scale(100),
|
||||||
|
focus: Vec2f = Vec2f.ZERO,
|
||||||
|
tile_size: i32 = 16,
|
||||||
|
window_size_offset_x: i32 = 0,
|
||||||
|
window_size_offset_y: i32 = 0,
|
||||||
|
|
||||||
|
pub fn create() !*Camera {
|
||||||
|
const self = Camera {};
|
||||||
|
return try Scene.allocate(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(self: *Camera, width: i32, height: i32) void {
|
||||||
|
std.debug.print("[Camera:resize] {d} x {d}\n", .{ width, height });
|
||||||
|
self.window_size_offset_x = @divFloor(width, 2);
|
||||||
|
self.window_size_offset_y = @divFloor(height, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *const Camera) void {
|
||||||
|
Scene.deallocate(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entity(self: *Camera) Entity {
|
||||||
|
return Entity.init(self, .{
|
||||||
|
.tag = TAG
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn world_to_screen_vec2i(self: *const Camera, coords: Vec2i) 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(
|
||||||
|
self.tile_size * coords.x - focus_x_screen + self.window_size_offset_x,
|
||||||
|
self.tile_size * coords.y - focus_y_screen + self.window_size_offset_y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn world_to_screen_recti(self: *const Camera, box: Recti) Recti {
|
||||||
|
return Recti.from_ab(
|
||||||
|
self.world_to_screen_vec2i(box.a),
|
||||||
|
self.world_to_screen_vec2i(box.b),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
sprite.draw(screen_pos, layer, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_focus(self: *Camera, f: Vec2f) void {
|
||||||
|
self.focus = f;
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
|
const std = @import("std");
|
||||||
const Color = @This();
|
const Color = @This();
|
||||||
|
|
||||||
r: f32,
|
r: f32,
|
||||||
|
|
@ -6,6 +6,16 @@ g: f32,
|
||||||
b: f32,
|
b: f32,
|
||||||
a: f32,
|
a: f32,
|
||||||
|
|
||||||
|
pub fn blend(a: *const Color, b: *const Color, t: f32) Color {
|
||||||
|
const real_t = 1 - (if (t < 0.0) 0.0 else if (t > 1.0) 1.0 else t);
|
||||||
|
return Color.rgba(
|
||||||
|
a.r + (b.r - a.r) * real_t,
|
||||||
|
a.g + (b.g - a.g) * real_t,
|
||||||
|
a.b + (b.b - a.b) * real_t,
|
||||||
|
a.a + (b.a - a.a) * real_t
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rgba(r: f32, g: f32, b: f32, a: f32) Color {
|
pub fn rgba(r: f32, g: f32, b: f32, a: f32) Color {
|
||||||
return .{
|
return .{
|
||||||
.r = r,
|
.r = r,
|
||||||
|
|
@ -15,6 +25,59 @@ pub fn rgba(r: f32, g: f32, b: f32, a: f32) Color {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_opacity(self: *const Color, a: f32) Color {
|
||||||
|
return .{
|
||||||
|
.r = self.r,
|
||||||
|
.g = self.g,
|
||||||
|
.b = self.b,
|
||||||
|
.a = a
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// r: 0 - 360
|
||||||
|
// g: 0 - 1
|
||||||
|
// b: 0 - 1
|
||||||
|
// a: 0 - 1
|
||||||
|
// no idea how it REALLY works, i dont know color theory but chatgpt does
|
||||||
|
pub fn hsla(h: f32, s: f32, l: f32, a: f32) Color {
|
||||||
|
const c = (1.0 - @abs(2.0 * l - 1.0)) * s;
|
||||||
|
const one = (h / 60.0);
|
||||||
|
const x = c * (1.0 - @abs(@rem(one, 2.0) - 1.0));
|
||||||
|
const m = l - c / 2.0;
|
||||||
|
|
||||||
|
var r: f32 = 0.0;
|
||||||
|
var g: f32 = 0.0;
|
||||||
|
var b: f32 = 0.0;
|
||||||
|
|
||||||
|
if (h < 60.0) {
|
||||||
|
r = c;
|
||||||
|
g = x;
|
||||||
|
b = 0.0;
|
||||||
|
} else if (h < 120.0) {
|
||||||
|
r = x;
|
||||||
|
g = c;
|
||||||
|
b = 0.0;
|
||||||
|
} else if (h < 180.0) {
|
||||||
|
r = 0.0;
|
||||||
|
g = c;
|
||||||
|
b = x;
|
||||||
|
} else if (h < 240.0) {
|
||||||
|
r = 0.0;
|
||||||
|
g = x;
|
||||||
|
b = c;
|
||||||
|
} else if (h < 300.0) {
|
||||||
|
r = x;
|
||||||
|
g = 0.0;
|
||||||
|
b = c;
|
||||||
|
} else {
|
||||||
|
r = c;
|
||||||
|
g = 0.0;
|
||||||
|
b = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color.rgba(r + m, g + m, b + m, a);
|
||||||
|
}
|
||||||
|
|
||||||
pub const WHITE = rgba(1, 1, 1, 1);
|
pub const WHITE = rgba(1, 1, 1, 1);
|
||||||
pub const RED = rgba(1, 0, 0, 1);
|
pub const RED = rgba(1, 0, 0, 1);
|
||||||
pub const ORANGE = rgba(1, 0.5, 0, 1);
|
pub const ORANGE = rgba(1, 0.5, 0, 1);
|
||||||
|
|
@ -28,3 +91,5 @@ pub const BLUE = rgba(0, 0, 1, 1);
|
||||||
pub const INDIGO = rgba(0.5, 0, 1, 1);
|
pub const INDIGO = rgba(0.5, 0, 1, 1);
|
||||||
pub const MAGENTA = rgba(1, 0, 1, 1);
|
pub const MAGENTA = rgba(1, 0, 1, 1);
|
||||||
pub const HOT_PINK = rgba(1, 0, 0.5, 1);
|
pub const HOT_PINK = rgba(1, 0, 0.5, 1);
|
||||||
|
|
||||||
|
pub const BROWN = rgba(0.4, 0.25, 0.1, 1);
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,16 @@ const c = @cImport({
|
||||||
@cInclude("glad/glad.h");
|
@cInclude("glad/glad.h");
|
||||||
@cInclude("GLFW/glfw3.h");
|
@cInclude("GLFW/glfw3.h");
|
||||||
});
|
});
|
||||||
const HashMap = std.HashMap;
|
const AutoHashMap = std.AutoHashMap;
|
||||||
|
|
||||||
|
var store: AutoHashMap(*c.GLFWwindow, *Engine) = AutoHashMap(*c.GLFWwindow, *Engine).init(std.heap.page_allocator);
|
||||||
|
|
||||||
// export const IGame = struct {
|
// export const IGame = struct {
|
||||||
// render: fn () void,
|
// render: fn () void,
|
||||||
// update: fn (f32) void,
|
// update: fn (f32) void,
|
||||||
// };
|
// };
|
||||||
current_scene: Scene,
|
current_scene: Scene,
|
||||||
|
projection: Matrix4f = undefined,
|
||||||
|
|
||||||
pub fn create(initial_scene: Scene) Engine {
|
pub fn create(initial_scene: Scene) Engine {
|
||||||
return .{
|
return .{
|
||||||
|
|
@ -35,9 +37,22 @@ fn errorCallback(err: c_int, desc_c: [*c]const u8) callconv(.C) void {
|
||||||
std.log.err("glfw error {x:0>8}: {s}", .{ err, desc });
|
std.log.err("glfw error {x:0>8}: {s}", .{ err, desc });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_resize (window: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void {
|
||||||
|
std.debug.print("[Engine:on_resize] {?}: {d} x {d}\n", .{ window, width, height });
|
||||||
|
c.glViewport(0, 0, width, height);
|
||||||
|
const engine_instance = store.get(window.?).?;
|
||||||
|
engine_instance.set_matrices(width, height);
|
||||||
|
engine_instance.current_scene.resize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_matrices(self: *Engine, width: i32, height: i32) void {
|
||||||
|
self.projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100);
|
||||||
|
shaders.set_projection_matrix(&self.projection);
|
||||||
|
}
|
||||||
|
|
||||||
// export fn run(game: *const IGame) !void {
|
// export fn run(game: *const IGame) !void {
|
||||||
pub fn run(self: *Engine) !void {
|
pub fn run(self: *Engine) !void {
|
||||||
|
|
||||||
// in case of errors, set callback early!
|
// in case of errors, set callback early!
|
||||||
// for some reason this returns an error function as well??
|
// for some reason this returns an error function as well??
|
||||||
_ = c.glfwSetErrorCallback(errorCallback);
|
_ = c.glfwSetErrorCallback(errorCallback);
|
||||||
|
|
@ -63,6 +78,8 @@ pub fn run(self: *Engine) !void {
|
||||||
};
|
};
|
||||||
defer c.glfwDestroyWindow(window);
|
defer c.glfwDestroyWindow(window);
|
||||||
|
|
||||||
|
try store.put(window, self);
|
||||||
|
|
||||||
// load opengl into the window
|
// load opengl into the window
|
||||||
c.glfwMakeContextCurrent(window);
|
c.glfwMakeContextCurrent(window);
|
||||||
if (c.gladLoadGL() != 1) {
|
if (c.gladLoadGL() != 1) {
|
||||||
|
|
@ -78,6 +95,8 @@ pub fn run(self: *Engine) !void {
|
||||||
|
|
||||||
try assets.load();
|
try assets.load();
|
||||||
|
|
||||||
|
_ = c.glfwSetWindowSizeCallback(window, on_resize);
|
||||||
|
|
||||||
|
|
||||||
const clearBrightness: f32 = 0.09;
|
const clearBrightness: f32 = 0.09;
|
||||||
c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0);
|
c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0);
|
||||||
|
|
@ -92,16 +111,15 @@ pub fn run(self: *Engine) !void {
|
||||||
var width: c_int = undefined;
|
var width: c_int = undefined;
|
||||||
var height: c_int = undefined;
|
var height: c_int = undefined;
|
||||||
c.glfwGetFramebufferSize(window, @ptrCast(&width), @ptrCast(&height));
|
c.glfwGetFramebufferSize(window, @ptrCast(&width), @ptrCast(&height));
|
||||||
|
std.debug.print("[Engine:run] window size {d} x {d}\n", .{ width, height });
|
||||||
const projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100);
|
self.set_matrices(width, height);
|
||||||
|
try self.current_scene.start();
|
||||||
|
|
||||||
// run the main loop
|
// run the main loop
|
||||||
while (c.glfwWindowShouldClose(window) == 0) {
|
while (c.glfwWindowShouldClose(window) == 0) {
|
||||||
shaders.set_projection_matrix(&projection);
|
|
||||||
c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT);
|
c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT);
|
||||||
self.current_scene.draw();
|
self.current_scene.draw();
|
||||||
// game.render();
|
assets.terrain[0][0].draw(Recti.from_xywh(-1000, -1000, 50000, 50000), Layer.FLOOR, Color.WHITE);
|
||||||
// game.update(1.0);
|
|
||||||
|
|
||||||
c.glfwSwapBuffers(window);
|
c.glfwSwapBuffers(window);
|
||||||
c.glfwPollEvents();
|
c.glfwPollEvents();
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,29 @@ const Layer = @import("Layer.zig");
|
||||||
const Color = @import("Color.zig");
|
const Color = @import("Color.zig");
|
||||||
const Recti = @import("geometry/Recti.zig");
|
const Recti = @import("geometry/Recti.zig");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const Tag = @import("Tag.zig");
|
||||||
|
const Scene = @import("Scene.zig");
|
||||||
|
|
||||||
const Entity = @This();
|
const Entity = @This();
|
||||||
|
|
||||||
const EntityOptions = struct {
|
const EntityOptions = struct {
|
||||||
renders: bool = true,
|
tag: Tag = Tag.NONE,
|
||||||
updates: bool = true,
|
|
||||||
accepts_keyboard: bool = false,
|
|
||||||
accepts_mouse: bool = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ptr: *anyopaque,
|
ptr: *anyopaque,
|
||||||
options: EntityOptions,
|
tag: Tag,
|
||||||
destroyFn: *const fn(*const anyopaque) void,
|
_destroy: *const fn(*const anyopaque) void,
|
||||||
updateFn: *const fn(*anyopaque, f32) void,
|
_update: *const fn(*anyopaque, f32) void,
|
||||||
drawFn: *const fn(*const anyopaque) void,
|
_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,
|
||||||
|
|
||||||
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", .{
|
||||||
|
@typeName(@typeInfo(@TypeOf(ptr)).Pointer.child),
|
||||||
|
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));
|
||||||
|
|
||||||
|
|
@ -41,38 +47,86 @@ 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 destroyImpl(pointer: *const anyopaque) void {
|
pub fn _destroy(pointer: *const anyopaque) void {
|
||||||
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||||
type_info.Pointer.child.destroy(self);
|
type_info.Pointer.child.destroy(self);
|
||||||
}
|
}
|
||||||
pub fn updateImpl(pointer: *anyopaque, dt: f32) void {
|
pub fn _start(pointer: *anyopaque, scene: *Scene) void {
|
||||||
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||||
type_info.Pointer.child.update(self, dt);
|
if(@hasDecl(type_info.Pointer.child, "start")) {
|
||||||
|
type_info.Pointer.child.start(self, scene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn drawImpl(pointer: *const anyopaque) void {
|
pub fn _resize(pointer: *anyopaque, width: i32, height: i32) void {
|
||||||
|
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||||
|
if(@hasDecl(type_info.Pointer.child, "resize")) {
|
||||||
|
type_info.Pointer.child.resize(self, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn _update(pointer: *anyopaque, dt: f32) void {
|
||||||
|
const self: MutablePointer = @ptrCast(@alignCast(pointer));
|
||||||
|
if(@hasDecl(type_info.Pointer.child, "update")) {
|
||||||
|
type_info.Pointer.child.update(self, dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn _draw(pointer: *const anyopaque) void {
|
||||||
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||||
type_info.Pointer.child.draw(self);
|
if(@hasDecl(type_info.Pointer.child, "draw")) {
|
||||||
|
type_info.Pointer.child.draw(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn _draw_opacity(pointer: *const anyopaque) void {
|
||||||
|
const self: ConstPointer = @ptrCast(@alignCast(pointer));
|
||||||
|
if(@hasDecl(type_info.Pointer.child, "draw_opacity")) {
|
||||||
|
type_info.Pointer.child.draw_opacity(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.ptr = ptr,
|
.ptr = ptr,
|
||||||
.options = options,
|
.tag = options.tag,
|
||||||
.destroyFn = gen.destroyImpl,
|
._destroy = gen._destroy,
|
||||||
|
._start = gen._start,
|
||||||
.updateFn = gen.updateImpl,
|
._resize = gen._resize,
|
||||||
.drawFn = gen.drawImpl,
|
._update = gen._update,
|
||||||
|
._draw = gen._draw,
|
||||||
|
._draw_opacity = gen._draw_opacity,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(self: *const Entity, dt: f32) void {
|
pub fn update(self: *const Entity, dt: f32) void {
|
||||||
self.updateFn(self.ptr, dt);
|
self._update(self.ptr, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: *const Entity) void {
|
pub fn draw(self: *const Entity) void {
|
||||||
self.drawFn(self.ptr);
|
self._draw(self.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_opacity(self: *const Entity) void {
|
||||||
|
self._draw_opacity(self.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *const Entity) void {
|
pub fn destroy(self: *const Entity) void {
|
||||||
self.destroyFn(self.ptr);
|
self._destroy(self.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(self: *const Entity, scene: *Scene) void {
|
||||||
|
self._start(self.ptr, scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(self: *const Entity, width: i32, height: i32) void {
|
||||||
|
self._resize(self.ptr, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
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| {
|
||||||
|
ptr[idx] = default;
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_array(ptr: anytype) void {
|
||||||
|
std.heap.page_allocator.free(ptr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
const c = @cImport({
|
||||||
|
@cInclude("OpenSimplex2F.h");
|
||||||
|
});
|
||||||
|
const std = @import("std");
|
||||||
|
const ArrayList = std.ArrayList;
|
||||||
|
const RealColor = @import("Color.zig");
|
||||||
|
|
||||||
|
const Noise = @This();
|
||||||
|
const NoiseContext = c.OpenSimplex2F_context;
|
||||||
|
const NoiseContextPointer = ?*NoiseContext;
|
||||||
|
|
||||||
|
octave_count: usize = 1,
|
||||||
|
scale: f32 = 1,
|
||||||
|
noise_context: NoiseContext = undefined,
|
||||||
|
noise_ptr: NoiseContextPointer = undefined,
|
||||||
|
|
||||||
|
pub fn create(seed: i64, octaves: usize, scale: f32) Noise {
|
||||||
|
var self = Noise {
|
||||||
|
.octave_count = octaves,
|
||||||
|
.scale = scale,
|
||||||
|
};
|
||||||
|
self.noise_context = NoiseContext {};
|
||||||
|
self.noise_ptr = &self.noise_context;
|
||||||
|
_ = c.OpenSimplex2F(seed, @ptrCast(&self.noise_ptr));
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *const Noise, x: f32, y: f32) f32 {
|
||||||
|
var total: f32 = 0;
|
||||||
|
var max: f32 = 0;
|
||||||
|
for (0..self.octave_count) |idx| {
|
||||||
|
// in a series / sum n = 1 -> inf
|
||||||
|
const n: f32 = @floatFromInt(idx + 1);
|
||||||
|
const amplitude: f32 = 1.0 / n;
|
||||||
|
// frequency is altered both by the scale of the while gen
|
||||||
|
// and the octave we're on.
|
||||||
|
const frequency: f32 = self.scale * n;
|
||||||
|
const sx = x * frequency + n;
|
||||||
|
const sy = y * frequency;
|
||||||
|
// -amplitude <= r <= amplitude
|
||||||
|
const r: f32 = @as(f32, @floatCast(c.OpenSimplex2F_noise2(self.noise_ptr, sx, sy))) * amplitude;
|
||||||
|
total += r;
|
||||||
|
max += amplitude;
|
||||||
|
}
|
||||||
|
const n: f32 = total / max;
|
||||||
|
return @min(@max((n + 1.0) / 2.0, 0), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *const Noise) void {
|
||||||
|
_ = c.OpenSimplex2F_free(self.noise_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Octave = struct {
|
||||||
|
frequency: f32,
|
||||||
|
amplitude: f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Custom = struct {
|
||||||
|
octaves: ArrayList(Octave) = undefined,
|
||||||
|
context: NoiseContext = undefined,
|
||||||
|
context_ptr: NoiseContextPointer = undefined,
|
||||||
|
scale: f32 = 1,
|
||||||
|
|
||||||
|
pub fn create(seed: i64, scale: f32, octaves: []const Octave) !Custom {
|
||||||
|
var self = Custom {
|
||||||
|
.scale = scale
|
||||||
|
};
|
||||||
|
self.octaves = ArrayList(Octave).init(std.heap.page_allocator);
|
||||||
|
self.context = NoiseContext {};
|
||||||
|
self.context_ptr = &self.context;
|
||||||
|
_ = c.OpenSimplex2F(seed, @ptrCast(&self.context_ptr));
|
||||||
|
|
||||||
|
for (octaves) |octave| {
|
||||||
|
try self.octaves.append(octave);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *const Custom, x: f32, y: f32) f32 {
|
||||||
|
var total: f32 = 0;
|
||||||
|
var max: f32 = 0;
|
||||||
|
for (self.octaves.items) |octave| {
|
||||||
|
// @compileLog(octave);
|
||||||
|
// octave
|
||||||
|
const sx = x * self.scale * octave.frequency;
|
||||||
|
const sy = y * self.scale * octave.frequency;
|
||||||
|
const r: f32 = @as(f32, @floatCast(c.OpenSimplex2F_noise2(self.context_ptr, sx, sy))) * octave.amplitude;
|
||||||
|
total += r;
|
||||||
|
max += octave.amplitude;
|
||||||
|
}
|
||||||
|
const n: f32 = total / max;
|
||||||
|
return @min(@max((n + 1.0) / 2.0, 0), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *const Custom) void {
|
||||||
|
_ = c.OpenSimplex2F_free(self.context_ptr);
|
||||||
|
self.octaves.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Color = struct {
|
||||||
|
noise_h: Noise.Custom,
|
||||||
|
noise_s: Noise.Custom,
|
||||||
|
noise_l: Noise.Custom,
|
||||||
|
range: ColorRange,
|
||||||
|
|
||||||
|
const OCTAVES = [_]Octave{
|
||||||
|
.{ .frequency = 1, .amplitude = 1.0 },
|
||||||
|
.{ .frequency = 2, .amplitude = 0.5 },
|
||||||
|
.{ .frequency = 4, .amplitude = 0.4 },
|
||||||
|
.{ .frequency = 8, .amplitude = 0.3 },
|
||||||
|
.{ .frequency = 16, .amplitude = 0.2 },
|
||||||
|
.{ .frequency = 30, .amplitude = 1.0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn create(seed: i64, range: ColorRange) !Noise.Color {
|
||||||
|
return .{
|
||||||
|
.noise_h = try Noise.Custom.create(seed + 0, 0.03, &OCTAVES),
|
||||||
|
.noise_s = try Noise.Custom.create(seed + 1, 0.03, &OCTAVES),
|
||||||
|
.noise_l = try Noise.Custom.create(seed + 2, 0.03, &OCTAVES),
|
||||||
|
.range = range,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *const Noise.Color, x: f32, y: f32) RealColor {
|
||||||
|
return RealColor.hsla(
|
||||||
|
self.noise_h.get(x, y) * (self.range.h[1] - self.range.h[0]) + self.range.h[0],
|
||||||
|
self.noise_s.get(x, y) * (self.range.s[1] - self.range.s[0]) + self.range.s[0],
|
||||||
|
self.noise_l.get(x, y) * (self.range.l[1] - self.range.l[0]) + self.range.l[0],
|
||||||
|
1.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *const Noise.Color) void {
|
||||||
|
self.noise_h.destroy();
|
||||||
|
self.noise_s.destroy();
|
||||||
|
self.noise_l.destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ColorRange = struct {
|
||||||
|
// min / max values
|
||||||
|
h: struct { f32, f32 },
|
||||||
|
s: struct { f32, f32 },
|
||||||
|
l: struct { f32, f32 },
|
||||||
|
|
||||||
|
pub const DIRT = Noise.ColorRange {
|
||||||
|
.h = .{ 30, 33 },
|
||||||
|
.s = .{ 0.30, 0.45 },
|
||||||
|
.l = .{ 0.12, 0.22 },
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const STONE = Noise.ColorRange {
|
||||||
|
.h = .{ 0, 360 },
|
||||||
|
.s = .{ 0.00, 0.02 },
|
||||||
|
.l = .{ 0.20, 0.30 },
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const GRASS = Noise.ColorRange {
|
||||||
|
.h = .{ 100, 110 },
|
||||||
|
.s = .{ 0.72, 0.82 },
|
||||||
|
.l = .{ 0.25, 0.40 },
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const GRASS_TUNDRA = Noise.ColorRange {
|
||||||
|
.h = .{ 115, 125 },
|
||||||
|
.s = .{ 0.4, 0.5 },
|
||||||
|
.l = .{ 0.2, 0.3 },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
const Pawn = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Entity = @import("Entity.zig");
|
||||||
|
const Scene = @import("Scene.zig");
|
||||||
|
const Camera = @import("Camera.zig");
|
||||||
|
const Terrain = @import("Terrain.zig");
|
||||||
|
const Tag = @import("Tag.zig");
|
||||||
|
const Vec2i = @import("geometry/Vec2i.zig");
|
||||||
|
const assets = @import("assets.zig");
|
||||||
|
const Layer = @import("Layer.zig");
|
||||||
|
const Color = @import("Color.zig");
|
||||||
|
var prng = std.rand.DefaultPrng.init(0);
|
||||||
|
|
||||||
|
camera: *const Camera = undefined,
|
||||||
|
position: Vec2i = Vec2i.ZERO,
|
||||||
|
|
||||||
|
pub fn random() !*Pawn {
|
||||||
|
var self: Pawn = Pawn {};
|
||||||
|
self.position = Vec2i.create(
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create() !*Pawn {
|
||||||
|
const self: Pawn = Pawn {};
|
||||||
|
return try Scene.allocate(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(self: *Pawn, scene: *const Scene) void {
|
||||||
|
self.camera = scene.get(Camera.TAG, Camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *const Pawn) void {
|
||||||
|
Scene.deallocate(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entity(self: *Pawn) Entity {
|
||||||
|
return Entity.init(self, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn tile(self: *Pawn) Tile {
|
||||||
|
// return Tile.init(.{
|
||||||
|
// .solid = true
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn draw(self: *const Pawn) void {
|
||||||
|
self.camera.draw_sprite_i(assets.pawn, self.position.to_unit_recti(), Layer.ENTITIES, Color.WHITE);
|
||||||
|
}
|
||||||
|
|
@ -6,16 +6,19 @@ const Layer = @import("Layer.zig");
|
||||||
const Color = @import("Color.zig");
|
const Color = @import("Color.zig");
|
||||||
const Entity = @import("Entity.zig");
|
const Entity = @import("Entity.zig");
|
||||||
const Terrain = @import("Terrain.zig");
|
const Terrain = @import("Terrain.zig");
|
||||||
|
const Tag = @import("Tag.zig");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ArrayList = std.ArrayList;
|
const ArrayList = std.ArrayList;
|
||||||
|
const AutoHashMap = std.AutoHashMap;
|
||||||
|
|
||||||
entities: ArrayList(Entity),
|
entities: ArrayList(Entity) = undefined,
|
||||||
|
tagged_entities: AutoHashMap(Tag.ID, *Entity) = undefined,
|
||||||
|
|
||||||
pub fn create() Scene {
|
pub fn create() Scene {
|
||||||
const e: ArrayList(Entity) = ArrayList(Entity).init(std.heap.page_allocator);
|
var self = Scene {};
|
||||||
return .{
|
self.entities = ArrayList(Entity).init(std.heap.page_allocator);
|
||||||
.entities = e
|
self.tagged_entities = AutoHashMap(Tag.ID, *Entity).init(std.heap.page_allocator);
|
||||||
};
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *Scene) void {
|
pub fn destroy(self: *Scene) void {
|
||||||
|
|
@ -26,11 +29,37 @@ pub fn destroy(self: *Scene) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(self: *Scene) !void {
|
pub fn start(self: *Scene) !void {
|
||||||
const terrain = try Terrain.create();
|
std.debug.print("[Scene:start] Scene starting...\n", .{});
|
||||||
try self.add(terrain);
|
std.debug.print("[Scene:start] entities: {}\n", .{ self.entities.items.len });
|
||||||
|
std.debug.print("[Scene:start] tagged entities: {}\n", .{ self.tagged_entities.count() });
|
||||||
|
for (self.entities.items) |entity| {
|
||||||
|
entity.start(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---
|
pub fn get(self: *const Scene, tag: Tag, comptime T: type) *T {
|
||||||
|
const tag_id = tag.id;
|
||||||
|
const entity_ptr: *Entity = self.tagged_entities.get(tag_id) orelse @panic("Could not find entity");
|
||||||
|
// @compileLog(entity_ptr);
|
||||||
|
const opaque_ptr = entity_ptr.ptr;
|
||||||
|
const real_ptr: *T = @ptrCast(@alignCast(opaque_ptr));
|
||||||
|
return real_ptr;
|
||||||
|
// var iterator = self.tagged_entities.iterator();
|
||||||
|
// while (iterator.next()) |entry| {
|
||||||
|
// const id_ptr: *Tag.ID = entry.key_ptr;
|
||||||
|
// const entity_ptr_ptr: **Entity = entry.value_ptr;
|
||||||
|
// const entity_ptr: *Entity = entity_ptr_ptr.*;
|
||||||
|
//
|
||||||
|
// const other_id = entity_ptr.tag.id;
|
||||||
|
// if (tag_id == other_id) {
|
||||||
|
// const opaque_ptr: *anyopaque = entity_ptr.ptr;
|
||||||
|
// const real_ptr: *T = @ptrCast(@alignCast(opaque_ptr));
|
||||||
|
// // @compileLog(r);
|
||||||
|
// return real_ptr;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// @panic("Could not find entity");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
||||||
const instance_ptr_type = @TypeOf(instance_ptr);
|
const instance_ptr_type = @TypeOf(instance_ptr);
|
||||||
|
|
@ -52,7 +81,14 @@ pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
||||||
if (!@hasDecl(instance_type, "entity"))
|
if (!@hasDecl(instance_type, "entity"))
|
||||||
@compileError("Pointer must be to a struct with fn entity() Entity");
|
@compileError("Pointer must be to a struct with fn entity() Entity");
|
||||||
|
|
||||||
try self.entities.append(instance_ptr.entity());
|
const entity: Entity = instance_ptr.entity();
|
||||||
|
|
||||||
|
const entity_ptr = try self.entities.addOne();
|
||||||
|
entity_ptr.* = entity;
|
||||||
|
|
||||||
|
if (entity_ptr.tag.id != Tag.NONE.id) {
|
||||||
|
try self.tagged_entities.put(entity.tag.id, entity_ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(self: *Scene, dt: f32) void {
|
pub fn update(self: *Scene, dt: f32) void {
|
||||||
|
|
@ -62,14 +98,18 @@ pub fn update(self: *Scene, dt: f32) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: *Scene) void {
|
pub fn draw(self: *Scene) void {
|
||||||
|
|
||||||
for (self.entities.items) |entity| {
|
for (self.entities.items) |entity| {
|
||||||
entity.draw();
|
entity.draw();
|
||||||
}
|
}
|
||||||
|
for (self.entities.items) |entity| {
|
||||||
|
entity.draw_opacity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assets.heart.draw(&Recti.from_xywh(120, 100, 32, 64), Layer.ENTITIES, Color.LIGHT_BLUE);
|
pub fn resize(self: *Scene, width: i32, height: i32) void {
|
||||||
assets.heart.draw(&Recti.from_xywh(100, 100, 32, 64), Layer.FLOOR, Color.WHITE);
|
for (self.entities.items) |entity| {
|
||||||
assets.heart.draw(&Recti.from_xywh(80, 100, 32, 64), Layer.ENTITIES, Color.INDIGO);
|
entity.resize(width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- helpfer functions for entities themselves
|
// --- helpfer functions for entities themselves
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ texture: *const Texture = undefined,
|
||||||
|
|
||||||
pub fn create(tex: *const Texture, rect: Recti) Sprite {
|
pub fn create(tex: *const Texture, rect: Recti) Sprite {
|
||||||
return .{
|
return .{
|
||||||
.texture_area = rect.scalef(Vec2f.new(
|
.texture_area = rect.scalef(Vec2f.create(
|
||||||
@floatFromInt(tex.width),
|
@floatFromInt(tex.width),
|
||||||
@floatFromInt(tex.height)
|
@floatFromInt(tex.height)
|
||||||
)),
|
)),
|
||||||
|
|
@ -24,7 +24,7 @@ pub fn create(tex: *const Texture, rect: Recti) Sprite {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: *const Sprite, screen_pos: *const Recti, layer: Layer, color: Color) void {
|
pub fn draw(self: *const Sprite, screen_pos: Recti, layer: Layer, color: Color) void {
|
||||||
self.texture.bind(c.GL_TEXTURE0);
|
self.texture.bind(c.GL_TEXTURE0);
|
||||||
c.glBegin(c.GL_QUADS);
|
c.glBegin(c.GL_QUADS);
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
const Tag = @This();
|
||||||
|
const std = @import("std");
|
||||||
|
pub const ID = *const anyopaque;
|
||||||
|
|
||||||
|
id: ID,
|
||||||
|
type: []const u8,
|
||||||
|
|
||||||
|
fn create_id_for_type(comptime T: type) ID {
|
||||||
|
// create a unique struct for each type this is called with.
|
||||||
|
const unique_struct = struct {
|
||||||
|
// this simply gives the struct a size, so the pointer is not
|
||||||
|
// optimized into oblivion.
|
||||||
|
var x: u8 = 0;
|
||||||
|
|
||||||
|
// capture the type so zig knows not to make this
|
||||||
|
// struct the same for each call. if the type isnt captured
|
||||||
|
// zig will create one struct in memory for each unique call.
|
||||||
|
// ie: the function will be unique, but this struct wont be.
|
||||||
|
comptime {
|
||||||
|
_ = T;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// @compileLog(T);
|
||||||
|
// @compileLog(&unique_struct.x);
|
||||||
|
|
||||||
|
// return the pointer to the only data within the struct,
|
||||||
|
// again so the compiler doesnt optimize this into non-existence.
|
||||||
|
return &unique_struct.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const NONE = Tag {
|
||||||
|
.type = "None",
|
||||||
|
.id = create_id_for_type(struct {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn create(comptime t: type) Tag {
|
||||||
|
// @compileLog(@typeName(t));
|
||||||
|
return Tag {
|
||||||
|
.type = @typeName(t),
|
||||||
|
.id = create_id_for_type(t),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn equals(self: *const Tag, other: Tag) bool {
|
||||||
|
return self.id == other.id;
|
||||||
|
}
|
||||||
199
src/Terrain.zig
199
src/Terrain.zig
|
|
@ -1,45 +1,206 @@
|
||||||
const Terrain = @This();
|
const Terrain = @This();
|
||||||
|
|
||||||
const assets = @import("assets.zig");
|
const assets = @import("assets.zig");
|
||||||
const Layer = @import("Layer.zig");
|
const Layer = @import("Layer.zig");
|
||||||
const Color = @import("Color.zig");
|
const Color = @import("Color.zig");
|
||||||
const Recti = @import("geometry/Recti.zig");
|
const Recti = @import("geometry/Recti.zig");
|
||||||
|
const Vec2f = @import("geometry/Vec2f.zig");
|
||||||
const Entity = @import("Entity.zig");
|
const Entity = @import("Entity.zig");
|
||||||
const Scene = @import("Scene.zig");
|
const Scene = @import("Scene.zig");
|
||||||
|
const Camera = @import("Camera.zig");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const allocator = std.heap.page_allocator;
|
||||||
var prng = std.rand.DefaultPrng.init(0);
|
var prng = std.rand.DefaultPrng.init(0);
|
||||||
|
const Noise = @import("Noise.zig");
|
||||||
|
|
||||||
size: u16 = 24,
|
const TAG = @import("Tag.zig").create(Terrain);
|
||||||
|
|
||||||
pub fn entity(self: *Terrain) Entity {
|
pub const CHUNK_SIZE = 48;
|
||||||
return Entity.init(self, .{});
|
const CHUNK_LENGTH = CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
|
||||||
|
const tile_size: usize = 16;
|
||||||
|
|
||||||
|
pub inline fn xy_to_index(x: i32, y: i32) i32 {
|
||||||
|
return x + y * CHUNK_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create() !*Terrain {
|
pub inline fn index_to_xy(index: i32) struct { i32, i32 } {
|
||||||
return try Scene.allocate(Terrain {
|
const y: i32 = @divFloor(index, CHUNK_SIZE);
|
||||||
.size = 24,
|
const x: i32 = @rem(index, CHUNK_SIZE);
|
||||||
|
return .{ x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
const GROWS = true;
|
||||||
|
const GROWTH_RATE: f32 = 0.5;
|
||||||
|
|
||||||
|
pub const Tile = struct {
|
||||||
|
texture_idx: usize,
|
||||||
|
growth: f32,
|
||||||
|
stone_decoration: f32,
|
||||||
|
grass_color: Color,
|
||||||
|
dirt_color: Color,
|
||||||
|
stone_color: Color,
|
||||||
|
|
||||||
|
pub const NULL = Tile {
|
||||||
|
.texture_idx = 0,
|
||||||
|
.growth = 0,
|
||||||
|
.stone_decoration = 0,
|
||||||
|
.grass_color = Color.WHITE,
|
||||||
|
.dirt_color = Color.WHITE,
|
||||||
|
.stone_color = Color.WHITE,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
tiles: []Tile = undefined,
|
||||||
|
|
||||||
|
// the noise for deciding random textures
|
||||||
|
texture_noise: Noise,
|
||||||
|
// noise for deciding grass growth
|
||||||
|
growth_noise: Noise,
|
||||||
|
// noise for stone decoration placement
|
||||||
|
stone_decoration_noise: Noise.Custom,
|
||||||
|
// noise for colors
|
||||||
|
dirt_color_noise: Noise.Color,
|
||||||
|
grass_color_noise: Noise.Color,
|
||||||
|
stone_color_noise: Noise.Color,
|
||||||
|
|
||||||
|
|
||||||
|
camera: *Camera = undefined,
|
||||||
|
|
||||||
|
pub fn entity(self: *Terrain) Entity {
|
||||||
|
return Entity.init(self, .{
|
||||||
|
.tag = TAG,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start(self: *Terrain, scene: *Scene) void {
|
||||||
|
self.camera = scene.get(Camera.TAG, Camera);
|
||||||
|
self.camera.set_focus(Vec2f.create(CHUNK_SIZE / 2, CHUNK_SIZE / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contrast(n: f32, blend_strength: f32) f32 {
|
||||||
|
const pi_halves = std.math.pi / 2.0;
|
||||||
|
const two_piths = 2.0 / std.math.pi;
|
||||||
|
const true_blend = std.math.pow(f32, 1.2, blend_strength) - 1;
|
||||||
|
const numerator_qty = pi_halves * (2 * n - 1) * true_blend;
|
||||||
|
const numerator = two_piths * std.math.atan(numerator_qty);
|
||||||
|
const denominator = two_piths * std.math.atan(pi_halves * true_blend);
|
||||||
|
const unadjusted_total = numerator / denominator;
|
||||||
|
// const adjusted_total = (unadjusted_total + 1.0) / 2.0;
|
||||||
|
return (unadjusted_total + 1.0) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_tiles(self: *Terrain) void {
|
||||||
|
for(0..CHUNK_LENGTH) |idx| {
|
||||||
|
const x, const y = index_to_xy(@intCast(idx));
|
||||||
|
const fx: f32 = @floatFromInt(x);
|
||||||
|
const fy: f32 = @floatFromInt(y);
|
||||||
|
const texture_random = self.texture_noise.get(fx, fy);
|
||||||
|
self.tiles[idx] = Tile {
|
||||||
|
.texture_idx = @intFromFloat(@floor(texture_random * 4)),
|
||||||
|
.growth = contrast(self.growth_noise.get(fx, fy), 10),
|
||||||
|
.stone_decoration = self.stone_decoration_noise.get(fx, fy),
|
||||||
|
.dirt_color = self.dirt_color_noise.get(fx, fy),
|
||||||
|
.grass_color = self.grass_color_noise.get(fx, fy),
|
||||||
|
.stone_color = self.stone_color_noise.get(fx, fy),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(seed: i64) !*Terrain {
|
||||||
|
var self: *Terrain = try Scene.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),
|
||||||
|
.stone_decoration_noise = try Noise.Custom.create(seed + 2, 1, &.{
|
||||||
|
.{ .frequency = 0.03, .amplitude = 1 },
|
||||||
|
.{ .frequency = 1, .amplitude = 1 }
|
||||||
|
}),
|
||||||
|
.dirt_color_noise = try Noise.Color.create(seed + 3, Noise.ColorRange.DIRT),
|
||||||
|
.grass_color_noise = try Noise.Color.create(seed + 4, Noise.ColorRange.GRASS),
|
||||||
|
.stone_color_noise = try Noise.Color.create(seed + 5, Noise.ColorRange.STONE)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.generate_tiles();
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *const Terrain) void {
|
pub fn destroy(self: *const Terrain) void {
|
||||||
|
self.texture_noise.destroy();
|
||||||
|
self.growth_noise.destroy();
|
||||||
|
self.stone_decoration_noise.destroy();
|
||||||
|
|
||||||
|
self.dirt_color_noise.destroy();
|
||||||
|
self.grass_color_noise.destroy();
|
||||||
|
self.stone_color_noise.destroy();
|
||||||
|
|
||||||
|
Entity.free_array(self.tiles);
|
||||||
Scene.deallocate(self);
|
Scene.deallocate(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(self: *Terrain, _: f32) void {
|
fn chance(percent: f32) bool {
|
||||||
if (prng.random().int(u8) == 34) {
|
return prng.random().float(f32) < percent;
|
||||||
self.size = self.size + 1;
|
}
|
||||||
|
|
||||||
|
fn grow(self: *Terrain, x: i32, y: i32, amt: f32) void {
|
||||||
|
if (x < 0 or x >= CHUNK_SIZE) return;
|
||||||
|
if (y < 0 or y >= CHUNK_SIZE) return;
|
||||||
|
const idx: usize = @intCast(xy_to_index(x, y));
|
||||||
|
const tile = &self.tiles[idx];
|
||||||
|
// @compileLog(tile);
|
||||||
|
tile.*.growth = @min(@max(tile.growth + amt, 0), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Terrain, dt: f32) void {
|
||||||
|
if (GROWS) {
|
||||||
|
for (0..CHUNK_LENGTH) |idx| {
|
||||||
|
const x, const y = index_to_xy(@intCast(idx));
|
||||||
|
const tile = self.tiles[idx];
|
||||||
|
const should_grow = chance(dt * GROWTH_RATE) and chance(tile.growth);
|
||||||
|
if (should_grow) {
|
||||||
|
self.grow(x, y, 0.010);
|
||||||
|
|
||||||
|
self.grow(x + 1, y, 0.008);
|
||||||
|
self.grow(x - 1, y, 0.008);
|
||||||
|
self.grow(x, y + 1, 0.008);
|
||||||
|
self.grow(x, y - 1, 0.008);
|
||||||
|
|
||||||
|
self.grow(x + 1, y + 1, 0.004);
|
||||||
|
self.grow(x + 1, y - 1, 0.004);
|
||||||
|
self.grow(x - 1, y + 1, 0.004);
|
||||||
|
self.grow(x - 1, y - 1, 0.004);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: *const Terrain) void {
|
pub fn draw(self: *const Terrain) void {
|
||||||
for(0..self.size) |y| {
|
for(0..CHUNK_LENGTH) |idx| {
|
||||||
for(0..self.size) |x| {
|
const tile = self.tiles[idx];
|
||||||
const idx: usize = @intFromFloat(@floor(prng.random().float(f32) * 4));
|
const x, const y = index_to_xy(@intCast(idx));
|
||||||
var grey = prng.random().float(f32);
|
const rect = Recti.from_xywh(x, y, 1, 1);
|
||||||
grey /= 4.0;
|
const sprite = assets.terrain[0][tile.texture_idx];
|
||||||
grey += 3.0 / 4.0;
|
self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, tile.grass_color);
|
||||||
const rect = Recti.from_xywh(@intCast(100 + 16 * x), @intCast(100 + 16 * y), 16, 16);
|
// switch(tile.texture_idx) {
|
||||||
assets.terrain[idx].draw(&rect, Layer.FLOOR, Color.rgba(grey, grey, grey, 1));
|
// 0 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.WHITE),
|
||||||
}
|
// 1 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.RED),
|
||||||
|
// 2 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.GREEN),
|
||||||
|
// 3 => self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, Color.BLUE),
|
||||||
|
// else => {}
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn draw_opacity(self: *const Terrain) void {
|
||||||
|
// for(0..CHUNK_LENGTH) |idx| {
|
||||||
|
// const tile = self.tiles[idx];
|
||||||
|
// const x, const y = index_to_xy(@intCast(idx));
|
||||||
|
// // const grassiness_max: f32 = @floatFromInt(assets.terrain.len + 1);
|
||||||
|
// // const grassiness: usize = @intFromFloat(@floor(tile.growth * grassiness_max));
|
||||||
|
// // if (grassiness == 0) continue;
|
||||||
|
// // const grassiness_idx = assets.terrain.len - @min(4, grassiness);
|
||||||
|
// const rect = Recti.from_xywh(x, y, 1, 1);
|
||||||
|
// const sprite = assets.terrain[0][tile.texture_idx];
|
||||||
|
// const color = tile.grass_color.with_opacity(tile.growth);
|
||||||
|
// self.camera.draw_sprite_i(sprite, rect, Layer.FLOOR, color);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ pub fn create(path: []const u8) !Texture {
|
||||||
c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_RGBA, @intCast(ihdr.width), @intCast(ihdr.height), 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, @ptrCast(out_buf));
|
c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_RGBA, @intCast(ihdr.width), @intCast(ihdr.height), 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, @ptrCast(out_buf));
|
||||||
c.glBindTexture(c.GL_TEXTURE_2D, 0);
|
c.glBindTexture(c.GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
std.debug.print("texture generated: ID={} Path={s}\n", .{ tex_id, path });
|
std.debug.print("[Texture:create] texture generated: ID={} Path={s}\n", .{ tex_id, path });
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.handle = @intCast(tex_id),
|
.handle = @intCast(tex_id),
|
||||||
|
|
|
||||||
|
|
@ -6,27 +6,77 @@ const std = @import("std");
|
||||||
const Assets = struct {
|
const Assets = struct {
|
||||||
tree: Sprite,
|
tree: Sprite,
|
||||||
heart: Sprite,
|
heart: Sprite,
|
||||||
terrain: [4]Sprite,
|
pawn: Sprite,
|
||||||
|
terrain: [4][4]Sprite,
|
||||||
|
rocks: [4]Sprite,
|
||||||
};
|
};
|
||||||
|
|
||||||
var assets: Assets = undefined;
|
var assets: Assets = undefined;
|
||||||
var texture: Texture = undefined;
|
var texture: Texture = undefined;
|
||||||
|
|
||||||
|
inline fn make8 (x: i32, y: i32, w: i32, h: i32) Sprite {
|
||||||
|
return Sprite.create(&texture, Recti.from_xywh(x * 8, y * 8, w * 8, h * 8));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load() !void {
|
pub fn load() !void {
|
||||||
|
|
||||||
|
// @compileLog(@TypeOf(terrain));
|
||||||
|
|
||||||
texture = try Texture.create("textures.png");
|
texture = try Texture.create("textures.png");
|
||||||
|
|
||||||
assets = .{
|
assets = .{
|
||||||
.tree = Sprite.create(&texture, Recti.from_xywh(8*27, 8*4, 8, 16)),
|
.tree = make8(27, 4, 1, 2),
|
||||||
.heart = Sprite.create(&texture, Recti.from_xywh(8*27, 8*4, 8, 16)),
|
.heart = make8(27, 4, 1, 2),
|
||||||
.terrain = [_]Sprite {
|
.pawn = make8(6, 11, 1, 1),
|
||||||
Sprite.create(&texture, Recti.from_xywh(8*3, 8*8, 8, 8)),
|
.terrain = [4][4]Sprite {
|
||||||
Sprite.create(&texture, Recti.from_xywh(8*3, 8*9, 8, 8)),
|
[4]Sprite { make8(18, 8, 1, 1), make8(19, 8, 1, 1), make8(18, 9, 1, 1), make8(19, 9, 1, 1) },
|
||||||
Sprite.create(&texture, Recti.from_xywh(8*4, 8*8, 8, 8)),
|
[4]Sprite { make8(20, 8, 1, 1), make8(21, 8, 1, 1), make8(20, 9, 1, 1), make8(21, 9, 1, 1) },
|
||||||
Sprite.create(&texture, Recti.from_xywh(8*4, 8*9, 8, 8)),
|
[4]Sprite { make8(18, 10, 1, 1), make8(19, 10, 1, 1), make8(18, 11, 1, 1), make8(19, 11, 1, 1) },
|
||||||
|
[4]Sprite { make8(20, 10, 1, 1), make8(21, 10, 1, 1), make8(20, 11, 1, 1), make8(21, 11, 1, 1) },
|
||||||
|
},
|
||||||
|
.rocks = [4]Sprite {
|
||||||
|
make8(18, 12, 1, 1), make8(19, 12, 1, 1), make8(20, 12, 1, 1), make8(21, 12, 1, 1)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_pointers(comptime array_ptr: anytype)
|
||||||
|
[@typeInfo(@typeInfo(@TypeOf(array_ptr)).Pointer.child).Array.len]
|
||||||
|
*const @typeInfo(@typeInfo(@TypeOf(array_ptr)).Pointer.child).Array.child
|
||||||
|
{
|
||||||
|
const len = @typeInfo(@typeInfo(@TypeOf(array_ptr)).Pointer.child).Array.len;
|
||||||
|
const item_type = @typeInfo(@typeInfo(@TypeOf(array_ptr)).Pointer.child).Array.child;
|
||||||
|
|
||||||
|
comptime var ptr_array: [len]*const item_type = undefined;
|
||||||
|
comptime for (0..len) |idx| {
|
||||||
|
ptr_array[idx] = &(array_ptr.*[idx]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return ptr_array;
|
||||||
|
}
|
||||||
|
|
||||||
pub const tree: *const Sprite = &assets.tree;
|
pub const tree: *const Sprite = &assets.tree;
|
||||||
pub const heart: *const Sprite = &assets.heart;
|
pub const heart: *const Sprite = &assets.heart;
|
||||||
pub const terrain:[]const Sprite = &assets.terrain;
|
pub const pawn: *const Sprite = &assets.pawn;
|
||||||
|
pub const terrain = [4]*const [4]*const Sprite {
|
||||||
|
&make_pointers(&assets.terrain[0]),
|
||||||
|
&make_pointers(&assets.terrain[1]),
|
||||||
|
&make_pointers(&assets.terrain[2]),
|
||||||
|
&make_pointers(&assets.terrain[3]),
|
||||||
|
};
|
||||||
|
pub const rocks: *const Sprite = make_pointers(&assets.rocks);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
const Matrix4f = @This();
|
const Matrix4f = @This();
|
||||||
|
|
||||||
values: [16]f32 = identity,
|
values: [16]f32,
|
||||||
|
|
||||||
const SIZE: i8 = 4 * 4;
|
const SIZE: i8 = 4 * 4;
|
||||||
const identity = from_values([16]f32 {
|
const identity = from_values([16]f32 {
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ pub fn from_xywh(x: f32, y: f32, w: f32, h: f32) Rectf {
|
||||||
.y = y,
|
.y = y,
|
||||||
.w = w,
|
.w = w,
|
||||||
.h = h,
|
.h = h,
|
||||||
.a = Vec2f.new(x, y),
|
.a = Vec2f.create(x, y),
|
||||||
.b = Vec2f.new(x + w, y + h),
|
.b = Vec2f.create(x + w, y + h),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
const Vec2i = @import("./Vec2i.zig");
|
const Vec2i = @import("./Vec2i.zig");
|
||||||
const Vec2f = @import("./Vec2f.zig");
|
const Vec2f = @import("./Vec2f.zig");
|
||||||
const Rectf = @import("./Rectf.zig");
|
const Rectf = @import("./Rectf.zig");
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
const Recti = @This();
|
const Recti = @This();
|
||||||
|
|
||||||
|
|
@ -17,8 +18,25 @@ pub fn from_xywh(x: i32, y: i32, w: i32, h: i32) Recti {
|
||||||
.y = y,
|
.y = y,
|
||||||
.w = w,
|
.w = w,
|
||||||
.h = h,
|
.h = h,
|
||||||
.a = Vec2i.new(x, y),
|
.a = Vec2i.create(x, y),
|
||||||
.b = Vec2i.new(x + w, y + h),
|
.b = Vec2i.create(x + w, y + h),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_ab(a: Vec2i, b: Vec2i) Recti {
|
||||||
|
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 = Vec2i.create(tlx, tly),
|
||||||
|
.b = Vec2i.create(brx, bry),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@ const Vec2f = @This();
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
|
|
||||||
pub fn new(x: f32, y: f32) Vec2f {
|
pub fn create(x: f32, y: f32) Vec2f {
|
||||||
return .{
|
return .{
|
||||||
.x = x,
|
.x = x,
|
||||||
.y = y,
|
.y = y,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ZERO = new(0, 0);
|
pub const ZERO = create(0, 0);
|
||||||
pub const ONE = new(1, 1);
|
pub const ONE = create(1, 1);
|
||||||
pub const NORTH = new(0, -1);
|
pub const NORTH = create(0, -1);
|
||||||
pub const SOUTH = new(0, 1);
|
pub const SOUTH = create(0, 1);
|
||||||
pub const EAST = new(1, 0);
|
pub const EAST = create(1, 0);
|
||||||
pub const WEST = new(-1, 0);
|
pub const WEST = create(-1, 0);
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,31 @@
|
||||||
const Vec2i = @This();
|
const Vec2i = @This();
|
||||||
|
|
||||||
|
const Recti = @import("Recti.zig");
|
||||||
|
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
|
|
||||||
pub fn new(x: i32, y: i32) Vec2i {
|
pub fn create(x: i32, y: i32) Vec2i {
|
||||||
return .{
|
return .{
|
||||||
.x = x,
|
.x = x,
|
||||||
.y = y,
|
.y = y,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ZERO = new(0, 0);
|
pub fn scale(self: *const Vec2i, s: i32) Vec2i {
|
||||||
pub const ONE = new(1, 1);
|
return .{
|
||||||
pub const NORTH = new(0, -1);
|
.x = self.x * s,
|
||||||
pub const SOUTH = new(0, 1);
|
.y = self.y * s
|
||||||
pub const EAST = new(1, 0);
|
};
|
||||||
pub const WEST = new(-1, 0);
|
}
|
||||||
|
|
||||||
|
pub fn to_unit_recti(self: *const Vec2i) Recti {
|
||||||
|
return Recti.from_xywh(self.x, self.y, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ZERO = create(0, 0);
|
||||||
|
pub const ONE = create(1, 1);
|
||||||
|
pub const NORTH = create(0, -1);
|
||||||
|
pub const SOUTH = create(0, 1);
|
||||||
|
pub const EAST = create(1, 0);
|
||||||
|
pub const WEST = create(-1, 0);
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
const Scene = @import("Scene.zig");
|
const Scene = @import("Scene.zig");
|
||||||
const Terrain = @import("Terrain.zig");
|
const Terrain = @import("Terrain.zig");
|
||||||
|
const Pawn = @import("Pawn.zig");
|
||||||
|
const Camera = @import("Camera.zig");
|
||||||
|
|
||||||
|
|
||||||
pub fn game() !Scene {
|
pub fn game() !Scene {
|
||||||
var scene = Scene.create();
|
var scene = Scene.create();
|
||||||
// first try is for allocating more memory in entities
|
// first try is for allocating more memory in entities
|
||||||
// second try is for allocating terrain on the heap...
|
// second try is for allocating terrain on the heap...
|
||||||
try scene.add(try Terrain.create());
|
try scene.add(try Camera.create());
|
||||||
|
try scene.add(try Terrain.create(123));
|
||||||
|
try scene.add(try Pawn.random());
|
||||||
|
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ pub const POSITION_ATTRIBUTE_ID = 0;
|
||||||
pub const COLOR_ATTRIBUTE_ID = 1;
|
pub const COLOR_ATTRIBUTE_ID = 1;
|
||||||
pub const TEXCOORD_ATTRIBUTE_ID = 2;
|
pub const TEXCOORD_ATTRIBUTE_ID = 2;
|
||||||
|
|
||||||
|
|
||||||
var flat: Shader = undefined;
|
var flat: Shader = undefined;
|
||||||
var active_shader: *const Shader = undefined;
|
var active_shader: *const Shader = undefined;
|
||||||
|
|
||||||
|
|
@ -67,6 +66,7 @@ pub fn load() !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_projection_matrix(matrix: *const Matrix4f) void {
|
pub fn set_projection_matrix(matrix: *const Matrix4f) void {
|
||||||
|
// std.debug.print("[shaders:set_projection_matrix] {}: {}\n", .{ active_shader, matrix });
|
||||||
active_shader.set_projection_matrix(matrix);
|
active_shader.set_projection_matrix(matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,7 +78,6 @@ const Shader = struct {
|
||||||
const Error = error {
|
const Error = error {
|
||||||
CompilationFailed
|
CompilationFailed
|
||||||
};
|
};
|
||||||
// cache: HashMap<*const u8, i32> = undefined,
|
|
||||||
|
|
||||||
fn enable(self: *const Shader) void {
|
fn enable(self: *const Shader) void {
|
||||||
c.glUseProgram(self.program_handle);
|
c.glUseProgram(self.program_handle);
|
||||||
|
|
@ -88,18 +87,18 @@ const Shader = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(vert_shader_text: []const u8, frag_shader_text: []const u8) !Shader {
|
fn compile(vert_shader_text: []const u8, frag_shader_text: []const u8) !Shader {
|
||||||
const vertex_shader: c.GLuint= c.glCreateShader(c.GL_VERTEX_SHADER);
|
const vertex_shader: c.GLuint = c.glCreateShader(c.GL_VERTEX_SHADER);
|
||||||
{
|
{
|
||||||
c.glShaderSource(vertex_shader, 1, @ptrCast(&vert_shader_text), null);
|
c.glShaderSource(vertex_shader, 1, @ptrCast(&vert_shader_text), null);
|
||||||
c.glCompileShader(vertex_shader);
|
c.glCompileShader(vertex_shader);
|
||||||
var compile_status: c.GLint = undefined;
|
var compile_status: c.GLint = undefined;
|
||||||
c.glGetShaderiv(vertex_shader, c.GL_COMPILE_STATUS, &compile_status);
|
c.glGetShaderiv(vertex_shader, c.GL_COMPILE_STATUS, &compile_status);
|
||||||
if (compile_status != c.GL_TRUE) {
|
if (compile_status != c.GL_TRUE) {
|
||||||
std.log.err("Vertex shader compilation failed!", .{});
|
std.log.err("[shaders:compile] Vertex shader compilation failed!", .{});
|
||||||
var error_text: [1000]u8 = undefined;
|
var error_text: [1000]u8 = undefined;
|
||||||
var len: i32 = undefined;
|
var len: i32 = undefined;
|
||||||
c.glGetShaderInfoLog(vertex_shader, 1000, &len, &error_text);
|
c.glGetShaderInfoLog(vertex_shader, 1000, &len, &error_text);
|
||||||
std.debug.print("{s}\n", .{ error_text[0..@intCast(len)] });
|
std.log.err("{s}\n", .{ error_text[0..@intCast(len)] });
|
||||||
return Shader.Error.CompilationFailed;
|
return Shader.Error.CompilationFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +110,7 @@ const Shader = struct {
|
||||||
var compile_status: c.GLint = undefined;
|
var compile_status: c.GLint = undefined;
|
||||||
c.glGetShaderiv(fragment_shader, c.GL_COMPILE_STATUS, &compile_status);
|
c.glGetShaderiv(fragment_shader, c.GL_COMPILE_STATUS, &compile_status);
|
||||||
if (compile_status != c.GL_TRUE) {
|
if (compile_status != c.GL_TRUE) {
|
||||||
std.log.err("Fragment shader compilation failed!", .{});
|
std.log.err("[shaders:compile] Fragment shader compilation failed!", .{});
|
||||||
var error_text: [1000]u8 = undefined;
|
var error_text: [1000]u8 = undefined;
|
||||||
var len: i32 = undefined;
|
var len: i32 = undefined;
|
||||||
c.glGetShaderInfoLog(fragment_shader, 1000, &len, &error_text);
|
c.glGetShaderInfoLog(fragment_shader, 1000, &len, &error_text);
|
||||||
|
|
|
||||||
BIN
textures.png
BIN
textures.png
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 47 KiB |
Loading…
Reference in New Issue