summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralaric <alaric@netmythos.org>2024-04-05 06:23:00 -0700
committeralaric <alaric@netmythos.org>2024-04-05 06:23:00 -0700
commitde6948de605bb8b74052f2afd73b361abbdf8d50 (patch)
treedd83e54279f0427ed9e02b881d1989f8707a7cbb
parent92b20e1bf706b62466f9952465011d6a91364805 (diff)
downloadmenger-de6948de605bb8b74052f2afd73b361abbdf8d50.tar.gz
menger-de6948de605bb8b74052f2afd73b361abbdf8d50.zip
It is actually a Menger Sponge now
-rw-r--r--src/vertex.glsl4
-rw-r--r--src/wasm_msponge.zig160
-rw-r--r--src/webgl.zig9
3 files changed, 163 insertions, 10 deletions
diff --git a/src/vertex.glsl b/src/vertex.glsl
index 175565b..df628cf 100644
--- a/src/vertex.glsl
+++ b/src/vertex.glsl
@@ -2,12 +2,14 @@
in vec4 pos;
in vec3 col;
+in vec3 offset;
uniform mat4 mat;
out vec4 a_col;
void main() {
- gl_Position = pos * mat;
+ vec4 p = pos + vec4(offset, 0);
+ gl_Position = (p * mat);
a_col = vec4(col, 1);
}
diff --git a/src/wasm_msponge.zig b/src/wasm_msponge.zig
index 69cf211..943fd38 100644
--- a/src/wasm_msponge.zig
+++ b/src/wasm_msponge.zig
@@ -12,12 +12,19 @@ const MyProgram = webgl.Program(
&.{
.{ .identifier = "pos", .shader_name = "pos", .kind = .vec4 },
.{ .identifier = "col", .shader_name = "col", .kind = .vec3 },
+ .{
+ .identifier = "offset",
+ .shader_name = "offset",
+ .kind = .vec3,
+ .instance_divisor = 1,
+ },
},
);
var prog: MyProgram = undefined;
var vao: webgl.VertexArrayObject = undefined;
var pos_buffer: webgl.Buffer = undefined;
var col_buffer: webgl.Buffer = undefined;
+var offset_buffer: webgl.Buffer = undefined;
export fn init() void {
wasm.print("Hello Menger Sponge {d}!", .{2});
@@ -25,8 +32,10 @@ export fn init() void {
vao = webgl.VertexArrayObject.init();
pos_buffer = webgl.createBuffer();
col_buffer = webgl.createBuffer();
+ offset_buffer = webgl.createBuffer();
prog.setVertexAttribPointer(.pos, vao, pos_buffer, .{});
prog.setVertexAttribPointer(.col, vao, col_buffer, .{});
+ prog.setVertexAttribPointer(.offset, vao, offset_buffer, .{});
webgl.bindBuffer(.array_buffer, pos_buffer);
webgl.bufferData(.array_buffer, &box_verts, .static_draw);
@@ -34,6 +43,8 @@ export fn init() void {
webgl.bindBuffer(.array_buffer, col_buffer);
webgl.bufferData(.array_buffer, &col_data, .static_draw);
+ setupSubdividedCube(4, mengerTest);
+
webgl.enable(.cull_face);
webgl.enable(.depth_test);
}
@@ -45,7 +56,7 @@ const col_data: [18 * 6]f32 = blk: {
const tri = red ++ green ++ blue;
break :blk tri ** 12;
};
-const box_verts = boxVertices(100, 100, 100);
+const box_verts = boxVertices(1, 1, 1);
fn multAllMat4(in: [][3]f32, mat: Mat4) void {
for (in) |*r| {
@@ -132,6 +143,114 @@ fn boxVertices(x: f32, y: f32, z: f32) [18 * 6]f32 {
var timer: f32 = 0;
+const max_depth = 4;
+var offsets: [pow(u32, 27, max_depth)][3]f32 = undefined;
+var cube_count: i32 = 0;
+var current_depth: u32 = 1;
+var base_scale: f32 = 1;
+
+fn updateMenger(depth: u32) void {
+ setupSubdividedCube(depth, mengerTest);
+}
+
+fn setupSubdividedCube(divisions: u32, condFn: *const fn (u32, u32, u32) bool) void {
+ webgl.bindBuffer(.array_buffer, offset_buffer);
+ const m_offsets = subdividedCube(divisions, condFn);
+ const m_ptr: [*]const f32 = @ptrCast(m_offsets);
+ const m_len = m_offsets.len * 3;
+ wasm.print("{d} cubes generated", .{m_offsets.len});
+ webgl.bufferData(.array_buffer, m_ptr[0..m_len], .dynamic_draw);
+ cube_count = @intCast(m_offsets.len);
+ current_depth = divisions;
+}
+
+fn subdividedCube(divisions: u32, condFn: *const fn (u32, u32, u32) bool) []const [3]f32 {
+ const cubes_per_side = pow(u32, 3, divisions);
+ base_scale = 1.0 / @as(f32, @floatFromInt(cubes_per_side));
+
+ var len: u32 = 0;
+ for (0..cubes_per_side) |z| {
+ for (0..cubes_per_side) |y| {
+ for (0..cubes_per_side) |x| {
+ if (condFn(x, y, z)) {
+ const c: @Vector(3, f32) = .{
+ @floatFromInt(x),
+ @floatFromInt(y),
+ @floatFromInt(z),
+ };
+ const adj: @Vector(3, f32) = @splat(@as(f32, @floatFromInt(cubes_per_side)) / 3.0);
+ offsets[len] = c - adj;
+ len += 1;
+ }
+ }
+ }
+ }
+
+ return offsets[0..len];
+}
+
+fn pow(comptime T: type, base: T, exp: T) T {
+ if (exp == 0) {
+ return 1;
+ } else if (exp > 0) {
+ return base * pow(T, base, exp - 1);
+ } else if (exp < 0) {
+ return pow(T, base, exp + 1) / base;
+ }
+ unreachable;
+}
+
+fn mengerOffsets(depth: u32) []const [3]f32 {
+ //if (depth == 0) return &[1][3]f32{.{ 0, 0, 0 }};
+ const cubes_per_side = pow(u32, 3, depth);
+ base_scale = 1.0 / @as(f32, @floatFromInt(cubes_per_side));
+
+ var len: u32 = 0;
+ for (0..cubes_per_side) |z| {
+ for (0..cubes_per_side) |y| {
+ for (0..cubes_per_side) |x| {
+ if (isValidIndex(x, y, z)) {
+ const c: @Vector(3, f32) = .{
+ @floatFromInt(x),
+ @floatFromInt(y),
+ @floatFromInt(z),
+ };
+ const adj: @Vector(3, f32) = @splat(@as(f32, @floatFromInt(cubes_per_side)) / 3.0);
+ offsets[len] = c - adj;
+ len += 1;
+ }
+ }
+ }
+ }
+
+ return offsets[0..len];
+}
+
+fn mengerTest(x: u32, y: u32, z: u32) bool {
+ const meng_x = !(x > 0 and (x - 1) % 3 == 0);
+ const meng_y = !(y > 0 and (y - 1) % 3 == 0);
+ const meng_z = !(z > 0 and (z - 1) % 3 == 0);
+ const tot = @as(u8, @intFromBool(meng_x)) + @as(u8, @intFromBool(meng_y)) + @as(u8, @intFromBool(meng_z));
+
+ if (x >= 3 or y >= 3 or z >= 3) {
+ return tot > 1 and mengerTest(@divFloor(x, 3), @divFloor(y, 3), @divFloor(z, 3));
+ } else {
+ return tot > 1;
+ }
+}
+
+fn inverseMenger(x: u32, y: u32, z: u32) bool {
+ return !mengerTest(x, y, z);
+}
+
+fn isValidIndex(x: u32, y: u32, z: u32) bool {
+ const meng_x = !(x > 0 and (x - 1) % 3 == 0);
+ const meng_y = !(y > 0 and (y - 1) % 3 == 0);
+ const meng_z = !(z > 0 and (z - 1) % 3 == 0);
+ const tot = @as(u8, @intFromBool(meng_x)) + @as(u8, @intFromBool(meng_y)) + @as(u8, @intFromBool(meng_z));
+ return tot > 1;
+}
+
export fn update(delta_time: f32) void {
timer += delta_time;
const bg = webgl.Color.fromVec(.{ 1, 1, 1, 1 });
@@ -144,23 +263,48 @@ export fn update(delta_time: f32) void {
const screen_dims = webgl.getScreenSize();
const aspect = screen_dims[0] / screen_dims[1];
const proj = perspectiveMatrix(degToRad(60), aspect, 1, 2000);
- const tlate = Mat4.translation(.{ @sin(timer * 4) * 100, 0, -200 });
- const rot = Mat4.yRotation(timer).multiply(Mat4.xRotation(timer));
- const s = (@sin(timer) * 0.5 + 0.5);
+ const tlate = Mat4.translation(.{ 0, 0, -225 });
+ const rot = Mat4.yRotation(timer).multiply(Mat4.xRotation(0)).multiply(Mat4.zRotation(0));
+ const s: f32 = 150 * base_scale;
const scale = Mat4.scale(.{ s, s, s });
const model = scale.multiply(rot.multiply(tlate));
const final_mat = model.multiply(proj);
- const m: matrix.Matrix(f32, 1, 4) = .{ .data = @bitCast([4]f32{ 0, 0, 0, 0 }) };
- wasm.print("{d}", .{m.multiply(final_mat).data});
prog.setUniform(.mat, final_mat);
- webgl.drawArrays(.triangles, 0, 36);
+
+ webgl.drawArraysInstanced(.triangles, 0, 36, cube_count);
+ //webgl.drawArrays(.triangles, 0, 36);
+
prog.setUniform(.color, .{ 0.0, 0.0, 0.0 });
for (0..12) |i| {
- webgl.drawArrays(.line_loop, @intCast(i * 3), 3);
+ //webgl.drawArrays(.line_loop, @intCast(i * 3), 3);
+ webgl.drawArraysInstanced(.line_loop, @intCast(i * 3), 3, cube_count);
}
}
+fn isPerfectSquare(val: f32) bool {
+ const s = @sqrt(val);
+ return s * s == val;
+}
+
+fn isFibonacci(val: u32) bool {
+ const n: f32 = @floatFromInt(val);
+ return isPerfectSquare(5 * n * n + 4) and isPerfectSquare(5 * n * n - 4);
+}
+
+fn myTest(x: u32, y: u32, z: u32) bool {
+ const total = x + y + z;
+ _ = total;
+ const total_f: f32 = @floatFromInt(x + y + z);
+ _ = total_f;
+ return isFibonacci(y) and x * x < z * z;
+}
+
+fn evenLatticeTest(x: u32, y: u32, z: u32) bool {
+ const total = x + y + z;
+ return total % 2 == 0;
+}
+
fn degToRad(deg: f32) f32 {
return deg * pi / 180;
}
diff --git a/src/webgl.zig b/src/webgl.zig
index 9a373f6..1e1c5a7 100644
--- a/src/webgl.zig
+++ b/src/webgl.zig
@@ -44,6 +44,7 @@ const AttributeInfo = struct {
identifier: [:0]const u8,
shader_name: []const u8,
kind: enum { vec2, vec3, vec4 },
+ instance_divisor: ?u16 = null,
};
pub const Buffer = bindings.Buffer;
@@ -129,6 +130,7 @@ pub fn Program(
for (attributes, 0..) |a, i| {
const h = bindings.getAttribLocation(handle, a.shader_name.ptr, a.shader_name.len);
if (h < 0) return error.FailedToGetUniformLocation;
+
attribute_handles[i] = h;
}
@@ -201,13 +203,17 @@ pub fn Program(
stride,
offset,
);
+
+ if (attr_info.instance_divisor) |d| {
+ bindings.vertexAttribDivisor(attr_handle, d);
+ }
}
};
}
pub fn clear(col: Color) void {
bindings.clearColor(col.r, col.g, col.b, col.a);
- bindings.clear(bindings.color_buffer_bit);
+ bindings.clear(bindings.color_buffer_bit | bindings.depth_buffer_bit);
}
pub fn getScreenSize() [2]f32 {
@@ -221,6 +227,7 @@ pub fn viewportToScreen() void {
}
pub const drawArrays = bindings.drawArrays;
+pub const drawArraysInstanced = bindings.drawArraysInstanced;
fn loadShader(shader_type: bindings.ShaderType, source: []const u8) !u32 {
const shader = bindings.createShader(shader_type);