fixing stuff

This commit is contained in:
Daniel Ledda
2025-01-03 19:21:18 +01:00
parent 3430b4e69a
commit 256292c20d
47 changed files with 3401 additions and 6901 deletions

4
.clangd Normal file
View File

@@ -0,0 +1,4 @@
CompileFlags:
Add:
- -DOS_LINUX
- -I ./

View File

@@ -1,98 +0,0 @@
cmake_minimum_required(VERSION 3.24)
project(somaesque)
set(VENDOR_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor")
set(SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
set(CMAKE_EXPORT_COMPILE_COMMANDS true)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
set(CMAKE_CXX_STANDARD 20)
option(GLFW_BUILD_DOCS OFF)
option(GLFW_BUILD_EXAMPLES OFF)
option(GLFW_BUILD_TESTS OFF)
option(GLFW_INSTALL OFF)
find_package(glfw3 3.3 REQUIRED)
find_package(glm REQUIRED)
# Glad
add_library(glad
STATIC
${VENDOR_DIR}/glad/glad.c
)
target_include_directories(glad
PUBLIC
${VENDOR_DIR}
)
# STB
add_library(loaders
STATIC
${VENDOR_DIR}/loaders/tinyobj.cpp
${VENDOR_DIR}/loaders/stb_image.cpp
)
target_include_directories(loaders
PUBLIC
${VENDOR_DIR}
)
# somaesque
add_executable(${PROJECT_NAME})
target_sources(${PROJECT_NAME}
PRIVATE
${SRC_DIR}/main.cpp
${SRC_DIR}/VoxelSpace.cpp
${SRC_DIR}/VoxelSpace.h
${SRC_DIR}/SomaSolve.cpp
${SRC_DIR}/SomaSolve.h
${SRC_DIR}/gfx/Texture.h
${SRC_DIR}/gfx/Texture.cpp
${SRC_DIR}/gfx/Mesh.h
${SRC_DIR}/gfx/Mesh.cpp
${SRC_DIR}/gfx/Shader.h
${SRC_DIR}/gfx/Shader.cpp
${SRC_DIR}/gfx/Color.h
${SRC_DIR}/gfx/Color.cpp
${SRC_DIR}/gfx/geometry.h
${SRC_DIR}/gfx/geometry.cpp
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
glfw
GL
X11
pthread
Xrandr
dl
glm::glm
glad
loaders
)
target_include_directories(somaesque
PUBLIC
${VENDOR_DIR}/KHR
)
# TESTING
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
FetchContent_MakeAvailable(googletest)
enable_testing()
add_executable(tests
${SRC_DIR}/tests.cpp
${SRC_DIR}/VoxelSpace.cpp
${SRC_DIR}/VoxelSpace.h
)
target_link_libraries(tests
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(tests)

3
build Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
g++ -I ./ -g -g3 -lglfw -lGLU -lGL -lXrandr -lXxf86vm -lXi -lXinerama -lX11 -lrt -ldl -DOS_LINUX=1 -DENABLE_ASSERT=1 ./app.cpp -o ./target/app

27
build.bat Normal file
View File

@@ -0,0 +1,27 @@
@echo off
if NOT EXIST .\target mkdir .\target
set commonLinkerFlags=-opt:ref
set commonCompilerFlags=^
-MT %= Make sure the C runtime library is statically linked =%^
-Gm- %= Turns off incremental building =%^
-nologo %= No one cares you made the compiler Microsoft =%^
-Oi %= Always use intrinsics =%^
-EHa- %= Disable exception handling =%^
-GR- %= Never use runtime type info from C++ =%^
-WX -W4 -wd4201 -wd4100 -wd4189 -wd4505 %= Compiler warnings, -WX warnings as errors, -W4 warning level 4, -wdXXXX disable warning XXXX =%^
-DAPP_DEBUG=0 -DENABLE_ASSERT=1 -DOS_WINDOWS=1 %= Custom #defines =%^
-D_CRT_SECURE_NO_WARNINGS=1^
-FC %= Full path of source code file in diagnostics =%^
-Zi %= Generate debugger info =%
pushd .\target
cl %commonCompilerFlags% -Fe:.\app.exe ..\app.cpp /link -incremental:no %commonLinkerFlags%
popd
exit /b
:error
echo Failed with error #%errorlevel%.
exit /b %errorlevel%

View File

@@ -1,55 +0,0 @@
const std = @import("std");
const zmath = @import("lib/zmath/build.zig");
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(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "somaesque-native-zig",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = mode,
});
exe.addIncludePath("/usr/local/include");
exe.linkLibC();
exe.linkSystemLibrary("glfw3");
exe.linkSystemLibrary("glm");
exe.linkSystemLibrary("GL");
exe.addIncludePath("lib/c");
exe.addCSourceFile("lib/c/glad/glad.c", &[_][]const u8{"-std=c11"});
exe.install();
// zmath
const zmath_pkg = zmath.package(b, target, mode, .{
.options = .{ .enable_cross_platform_determinism = true },
});
zmath_pkg.link(exe);
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
//const exe_tests = b.addTest("src/main.zig");
//exe_tests.setTarget(target);
//exe_tests.setBuildMode(mode);
//const test_step = b.step("test", "Run unit tests");
//test_step.dependOn(&exe_tests.step);
}

View File

@@ -1,138 +0,0 @@
# zmath v0.9.6 - SIMD math library for game developers
Tested on x86_64 and AArch64.
Provides ~140 optimized routines and ~70 extensive tests.
Can be used with any graphics API.
Documentation can be found [here](https://github.com/michal-z/zig-gamedev/blob/main/libs/zmath/src/zmath.zig).
Benchamrks can be found [here](https://github.com/michal-z/zig-gamedev/blob/main/libs/zmath/src/benchmark.zig).
An intro article can be found [here](https://zig.news/michalz/fast-multi-platform-simd-math-library-in-zig-2adn).
## Getting started
Copy `zmath` folder to a `libs` subdirectory of the root of your project.
Then in your `build.zig` add:
```zig
const std = @import("std");
const zmath = @import("libs/zmath/build.zig");
pub fn build(b: *std.Build) void {
...
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
zmath_pkg = zmath.package(b, target, optimize, .{
.options = .{ .enable_cross_platform_determinism = true },
});
zmath_pkg.link(exe);
}
```
Now in your code you may import and use zmath:
```zig
const zm = @import("zmath");
pub fn main() !void {
//
// OpenGL/Vulkan example
//
const object_to_world = zm.rotationY(..);
const world_to_view = zm.lookAtRh(
zm.f32x4(3.0, 3.0, 3.0, 1.0), // eye position
zm.f32x4(0.0, 0.0, 0.0, 1.0), // focus point
zm.f32x4(0.0, 1.0, 0.0, 0.0), // up direction ('w' coord is zero because this is a vector not a point)
);
// `perspectiveFovRhGl` produces Z values in [-1.0, 1.0] range (Vulkan app should use `perspectiveFovRh`)
const view_to_clip = zm.perspectiveFovRhGl(0.25 * math.pi, aspect_ratio, 0.1, 20.0);
const object_to_view = zm.mul(object_to_world, world_to_view);
const object_to_clip = zm.mul(object_to_view, view_to_clip);
// Transposition is needed because GLSL uses column-major matrices by default
gl.uniformMatrix4fv(0, 1, gl.TRUE, zm.arrNPtr(&object_to_clip));
// In GLSL: gl_Position = vec4(in_position, 1.0) * object_to_clip;
//
// DirectX example
//
const object_to_world = zm.rotationY(..);
const world_to_view = zm.lookAtLh(
zm.f32x4(3.0, 3.0, -3.0, 1.0), // eye position
zm.f32x4(0.0, 0.0, 0.0, 1.0), // focus point
zm.f32x4(0.0, 1.0, 0.0, 0.0), // up direction ('w' coord is zero because this is a vector not a point)
);
const view_to_clip = zm.perspectiveFovLh(0.25 * math.pi, aspect_ratio, 0.1, 20.0);
const object_to_view = zm.mul(object_to_world, world_to_view);
const object_to_clip = zm.mul(object_to_view, view_to_clip);
// Transposition is needed because HLSL uses column-major matrices by default
const mem = allocateUploadMemory(...);
zm.storeMat(mem, zm.transpose(object_to_clip));
// In HLSL: out_position_sv = mul(float4(in_position, 1.0), object_to_clip);
//
// 'WASD' camera movement example
//
{
const speed = zm.f32x4s(10.0);
const delta_time = zm.f32x4s(demo.frame_stats.delta_time);
const transform = zm.mul(zm.rotationX(demo.camera.pitch), zm.rotationY(demo.camera.yaw));
var forward = zm.normalize3(zm.mul(zm.f32x4(0.0, 0.0, 1.0, 0.0), transform));
zm.storeArr3(&demo.camera.forward, forward);
const right = speed * delta_time * zm.normalize3(zm.cross3(zm.f32x4(0.0, 1.0, 0.0, 0.0), forward));
forward = speed * delta_time * forward;
var cam_pos = zm.loadArr3(demo.camera.position);
if (keyDown('W')) {
cam_pos += forward;
} else if (keyDown('S')) {
cam_pos -= forward;
}
if (keyDown('D')) {
cam_pos += right;
} else if (keyDown('A')) {
cam_pos -= right;
}
zm.storeArr3(&demo.camera.position, cam_pos);
}
//
// SIMD wave equation solver example (works with vector width 4, 8 and 16)
// 'T' can be F32x4, F32x8 or F32x16
//
var z_index: i32 = 0;
while (z_index < grid_size) : (z_index += 1) {
const z = scale * @intToFloat(f32, z_index - grid_size / 2);
const vz = zm.splat(T, z);
var x_index: i32 = 0;
while (x_index < grid_size) : (x_index += zm.veclen(T)) {
const x = scale * @intToFloat(f32, x_index - grid_size / 2);
const vx = zm.splat(T, x) + voffset * zm.splat(T, scale);
const d = zm.sqrt(vx * vx + vz * vz);
const vy = zm.sin(d - vtime);
const index = @intCast(usize, x_index + z_index * grid_size);
zm.store(xslice[index..], vx, 0);
zm.store(yslice[index..], vy, 0);
zm.store(zslice[index..], vz, 0);
}
}
}
```

View File

@@ -1,97 +0,0 @@
const std = @import("std");
pub const Options = struct {
enable_cross_platform_determinism: bool = true,
};
pub const Package = struct {
options: Options,
zmath: *std.Build.Module,
zmath_options: *std.Build.Module,
pub fn link(pkg: Package, exe: *std.Build.CompileStep) void {
exe.addModule("zmath", pkg.zmath);
exe.addModule("zmath_options", pkg.zmath_options);
}
};
pub fn package(
b: *std.Build,
_: std.zig.CrossTarget,
_: std.builtin.Mode,
args: struct {
options: Options = .{},
},
) Package {
const step = b.addOptions();
step.addOption(
bool,
"enable_cross_platform_determinism",
args.options.enable_cross_platform_determinism,
);
const zmath_options = step.createModule();
const zmath = b.createModule(.{
.source_file = .{ .path = thisDir() ++ "/src/main.zig" },
.dependencies = &.{
.{ .name = "zmath_options", .module = zmath_options },
},
});
return .{
.options = args.options,
.zmath = zmath,
.zmath_options = zmath_options,
};
}
pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
const test_step = b.step("test", "Run zmath tests");
test_step.dependOn(runTests(b, optimize, target));
const benchmark_step = b.step("benchmark", "Run zmath benchmarks");
benchmark_step.dependOn(runBenchmarks(b, target));
}
pub fn runTests(
b: *std.Build,
optimize: std.builtin.Mode,
target: std.zig.CrossTarget,
) *std.Build.Step {
const tests = b.addTest(.{
.name = "zmath-tests",
.root_source_file = .{ .path = thisDir() ++ "/src/main.zig" },
.target = target,
.optimize = optimize,
});
const zmath_pkg = package(b, target, optimize, .{});
tests.addModule("zmath_options", zmath_pkg.zmath_options);
return &tests.run().step;
}
pub fn runBenchmarks(
b: *std.Build,
target: std.zig.CrossTarget,
) *std.Build.Step {
const exe = b.addExecutable(.{
.name = "zmath-benchmarks",
.root_source_file = .{ .path = thisDir() ++ "/src/benchmark.zig" },
.target = target,
.optimize = .ReleaseFast,
});
const zmath_pkg = package(b, target, .ReleaseFast, .{});
exe.addModule("zmath", zmath_pkg.zmath);
return &exe.run().step;
}
inline fn thisDir() []const u8 {
return comptime std.fs.path.dirname(@src().file) orelse ".";
}

View File

@@ -1,469 +0,0 @@
// -------------------------------------------------------------------------------------------------
// zmath - benchmarks
// -------------------------------------------------------------------------------------------------
// 'zig build benchmark' in the root project directory will build and run 'ReleaseFast' configuration.
//
// -------------------------------------------------------------------------------------------------
// 'AMD Ryzen 9 3950X 16-Core Processor', Windows 11, Zig 0.10.0-dev.2620+0e9458a3f
// -------------------------------------------------------------------------------------------------
// matrix mul benchmark (AOS) - scalar version: 1.5880s, zmath version: 1.0642s
// cross3, scale, bias benchmark (AOS) - scalar version: 0.9318s, zmath version: 0.6888s
// cross3, dot3, scale, bias benchmark (AOS) - scalar version: 1.2258s, zmath version: 1.1095s
// quaternion mul benchmark (AOS) - scalar version: 1.4123s, zmath version: 0.6958s
// wave benchmark (SOA) - scalar version: 4.8165s, zmath version: 0.7338s
//
// -------------------------------------------------------------------------------------------------
// 'AMD Ryzen 7 5800X 8-Core Processer', Linux 5.17.14, Zig 0.10.0-dev.2624+d506275a0
// -------------------------------------------------------------------------------------------------
// matrix mul benchmark (AOS) - scalar version: 1.3672s, zmath version: 0.8617s
// cross3, scale, bias benchmark (AOS) - scalar version: 0.6586s, zmath version: 0.4803s
// cross3, dot3, scale, bias benchmark (AOS) - scalar version: 1.0620s, zmath version: 0.8942s
// quaternion mul benchmark (AOS) - scalar version: 1.1324s, zmath version: 0.6064s
// wave benchmark (SOA) - scalar version: 3.6598s, zmath version: 0.4231s
//
// -------------------------------------------------------------------------------------------------
// 'Apple M1 Max', macOS Version 12.4, Zig 0.10.0-dev.2657+74442f350
// -------------------------------------------------------------------------------------------------
// matrix mul benchmark (AOS) - scalar version: 1.0297s, zmath version: 1.0538s
// cross3, scale, bias benchmark (AOS) - scalar version: 0.6294s, zmath version: 0.6532s
// cross3, dot3, scale, bias benchmark (AOS) - scalar version: 0.9807s, zmath version: 1.0988s
// quaternion mul benchmark (AOS) - scalar version: 1.5413s, zmath version: 0.7800s
// wave benchmark (SOA) - scalar version: 3.4220s, zmath version: 1.0255s
//
// -------------------------------------------------------------------------------------------------
// '11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz', Windows 11, Zig 0.10.0-dev.2620+0e9458a3f
// -------------------------------------------------------------------------------------------------
// matrix mul benchmark (AOS) - scalar version: 2.2308s, zmath version: 0.9376s
// cross3, scale, bias benchmark (AOS) - scalar version: 1.0821s, zmath version: 0.5110s
// cross3, dot3, scale, bias benchmark (AOS) - scalar version: 1.6580s, zmath version: 0.9167s
// quaternion mul benchmark (AOS) - scalar version: 2.0139s, zmath version: 0.5856s
// wave benchmark (SOA) - scalar version: 3.7832s, zmath version: 0.3642s
//
// -------------------------------------------------------------------------------------------------
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// m = mul(ma, mb); data set fits in L1 cache; AOS data layout.
try mat4MulBenchmark(allocator, 100_000);
// v = 0.01 * cross3(va, vb) + vec3(1.0); data set fits in L1 cache; AOS data layout.
try cross3ScaleBiasBenchmark(allocator, 10_000);
// v = dot3(va, vb) * (0.1 * cross3(va, vb) + vec3(1.0)); data set fits in L1 cache; AOS data layout.
try cross3Dot3ScaleBiasBenchmark(allocator, 10_000);
// q = qmul(qa, qb); data set fits in L1 cache; AOS data layout.
try quatBenchmark(allocator, 10_000);
// d = sqrt(x * x + z * z); y = sin(d - t); SOA layout.
try waveBenchmark(allocator, 1_000);
}
const std = @import("std");
const time = std.time;
const Timer = time.Timer;
const zm = @import("zmath");
var prng = std.rand.DefaultPrng.init(0);
const random = prng.random();
noinline fn mat4MulBenchmark(allocator: std.mem.Allocator, comptime count: comptime_int) !void {
std.debug.print("\n", .{});
std.debug.print("{s:>42} - ", .{"matrix mul benchmark (AOS)"});
var data0 = std.ArrayList([16]f32).init(allocator);
defer data0.deinit();
var data1 = std.ArrayList([16]f32).init(allocator);
defer data1.deinit();
var i: usize = 0;
while (i < 64) : (i += 1) {
try data0.append([16]f32{
random.float(f32), random.float(f32), random.float(f32), random.float(f32),
random.float(f32), random.float(f32), random.float(f32), random.float(f32),
random.float(f32), random.float(f32), random.float(f32), random.float(f32),
random.float(f32), random.float(f32), random.float(f32), random.float(f32),
});
try data1.append([16]f32{
random.float(f32), random.float(f32), random.float(f32), random.float(f32),
random.float(f32), random.float(f32), random.float(f32), random.float(f32),
random.float(f32), random.float(f32), random.float(f32), random.float(f32),
random.float(f32), random.float(f32), random.float(f32), random.float(f32),
});
}
// Warmup, fills L1 cache.
i = 0;
while (i < 100) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const ma = zm.loadMat(a[0..]);
const mb = zm.loadMat(b[0..]);
const r = zm.mul(ma, mb);
std.mem.doNotOptimizeAway(&r);
}
}
}
{
i = 0;
var timer = try Timer.start();
const start = timer.lap();
while (i < count) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const r = [16]f32{
a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12],
a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13],
a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14],
a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15],
a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12],
a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13],
a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14],
a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15],
a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12],
a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13],
a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14],
a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15],
a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12],
a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13],
a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14],
a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15],
};
std.mem.doNotOptimizeAway(&r);
}
}
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("scalar version: {d:.4}s, ", .{elapsed_s});
}
{
i = 0;
var timer = try Timer.start();
const start = timer.lap();
while (i < count) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const ma = zm.loadMat(a[0..]);
const mb = zm.loadMat(b[0..]);
const r = zm.mul(ma, mb);
std.mem.doNotOptimizeAway(&r);
}
}
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("zmath version: {d:.4}s\n", .{elapsed_s});
}
}
noinline fn cross3ScaleBiasBenchmark(allocator: std.mem.Allocator, comptime count: comptime_int) !void {
std.debug.print("{s:>42} - ", .{"cross3, scale, bias benchmark (AOS)"});
var data0 = std.ArrayList([3]f32).init(allocator);
defer data0.deinit();
var data1 = std.ArrayList([3]f32).init(allocator);
defer data1.deinit();
var i: usize = 0;
while (i < 256) : (i += 1) {
try data0.append([3]f32{ random.float(f32), random.float(f32), random.float(f32) });
try data1.append([3]f32{ random.float(f32), random.float(f32), random.float(f32) });
}
// Warmup, fills L1 cache.
i = 0;
while (i < 100) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const va = zm.loadArr3(a);
const vb = zm.loadArr3(b);
const cp = zm.f32x4s(0.01) * zm.cross3(va, vb) + zm.f32x4s(1.0);
std.mem.doNotOptimizeAway(&cp);
}
}
}
{
i = 0;
var timer = try Timer.start();
const start = timer.lap();
while (i < count) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const r = [3]f32{
0.01 * (a[1] * b[2] - a[2] * b[1]) + 1.0,
0.01 * (a[2] * b[0] - a[0] * b[2]) + 1.0,
0.01 * (a[0] * b[1] - a[1] * b[0]) + 1.0,
};
std.mem.doNotOptimizeAway(&r);
}
}
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("scalar version: {d:.4}s, ", .{elapsed_s});
}
{
i = 0;
var timer = try Timer.start();
const start = timer.lap();
while (i < count) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const va = zm.loadArr3(a);
const vb = zm.loadArr3(b);
const cp = zm.f32x4s(0.01) * zm.cross3(va, vb) + zm.f32x4s(1.0);
std.mem.doNotOptimizeAway(&cp);
}
}
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("zmath version: {d:.4}s\n", .{elapsed_s});
}
}
noinline fn cross3Dot3ScaleBiasBenchmark(allocator: std.mem.Allocator, comptime count: comptime_int) !void {
std.debug.print("{s:>42} - ", .{"cross3, dot3, scale, bias benchmark (AOS)"});
var data0 = std.ArrayList([3]f32).init(allocator);
defer data0.deinit();
var data1 = std.ArrayList([3]f32).init(allocator);
defer data1.deinit();
var i: usize = 0;
while (i < 256) : (i += 1) {
try data0.append([3]f32{ random.float(f32), random.float(f32), random.float(f32) });
try data1.append([3]f32{ random.float(f32), random.float(f32), random.float(f32) });
}
// Warmup, fills L1 cache.
i = 0;
while (i < 100) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const va = zm.loadArr3(a);
const vb = zm.loadArr3(b);
const r = (zm.dot3(va, vb) * (zm.f32x4s(0.1) * zm.cross3(va, vb) + zm.f32x4s(1.0)))[0];
std.mem.doNotOptimizeAway(&r);
}
}
}
{
i = 0;
var timer = try Timer.start();
const start = timer.lap();
while (i < count) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const d = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
const r = [3]f32{
d * (0.1 * (a[1] * b[2] - a[2] * b[1]) + 1.0),
d * (0.1 * (a[2] * b[0] - a[0] * b[2]) + 1.0),
d * (0.1 * (a[0] * b[1] - a[1] * b[0]) + 1.0),
};
std.mem.doNotOptimizeAway(&r);
}
}
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("scalar version: {d:.4}s, ", .{elapsed_s});
}
{
i = 0;
var timer = try Timer.start();
const start = timer.lap();
while (i < count) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const va = zm.loadArr3(a);
const vb = zm.loadArr3(b);
const r = zm.dot3(va, vb) * (zm.f32x4s(0.1) * zm.cross3(va, vb) + zm.f32x4s(1.0));
std.mem.doNotOptimizeAway(&r);
}
}
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("zmath version: {d:.4}s\n", .{elapsed_s});
}
}
noinline fn quatBenchmark(allocator: std.mem.Allocator, comptime count: comptime_int) !void {
std.debug.print("{s:>42} - ", .{"quaternion mul benchmark (AOS)"});
var data0 = std.ArrayList([4]f32).init(allocator);
defer data0.deinit();
var data1 = std.ArrayList([4]f32).init(allocator);
defer data1.deinit();
var i: usize = 0;
while (i < 256) : (i += 1) {
try data0.append([4]f32{ random.float(f32), random.float(f32), random.float(f32), random.float(f32) });
try data1.append([4]f32{ random.float(f32), random.float(f32), random.float(f32), random.float(f32) });
}
// Warmup, fills L1 cache.
i = 0;
while (i < 100) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const va = zm.loadArr4(a);
const vb = zm.loadArr4(b);
const r = zm.qmul(va, vb);
std.mem.doNotOptimizeAway(&r);
}
}
}
{
i = 0;
var timer = try Timer.start();
const start = timer.lap();
while (i < count) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const r = [4]f32{
(b[3] * a[0]) + (b[0] * a[3]) + (b[1] * a[2]) - (b[2] * a[1]),
(b[3] * a[1]) - (b[0] * a[2]) + (b[1] * a[3]) + (b[2] * a[0]),
(b[3] * a[2]) + (b[0] * a[1]) - (b[1] * a[0]) + (b[2] * a[3]),
(b[3] * a[3]) - (b[0] * a[0]) - (b[1] * a[1]) - (b[2] * a[2]),
};
std.mem.doNotOptimizeAway(&r);
}
}
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("scalar version: {d:.4}s, ", .{elapsed_s});
}
{
i = 0;
var timer = try Timer.start();
const start = timer.lap();
while (i < count) : (i += 1) {
for (data1.items) |b| {
for (data0.items) |a| {
const va = zm.loadArr4(a);
const vb = zm.loadArr4(b);
const r = zm.qmul(va, vb);
std.mem.doNotOptimizeAway(&r);
}
}
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("zmath version: {d:.4}s\n", .{elapsed_s});
}
}
noinline fn waveBenchmark(allocator: std.mem.Allocator, comptime count: comptime_int) !void {
_ = allocator;
std.debug.print("{s:>42} - ", .{"wave benchmark (SOA)"});
const grid_size = 1024;
{
var t: f32 = 0.0;
const scale: f32 = 0.05;
var timer = try Timer.start();
const start = timer.lap();
var iter: usize = 0;
while (iter < count) : (iter += 1) {
var z_index: i32 = 0;
while (z_index < grid_size) : (z_index += 1) {
const z = scale * @intToFloat(f32, z_index - grid_size / 2);
var x_index: i32 = 0;
while (x_index < grid_size) : (x_index += 4) {
const x0 = scale * @intToFloat(f32, x_index + 0 - grid_size / 2);
const x1 = scale * @intToFloat(f32, x_index + 1 - grid_size / 2);
const x2 = scale * @intToFloat(f32, x_index + 2 - grid_size / 2);
const x3 = scale * @intToFloat(f32, x_index + 3 - grid_size / 2);
const d0 = zm.sqrt(x0 * x0 + z * z);
const d1 = zm.sqrt(x1 * x1 + z * z);
const d2 = zm.sqrt(x2 * x2 + z * z);
const d3 = zm.sqrt(x3 * x3 + z * z);
const y0 = zm.sin(d0 - t);
const y1 = zm.sin(d1 - t);
const y2 = zm.sin(d2 - t);
const y3 = zm.sin(d3 - t);
std.mem.doNotOptimizeAway(&y0);
std.mem.doNotOptimizeAway(&y1);
std.mem.doNotOptimizeAway(&y2);
std.mem.doNotOptimizeAway(&y3);
}
}
t += 0.001;
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("scalar version: {d:.4}s, ", .{elapsed_s});
}
{
const T = zm.F32x16;
const static = struct {
const offsets = [16]f32{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
};
const voffset = zm.load(static.offsets[0..], T, 0);
var vt = zm.splat(T, 0.0);
const scale: f32 = 0.05;
var timer = try Timer.start();
const start = timer.lap();
var iter: usize = 0;
while (iter < count) : (iter += 1) {
var z_index: i32 = 0;
while (z_index < grid_size) : (z_index += 1) {
const z = scale * @intToFloat(f32, z_index - grid_size / 2);
const vz = zm.splat(T, z);
var x_index: i32 = 0;
while (x_index < grid_size) : (x_index += zm.veclen(T)) {
const x = scale * @intToFloat(f32, x_index - grid_size / 2);
const vx = zm.splat(T, x) + voffset * zm.splat(T, scale);
const d = zm.sqrt(vx * vx + vz * vz);
const vy = zm.sin(d - vt);
std.mem.doNotOptimizeAway(&vy);
}
}
vt += zm.splat(T, 0.001);
}
const end = timer.read();
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
std.debug.print("zmath version: {d:.4}s\n", .{elapsed_s});
}
}

View File

@@ -1,18 +0,0 @@
//--------------------------------------------------------------------------------------------------
//
// SIMD math library for game developers
// https://github.com/michal-z/zig-gamedev/tree/main/libs/zmath
//
// See zmath.zig for more details.
// See util.zig for additional functionality.
//
//--------------------------------------------------------------------------------------------------
pub const version = @import("std").SemanticVersion{ .major = 0, .minor = 9, .patch = 6 };
pub usingnamespace @import("zmath.zig");
pub const util = @import("util.zig");
// ensure transitive closure of test coverage
comptime {
_ = util;
}

View File

@@ -1,182 +0,0 @@
// ==============================================================================
//
// Collection of useful functions building on top of, and extending, core zmath.
// https://github.com/michal-z/zig-gamedev/tree/main/libs/zmath
//
// ------------------------------------------------------------------------------
// 1. Matrix functions
// ------------------------------------------------------------------------------
//
// As an example, in a left handed Y-up system:
// getAxisX is equivalent to the right vector
// getAxisY is equivalent to the up vector
// getAxisZ is equivalent to the forward vector
//
// getTranslationVec(m: Mat) Vec
// getAxisX(m: Mat) Vec
// getAxisY(m: Mat) Vec
// getAxisZ(m: Mat) Vec
//
// ==============================================================================
const zm = @import("zmath.zig");
const std = @import("std");
const math = std.math;
const expect = std.testing.expect;
pub fn getTranslationVec(m: zm.Mat) zm.Vec {
var translation = m[3];
translation[3] = 0;
return translation;
}
pub fn getScaleVec(m: zm.Mat) zm.Vec {
const scale_x = zm.length3(zm.f32x4(m[0][0], m[1][0], m[2][0], 0))[0];
const scale_y = zm.length3(zm.f32x4(m[0][1], m[1][1], m[2][1], 0))[0];
const scale_z = zm.length3(zm.f32x4(m[0][2], m[1][2], m[2][2], 0))[0];
return zm.f32x4(scale_x, scale_y, scale_z, 0);
}
pub fn getRotationQuat(_m: zm.Mat) zm.Quat {
// Ortho normalize given matrix.
const c1 = zm.normalize3(zm.f32x4(_m[0][0], _m[1][0], _m[2][0], 0));
const c2 = zm.normalize3(zm.f32x4(_m[0][1], _m[1][1], _m[2][1], 0));
const c3 = zm.normalize3(zm.f32x4(_m[0][2], _m[1][2], _m[2][2], 0));
var m = _m;
m[0][0] = c1[0];
m[1][0] = c1[1];
m[2][0] = c1[2];
m[0][1] = c2[0];
m[1][1] = c2[1];
m[2][1] = c2[2];
m[0][2] = c3[0];
m[1][2] = c3[1];
m[2][2] = c3[2];
// Extract rotation
return zm.quatFromMat(m);
}
pub fn getAxisX(m: zm.Mat) zm.Vec {
return zm.normalize3(zm.f32x4(m[0][0], m[0][1], m[0][2], 0.0));
}
pub fn getAxisY(m: zm.Mat) zm.Vec {
return zm.normalize3(zm.f32x4(m[1][0], m[1][1], m[1][2], 0.0));
}
pub fn getAxisZ(m: zm.Mat) zm.Vec {
return zm.normalize3(zm.f32x4(m[2][0], m[2][1], m[2][2], 0.0));
}
test "zmath.util.mat.translation" {
// zig fmt: off
const mat_data = [18]f32{
1.0,
2.0, 3.0, 4.0, 5.0,
6.0, 7.0, 8.0, 9.0,
10.0,11.0, 12.0,13.0,
14.0, 15.0, 16.0, 17.0,
18.0,
};
// zig fmt: on
const mat = zm.loadMat(mat_data[1..]);
const translation = getTranslationVec(mat);
try expect(zm.approxEqAbs(translation, zm.f32x4(14.0, 15.0, 16.0, 0.0), 0.0001));
}
test "zmath.util.mat.scale" {
const mat = zm.mul(zm.scaling(3, 4, 5), zm.translation(6, 7, 8));
const scale = getScaleVec(mat);
try expect(zm.approxEqAbs(scale, zm.f32x4(3.0, 4.0, 5.0, 0.0), 0.0001));
}
test "zmath.util.mat.rotation" {
const rotate_origin = zm.matFromRollPitchYaw(0.1, 1.2, 2.3);
const mat = zm.mul(zm.mul(rotate_origin, zm.scaling(3, 4, 5)), zm.translation(6, 7, 8));
const rotate_get = getRotationQuat(mat);
const v0 = zm.mul(zm.f32x4s(1), rotate_origin);
const v1 = zm.mul(zm.f32x4s(1), zm.quatToMat(rotate_get));
try expect(zm.approxEqAbs(v0, v1, 0.0001));
}
test "zmath.util.mat.z_vec" {
const degToRad = std.math.degreesToRadians;
var identity = zm.identity();
var z_vec = getAxisZ(identity);
try expect(zm.approxEqAbs(z_vec, zm.f32x4(0.0, 0.0, 1.0, 0), 0.0001));
const rot_yaw = zm.rotationY(degToRad(f32, 90));
identity = zm.mul(identity, rot_yaw);
z_vec = getAxisZ(identity);
try expect(zm.approxEqAbs(z_vec, zm.f32x4(1.0, 0.0, 0.0, 0), 0.0001));
}
test "zmath.util.mat.y_vec" {
const degToRad = std.math.degreesToRadians;
var identity = zm.identity();
var y_vec = getAxisY(identity);
try expect(zm.approxEqAbs(y_vec, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01));
const rot_yaw = zm.rotationY(degToRad(f32, 90));
identity = zm.mul(identity, rot_yaw);
y_vec = getAxisY(identity);
try expect(zm.approxEqAbs(y_vec, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01));
const rot_pitch = zm.rotationX(degToRad(f32, 90));
identity = zm.mul(identity, rot_pitch);
y_vec = getAxisY(identity);
try expect(zm.approxEqAbs(y_vec, zm.f32x4(0.0, 0.0, 1.0, 0), 0.01));
}
test "zmath.util.mat.right" {
const degToRad = std.math.degreesToRadians;
var identity = zm.identity();
var right = getAxisX(identity);
try expect(zm.approxEqAbs(right, zm.f32x4(1.0, 0.0, 0.0, 0), 0.01));
const rot_yaw = zm.rotationY(degToRad(f32, 90));
identity = zm.mul(identity, rot_yaw);
right = getAxisX(identity);
try expect(zm.approxEqAbs(right, zm.f32x4(0.0, 0.0, -1.0, 0), 0.01));
const rot_pitch = zm.rotationX(degToRad(f32, 90));
identity = zm.mul(identity, rot_pitch);
right = getAxisX(identity);
try expect(zm.approxEqAbs(right, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01));
}
// ------------------------------------------------------------------------------
// This software is available under 2 licenses -- choose whichever you prefer.
// ------------------------------------------------------------------------------
// ALTERNATIVE A - MIT License
// Copyright (c) 2022 Michal Ziulek and Contributors
// Permission is hereby granted, free of charge, to any person obtaining identity copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is 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 Software.
// THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ------------------------------------------------------------------------------
// ALTERNATIVE B - Public Domain (www.unlicense.org)
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
// software, either in source code form or as identity compiled binary, for any purpose,
// commercial or non-commercial, and by any means.
// In jurisdictions that recognize copyright laws, the author or authors of this
// software dedicate any and all copyright interest in the software to the public
// domain. We make this dedication for the benefit of the public at large and to
// the detriment of our heirs and successors. We intend this dedication to be an
// overt act of relinquishment in perpetuity of all present and future rights to
// this software under copyright law.
// THE SOFTWARE IS 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 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,11 @@
#include <bitset>
#include <span>
#include <cstdint>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include "VoxelSpace.h"
auto get_dims_input(int dims[3]) -> void {
void get_dims_input(int dims[3]) {
std::cout << "Enter dimensions separated by newlines. (x*y*z must not exceed 64)\n";
auto success = false;
bool success = false;
while (!success) {
std::cout << "x: ";
std::cin >> dims[0];
@@ -18,7 +14,7 @@ auto get_dims_input(int dims[3]) -> void {
std::cout << "z: ";
std::cin >> dims[2];
auto size = dims[0]*dims[1]*dims[2];
int size = dims[0]*dims[1]*dims[2];
if (size <= 64) {
success = true;
} else {
@@ -28,12 +24,12 @@ auto get_dims_input(int dims[3]) -> void {
}
}
auto get_reprs_input(int units_required) -> std::vector<uint64_t> {
std::vector<uint64> get_reprs_input(int units_required) {
std::cout << "Enter bit-representations (big endian, max 64 bits, total 1s must add up to " << units_required << "). press ENTER twice to finish input.\n";
auto reprs = std::vector<uint64_t>();
auto total_units = 0;
std::vector<uint64> reprs = std::vector<uint64>();
int total_units = 0;
while (true) {
auto input = std::string();
std::string input = std::string();
std::getline(std::cin, input);
if (input.size() == 0) {
if (total_units == units_required) {
@@ -44,12 +40,12 @@ auto get_reprs_input(int units_required) -> std::vector<uint64_t> {
continue;
}
}
auto bit_repr = 0ul;
auto i = 0;
auto good_repr = true;
uint64 bit_repr = 0;
int i = 0;
bool good_repr = true;
for (auto it = input.rbegin(); it < input.rend(); it++, i++) {
if (*it == '1') {
bit_repr |= 1ul << i;
bit_repr |= 1 << i;
total_units++;
} else if (*it != '0' || i >= 64) {
std::cout << "Input invalid. Enter a binary string only with max 64 bits." << '\n';
@@ -64,191 +60,189 @@ auto get_reprs_input(int units_required) -> std::vector<uint64_t> {
return reprs;
}
namespace SomaSolve {
using SomaSolution = std::vector<uint64_t>;
typedef std::vector<uint64> SomaSolution;
struct Solver {
std::vector<uint64_t>* input;
std::vector<int>* offsets;
std::vector<SomaSolution>* solutions;
};
struct Solver {
std::vector<uint64>* input;
std::vector<int>* offsets;
std::vector<SomaSolution>* solutions;
};
auto STD_SOMA = std::vector<uint64_t>{ 23ul, 30ul, 15ul, 1043ul, 24594ul, 12306ul, 11ul };
std::vector<uint64> STD_SOMA = { 23ul, 30ul, 15ul, 1043ul, 24594ul, 12306ul, 11ul };
auto backtrack_solve_iter(std::vector<uint64_t> *polycube_input, std::vector<int> *offsets)-> void {
auto num_inputs = offsets->size() - 1;
void backtrack_solve_iter(std::vector<uint64> *polycube_input, std::vector<int> *offsets) {
int num_inputs = offsets->size() - 1;
auto solns = std::vector<int>();
std::vector<int> solns = std::vector<int>();
auto iter_stack = std::vector<int>();
auto curr_soln_stack = std::vector<int>();
auto soln_spaces_stack = std::vector<uint64_t>();
soln_spaces_stack.push_back(0ul);
std::vector<int> iter_stack = std::vector<int>();
std::vector<int> curr_soln_stack = std::vector<int>();
std::vector<uint64> soln_spaces_stack = std::vector<uint64>();
soln_spaces_stack.push_back(0ul);
auto depth = 0;
int depth = 0;
while (depth >= 0) {
if (depth >= iter_stack.size()) {
iter_stack.push_back(offsets->at(depth));
}
auto end = offsets->at(depth + 1);
auto broke = false;
for (; iter_stack[depth] < end; iter_stack[depth]++) {
auto next_space = polycube_input->at(iter_stack[depth]);
auto soln_space = soln_spaces_stack[depth];
std::cout << next_space << " " << soln_space << std::endl;
auto successful_fuse = (soln_space | next_space) == (soln_space ^ next_space);
if (successful_fuse) {
soln_spaces_stack.push_back(soln_space |= next_space);
curr_soln_stack.push_back(iter_stack[depth]);
depth++;
if (curr_soln_stack.size() == num_inputs) {
solns.push_back(1);
curr_soln_stack.pop_back();
soln_spaces_stack.pop_back();
depth--;
} else {
depth++;
auto broke = true;
break;
}
}
}
if (!broke) {
curr_soln_stack.pop_back();
soln_spaces_stack.pop_back();
depth--;
}
while (depth >= 0) {
if (depth >= iter_stack.size()) {
iter_stack.push_back(offsets->at(depth));
}
std::cout << "Done. Found " << solns.size() << " solutions." << std::endl;
}
auto backtrack_solve(Solver *solver, uint64_t working_solution = 0ul, int curr_piece = 0) -> void {
auto input = solver->input;
auto offsets = solver->offsets;
auto solutions = solver->solutions;
auto start = offsets->at(curr_piece);
auto end = offsets->at(curr_piece + 1);
auto num_pieces = offsets->size() - 1;
for (int i = start; i < end; i++) {
auto successful_fuse = !Voxel::collides(working_solution, input->at(i));
int end = offsets->at(depth + 1);
bool broke = false;
for (; iter_stack[depth] < end; iter_stack[depth]++) {
uint64 next_space = polycube_input->at(iter_stack[depth]);
uint64 soln_space = soln_spaces_stack[depth];
std::cout << next_space << " " << soln_space << std::endl;
bool successful_fuse = (soln_space | next_space) == (soln_space ^ next_space);
if (successful_fuse) {
auto new_working_solution = working_solution | input->at(i);
solutions->back().at(curr_piece) = input->at(i);
if (curr_piece == num_pieces - 1) {
auto last_soln = solutions->back();
solutions->push_back(SomaSolution(last_soln.begin(), last_soln.end()));
return;
soln_spaces_stack.push_back(soln_space |= next_space);
curr_soln_stack.push_back(iter_stack[depth]);
depth++;
if (curr_soln_stack.size() == num_inputs) {
solns.push_back(1);
curr_soln_stack.pop_back();
soln_spaces_stack.pop_back();
depth--;
} else {
backtrack_solve(solver, new_working_solution, curr_piece + 1);
}
}
}
if (curr_piece == 0) {
solutions->pop_back();
}
}
auto get_solution_rotations(SomaSolution *solution, int dims[3]) -> std::vector<SomaSolution> {
auto result = std::vector<SomaSolution>(Voxel::NUM_ROTS_3D);
for (int piece_i = 0; piece_i < solution->size(); piece_i++) {
auto space = Voxel::Space{
.space=solution->at(piece_i),
.dim_x=dims[0],
.dim_y=dims[1],
.dim_z=dims[2],
};
auto piece_rotations = Voxel::getAllRotations(&space);
for (int rot_i = 0; rot_i < piece_rotations.size(); rot_i++) {
result[rot_i].push_back(piece_rotations[rot_i].space);
}
}
return result;
}
auto filter_unique(std::vector<SomaSolution> *solutions, int dims[3]) -> std::vector<SomaSolution> {
if (solutions->size() == 0) {
return std::vector<SomaSolution>();
}
auto unique_solns = std::vector<SomaSolution>{};
for (auto &solution : *solutions) {
auto found_match = false;
for (auto &rotation : get_solution_rotations(&solution, dims)) {
for (auto &unique_soln : unique_solns) {
auto is_match = true;
for (int piece_i = 0; piece_i < unique_soln.size(); piece_i++) {
if (rotation[piece_i] != unique_soln[piece_i]) {
is_match = false;
break;
}
}
if (is_match) {
found_match = true;
break;
}
}
if (found_match) {
depth++;
broke = true;
break;
}
}
if (!found_match) {
unique_solns.push_back(SomaSolution(solution));
}
if (!broke) {
curr_soln_stack.pop_back();
soln_spaces_stack.pop_back();
depth--;
}
}
std::cout << "Done. Found " << solns.size() << " solutions." << std::endl;
}
void backtrack_solve(Solver *solver, uint64 working_solution = 0, int curr_piece = 0) {
std::vector<uint64> *input = solver->input;
std::vector<int> *offsets = solver->offsets;
std::vector<SomaSolution> *solutions = solver->solutions;
int start = offsets->at(curr_piece);
int end = offsets->at(curr_piece + 1);
size_t num_pieces = offsets->size() - 1;
for (int i = start; i < end; i++) {
bool successful_fuse = !collides(working_solution, input->at(i));
if (successful_fuse) {
uint64 new_working_solution = working_solution | input->at(i);
solutions->back().at(curr_piece) = input->at(i);
if (curr_piece == num_pieces - 1) {
std::vector<uint64> last_soln = solutions->back();
solutions->push_back(SomaSolution(last_soln.begin(), last_soln.end()));
return;
} else {
backtrack_solve(solver, new_working_solution, curr_piece + 1);
}
}
return unique_solns;
}
auto solve(std::vector<uint64_t> *reprs_in, int dims[3]) -> std::vector<SomaSolution> {
auto reprs = *reprs_in;
auto offsets = std::vector<int>();
auto polycubes = std::vector<uint64_t>();
polycubes.reserve(reprs.size() * 10);
auto model_space = Voxel::Space{
.space={},
.dim_x=dims[0],
.dim_y=dims[1],
.dim_z=dims[2],
};
offsets.push_back(0);
auto space = model_space;
space.space = reprs[0];
Voxel::cullEmptySpace(&space);
auto positions = Voxel::getAllPositionsInPrism(&space, dims);
polycubes.insert(polycubes.end(), positions.begin(), positions.end());
for (int i = 1; i < reprs.size(); i++) {
offsets.push_back(polycubes.size());
auto space = model_space;
space.space = reprs[i];
Voxel::cullEmptySpace(&space);
auto perms = Voxel::getAllPermutationsInPrism(&space, dims);
polycubes.insert(polycubes.end(), perms.begin(), perms.end());
}
offsets.push_back(polycubes.size());
auto solutions = std::vector<SomaSolution>{std::vector<uint64_t>(reprs.size())};
auto solver = Solver{
.input=&polycubes,
.offsets=&offsets,
.solutions=&solutions,
};
backtrack_solve(&solver);
return filter_unique(solver.solutions, dims);
}
auto interactive_cmd_line_solve_soma() -> void {
int dims[3] = { 3, 3, 3 };
//get_dims_input(dims);
//std::cout << '\n';
//auto reprs = get_reprs_input(dims[0]*dims[1]*dims[2]);
std::cout << "Great. Calculating solutions...\n";
auto solutions = SomaSolve::solve(&SomaSolve::STD_SOMA, std::array<int, 3>{ 3, 3, 3 }.data());
std::cout << solutions.size() << " solutions found." << std::endl;
if (curr_piece == 0) {
solutions->pop_back();
}
}
std::vector<SomaSolution> get_solution_rotations(SomaSolution *solution, int dims[3]) {
std::vector<SomaSolution> result = std::vector<SomaSolution>(NUM_ROTS_3D);
for (int piece_i = 0; piece_i < solution->size(); piece_i++) {
Space space = {
solution->at(piece_i),
dims[0],
dims[1],
dims[2],
};
std::vector<Space> piece_rotations = getAllRotations(&space);
for (int rot_i = 0; rot_i < piece_rotations.size(); rot_i++) {
result[rot_i].push_back(piece_rotations[rot_i].space);
}
}
return result;
}
std::vector<SomaSolution> filter_unique(std::vector<SomaSolution> *solutions, int dims[3]) {
if (solutions->size() == 0) {
return std::vector<SomaSolution>();
}
std::vector<SomaSolution> unique_solns = std::vector<SomaSolution>{};
for (std::vector<uint64> &solution : *solutions) {
bool found_match = false;
for (SomaSolution &rotation : get_solution_rotations(&solution, dims)) {
for (auto &unique_soln : unique_solns) {
bool is_match = true;
for (int piece_i = 0; piece_i < unique_soln.size(); piece_i++) {
if (rotation[piece_i] != unique_soln[piece_i]) {
is_match = false;
break;
}
}
if (is_match) {
found_match = true;
break;
}
}
if (found_match) {
break;
}
}
if (!found_match) {
unique_solns.push_back(SomaSolution(solution));
}
}
return unique_solns;
}
std::vector<SomaSolution> solve(std::vector<uint64> *reprs_in, int dims[3]) {
std::vector<uint64> reprs = *reprs_in;
std::vector<int> offsets = std::vector<int>();
std::vector<uint64> polycubes = std::vector<uint64>();
polycubes.reserve(reprs.size() * 10);
Space model_space = {
{},
dims[0],
dims[1],
dims[2],
};
offsets.push_back(0);
Space space = model_space;
space.space = reprs[0];
cullEmptySpace(&space);
std::vector<uint64> positions = getAllPositionsInPrism(&space, dims);
polycubes.insert(polycubes.end(), positions.begin(), positions.end());
for (int i = 1; i < reprs.size(); i++) {
offsets.push_back(polycubes.size());
Space space = model_space;
space.space = reprs[i];
cullEmptySpace(&space);
std::vector<uint64> perms = getAllPermutationsInPrism(&space, dims);
polycubes.insert(polycubes.end(), perms.begin(), perms.end());
}
offsets.push_back(polycubes.size());
std::vector<SomaSolution> solutions = {std::vector<uint64>(reprs.size())};
Solver solver = {
&polycubes,
&offsets,
&solutions,
};
backtrack_solve(&solver);
return filter_unique(solver.solutions, dims);
}
void interactive_cmd_line_solve_soma() {
int dims[3] = { 3, 3, 3 };
//get_dims_input(dims);
//std::cout << '\n';
//auto reprs = get_reprs_input(dims[0]*dims[1]*dims[2]);
std::cout << "Great. Calculating solutions...\n";
std::vector<SomaSolution> solutions = solve(&STD_SOMA, dims);
std::cout << solutions.size() << " solutions found." << std::endl;
}

View File

@@ -1,10 +1,7 @@
#include <cstdint>
#include <vector>
namespace SomaSolve {
extern std::vector<uint64_t> STD_SOMA;
using SomaSolution = std::vector<uint64_t>;
auto solve(std::vector<uint64_t> *reprs_in, int dims[3]) -> std::vector<SomaSolution>;
auto interactive_cmd_line_solve_soma() -> void;
}
extern std::vector<uint64_t> STD_SOMA;
typedef std::vector<uint64_t> SomaSolution;
std::vector<SomaSolution> solve(std::vector<uint64_t> *reprs_in, int dims[3]);
void interactive_cmd_line_solve_soma();

View File

@@ -5,284 +5,282 @@
#include <cstdint>
#include "VoxelSpace.h"
namespace Voxel {
auto index(int dim_y, int dim_z, int x, int y, int z) -> int {
return dim_y * dim_z * x + dim_z * y + z;
int index(int dim_y, int dim_z, int x, int y, int z) {
return dim_y * dim_z * x + dim_z * y + z;
}
// ┌ ┐ ┌ ┐ ┌ ┐
// │ 1, 0, 0 │ │ x │ │ x │
// │ 0, 0, -1 │ * │ y │ = │-z │
// │ 0, 1, 0 │ │ z │ │ y │
// └ ┘ └ ┘ └ ┘
int newIndexRotX(Space *space, int x, int y, int z) {
return space->dim_z * space->dim_y * x + space->dim_y * (space->dim_z - 1 - z) + y;
}
// ┌ ┐ ┌ ┐ ┌ ┐
// │ 0, 0, 1 │ │ x │ │ z │
// │ 0, 1, 0 │ * │ y │ = │-y │
// │ -1, 0, 0 │ │ z │ │ x │
// └ ┘ └ ┘ └ ┘
int newIndexRotY(Space *space, int x, int y, int z) {
return space->dim_y * space->dim_x * z + space->dim_x * y + (space->dim_x - 1 - x);
}
// ┌ ┐ ┌ ┐ ┌ ┐
// │ 0, -1, 0 │ │ x │ │-y │
// │ 1, 0, 0 │ * │ y │ = │ x │
// │ 0, 0, 1 │ │ z │ │ z │
// └ ┘ └ ┘ └ ┘
int newIndexRotZ(Space *space, int x, int y, int z) {
return space->dim_x * space->dim_z * (space->dim_y - 1 - y) + space->dim_z * x + z;
}
uint64 toggle(uint64_t space, int index) {
space ^= 1ul << index;
return space;
}
uint64 set(uint64_t space, int index, bool val) {
if (val) {
space |= 1ul << index;
} else {
space &= ~(1ul << index);
}
return space;
}
// ┌ ┐ ┌ ┐ ┌ ┐
// │ 1, 0, 0 │ │ x │ │ x │
// │ 0, 0, -1 │ * │ y │ = │-z │
// │ 0, 1, 0 │ │ z │ │ y │
// └ ┘ └ ┘ └ ┘
auto newIndexRotX(Space *space, int x, int y, int z) -> int {
return space->dim_z * space->dim_y * x + space->dim_y * (space->dim_z - 1 - z) + y;
}
bool collides(uint64_t a, uint64_t b) {
return (a | b) != (a ^ b);
}
// ┌ ┐ ┌ ┐ ┌ ┐
// │ 0, 0, 1 │ │ x │ │ z │
// │ 0, 1, 0 │ * │ y │ = │-y │
// │ -1, 0, 0 │ │ z │ │ x │
// └ ┘ └ ┘ └ ┘
auto newIndexRotY(Space *space, int x, int y, int z) -> int {
return space->dim_y * space->dim_x * z + space->dim_x * y + (space->dim_x - 1 - x);
}
bool collides(Space *a, Space *b) {
return (a->space | b->space) != (a->space ^ b->space);
}
// ┌ ┐ ┌ ┐ ┌ ┐
// │ 0, -1, 0 │ │ x │ │-y │
// │ 1, 0, 0 │ * │ y │ = │ x │
// │ 0, 0, 1 │ │ z │ │ z │
// └ ┘ └ ┘ └ ┘
auto newIndexRotZ(Space *space, int x, int y, int z) -> int {
return space->dim_x * space->dim_z * (space->dim_y - 1 - y) + space->dim_z * x + z;
}
bool filledAt(Space *space, int x, int y, int z) {
uint64 mask = 1ul << (space->dim_y * space->dim_z * x + space->dim_z * y + z);
return (space->space & mask) != 0ul;
}
auto toggle(uint64_t space, int index) -> uint64_t {
space ^= 1ul << index;
return space;
}
Extrema getExtrema(Space *space) {
Extrema extrema = {
0,
space->dim_x,
0,
space->dim_y,
0,
space->dim_z,
};
auto set(uint64_t space, int index, bool val) -> uint64_t {
if (val) {
space |= 1ul << index;
} else {
space &= ~(1ul << index);
}
return space;
}
auto collides(uint64_t a, uint64_t b) -> bool {
return (a | b) != (a ^ b);
}
auto collides(Space *a, Space *b) -> bool {
return (a->space | b->space) != (a->space ^ b->space);
}
auto filledAt(Space *space, int x, int y, int z) -> bool {
auto mask = 1ul << (space->dim_y * space->dim_z * x + space->dim_z * y + z);
return (space->space & mask) != 0ul;
}
auto getExtrema(Space *space) -> Extrema {
auto extrema = Extrema{
.xMax=0,
.xMin=space->dim_x,
.yMax=0,
.yMin=space->dim_y,
.zMax=0,
.zMin=space->dim_z,
};
for (int x = 0; x < space->dim_x; x++) {
for (int y = 0; y < space->dim_y; y++) {
for (int z = 0; z < space->dim_z; z++) {
if (filledAt(space, x, y, z)) {
if (x > extrema.xMax) extrema.xMax = x;
if (x < extrema.xMin) extrema.xMin = x;
if (y > extrema.yMax) extrema.yMax = y;
if (y < extrema.yMin) extrema.yMin = y;
if (z > extrema.zMax) extrema.zMax = z;
if (z < extrema.zMin) extrema.zMin = z;
}
for (int x = 0; x < space->dim_x; x++) {
for (int y = 0; y < space->dim_y; y++) {
for (int z = 0; z < space->dim_z; z++) {
if (filledAt(space, x, y, z)) {
if (x > extrema.xMax) extrema.xMax = x;
if (x < extrema.xMin) extrema.xMin = x;
if (y > extrema.yMax) extrema.yMax = y;
if (y < extrema.yMin) extrema.yMin = y;
if (z > extrema.zMax) extrema.zMax = z;
if (z < extrema.zMin) extrema.zMin = z;
}
}
}
return extrema;
}
auto cullEmptySpace(Space *space) -> void {
auto extrema = getExtrema(space);
auto space_index = 0;
auto newSpace = 0ul;
for (int x = extrema.xMin; x <= extrema.xMax; x++) {
for (int y = extrema.yMin; y <= extrema.yMax; y++) {
for (int z = extrema.zMin; z <= extrema.zMax; z++) {
if (filledAt(space, x, y, z)) {
newSpace |= 1ul << space_index;
}
space_index++;
return extrema;
}
void cullEmptySpace(Space *space) {
Extrema extrema = getExtrema(space);
int space_index = 0;
uint64 newSpace = 0ul;
for (int x = extrema.xMin; x <= extrema.xMax; x++) {
for (int y = extrema.yMin; y <= extrema.yMax; y++) {
for (int z = extrema.zMin; z <= extrema.zMax; z++) {
if (filledAt(space, x, y, z)) {
newSpace |= 1ul << space_index;
}
space_index++;
}
}
}
space->dim_x = extrema.xMax - extrema.xMin + 1;
space->dim_y = extrema.yMax - extrema.yMin + 1;
space->dim_z = extrema.zMax - extrema.zMin + 1;
space->space = newSpace;
}
void rotate90X(Space *space) {
uint64 new_space = 0;
for (int x = 0; x < space->dim_x; x++) {
for (int y = 0; y < space->dim_y; y++) {
for (int z = 0; z < space->dim_z; z++) {
if (filledAt(space, x, y, z)) {
new_space |= 1 << newIndexRotX(space, x, y, z);
}
}
}
space->dim_x = extrema.xMax - extrema.xMin + 1;
space->dim_y = extrema.yMax - extrema.yMin + 1;
space->dim_z = extrema.zMax - extrema.zMin + 1;
space->space = newSpace;
}
int temp = space->dim_y;
space->dim_y = space->dim_z;
space->dim_z = temp;
space->space = new_space;
}
auto rotate90X(Space *space) -> void {
auto new_space = 0ul;
for (int x = 0; x < space->dim_x; x++) {
for (int y = 0; y < space->dim_y; y++) {
for (int z = 0; z < space->dim_z; z++) {
if (filledAt(space, x, y, z)) {
new_space |= 1 << newIndexRotX(space, x, y, z);
}
void rotate90Y(Space *space) {
uint64 new_space = 0;
for (int x = 0; x < space->dim_x; x++) {
for (int y = 0; y < space->dim_y; y++) {
for (int z = 0; z < space->dim_z; z++) {
if (filledAt(space, x, y, z)) {
new_space |= 1 << newIndexRotY(space, x, y, z);
}
}
}
auto temp = space->dim_y;
space->dim_y = space->dim_z;
space->dim_z = temp;
space->space = new_space;
}
int temp = space->dim_x;
space->dim_x = space->dim_z;
space->dim_z = temp;
space->space = new_space;
}
auto rotate90Y(Space *space) -> void {
auto new_space = 0ul;
for (int x = 0; x < space->dim_x; x++) {
for (int y = 0; y < space->dim_y; y++) {
for (int z = 0; z < space->dim_z; z++) {
if (filledAt(space, x, y, z)) {
new_space |= 1 << newIndexRotY(space, x, y, z);
}
void rotate90Z(Space *space) {
uint64 new_space = 0;
for (int x = 0; x < space->dim_x; x++) {
for (int y = 0; y < space->dim_y; y++) {
for (int z = 0; z < space->dim_z; z++) {
if (filledAt(space, x, y, z)) {
new_space |= 1 << newIndexRotZ(space, x, y, z);
}
}
}
auto temp = space->dim_x;
space->dim_x = space->dim_z;
space->dim_z = temp;
space->space = new_space;
}
int temp = space->dim_x;
space->dim_x = space->dim_y;
space->dim_y = temp;
space->space = new_space;
}
auto rotate90Z(Space *space) -> void {
auto new_space = 0ul;
for (int x = 0; x < space->dim_x; x++) {
for (int y = 0; y < space->dim_y; y++) {
for (int z = 0; z < space->dim_z; z++) {
if (filledAt(space, x, y, z)) {
new_space |= 1 << newIndexRotZ(space, x, y, z);
}
}
bool isMatch(Space *a, Space *b) {
return a->space == b->space
&& a->dim_x == b->dim_x
&& a->dim_y == b->dim_y
&& a->dim_z == b->dim_z;
}
void pushNewUniqueSpins(std::vector<Space> *existingSpaces, Space* spaceToSpin) {
Space spins[4] = {};
spins[0] = *spaceToSpin;
for (int i = 0; i < 3; i++) {
spins[i + 1] = spins[i];
rotate90X(&spins[i + 1]);
}
for (int i = 0; i < 4; i++) {
bool matchFound = false;
for (Space &existingSpace : *existingSpaces) {
if (isMatch(&existingSpace, &spins[i])) {
matchFound = true;
break;
}
}
auto temp = space->dim_x;
space->dim_x = space->dim_y;
space->dim_y = temp;
space->space = new_space;
}
auto isMatch(Space *a, Space *b) -> bool {
return a->space == b->space
&& a->dim_x == b->dim_x
&& a->dim_y == b->dim_y
&& a->dim_z == b->dim_z;
}
auto pushNewUniqueSpins(std::vector<Space> *existingSpaces, Space* spaceToSpin) -> void {
Space spins[4] = {};
spins[0] = *spaceToSpin;
for (int i = 0; i < 3; i++) {
spins[i + 1] = spins[i];
rotate90X(&spins[i + 1]);
if (!matchFound) {
existingSpaces->push_back(spins[i]);
}
for (int i = 0; i < 4; i++) {
auto matchFound = false;
for (auto &existingSpace : *existingSpaces) {
if (isMatch(&existingSpace, &spins[i])) {
matchFound = true;
break;
}
}
if (!matchFound) {
existingSpaces->push_back(spins[i]);
}
}
}
auto pushXAxisSpins(std::vector<Space> *existingSpaces, Space* spaceToSpin) -> void {
auto refSpace = *spaceToSpin;
for (int i = 0; i < 4; i++) {
rotate90X(&refSpace);
existingSpaces->push_back(refSpace);
}
}
auto getUniqueRotations(Space *space) -> std::vector<Space> {
auto rotations = std::vector<Space>();
rotations.reserve(24);
auto refSpace = *space;
cullEmptySpace(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
rotate90Z(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
return rotations;
}
auto getAllRotations(Space *space) -> std::vector<Space> {
auto rotations = std::vector<Space>();
rotations.reserve(24);
auto refSpace = *space;
pushXAxisSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
rotate90Z(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
return rotations;
}
auto getAllPositionsInPrism(Space *space, int prism_dims[3]) -> std::vector<uint64_t> {
auto cubePositions = std::vector<uint64_t>();
if (space->dim_x > prism_dims[0] || space->dim_y > prism_dims[1] || space->dim_z > prism_dims[2]) {
return cubePositions;
}
auto xPositionCount = prism_dims[0] - space->dim_x + 1;
auto yPositionCount = prism_dims[1] - space->dim_y + 1;
auto zPositionCount = prism_dims[2] - space->dim_z + 1;
for (int x = 0; x < xPositionCount; x++) {
for (int y = 0; y < yPositionCount; y++) {
for (int z = 0; z < zPositionCount; z++) {
auto new_space = 0ul;
for (int posX = 0; posX < space->dim_x; posX++) {
for (int posY = 0; posY < space->dim_y; posY++) {
for (int posZ = 0; posZ < space->dim_z; posZ++) {
auto set_val = filledAt(space, posX, posY, posZ);
auto index_to_set = index(prism_dims[1], prism_dims[2], x + posX, y + posY, z + posZ);
new_space = set(new_space, index_to_set, set_val);
}
}
}
cubePositions.push_back(new_space);
}
}
}
return cubePositions;
}
auto getAllPermutationsInPrism(Space *space, int prism_dims[3]) -> std::vector<uint64_t> {
auto rotations = getUniqueRotations(space);
auto result = std::vector<uint64_t>();
for (auto &rotation : rotations) {
auto positions = getAllPositionsInPrism(&rotation, prism_dims);
result.insert(result.end(), positions.begin(), positions.end());
}
return result;
}
auto size(uint64_t space) -> int {
auto size = 0;
for (int i = 0; i < 64; i++) {
if ((space & (1ul << i)) != 0) {
size++;
}
}
return size;
}
}
void pushXAxisSpins(std::vector<Space> *existingSpaces, Space* spaceToSpin) {
Space refSpace = *spaceToSpin;
for (int i = 0; i < 4; i++) {
rotate90X(&refSpace);
existingSpaces->push_back(refSpace);
}
}
std::vector<Space> getUniqueRotations(Space *space) {
std::vector<Space> rotations = std::vector<Space>();
rotations.reserve(24);
auto refSpace = *space;
cullEmptySpace(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
rotate90Z(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
return rotations;
}
std::vector<Space> getAllRotations(Space *space) {
std::vector<Space> rotations = {};
rotations.reserve(24);
Space refSpace = *space;
pushXAxisSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
rotate90Z(&refSpace);
pushXAxisSpins(&rotations, &refSpace);
return rotations;
}
std::vector<uint64> getAllPositionsInPrism(Space *space, int prism_dims[3]) {
std::vector<uint64> cubePositions = {};
if (space->dim_x > prism_dims[0] || space->dim_y > prism_dims[1] || space->dim_z > prism_dims[2]) {
return cubePositions;
}
int xPositionCount = prism_dims[0] - space->dim_x + 1;
int yPositionCount = prism_dims[1] - space->dim_y + 1;
int zPositionCount = prism_dims[2] - space->dim_z + 1;
for (int x = 0; x < xPositionCount; x++) {
for (int y = 0; y < yPositionCount; y++) {
for (int z = 0; z < zPositionCount; z++) {
uint64 new_space = 0;
for (int posX = 0; posX < space->dim_x; posX++) {
for (int posY = 0; posY < space->dim_y; posY++) {
for (int posZ = 0; posZ < space->dim_z; posZ++) {
bool set_val = filledAt(space, posX, posY, posZ);
int index_to_set = index(prism_dims[1], prism_dims[2], x + posX, y + posY, z + posZ);
new_space = set(new_space, index_to_set, set_val);
}
}
}
cubePositions.push_back(new_space);
}
}
}
return cubePositions;
}
std::vector<uint64> getAllPermutationsInPrism(Space *space, int prism_dims[3]) {
std::vector<Space> rotations = getUniqueRotations(space);
std::vector<uint64> result = std::vector();
for (auto &rotation : rotations) {
auto positions = getAllPositionsInPrism(&rotation, prism_dims);
result.insert(result.end(), positions.begin(), positions.end());
}
return result;
}
int size(uint64_t space) {
int size = 0;
for (int i = 0; i < 64; i++) {
if ((space & (1ul << i)) != 0) {
size++;
}
}
return size;
}

View File

@@ -2,67 +2,65 @@
#define VOXELSPACE_H
#include <vector>
#include <cstdint>
#include "lib/djstdlib/core.h"
namespace Voxel {
constexpr int NUM_ROTS_3D = 24;
constexpr int NUM_ROTS_3D = 24;
struct Extrema {
int xMax;
int xMin;
int yMax;
int yMin;
int zMax;
int zMin;
};
struct Extrema {
int xMax;
int xMin;
int yMax;
int yMin;
int zMax;
int zMin;
};
struct Space {
uint64_t space;
int dim_x;
int dim_y;
int dim_z;
};
struct Space {
uint64 space;
int dim_x;
int dim_y;
int dim_z;
};
auto newIndexRotX(Space *space, int x, int y, int z) -> int;
int newIndexRotX(Space *space, int x, int y, int z);
auto newIndexRotY(Space *space, int x, int y, int z) -> int;
int newIndexRotY(Space *space, int x, int y, int z);
auto newIndexRotZ(Space *space, int x, int y, int z) -> int;
int newIndexRotZ(Space *space, int x, int y, int z);
auto toggle(uint64_t space, int index) -> uint64_t;
uint64 toggle(uint64 space, int index);
auto set(uint64_t space, int index, bool val) -> uint64_t;
uint64 set(uint64 space, int index, bool val);
auto collides(Space *a, Space *b) -> bool;
auto collides(uint64_t a, uint64_t b) -> bool;
bool collides(Space *a, Space *b);
bool collides(uint64 a, uint64 b);
auto add(Space *a, Space *b) -> Space;
Space add(Space *a, Space *b);
auto filledAt(Space *space, int x, int y, int z) -> bool;
bool filledAt(Space *space, int x, int y, int z);
auto getExtrema(Space *space) -> Extrema;
Extrema getExtrema(Space *space);
auto cullEmptySpace(Space *space) -> void;
void cullEmptySpace(Space *space);
auto isMatch(Space *a, Space *b) -> bool;
bool isMatch(Space *a, Space *b);
auto rotate90X(Space *space) -> void;
void rotate90X(Space *space);
auto rotate90Y(Space *space) -> void;
void rotate90Y(Space *space);
auto rotate90Z(Space *space) -> void;
void rotate90Z(Space *space);
auto pushNewUniqueSpins(std::vector<Space> *existingSpaces, Space* spaceToSpin) -> void;
void pushNewUniqueSpins(std::vector<Space> *existingSpaces, Space* spaceToSpin);
auto getUniqueRotations(Space *space) -> std::vector<Space>;
std::vector<Space> getUniqueRotations(Space *space);
auto getAllRotations(Space *space) -> std::vector<Space>;
std::vector<Space> getAllRotations(Space *space);
auto getAllPositionsInPrism(Space *space, int prism_dims[3]) -> std::vector<uint64_t>;
std::vector<uint64> getAllPositionsInPrism(Space *space, int prism_dims[3]);
auto getAllPermutationsInPrism(Space *space, int prism_dims[3]) -> std::vector<uint64_t>;
std::vector<uint64> getAllPermutationsInPrism(Space *space, int prism_dims[3]);
auto size(uint64_t space) -> int;
}
int size(uint64 space);
#endif

View File

@@ -1,9 +0,0 @@
pub usingnamespace @cImport({
@cInclude("glad/glad.h");
@cInclude("GLFW/glfw3.h");
@cDefine("STB_IMAGE_IMPLEMENTATION", "");
@cDefine("TINYOBJ_LOADER_C_IMPLEMENTATION", "");
@cInclude("loaders/stb_image.h");
@cInclude("loaders/tinyobj.h");
});

View File

@@ -1,11 +1,8 @@
#include <cstdint>
#include <glm/ext/vector_float3.hpp>
#include <string>
#include <math.h>
#include <iostream>
#include "Color.h"
#include "../lib/djstdlib/core.h"
auto hue_to_rgb(float p, float q, float t) -> float {
real32 hue_to_rgb(float p, float q, float t) {
if (t < 0) {
t += 1;
} else if (t > 1) {
@@ -17,7 +14,7 @@ auto hue_to_rgb(float p, float q, float t) -> float {
return p;
};
auto hsl_to_hex(float h, float s, float l) -> glm::vec3 {
glm::vec3 hsl_to_hex(real32 h, real32 s, real32 l) {
h /= 360;
s /= 100;
l /= 100;
@@ -34,7 +31,7 @@ auto hsl_to_hex(float h, float s, float l) -> glm::vec3 {
return glm::vec3(r, g, b);
}
auto Color::color_from_index(int index) -> glm::vec3 {
glm::vec3 color_from_index(int index) {
auto color_wheel_cycle = floorf(index / 6.0f);
auto darkness_cycle = floorf(index / 12.0f);
auto spacing = (360.0f / 6.0f);

View File

@@ -1,5 +1,3 @@
#include <glm/ext/vector_float3.hpp>
namespace Color {
auto color_from_index(int index) -> glm::vec3;
};
glm::vec3 color_from_index(int index);

View File

@@ -1,43 +0,0 @@
fn hue_to_rgb(p: f32, q: f32, t: f32) f32 {
if (t < 0) {
t += 1;
} else if (t > 1) {
t -= 1;
}
if (t < 1.0 / 6) return p + (q - p) * 6 * t;
if (t < 1.0 / 2) return q;
if (t < 2.0 / 3) return p + (q - p) * (2.0 / 3 - t) * 6;
return p;
}
fn hsl_to_hex(h: f32, s: f32, l: f32) @Vector(3, f32) {
h /= 360;
s /= 100;
l /= 100;
const r: f32;
const g: f32;
const b: f32;
if (s == 0) {
r = l;
g = l;
b = l;
} else {
const q = if (l < 0.5) l * (1 + s) else l + s - l * s;
const p = 2 * l - q;
r = hue_to_rgb(p, q, h + 1.0 / 3);
g = hue_to_rgb(p, q, h);
b = hue_to_rgb(p, q, h - 1.0 / 3);
}
return @Vector(3, f32){ r, g, b };
}
pub fn color_from_index(index: i32) @Vector(3, f32) {
const color_wheel_cycle = @floor(index / 6.0);
const darkness_cycle = @floor(index / 12.0);
const spacing = (360.0 / 6.0);
const offset = if (color_wheel_cycle == 0) 0 else spacing / (color_wheel_cycle + 2);
const hue = spacing * (index % 6) + offset;
const saturation = 100.0f;
const lightness = 1.0f / (2 + darkness_cycle) * 100;
return hsl_to_hex(hue, saturation, lightness);
}

View File

@@ -1,6 +1,6 @@
#include <iostream>
#include "Mesh.h"
#include "loaders/tinyobj.h"
#include "../lib/loaders/tinyobj.h"
auto Mesh::init(const char* obj_file) -> void {
auto reader = tinyobj::ObjReader();

View File

@@ -1,7 +1,7 @@
#ifndef LEDDA_MESH_H
#define LEDDA_MESH_H
#include "glad/glad.h"
#include "../lib/glad/glad.h"
#include "geometry.h"
struct Mesh {
@@ -11,8 +11,8 @@ struct Mesh {
unsigned int vbo_norm;
unsigned int ebo;
unsigned int num_indices;
auto init(const char* obj_file) -> void;
auto init(const LeddaGeometry::Shape* shape) -> void;
void init(const char* obj_file);
void init(const Shape* shape);
};
#endif

View File

@@ -1,94 +0,0 @@
const std = @import("std");
const c = @import("../c.zig");
const djleddaGeom = @import("djleddaGeom.zig");
pub const Mesh = struct {
vao: c_uint,
vbo_xyz: c_uint,
vbo_uv: c_uint,
vbo_norm: c_uint,
ebo: c_uint,
num_indices: c_uint,
pub fn from_shape(shape: *const djleddaGeom.Shape) void {
const mesh = Mesh{};
mesh.num_indices = shape.indices.len;
c.glGenVertexArrays(1, &mesh.vao);
c.glGenBuffers(1, &mesh.vbo_xyz);
c.glGenBuffers(1, &mesh.vbo_uv);
c.glGenBuffers(1, &mesh.ebo);
c.glBindVertexArray(mesh.vao);
c.glBindBuffer(c.GL_ARRAY_BUFFER, mesh.vbo_xyz);
c.glBufferData(c.GL_ARRAY_BUFFER, shape.xyz.ptr * @sizeOf(float), shape.xyz, c.GL_STATIC_DRAW);
c.glVertexAttribPointer(0, 3, c.GL_FLOAT, c.GL_FALSE, 3 * @sizeOf(f32), @as(*void, 0));
c.glEnableVertexAttribArray(0);
c.glBindBuffer(c.GL_ARRAY_BUFFER, mesh.vbo_uv);
c.glBufferData(c.GL_ARRAY_BUFFER, shape.uv.ptr * @sizeOf(f32), shape.uv, c.GL_STATIC_DRAW);
c.glVertexAttribPointer(1, 2, c.GL_FLOAT, c.GL_FALSE, 2 * @sizeOf(f32), @as(*void, 0));
c.glEnableVertexAttribArray(1);
c.glBindBuffer(c.GL_ELEMENT_ARRAY_BUFFER, mesh.ebo);
c.glBufferData(c.GL_ELEMENT_ARRAY_BUFFER, shape.indices.len * @sizeOf(c_uint), shape.indices.ptr, c.GL_STATIC_DRAW);
}
// pub fn init(obj_file: *[]const u8) void {
// const reader = c.tinyobj.ObjReader();
// const success = reader.ParseFromFile(obj_file);
// std.debug.print("{}\n", .{reader.Error()});
//
// const attrib = reader.GetAttrib();
//
// const indices_t = reader.GetShapes().at(0).mesh.indices;
// const indices = ArrayList(c_uint)(indices_t.size());
//
// const vertices = ArrayList()(3*indices_t.size());
// const normals = ArrayList()(3*indices_t.size());
// const texcoords = ArrayList()(2*indices_t.size());
//
// for (int i = 0; i < indices_t.size(); i++) {
// const vertex_data = indices_t[i];
// vertices[3*i] = attrib.vertices[3*vertex_data.vertex_index];
// vertices[3*i+1] = attrib.vertices[3*vertex_data.vertex_index + 1];
// vertices[3*i+2] = attrib.vertices[3*vertex_data.vertex_index + 2];
//
// normals[3*i] = attrib.normals[3*vertex_data.normal_index];
// normals[3*i+1] = attrib.normals[3*vertex_data.normal_index + 1];
// normals[3*i+2] = attrib.normals[3*vertex_data.normal_index + 2];
//
// texcoords[2*i] = attrib.texcoords[2*vertex_data.texcoord_index];
// texcoords[2*i+1] = attrib.texcoords[2*vertex_data.texcoord_index + 1];
//
// indices[i] = i;
// }
//
// num_indices = indices_t.size();
// glGenVertexArrays(1, &vao);
// glGenBuffers(1, &vbo_xyz);
// glGenBuffers(1, &vbo_uv);
// glGenBuffers(1, &vbo_norm);
// //glGenBuffers(1, &ebo);
//
// glBindVertexArray(vao);
//
// glBindBuffer(GL_ARRAY_BUFFER, vbo_xyz);
// glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);
// glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
// glEnableVertexAttribArray(0);
//
// glBindBuffer(GL_ARRAY_BUFFER, vbo_uv);
// glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(float), texcoords.data(), GL_STATIC_DRAW);
// glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
// glEnableVertexAttribArray(1);
//
// glBindBuffer(GL_ARRAY_BUFFER, vbo_norm);
// glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(float), normals.data(), GL_STATIC_DRAW);
// glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
// glEnableVertexAttribArray(2);
//
// //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
// //glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
// }
};

View File

@@ -1,81 +0,0 @@
#ifndef ORBIT_CONTROLS_H
#define ORBIT_CONTROLS_H
#include "glad/glad.h"
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "loaders/stb_image.h"
constexpr auto ROTATION_FACTOR = 1.0f / 200.0f;
struct Point {
float x;
float y;
};
class OrbitControls {
private:
bool dragging;
bool hovered;
bool scrolling;
bool flyingEnabled;
float lastX;
float lastY;
Point lastScroll1;
Point lastScroll2;
glm::vec3 y_axis;
glm::vec3 x_axis;
glm::vec3 start;
Entity* orbited_object;
OrbitControls(Entity* orbited, Camera* camera) {
camera = camera;
orbited_object = orbited;
y_axis = orbited_object.worldToLocal(camera.up);
x_axis = orbited_object.position.sub(camera.position);
x_axis /= sqrt(pow(x_axis.x) + pow(x_axis.y, 2) + pow(x_axis.z, 2));
x_axis = glm::cross(x_axis, y_axis);
start = orbited_object.rotation;
this.element.addEventListener('wheel', (ev) => this.handleScroll(ev));
this.element.addEventListener('mouseover', () => this.hovered = true);
this.element.addEventListener('mouseout', () => this.hovered = false);
this.element.addEventListener('mousedown', (ev) => this.handleMouseDown(ev));
window.addEventListener('mousemove', (ev) => this.handleMove(ev));
window.addEventListener('mouseup', () => this.dragging = false);
}
on_mouse_down(event) {
if (event.button === 1) {
this.object.setRotationFromEuler(this.start);
}
if (!this.dragging) {
this.lastX = event.x;
this.lastY = event.y;
this.dragging = true;
}
}
on_mouse_move(event) {
if (dragging) {
auto x_diff = event.movementX * ROTATION_FACTOR;
auto y_diff = event.movementY * ROTATION_FACTOR;
glm::rotate(&orbited_object, x_diff, &y_axis);
//rotate on world axis ???
glm::rotate(&orbited_object, y_diff &x_axis);
}
}
on_scroll(event) {
if (this.flyingEnabled && this.hovered) {
for (const fliable of this.fliables) {
const direction = event.deltaY / Math.abs(event.deltaY);
fliable.flyBy(direction / 10);
}
}
}
}
#endif

View File

@@ -1,43 +1,42 @@
#include "glad/glad.h"
#include <array>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include "Shader.h"
#include "../lib/djstdlib/core.h"
#include "../lib/glad/glad.h"
enum ShaderType {
fragment=GL_FRAGMENT_SHADER,
vertex=GL_VERTEX_SHADER,
};
auto create_shader(const char* file_path, ShaderType shader_type, char* info_log) -> unsigned int {
uint32 create_shader(const char* file_path, ShaderType shader_type, char* info_log) {
std::stringstream shader_stream;
std::ifstream shader_file;
shader_file.open(file_path);
shader_stream << shader_file.rdbuf();
shader_file.close();
auto shader_string = shader_stream.str();
const auto shader_code = shader_string.c_str();
std::string string = shader_stream.str();
const char *shader_code = string.c_str();
auto vertex_shader = glCreateShader(shader_type);
GLuint vertex_shader = glCreateShader(shader_type);
glShaderSource(vertex_shader, 1, &shader_code, NULL);
glCompileShader(vertex_shader);
int success;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
auto shader_type_name = shader_type == ShaderType::fragment ? "FRAGMENT" : "VERTEX";
const char* shader_type_name = shader_type == ShaderType::fragment ? "FRAGMENT" : "VERTEX";
std::cout << "ERROR::SHADER::" << shader_type_name << "::COMPILATION_FAILED\n" << info_log << std::endl;
}
return vertex_shader;
}
auto Shader::init(const char* vertex_path, const char* fragment_path) -> void {
auto info_log = std::array<char, 512>();
auto vertex_shader = create_shader(vertex_path, ShaderType::vertex, info_log.data());
auto fragment_shader = create_shader(fragment_path, ShaderType::fragment, info_log.data());
void Shader::init(const char* vertex_path, const char* fragment_path) {
char info_log[512] = {0};
uint32 vertex_shader = create_shader(vertex_path, ShaderType::vertex, info_log);
uint32 fragment_shader = create_shader(fragment_path, ShaderType::fragment, info_log);
prog_id = glCreateProgram();
glAttachShader(prog_id, vertex_shader);
@@ -47,8 +46,8 @@ auto Shader::init(const char* vertex_path, const char* fragment_path) -> void {
int success;
glGetProgramiv(prog_id, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(prog_id, 512, NULL, info_log.data());
std::cout << "ERROR::SHADER::PROGRAM::LINK_FAILED\n" << info_log.data() << std::endl;
glGetProgramInfoLog(prog_id, 512, NULL, info_log);
std::cout << "ERROR::SHADER::PROGRAM::LINK_FAILED\n" << info_log << std::endl;
}
glDeleteShader(vertex_shader);

View File

@@ -3,7 +3,7 @@
struct Shader {
unsigned int prog_id;
auto init(const char* vertex_path, const char* fragment_path) -> void;
void init(const char* vertex_path, const char* fragment_path);
};
#endif

View File

@@ -1,56 +0,0 @@
const c = @import("../c.zig");
const std = @import("std");
const ShaderType = enum(u32) {
fragment = c.GL_FRAGMENT_SHADER,
vertex = c.GL_VERTEX_SHADER,
};
fn create_shader(file_path: []const u8, shader_type: ShaderType, info_log: *[]const u8, allocator: *std.mem.Allocator) c_uint {
const file = try std.fs.openFileAbsolute(file_path);
const file_reader = file.reader(file);
const shader_code = std.ArrayList(u8);
shader_code.initCapacity(allocator, 1024);
defer allocator.free(shader_code);
file_reader.readAllArrayList(shader_code, 1024 * 1024);
const vertex_shader = c.glCreateShader(shader_type);
c.glShaderSource(vertex_shader, 1, &shader_code.items, c.NULL);
c.glCompileShader(vertex_shader);
const success: i32 = undefined;
c.glGetShaderiv(vertex_shader, c.GL_COMPILE_STATUS, &success);
if (success != 0) {
c.glGetShaderInfoLog(vertex_shader, 512, c.NULL, info_log);
const shader_type_name = if (shader_type == ShaderType.fragment) "FRAGMENT" else "VERTEX";
std.debug.print("ERROR::SHADER::{}::COMPILATION_FAILED\n{}\n", .{ shader_type_name, info_log });
}
return vertex_shader;
}
const Shader = struct {
prog_id: c_uint,
pub fn init(self: Shader, vertex_path: *[]const u8, fragment_path: *[]const u8, allocator: *std.mem.Allocator) void {
const info_log = [512]u8{};
const vertex_shader = create_shader(vertex_path, ShaderType.vertex, &info_log, allocator);
const fragment_shader = create_shader(fragment_path, ShaderType.fragment, &info_log, allocator);
self.prog_id = c.glCreateProgram();
c.glAttachShader(self.prog_id, vertex_shader);
c.glAttachShader(self.prog_id, fragment_shader);
c.glLinkProgram(self.prog_id);
const success: c_uint = undefined;
c.glGetProgramiv(self.prog_id, c.GL_LINK_STATUS, &success);
if (!success) {
c.glGetProgramInfoLog(self.prog_id, 512, c.NULL, &info_log);
std.debug.print("ERROR::SHADER::PROGRAM::LINK_FAILED\n{}\n", .{info_log});
}
c.glDeleteShader(vertex_shader);
c.glDeleteShader(fragment_shader);
}
};

View File

@@ -1,9 +1,9 @@
#include "Texture.h"
#include <iostream>
#include "loaders/stb_image.h"
#include "glad/glad.h"
#include "../lib/loaders/stb_image.h"
#include "../lib/glad/glad.h"
auto Texture::init(const char* source_path) -> void {
void Texture::init(const char* source_path) {
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
@@ -12,7 +12,7 @@ auto Texture::init(const char* source_path) -> void {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int nr_channels;
auto data = stbi_load(source_path, &width, &height, &nr_channels, 0);
stbi_uc *data = stbi_load(source_path, &width, &height, &nr_channels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);

View File

@@ -5,7 +5,7 @@ struct Texture {
unsigned int tex_id;
int width;
int height;
auto init(const char* source_path) -> void;
void init(const char* source_path);
};
#endif

View File

@@ -1,57 +0,0 @@
// Buffer layout:
// X, Y, Z, U, V
pub const Shape = struct {
indices: []c_uint,
uv: []f32,
xyz: []f32,
};
const triangle_vertices = []f32{
-0.5, -0.5, 0.0, 1.0, 1.0,
0.5, -0.5, 0.0, 0.5, 0.5,
0.0, 0.5, 0.0, 0.0, 0.0,
};
const triangle_indices = []c_uint{ 0, 1, 2 };
const cube_vertices = []f32{ -0.5, -0.5, -0.5, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0, 1.0, -0.5, 0.5, 0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, -0.5, 1.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, 0.5, 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 1.0, 1.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, 0.5, 0.0, 0.0, -0.5, 0.5, -0.5, 0.0, 1.0 };
const cube_indices = []c_uint{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
const square_xyz = []f32{
0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, -0.5, 0.0,
-0.5, 0.5, 0.0,
};
const square_uv = []f32{
1.0, 1.0,
1.0, 0.0,
0.0, 0.0,
0.0, 1.0,
};
const square_indices = []c_uint{
0, 1, 3,
1, 2, 3,
};
pub const TRIANGLE = Shape{
.indices = triangle_indices,
.uv = triangle_vertices,
.xyz = triangle_vertices,
};
pub const SQUARE = Shape{
.indices = square_indices,
.uv = square_uv,
.xyz = square_xyz,
};
pub const CUBE = Shape{
.indices = cube_indices,
.uv = triangle_vertices,
.xyz = triangle_vertices,
};

View File

@@ -1,20 +1,20 @@
#include <array>
#include "geometry.h"
#include "../lib/djstdlib/core.h"
// Buffer layout:
// X, Y, Z, U, V
auto triangle_vertices = std::to_array<float>({
real32 triangle_vertices[] = {
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 0.5f, 0.5f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
});
};
auto triangle_indices = std::to_array<unsigned int>({
uint32 triangle_indices[] = {
0, 1, 2
});
};
auto cube_vertices = std::to_array<float>({
real32 cube_vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
@@ -56,57 +56,55 @@ auto cube_vertices = std::to_array<float>({
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
});
};
auto cube_indices = std::to_array<unsigned int>({
uint32 cube_indices[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
});
};
auto square_xyz = std::to_array<float>({
real32 square_xyz[] = {
0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
});
};
auto square_uv = std::to_array<float>({
real32 square_uv[] = {
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
});
};
auto square_indices = std::to_array<unsigned int>({
uint32 square_indices[] = {
0, 1, 3,
1, 2, 3,
});
};
namespace LeddaGeometry {
const Shape TRIANGLE = {
.indices = triangle_indices.data(),
.indices_size = sizeof(triangle_indices),
.uv = triangle_vertices.data(),
.uv_size = sizeof(triangle_vertices),
.xyz = triangle_vertices.data(),
.xyz_size = sizeof(triangle_vertices),
};
const Shape TRIANGLE = {
.indices = triangle_indices,
.indices_size = ArrayCount(triangle_indices),
.uv = triangle_vertices,
.uv_size = ArrayCount(triangle_vertices),
.xyz = triangle_vertices,
.xyz_size = ArrayCount(triangle_vertices),
};
const Shape SQUARE = {
.indices = square_indices.data(),
.indices_size = square_indices.size(),
.uv = square_uv.data(),
.uv_size = square_uv.size(),
.xyz = square_xyz.data(),
.xyz_size = square_xyz.size(),
};
const Shape SQUARE = {
.indices = square_indices,
.indices_size = ArrayCount(square_indices),
.uv = square_uv,
.uv_size = ArrayCount(square_uv),
.xyz = square_xyz,
.xyz_size = ArrayCount(square_xyz),
};
const Shape CUBE = {
.indices = cube_indices.data(),
.indices_size = cube_indices.size(),
.uv = triangle_vertices.data(),
.uv_size = triangle_vertices.size(),
.xyz = triangle_vertices.data(),
.xyz_size = triangle_vertices.size(),
};
}
const Shape CUBE = {
.indices = cube_indices,
.indices_size = ArrayCount(cube_indices),
.uv = triangle_vertices,
.uv_size = ArrayCount(triangle_vertices),
.xyz = triangle_vertices,
.xyz_size = ArrayCount(triangle_vertices),
};

View File

@@ -1,20 +1,18 @@
#ifndef LEDDA_GEOMETRY_H
#define LEDDA_GEOMETRY_H
#include <cstddef>
#include <stddef.h>
namespace LeddaGeometry {
struct Shape {
unsigned int* indices;
size_t indices_size;
float* uv;
size_t uv_size;
float* xyz;
size_t xyz_size;
};
extern const Shape TRIANGLE;
extern const Shape SQUARE;
extern const Shape CUBE;
}
struct Shape {
unsigned int* indices;
size_t indices_size;
float* uv;
size_t uv_size;
float* xyz;
size_t xyz_size;
};
extern const Shape TRIANGLE;
extern const Shape SQUARE;
extern const Shape CUBE;
#endif

14
src/lib/djstdlib/app.cpp Normal file
View File

@@ -0,0 +1,14 @@
#include <stdio.h>
#include "core.cpp"
#include "core.h"
int main(int argc, char **argv) {
int statusCode = 0;
initialiseCore();
Arena *arena = arenaAlloc(Megabytes(64));
list<string> args = getArgs(arena, argc, argv);
prinft("%S", strSplit(arena, "-"_s, "hallo-world"_s));
return statusCode;
}

511
src/lib/djstdlib/core.cpp Normal file
View File

@@ -0,0 +1,511 @@
#include <unistd.h> // TODO(djledda): get outta here
#include <math.h>
#include <string.h>
#define STB_SPRINTF_IMPLEMENTATION
#include "core.h"
#include "os.cpp"
void *pushSize(Arena *arena, size_t bytes) {
if (arena->capacity - arena->head >= bytes) {
void *ptr = (char *)arena->memory + arena->head;
arena->head += bytes;
return ptr;
}
return 0;
}
Arena *arenaAlloc(size_t capacity) {
Arena *result = (Arena *)os_alloc(sizeof(Arena) + capacity);
result->memory = result + sizeof(Arena);
result->capacity = capacity;
result->head = 0;
return result;
}
void arenaFree(Arena *arena) {
os_free(arena, arena->capacity);
}
void arenaFreeFrom(Arena *arena, size_t position) {
arena->head = position;
}
Arena *scratchArenas[2];
void initialiseCore() {
for (EachInArray(scratchArenas, i)) {
scratchArenas[i] = arenaAlloc(Megabytes(64));
}
}
Scratch scratchStart(Arena **conflicts, size_t conflictCount) {
Scratch scratch = {0};
for (size_t i = 0; i < ArrayCount(scratchArenas); i += 1) {
bool conflicted = false;
for (Arena **conflict = conflicts; conflict < conflicts + conflictCount; conflict += 1) {
if (*conflict == scratchArenas[i]) {
conflicted = true;
break;
}
}
if (conflicted == false) {
scratch.arena = scratchArenas[i];
scratch.start = scratch.arena->head;
break;
}
}
return scratch;
}
#define DeferLoop(begin_stmnt, end_stmnt) for(int __defer_i = ((begin_stmnt), 0); __defer_i < 1; (++__defer_i, (end_stmnt)))
#define WithScratch(scratchName) Scratch scratchName; DeferLoop(scratchName = scratchStart(0, 0), scratchEnd(scratchName))
void scratchEnd(Scratch scratch) {
arenaFreeFrom(scratch.arena, scratch.start);
}
template <typename T>
T *appendList(list<T> *list, T element) {
if (list->head < list->length) {
list->data[list->head] = element;
list->head++;
return &(list->data[list->head - 1]);
} else {
return 0;
}
}
template <typename T>
void zeroListFull(list<T> *list) {
memset(list->data, 0, list->head * sizeof(T));
}
template <typename T>
void zeroList(list<T> *list) {
list->head = 0;
memset(list->data, 0, list->head * sizeof(T));
}
inline string operator""_s(const char *cstrLiteral, unsigned long length) {
return {
(char *)cstrLiteral,
length,
};
}
const char *cstring(Arena *arena, list<char> buf) {
char *arr = PushArray(arena, char, buf.length + 1);
memmove(arr, buf.data, buf.length);
arr[buf.length] = '\0';
return arr;
}
const char *cstring(Arena *arena, string str) {
char *arr = PushArray(arena, char, str.length + 1);
memmove(arr, str.str, str.length);
arr[str.length] = '\0';
return arr;
}
bool strEql(string s1, string s2) {
if (s1.length != s2.length) {
return false;
}
for (size_t i = 0; i < s1.length; i++) {
if (s1.str[i] != s2.str[i]) {
return false;
}
}
return true;
}
size_t calcStringLen(const char *str) {
size_t size = 0;
if (str == NULL) {
return size;
}
while (str[size] != '\0') {
size++;
}
return size;
}
string strFromCString(Arena *arena, const char *str) {
string result = PushString(arena, calcStringLen(str));
memcpy(result.str, str, result.length);
return result;
}
string strReverse(Arena *arena, string str) {
string reversed = PushString(arena, str.length);
for (
size_t mainIndex = str.length - 1, reversedIndex = 0;
mainIndex < str.length;
mainIndex--, reversedIndex++
) {
reversed.str[reversedIndex] = str.str[mainIndex];
}
return reversed;
}
string strPrintfv(Arena *arena, const char *fmt, va_list args) {
string result = {0};
va_list argsCopy;
va_copy(argsCopy, args);
uint64 bufSize = stb_vsnprintf(0, 0, fmt, args) + 1;
result.str = PushArray(arena, char, bufSize);
result.length = bufSize - 1;
stb_vsnprintf((char *)result.str, (int)bufSize, fmt, argsCopy);
return result;
}
string strPrintf(Arena *arena, const char *fmt, ...) {
string result = {0};
va_list args;
va_start(args, fmt);
result = strPrintfv(arena, fmt, args);
va_end(args);
return result;
}
template <typename T>
list<T> listSlice(list<T> l, size_t start, size_t stop) {
if (stop == 0) {
stop = l.head;
}
// TODO(djledda): maybe assert instead
if (stop > l.head || start > stop) {
return {0};
}
return {
l.data + start,
stop - start,
stop - start,
};
}
string strSlice(string str, size_t start, size_t stop) {
if (stop == 0) {
stop = str.length;
}
// TODO(djledda): maybe assert instead
if (stop > str.length || start > stop) {
return {0};
}
return {
str.str + start,
stop - start,
};
}
string strSlice(char *data, size_t start, size_t stop) {
return {
data + start,
stop - start,
};
}
bool stringContains(string str, char c) {
for (size_t i = 0; i < str.length; i++) {
if (str.str[i] == c) {
return true;
}
}
return false;
}
string NUMERIC_CHARS = "0123456789"_s;
inline bool isNumeric(char c) {
return stringContains(NUMERIC_CHARS, c);
}
list<string> strSplit(Arena *arena, string splitStr, string inputStr) {
list<string> result = {0};
if (inputStr.length > 0) {
size_t splitCount = 0;
size_t c = 0;
size_t start = 0;
void *beginning = (char *)arena->memory + arena->head;
while (c < inputStr.length - splitStr.length) {
if (strEql(strSlice(inputStr, c, c + splitStr.length), splitStr)) {
string *splitString = PushStruct(arena, string);
splitString->str = inputStr.str + start;
splitString->length = c - start;
splitCount++;
start = c + 1;
}
c++;
}
string *splitString = PushStruct(arena, string);
splitString->str = inputStr.str + start;
splitString->length = inputStr.length - start;
splitCount++;
result.data = (string *)beginning,
result.head = splitCount,
result.length = splitCount;
}
return result;
}
int8 parsePositiveInt(string str, size_t *lengthPointer) {
size_t numEnd = 0;
char currChar = str.str[numEnd];
while (numEnd < str.length && isNumeric(currChar)) {
currChar = str.str[++numEnd];
*lengthPointer += 1;
}
*lengthPointer -= 1;
if (numEnd > 0) {
uint8 result = 0;
for (size_t i = 0; i < numEnd; i++) {
result *= 10;
result += str.str[i] - '0';
}
return result;
} else {
return -1;
}
}
real32 parsePositiveReal32(string str, size_t *lengthPointer) {
real32 result = NAN;
string wholePartStr = string{0};
string fractionalPartStr = string{0};
bool split = false;
size_t c = 0;
while (c < str.length) {
if (str.str[c] == '.') {
wholePartStr.str = str.str;
wholePartStr.length = c;
fractionalPartStr.str = str.str + c + 1;
fractionalPartStr.length = str.length - c - 1;
split = true;
break;
}
c++;
}
if (split) {
int wholePart = parsePositiveInt(wholePartStr, lengthPointer);
*lengthPointer += 1;
int fractionalPart = parsePositiveInt(fractionalPartStr, lengthPointer);
if (wholePart >= 0 && fractionalPart >= 0) {
real32 fractionalPartMultiplier = 1.0f / powf(10.0f, (real32)fractionalPartStr.length);
result = (real32)wholePart + (real32)fractionalPart * (real32)fractionalPartMultiplier;
}
} else if (c > 0) {
result = (real32)parsePositiveInt(str, lengthPointer);
}
return result;
}
string readEntireFile(Arena *arena, string filename) {
#if OS_WINDOWS
string result = {0};
HANDLE fileHandle = CreateFileA(cstring(arena, filename), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if (fileHandle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER fileSize;
if (GetFileSizeEx(fileHandle, &fileSize)) {
string readfile = PushString(arena, (size_t)fileSize.QuadPart);
if (readfile.str) {
DWORD bytesRead;
if (ReadFile(fileHandle, readfile.str, (DWORD)fileSize.QuadPart, &bytesRead, NULL) && (fileSize.QuadPart == bytesRead)) {
result = readfile;
}
}
}
CloseHandle(fileHandle);
}
return result;
#elif OS_LINUX
FILE *input = fopen((char *)filename.str, "r");
struct stat st;
stat((char *)filename.str, &st);
size_t fsize = st.st_size;
string readBuffer = PushString(arena, fsize);
fread(readBuffer.str, sizeof(byte), readBuffer.length, input);
fclose(input);
return readBuffer;
#endif
}
bool writeEntireFile(Arena *arena, string filename, const byte *contents, size_t contentsLength) {
bool result = false;
#if OS_WINDOWS
HANDLE fileHandle = CreateFileA(cstring(arena, filename), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);
if (fileHandle != INVALID_HANDLE_VALUE) {
DWORD bytesWritten;
if (WriteFile(fileHandle, contents, (DWORD)contentsLength, &bytesWritten, NULL)) {
// file written successfully
result = bytesWritten == contentsLength;
}
CloseHandle(fileHandle);
}
#elif OS_LINUX
Assert(false);
#endif
return result;
}
bool fileAppend(Arena *arena, string filename, const byte *contents, size_t contentsLength) {
bool result = false;
#if OS_WINDOWS
HANDLE fileHandle = CreateFileA(cstring(arena, filename), FILE_APPEND_DATA | FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle != INVALID_HANDLE_VALUE) {
DWORD bytesWritten;
DWORD position = SetFilePointer(fileHandle, 0, NULL, FILE_END);
if (WriteFile(fileHandle, contents, (DWORD)contentsLength, &bytesWritten, NULL)) {
// file written successfully
result = bytesWritten == contentsLength;
}
CloseHandle(fileHandle);
}
#elif OS_LINUX
Assert(false);
#endif
return result;
}
list<string> getArgs(Arena *arena, int argc, char **argv) {
list<string> args = PushList(arena, string, (size_t)argc);
for (int i = 1; i < argc; i++) {
appendList(&args, strFromCString(arena, argv[i]));
}
return args;
}
UnixTimestamp getSystemUnixTime() {
time_t now;
time(&now);
return (UnixTimestamp)now;
}
Timestamp timestampFromUnixTime(UnixTimestamp *unixTimestamp) {
tm *timestamp = gmtime((time_t *)&time);
return *timestamp;
}
string formatTimeHms(Arena *arena, UnixTimestamp time) {
local_persist const string format = "HH-MM-SS"_s;
string buf = PushString(arena, format.length);
tm *timestamp = gmtime((time_t *)&time);
strftime(buf.str, buf.length + 1, "%T", timestamp);
return buf;
}
string formatTimeHms(Arena *arena, Timestamp *time) {
local_persist const string format = "HH-MM-SS"_s;
string buf = PushString(arena, format.length);
strftime(buf.str, buf.length + 1, "%T", (tm *)time);
return buf;
}
string formatTimeYmd(Arena *arena, UnixTimestamp time) {
local_persist const string format = "YYYY-mm-dd"_s;
string buf = PushString(arena, format.length);
tm *timestamp = gmtime((time_t *)&time);
strftime(buf.str, buf.length + 1, "%Y-%m-%d", timestamp);
return buf;
}
string formatTimeYmd(Arena *arena, Timestamp *time) {
local_persist const string format = "YYYY-mm-dd"_s;
string buf = PushString(arena, format.length);
strftime(buf.str, buf.length + 1, "%Y-%m-%d", (tm *)time);
return buf;
}
function void __core_log(LogTarget target, const char *fmt, va_list argList) {
Scratch scratch = scratchStart(0, 0);
string result = strPrintfv(scratch.arena, fmt, argList);
#if OS_WINDOWS
DWORD done;
HANDLE stdHandle;
switch (target) {
case LogTarget_stdin:
stdHandle = GetStdHandle(STD_INPUT_HANDLE);
break;
case LogTarget_stdout:
stdHandle = GetStdHandle(STD_ERROR_HANDLE);
break;
case LogTarget_stderr:
stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
break;
default:
stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
break;
}
WriteFile(stdHandle, result.str, (DWORD)result.length, &done, 0);
#elif OS_LINUX
// TODO(djledda): finish implementation without cstdlib
switch (target) {
case LogTarget_stdin:
write(0, (const void *)result.str, result.length);
break;
case LogTarget_stderr:
fflush(stderr);
write(2, (const void *)result.str, result.length);
break;
case LogTarget_stdout:
default:
fflush(stdout);
write(1, (const void *)result.str, result.length);
break;
}
#endif
scratchEnd(scratch);
}
void logErr(const char *fmt, ...) {
va_list argList;
va_start(argList, fmt);
__core_log(LogTarget_stdout, fmt, argList);
va_end(argList);
}
function void logStdout(const char *fmt, ...) {
va_list argList;
va_start(argList, fmt);
__core_log(LogTarget_stdout, fmt, argList);
va_end(argList);
}
void log(const char *fmt, ...) {
va_list argList;
va_start(argList, fmt);
__core_log(LogTarget_stdout, fmt, argList);
va_end(argList);
}
void log(list<int> l, LogTarget target) {
void (*logFn)(const char *fmt, ...) = target == LogTarget_stdout ? &logStdout : &logErr;
logFn("{ ");
for (size_t i = 0; i < l.length; i++) {
if (i != 0) {
logFn(", ");
}
logFn("%i", l.data[i]);
}
logFn(" } length: %zu, head: %zu\n", l.length, l.head);
}
void log(list<string> l, LogTarget target) {
void (*logFn)(const char *fmt, ...) = target == LogTarget_stdout ? &logStdout : &logErr;
logFn("{ ");
for (size_t i = 0; i < l.length; i++) {
if (i != 0) {
logFn(", ");
}
logFn("\"%S\"", l.data[i]);
}
logFn(" } length: %zu, head: %zu\n", l.length, l.head);
}
int intCompare(const void *a, const void *b) {
int *x = (int *)a;
int *y = (int *)b;
return (*x > *y) - (*x < *y);
}

219
src/lib/djstdlib/core.h Normal file
View File

@@ -0,0 +1,219 @@
#ifndef CORE_H
#define CORE_H
// cstdlib includes
#include <math.h>
#include <stdint.h> // necessary for int type sizes
#include <stdio.h>
#include <time.h> // TODO(djledda): try not to depend on this one
// ### Misc macros ###
#if ENABLE_ASSERT
#define Assert(expression) if (!(expression)) {*(volatile int *)0 = 0;}
#else
#define Assert(expression)
#endif
#define function static
#define global static
#define local_persist static
// ### Types ###
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint8_t byte;
typedef float real32;
typedef double real64;
// ### Sizes and Numbers ###
#define Bytes(n) (n)
#define Kilobytes(n) (n << 10)
#define Megabytes(n) (n << 20)
#define Gigabytes(n) (((uint64)n) << 30)
#define Terabytes(n) (((uint64)n) << 40)
#define Thousand(n) ((n)*1000)
#define Million(n) ((n)*1000000)
#define Billion(n) ((n)*1000000000LL)
#define ArrayCount(arr) (sizeof(arr) / sizeof((arr)[0]))
// ### Arenas ###
struct Arena {
void *memory;
size_t capacity;
size_t head;
};
struct Scratch {
Arena *arena;
size_t start;
};
void *pushSize(Arena *arena, size_t bytes);
Arena *arenaAlloc(size_t capacity);
void arenaFree(Arena *arena);
void arenaFreeFrom(Arena *arena, size_t pos);
void initialiseCore();
Scratch scratchStart(Arena **conflicts, size_t conflictCount);
void scratchEnd(Scratch scratch);
#define PushArray(arena, type, size) (type *)pushSize(arena, sizeof(type) * (size))
#define PushStruct(arena, type) (type *)pushSize(arena, sizeof(type))
// ### Vectors ###
template <typename T>
union Vector2 {
struct {
T x;
T y;
};
T vec[2];
};
template <typename T>
inline function Vector2<T> vec2(T x, T y) {
Vector2<T> result = {0};
result.x = x;
result.y = y;
return result;
}
template <typename T>
union Vector3 {
struct {
T x;
T y;
T z;
};
T vec[3];
};
template <typename T>
inline function Vector3<T> vec3(T x, T y, T z) {
Vector3<T> result = {0};
result.x = x;
result.y = y;
result.z = z;
return result;
}
template <typename T>
union Vector4 {
struct {
T x;
T y;
T z;
T w;
};
T vec[4];
};
template <typename T>
inline function Vector4<T> vec4(T x, T y, T z, T w) {
Vector4<T> result = {0};
result.x = x;
result.y = y;
result.z = z;
result.w = w;
return result;
}
// ### Lists ###
template <typename T>
struct list {
T* data;
size_t length;
size_t head;
};
#define PushList(arena, type, size) (list<type>{ PushArray(arena, type, size), size, 0 })
#define PushFullList(arena, type, size) (list<type>{ PushArray(arena, type, size), size, size })
template <typename T> T *appendList(list<T> *list, T element);
template <typename T> void zeroList(list<T> *list);
template <typename T> void zeroListFull(list<T> *list);
template <typename T> list<T> listSlice(list<T> l, size_t start, size_t stop = 0);
// ### Strings ###
struct string {
char *str;
size_t length;
};
#define STB_SPRINTF_DECORATE(name) stb_##name // define this before including if you want to change the names
#include "vendor/stb_sprintf.h"
#define strlit(lit) (string{(char *)(lit), sizeof(lit) - 1})
#define PushString(arena, length) (string{ (char *)pushSize(arena, length), (length) })
string operator""_s(const char *cstrLiteral, unsigned long length);
// C Strings
const char *cstring(Arena *arena, list<char> buf);
const char *cstring(Arena *arena, string str);
size_t calcStringLen(const char *str);
string strFromCString(Arena *arena, const char *str);
bool strEql(string s1, string s2);
bool stringContains(string str, char c);
string strReverse(Arena *arena, string str);
string strSlice(string str, size_t start, size_t stop = 0);
string strSlice(char *data, size_t start, size_t stop = 0);
list<string> strSplit(Arena *arena, string splitStr, string inputStr);
string strPrintfv(Arena *arena, const char *fmt, va_list args);
string strPrintf(Arena *arena, const char *fmt, ...);
int8 parsePositiveInt(string str, size_t *lengthPointer);
real32 parsePositiveReal32(Arena *arena, string str, size_t *lengthPointer);
inline function bool isNumeric(char c);
// ### File IO ###
string readEntireFile(Arena *arena, string filename);
bool writeEntireFile(Arena *arena, string filename, const byte *contents, size_t contentsLength);
bool fileAppend(Arena *arena, string filename, const byte *contents, size_t contentsLength);
// ### Cmdline ###
list<string> getArgs(Arena *arena, int argc, char **argv);
// ### Time ###
typedef uint64 UnixTimestamp;
typedef tm Timestamp;
UnixTimestamp getSystemUnixTime();
Timestamp timestampFromUnixTime(UnixTimestamp *unixTimestamp);
string formatTimeHms(Arena *arena, UnixTimestamp time);
string formatTimeHms(Arena *arena, Timestamp *time);
string formatTimeYmd(Arena *arena, UnixTimestamp time);
string formatTimeYmd(Arena *arena, Timestamp *time);
// ### Linked Lists ###
// TODO(djledda): implement basic linked lists (based on arenas?)
// ### Logging ###
enum LogTarget {
LogTarget_stdout,
LogTarget_stdin,
LogTarget_stderr,
LogTarget_count,
};
void log(list<int> l, LogTarget target = LogTarget_stdout);
void log(list<string> l, LogTarget target = LogTarget_stdout);
void log(const char *fmt, ...);
void logError(const char *fmt, ...);
// ### Loops ###
#define EachIn(list, it) size_t it = 0; it < list.length; it++
#define EachInReversed(list, it) size_t it = list.length - 1; it >= 0 && it < list.length; it--
#define EachInArray(arr, it) size_t it = 0; it < ArrayCount(arr); ++it
// ### Misc ###
int intCompare(const void *a, const void *b);
#endif

12
src/lib/djstdlib/os.cpp Normal file
View File

@@ -0,0 +1,12 @@
#ifndef OS_CPP
#define OS_CPP
#if OS_WINDOWS
#include "os_win32.cpp"
#elif OS_LINUX
#include "os_linux.cpp"
#else
#error Development environment not supported.
#endif
#endif

12
src/lib/djstdlib/os.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef OS_H
#define OS_H
#include "core.h"
// ### Memory ###
void *os_alloc(size_t capacity);
void os_reserve(void *ptr);
void os_decommit(void *ptr);
void os_free(void *ptr, size_t freeSize);
#endif

View File

@@ -0,0 +1,24 @@
#ifndef OS_IMPL_LINUX_CPP
#define OS_IMPL_LINUX_CPP
#include "os.h"
#include <sys/mman.h>
#include <sys/stat.h>
void *os_alloc(size_t capacity) {
return mmap(0, capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
void os_commit(void *ptr) {
}
void os_decommit(void *ptr) {
}
void os_free(void *ptr, size_t size) {
int err = munmap(ptr, size);
Assert(err != -1);
}
#endif

View File

@@ -0,0 +1,21 @@
#ifndef OS_IMPL_WIN32_CPP
#define OS_IMPL_WIN32_CPP
#include "os.h"
#include "Windows.h"
void *os_alloc(size_t commitSize) {
return VirtualAlloc(NULL, commitSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
}
void os_reserve(void *ptr) {
}
void os_decommit(void *ptr) {
}
void os_free(void *ptr, size_t size) {
VirtualFree(ptr, NULL, MEM_RELEASE);
}
#endif

1923
src/lib/djstdlib/vendor/stb_sprintf.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +1,33 @@
#include <bitset>
#include <array>
#include <span>
#include <cstdint>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <optional>
#include "glad/glad.h"
#include "lib/glad/glad.h"
#include <glm/ext/matrix_transform.hpp>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "loaders/stb_image.h"
#include "lib/loaders/stb_image.h"
#include "gfx/geometry.h"
#include "gfx/Texture.h"
#include "gfx/Mesh.h"
#include "gfx/Shader.h"
#include "gfx/Color.h"
#include "VoxelSpace.h"
#include "SomaSolve.h"
#include "lib/djstdlib/core.cpp"
struct Entity;
struct Polycube;
struct SceneGraphNode;
auto new_entity() -> int;
auto get_entity(int id) -> Entity*;
auto get_scene_graph_node(int id) -> SceneGraphNode*;
auto new_graph_node() -> int;
int new_entity();
Entity *get_entity(int id);
SceneGraphNode *get_scene_graph_node(int id);
int new_graph_node();
auto print_mat(glm::mat4* matrix) -> void {
void print_mat(glm::mat4* matrix) {
auto mat = *matrix;
std::cout << mat[0][0] << mat[0][1] << mat[0][2] << mat[0][3] << std::endl;
std::cout << mat[1][0] << mat[1][1] << mat[1][2] << mat[1][3] << std::endl;
@@ -49,19 +43,19 @@ struct Camera {
glm::vec3 up;
glm::vec3 target;
auto init(float aspect_ratio = 800.0f / 600.0f) -> void {
void init(float aspect_ratio = 800.0f / 600.0f) {
view = glm::mat4();
proj = glm::perspective(glm::radians(45.0f), aspect_ratio, 0.1f, 100.0f);
pos = glm::vec3(0.0f);
up = glm::vec3(0.0f, 1.0f, 0.0f);
}
auto look_at(float x, float y, float z) -> void {
void look_at(float x, float y, float z) {
target = glm::vec3(x, y, z);
view = glm::lookAt(pos, target, up);
}
auto set_up(float up_x, float up_y, float up_z) -> void {
void set_up(float up_x, float up_y, float up_z) {
up = glm::vec3(up_x, up_y, up_z);
}
};
@@ -69,7 +63,7 @@ struct Camera {
struct GlobalAppState {
int current_polycube;
int last_polycube_visible;
Shader* active_shader;
Shader *active_shader;
std::vector<Polycube> polycubes;
};
GlobalAppState app_state;
@@ -80,8 +74,8 @@ struct WindowDims {
};
struct Entity {
Mesh* mesh;
Texture* tex;
Mesh *mesh;
Texture *tex;
bool visible;
int scene_graph_node;
};
@@ -95,19 +89,19 @@ struct SceneGraphNode {
std::vector<int> children;
std::optional<int> entity;
auto reset() -> void {
void reset() {
scale = glm::vec3(1.0f, 1.0f, 1.0f);
translation = glm::vec3(0.0f, 0.0f, 0.0f);
rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);
}
auto init() -> void {
void init() {
reset();
local = glm::mat4(1.0f);
world = local;
}
auto update_local() -> void {
void update_local() {
local = glm::scale(
glm::translate(
glm::mat4(1.0f),
@@ -122,8 +116,8 @@ struct Polycube {
int graph_node;
glm::vec3 color;
auto show() -> void {
auto node = get_scene_graph_node(graph_node);
void show() {
SceneGraphNode *node = get_scene_graph_node(graph_node);
for (auto &child : node->children) {
auto node = get_scene_graph_node(child);
if (node->entity) {
@@ -132,19 +126,19 @@ struct Polycube {
}
}
auto hide() -> void {
auto node = get_scene_graph_node(graph_node);
for (auto &child : node->children) {
auto node = get_scene_graph_node(child);
void hide() {
SceneGraphNode *node = get_scene_graph_node(graph_node);
for (int &child : node->children) {
SceneGraphNode *node = get_scene_graph_node(child);
if (node->entity) {
get_entity(*node->entity)->visible = false;
}
}
}
auto get_centre() -> glm::vec3 {
auto centre = glm::vec3(0.0f);
for (auto &child : get_scene_graph_node(graph_node)->children) {
glm::vec3 get_centre() {
glm::vec3 centre = glm::vec3(0.0f);
for (int &child : get_scene_graph_node(graph_node)->children) {
centre += get_scene_graph_node(child)->translation;
}
centre /= get_scene_graph_node(graph_node)->children.size();
@@ -159,17 +153,17 @@ struct Frame {
int y;
Camera* cam;
auto init(Camera* camera) -> void {
void init(Camera* camera) {
camera->init((float)width / (float)height);
cam = camera;
}
};
auto framebuffer_size_callback(GLFWwindow* window, int width, int height) -> void {
void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
glViewport(0, 0, width, height);
}
auto init_window_and_gl(WindowDims* window_dims) -> GLFWwindow* {
GLFWwindow *init_window_and_gl(WindowDims *window_dims) {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
@@ -193,19 +187,19 @@ auto init_window_and_gl(WindowDims* window_dims) -> GLFWwindow* {
return window;
}
auto gl_update_viewport(WindowDims* window_dims, Frame* frame) -> void {
void gl_update_viewport(WindowDims* window_dims, Frame* frame) {
glViewport(frame->x, window_dims->height - frame->y - frame->height, frame->width, frame->height);
}
auto cube_mesh = Mesh{};
auto wall_tex = Texture{};
auto entities = std::vector<Entity>();
auto scene_graph_nodes = std::vector<SceneGraphNode>();
Mesh cube_mesh = {0};
Texture wall_tex = {0};
std::vector<Entity> entities = std::vector<Entity>();
std::vector<SceneGraphNode> scene_graph_nodes = std::vector<SceneGraphNode>();
auto process_input(GLFWwindow *window) -> void {
static auto wireframe = false;
static auto last_frame_state_press_enter = false;
static auto last_frame_state_press = false;
void process_input(GLFWwindow *window) {
static bool wireframe = false;
static bool last_frame_state_press_enter = false;
static bool last_frame_state_press = false;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
@@ -232,7 +226,7 @@ auto process_input(GLFWwindow *window) -> void {
}
auto new_entity() -> int {
int new_entity() {
entities.emplace_back();
scene_graph_nodes.emplace_back();
entities.back().scene_graph_node = scene_graph_nodes.size();
@@ -240,21 +234,21 @@ auto new_entity() -> int {
return entities.size();
}
auto get_entity(int id) -> Entity* {
Entity *get_entity(int id) {
return &entities[id - 1];
}
auto get_scene_graph_node(int id) -> SceneGraphNode* {
SceneGraphNode *get_scene_graph_node(int id) {
return &scene_graph_nodes[id - 1];
}
auto new_graph_node() -> int {
int new_graph_node() {
scene_graph_nodes.emplace_back();
return scene_graph_nodes.size();
}
auto draw_entity(Entity* entity) -> void {
auto modelUniformLoc = glGetUniformLocation(app_state.active_shader->prog_id, "model");
void draw_entity(Entity *entity) {
GLint modelUniformLoc = glGetUniformLocation(app_state.active_shader->prog_id, "model");
glUniformMatrix4fv(modelUniformLoc, 1, GL_FALSE, glm::value_ptr(get_scene_graph_node(entity->scene_graph_node)->world));
glBindTexture(GL_TEXTURE_2D, entity->tex->tex_id);
glBindVertexArray(entity->mesh->vao);
@@ -262,17 +256,17 @@ auto draw_entity(Entity* entity) -> void {
//glDrawElements(GL_TRIANGLES, entity->mesh->num_indices, GL_UNSIGNED_INT, 0);
}
auto create_polycube_from_repr(Voxel::Space* repr) -> Polycube {
auto polycube_id = new_graph_node();
Polycube create_polycube_from_repr(Space *repr) {
int polycube_id = new_graph_node();
get_scene_graph_node(polycube_id)->init();
for (int x = 0; x < repr->dim_x; x++) {
for (int y = 0; y < repr->dim_y; y++) {
for (int z = 0; z < repr->dim_z; z++) {
if (Voxel::filledAt(repr, x, y, z)) {
auto polycube_segment = get_entity(new_entity());
if (filledAt(repr, x, y, z)) {
Entity *polycube_segment = get_entity(new_entity());
polycube_segment->mesh=&cube_mesh,
polycube_segment->tex=&wall_tex;
auto graph_node = get_scene_graph_node(polycube_segment->scene_graph_node);
SceneGraphNode *graph_node = get_scene_graph_node(polycube_segment->scene_graph_node);
graph_node->init();
graph_node->translation = glm::vec3(
-((repr->dim_z - 1)/2.0f) + z,
@@ -285,67 +279,67 @@ auto create_polycube_from_repr(Voxel::Space* repr) -> Polycube {
}
}
}
auto result = Polycube{
Polycube result = {
.graph_node=polycube_id,
.color=glm::vec3(1.0f),
};
return result;
}
auto recalculate_scene_graph(SceneGraphNode* top) -> void {
void recalculate_scene_graph(SceneGraphNode *top) {
if (top->children.size() == 0) {
return;
}
for (auto &node_id : top->children) {
auto graph_node = get_scene_graph_node(node_id);
for (int &node_id : top->children) {
SceneGraphNode *graph_node = get_scene_graph_node(node_id);
graph_node->update_local();
graph_node->world = top->world * graph_node->local;
recalculate_scene_graph(graph_node);
}
}
auto main_cmd() -> int {
SomaSolve::interactive_cmd_line_solve_soma();
int main_cmd() {
interactive_cmd_line_solve_soma();
return 0;
}
auto main_gfx() -> int {
auto window_dims = WindowDims{ 800, 600 };
auto window = init_window_and_gl(&window_dims);
if (window == nullptr) {
int main_gfx() {
WindowDims window_dims = { 800, 600 };
GLFWwindow *window = init_window_and_gl(&window_dims);
if (!window) {
return -1;
}
app_state = GlobalAppState{
app_state = {
.current_polycube=0,
.last_polycube_visible=6,
.active_shader=nullptr,
.active_shader=0,
.polycubes={},
};
auto phong_shader = Shader{};
Shader phong_shader = {0};
phong_shader.init("../assets/shaders/phong-solid.vertex.glsl", "../assets/shaders/phong-solid.fragment.glsl");
app_state.active_shader = &phong_shader;
cube_mesh.init("../assets/models/c000000.obj");
wall_tex.init("../assets/textures/brick-wall.jpg");
auto little_frame = Frame{ .width=80, .height=60, .x=20, .y=20 };
auto big_frame = Frame{ .width=800, .height=600, .x=0, .y=0 };
auto main_cam = Camera{};
auto other_cam = Camera{};
Frame little_frame = { .width=80, .height=60, .x=20, .y=20 };
Frame big_frame = { .width=800, .height=600, .x=0, .y=0 };
Camera main_cam = {};
Camera other_cam = {};
little_frame.init(&other_cam);
big_frame.init(&main_cam);
auto frames = std::vector{ &big_frame, &little_frame };
std::vector<Frame> frames = { &big_frame, &little_frame };
auto root_node = SceneGraphNode{};
SceneGraphNode root_node = {};
root_node.init();
for (int i = 0; i < SomaSolve::STD_SOMA.size(); i++) {
auto voxel_space = Voxel::Space{ SomaSolve::STD_SOMA[i], 3, 3, 3 };
Voxel::cullEmptySpace(&voxel_space);
auto polycube = create_polycube_from_repr(&voxel_space);
polycube.color = Color::color_from_index(i);
for (int i = 0; i < STD_SOMA.size(); i++) {
auto voxel_space = Space{ STD_SOMA[i], 3, 3, 3 };
cullEmptySpace(&voxel_space);
Polycube polycube = create_polycube_from_repr(&voxel_space);
polycube.color = color_from_index(i);
app_state.polycubes.push_back(polycube);
root_node.children.push_back(app_state.polycubes.back().graph_node);
}
@@ -353,18 +347,18 @@ auto main_gfx() -> int {
main_cam.pos = glm::vec3(4.0f, 4.0f, 4.0f);
main_cam.look_at(0.0f, 0.0f, 0.0f);
auto light_pos = glm::vec3(6.0f);
glm::vec3 light_pos = glm::vec3(6.0f);
glUseProgram(app_state.active_shader->prog_id);
auto view_loc = glGetUniformLocation(app_state.active_shader->prog_id, "view");
auto proj_loc = glGetUniformLocation(app_state.active_shader->prog_id, "projection");
auto light_pos_loc = glGetUniformLocation(app_state.active_shader->prog_id, "light_pos");
GLint view_loc = glGetUniformLocation(app_state.active_shader->prog_id, "view");
GLint proj_loc = glGetUniformLocation(app_state.active_shader->prog_id, "projection");
GLint light_pos_loc = glGetUniformLocation(app_state.active_shader->prog_id, "light_pos");
glUniform3fv(light_pos_loc, 1, glm::value_ptr(light_pos));
glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(main_cam.proj));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, glm::value_ptr(main_cam.view));
auto last_frame = glfwGetTime();
auto time_delta = 1.0f/60.0f;
real32 last_frame = glfwGetTime();
real32 time_delta = 1.0f/60.0f;
while (!glfwWindowShouldClose(window)) {
time_delta = glfwGetTime() - last_frame;
process_input(window);
@@ -379,16 +373,16 @@ auto main_gfx() -> int {
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
gl_update_viewport(&window_dims, &big_frame);
auto current_polycube = &app_state.polycubes[app_state.current_polycube];
Polycube *current_polycube = &app_state.polycubes[app_state.current_polycube];
get_scene_graph_node(current_polycube->graph_node)->rotation = glm::quat(glm::vec3(0, glfwGetTime() / 2, 0));
glBindVertexArray(cube_mesh.vao);
//glBindTexture(GL_TEXTURE_2D, entity.tex->tex_id);
recalculate_scene_graph(&root_node);
auto model_uniform_loc = glGetUniformLocation(app_state.active_shader->prog_id, "model");
auto solid_color_loc = glGetUniformLocation(app_state.active_shader->prog_id, "solid_color");
GLint model_uniform_loc = glGetUniformLocation(app_state.active_shader->prog_id, "model");
GLint solid_color_loc = glGetUniformLocation(app_state.active_shader->prog_id, "solid_color");
glUniform3fv(solid_color_loc, 1, glm::value_ptr(current_polycube->color));
for (auto &entity : entities) {
for (Entity &entity : entities) {
if (entity.visible) {
glUniformMatrix4fv(model_uniform_loc, 1, GL_FALSE, glm::value_ptr(get_scene_graph_node(entity.scene_graph_node)->world));
glDrawArrays(GL_TRIANGLES, 0, entity.mesh->num_indices);
@@ -404,7 +398,7 @@ auto main_gfx() -> int {
return 0;
}
auto main() -> int {
int main() {
return main_cmd();
}

View File

@@ -1,402 +0,0 @@
const std = @import("std");
const c = @import("c.zig");
const zm = @import("zm");
const Mesh = @import("gfx/Mesh.zig").Mesh;
const ArrayList = std.ArrayList;
fn print_mat(matrix: *const zm.Mat) void {
std.debug.print("{}, {}, {}, {}\n", .{ matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3] });
std.debug.print("{}, {}, {}, {}\n", .{ matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3] });
std.debug.print("{}, {}, {}, {}\n", .{ matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3] });
std.debug.print("{}, {}, {}, {}\n", .{ matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3] });
}
const Camera = struct {
view: zm.Mat = .{ zm.f32x4s(0.0), zm.f32x4s(0.0), zm.f32x4s(0.0), zm.f32x4s(0.0) },
proj: zm.Mat,
pos: zm.Vec = zm.f32x4s(0.0),
up: zm.Vec = zm.f32x4s(0.0),
target: zm.Vec,
pub fn init(self: Camera, aspect_ratio: f32) void {
self.proj = zm.perspectiveFovRh(std.math.degreesToRadians(45.0), aspect_ratio, 0.1, 100.0);
}
pub fn new(aspect_ratio: f32) Camera {
const cam = Camera{};
init(cam, aspect_ratio);
return cam;
}
pub fn look_at(self: Camera, x: f32, y: f32, z: f32) void {
self.target = zm.f32x4(x, y, z, 0.0);
self.view = zm.lookAtRh(self.pos, self.target, self.up);
}
pub fn set_up(self: Camera, up_x: f32, up_y: f32, up_z: f32) void {
self.up = zm.f32x4(up_x, up_y, up_z, 0.0);
}
};
const GlobalAppState = struct {
current_polycube: i32,
last_polycube_visible: i32,
active_shader: ?*Shader,
polycubes: ArrayList(Polycube),
};
const app_state: GlobalAppState = .{};
const WindowDims = struct {
width: u32,
height: u32,
};
const Entity = struct {
mesh: *Mesh,
tex: *Texture,
visible: bool,
scene_graph_node: i32,
};
const SceneGraphNode = struct {
local: zm.Mat,
world: zm.Mat,
translation: zm.Vec,
rotation: zm.Quat,
scale: zm.Vec,
children: ArrayList(i32),
entity: ?i32,
pub fn reset(self: SceneGraphNode) void {
self.scale = zm.f32x4(1.0, 1.0, 1.0, 0.0);
self.translation = zm.f32x4s(0.0);
self.rotation = zm.f32x4s(0.0);
}
pub fn init(self: SceneGraphNode) void {
self.reset();
self.local = zm.identity();
self.world = self.local;
}
pub fn update_local(self: SceneGraphNode) void {
const scaling = zm.scaling(self.scale);
const translation = zm.translation(self.translation);
const rotation = zm.quatToMat(self.rotation);
self.local = zm.mul(zm.mul(translation, rotation), scaling);
self.local = scaling(
zm.translate(
zm.identity(),
self.translation
) * toMat4(self.rotation),
self.scale
);
}
};
const Polycube = struct {
graph_node: i32,
color: zm.Vec,
pub fn show(self: Polycube) void {
const node = get_scene_graph_node(self.graph_node);
for (node.children.items) |child_id| {
const child_node = get_scene_graph_node(child_id);
if (child_node.entity) |entity_id| {
get_entity(entity_id).visible = true;
}
}
}
pub fn hide(self: Polycube) void {
const node = get_scene_graph_node(self.graph_node);
for (node.children.items) |child_id| {
const child_node = get_scene_graph_node(child_id);
if (child_node.entity) |entity_id| {
get_entity(entity_id).visible = false;
}
}
}
pub fn get_centre(self: Polycube) zm.Vec {
const centre = zm.Vec(0.0);
for (get_scene_graph_node(self.graph_node).children.items) |child_id| {
centre += get_scene_graph_node(child_id).translation;
}
centre /= get_scene_graph_node(self.graph_node).children.size();
return centre;
}
};
const Frame = struct {
width: i32,
height: i32,
x: i32,
y: i32,
cam: *Camera,
pub fn new(camera: *Camera, width: i32, height: i32) Frame {
const frame = Frame{};
camera.init(@as(f32, width) / @as(f32, height));
frame.cam = camera;
return frame;
}
};
fn framebuffer_size_callback(width: i32, height: i32) void {
c.glViewport(0, 0, width, height);
}
fn init_window_and_gl(window_dims: *WindowDims) ?*c.GLFWwindow {
c.glfwInit();
c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 4);
c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 6);
c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE);
const window = c.glfwCreateWindow(window_dims.width, window_dims.height, "Somaesque", c.NULL, c.NULL);
if (window == c.NULL) {
std.debug.print("Failed to create GLFW window");
c.glfwTerminate();
return null;
}
c.glfwMakeContextCurrent(window);
if (!c.gladLoadGLLoader(@as(c.GLADloadproc, c.glfwGetProcAddress))) {
std.debug.print("Failed to initialize GLAD");
return null;
}
c.glViewport(0, 0, 800, 600);
c.glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
c.glEnable(c.GL_DEPTH_TEST);
return window;
}
fn gl_update_viewport(window_dims: *WindowDims, frame: *Frame) void {
c.glViewport(frame.x, window_dims.height - frame.y - frame.height, frame.width, frame.height);
}
const cube_mesh = Mesh{};
const wall_tex = Texture{};
const entities = ArrayList(Entity);
const scene_graph_nodes = ArrayList(SceneGraphNode);
fn process_input(window: *c.GLFWwindow) void {
const static = struct {
wireframe: bool = false,
last_frame_state_press_enter: bool = false,
last_frame_state_press: bool = false,
};
if (c.glfwGetKey(window, c.GLFW_KEY_ESCAPE) == c.GLFW_PRESS) {
c.glfwSetWindowShouldClose(window, true);
}
if (c.glfwGetKey(window, c.GLFW_KEY_SPACE) == c.GLFW_PRESS and !static.last_frame_state_press) {
c.glPolygonMode(c.GL_FRONT_AND_BACK, if (!static.wireframe) c.GL_LINE else c.GL_FILL);
static.wireframe = !static.wireframe;
static.last_frame_state_press = true;
} else if (c.glfwGetKey(window, c.GLFW_KEY_SPACE) == c.GLFW_RELEASE) {
static.last_frame_state_press = false;
}
if (c.glfwGetKey(window, c.GLFW_KEY_ENTER) == c.GLFW_PRESS and !static.last_frame_state_press_enter) {
if (app_state.current_polycube == 6) {
app_state.current_polycube = 0;
} else {
app_state.current_polycube += 1;
}
static.last_frame_state_press_enter = true;
} else if (c.glfwGetKey(window, c.GLFW_KEY_ENTER) == c.GLFW_RELEASE) {
static.last_frame_state_press_enter = false;
}
}
fn new_entity() i32 {
entities.append(.{});
scene_graph_nodes.append(.{});
entities.items[entities.items.len - 1].scene_graph_node = scene_graph_nodes.items.len;
scene_graph_nodes.items[scene_graph_nodes.items.len - 1].entity = entities.items.len;
return entities.items.len;
}
fn get_entity(id: i32) ?*Entity {
if (entities.items[id - 1]) {
return &entities.items[id - 1];
}
return null;
}
fn get_scene_graph_node(id: i32) *SceneGraphNode {
if (scene_graph_nodes.items[id - 1]) {
return &scene_graph_nodes.items[id - 1];
}
return null;
}
fn new_graph_node() i32 {
scene_graph_nodes.append(.{});
return scene_graph_nodes.items.len;
}
fn draw_entity(entity: *Entity) void {
const modelUniformLoc = c.glGetUniformLocation(app_state.active_shader.prog_id, "model");
c.glUniformMatrix4fv(modelUniformLoc, 1, c.GL_FALSE, &get_scene_graph_node(entity.scene_graph_node).world);
c.glBindTexture(c.GL_TEXTURE_2D, entity.tex.tex_id);
c.glBindVertexArray(entity.mesh.vao);
c.glDrawArrays(c.GL_TRIANGLES, 0, entity.mesh.num_indices);
//c.glDrawElements(c.GL_TRIANGLES, entity.mesh.num_indices, c.GL_UNSIGNED_INT, 0);
}
fn create_polycube_from_repr(repr: *Voxel.Space) Polycube {
const polycube_id = new_graph_node();
get_scene_graph_node(polycube_id).init();
var x: usize = 1;
var y: usize = 1;
var z: usize = 1;
while (x < repr.dim_x) : (x += 1) {
while (y < repr.dim_y) : (y += 1) {
while (z < repr.dim_z) : (z += 1) {
if (Voxel.filledAt(repr, x, y, z)) {
const polycube_segment = get_entity(new_entity());
polycube_segment.mesh = &cube_mesh;
polycube_segment.tex = &wall_tex;
const graph_node = get_scene_graph_node(polycube_segment.scene_graph_node);
graph_node.init();
graph_node.translation = zm.f32x4(
-((repr.dim_z - 1)/2.0) + z,
((repr.dim_x - 1)/2.0) - x,
-((repr.dim_y - 1)/2.0) + y,
0.0,
);
graph_node.update_local();
get_scene_graph_node(polycube_id).children.append(polycube_segment.scene_graph_node);
}
}
}
}
const result = Polycube{
.graph_node = polycube_id,
.color = zm.f32x4s(1.0),
};
return result;
}
fn recalculate_scene_graph(top: *SceneGraphNode) void {
if (top.children.size() == 0) {
return;
}
for (top.children.items) |child_id| {
const graph_node = get_scene_graph_node(child_id);
graph_node.update_local();
graph_node.world = zm.mul(top.world, graph_node.local);
recalculate_scene_graph(graph_node);
}
}
pub fn main() void {
const window_dims = WindowDims{ 800, 600 };
const window = init_window_and_gl(&window_dims);
if (window == null) {
return -1;
}
app_state = GlobalAppState{
.current_polycube=0,
.last_polycube_visible=6,
.active_shader=null,
.polycubes={},
};
const phong_shader = Shader{};
phong_shader.init("../assets/shaders/phong-solid.vertex.glsl", "../assets/shaders/phong-solid.fragment.glsl");
app_state.active_shader = &phong_shader;
cube_mesh.init("../assets/models/c000000.obj");
wall_tex.init("../assets/textures/brick-wall.jpg");
const little_frame = Frame{ .width=80, .height=60, .x=20, .y=20 };
const big_frame = Frame{ .width=800, .height=600, .x=0, .y=0 };
const main_cam = Camera{};
const other_cam = Camera{};
little_frame.init(&other_cam);
big_frame.init(&main_cam);
const frames = [_]*Frame{ &big_frame, &little_frame };
const root_node = SceneGraphNode{};
root_node.init();
var i: usize = 0;
while (i < SomaSolve.STD_SOMA.items.len) : (i += 1) {
const voxel_space = voxel.Space{ SomaSolve.STD_SOMA[i], 3, 3, 3 };
voxel.cullEmptySpace(&voxel_space);
const polycube = create_polycube_from_repr(&voxel_space);
polycube.color = color.color_from_index(i);
app_state.polycubes.append(polycube);
root_node.children.append(app_state.polycubes.items[app_state.polycubes.items.len - 1].graph_node);
}
main_cam.pos = zm.f32x4(4.0, 4.0, 4.0, 0.0);
main_cam.look_at(0.0, 0.0, 0.0);
const light_pos = zm.f32x4(6.0, 6.0, 6.0, 0.0);
c.glUseProgram(app_state.active_shader.prog_id);
const view_loc = c.glGetUniformLocation(app_state.active_shader.prog_id, "view");
const proj_loc = c.glGetUniformLocation(app_state.active_shader.prog_id, "projection");
const light_pos_loc = c.glGetUniformLocation(app_state.active_shader.prog_id, "light_pos");
c.glUniform3fv(light_pos_loc, 1, &light_pos);
c.glUniformMatrix4fv(proj_loc, 1, GL_FALSE, &main_cam.proj);
c.glUniformMatrix4fv(view_loc, 1, GL_FALSE, &main_cam.view);
var last_frame = c.glfwGetTime();
var time_delta = 1.0/60.0;
while (!c.glfwWindowShouldClose(window)) {
time_delta = c.glfwGetTime() - last_frame;
process_input(window);
if (app_state.last_polycube_visible != app_state.current_polycube) {
app_state.polycubes[app_state.last_polycube_visible].hide();
app_state.polycubes[app_state.current_polycube].show();
app_state.last_polycube_visible = app_state.current_polycube;
}
c.glClearColor(0.0, 0.0, 0.0, 1.0);
c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT);
c.gl_update_viewport(&window_dims, &big_frame);
const current_polycube = &app_state.polycubes[app_state.current_polycube];
c.get_scene_graph_node(current_polycube.graph_node).rotation = zm.quatFromRollPitchYaw(0.0, c.glfwGetTime() / 2.0, 0.0);
c.glBindVertexArray(cube_mesh.vao);
//glBindTexture(GL_TEXTURE_2D, entity.tex->tex_id);
recalculate_scene_graph(&root_node);
const model_uniform_loc = c.glGetUniformLocation(app_state.active_shader.prog_id, "model");
const solid_color_loc = c.glGetUniformLocation(app_state.active_shader.prog_id, "solid_color");
c.glUniform3fv(solid_color_loc, 1, &current_polycube.color);
while (entities.items) |entity| {
if (entity.visible) {
c.glUniformMatrix4fv(model_uniform_loc, 1, c.GL_FALSE, &get_scene_graph_node(entity.scene_graph_node).world);
c.glDrawArrays(c.GL_TRIANGLES, 0, entity.mesh.num_indices);
//glDrawElements(GL_TRIANGLES, entity->mesh->num_indices, GL_UNSIGNED_INT, 0);
}
}
c.glfwSwapBuffers(window);
c.glfwPollEvents();
}
c.glfwTerminate();
return 0;
}
//test "simple test" {
// var list = std.ArrayList(i32).init(std.testing.allocator);
// defer list.deinit(); // try commenting this out and see if zig detects the memory leak!
// try list.append(42);
// try std.testing.expectEqual(@as(i32, 42), list.pop());
//}