summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.zig46
-rw-r--r--build.zig.zon34
-rw-r--r--src/main.zig420
-rw-r--r--src/matrix.zig80
-rw-r--r--src/shell.html134
-rw-r--r--src/wasm_cdots.zig537
-rw-r--r--src/webgl.js261
-rw-r--r--src/webgl.zig152
8 files changed, 451 insertions, 1213 deletions
diff --git a/build.zig b/build.zig
index 34a9aee..e0567c3 100644
--- a/build.zig
+++ b/build.zig
@@ -1,37 +1,45 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
- const target = b.resolveTargetQuery(.{
+ // The engine only supports wasm right now so if you set a whitelist here,
+ // you won't have to remember to specify your target each time you compile.
+ const wasm_target: std.Target.Query = .{
.cpu_arch = .wasm32,
.os_tag = .freestanding,
+ };
+ const target = b.standardTargetOptions(.{
+ .whitelist = &.{wasm_target},
+ .default_target = wasm_target,
});
const optimize = b.standardOptimizeOption(.{});
- b.installFile("src/shell.html", "index.html");
- b.installFile("src/webgl.js", "webgl.js");
+ // Import the dependency via your build.zig.zon
+ const engine = b.dependency("engine", .{});
const exe = b.addExecutable(.{
- .name = "cdots",
- .root_source_file = .{ .path = "src/wasm_cdots.zig" },
+ // IMPORTANT! Right now the shell expects a file named game.wasm in the bin directory.
+ // I will make it flexible eventually. But right now if you change this line,
+ // Your project won't work right.
+ .name = "game",
+ .root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
+ // WASM doesn't use a normal entry point. The HTML/JS shell code is going
+ // to handle calling our functions.
exe.entry = .disabled;
- exe.root_module.export_symbol_names = &[_][]const u8{
- "init",
- "update",
- };
-
- b.installArtifact(exe);
+ exe.root_module.addImport("engine", engine.module("engine"));
- const exe_unit_tests = b.addTest(.{
- .root_source_file = .{ .path = "src/wasm_cdots.zig" },
- .target = target,
- .optimize = optimize,
+ // Here we install a pre-written HTML/JS shell. After building, if you
+ // run a webserver with your zig-out dir as the root, you should see your
+ // program.
+ const shell_files = engine.namedWriteFiles("shell");
+ const install_shell = b.addInstallDirectory(.{
+ .source_dir = .{ .generated = &shell_files.generated_directory },
+ .install_dir = .prefix,
+ .install_subdir = "",
});
+ b.getInstallStep().dependOn(&install_shell.step);
- const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
-
- const test_step = b.step("test", "Run unit tests");
- test_step.dependOn(&run_exe_unit_tests.step);
+ b.installArtifact(exe);
}
diff --git a/build.zig.zon b/build.zig.zon
index 5b06257..2196254 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -15,37 +15,11 @@
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
- // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
- //.example = .{
- // // When updating this field to a new URL, be sure to delete the corresponding
- // // `hash`, otherwise you are communicating that you expect to find the old hash at
- // // the new URL.
- // .url = "https://example.com/foo.tar.gz",
- //
- // // This is computed from the file contents of the directory of files that is
- // // obtained after fetching `url` and applying the inclusion rules given by
- // // `paths`.
- // //
- // // This field is the source of truth; packages do not come from a `url`; they
- // // come from a `hash`. `url` is just one of many possible mirrors for how to
- // // obtain a package matching this `hash`.
- // //
- // // Uses the [multihash](https://multiformats.io/multihash/) format.
- // .hash = "...",
- //
- // // When this is provided, the package is found in a directory relative to the
- // // build root. In this case the package's hash is irrelevant and therefore not
- // // computed. This field and `url` are mutually exclusive.
- // .path = "foo",
- //},
+ .engine = .{
+ .url = "https://git.netmythos.org/engine.git/snapshot/engine-89ed3b75abde2bc08eb1638d5c0becc8606e6a95.tar.gz",
+ .hash = "1220ee36744e9bf24ac28d47d5cd461a7b32f2d7640ca49e665db834fc45f8c72910",
+ },
},
-
- // Specifies the set of files and directories that are included in this package.
- // Only files and directories listed here are included in the `hash` that
- // is computed for this package.
- // Paths are relative to the build root. Use the empty string (`""`) to refer to
- // the build root itself.
- // A directory listed here means that all files within, recursively, are included.
.paths = .{
// This makes *all* files, recursively, included in this package. It is generally
// better to explicitly list the files and directories instead, to insure that
diff --git a/src/main.zig b/src/main.zig
new file mode 100644
index 0000000..5975572
--- /dev/null
+++ b/src/main.zig
@@ -0,0 +1,420 @@
+const std = @import("std");
+const engine = @import("engine");
+comptime {
+ _ = engine;
+}
+const webgl = engine.webgl;
+const random = engine.random;
+
+const Mat3 = engine.matrix.Matrix(f32, 3, 3);
+
+//extern fn consoleLog(ptr: [*c]const u8, len: u32) void;
+//extern fn rand() f32;
+//extern fn getScreenWidth() f32;
+//extern fn getScreenHeight() f32;
+//extern fn registerKeyInput(ptr: [*c]const u8, len: u32, out: *u32) void;
+
+const vs_source = @embedFile("vertex.glsl");
+const fs_source = @embedFile("fragment.glsl");
+
+const pi = 3.1415926535;
+const max_dist = 100;
+const star_count = 100000;
+const circle = circlePoints(32);
+const max_speed = 2;
+
+var rng: LinearCongruentialGenerator = undefined;
+var stars: [star_count]Star = undefined;
+
+var up_pressed: bool = false;
+var down_pressed: bool = false;
+var right_pressed: bool = false;
+var left_pressed: bool = false;
+
+var circle_program: CircleProgram = undefined;
+var circle_vao: webgl.VertexArrayObject = undefined;
+var pos_buffer: webgl.Buffer = undefined;
+var translation_buffer: webgl.Buffer = undefined;
+var color_buffer: webgl.Buffer = undefined;
+var scale_buffer: webgl.Buffer = undefined;
+
+var line_program: LineProgram = undefined;
+var line_vao: webgl.VertexArrayObject = undefined;
+var line_pos_buf: webgl.Buffer = undefined;
+var line_col_buf: webgl.Buffer = undefined;
+
+var frame_counter: u32 = 0;
+
+const batch_capacity = 90000;
+var translation_data: [batch_capacity][2]f32 = undefined;
+var line_data: [batch_capacity][2][2]f32 = undefined;
+var scale_data: [batch_capacity]f32 = undefined;
+var color_data: [batch_capacity]f32 = undefined;
+
+var timer: f32 = 0.0;
+var anim_t: f32 = 0;
+
+var speed: f32 = 1;
+var sub_count: u32 = star_count / 2;
+var color_mode: enum(u8) { rainbow, solid, angle, depth } = .rainbow;
+
+const DrawBatch = struct {
+ translation: [][2]f32,
+ scales: []f32,
+ colors: []f32,
+ lines: [][2][2]f32,
+ len: u32 = 0,
+
+ fn addInstance(self: *DrawBatch, translation: [2]f32, past_translation: [2]f32, hue: f32, scale: f32) !void {
+ if (self.len == self.translation.len or self.len == self.colors.len or self.len == self.scales.len or self.len == self.lines.len) return error.OutOfSpace;
+
+ self.translation[self.len] = translation;
+ self.colors[self.len] = hue;
+ self.scales[self.len] = scale;
+ self.lines[self.len] = .{ past_translation, translation };
+ self.len += 1;
+ }
+
+ fn draw(self: DrawBatch) void {
+ const dims = webgl.getScreenSize();
+ const width = dims[0];
+ const height = dims[1];
+ circle_vao.bind();
+ circle_program.use();
+ circle_program.setUniform(.resolution, .{ width, height });
+ translation_buffer.bindAndFill(.array_buffer, .vec2, self.translation, .dynamic_draw);
+ scale_buffer.bindAndFill(.array_buffer, .f32, self.scales, .dynamic_draw);
+ color_buffer.bindAndFill(.array_buffer, .f32, self.colors, .dynamic_draw);
+
+ webgl.drawArraysInstanced(.triangles, 0, circle.len, @intCast(self.len));
+
+ line_vao.bind();
+ line_program.use();
+ line_program.setUniform(.resolution, .{ width, height });
+
+ const l_mp: [*]const f32 = @ptrCast(self.lines.ptr);
+ const l_pos: []const f32 = l_mp[0 .. self.lines.len * 4];
+ line_pos_buf.bindAndFill(.array_buffer, .f32, l_pos, .dynamic_draw);
+
+ line_col_buf.bindAndFill(.array_buffer, .f32, self.colors, .dynamic_draw);
+
+ webgl.drawArraysInstanced(.lines, 0, 2, @intCast(self.len));
+ }
+};
+
+const KeyboardKey = enum {
+ up,
+ down,
+ left,
+ right,
+ c,
+};
+
+const LineProgram = webgl.Program(
+ &.{
+ .{ .identifier = "resolution", .shader_name = "u_resolution", .kind = .vec2 },
+ },
+ &.{
+ .{ .identifier = "pos", .shader_name = "in_pos", .kind = .vec4, .instance_divisor = 1 },
+ .{ .identifier = "color", .shader_name = "color", .kind = .f32, .instance_divisor = 1 },
+ },
+);
+
+const CircleProgram = webgl.Program(
+ &.{
+ .{ .identifier = "resolution", .shader_name = "u_resolution", .kind = .vec2 },
+ },
+ &.{
+ .{ .identifier = "pos", .shader_name = "in_pos", .kind = .vec2 },
+ .{ .identifier = "color", .shader_name = "color", .kind = .f32, .instance_divisor = 1 },
+ .{ .identifier = "scale", .shader_name = "scale", .kind = .f32, .instance_divisor = 1 },
+ .{ .identifier = "translation", .shader_name = "translation", .kind = .vec2, .instance_divisor = 1 },
+ },
+);
+
+const Star = struct {
+ dist: f32,
+ pdist: f32,
+ angle: f32,
+ initial_len: f32,
+ hue: f32,
+};
+
+pub const LinearCongruentialGenerator = struct {
+ mod: u64,
+ mul: u64,
+ inc: u64,
+ seed: u64,
+
+ const Self = @This();
+ /// Move to the next seed value internally and return that value
+ pub fn next(self: *Self) u64 {
+ const r = (self.seed *% self.mul +% self.inc) % self.mod;
+ self.seed = r;
+ return r;
+ }
+
+ /// Generate an int of type T with a value from min to max (inclusive)
+ pub fn randInt(self: *Self, comptime T: type, min: T, max: T) T {
+ assert(max > min);
+ const range: u64 = @as(u64, @intCast(max - min)) + 1;
+ assert(self.mod >= range);
+ const val: T = @intCast(self.next() % range);
+ return min + val;
+ }
+
+ pub fn randFloat(self: *Self, comptime T: type) T {
+ const pct: T = @as(T, @floatFromInt(self.next())) / @as(T, @floatFromInt(self.mod));
+ return pct;
+ }
+
+ pub fn randEnum(self: *Self, comptime T: type) T {
+ const info = @typeInfo(T);
+ if (info != .Enum) @compileError("Cannot call randEnum on type " ++ @typeName(T));
+ const fields = info.Enum.fields;
+ const vals = comptime blk: {
+ var result: [fields.len]T = undefined;
+ for (fields, 0..) |f, i| {
+ result[i] = @field(T, f.name);
+ }
+ break :blk result;
+ };
+ const i = self.randInt(usize, 0, fields.len - 1);
+ return vals[i];
+ }
+
+ pub fn randBool(self: *Self) bool {
+ return self.next() % 2 == 0;
+ }
+
+ pub fn ZX81(seed: u64) Self {
+ const mod = pow(u64, 2, 16) + 1;
+ return .{
+ .seed = seed,
+ .mod = mod,
+ .mul = 75,
+ .inc = 74,
+ };
+ }
+};
+
+fn assert(ok: bool) void {
+ if (!ok) unreachable;
+}
+
+pub 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;
+}
+
+pub fn init() void {
+ const seed: u64 = random.randomSeed();
+ rng = LinearCongruentialGenerator.ZX81(seed);
+
+ circle_program = CircleProgram.init(@embedFile("vertex.glsl"), fs_source) catch |err| {
+ engine.print("Failed to create CircleProgram. {}", .{err});
+ return;
+ };
+ circle_vao = webgl.VertexArrayObject.init();
+ pos_buffer = webgl.Buffer.init();
+ translation_buffer = webgl.Buffer.init();
+ color_buffer = webgl.Buffer.init();
+ scale_buffer = webgl.Buffer.init();
+ circle_program.setVertexAttribPointer(.pos, circle_vao, pos_buffer);
+ pos_buffer.bindAndFill(.array_buffer, .vec2, &circle, .static_draw);
+ circle_program.setVertexAttribPointer(.scale, circle_vao, scale_buffer);
+ circle_program.setVertexAttribPointer(.color, circle_vao, color_buffer);
+ circle_program.setVertexAttribPointer(.translation, circle_vao, translation_buffer);
+
+ line_program = LineProgram.init(@embedFile("line_vertex.glsl"), fs_source) catch |err| {
+ engine.print("Failed to create CircleProgram. {}", .{err});
+ return;
+ };
+ line_vao = webgl.VertexArrayObject.init();
+ line_pos_buf = webgl.Buffer.init();
+ line_col_buf = webgl.Buffer.init();
+ line_program.setVertexAttribPointer(.pos, line_vao, line_pos_buf);
+ line_program.setVertexAttribPointer(.color, line_vao, line_col_buf);
+
+ const dims = webgl.getScreenSize();
+ const height = dims[1];
+
+ for (&stars) |*s| {
+ s.angle = lerp(0, 2 * pi, rng.randFloat(f32));
+ s.initial_len = lerp(0, height / 2, rng.randFloat(f32));
+ s.dist = max_dist;
+ s.pdist = max_dist;
+ s.hue = rng.randFloat(f32);
+ }
+}
+
+fn rad2deg(rads: f32) f32 {
+ return rads * (180.0 / pi);
+}
+
+pub fn update(elapsed_time: f32) void {
+ const report_freq = 100;
+ frame_counter += 1;
+ timer += elapsed_time;
+ anim_t += elapsed_time;
+ if (frame_counter % report_freq == 0) {
+ const avg = timer / report_freq;
+ engine.print("{d:.2} Average FPS", .{1.0 / avg});
+ timer = 0;
+ }
+
+ if (right_pressed) {
+ speed += 0.1;
+ }
+ if (left_pressed) {
+ speed -= 0.1;
+ }
+ speed = @min(max_speed, @max(speed, -max_speed));
+
+ const count_delta = 500;
+ if (up_pressed) {
+ if (sub_count + count_delta <= star_count) {
+ sub_count += count_delta;
+ }
+ }
+
+ if (down_pressed) {
+ if (sub_count >= count_delta) {
+ sub_count -= count_delta;
+ }
+ }
+
+ const dims = webgl.getScreenSize();
+ const width = dims[0];
+ const height = dims[1];
+
+ webgl.viewport(0, 0, @intFromFloat(width), @intFromFloat(height));
+ circle_program.use();
+ circle_vao.bind();
+ circle_program.setUniform(.resolution, .{ width, height });
+
+ webgl.clear(engine.Color.black);
+
+ var batch: DrawBatch = .{
+ .translation = &translation_data,
+ .colors = &color_data,
+ .scales = &scale_data,
+ .lines = &line_data,
+ };
+
+ for (stars[0..sub_count]) |*s| {
+ s.pdist = s.dist;
+ s.dist -= speed;
+ s.angle += @cos(anim_t) * 0.05;
+ const plen = lerp(1000, s.initial_len, s.pdist / max_dist);
+ const psx = (@cos(s.angle) * plen) + width * 0.5;
+ const psy = (@sin(s.angle) * plen) + height * 0.5;
+
+ const len = lerp(1000, s.initial_len, s.dist / max_dist);
+ const sx = (@cos(s.angle) * len) + width * 0.5;
+ const sy = (@sin(s.angle) * len) + height * 0.5;
+ const scale = lerp(16, 0, s.dist / max_dist);
+
+ const col = switch (color_mode) {
+ .rainbow => s.hue,
+ .solid => @sin(anim_t * 0.1) * 0.5 + 1,
+ .angle => (s.angle / (2 * pi)) + (@cos(anim_t) + 1) / 2,
+ .depth => s.dist / (max_dist * 0.5),
+ };
+
+ batch.addInstance(.{ sx, sy }, .{ psx, psy }, col, scale) catch unreachable;
+ if (batch.len == batch_capacity) {
+ batch.draw();
+ batch.len = 0;
+ }
+
+ if (sx < 0 or sx > width or sy < 0 or sy > height + 32) {
+ s.angle = lerp(0, 8 * pi, rng.randFloat(f32));
+ s.initial_len = lerp(0, height, rng.randFloat(f32));
+ s.dist = max_dist;
+ s.pdist = max_dist;
+ }
+ }
+
+ batch.draw();
+}
+
+pub fn handleInput(ev: engine.input.InputEvent) void {
+ const SpecialKeys = engine.wasm.SpecialKeyCodepoints;
+ const up = @intFromEnum(SpecialKeys.arrow_up);
+ const down = @intFromEnum(SpecialKeys.arrow_down);
+ const left = @intFromEnum(SpecialKeys.arrow_left);
+ const right = @intFromEnum(SpecialKeys.arrow_right);
+ switch (ev) {
+ .key => |k| {
+ switch (k.codepoint) {
+ 'c' => {
+ if (k.is_down and !k.is_repeat) {
+ if (color_mode == .depth) {
+ color_mode = .rainbow;
+ } else {
+ color_mode = @enumFromInt(@intFromEnum(color_mode) + 1);
+ }
+ }
+ },
+ up => {
+ up_pressed = k.is_down;
+ },
+ down => {
+ down_pressed = k.is_down;
+ },
+ left => {
+ left_pressed = k.is_down;
+ },
+ right => {
+ right_pressed = k.is_down;
+ },
+ else => {},
+ }
+ },
+ else => {},
+ }
+}
+
+fn lerp(a: f32, b: f32, v: f32) f32 {
+ return a + (b - a) * v;
+}
+
+fn invLerp(a: f32, b: f32, v: f32) f32 {
+ return (v - a) / (b - a);
+}
+
+fn mapLerp(from_a: f32, from_b: f32, to_a: f32, to_b: f32, v: f32) f32 {
+ const pct = invLerp(from_a, from_b, v);
+ return lerp(to_a, to_b, pct);
+}
+
+fn circlePoints(comptime segments: u32) [segments * 3][2]f32 {
+ const segment_rads = (2 * pi) / @as(comptime_float, segments);
+ var r: [segments * 3][2]f32 = undefined;
+ for (0..segments) |s| {
+ const sf: f32 = @floatFromInt(s);
+ const start_angle = segment_rads * sf;
+ const start_x = @cos(start_angle);
+ const start_y = @sin(start_angle);
+ const start: @Vector(2, f32) = .{ start_x, start_y };
+
+ const end_angle = segment_rads * (sf + 1);
+ const end_x = @cos(end_angle);
+ const end_y = @sin(end_angle);
+ const end: @Vector(2, f32) = .{ end_x, end_y };
+
+ const i = s * 3;
+ r[i] = @Vector(2, f32){ 0, 0 };
+ r[i + 1] = start;
+ r[i + 2] = end;
+ }
+
+ return r;
+}
diff --git a/src/matrix.zig b/src/matrix.zig
deleted file mode 100644
index 025af7c..0000000
--- a/src/matrix.zig
+++ /dev/null
@@ -1,80 +0,0 @@
-pub fn Matrix(comptime T: type, rows: usize, cols: usize) type {
- const RowVec = @Vector(rows, T);
- const ColVec = @Vector(cols, T);
-
- return struct {
- pub const RowT = [rows]T;
- const Self = @This();
-
- pub const identity: Self = blk: {
- const fill = if (T == bool) true else 1;
- const empty = if (T == bool) false else 0;
- var r: [cols]@Vector(rows, T) = undefined;
- for (0..cols) |c| {
- var irow: RowT = [1]T{empty} ** rows;
- irow[c] = fill;
- r[c] = irow;
- }
- break :blk .{ .data = r };
- };
-
- data: [cols]RowT,
-
- pub fn multiply(a: Self, b: Self) Self {
- comptime assert(rows == cols);
- var result: Self = undefined;
- for (0..rows) |ri| {
- const r = a.row(ri);
- for (0..cols) |ci| {
- const c = b.data[ci];
- result.data[ci][ri] = @reduce(.Add, r * c);
- }
- }
- return result;
- }
-
- pub fn translation(t: @Vector(cols - 1, T)) Self {
- var base = Self.identity;
- for (0..cols - 1) |ci| {
- base.data[ci][rows - 1] = t[ci];
- }
- return base;
- }
-
- pub fn rotation(angle: T) Self {
- if (rows < 2 or cols < 2) @compileError("Called rotation on a Matrix smaller than 2x2");
- const c = @cos(angle);
- const s = @sin(angle);
- var base = Self.identity;
- base.data[0][0] = c;
- base.data[0][1] = -s;
- base.data[1][0] = s;
- base.data[1][1] = c;
- return base;
- }
-
- pub fn scale(sx: T, sy: T) Self {
- var r = identity;
- r.data[0][0] = sx;
- r.data[1][1] = sy;
- return r;
- }
-
- pub fn row(self: Self, ri: usize) RowVec {
- var r: RowVec = undefined;
- for (0..cols) |ci| {
- r[ci] = self.data[ci][ri];
- }
- return r;
- }
-
- pub fn col(self: Self, ci: usize) ColVec {
- const start = ci * rows;
- return self.data[start .. start + cols];
- }
- };
-}
-
-fn assert(ok: bool) void {
- if (!ok) unreachable;
-}
diff --git a/src/shell.html b/src/shell.html
deleted file mode 100644
index d4f5c85..0000000
--- a/src/shell.html
+++ /dev/null
@@ -1,134 +0,0 @@
-<!doctype html>
-<html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Color Dots</title>
- <style>
- body {
- overflow: hidden;
- min-height: 720px;
- min-width: 1280px;
- display: flex;
- flex-direction: column;
- margin: 0;
- }
- #app-canvas {
- display: flex;
- flex-grow: 1;
- width: 100%;
- height: 100%;
- }
- </style>
- </head>
- <body>
- <canvas id="app-canvas" tabindex="0"></canvas>
- <script src="webgl.js"></script>
- <script>
- canvas.width = canvas.clientWidth;
- canvas.height = canvas.clientHeight;
- let memory = null;
- let last_frame_time = Date.now();
-
- const writeString = (str, pointer, length) => {
- if (!memory) {
- return null;
- }
-
- const l = Math.min(length, str.length);
- const from = new TextEncoder().encode(str.slice(0, l));
- const to = new Uint8Array(memory.buffer, pointer, length);
- to.set(from);
- return l;
- };
-
- const readString = (pointer, length) => {
- if (!memory) {
- return null;
- }
-
- // Memory in WASM is one big buffer. We can read a string from the
- // Zig/WASM space if we know the pointer and length.
- return new TextDecoder().decode(
- new Uint8Array(memory.buffer, pointer, length),
- );
- };
-
-
- const consoleLog = (ptr, len) => {
- console.log(readString(ptr, len));
- }
-
- const rand = () => {
- return Math.random();
- };
-
- const loadTexture = (ptr, len, tex_id, ret_ptr) => {
- const path = readString(ptr, len);
- var image = new Image();
- image.src = path;
- console.log("loading ", path);
- image.addEventListener('load', function() {
- const ret_list = new Uint32Array(memory.buffer, ret_ptr, 3);
- ret_list[0] = 1;
- ret_list[1] = image.width;
- ret_list[2] = image.height;
- console.log(path, " loaded");
- const tex = glTextures.get(tex_id);
- gfx_ctx.bindTexture(gfx_ctx.TEXTURE_2D, tex);
- gfx_ctx.texImage2D(gfx_ctx.TEXTURE_2D, 0, gfx_ctx.RGBA, gfx_ctx.RGBA, gfx_ctx.UNSIGNED_BYTE, image);
- gfx_ctx.generateMipmap(gfx_ctx.TEXTURE_2D);
- });
- };
-
- const keyRegistry = new Map();
- canvas.addEventListener("keydown", (e) => {
- const p = keyRegistry.get(e.code);
- if (p) {
- p[0] = 1;
- }
- });
-
- canvas.addEventListener("keyup", (e) => {
- const p = keyRegistry.get(e.code);
- if (p) {
- p[0] = 0;
- }
- });
-
- const registerKeyInput = (ptr, len, out_ptr) => {
- const code = readString(ptr, len);
- const list = new Uint32Array(memory.buffer, out_ptr, 1);
- keyRegistry.set(code, list);
- };
-
- const importObject = {
- env: {
- ...webgl,
- consoleLog,
- rand,
- loadTexture,
- registerKeyInput,
- },
- };
-
- WebAssembly.instantiateStreaming(fetch("bin/cdots.wasm"), importObject).then(
- (obj) => {
- memory = obj.instance.exports.memory;
- obj.instance.exports.init();
-
- const update = obj.instance.exports.update;
- function step() {
- const time = Date.now();
- const elapsed = time - last_frame_time;
- update(elapsed / 1000);
- last_frame_time = time;
- window.requestAnimationFrame(step);
- }
-
- window.requestAnimationFrame(step);
- }
- );
- </script>
- </body>
-</html>
diff --git a/src/wasm_cdots.zig b/src/wasm_cdots.zig
deleted file mode 100644
index 967bb7c..0000000
--- a/src/wasm_cdots.zig
+++ /dev/null
@@ -1,537 +0,0 @@
-const std = @import("std");
-const webgl = @import("webgl.zig");
-
-const Mat3 = @import("matrix.zig").Matrix(f32, 3, 3);
-
-extern fn consoleLog(ptr: [*c]const u8, len: u32) void;
-extern fn rand() f32;
-extern fn getScreenWidth() f32;
-extern fn getScreenHeight() f32;
-extern fn registerKeyInput(ptr: [*c]const u8, len: u32, out: *u32) void;
-
-const vs_source = @embedFile("vertex.glsl");
-const fs_source = @embedFile("fragment.glsl");
-
-const pi = 3.1415926535;
-const max_dist = 100;
-const star_count = 100000;
-const circle = circlePoints(32);
-const max_speed = 2;
-
-var rng: LinearCongruentialGenerator = undefined;
-var stars: [star_count]Star = undefined;
-
-var right: u32 = 0;
-var left: u32 = 0;
-var up: u32 = 0;
-var down: u32 = 0;
-var c_key: u32 = 0;
-var c_was_pressed: u32 = 0;
-
-var circle_program: CircleProgram = undefined;
-var line_program: LineProgram = undefined;
-
-var frame_counter: u32 = 0;
-
-const batch_capacity = 90000;
-var translation_data: [batch_capacity][2]f32 = undefined;
-var line_data: [batch_capacity][2][2]f32 = undefined;
-var scale_data: [batch_capacity]f32 = undefined;
-var color_data: [batch_capacity]f32 = undefined;
-
-var timer: f32 = 0.0;
-var anim_t: f32 = 0;
-
-var speed: f32 = 1;
-var sub_count: u32 = star_count / 2;
-var color_mode: enum(u8) { rainbow, solid, angle, depth } = .rainbow;
-
-const DrawBatch = struct {
- translation: [][2]f32,
- scales: []f32,
- colors: []f32,
- lines: [][2][2]f32,
- len: u32 = 0,
-
- fn addInstance(self: *DrawBatch, translation: [2]f32, past_translation: [2]f32, hue: f32, scale: f32) !void {
- if (self.len == self.translation.len or self.len == self.colors.len or self.len == self.scales.len or self.len == self.lines.len) return error.OutOfSpace;
-
- self.translation[self.len] = translation;
- self.colors[self.len] = hue;
- self.scales[self.len] = scale;
- self.lines[self.len] = .{ past_translation, translation };
- self.len += 1;
- }
-
- fn draw(self: DrawBatch) void {
- const width = getScreenWidth();
- const height = getScreenHeight();
- webgl.bindVertexArray(circle_program.vao);
- webgl.useProgram(circle_program.prog);
- webgl.uniform2f(circle_program.res_uniform_location, width, height);
- webgl.bindBuffer(.array_buffer, circle_program.translation_buffer);
- webgl.bufferData(.array_buffer, @ptrCast(self.translation), self.len * 2, .dynamic_draw);
-
- webgl.bindBuffer(.array_buffer, circle_program.scale_buffer);
- webgl.bufferData(.array_buffer, @ptrCast(self.scales), self.len, .dynamic_draw);
-
- webgl.bindBuffer(.array_buffer, circle_program.col_buffer);
- webgl.bufferData(.array_buffer, @ptrCast(self.colors), self.len, .dynamic_draw);
- webgl.drawArraysInstanced(.triangles, 0, circle.len, @intCast(self.len));
-
- webgl.bindVertexArray(line_program.vao);
- webgl.useProgram(line_program.prog);
- webgl.uniform2f(line_program.res_uniform_location, width, height);
-
- webgl.bindBuffer(.array_buffer, line_program.pos_buffer);
- webgl.bufferData(.array_buffer, @ptrCast(self.lines), self.len * 2 * 2, .dynamic_draw);
-
- webgl.bindBuffer(.array_buffer, line_program.col_buffer);
- webgl.bufferData(.array_buffer, @ptrCast(self.colors), self.len, .dynamic_draw);
- webgl.drawArraysInstanced(.lines, 0, 2, @intCast(self.len));
- }
-};
-
-const KeyboardKey = enum {
- up,
- down,
- left,
- right,
- c,
-};
-
-const LineProgram = struct {
- prog: webgl.Program,
- vao: webgl.VertexArrayObject,
-
- res_uniform_location: i32,
-
- pos_buffer: webgl.Buffer,
- col_buffer: webgl.Buffer,
-
- fn init() !LineProgram {
- const vert = loadShader(.vertex_shader, @embedFile("line_vertex.glsl")) catch return error.FailedToLoadVertexShader;
- const frag = loadShader(.fragment_shader, fs_source) catch return error.FailedToLoadFragmentShader;
- const prog = createGLProgram(vert, frag) catch return error.FailedToCreateProgram;
- webgl.useProgram(prog);
-
- const attr_name = "in_pos";
- const pos_attr_location = webgl.getAttribLocation(prog, attr_name.ptr, attr_name.len);
-
- const col_attr = "color";
- const col_attr_location = webgl.getAttribLocation(prog, col_attr.ptr, col_attr.len);
-
- const res_uniform_location = getUniformLocation(prog, "u_resolution") catch unreachable;
-
- const pos_buffer = webgl.createBuffer();
- webgl.bindBuffer(.array_buffer, pos_buffer);
- webgl.bufferData(.array_buffer, @ptrCast(&[_]f32{ 0, 0, 0, 0 }), 2, .static_draw);
-
- const vao = webgl.createVertexArray();
- webgl.bindVertexArray(vao);
- webgl.enableVertexAttribArray(pos_attr_location);
- webgl.vertexAttribPointer(@intCast(pos_attr_location), 4, .f32, .false, 0, 0);
- webgl.vertexAttribDivisor(pos_attr_location, 1);
-
- const col_buffer = webgl.createBuffer();
- webgl.bindBuffer(.array_buffer, col_buffer);
- webgl.enableVertexAttribArray(col_attr_location);
- webgl.vertexAttribPointer(@intCast(col_attr_location), 1, .f32, .false, 0, 0);
- webgl.vertexAttribDivisor(col_attr_location, 1);
-
- return .{
- .prog = prog,
- .pos_buffer = pos_buffer,
- .col_buffer = col_buffer,
- .res_uniform_location = res_uniform_location,
- .vao = vao,
- };
- }
-};
-
-const CircleProgram = struct {
- prog: webgl.Program,
- vao: webgl.VertexArrayObject,
-
- res_uniform_location: i32,
-
- translation_buffer: webgl.Buffer,
- scale_buffer: webgl.Buffer,
- col_buffer: webgl.Buffer,
-
- fn init() !CircleProgram {
- const vert = loadShader(.vertex_shader, @embedFile("vertex.glsl")) catch return error.FailedToLoadVertexShader;
- const frag = loadShader(.fragment_shader, fs_source) catch return error.FailedToLoadFragmentShader;
- const prog = createGLProgram(vert, frag) catch return error.FailedToCreateProgram;
- webgl.useProgram(prog);
-
- const attr_name = "in_pos";
- const pos_attr_location = webgl.getAttribLocation(prog, attr_name.ptr, attr_name.len);
-
- const col_attr = "color";
- const col_attr_location = webgl.getAttribLocation(prog, col_attr.ptr, col_attr.len);
-
- const translation_attr = "translation";
- const translation_attr_location = webgl.getAttribLocation(
- prog,
- translation_attr.ptr,
- translation_attr.len,
- );
-
- const scale_attr = "scale";
- const scale_attr_location = webgl.getAttribLocation(
- prog,
- scale_attr.ptr,
- scale_attr.len,
- );
-
- const res_uniform_location = getUniformLocation(prog, "u_resolution") catch unreachable;
-
- const pos_buffer = webgl.createBuffer();
- webgl.bindBuffer(.array_buffer, pos_buffer);
- webgl.bufferData(.array_buffer, @ptrCast(&circle), circle.len * 2, .static_draw);
-
- const vao = webgl.createVertexArray();
- webgl.bindVertexArray(vao);
- webgl.enableVertexAttribArray(pos_attr_location);
- webgl.vertexAttribPointer(@intCast(pos_attr_location), 2, .f32, .false, 0, 0);
-
- const col_buffer = webgl.createBuffer();
- webgl.bindBuffer(.array_buffer, col_buffer);
- webgl.enableVertexAttribArray(col_attr_location);
- webgl.vertexAttribPointer(@intCast(col_attr_location), 1, .f32, .false, 0, 0);
- webgl.vertexAttribDivisor(col_attr_location, 1);
-
- const scale_buffer = webgl.createBuffer();
- webgl.bindBuffer(.array_buffer, scale_buffer);
- webgl.enableVertexAttribArray(scale_attr_location);
- webgl.vertexAttribPointer(@intCast(scale_attr_location), 1, .f32, .false, 0, 0);
- webgl.vertexAttribDivisor(scale_attr_location, 1);
-
- const translation_buffer = webgl.createBuffer();
- webgl.bindBuffer(.array_buffer, translation_buffer);
- webgl.enableVertexAttribArray(translation_attr_location);
- webgl.vertexAttribPointer(@intCast(translation_attr_location), 2, .f32, .false, 0, 0);
- webgl.vertexAttribDivisor(translation_attr_location, 1);
-
- return .{
- .prog = prog,
- .translation_buffer = translation_buffer,
- .col_buffer = col_buffer,
- .scale_buffer = scale_buffer,
- .res_uniform_location = res_uniform_location,
- .vao = vao,
- };
- }
-};
-
-const Star = struct {
- dist: f32,
- pdist: f32,
- angle: f32,
- initial_len: f32,
- hue: f32,
-};
-
-pub const LinearCongruentialGenerator = struct {
- mod: u64,
- mul: u64,
- inc: u64,
- seed: u64,
-
- const Self = @This();
- /// Move to the next seed value internally and return that value
- pub fn next(self: *Self) u64 {
- const r = (self.seed *% self.mul +% self.inc) % self.mod;
- self.seed = r;
- return r;
- }
-
- /// Generate an int of type T with a value from min to max (inclusive)
- pub fn randInt(self: *Self, comptime T: type, min: T, max: T) T {
- assert(max > min);
- const range: u64 = @as(u64, @intCast(max - min)) + 1;
- assert(self.mod >= range);
- const val: T = @intCast(self.next() % range);
- return min + val;
- }
-
- pub fn randFloat(self: *Self, comptime T: type) T {
- const pct: T = @as(T, @floatFromInt(self.next())) / @as(T, @floatFromInt(self.mod));
- return pct;
- }
-
- pub fn randEnum(self: *Self, comptime T: type) T {
- const info = @typeInfo(T);
- if (info != .Enum) @compileError("Cannot call randEnum on type " ++ @typeName(T));
- const fields = info.Enum.fields;
- const vals = comptime blk: {
- var result: [fields.len]T = undefined;
- for (fields, 0..) |f, i| {
- result[i] = @field(T, f.name);
- }
- break :blk result;
- };
- const i = self.randInt(usize, 0, fields.len - 1);
- return vals[i];
- }
-
- pub fn randBool(self: *Self) bool {
- return self.next() % 2 == 0;
- }
-
- pub fn ZX81(seed: u64) Self {
- const mod = pow(u64, 2, 16) + 1;
- return .{
- .seed = seed,
- .mod = mod,
- .mul = 75,
- .inc = 74,
- };
- }
-};
-
-fn formatLog(comptime fmt: []const u8, args: anytype) void {
- var buf: [512]u8 = undefined;
- const m = std.fmt.bufPrint(&buf, fmt, args) catch return;
- consoleLog(m.ptr, m.len);
-}
-
-fn assert(ok: bool) void {
- if (!ok) unreachable;
-}
-
-pub 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;
-}
-
-export fn init() void {
- const f_seed = rand() * (pow(f32, 2, 16) + 1);
- const seed: u64 = @intFromFloat(f_seed);
- rng = LinearCongruentialGenerator.ZX81(seed);
-
- circle_program = CircleProgram.init() catch |err| {
- formatLog("Failed to create CircleProgram. {}", .{err});
- return;
- };
-
- line_program = LineProgram.init() catch |err| {
- formatLog("Failed to create CircleProgram. {}", .{err});
- return;
- };
-
- const height = getScreenHeight();
-
- for (&stars) |*s| {
- s.angle = lerp(0, 2 * pi, rng.randFloat(f32));
- s.initial_len = lerp(0, height / 2, rng.randFloat(f32));
- s.dist = max_dist;
- s.pdist = max_dist;
- s.hue = rng.randFloat(f32);
- }
-
- registerKey(.up, &up);
- registerKey(.right, &right);
- registerKey(.left, &left);
- registerKey(.down, &down);
- registerKey(.c, &c_key);
-}
-
-fn registerKey(key: KeyboardKey, out: *u32) void {
- const key_code = switch (key) {
- .up => "ArrowUp",
- .down => "ArrowDown",
- .left => "ArrowLeft",
- .right => "ArrowRight",
- .c => "KeyC",
- };
- registerKeyInput(key_code.ptr, key_code.len, out);
-}
-
-fn rad2deg(rads: f32) f32 {
- return rads * (180.0 / pi);
-}
-
-export fn update(elapsed_time: f32) void {
- const report_freq = 100;
- frame_counter += 1;
- timer += elapsed_time;
- anim_t += elapsed_time;
- if (frame_counter % report_freq == 0) {
- const avg = timer / report_freq;
- formatLog("{d:.2} Average FPS", .{1.0 / avg});
- timer = 0;
- }
-
- const next_col_mode = c_key != 0 and c_was_pressed == 0;
- c_was_pressed = c_key;
- if (next_col_mode) {
- if (color_mode == .depth) {
- color_mode = .rainbow;
- } else {
- color_mode = @enumFromInt(@intFromEnum(color_mode) + 1);
- }
- }
-
- if (right != 0) {
- speed += 0.1;
- }
- if (left != 0) {
- speed -= 0.1;
- }
- speed = @min(max_speed, @max(speed, -max_speed));
-
- const count_delta = 500;
- if (up != 0) {
- if (sub_count + count_delta <= star_count) {
- sub_count += count_delta;
- }
- }
-
- if (down != 0) {
- if (sub_count >= count_delta) {
- sub_count -= count_delta;
- }
- }
-
- const width = getScreenWidth();
- const height = getScreenHeight();
-
- webgl.viewport(0, 0, @intFromFloat(width), @intFromFloat(height));
- webgl.useProgram(circle_program.prog);
- webgl.bindVertexArray(circle_program.vao);
- webgl.uniform2f(circle_program.res_uniform_location, height, height);
-
- webgl.clearColor(0.0, 0.0, 0.0, 1.0);
- webgl.clear(webgl.color_buffer_bit | webgl.depth_buffer_bit);
-
- var batch: DrawBatch = .{
- .translation = &translation_data,
- .colors = &color_data,
- .scales = &scale_data,
- .lines = &line_data,
- };
-
- for (stars[0..sub_count]) |*s| {
- s.pdist = s.dist;
- s.dist -= speed;
- s.angle += @cos(anim_t) * 0.05;
- const plen = lerp(1000, s.initial_len, s.pdist / max_dist);
- const psx = (@cos(s.angle) * plen) + width * 0.5;
- const psy = (@sin(s.angle) * plen) + height * 0.5;
-
- const len = lerp(1000, s.initial_len, s.dist / max_dist);
- const sx = (@cos(s.angle) * len) + width * 0.5;
- const sy = (@sin(s.angle) * len) + height * 0.5;
- const scale = lerp(16, 0, s.dist / max_dist);
-
- const col = switch (color_mode) {
- .rainbow => s.hue,
- .solid => @sin(anim_t * 0.1) * 0.5 + 1,
- .angle => (s.angle / (2 * pi)) + (@cos(anim_t) + 1) / 2,
- .depth => s.dist / (max_dist * 0.5),
- };
-
- batch.addInstance(.{ sx, sy }, .{ psx, psy }, col, scale) catch unreachable;
- if (batch.len == batch_capacity) {
- batch.draw();
- batch.len = 0;
- }
-
- if (sx < 0 or sx > width or sy < 0 or sy > height + 32) {
- s.angle = lerp(0, 8 * pi, rng.randFloat(f32));
- s.initial_len = lerp(0, height, rng.randFloat(f32));
- s.dist = max_dist;
- s.pdist = max_dist;
- }
- }
-
- batch.draw();
-}
-
-fn lerp(a: f32, b: f32, v: f32) f32 {
- return a + (b - a) * v;
-}
-
-fn invLerp(a: f32, b: f32, v: f32) f32 {
- return (v - a) / (b - a);
-}
-
-fn mapLerp(from_a: f32, from_b: f32, to_a: f32, to_b: f32, v: f32) f32 {
- const pct = invLerp(from_a, from_b, v);
- return lerp(to_a, to_b, pct);
-}
-
-fn circlePoints(comptime segments: u32) [segments * 3][2]f32 {
- const segment_rads = (2 * pi) / @as(comptime_float, segments);
- var r: [segments * 3][2]f32 = undefined;
- for (0..segments) |s| {
- const sf: f32 = @floatFromInt(s);
- const start_angle = segment_rads * sf;
- const start_x = @cos(start_angle);
- const start_y = @sin(start_angle);
- const start: @Vector(2, f32) = .{ start_x, start_y };
-
- const end_angle = segment_rads * (sf + 1);
- const end_x = @cos(end_angle);
- const end_y = @sin(end_angle);
- const end: @Vector(2, f32) = .{ end_x, end_y };
-
- const i = s * 3;
- r[i] = @Vector(2, f32){ 0, 0 };
- r[i + 1] = start;
- r[i + 2] = end;
- }
-
- return r;
-}
-
-fn getUniformLocation(program: webgl.Program, name: []const u8) !i32 {
- const loc = webgl.getUniformLocation(program, name.ptr, name.len);
- if (loc < 0) return error.FailedToGetLocation;
-
- return loc;
-}
-
-fn loadShader(shader_type: webgl.GLShaderType, source: []const u8) !webgl.Shader {
- const shader = webgl.createShader(shader_type);
- errdefer webgl.deleteShader(shader);
-
- webgl.shaderSource(shader, source.ptr, source.len);
- webgl.compileShader(shader);
-
- if (webgl.getShaderParameter(shader, .compile_status) == 0) {
- var buf: [512]u8 = undefined;
- const len = webgl.getShaderInfoLog(shader, &buf, buf.len);
- const msg = buf[0..len];
- consoleLog(msg.ptr, msg.len);
- return error.CompilationFailed;
- }
-
- return shader;
-}
-
-fn createGLProgram(vert: webgl.Shader, frag: webgl.Shader) !webgl.Program {
- const program = webgl.createProgram();
- errdefer webgl.deleteProgram(program);
-
- webgl.attachShader(program, vert);
- webgl.attachShader(program, frag);
- webgl.linkProgram(program);
- if (webgl.getProgramParameter(program, .link_status) == 0) {
- var buf: [512]u8 = undefined;
- const len = webgl.getProgramInfoLog(program, &buf, buf.len);
- const msg = buf[0..len];
- consoleLog(msg.ptr, msg.len);
- return error.LinkFailed;
- }
-
- return program;
-}
diff --git a/src/webgl.js b/src/webgl.js
deleted file mode 100644
index 572773c..0000000
--- a/src/webgl.js
+++ /dev/null
@@ -1,261 +0,0 @@
-const canvas = document.getElementById("app-canvas");
-const gfx_ctx = canvas.getContext("webgl2");
-if (gfx_ctx === null) {
- alert("There was a problem initializing WebGL. Your browser or machine may not support it.");
-}
-
-gfx_ctx.enable(gfx_ctx.BLEND);
-gfx_ctx.enable(gfx_ctx.DEPTH_TEST);
-gfx_ctx.blendFunc(gfx_ctx.SRC_ALPHA, gfx_ctx.ONE_MINUS_SRC_ALPHA);
-
-let next_id = 0;
-const getId = () => {
- next_id += 1;
- return next_id - 1;
-};
-
-const glBuffers = new Map();
-const glShaders = new Map();
-const glPrograms = new Map();
-const glVertexArrays = new Map();
-const glUniformLocations = new Map();
-
-const clearColor = (r, g, b, a) => {
- gfx_ctx.clearColor(r, g, b, a);
-};
-
-const clear = (mask) => {
- gfx_ctx.clear(mask);
-};
-
-const createBuffer = () => {
- const id = getId();
- glBuffers.set(id, gfx_ctx.createBuffer());
- return id;
-};
-
-const bindBuffer = (target, id) => {
- gfx_ctx.bindBuffer(target, glBuffers.get(id));
-};
-
-const bufferData = (target, ptr, len, usage) => {
- const floats = new Float32Array(memory.buffer, ptr, len);
- if (len === 9) {
- console.log(floats);
- }
- gfx_ctx.bufferData(target, floats, usage);
-};
-
-const createShader = (type) => {
- const id = getId();
- glShaders.set(id, gfx_ctx.createShader(type));
- return id;
-};
-
-const shaderSource = (shader, ptr, len) => {
- const source = readString(ptr, len);
- console.log(source);
- gfx_ctx.shaderSource(glShaders.get(shader), source);
-};
-
-const compileShader = (shader) => {
- gfx_ctx.compileShader(glShaders.get(shader));
-};
-
-const getShaderParameter = (shader, info) => {
- return gfx_ctx.getShaderParameter(glShaders.get(shader), info);
-};
-
-const deleteShader = (shader) => {
- gfx_ctx.deleteShader(glShaders.get(shader));
-};
-
-const getShaderInfoLog = (shader, ptr, len) => {
- const msg = gfx_ctx.getShaderInfoLog(glShaders.get(shader));
- const r = writeString(msg, ptr, len);
- return r;
-};
-
-const createProgram = (type) => {
- const id = getId();
- glPrograms.set(id, gfx_ctx.createProgram());
- return id;
-};
-
-const deleteProgram = (program) => {
- gfx_ctx.deleteProgram(glPrograms.get(program));
-};
-
-const attachShader = (program_id, shader_id) => {
- const program = glPrograms.get(program_id);
- const shader = glShaders.get(shader_id);
- gfx_ctx.attachShader(program, shader);
-};
-
-const linkProgram = (program) => {
- gfx_ctx.linkProgram(glPrograms.get(program));
-};
-
-const getProgramParameter = (program_id, info) => {
- const program = glPrograms.get(program_id);
- return gfx_ctx.getProgramParameter(program, info);
-};
-
-const getProgramInfoLog = (program, ptr, len) => {
- const msg = gfx_ctx.getProgramInfoLog(glPrograms.get(program));
- const r = writeString(msg, ptr, len);
- return r;
-};
-
-const getAttribLocation = (program, ptr, len) => {
- const attrib = readString(ptr, len);
- return gfx_ctx.getAttribLocation(glPrograms.get(program), attrib);
-};
-
-const getUniformLocation = (program, ptr, len) => {
- const uniform = readString(ptr, len);
- const loc = gfx_ctx.getUniformLocation(glPrograms.get(program), uniform);
- if (!loc) console.log("Uniform ", uniform, " could not be found");
- if (!loc) return -1;
-
- const id = getId();
- glUniformLocations.set(id, loc);
- return id;
-};
-
-const createVertexArray = () => {
- const id = getId();
- glVertexArrays.set(id, gfx_ctx.createVertexArray());
- return id;
-};
-
-const bindVertexArray = (vao) => {
- gfx_ctx.bindVertexArray(glVertexArrays.get(vao));
-};
-
-const enableVertexAttribArray = (attrib_location) => {
- gfx_ctx.enableVertexAttribArray(attrib_location);
-};
-
-const vertexAttribPointer = (loc, size, type, normalize, stride, offset) => {
- gfx_ctx.vertexAttribPointer(loc, size, type, normalize, stride, offset);
-};
-
-const viewport = (x, y, width, height) => {
- gfx_ctx.viewport(x, y, width, height);
-};
-
-const drawArrays = (mode, first, count) => {
- gfx_ctx.drawArrays(mode, first, count);
-};
-
-const useProgram = (prog) => {
- gfx_ctx.useProgram(glPrograms.get(prog));
-};
-
-const uniform1i = (location, v0) => {
- gfx_ctx.uniform1i(glUniformLocations.get(location), v0);
-};
-
-const uniform2f = (location, v0, v1) => {
- gfx_ctx.uniform2f(glUniformLocations.get(location), v0, v1);
-};
-
-const uniform4f = (location, v0, v1, v2, v3) => {
- gfx_ctx.uniform4f(glUniformLocations.get(location), v0, v1, v2, v3);
-};
-
-const uniformMatrix3fv = (location, ptr) => {
- const u = glUniformLocations.get(location);
- const floats = new Float32Array(memory.buffer, ptr, 9);
-
- gfx_ctx.uniformMatrix3fv(glUniformLocations.get(location), false, floats);
-};
-
-const glTextures = new Map();
-
-const createTexture = () => {
- const id = getId();
- glTextures.set(id, gfx_ctx.createTexture());
- return id;
-};
-
-const bindTexture = (target, tex_id) => {
- const texture = glTextures.get(tex_id);
- gfx_ctx.bindTexture(target, texture);
-};
-
-const texImage2D = (target, level, interal_format,
- width, height, border, format,
- data_type, ptr, count, offset) => {
- const data = new Uint8Array(memory.buffer, ptr, count);
- gfx_ctx.texImage2D(target, level, interal_format, width, height, border, format, data_type, data, offset);
-};
-
-const activeTexture = (tex_id) => {
- gfx_ctx.activeTexture(tex_id);
-};
-
-const vertexAttribDivisor = (loc, divisor) => {
- gfx_ctx.vertexAttribDivisor(loc, divisor);
-};
-
-const drawArraysInstanced = (mode, first, count, instanceCount) => {
- gfx_ctx.drawArraysInstanced(mode, first, count, instanceCount);
-};
-
-const getScreenWidth = () => {
- return gfx_ctx.drawingBufferWidth;
-};
-
-const getScreenHeight = () => {
- return gfx_ctx.drawingBufferHeight;
-};
-
-const webgl = {
- clear,
- clearColor,
- createBuffer,
- bindBuffer,
- bufferData,
-
- createShader,
- shaderSource,
- compileShader,
- getShaderParameter,
- deleteShader,
- getShaderInfoLog,
-
- createProgram,
- deleteProgram,
- attachShader,
- linkProgram,
- getProgramParameter,
- getProgramInfoLog,
- useProgram,
-
- getAttribLocation,
- getUniformLocation,
- createVertexArray,
- bindVertexArray,
- enableVertexAttribArray,
- vertexAttribPointer,
- viewport,
- drawArrays,
-
- uniform1i,
- uniform2f,
- uniform4f,
- uniformMatrix3fv,
-
- createTexture,
- bindTexture,
- texImage2D,
- activeTexture,
-
- vertexAttribDivisor,
- drawArraysInstanced,
-
- getScreenWidth,
- getScreenHeight,
-};
diff --git a/src/webgl.zig b/src/webgl.zig
deleted file mode 100644
index 0343bff..0000000
--- a/src/webgl.zig
+++ /dev/null
@@ -1,152 +0,0 @@
-pub const Buffer = extern struct { handle: u32 };
-pub const Shader = packed struct(u32) { handle: u32 };
-pub const Program = packed struct(u32) { handle: u32 };
-pub const Texture = packed struct(u32) { handle: u32 };
-
-pub const GLProgramInfo = enum(u32) {
- delete_status = 0x8B80,
- link_status = 0x8B82,
-};
-
-pub const GLShaderType = enum(u32) {
- fragment_shader = 0x8B30,
- vertex_shader = 0x8B31,
-};
-
-pub const GLShaderInfo = enum(u32) {
- shader_type = 0x8B4F,
- delete_status = 0x8B80,
- compile_status = 0x8B81,
-};
-
-pub const GLBindingPoint = enum(u32) {
- array_buffer = 0x8892,
- element_array_buffer = 0x8893,
-};
-
-pub const GLUsagePattern = enum(u32) {
- stream_draw = 0x88E0,
- static_draw = 0x88E4,
- dynamic_draw = 0x88E8,
-};
-
-pub const color_buffer_bit = 0x00004000;
-pub const depth_buffer_bit = 0x00000100;
-
-pub extern fn clearColor(r: f32, g: f32, b: f32, a: f32) void;
-pub extern fn clear(mask: u32) void;
-
-pub extern fn createBuffer() Buffer;
-pub extern fn bindBuffer(target: GLBindingPoint, buffer: Buffer) void;
-pub extern fn bufferData(
- target: GLBindingPoint,
- ptr: [*c]const f32,
- len: u32,
- usage: GLUsagePattern,
-) void;
-
-pub extern fn createShader(shader_type: GLShaderType) Shader;
-pub extern fn shaderSource(shader: Shader, source_ptr: [*c]const u8, len: u32) void;
-pub extern fn compileShader(shader: Shader) void;
-pub extern fn getShaderParameter(shader: Shader, info: GLShaderInfo) u32;
-pub extern fn deleteShader(shader: Shader) void;
-pub extern fn getShaderInfoLog(shader: Shader, buf: [*c]u8, len: u32) u32;
-
-pub extern fn createProgram() Program;
-pub extern fn deleteProgram(program: Program) void;
-pub extern fn attachShader(program: Program, shader: Shader) void;
-pub extern fn linkProgram(program: Program) void;
-pub extern fn getProgramParameter(program: Program, info: GLProgramInfo) u32;
-pub extern fn getProgramInfoLog(program: Program, buf: [*c]const u8, len: u32) u32;
-pub extern fn useProgram(program: Program) void;
-
-pub extern fn getAttribLocation(program: Program, buf: [*c]const u8, len: u32) i32;
-pub extern fn getUniformLocation(program: Program, buf: [*c]const u8, len: u32) i32;
-
-pub extern fn uniform1i(location: i32, v0: i32) void;
-pub extern fn uniform2f(location: i32, v0: f32, v1: f32) void;
-pub extern fn uniform4f(location: i32, v0: f32, v1: f32, v2: f32, v3: f32) void;
-pub extern fn uniformMatrix3fv(location: i32, ptr: [*c]const @Vector(3, f32)) void;
-
-pub const VertexArrayObject = packed struct(u32) { handle: u32 };
-const GLType = enum(u32) {
- i8 = 0x1400,
- u8 = 0x1401,
- i16 = 0x1402,
- u16 = 0x1403,
- i32 = 0x1404,
- u32 = 0x1405,
- f32 = 0x1406,
-};
-
-const GLBool = enum(i32) {
- false = 0,
- true = 1,
-};
-
-pub extern fn createVertexArray() VertexArrayObject;
-pub extern fn bindVertexArray(vao: VertexArrayObject) void;
-pub extern fn enableVertexAttribArray(attrib_location: i32) void;
-pub extern fn vertexAttribPointer(
- attrib_location: u32,
- size: i32,
- gl_type: GLType,
- normalize: GLBool,
- stride: i32,
- offset: i32,
-) void;
-
-pub extern fn viewport(x: i32, y: i32, width: i32, height: i32) void;
-
-const GLDrawMode = enum(u32) {
- points = 0x0000,
- lines = 0x0001,
- line_loop = 0x0002,
- line_strip = 0x0003,
- triangles = 0x0004,
- triangle_strip = 0x00005,
- triangle_fan = 0x00006,
-};
-
-pub extern fn drawArrays(mode: GLDrawMode, first: i32, count: i32) void;
-
-pub extern fn createTexture() Texture;
-
-const TextureBindTarget = enum(u32) {
- texture_2d = 0x0DE1,
- texture_cube_map = 0x8514,
- texture_3d = 0x806F,
- texture_2d_array = 0x8C1A,
-};
-pub extern fn bindTexture(target: TextureBindTarget, texture: Texture) void;
-
-pub const texture_0 = 0x84c0;
-pub extern fn activeTexture(idx: u32) void;
-
-const TextureTarget = enum(u32) {
- texture_2d = 0x0DE1,
-};
-const TextureFormat = enum(u32) {
- rgba = 0x1908,
-};
-pub extern fn texImage2D(
- target: TextureTarget,
- level: i32,
- internal_format: TextureFormat,
- width: i32,
- height: i32,
- border: i32,
- format: TextureFormat,
- data_type: GLType,
- ptr: *const anyopaque,
- count: u32,
- offset: u32,
-) void;
-
-pub extern fn vertexAttribDivisor(loc: i32, divisor: i32) void;
-pub extern fn drawArraysInstanced(
- mode: GLDrawMode,
- first: i32,
- count: i32,
- instace_count: i32,
-) void;