Skip to content

Commit 0ab3ba2

Browse files
committed
Port minimal_glfw_gl to Emscripten
1 parent 8e5981a commit 0ab3ba2

File tree

5 files changed

+154
-19
lines changed

5 files changed

+154
-19
lines changed

build.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ pub const samples = struct {
160160
/// Sample apps that can be built as web applications using zemscripten.
161161
pub const web = struct {
162162
pub const sdl2_demo = samples.crossplatform.sdl2_demo;
163+
pub const minimal_glfw_gl = samples.crossplatform.minimal_glfw_gl;
163164

164165
// TODO: WebGL samples
165-
// pub const minimal_glfw_gl = samples.crossplatform.minimal_glfw_gl;
166166
// pub const minimal_sdl_gl = samples.crossplatform.minimal_sdl_gl;
167167
// pub const minimal_zgui_glfw_gl = samples.crossplatform.minimal_zgui_glfw_gl;
168168

samples/minimal_glfw_gl/build.zig

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub fn build(b: *std.Build, options: anytype) *std.Build.Step.Compile {
77
const src_path = b.pathJoin(&.{ cwd_path, "src" });
88
const exe = b.addExecutable(.{
99
.name = demo_name,
10-
.root_source_file = b.path(b.pathJoin(&.{ src_path, demo_name ++ ".zig" })),
10+
.root_source_file = b.path(b.pathJoin(&.{ src_path, "main.zig" })),
1111
.target = options.target,
1212
.optimize = options.optimize,
1313
});
@@ -34,3 +34,55 @@ pub fn build(b: *std.Build, options: anytype) *std.Build.Step.Compile {
3434

3535
return exe;
3636
}
37+
38+
pub fn buildWeb(b: *std.Build, options: anytype) *std.Build.Step {
39+
const cwd_path = b.pathJoin(&.{ "samples", demo_name });
40+
const src_path = b.pathJoin(&.{ cwd_path, "src" });
41+
42+
const zemscripten = @import("zemscripten");
43+
44+
const zglfw = b.dependency("zglfw", .{
45+
.target = options.target,
46+
});
47+
const zopengl = b.dependency("zopengl", .{
48+
.target = options.target,
49+
});
50+
51+
const wasm = b.addStaticLibrary(.{
52+
.name = demo_name,
53+
.root_source_file = b.path(b.pathJoin(&.{ src_path, "main-web.zig" })),
54+
.target = options.target,
55+
.optimize = options.optimize,
56+
});
57+
58+
wasm.root_module.addImport("zglfw", zglfw.module("root"));
59+
60+
wasm.root_module.addImport("zopengl", zopengl.module("root"));
61+
62+
wasm.root_module.addImport("zemscripten", b.dependency("zemscripten", .{}).module("root"));
63+
64+
const emcc_flags = zemscripten.emccDefaultFlags(b.allocator, .{
65+
.optimize = options.optimize,
66+
.fsanitize = true,
67+
});
68+
69+
var emcc_settings = zemscripten.emccDefaultSettings(b.allocator, .{
70+
.optimize = options.optimize,
71+
});
72+
emcc_settings.put("ALLOW_MEMORY_GROWTH", "1") catch unreachable;
73+
emcc_settings.put("USE_GLFW", "3") catch unreachable;
74+
emcc_settings.put("MIN_WEBGL_VERSION", "2") catch unreachable;
75+
emcc_settings.put("MAX_WEBGL_VERSION", "2") catch unreachable;
76+
emcc_settings.put("FULL_ES2", "1") catch unreachable;
77+
78+
return zemscripten.emccStep(
79+
b,
80+
wasm,
81+
.{
82+
.optimize = options.optimize,
83+
.flags = emcc_flags,
84+
.settings = emcc_settings,
85+
.install_dir = .{ .custom = "web" },
86+
},
87+
);
88+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const std = @import("std");
2+
3+
const zemscripten = @import("zemscripten");
4+
pub const panic = zemscripten.panic;
5+
6+
pub const std_options = std.Options{
7+
.logFn = zemscripten.log,
8+
};
9+
10+
const minimal_glfw_gl = @import("minimal_glfw_gl.zig");
11+
12+
var initialised = false;
13+
14+
export fn main() c_int {
15+
zemscripten.setMainLoop(mainLoopCallback, null, false);
16+
return 0;
17+
}
18+
19+
export fn mainLoopCallback() void {
20+
if (initialised == false) {
21+
minimal_glfw_gl.init(.{
22+
.api = .opengl_es_api,
23+
.version_major = 2,
24+
.version_minor = 0,
25+
}) catch |err| {
26+
std.log.err("minimal_glfw_gl.init failed with error: {s}", .{@errorName(err)});
27+
return;
28+
};
29+
initialised = true;
30+
}
31+
32+
minimal_glfw_gl.updateAndRender();
33+
}

samples/minimal_glfw_gl/src/main.zig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const std = @import("std");
2+
3+
const minimal_glfw_gl = @import("minimal_glfw_gl.zig");
4+
5+
pub fn main() !void {
6+
{ // Change current working directory to where the executable is located.
7+
var buffer: [1024]u8 = undefined;
8+
const path = std.fs.selfExeDirPath(buffer[0..]) catch ".";
9+
try std.posix.chdir(path);
10+
}
11+
12+
try minimal_glfw_gl.init(.{
13+
.api = .opengl_api,
14+
.version_major = 4,
15+
.version_minor = 0,
16+
});
17+
defer minimal_glfw_gl.deinit();
18+
19+
while (minimal_glfw_gl.shouldQuit() == false) {
20+
minimal_glfw_gl.updateAndRender();
21+
}
22+
}

samples/minimal_glfw_gl/src/minimal_glfw_gl.zig

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,63 @@ const std = @import("std");
22
const glfw = @import("zglfw");
33
const zopengl = @import("zopengl");
44

5-
pub fn main() !void {
5+
var window: *glfw.Window = undefined;
6+
7+
pub fn init(gl_settings: struct {
8+
api: glfw.ClientApi,
9+
version_major: u16,
10+
version_minor: u16,
11+
}) !void {
612
try glfw.init();
7-
defer glfw.terminate();
813

9-
const gl_major = 4;
10-
const gl_minor = 0;
11-
glfw.windowHint(.context_version_major, gl_major);
12-
glfw.windowHint(.context_version_minor, gl_minor);
14+
glfw.windowHint(.client_api, gl_settings.api);
15+
glfw.windowHint(.context_version_major, gl_settings.version_major);
16+
glfw.windowHint(.context_version_minor, gl_settings.version_minor);
1317
glfw.windowHint(.opengl_profile, .opengl_core_profile);
1418
glfw.windowHint(.opengl_forward_compat, true);
15-
glfw.windowHint(.client_api, .opengl_api);
1619
glfw.windowHint(.doublebuffer, true);
1720

18-
const window = try glfw.Window.create(600, 600, "zig-gamedev: minimal_glfw_gl", null);
19-
defer window.destroy();
21+
window = try glfw.Window.create(600, 600, "zig-gamedev: minimal_glfw_gl", null);
2022

2123
glfw.makeContextCurrent(window);
2224

23-
try zopengl.loadCoreProfile(glfw.getProcAddress, gl_major, gl_minor);
24-
25-
const gl = zopengl.bindings;
25+
switch (gl_settings.api) {
26+
.no_api => unreachable,
27+
.opengl_api => {
28+
try zopengl.loadCoreProfile(
29+
glfw.getProcAddress,
30+
gl_settings.version_major,
31+
gl_settings.version_minor,
32+
);
33+
},
34+
.opengl_es_api => {
35+
try zopengl.loadEsProfile(
36+
glfw.getProcAddress,
37+
gl_settings.version_major,
38+
gl_settings.version_minor,
39+
);
40+
},
41+
}
2642

2743
glfw.swapInterval(1);
44+
}
2845

29-
while (!window.shouldClose()) {
30-
glfw.pollEvents();
46+
pub fn deinit() void {
47+
window.destroy();
48+
glfw.terminate();
49+
}
3150

32-
gl.clearBufferfv(gl.COLOR, 0, &[_]f32{ 0.2, 0.6, 0.4, 1.0 });
51+
pub fn shouldQuit() bool {
52+
return window.shouldClose();
53+
}
3354

34-
window.swapBuffers();
35-
}
55+
pub fn updateAndRender() void {
56+
glfw.pollEvents();
57+
58+
const gl = zopengl.bindings;
59+
60+
gl.clearColor(0.12, 0.24, 0.36, 1.0);
61+
gl.clear(gl.COLOR_BUFFER_BIT);
62+
63+
window.swapBuffers();
3664
}

0 commit comments

Comments
 (0)