lots of restructuring... LOTS.

stable
Ivory 2025-01-02 05:28:40 -05:00
parent 8796331efa
commit 2f146a9a14
36 changed files with 580 additions and 8724 deletions

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

142
build.zig
View File

@ -1,121 +1,65 @@
const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
// const GL_TYPE = enum([]const u8) {
// COMPAT = "compat",
// CORE = "core",
// };
//
// const GL_VERSION = enum([]const u8) {
// GL33 = "3.3",
// GL46 = "4.6",
// };
const glad_folder = "glad-4.6-compat";
pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
// const lib = b.addStaticLibrary(.{
// .name = "test-game",
// // In this case the main source file is merely a path, however, in more
// // complicated build scripts, this could be a generated file.
// .root_source_file = b.path("src/root.zig"),
// .target = target,
// .optimize = optimize,
// });
//
// // This declares intent for the library to be installed into the standard
// // location when the user invokes the "install" step (the default step when
// // running `zig build`).
// b.installArtifact(lib);
const exe = b.addExecutable(.{
.name = "test-game",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
exe.addCSourceFile(.{
.file = b.path(glad_folder ++ "/src/glad.c")
const c = b.addModule("c", .{
.root_source_file = b.path("src/c.zig"),
.target = target,
.optimize = optimize,
});
exe.addIncludePath(b.path(glad_folder ++ "/include"));
// c.addLibraryPath(b.path("/usr/local/lib"));
c.linkSystemLibrary("SDL3", .{});
c.addIncludePath(b.path("open-simplex/include"));
c.linkSystemLibrary("SDL3_image", .{});
exe.addCSourceFile(.{
.file = b.path("open-simplex/src/OpenSimplex2F.c")
const engine = b.addModule("engine", .{
.root_source_file = b.path("src/engine/root.zig"),
.target = target,
.optimize = optimize,
});
engine.addImport("engine", engine);
engine.addImport("c", c);
const exe = b.addExecutable(.{
.name = "hadean",
.root_source_file = b.path("src/hadean/main.zig"),
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("engine", engine);
exe.root_module.addImport("c", c);
exe.addCSourceFile(.{ .file = b.path("open-simplex/src/OpenSimplex2F.c") });
exe.addIncludePath(b.path("open-simplex/include"));
exe.linkLibC();
exe.linkSystemLibrary("glfw");
exe.linkSystemLibrary("GL");
exe.linkSystemLibrary("z");
exe.linkSystemLibrary("spng");
exe.root_module.addRPathSpecial("$ORIGIN/../lib");
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
b.installArtifact(exe);
b.getInstallStep().dependOn(&(b.addInstallFile(.{
.cwd_relative = "/usr/local/lib/libSDL3.so.0.1.7"
}, "lib/libSDL3.so.0")).step);
b.getInstallStep().dependOn(&(b.addInstallFile(.{
.cwd_relative = "/usr/local/lib/libSDL3_image.so.0.1.0"
}, "lib/libSDL3_image.so.0")).step);
b.getInstallStep().dependOn(&(b.addInstallFile(
b.path("assets/textures.png"),
"assets/textures.png"
)).step);
// This *creates* a Run step in the build graph, to be executed when another
// step is evaluated that depends on it. The next line below will establish
// such a dependency.
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
// By making the run step depend on the install step, it will be run from the
// installation directory rather than directly from within the cache directory.
// This is not necessary, however, if the application depends on other installed
// files, this ensures they will be present and in the expected location.
run_cmd.step.dependOn(b.getInstallStep());
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
// This will evaluate the `run` step rather than the default, which is "install".
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// // Creates a step for unit testing. This only builds the test executable
// // but does not run it.
// const lib_unit_tests = b.addTest(.{
// .root_source_file = b.path("src/root.zig"),
// .target = target,
// .optimize = optimize,
// });
//
// const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
// const exe_unit_tests = b.addTest(.{
// .root_source_file = b.path("src/main.zig"),
// .target = target,
// .optimize = optimize,
// });
// const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
// Similar to creating the run step earlier, this exposes a `test` step to
// the `zig build --help` menu, providing a way for the user to request
// running the unit tests.
// const test_step = b.step("test", "Run unit tests");
// test_step.dependOn(&run_lib_unit_tests.step);
// test_step.dependOn(&run_exe_unit_tests.step);
// because engine and hadean are diff modules their c modules
// get different caches, causing opaques to be different between them.
// kinda makes sense, because zig is namespacy and c is not!
// it would be nice to in some way ensure both got the same version, though.
}

View File

@ -1,311 +0,0 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,186 +0,0 @@
const std = @import("std");
const Recti = @import("geometry/Recti.zig");
const Matrix4f = @import("geometry/Matrix4f.zig");
const shaders = @import("shaders.zig");
const Texture = @import("Texture.zig");
const Sprite = @import("Sprite.zig");
const Layer = @import("Layer.zig");
const Color = @import("Color.zig");
const Scene = @import("Scene.zig");
const assets = @import("assets.zig");
const Vec2i = @import("geometry/Vec2i.zig");
const c = @cImport({
@cInclude("glad/glad.h");
@cInclude("GLFW/glfw3.h");
});
const AutoHashMap = std.AutoHashMap;
const Error = error {
WindowNotInitialized,
WindowAlreadyInitialized,
NoScene,
AlreadyRunning
};
pub const Debug = struct {
pub var CAMERA = true;
};
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;
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 {
const desc: *const u8 = @ptrCast(desc_c);
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", .{ 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 glfw_on_mouse_move(_: ?*c.GLFWwindow, fx: f64, fy: f64) callconv(.C) void {
const x: i32 = @intFromFloat(fx);
const y: i32 = @intFromFloat(fy);
mouse_pos = Vec2i { .x = x, .y = y };
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;
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 } {
var width: c_int = undefined;
var height: c_int = undefined;
c.glfwGetFramebufferSize(window, @ptrCast(&width), @ptrCast(&height));
return .{ width, height };
}
pub fn setup() !void {
if (window != null) return Error.WindowAlreadyInitialized;
// in case of errors, set callback early!
// for some reason this returns an error function as well??
_ = c.glfwSetErrorCallback(glfw_on_error);
// initialize glfw capabilities & cleanup
if (c.glfwInit() != 1) {
std.log.err("Failed to init glfw", .{});
return error.Initialization;
}
// ensure glfw knows what we're about
// c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 3);
c.glfwDefaultWindowHints();
c.glfwWindowHint(c.GLFW_SAMPLES, 4);
// c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 3);
// c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE);
// create the window & cleanup
window = c.glfwCreateWindow(1920, 1080, "Hadean, maybe", null, null) orelse {
std.log.err("Failed to open window", .{});
return error.Initialization;
};
// load opengl into the window
c.glfwMakeContextCurrent(window);
if (c.gladLoadGL() != 1) {
std.log.err("Failed to load GL context", .{});
return error.Initialization;
}
// configure the context!
c.glfwSwapInterval(1);
// compile shaders...
try shaders.load();
try assets.load();
_ = c.glfwSetWindowSizeCallback(window, glfw_on_resize);
_ = c.glfwSetCursorPosCallback(window, glfw_on_mouse_move);
_ = c.glfwSetCursorEnterCallback(window, glfw_on_mouse_enter);
_ = c.glfwSetMouseButtonCallback(window, glfw_on_mouse_button);
const clearBrightness: f32 = 0.09;
c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0);
// c.glEnable(c.GL_MULTISAMPLE);
c.glDisable(c.GL_MULTISAMPLE);
c.glEnable(c.GL_BLEND);
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
c.glEnable(c.GL_DEPTH_TEST);
c.glDepthFunc(c.GL_LEQUAL);
c.glDepthMask(c.GL_TRUE);
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);
}
pub fn destroy() void {
c.glfwDestroyWindow(window);
c.glfwTerminate();
}
pub fn set_scene(scene: Scene) void {
next_scene = scene;
}
pub fn run() !void {
if (window == null) return Error.WindowNotInitialized;
if (current_scene != null) return Error.AlreadyRunning;
if (next_scene == null) return Error.NoScene;
// run the main loop
while (c.glfwWindowShouldClose(window) == 0) {
// switch scenes if need be
if (next_scene != null) {
if (current_scene != null) current_scene.?.destroy();
current_scene = next_scene;
next_scene = null;
// start our scene
try current_scene.?.start();
// and send it the appropriate resize.
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);
current_scene.?.draw();
c.glFlush();
c.glfwSwapBuffers(window);
c.glfwPollEvents();
current_scene.?.update(0.0042);
}
}

View File

@ -1,46 +0,0 @@
const Rectf = @import("geometry/Rectf.zig");
const Recti = @import("geometry/Recti.zig");
const Vec2f = @import("geometry/Vec2f.zig");
const Color = @import("Color.zig");
const Texture = @import("Texture.zig");
const Layer = @import("Layer.zig");
const shaders = @import("shaders.zig");
const c = @cImport({
@cInclude("glad/glad.h");
@cInclude("GLFW/glfw3.h");
});
const Sprite = @This();
texture_area: Rectf = undefined,
texture: *const Texture = undefined,
pub fn create(tex: *const Texture, rect: Recti) Sprite {
return .{
.texture_area = rect.scalef(Vec2f.create(
@floatFromInt(tex.width),
@floatFromInt(tex.height)
)),
.texture = tex,
};
}
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);
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
c.glVertex3i(screen_pos.a.x, screen_pos.a.y, layer.z_index);
c.glVertexAttrib2f(shaders.TEXCOORD_ATTRIBUTE_ID, self.texture_area.b.x, self.texture_area.a.y);
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
c.glVertex3i(screen_pos.b.x, screen_pos.a.y, layer.z_index);
c.glVertexAttrib2f(shaders.TEXCOORD_ATTRIBUTE_ID, self.texture_area.b.x, self.texture_area.b.y);
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
c.glVertex3i(screen_pos.b.x, screen_pos.b.y, layer.z_index);
c.glVertexAttrib2f(shaders.TEXCOORD_ATTRIBUTE_ID, self.texture_area.a.x, self.texture_area.b.y);
c.glVertexAttrib4f(shaders.COLOR_ATTRIBUTE_ID, color.r, color.g, color.b, color.a);
c.glVertex3i(screen_pos.a.x, screen_pos.b.y, layer.z_index);
}
c.glEnd();
}

View File

@ -1,71 +0,0 @@
const c = @cImport({
// @cInclude("png.h");
@cInclude("spng.h");
// @cInclude("zlib.h");
// @cInclude("stdio.h");
@cInclude("glad/glad.h");
@cInclude("GLFW/glfw3.h");
});
const std = @import("std");
const File = std.fs.File;
const Dir = std.fs.Dir;
const heap = std.heap.page_allocator;
const Texture = @This();
const Error = error {
Fuck
};
handle: u32,
width: u32,
height: u32,
pub fn bind(self: *const Texture, unit: u32) void {
c.glActiveTexture(unit);
c.glBindTexture(c.GL_TEXTURE_2D, self.handle);
}
pub fn create(path: []const u8) !Texture {
var file = try std.fs.cwd().openFile(path, .{});
defer file.close();
const file_size = (try file.stat()).size;
const buffer: []u8 = try heap.alloc(u8, file_size);
defer heap.free(buffer);
const reader = file.reader();
_ = try reader.readAll(buffer);
const context = c.spng_ctx_new(0);
defer c.spng_ctx_free(context);
_ = c.spng_set_png_buffer(context, @ptrCast(buffer), buffer.len);
var out_size: usize = undefined;
_ = c.spng_decoded_image_size(context, c.SPNG_FMT_RGBA8, &out_size);
const out_buf: []u8 = try heap.alloc(u8, out_size);
defer heap.free(out_buf);
_ = c.spng_decode_image(context, @ptrCast(out_buf), out_size, c.SPNG_FMT_RGBA8, 0);
var ihdr = c.struct_spng_ihdr {};
_ = c.spng_get_ihdr(context, &ihdr);
var tex_id: u32 = undefined;
c.glGenTextures(1, &tex_id);
c.glBindTexture(c.GL_TEXTURE_2D, tex_id);
c.glActiveTexture(c.GL_TEXTURE0);
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST);
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST);
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);
std.debug.print("[Texture:create] texture generated: ID={} Path={s}\n", .{ tex_id, path });
return .{
.handle = @intCast(tex_id),
.width = ihdr.width,
.height = ihdr.height,
};
}

8
src/c.zig 100644
View File

@ -0,0 +1,8 @@
const c = @cImport({
@cInclude("SDL3/SDL.h");
@cInclude("SDL3_image/SDL_image.h");
@cInclude("OpenSimplex2F.h");
});
pub usingnamespace c;

View File

@ -0,0 +1,90 @@
const std = @import("std");
const Recti = @import("geometry/Recti.zig");
const Matrix4f = @import("geometry/Matrix4f.zig");
const Layer = @import("Layer.zig");
const Color = @import("Color.zig");
const Scene = @import("Scene.zig");
const Vec2i = @import("geometry/Vec2i.zig");
const c = @import("c");
const SDL_GetError = c.SDL_GetError;
const SDL_Log = c.SDL_Log;
const SDL_Init = c.SDL_Init;
const SDL_INIT_VIDEO = c.SDL_INIT_VIDEO;
const SDL_PollEvent = c.SDL_PollEvent;
const SDL_Event = c.SDL_Event;
const SDL_EVENT_QUIT = c.SDL_EVENT_QUIT;
const SDL_SetRenderDrawColor = c.SDL_SetRenderDrawColor;
const SDL_RenderClear = c.SDL_RenderClear;
const SDL_RenderPresent = c.SDL_RenderPresent;
const SDL_Quit = c.SDL_Quit;
pub const Error = error {
WindowNotInitialized,
WindowAlreadyInitialized,
RendererNotInitialized,
RendererAlreadyInitialized,
NoScene,
AlreadyRunning
};
var window: ?*c.SDL_Window = null;
var renderer: ?*c.SDL_Renderer = null;
var current_scene: ?Scene = null;
var next_scene: ?Scene = null;
var running: bool = false;
const LoaderFn = *const fn (*c.SDL_Window, *c.SDL_Renderer) void;
var loader: ?LoaderFn = null;
pub fn setup() !void {
if (window != null) return Error.WindowAlreadyInitialized;
if (renderer != null) return Error.RendererAlreadyInitialized;
if (!SDL_Init(SDL_INIT_VIDEO)) {
std.debug.panic("SDL failed to initialize with error: {s}", .{ SDL_GetError() });
}
if (!c.SDL_CreateWindowAndRenderer("SDL3", 800, 600, 0, &window, &renderer)) {
std.debug.panic("SDL failed to initialize window or renderer with error: {s}", .{ SDL_GetError() });
}
if (loader) |loader_fn| {
loader_fn(window.?, renderer.?);
}
}
pub fn set_loader(loader_fn: LoaderFn) void {
loader = loader_fn;
}
pub fn destroy() void {
SDL_Quit();
}
pub fn set_scene(scene: Scene) void {
next_scene = scene;
}
pub fn run() !void {
if (window == null) return Error.WindowNotInitialized;
if (renderer == null) return Error.RendererNotInitialized;
if (current_scene != null) return Error.AlreadyRunning;
if (next_scene == null) return Error.NoScene;
running = true;
var event: SDL_Event = undefined;
while (running) {
_ = c.SDL_SetRenderDrawColor(renderer, 127, 127, 127, 255);
_ = c.SDL_RenderClear(renderer);
_ = c.SDL_RenderPresent(renderer);
while(c.SDL_PollEvent(&event)) {
if (event.type == c.SDL_EVENT_QUIT) {
running = false;
}
}
}
}

View File

@ -1,13 +1,15 @@
const assets = @import("assets.zig");
const Layer = @import("Layer.zig");
const Color = @import("Color.zig");
const Recti = @import("geometry/Recti.zig");
const std = @import("std");
const Tag = @import("Tag.zig");
const Scene = @import("Scene.zig");
const Entity = @This();
const std = @import("std");
const engine = @import("engine");
const Tag = engine.Tag;
const Scene = engine.Scene;
const Recti = engine.geometry.Recti;
const Layer = engine.Layer;
const EntityOptions = struct {
tag: Tag = Tag.NONE,
};

View File

@ -0,0 +1,6 @@
const engine = @import("engine");
const Vec2i = engine.geometry.Vec2i;
pub var mouse_pos: ?Vec2i = Vec2i.create(0, 0);

View File

@ -0,0 +1,120 @@
const std = @import("std");
pub fn create(comptime functions: anytype) type {
const functions_typeinfo = @typeInfo(@TypeOf(functions));
if (functions_typeinfo != .Struct)
@compileError("Interface must be an anonymous struct type");
for (functions_typeinfo.Struct.fields) |field| {
const function_type = @field(functions, field.name);
if (@typeInfo(function_type) != .Fn) {
@compileError("Interface must only have Fn fields.");
}
}
const VTable = comptime blk: {
var fields: [functions_typeinfo.Struct.fields.len]std.builtin.Type.StructField = undefined;
for (functions_typeinfo.Struct.fields, 0..) |field, idx| {
const passed_function_type = @field(functions, field.name);
const passed_function_typeinfo = @typeInfo(passed_function_type);
const function_typeinfo: std.builtin.Type = .{
.Fn = .{
.params = &[_]std.builtin.Type.Fn.Param {
std.builtin.Type.Fn.Param {
.type = *anyopaque,
.is_generic = false,
.is_noalias = false,
},
std.builtin.Type.Fn.Param {
.type = std.meta.ArgsTuple(passed_function_type),
.is_generic = false,
.is_noalias = false,
},
},
.is_var_args = passed_function_typeinfo.Fn.is_var_args,
.is_generic = passed_function_typeinfo.Fn.is_generic,
.return_type = passed_function_typeinfo.Fn.return_type,
.calling_convention = passed_function_typeinfo.Fn.calling_convention,
}
};
const VTFunction = @Type(function_typeinfo);
fields[idx] = std.builtin.Type.StructField{
.name = field.name,
.type = *const VTFunction,
.is_comptime = false,
.default_value = null,
.alignment = @alignOf(*const anyopaque),
};
}
const VTableType = @Type(.{
.Struct = .{
.layout = .auto,
.decls = &[0]std.builtin.Type.Declaration {},
.fields = &fields,
.is_tuple = false,
}
});
break :blk VTableType;
};
return struct {
const Self = @This();
const VTableEnum = std.meta.FieldEnum(VTable);
ptr: *anyopaque,
vtable: VTable = undefined,
pub fn call(
self: *Self,
comptime tag: VTableEnum,
args: std.meta.ArgsTuple(@field(functions, @tagName(tag)))
)
@typeInfo(@field(functions, @tagName(tag))).Fn.return_type.?
{
return @call(.auto, @field(self.vtable, @tagName(tag)), .{ self.ptr, args });
}
pub fn init(impl: anytype) Self {
const ImplPointer = @TypeOf(impl);
const impl_typeinfo = @typeInfo(ImplPointer);
if (impl_typeinfo != .Pointer)
@compileError("Cannot initialize interface for non-pointer type");
if (impl_typeinfo.Pointer.size != .One)
@compileError("Cannot initialize interface for multi-item pointer");
if (impl_typeinfo.Pointer.is_const)
@compileError("Cannot initialize interface for non-mutable pointer");
if (@typeInfo(impl_typeinfo.Pointer.child) != .Struct)
@compileError("Cannot initialize interface for pointer to non-struct");
const Impl = impl_typeinfo.Pointer.child;
const vtable = comptime blk: {
var vtable: VTable = undefined;
for (functions_typeinfo.Struct.fields) |field_type| {
const Args = std.meta.ArgsTuple(@field(functions, field_type.name));
const wrapper = struct {
pub fn invoke(ptr: *anyopaque, args: Args) @typeInfo(@field(functions, field_type.name)).Fn.return_type.? {
const self: ImplPointer = @ptrCast(@alignCast(ptr));
return @call(.auto, @field(Impl, field_type.name), .{ self } ++ args);
}
};
@field(vtable, field_type.name) = wrapper.invoke;
}
break :blk vtable;
};
const interface: Self = .{ .ptr = impl, .vtable = vtable };
return interface;
}
};
}

View File

@ -1,6 +1,4 @@
const c = @cImport({
@cInclude("OpenSimplex2F.h");
});
const c = @import("c");
const std = @import("std");
const ArrayList = std.ArrayList;
const RealColor = @import("Color.zig");

View File

@ -1,11 +1,10 @@
const Scene = @This();
const assets = @import("assets.zig");
const Recti = @import("geometry/Recti.zig");
const Layer = @import("Layer.zig");
const Color = @import("Color.zig");
const Entity = @import("Entity.zig");
const Terrain = @import("Terrain.zig");
const engine = @import("engine");
const Entity = engine.Entity;
const Vec2i = @import("geometry/Vec2i.zig");
const Tag = @import("Tag.zig");
const std = @import("std");

View File

@ -0,0 +1,28 @@
const Rectf = @import("geometry/Rectf.zig");
const Recti = @import("geometry/Recti.zig");
const Vec2f = @import("geometry/Vec2f.zig");
const Color = @import("Color.zig");
const Texture = @import("Texture.zig");
const Layer = @import("Layer.zig");
const Sprite = @This();
texture_area: Rectf = undefined,
texture: *const Texture = undefined,
pub fn create(tex: *const Texture, rect: Recti) Sprite {
return .{
.texture_area = rect.scalef(Vec2f.create(
@floatFromInt(tex.width),
@floatFromInt(tex.height)
)),
.texture = tex,
};
}
pub fn draw(self: *const Sprite, screen_pos: Recti, layer: Layer, color: Color) void {
_ = self;
_ = screen_pos;
_ = layer;
_ = color;
@panic("Not Implemented");
}

View File

@ -0,0 +1,54 @@
const Texture = @This();
const std = @import("std");
const c = @import("c");
var gpa = std.heap.GeneralPurposeAllocator(.{}) {};
// var gpa = Allocator {};
var alloc = gpa.allocator();
// var alloc: std.mem.Allocator = (std.heap.GeneralPurposeAllocator(.{}) {}).allocator();
var exe_dir: []const u8 = undefined;
var exe_dir_valid = false;
handle: *c.SDL_Texture,
width: u32,
height: u32,
fn ensure_lazy_dir() void {
if (!exe_dir_valid)
exe_dir = std.fs.selfExeDirPathAlloc(alloc)
catch @panic("Couldnt get directory of executable.");
}
pub fn create(renderer: *c.SDL_Renderer, path: []const u8) Texture {
ensure_lazy_dir();
// allocPrintZ includes null terminator! :D
const new_path: [:0]const u8 = std.fmt.allocPrintZ(alloc, "{s}/../assets/{s}", .{ exe_dir, path })
catch @panic("OOM");
defer alloc.free(new_path);
// std.debug.print("{s} length {}\n", .{ new_path, new_path.len });
const io: *c.SDL_IOStream = c.SDL_IOFromFile(new_path, "r") orelse {
std.debug.print("SDL Error: {s}\n", .{ c.SDL_GetError() });
@panic("Failed to create IO for Texture");
};
const surface: *c.SDL_Surface = c.IMG_LoadPNG_IO(io) orelse {
std.debug.print("SDL Error: {s}\n", .{ c.SDL_GetError() });
@panic("Failed to create Surface for Texture");
};
const texture = c.SDL_CreateTextureFromSurface(renderer, surface) orelse {
std.debug.print("SDL Error: {s}\n", .{ c.SDL_GetError() });
@panic("Failed to create Texture");
};
return .{
.handle = texture,
.width = @intCast(texture.*.w),
.height = @intCast(texture.*.h),
};
}
// *const fn (*const cimport.struct_SDL_Window, *const cimport.struct_SDL_Renderer) void
// *const fn (*const cimport.struct_SDL_Window, *const cimport.struct_SDL_Renderer) void

View File

@ -0,0 +1,84 @@
const std = @import("std");
const engine = @import("engine");
const Color = engine.Color;
const Layer = engine.Layer;
const Vec2i = engine.geometry.Vec2i;
const Vec2f = engine.geometry.Vec2f;
const Rectf = engine.geometry.Rectf;
const Recti = @This();
x: i32,
y: i32,
w: i32,
h: i32,
a: Vec2i,
b: Vec2i,
pub fn from_xywh(x: i32, y: i32, w: i32, h: i32) Recti {
return .{
.x = x,
.y = y,
.w = w,
.h = h,
.a = Vec2i.create(x, y),
.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),
};
}
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_ab(
self.a.to_vec2f(),
self.b.to_vec2f()
);
}
pub fn scalef(self: *const Recti, scale: Vec2f) Rectf {
return Rectf.from_xywh(
@as(f32, @floatFromInt(self.x)) / scale.x,
@as(f32, @floatFromInt(self.y)) / scale.y,
@as(f32, @floatFromInt(self.w)) / scale.x,
@as(f32, @floatFromInt(self.h)) / scale.y,
);
}
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 {
_ = self;
_ = layer;
_ = color;
}
pub fn draw_outline(self: *const Recti, layer: Layer, color: Color) void {
_ = self;
_ = layer;
_ = color;
}

View File

@ -2,12 +2,7 @@ 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,
y: f32,
@ -27,25 +22,10 @@ pub fn to_vec2i(self: *const Vec2f) Vec2i {
}
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();
_ = self;
_ = radius;
_ = layer;
_ = color;
}
pub const ZERO = create(0, 0);

View File

@ -4,12 +4,7 @@ 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,
y: i32,
@ -40,25 +35,10 @@ pub fn add(self: Vec2i, other: Vec2i) Vec2i {
}
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();
_ = self;
_ = radius;
_ = layer;
_ = color;
}
pub fn to_vec2f(self: *const Vec2i) Vec2f {

View File

@ -0,0 +1,8 @@
pub const Vec2f = @import("Vec2f.zig");
pub const Vec2i = @import("Vec2i.zig");
pub const Rectf = @import("Rectf.zig");
pub const Recti = @import("Recti.zig");
pub const Matrix4f = @import("Matrix4f.zig");

View File

@ -0,0 +1,18 @@
pub const Control = @import("Control.zig");
pub const Scene = @import("Scene.zig");
pub const Tag = @import("Tag.zig");
pub const Layer = @import("Layer.zig");
pub const Interface = @import("Interface.zig");
pub const Entity = @import("Entity.zig");
pub const Color = @import("Color.zig");
pub const Noise = @import("Noise.zig");
pub const Input = @import("Input.zig");
pub const Sprite = @import("Sprite.zig");
pub const Texture = @import("Texture.zig");
pub const geometry = @import("geometry/root.zig");
pub const Debug = struct {
pub const camera = false;
};

View File

@ -1,137 +0,0 @@
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();
x: i32,
y: i32,
w: i32,
h: i32,
a: Vec2i,
b: Vec2i,
pub fn from_xywh(x: i32, y: i32, w: i32, h: i32) Recti {
return .{
.x = x,
.y = y,
.w = w,
.h = h,
.a = Vec2i.create(x, y),
.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),
};
}
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_ab(
self.a.to_vec2f(),
self.b.to_vec2f()
);
}
pub fn scalef(self: *const Recti, scale: Vec2f) Rectf {
return Rectf.from_xywh(
@as(f32, @floatFromInt(self.x)) / scale.x,
@as(f32, @floatFromInt(self.y)) / scale.y,
@as(f32, @floatFromInt(self.w)) / scale.x,
@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();
}

View File

@ -1,22 +1,19 @@
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");
const Rectf = @import("geometry/Rectf.zig");
const shaders = @import("shaders.zig");
const c = @cImport({
@cInclude("glad/glad.h");
@cInclude("GLFW/glfw3.h");
});
const engine = @import("engine");
const Entity = engine.Entity;
const Scene = engine.Scene;
const Input = engine.Input;
const Sprite = engine.Sprite;
const Color = engine.Color;
const Layer = engine.Layer;
const Vec2i = engine.geometry.Vec2i;
const Vec2f = engine.geometry.Vec2f;
const Recti = engine.geometry.Recti;
const Rectf = engine.geometry.Rectf;
pub const TAG = engine.Tag.create(Camera);
// focus: Vec2i = Vec2i.EAST.scale(100),
focus: Vec2f = Vec2f.ZERO,
@ -28,33 +25,17 @@ 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();
_ = a;
_ = b;
_ = layer;
_ = color;
}
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();
_ = a;
_ = b;
_ = layer;
_ = color;
}
pub fn create() !*Camera {
@ -78,10 +59,10 @@ 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) {
if (self.drag_pos != null and self.drag_focus != null and Input.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.?);
const drag_current_world = self.screen_to_world_vec2i(Input.mouse_pos.?);
self.focus = Vec2f {
.x = self.drag_focus.?.x + (drag_start_world.x - drag_current_world.x),
@ -91,10 +72,10 @@ pub fn update(self: *Camera, _: f32) void {
}
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);
if (engine.Debug.camera and self.drag_pos != null and self.drag_focus != null) {
if(Input.mouse_pos != null) {
draw_line_vec2i(self.drag_pos.?, Input.mouse_pos.?, Layer.CAMERA, Color.WHITE);
Input.mouse_pos.?.draw(4, Layer.CAMERA, Color.CYAN);
}
self.drag_pos.?.draw(4, Layer.CAMERA, Color.RED);
@ -170,8 +151,8 @@ pub fn mouse_area(_: *const Camera) Recti {
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.?;
if (Input.mouse_pos == null) return false;
self.drag_pos = Input.mouse_pos.?;
self.drag_focus = self.focus;
return true;
} else return false;

View File

@ -1,21 +1,26 @@
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 engine = @import("engine");
const Recti = engine.geometry.Recti;
const Rectf = engine.geometry.Rectf;
const Tag = engine.Tag;
const Scene = engine.Scene;
const Layer = engine.Layer;
const Entity = engine.Entity;
const TAG = Tag.create(Selection);
selection: std.ArrayList(Selectable),
const ISelectable = engine.Interface.create(.{
.get_hitbox = fn () Rectf,
});
selection: std.ArrayList(ISelectable),
focused: bool = false,
pub fn create() !*Selection {
return try Scene.EntityPool.allocate(Selection {
.selection = std.ArrayList(Selectable).init(std.heap.page_allocator),
.selection = std.ArrayList(ISelectable).init(std.heap.page_allocator),
});
}
@ -51,15 +56,3 @@ 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
};
}
};

View File

@ -1,19 +1,22 @@
const Terrain = @This();
const assets = @import("assets.zig");
const Layer = @import("Layer.zig");
const Color = @import("Color.zig");
const Recti = @import("geometry/Recti.zig");
const Vec2f = @import("geometry/Vec2f.zig");
const Vec2i = @import("geometry/Vec2i.zig");
const Entity = @import("Entity.zig");
const Scene = @import("Scene.zig");
const Camera = @import("Camera.zig");
const engine = @import("engine");
const Scene = engine.Scene;
const Entity = engine.Entity;
const Vec2i = engine.geometry.Vec2i;
const Color = engine.Color;
const Recti = engine.geometry.Recti;
const Noise = engine.Noise;
const Layer = engine.Layer;
const std = @import("std");
const allocator = std.heap.page_allocator;
var prng = std.rand.DefaultPrng.init(0);
const Noise = @import("Noise.zig");
const TAG = @import("Tag.zig").create(Terrain);
const Camera = @import("Camera.zig");
const assets = @import("assets.zig");
const TAG = @import("engine").Tag.create(Terrain);
pub const CHUNK_SIZE = 48;
const CHUNK_LENGTH = CHUNK_SIZE * CHUNK_SIZE;

View File

@ -1,7 +1,9 @@
const Texture = @import("Texture.zig");
const Sprite = @import("Sprite.zig");
const Recti = @import("geometry/Recti.zig");
const engine = @import("engine");
const Texture = engine.Texture;
const Sprite = engine.Sprite;
const Recti = engine.geometry.Recti;
const std = @import("std");
const c = @import("c");
const Assets = struct {
tree: Sprite,
@ -18,11 +20,10 @@ 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(window: *c.SDL_Window, renderer: *c.SDL_Renderer) void {
_ = window;
// @compileLog(@TypeOf(terrain));
texture = try Texture.create("textures.png");
texture = Texture.create(renderer, "textures.png");
assets = .{
.tree = make8(27, 4, 1, 2),
@ -59,13 +60,28 @@ pub const tree: *const Sprite = &assets.tree;
pub const heart: *const Sprite = &assets.heart;
pub const pawn: *const Sprite = &assets.pawn;
pub const terrain = [4]*const [4]*const Sprite {
// make pointers turns an array of things into an array
// of pointers to those things.
// my question, is, why does this need to happen?
// in theory, all these public exported things are
// pointers because they need to be const and point to
// the var stuff stored above. thats fine, but, why cant
// we just have a const pointer to the array itself?
// *const [4][4]Sprite?
// i assume a const pointer into an array doesnt let
// you change the data in the array?
&make_pointers(&assets.terrain[0]),
&make_pointers(&assets.terrain[1]),
&make_pointers(&assets.terrain[2]),
&make_pointers(&assets.terrain[3]),
};
// this type seems wrong?
// i suppose its still a pointer to a sprite, but is it not a pointer
// to a const array of sprites?
//
// pub const rocks: *const [4]Sprite = &assets.rocks;
pub const rocks: *const Sprite = make_pointers(&assets.rocks);
// this new one builds fine?

View File

@ -0,0 +1,15 @@
const std = @import("std");
const Engine = @import("engine");
// const assets = @import("assets.zig");
const scenes = @import("scenes.zig");
const assets = @import("assets.zig");
pub fn main() !void {
Engine.Control.set_loader(assets.load);
try Engine.Control.setup();
defer Engine.Control.destroy();
Engine.Control.set_scene(try scenes.game());
try Engine.Control.run();
}

View File

@ -1,8 +1,8 @@
const Scene = @import("Scene.zig");
const Terrain = @import("Terrain.zig");
const Pawn = @import("Pawn.zig");
const engine = @import("engine");
const Scene = engine.Scene;
const Camera = @import("Camera.zig");
const Selection = @import("Selection.zig");
const Terrain = @import("Terrain.zig");
pub fn game() !Scene {
var scene = Scene.create();

View File

@ -1,13 +0,0 @@
const std = @import("std");
const Engine = @import("Engine.zig");
// const assets = @import("assets.zig");
const scenes = @import("scenes.zig");
pub fn main() !void {
// engine.preload(assets.load);
try Engine.setup();
Engine.set_scene(try scenes.game());
try Engine.run();
Engine.destroy();
}

View File

@ -1,6 +0,0 @@
const std = @import("std");
export fn add(a: i32, b: i32) i32 {
return a + b;
}