diff --git a/build.zig b/build.zig index e7accb34..23ead7a7 100644 --- a/build.zig +++ b/build.zig @@ -61,45 +61,30 @@ pub fn build(b: *std.Build) !void { const options = Options{ .core = .{ .gpu_dawn_options = gpu_dawn_options } }; if (target.getCpuArch() != .wasm32) { - const app = b.addExecutable(.{ - .name = "mach", - .root_source_file = .{ .path = "src/mach.zig" }, - .version = .{ .major = 0, .minor = 1, .patch = 0 }, - .optimize = optimize, - .target = target, - }); - app.addModule("mach", module(b, optimize, target)); - if (app.target.getOsTag() == .windows) app.linkLibC(); - b.installArtifact(app); - - const app_run_cmd = b.addRunArtifact(app); - if (b.args) |args| app_run_cmd.addArgs(args); - const app_run_step = b.step("run", "Run Mach Engine Application"); - app_run_step.dependOn(&app_run_cmd.step); - const tests_step = b.step("test", "Run tests"); tests_step.dependOn(&testStep(b, optimize, target).step); - const shaderexp_app = try App.init( + const editor = try App.init( b, .{ - .name = "shaderexp", - .src = "shaderexp/main.zig", + .name = "mach", + .src = "src/editor/app.zig", + .custom_entrypoint = "src/editor/main.zig", .target = target, .optimize = optimize, }, ); - try shaderexp_app.link(options); - shaderexp_app.install(); + try editor.link(options); + editor.install(); - const shaderexp_install_step = b.step("shaderexp", "Install shaderexp"); - shaderexp_install_step.dependOn(&shaderexp_app.getInstallStep().?.step); - const shaderexp_run_cmd = shaderexp_app.addRunArtifact(); - shaderexp_run_cmd.step.dependOn(shaderexp_install_step); + const editor_install_step = b.step("editor", "Install editor"); + editor_install_step.dependOn(&editor.getInstallStep().?.step); + const editor_run_cmd = editor.addRunArtifact(); + editor_run_cmd.step.dependOn(editor_install_step); - const shaderexp_run_step = b.step("run-shaderexp", "Run shaderexp"); - shaderexp_run_step.dependOn(&shaderexp_run_cmd.step); - b.getInstallStep().dependOn(shaderexp_install_step); + const editor_run_step = b.step("run", "Run the editor"); + editor_run_step.dependOn(&editor_run_cmd.step); + b.getInstallStep().dependOn(editor_install_step); } const compile_all = b.step("compile-all", "Compile Mach"); @@ -137,6 +122,7 @@ pub const App = struct { src: []const u8, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode, + custom_entrypoint: ?[]const u8 = null, deps: ?[]const std.build.ModuleDependency = null, res_dirs: ?[]const []const u8 = null, watch_paths: ?[]const []const u8 = null, @@ -157,6 +143,7 @@ pub const App = struct { .src = options.src, .target = options.target, .optimize = options.optimize, + .custom_entrypoint = options.custom_entrypoint, .deps = deps.items, .res_dirs = options.res_dirs, .watch_paths = options.watch_paths, diff --git a/libs/mach-core b/libs/mach-core index ed911a7f..5e1dd169 160000 --- a/libs/mach-core +++ b/libs/mach-core @@ -1 +1 @@ -Subproject commit ed911a7f83605adb8c31cf1a02a18a7879a260bc +Subproject commit 5e1dd1697b2a9487ae136c27a0c5e651321fd439 diff --git a/shaderexp/README.md b/shaderexp/README.md deleted file mode 100644 index e1beee4b..00000000 --- a/shaderexp/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Shaderexp - -This is an executable for testing wgsl shaders on the fly. -Build it and run it with: -`zig build run-shaderexp` - -Then modify shaderexp/frag.wgsl and save. The window will update and use the new fragment shader. -If errors occur, the window will show a black_screen and an error message will be written to stdout. diff --git a/shaderexp/example-shaders/mandelbrot.wgsl b/shaderexp/example-shaders/mandelbrot.wgsl deleted file mode 100755 index dd20c113..00000000 --- a/shaderexp/example-shaders/mandelbrot.wgsl +++ /dev/null @@ -1,38 +0,0 @@ -struct UniformBufferObject { - resolution: vec2, - time: f32, -} -@group(0) @binding(0) var ubo : UniformBufferObject; - -@fragment fn main( - @location(0) uv : vec2 -) -> @location(0) vec4 { - let aspect = ubo.resolution / min(ubo.resolution.x,ubo.resolution.y); - let translated_uv = (uv - vec2(0.5,0.5)) * aspect * 2.0; - let col = f32(mandel(translated_uv)) / 100.0; - - return vec4(vec3(col), 1.0); -} - -fn mandel(uv: vec2) -> i32{ - let zoom = 1.0; - let center_position = vec2(0.5,0.0); - let mapped_point = uv * zoom - center_position; - var z = mapped_point; - var tmp:f32; - var i:i32 = 0; - var found = false; - var res = 0; - loop { - if (i >= 100){ - break; - } - tmp = z.x; - z.x = z.x * z.x - z.y * z.y + mapped_point.x; - z.y = 2. * tmp * z.y + mapped_point.y; - found = found || (z.x * z.x + z.y * z.y > 16.); - res = res + 1 * i32(!found); - i = i + 1; - } - return res; -} diff --git a/shaderexp/example-shaders/ray_marching.wgsl b/shaderexp/example-shaders/ray_marching.wgsl deleted file mode 100755 index 632368b4..00000000 --- a/shaderexp/example-shaders/ray_marching.wgsl +++ /dev/null @@ -1,98 +0,0 @@ -// A slight modification / translation of https://www.shadertoy.com/view/XlGBW3 -// to WGSL. -// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. - -struct UniformBufferObject { - resolution: vec2, - time: f32, -} -@group(0) @binding(0) var ubo : UniformBufferObject; - -fn getDist(p:vec3) -> f32{ - let dist_from_center:f32 = 2.*sin(ubo.time * 3.); - let rotation_speed:f32 = 6.; - - let sphere1 = vec4(dist_from_center*cos(rotation_speed*ubo.time + 3.14159 * 0. * 2. / 3.),1.1, dist_from_center*sin(rotation_speed*ubo.time + 3.14159 + 3.14159 * 0. * 2. / 3.),1.); - let sphere2 = vec4(dist_from_center*cos(rotation_speed*ubo.time + 3.14159 * 1. * 2. / 3.),1.1, dist_from_center*sin(rotation_speed*ubo.time + 3.14159 + 3.14159 * 1. * 2. / 3.),1.); - let sphere3 = vec4(dist_from_center*cos(rotation_speed*ubo.time + 3.14159 * 2. * 2. / 3.),1.1, dist_from_center*sin(rotation_speed*ubo.time + 3.14159 + 3.14159 * 2. * 2. / 3.),1.); - - let sphere1_dist:f32 = length(p - sphere1.xyz) - sphere1.w; - let sphere2_dist:f32 = length(p - sphere2.xyz) - sphere2.w; - let sphere3_dist:f32 = length(p - sphere3.xyz) - sphere3.w; - let plane_dist = p.y; - - return min(min(min(sphere1_dist,sphere2_dist),sphere3_dist),plane_dist); -} - -fn rayMarch(ro:vec3, rd:vec3) -> f32{ - let MAX_STEPS:i32 = 100; - let MAX_DIST:f32 = 100.0; - let SURF_DIST:f32 = 0.01; - var d:f32 = 0.0; - - var i: i32 = 0; - loop { - if(i >= MAX_STEPS){ - break; - } - - let p = ro + rd * d; - let ds = getDist(p); - d = d + ds; - if(d > MAX_DIST || ds <= SURF_DIST){ - break; - } - - i = i + 1; - } - return d; -} - -fn getNormal(p:vec3) -> vec3{ - let d = getDist(p); - let e = vec2(0.1,0.0); - - // We can find the normal using the points around the hit point - let n = d - vec3( - getDist(p-e.xyy), - getDist(p-e.yxy), - getDist(p-e.yyx) - ); - - return normalize(n); -} - -fn getLight(p:vec3) -> f32{ - let SURF_DIST:f32 = .01; - - let light_pos = vec3(0.,5.,0.); - let l = normalize(light_pos - p) * 1.; - let n = getNormal(p); - - var dif = clamp(dot(n,l),.0,1.); - - let d = rayMarch(p + n * SURF_DIST * 2.,l); - if(d -) -> @location(0) vec4 { - let aspect = ubo.resolution / min(ubo.resolution.x,ubo.resolution.y); - let tmp_uv = (uv - vec2(0.5,0.5)) * aspect * 2.0; - var col = vec3(0.0); - - let r_origin = vec3(4.0,3.,.0); - let r_dir = normalize(vec3(-1.0,tmp_uv.y,tmp_uv.x)); - let d = rayMarch(r_origin,r_dir); - col = vec3(d / 8.); - let p = r_origin + r_dir * d; - let diff = getLight(p); - - col = vec3(diff , 0.,0.); - return vec4(col,0.0); -} diff --git a/shaderexp/example-shaders/test_shader.wgsl b/shaderexp/example-shaders/test_shader.wgsl deleted file mode 100755 index f87030ee..00000000 --- a/shaderexp/example-shaders/test_shader.wgsl +++ /dev/null @@ -1,40 +0,0 @@ -struct UniformBufferObject { - resolution: vec2, - time: f32, -} -@group(0) @binding(0) var ubo : UniformBufferObject; - -@fragment fn main( - @location(0) uv : vec2 -) -> @location(0) vec4 { - let aspect = ubo.resolution.xy / ubo.resolution.y; - let translated_uv = (uv - vec2(0.5,0.5)) * 2.0 * aspect; - let freq:f32 = 5.0; - let speed: f32 = 5.0; - let h = (sin(freq * length(translated_uv) + speed * ubo.time) + 1.0) / 2.0; - - let h_off = 20.0; - return vec4(hsl_to_rgb(h * (360.0 - h_off * 2.0) + h_off ,0.7,0.5),1.0); -} - -// 0 ≤ H < 360, 0 ≤ S ≤ 1 and 0 ≤ L ≤ 1 -fn hsl_to_rgb(h:f32,s:f32,l:f32) -> vec3 { - let tmp_h = h % 360.0; - let c = (1.0 - abs(2.0 * l - 1.0)) * s; - let x = c * (1.0 - abs((tmp_h / 60.0) % 2.0 - 1.0)); - let m = l - c / 2.0; - - let case_1 = vec3(c ,x ,0.0); - let case_2 = vec3(x ,c ,0.0); - let case_3 = vec3(0.0,c ,x); - let case_4 = vec3(0.0,x ,c); - let case_5 = vec3(x ,0.0,c); - let case_6 = vec3(c ,0.0,x); - - return case_1 * f32(tmp_h < 60.0 && tmp_h >= 0.0) + - case_2 * f32(tmp_h < 120.0 && tmp_h >= 60.0) + - case_3 * f32(tmp_h < 180.0 && tmp_h >= 120.0) + - case_4 * f32(tmp_h < 240.0 && tmp_h >= 180.0) + - case_5 * f32(tmp_h < 300.0 && tmp_h >= 240.0) + - case_6 * f32(tmp_h < 360.0 && tmp_h >= 300.0) + vec3(m); -} diff --git a/src/editor/Builder.zig b/src/editor/Builder.zig index 9cb2a2c4..a0b22035 100644 --- a/src/editor/Builder.zig +++ b/src/editor/Builder.zig @@ -2,7 +2,7 @@ const std = @import("std"); const mime_map = @import("Builder/mime.zig").mime_map; const Target = @import("target.zig").Target; const OptimizeMode = std.builtin.OptimizeMode; -const allocator = @import("entrypoint.zig").allocator; +const allocator = @import("main.zig").allocator; const Builder = @This(); diff --git a/shaderexp/main.zig b/src/editor/app.zig similarity index 98% rename from shaderexp/main.zig rename to src/editor/app.zig index b0229085..276e08f5 100755 --- a/shaderexp/main.zig +++ b/src/editor/app.zig @@ -24,13 +24,13 @@ fragment_shader_code: [:0]const u8, last_mtime: i128, pub fn init(app: *App) !void { - try app.core.init(allocator, .{ .title = "shaderexp" }); + try app.core.init(allocator, .{ .title = "Mach editor" }); var fragment_file: std.fs.File = undefined; var last_mtime: i128 = undefined; // TODO: there is no guarantee we are in the mach project root - if (std.fs.cwd().openFile("shaderexp/frag.wgsl", .{ .mode = .read_only })) |file| { + if (std.fs.cwd().openFile("src/editor/frag.wgsl", .{ .mode = .read_only })) |file| { fragment_file = file; if (file.stat()) |stat| { last_mtime = stat.mtime; diff --git a/shaderexp/black_screen_frag.wgsl b/src/editor/black_screen_frag.wgsl similarity index 100% rename from shaderexp/black_screen_frag.wgsl rename to src/editor/black_screen_frag.wgsl diff --git a/shaderexp/frag.wgsl b/src/editor/frag.wgsl similarity index 100% rename from shaderexp/frag.wgsl rename to src/editor/frag.wgsl diff --git a/src/editor/entrypoint.zig b/src/editor/main.zig similarity index 92% rename from src/editor/entrypoint.zig rename to src/editor/main.zig index f3a8f137..96e7e9d8 100644 --- a/src/editor/entrypoint.zig +++ b/src/editor/main.zig @@ -1,8 +1,22 @@ +//! The 'mach' CLI and engine editor + +// Check that the user's app matches the required interface. +comptime { + if (!@import("builtin").is_test) @import("core").AppInterface(@import("app")); +} + const std = @import("std"); const builtin = @import("builtin"); + +const App = @import("app").App; +const core = @import("core"); +const gpu = core.gpu; + const Builder = @import("Builder.zig"); const Target = @import("target.zig").Target; +pub const GPUInterface = gpu.dawn.Interface; + const default_zig_path = "zig"; var args: []const [:0]u8 = undefined; @@ -10,13 +24,24 @@ var arg_i: usize = 1; var gpa = std.heap.GeneralPurposeAllocator(.{}){}; pub const allocator = gpa.allocator(); -pub fn Main() !void { +pub fn main() !void { defer _ = gpa.deinit(); args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); - if (args.len == 1) return; + if (args.len == 1) { + gpu.Impl.init(); + _ = gpu.Export(GPUInterface); + + var app: App = undefined; + try app.init(); + defer app.deinit(); + + while (true) { + if (try app.update()) return; + } + } if (std.mem.eql(u8, args[arg_i], "build")) { arg_i += 1; diff --git a/src/editor/target.zig b/src/editor/target.zig index 5f57b209..efeeea8d 100644 --- a/src/editor/target.zig +++ b/src/editor/target.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const allocator = @import("entrypoint.zig").allocator; +const allocator = @import("main.zig").allocator; pub const Target = enum { @"linux-x86_64", diff --git a/shaderexp/vert.wgsl b/src/editor/vert.wgsl similarity index 100% rename from shaderexp/vert.wgsl rename to src/editor/vert.wgsl diff --git a/src/mach.zig b/src/mach.zig deleted file mode 100644 index 982c06a9..00000000 --- a/src/mach.zig +++ /dev/null @@ -1,7 +0,0 @@ -//! The 'mach' CLI and engine editor - -const entrypoint = @import("editor/entrypoint.zig"); - -pub fn main() !void { - try entrypoint.Main(); -}