├── .gitignore ├── Lesson01 ├── build.zig └── src │ ├── c.zig │ └── main.zig ├── Lesson02 ├── build.zig └── src │ ├── c.zig │ └── main.zig ├── Lesson03 ├── build.zig └── src │ ├── c.zig │ └── main.zig ├── Lesson04 ├── build.zig └── src │ ├── c.zig │ └── main.zig ├── Lesson05 ├── build.zig └── src │ ├── c.zig │ └── main.zig ├── Lesson06 ├── build.zig ├── src │ ├── c.zig │ ├── data │ │ └── NeHe.png │ ├── main.zig │ └── png.zig └── stb_image-2.23 │ ├── stb_image.h │ └── stb_image_impl.c ├── Lesson07 ├── build.zig ├── src │ ├── c.zig │ ├── data │ │ └── Crate.png │ ├── main.zig │ └── png.zig └── stb_image-2.23 │ ├── stb_image.h │ └── stb_image_impl.c ├── Lesson08 ├── build.zig ├── src │ ├── c.zig │ ├── data │ │ └── Glass.png │ ├── main.zig │ └── png.zig └── stb_image-2.23 │ ├── stb_image.h │ └── stb_image_impl.c ├── README.md └── zigNeHe.png /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | **/zig-cache 3 | **/zig-out 4 | -------------------------------------------------------------------------------- /Lesson01/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const currentTarget = @import("builtin").target; 3 | 4 | pub fn build(b: *std.Build) void { 5 | const target = b.standardTargetOptions(.{}); 6 | const optimize = b.standardOptimizeOption(.{}); 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "Lesson01", 10 | .root_source_file = .{ .path = "src/main.zig" }, 11 | .target = target, 12 | .optimize = optimize, 13 | }); 14 | 15 | switch (currentTarget.os.tag) { 16 | .macos => { 17 | exe.addFrameworkPath(.{ .path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" }); 18 | exe.linkFramework("OpenGL"); 19 | }, 20 | .freebsd => { 21 | exe.addIncludePath(.{ .path = "/usr/local/include/GL" }); 22 | exe.linkSystemLibrary("gl"); 23 | exe.linkSystemLibrary("glu"); 24 | }, 25 | .linux => { 26 | exe.addLibraryPath(.{ .path = "/usr/lib/x86_64-linux-gnu" }); 27 | exe.linkSystemLibrary("c"); 28 | exe.linkSystemLibrary("GL"); 29 | }, 30 | else => { 31 | @panic("don't know how to build on your system"); 32 | }, 33 | } 34 | exe.addIncludePath(.{ .path = "/usr/local/include" }); 35 | exe.linkSystemLibrary("glfw"); 36 | 37 | b.installArtifact(exe); 38 | 39 | const run_cmd = b.addRunArtifact(exe); 40 | run_cmd.step.dependOn(b.getInstallStep()); 41 | 42 | const run_step = b.step("run", "Run the app"); 43 | run_step.dependOn(&run_cmd.step); 44 | } 45 | -------------------------------------------------------------------------------- /Lesson01/src/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cInclude("GLFW/glfw3.h"); 3 | }); 4 | -------------------------------------------------------------------------------- /Lesson01/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const warn = std.log.warn; 3 | const panic = std.debug.panic; 4 | const c = @import("c.zig"); 5 | 6 | const width: i32 = 1024; 7 | const height: i32 = 768; 8 | 9 | var window: *c.GLFWwindow = undefined; 10 | 11 | fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { 12 | _ = err; 13 | panic("Error: {s}\n", .{description}); 14 | } 15 | 16 | fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { 17 | _ = scancode; 18 | _ = mods; 19 | 20 | if (action != c.GLFW_PRESS) return; 21 | 22 | switch (key) { 23 | c.GLFW_KEY_ESCAPE => c.glfwSetWindowShouldClose(win, c.GL_TRUE), 24 | else => {}, 25 | } 26 | } 27 | 28 | fn perspectiveGL(fovY: f64, aspect: f64, zNear: f64, zFar: f64) void { 29 | const fH = std.math.tan(fovY / 360 * std.math.pi) * zNear; 30 | const fW = fH * aspect; 31 | c.glFrustum(-fW, fW, -fH, fH, zNear, zFar); 32 | } 33 | 34 | fn init_gl() void { 35 | c.glMatrixMode(c.GL_PROJECTION); // Select The Projection Matrix 36 | c.glLoadIdentity(); 37 | 38 | const fHeight: f32 = @floatFromInt(height); 39 | const fWidth: f32 = @floatFromInt(width); 40 | const aspect_ratio = fHeight / fWidth; 41 | perspectiveGL(45.0, (1.0 / aspect_ratio), 0.1, 100.0); 42 | 43 | c.glMatrixMode(c.GL_MODELVIEW); 44 | c.glShadeModel(c.GL_SMOOTH); // Enables Smooth Shading 45 | c.glClearColor(0.0, 0.0, 0.0, 0.0); // Black Background 46 | c.glClearDepth(1.0); // Depth Buffer Setup 47 | c.glEnable(c.GL_DEPTH_TEST); // Enables Depth Testing 48 | c.glDepthFunc(c.GL_LEQUAL); // The Type Of Depth Test To Do 49 | c.glHint(c.GL_PERSPECTIVE_CORRECTION_HINT, c.GL_NICEST); // Really Nice Perspective Calculations 50 | } 51 | 52 | fn init() bool { 53 | _ = c.glfwSetErrorCallback(errorCallback); 54 | 55 | if (c.glfwInit() == c.GL_FALSE) { 56 | warn("Failed to initialize GLFW\n", .{}); 57 | return false; 58 | } 59 | 60 | c.glfwWindowHint(c.GLFW_SAMPLES, 4); // 4x antialiasing 61 | 62 | window = c.glfwCreateWindow(width, height, "Lesson01", null, null) orelse { 63 | panic("unable to create window\n", .{}); 64 | }; 65 | 66 | _ = c.glfwSetKeyCallback(window, keyCallback); 67 | c.glfwMakeContextCurrent(window); 68 | c.glfwSwapInterval(1); 69 | 70 | init_gl(); 71 | return true; 72 | } 73 | 74 | pub fn main() u8 { 75 | if (!init()) { 76 | return 1; 77 | } 78 | 79 | while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { 80 | // Draw nothing, see you in tutorial 2 ! 81 | // Swap buffers 82 | c.glfwSwapBuffers(window); 83 | 84 | c.glfwPollEvents(); 85 | } 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /Lesson02/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const currentTarget = @import("builtin").target; 3 | 4 | pub fn build(b: *std.Build) void { 5 | const target = b.standardTargetOptions(.{}); 6 | const optimize = b.standardOptimizeOption(.{}); 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "Lesson02", 10 | .root_source_file = .{ .path = "src/main.zig" }, 11 | .target = target, 12 | .optimize = optimize, 13 | }); 14 | 15 | switch (currentTarget.os.tag) { 16 | .macos => { 17 | exe.addFrameworkPath(.{ .path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" }); 18 | exe.linkFramework("OpenGL"); 19 | }, 20 | .freebsd => { 21 | exe.addIncludePath(.{ .path = "/usr/local/include/GL" }); 22 | exe.linkSystemLibrary("gl"); 23 | exe.linkSystemLibrary("glu"); 24 | }, 25 | .linux => { 26 | exe.addLibraryPath(.{ .path = "/usr/lib/x86_64-linux-gnu" }); 27 | exe.linkSystemLibrary("c"); 28 | exe.linkSystemLibrary("GL"); 29 | }, 30 | else => { 31 | @panic("don't know how to build on your system"); 32 | }, 33 | } 34 | exe.addIncludePath(.{ .path = "/usr/local/include" }); 35 | exe.linkSystemLibrary("glfw"); 36 | 37 | b.installArtifact(exe); 38 | 39 | const run_cmd = b.addRunArtifact(exe); 40 | run_cmd.step.dependOn(b.getInstallStep()); 41 | 42 | const run_step = b.step("run", "Run the app"); 43 | run_step.dependOn(&run_cmd.step); 44 | } 45 | -------------------------------------------------------------------------------- /Lesson02/src/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cInclude("GLFW/glfw3.h"); 3 | }); 4 | -------------------------------------------------------------------------------- /Lesson02/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const warn = std.log.warn; 3 | const panic = std.debug.panic; 4 | const c = @import("c.zig"); 5 | 6 | const width: i32 = 1024; 7 | const height: i32 = 768; 8 | 9 | var window: *c.GLFWwindow = undefined; 10 | 11 | fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { 12 | _ = err; 13 | panic("Error: {s}\n", .{description}); 14 | } 15 | 16 | fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { 17 | _ = scancode; 18 | _ = mods; 19 | 20 | if (action != c.GLFW_PRESS) return; 21 | 22 | switch (key) { 23 | c.GLFW_KEY_ESCAPE => c.glfwSetWindowShouldClose(win, c.GL_TRUE), 24 | else => {}, 25 | } 26 | } 27 | 28 | fn perspectiveGL(fovY: f64, aspect: f64, zNear: f64, zFar: f64) void { 29 | const fH = std.math.tan(fovY / 360 * std.math.pi) * zNear; 30 | const fW = fH * aspect; 31 | c.glFrustum(-fW, fW, -fH, fH, zNear, zFar); 32 | } 33 | 34 | fn init_gl() void { 35 | c.glMatrixMode(c.GL_PROJECTION); // Select The Projection Matrix 36 | c.glLoadIdentity(); 37 | const fHeight: f32 = @floatFromInt(height); 38 | const fWidth: f32 = @floatFromInt(width); 39 | const aspect_ratio = fHeight / fWidth; 40 | perspectiveGL(45.0, (1.0 / aspect_ratio), 0.1, 100.0); 41 | c.glMatrixMode(c.GL_MODELVIEW); 42 | c.glShadeModel(c.GL_SMOOTH); // Enables Smooth Shading 43 | c.glClearColor(0.0, 0.0, 0.0, 0.0); // Black Background 44 | c.glClearDepth(1.0); // Depth Buffer Setup 45 | c.glEnable(c.GL_DEPTH_TEST); // Enables Depth Testing 46 | c.glDepthFunc(c.GL_LEQUAL); // The Type Of Depth Test To Do 47 | c.glHint(c.GL_PERSPECTIVE_CORRECTION_HINT, c.GL_NICEST); // Really Nice Perspective Calculations 48 | } 49 | 50 | fn init() bool { 51 | _ = c.glfwSetErrorCallback(errorCallback); 52 | 53 | if (c.glfwInit() == c.GL_FALSE) { 54 | warn("Failed to initialize GLFW\n", .{}); 55 | return false; 56 | } 57 | 58 | c.glfwWindowHint(c.GLFW_SAMPLES, 4); // 4x antialiasing 59 | 60 | window = c.glfwCreateWindow(width, height, "Lesson02", null, null) orelse { 61 | panic("unable to create window\n", .{}); 62 | }; 63 | 64 | _ = c.glfwSetKeyCallback(window, keyCallback); 65 | c.glfwMakeContextCurrent(window); 66 | c.glfwSwapInterval(1); 67 | 68 | init_gl(); 69 | return true; 70 | } 71 | 72 | fn draw() void { // Here's Where We Do All The Drawing 73 | c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer 74 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 75 | c.glTranslatef(-1.5, 0.0, -6.0); // Move Left 1.5 Units And Into The Screen 6.0 76 | 77 | c.glBegin(c.GL_TRIANGLES); // Drawing Using Triangles 78 | c.glVertex3f( 0.0, 1.0, 0.0); // Move Up One Unit From Center (Top Point) 79 | c.glVertex3f(-1.0, -1.0, 0.0); // Left And Down One Unit (Bottom Left) 80 | c.glVertex3f( 1.0, -1.0, 0.0); // Right And Down One Unit (Bottom Right) 81 | c.glEnd(); // Finished Drawing The Triangle 82 | 83 | c.glTranslatef(3.0, 0.0, 0.0); // Move Right 3 Units 84 | 85 | c.glBegin(c.GL_QUADS); // Draw A Quad 86 | c.glVertex3f(-1.0, 1.0, 0.0); // Top Left 87 | c.glVertex3f( 1.0, 1.0, 0.0); // Top Right 88 | c.glVertex3f( 1.0, -1.0, 0.0); // Bottom Right 89 | c.glVertex3f(-1.0, -1.0, 0.0); // Bottom Left 90 | c.glEnd(); // Done Drawing The Quad 91 | 92 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 93 | } 94 | 95 | pub fn main() u8 { 96 | if (!init()) { 97 | return 1; 98 | } 99 | 100 | while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { 101 | // Actually draw stuff. 102 | draw(); 103 | 104 | // Swap buffers 105 | c.glfwSwapBuffers(window); 106 | 107 | c.glfwPollEvents(); 108 | } 109 | 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /Lesson03/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const currentTarget = @import("builtin").target; 3 | 4 | pub fn build(b: *std.Build) void { 5 | const target = b.standardTargetOptions(.{}); 6 | const optimize = b.standardOptimizeOption(.{}); 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "Lesson03", 10 | .root_source_file = .{ .path = "src/main.zig" }, 11 | .target = target, 12 | .optimize = optimize, 13 | }); 14 | 15 | switch (currentTarget.os.tag) { 16 | .macos => { 17 | exe.addFrameworkPath(.{ .path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" }); 18 | exe.linkFramework("OpenGL"); 19 | }, 20 | .freebsd => { 21 | exe.addIncludePath(.{ .path = "/usr/local/include/GL" }); 22 | exe.linkSystemLibrary("gl"); 23 | exe.linkSystemLibrary("glu"); 24 | }, 25 | .linux => { 26 | exe.addLibraryPath(.{ .path = "/usr/lib/x86_64-linux-gnu" }); 27 | exe.linkSystemLibrary("c"); 28 | exe.linkSystemLibrary("GL"); 29 | }, 30 | else => { 31 | @panic("don't know how to build on your system"); 32 | }, 33 | } 34 | exe.addIncludePath(.{ .path = "/usr/local/include" }); 35 | exe.linkSystemLibrary("glfw"); 36 | 37 | b.installArtifact(exe); 38 | 39 | const run_cmd = b.addRunArtifact(exe); 40 | run_cmd.step.dependOn(b.getInstallStep()); 41 | 42 | const run_step = b.step("run", "Run the app"); 43 | run_step.dependOn(&run_cmd.step); 44 | } 45 | -------------------------------------------------------------------------------- /Lesson03/src/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cInclude("GLFW/glfw3.h"); 3 | }); 4 | -------------------------------------------------------------------------------- /Lesson03/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const warn = std.log.warn; 3 | const panic = std.debug.panic; 4 | const c = @import("c.zig"); 5 | 6 | const width: i32 = 1024; 7 | const height: i32 = 768; 8 | 9 | var window: *c.GLFWwindow = undefined; 10 | 11 | fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { 12 | _ = err; 13 | panic("Error: {s}\n", .{description}); 14 | } 15 | 16 | fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { 17 | _ = scancode; 18 | _ = mods; 19 | 20 | if (action != c.GLFW_PRESS) return; 21 | 22 | switch (key) { 23 | c.GLFW_KEY_ESCAPE => c.glfwSetWindowShouldClose(win, c.GL_TRUE), 24 | else => {}, 25 | } 26 | } 27 | 28 | fn perspectiveGL(fovY: f64, aspect: f64, zNear: f64, zFar: f64) void { 29 | const fH = std.math.tan(fovY / 360 * std.math.pi) * zNear; 30 | const fW = fH * aspect; 31 | c.glFrustum(-fW, fW, -fH, fH, zNear, zFar); 32 | } 33 | 34 | fn init_gl() void { 35 | c.glMatrixMode(c.GL_PROJECTION); // Select The Projection Matrix 36 | c.glLoadIdentity(); 37 | const fHeight: f32 = @floatFromInt(height); 38 | const fWidth: f32 = @floatFromInt(width); 39 | const aspect_ratio = fHeight / fWidth; 40 | perspectiveGL(45.0, (1.0 / aspect_ratio), 0.1, 100.0); 41 | c.glMatrixMode(c.GL_MODELVIEW); 42 | c.glShadeModel(c.GL_SMOOTH); // Enables Smooth Shading 43 | c.glClearColor(0.0, 0.0, 0.0, 0.0); // Black Background 44 | c.glClearDepth(1.0); // Depth Buffer Setup 45 | c.glEnable(c.GL_DEPTH_TEST); // Enables Depth Testing 46 | c.glDepthFunc(c.GL_LEQUAL); // The Type Of Depth Test To Do 47 | c.glHint(c.GL_PERSPECTIVE_CORRECTION_HINT, c.GL_NICEST); // Really Nice Perspective Calculations 48 | } 49 | 50 | fn init() bool { 51 | _ = c.glfwSetErrorCallback(errorCallback); 52 | 53 | if (c.glfwInit() == c.GL_FALSE) { 54 | warn("Failed to initialize GLFW\n", .{}); 55 | return false; 56 | } 57 | 58 | c.glfwWindowHint(c.GLFW_SAMPLES, 4); // 4x antialiasing 59 | 60 | window = c.glfwCreateWindow(width, height, "Lesson03", null, null) orelse { 61 | panic("unable to create window\n", .{}); 62 | }; 63 | 64 | _ = c.glfwSetKeyCallback(window, keyCallback); 65 | c.glfwMakeContextCurrent(window); 66 | c.glfwSwapInterval(1); 67 | 68 | init_gl(); 69 | return true; 70 | } 71 | 72 | fn draw() void { // Here's Where We Do All The Drawing 73 | c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer 74 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 75 | c.glTranslatef(-1.5, 0.0, -6.0); // Move Left 1.5 Units And Into The Screen 6.0 76 | 77 | c.glBegin(c.GL_TRIANGLES); // Drawing Using Triangles 78 | c.glColor3f(1.0, 0.0, 0.0); // Set The Color To Red 79 | c.glVertex3f(0.0, 1.0, 0.0); // Move Up One Unit From Center (Top Point) 80 | c.glColor3f(0.0, 1.0, 0.0); // Set The Color To Green 81 | c.glVertex3f(-1.0, -1.0, 0.0); // Left And Down One Unit (Bottom Left) 82 | c.glColor3f(0.0, 0.0, 1.0); // Set The Color To Blue 83 | c.glVertex3f(1.0, -1.0, 0.0); // Right And Down One Unit (Bottom Right) 84 | c.glEnd(); // Finished Drawing The Triangle 85 | 86 | c.glTranslatef(3.0, 0.0, 0.0); // Move Right 3 Units 87 | 88 | c.glColor3f(0.5, 0.5, 1.0); // Set The Color To Blue One Time Only 89 | 90 | c.glBegin(c.GL_QUADS); // Draw A Quad 91 | c.glVertex3f(-1.0, 1.0, 0.0); // Top Left 92 | c.glVertex3f( 1.0, 1.0, 0.0); // Top Right 93 | c.glVertex3f( 1.0, -1.0, 0.0); // Bottom Right 94 | c.glVertex3f(-1.0, -1.0, 0.0); // Bottom Left 95 | c.glEnd(); // Done Drawing The Quad 96 | 97 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 98 | } 99 | 100 | pub fn main() u8 { 101 | if (!init()) { 102 | return 1; 103 | } 104 | 105 | while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { 106 | // Actually draw stuff. 107 | draw(); 108 | 109 | // Swap buffers 110 | c.glfwSwapBuffers(window); 111 | 112 | c.glfwPollEvents(); 113 | } 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /Lesson04/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const currentTarget = @import("builtin").target; 3 | 4 | pub fn build(b: *std.Build) void { 5 | const target = b.standardTargetOptions(.{}); 6 | const optimize = b.standardOptimizeOption(.{}); 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "Lesson04", 10 | .root_source_file = .{ .path = "src/main.zig" }, 11 | .target = target, 12 | .optimize = optimize, 13 | }); 14 | 15 | switch (currentTarget.os.tag) { 16 | .macos => { 17 | exe.addFrameworkPath(.{ .path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" }); 18 | exe.linkFramework("OpenGL"); 19 | }, 20 | .freebsd => { 21 | exe.addIncludePath(.{ .path = "/usr/local/include/GL" }); 22 | exe.linkSystemLibrary("gl"); 23 | exe.linkSystemLibrary("glu"); 24 | }, 25 | .linux => { 26 | exe.addLibraryPath(.{ .path = "/usr/lib/x86_64-linux-gnu" }); 27 | exe.linkSystemLibrary("c"); 28 | exe.linkSystemLibrary("GL"); 29 | }, 30 | else => { 31 | @panic("don't know how to build on your system"); 32 | }, 33 | } 34 | exe.addIncludePath(.{ .path = "/usr/local/include" }); 35 | exe.linkSystemLibrary("glfw"); 36 | 37 | b.installArtifact(exe); 38 | 39 | const run_cmd = b.addRunArtifact(exe); 40 | run_cmd.step.dependOn(b.getInstallStep()); 41 | 42 | const run_step = b.step("run", "Run the app"); 43 | run_step.dependOn(&run_cmd.step); 44 | } 45 | -------------------------------------------------------------------------------- /Lesson04/src/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cInclude("GLFW/glfw3.h"); 3 | }); 4 | -------------------------------------------------------------------------------- /Lesson04/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const warn = std.log.warn; 3 | const panic = std.debug.panic; 4 | const c = @import("c.zig"); 5 | 6 | const width: i32 = 1024; 7 | const height: i32 = 768; 8 | 9 | var window: *c.GLFWwindow = undefined; 10 | var rtri: c.GLfloat = 0.0; // Angle For The Triangle 11 | var rquad: c.GLfloat = 0.0; // Angle For The Quad 12 | 13 | fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { 14 | _ = err; 15 | panic("Error: {s}\n", .{description}); 16 | } 17 | 18 | fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { 19 | _ = scancode; 20 | _ = mods; 21 | 22 | if (action != c.GLFW_PRESS) return; 23 | 24 | switch (key) { 25 | c.GLFW_KEY_ESCAPE => c.glfwSetWindowShouldClose(win, c.GL_TRUE), 26 | else => {}, 27 | } 28 | } 29 | 30 | fn perspectiveGL(fovY: f64, aspect: f64, zNear: f64, zFar: f64) void { 31 | const fH = std.math.tan(fovY / 360 * std.math.pi) * zNear; 32 | const fW = fH * aspect; 33 | c.glFrustum(-fW, fW, -fH, fH, zNear, zFar); 34 | } 35 | 36 | fn init_gl() void { 37 | c.glMatrixMode(c.GL_PROJECTION); // Select The Projection Matrix 38 | c.glLoadIdentity(); 39 | const fHeight: f32 = @floatFromInt(height); 40 | const fWidth: f32 = @floatFromInt(width); 41 | const aspect_ratio = fHeight / fWidth; 42 | perspectiveGL(45.0, (1.0 / aspect_ratio), 0.1, 100.0); 43 | c.glMatrixMode(c.GL_MODELVIEW); 44 | c.glShadeModel(c.GL_SMOOTH); // Enables Smooth Shading 45 | c.glClearColor(0.0, 0.0, 0.0, 0.0); // Black Background 46 | c.glClearDepth(1.0); // Depth Buffer Setup 47 | c.glEnable(c.GL_DEPTH_TEST); // Enables Depth Testing 48 | c.glDepthFunc(c.GL_LEQUAL); // The Type Of Depth Test To Do 49 | c.glHint(c.GL_PERSPECTIVE_CORRECTION_HINT, c.GL_NICEST); // Really Nice Perspective Calculations 50 | } 51 | 52 | fn init() bool { 53 | _ = c.glfwSetErrorCallback(errorCallback); 54 | 55 | if (c.glfwInit() == c.GL_FALSE) { 56 | warn("Failed to initialize GLFW\n", .{}); 57 | return false; 58 | } 59 | 60 | c.glfwWindowHint(c.GLFW_SAMPLES, 4); // 4x antialiasing 61 | 62 | window = c.glfwCreateWindow(width, height, "Lesson04", null, null) orelse { 63 | panic("unable to create window\n", .{}); 64 | }; 65 | 66 | _ = c.glfwSetKeyCallback(window, keyCallback); 67 | c.glfwMakeContextCurrent(window); 68 | c.glfwSwapInterval(1); 69 | 70 | init_gl(); 71 | return true; 72 | } 73 | 74 | fn draw() void { // Here's Where We Do All The Drawing 75 | c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer 76 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 77 | c.glTranslatef(-1.5, 0.0, -6.0); // Move Left 1.5 Units And Into The Screen 6.0 78 | c.glRotatef(rtri, 0.0, 1.0, 0.0); // Rotate The Triangle On The Y axis 79 | 80 | c.glBegin(c.GL_TRIANGLES); // Drawing Using Triangles 81 | c.glColor3f(1.0, 0.0, 0.0); // Set The Color To Red 82 | c.glVertex3f(0.0, 1.0, 0.0); // Move Up One Unit From Center (Top Point) 83 | c.glColor3f(0.0, 1.0, 0.0); // Set The Color To Green 84 | c.glVertex3f(-1.0, -1.0, 0.0); // Left And Down One Unit (Bottom Left) 85 | c.glColor3f(0.0, 0.0, 1.0); // Set The Color To Blue 86 | c.glVertex3f(1.0, -1.0, 0.0); // Right And Down One Unit (Bottom Right) 87 | c.glEnd(); // Finished Drawing The Triangle 88 | 89 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 90 | c.glTranslatef(1.5, 0.0, -6.0); // Move Right 3 Units 91 | c.glRotatef(rquad, 1.0, 0.0, 0.0); // Rotate The Quad On The X axis ( NEW ) 92 | 93 | c.glColor3f(0.5, 0.5, 1.0); // Set The Color To Blue One Time Only 94 | 95 | c.glBegin(c.GL_QUADS); // Draw A Quad 96 | c.glVertex3f(-1.0, 1.0, 0.0); // Top Left 97 | c.glVertex3f( 1.0, 1.0, 0.0); // Top Right 98 | c.glVertex3f( 1.0, -1.0, 0.0); // Bottom Right 99 | c.glVertex3f(-1.0, -1.0, 0.0); // Bottom Left 100 | c.glEnd(); // Done Drawing The Quad 101 | 102 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 103 | 104 | rtri += 0.6; // Increase The Rotation Variable For The Triangle 105 | rquad -= 0.45; // Decrease The Rotation Variable For The Quad 106 | } 107 | 108 | pub fn main() u8 { 109 | if (!init()) { 110 | return 1; 111 | } 112 | 113 | while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { 114 | // Actually draw stuff. 115 | draw(); 116 | 117 | // Swap buffers 118 | c.glfwSwapBuffers(window); 119 | 120 | c.glfwPollEvents(); 121 | } 122 | 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /Lesson05/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const currentTarget = @import("builtin").target; 3 | 4 | pub fn build(b: *std.Build) void { 5 | const target = b.standardTargetOptions(.{}); 6 | const optimize = b.standardOptimizeOption(.{}); 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "Lesson05", 10 | .root_source_file = .{ .path = "src/main.zig" }, 11 | .target = target, 12 | .optimize = optimize, 13 | }); 14 | 15 | switch (currentTarget.os.tag) { 16 | .macos => { 17 | exe.addFrameworkPath(.{ .path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" }); 18 | exe.linkFramework("OpenGL"); 19 | }, 20 | .freebsd => { 21 | exe.addIncludePath(.{ .path = "/usr/local/include/GL" }); 22 | exe.linkSystemLibrary("gl"); 23 | exe.linkSystemLibrary("glu"); 24 | }, 25 | .linux => { 26 | exe.addLibraryPath(.{ .path = "/usr/lib/x86_64-linux-gnu" }); 27 | exe.linkSystemLibrary("c"); 28 | exe.linkSystemLibrary("GL"); 29 | }, 30 | else => { 31 | @panic("don't know how to build on your system"); 32 | }, 33 | } 34 | exe.addIncludePath(.{ .path = "/usr/local/include" }); 35 | exe.linkSystemLibrary("glfw"); 36 | 37 | b.installArtifact(exe); 38 | 39 | const run_cmd = b.addRunArtifact(exe); 40 | run_cmd.step.dependOn(b.getInstallStep()); 41 | 42 | const run_step = b.step("run", "Run the app"); 43 | run_step.dependOn(&run_cmd.step); 44 | } 45 | -------------------------------------------------------------------------------- /Lesson05/src/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cInclude("GLFW/glfw3.h"); 3 | }); 4 | -------------------------------------------------------------------------------- /Lesson05/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const warn = std.log.warn; 3 | const panic = std.debug.panic; 4 | const c = @import("c.zig"); 5 | 6 | const width: i32 = 1024; 7 | const height: i32 = 768; 8 | 9 | var window: *c.GLFWwindow = undefined; 10 | var rtri: c.GLfloat = 0.0; // Angle For The Triangle 11 | var rquad: c.GLfloat = 0.0; // Angle For The Quad 12 | 13 | fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { 14 | _ = err; 15 | panic("Error: {s}\n", .{description}); 16 | } 17 | 18 | fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { 19 | _ = scancode; 20 | _ = mods; 21 | 22 | if (action != c.GLFW_PRESS) return; 23 | 24 | switch (key) { 25 | c.GLFW_KEY_ESCAPE => c.glfwSetWindowShouldClose(win, c.GL_TRUE), 26 | else => {}, 27 | } 28 | } 29 | 30 | fn perspectiveGL(fovY: f64, aspect: f64, zNear: f64, zFar: f64) void { 31 | const fH = std.math.tan(fovY / 360 * std.math.pi) * zNear; 32 | const fW = fH * aspect; 33 | c.glFrustum(-fW, fW, -fH, fH, zNear, zFar); 34 | } 35 | 36 | fn init_gl() void { 37 | c.glMatrixMode(c.GL_PROJECTION); // Select The Projection Matrix 38 | c.glLoadIdentity(); 39 | const fHeight: f32 = @floatFromInt(height); 40 | const fWidth: f32 = @floatFromInt(width); 41 | const aspect_ratio = fHeight / fWidth; 42 | perspectiveGL(45.0, (1.0 / aspect_ratio), 0.1, 100.0); 43 | c.glMatrixMode(c.GL_MODELVIEW); 44 | c.glShadeModel(c.GL_SMOOTH); // Enables Smooth Shading 45 | c.glClearColor(0.0, 0.0, 0.0, 0.0); // Black Background 46 | c.glClearDepth(1.0); // Depth Buffer Setup 47 | c.glEnable(c.GL_DEPTH_TEST); // Enables Depth Testing 48 | c.glDepthFunc(c.GL_LEQUAL); // The Type Of Depth Test To Do 49 | c.glHint(c.GL_PERSPECTIVE_CORRECTION_HINT, c.GL_NICEST); // Really Nice Perspective Calculations 50 | } 51 | 52 | fn init() bool { 53 | _ = c.glfwSetErrorCallback(errorCallback); 54 | 55 | if (c.glfwInit() == c.GL_FALSE) { 56 | warn("Failed to initialize GLFW\n", .{}); 57 | return false; 58 | } 59 | 60 | c.glfwWindowHint(c.GLFW_SAMPLES, 4); // 4x antialiasing 61 | 62 | window = c.glfwCreateWindow(width, height, "Lesson05", null, null) orelse { 63 | panic("unable to create window\n", .{}); 64 | }; 65 | 66 | _ = c.glfwSetKeyCallback(window, keyCallback); 67 | c.glfwMakeContextCurrent(window); 68 | c.glfwSwapInterval(1); 69 | 70 | init_gl(); 71 | return true; 72 | } 73 | 74 | fn draw() void { // Here's Where We Do All The Drawing 75 | c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer 76 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 77 | c.glTranslatef(-1.5, 0.0, -6.0); // Move Left 1.5 Units And Into The Screen 6.0 78 | c.glRotatef(rtri, 0.0, 1.0, 0.0); // Rotate The Triangle On The Y axis 79 | 80 | c.glBegin(c.GL_TRIANGLES); // Drawing Using Triangles 81 | c.glColor3f(1.0, 0.0, 0.0); // Red 82 | c.glVertex3f(0.0, 1.0, 0.0); // Top Of Triangle (Front) 83 | c.glColor3f(0.0, 1.0, 0.0); // Green 84 | c.glVertex3f(-1.0, -1.0, 1.0); // Left Of Triangle (Front) 85 | c.glColor3f(0.0, 0.0, 1.0); // Blue 86 | c.glVertex3f(1.0, -1.0, 1.0); // Right Of Triangle (Front) 87 | c.glColor3f(1.0, 0.0, 0.0); // Red 88 | c.glVertex3f(0.0, 1.0, 0.0); // Top Of Triangle (Right) 89 | c.glColor3f(0.0, 0.0, 1.0); // Blue 90 | c.glVertex3f(1.0, -1.0, 1.0); // Left Of Triangle (Right) 91 | c.glColor3f(0.0, 1.0, 0.0); // Green 92 | c.glVertex3f(1.0, -1.0, -1.0); // Right Of Triangle (Right) 93 | c.glColor3f(1.0, 0.0, 0.0); // Red 94 | c.glVertex3f(0.0, 1.0, 0.0); // Top Of Triangle (Back) 95 | c.glColor3f(0.0, 1.0, 0.0); // Green 96 | c.glVertex3f(1.0, -1.0, -1.0); // Left Of Triangle (Back) 97 | c.glColor3f(0.0, 0.0, 1.0); // Blue 98 | c.glVertex3f(-1.0, -1.0, -1.0); // Right Of Triangle (Back) 99 | c.glColor3f(1.0, 0.0, 0.0); // Red 100 | c.glVertex3f(0.0, 1.0, 0.0); // Top Of Triangle (Left) 101 | c.glColor3f(0.0, 0.0, 1.0); // Blue 102 | c.glVertex3f(-1.0, -1.0, -1.0); // Left Of Triangle (Left) 103 | c.glColor3f(0.0, 1.0, 0.0); // Green 104 | c.glVertex3f(-1.0, -1.0, 1.0); // Right Of Triangle (Left) 105 | c.glEnd(); // Finished Drawing The Triangle 106 | 107 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 108 | c.glTranslatef(1.5, 0.0, -6.0); // Move Right 3 Units 109 | c.glRotatef(rquad, 1.0, 0.0, 0.0); // Rotate The Quad On The X axis (NEW ) 110 | 111 | c.glBegin(c.GL_QUADS); // Draw A Quad 112 | c.glColor3f(0.0, 1.0, 0.0); // Set The Color To Green 113 | c.glVertex3f( 1.0, 1.0, -1.0); // Top Right Of The Quad (Top) 114 | c.glVertex3f(-1.0, 1.0, -1.0); // Top Left Of The Quad (Top) 115 | c.glVertex3f(-1.0, 1.0, 1.0); // Bottom Left Of The Quad (Top) 116 | c.glVertex3f( 1.0, 1.0, 1.0); // Bottom Right Of The Quad (Top) 117 | c.glColor3f(1.0, 0.5, 0.0); // Set The Color To Orange 118 | c.glVertex3f( 1.0, -1.0, 1.0); // Top Right Of The Quad (Bottom) 119 | c.glVertex3f(-1.0, -1.0, 1.0); // Top Left Of The Quad (Bottom) 120 | c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Left Of The Quad (Bottom) 121 | c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Right Of The Quad (Bottom) 122 | c.glColor3f(1.0, 0.0, 0.0); // Set The Color To Red 123 | c.glVertex3f( 1.0, 1.0, 1.0); // Top Right Of The Quad (Front) 124 | c.glVertex3f(-1.0, 1.0, 1.0); // Top Left Of The Quad (Front) 125 | c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Left Of The Quad (Front) 126 | c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Right Of The Quad (Front) 127 | c.glColor3f(1.0, 1.0, 0.0); // Set The Color To Yellow 128 | c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Left Of The Quad (Back) 129 | c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Right Of The Quad (Back) 130 | c.glVertex3f(-1.0, 1.0, -1.0); // Top Right Of The Quad (Back) 131 | c.glVertex3f( 1.0, 1.0, -1.0); // Top Left Of The Quad (Back) 132 | c.glColor3f(0.0, 0.0, 1.0); // Set The Color To Blue 133 | c.glVertex3f(-1.0, 1.0, 1.0); // Top Right Of The Quad (Left) 134 | c.glVertex3f(-1.0, 1.0, -1.0); // Top Left Of The Quad (Left) 135 | c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Left Of The Quad (Left) 136 | c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Right Of The Quad (Left) 137 | c.glColor3f(1.0, 0.0, 1.0); // Set The Color To Violet 138 | c.glVertex3f( 1.0, 1.0, -1.0); // Top Right Of The Quad (Right) 139 | c.glVertex3f( 1.0, 1.0, 1.0); // Top Left Of The Quad (Right) 140 | c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Left Of The Quad (Right) 141 | c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Right Of The Quad (Right) 142 | c.glEnd(); // Done Drawing The Quad 143 | 144 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 145 | 146 | rtri += 0.6; // Increase The Rotation Variable For The Triangle 147 | rquad -= 0.45; // Decrease The Rotation Variable For The Quad 148 | } 149 | 150 | pub fn main() u8 { 151 | if (!init()) { 152 | return 1; 153 | } 154 | 155 | while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { 156 | // Actually draw stuff. 157 | draw(); 158 | 159 | // Swap buffers 160 | c.glfwSwapBuffers(window); 161 | 162 | c.glfwPollEvents(); 163 | } 164 | 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /Lesson06/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const currentTarget = @import("builtin").target; 3 | 4 | pub fn build(b: *std.Build) void { 5 | const target = b.standardTargetOptions(.{}); 6 | const optimize = b.standardOptimizeOption(.{}); 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "Lesson06", 10 | .root_source_file = .{ .path = "src/main.zig" }, 11 | .target = target, 12 | .optimize = optimize, 13 | }); 14 | 15 | exe.addCSourceFile(.{ 16 | .file = .{ .path = "stb_image-2.23/stb_image_impl.c" }, 17 | .flags = &[_][]const u8{"-std=c99"}, 18 | }); 19 | 20 | switch (currentTarget.os.tag) { 21 | .macos => { 22 | exe.addFrameworkPath(.{ .path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" }); 23 | exe.linkFramework("OpenGL"); 24 | }, 25 | .freebsd => { 26 | exe.addIncludePath(.{ .path = "/usr/local/include/GL" }); 27 | exe.linkSystemLibrary("gl"); 28 | exe.linkSystemLibrary("glu"); 29 | }, 30 | .linux => { 31 | exe.addLibraryPath(.{ .path = "/usr/lib/x86_64-linux-gnu" }); 32 | exe.linkSystemLibrary("c"); 33 | exe.linkSystemLibrary("GL"); 34 | }, 35 | else => { 36 | @panic("don't know how to build on your system"); 37 | }, 38 | } 39 | exe.addIncludePath(.{ .path = "stb_image-2.23" }); 40 | exe.addIncludePath(.{ .path = "/usr/local/include" }); 41 | exe.linkSystemLibrary("glfw"); 42 | 43 | b.installArtifact(exe); 44 | 45 | const run_cmd = b.addRunArtifact(exe); 46 | run_cmd.step.dependOn(b.getInstallStep()); 47 | 48 | const run_step = b.step("run", "Run the app"); 49 | run_step.dependOn(&run_cmd.step); 50 | } 51 | -------------------------------------------------------------------------------- /Lesson06/src/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cInclude("GLFW/glfw3.h"); 3 | @cDefine("STBI_ONLY_PNG", ""); 4 | @cDefine("STBI_NO_STDIO", ""); 5 | @cInclude("stb_image.h"); 6 | }); 7 | -------------------------------------------------------------------------------- /Lesson06/src/data/NeHe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mypalmike/zigNeHe/97888ec41794d1ffde02f102416a7dfa2bb71f70/Lesson06/src/data/NeHe.png -------------------------------------------------------------------------------- /Lesson06/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const warn = std.log.warn; 3 | const panic = std.debug.panic; 4 | const c = @import("c.zig"); 5 | const PngImage = @import("png.zig").PngImage; 6 | const nehe_png = @embedFile("data/NeHe.png"); 7 | 8 | const width: i32 = 1024; 9 | const height: i32 = 768; 10 | 11 | var window: *c.GLFWwindow = undefined; 12 | 13 | var xrot: c.GLfloat = 0.0; 14 | var yrot: c.GLfloat = 0.0; 15 | var zrot: c.GLfloat = 0.0; 16 | 17 | var texture: c.GLuint = 0; // texture[1]; // Storage For One Texture 18 | 19 | fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { 20 | _ = err; 21 | panic("Error: {s}\n", .{description}); 22 | } 23 | 24 | fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { 25 | _ = scancode; 26 | _ = mods; 27 | 28 | if (action != c.GLFW_PRESS) return; 29 | 30 | switch (key) { 31 | c.GLFW_KEY_ESCAPE => c.glfwSetWindowShouldClose(win, c.GL_TRUE), 32 | else => {}, 33 | } 34 | } 35 | 36 | fn perspectiveGL(fovY: f64, aspect: f64, zNear: f64, zFar: f64) void { 37 | const fH = std.math.tan(fovY / 360 * std.math.pi) * zNear; 38 | const fW = fH * aspect; 39 | c.glFrustum(-fW, fW, -fH, fH, zNear, zFar); 40 | } 41 | 42 | fn load_texture() !void { 43 | var img = try PngImage.create(nehe_png); 44 | c.glGenTextures(1, &texture); 45 | errdefer c.glDeleteTextures(1, &texture); 46 | 47 | c.glBindTexture(c.GL_TEXTURE_2D, texture); 48 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR); 49 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR); 50 | // c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_S, c.GL_CLAMP_TO_EDGE); 51 | // c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_T, c.GL_CLAMP_TO_EDGE); 52 | // c.glPixelStorei(c.GL_PACK_ALIGNMENT, 4); 53 | c.glTexImage2D( 54 | c.GL_TEXTURE_2D, 55 | 0, 56 | c.GL_RGBA, 57 | @intCast(img.width), 58 | @intCast(img.height), 59 | 0, 60 | c.GL_RGBA, 61 | c.GL_UNSIGNED_BYTE, 62 | @ptrCast(&img.raw[0]), 63 | ); 64 | 65 | } 66 | 67 | fn init_gl() void { 68 | load_texture() catch { 69 | warn("Failed to load texture.\n", .{}); 70 | }; 71 | 72 | c.glMatrixMode(c.GL_PROJECTION); // Select The Projection Matrix 73 | c.glLoadIdentity(); 74 | const fHeight: f32 = @floatFromInt(height); 75 | const fWidth: f32 = @floatFromInt(width); 76 | const aspect_ratio = fHeight / fWidth; 77 | perspectiveGL(45.0, (1.0 / aspect_ratio), 0.1, 100.0); 78 | c.glMatrixMode(c.GL_MODELVIEW); 79 | c.glEnable(c.GL_TEXTURE_2D); 80 | c.glShadeModel(c.GL_SMOOTH); // Enables Smooth Shading 81 | c.glClearColor(0.0, 0.0, 0.0, 0.0); // Black Background 82 | c.glClearDepth(1.0); // Depth Buffer Setup 83 | c.glEnable(c.GL_DEPTH_TEST); // Enables Depth Testing 84 | c.glDepthFunc(c.GL_LEQUAL); // The Type Of Depth Test To Do 85 | c.glHint(c.GL_PERSPECTIVE_CORRECTION_HINT, c.GL_NICEST); // Really Nice Perspective Calculations 86 | } 87 | 88 | fn init() bool { 89 | _ = c.glfwSetErrorCallback(errorCallback); 90 | 91 | if (c.glfwInit() == c.GL_FALSE) { 92 | warn("Failed to initialize GLFW\n", .{}); 93 | return false; 94 | } 95 | 96 | c.glfwWindowHint(c.GLFW_SAMPLES, 4); // 4x antialiasing 97 | 98 | window = c.glfwCreateWindow(width, height, "Lesson06", null, null) orelse { 99 | panic("unable to create window\n", .{}); 100 | }; 101 | 102 | _ = c.glfwSetKeyCallback(window, keyCallback); 103 | c.glfwMakeContextCurrent(window); 104 | c.glfwSwapInterval(1); 105 | 106 | init_gl(); 107 | return true; 108 | } 109 | 110 | fn draw() void { // Here's Where We Do All The Drawing 111 | c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer 112 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 113 | c.glTranslatef(0.0, 0.0, -5.0); // Move Into The Screen 5 Units 114 | c.glRotatef(xrot, 1.0, 0.0, 0.0); // Rotate On The X Axis 115 | c.glRotatef(yrot, 0.0, 1.0, 0.0); // Rotate On The Y Axis 116 | c.glRotatef(zrot, 0.0, 0.0, 1.0); // Rotate On The Z Axis 117 | c.glBindTexture(c.GL_TEXTURE_2D, texture); // Select Our Texture 118 | 119 | c.glBegin(c.GL_QUADS); 120 | // Front Face 121 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 122 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 123 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, 1.0); // Top Right Of The Texture and Quad 124 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, 1.0); // Top Left Of The Texture and Quad 125 | // Back Face 126 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Right Of The Texture and Quad 127 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 128 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 129 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Left Of The Texture and Quad 130 | // Top Face 131 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 132 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, 1.0, 1.0); // Bottom Left Of The Texture and Quad 133 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, 1.0, 1.0); // Bottom Right Of The Texture and Quad 134 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 135 | // Bottom Face 136 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, -1.0, -1.0); // Top Right Of The Texture and Quad 137 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, -1.0, -1.0); // Top Left Of The Texture and Quad 138 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 139 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 140 | // Right face 141 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Right Of The Texture and Quad 142 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 143 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, 1.0, 1.0); // Top Left Of The Texture and Quad 144 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 145 | // Left Face 146 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Left Of The Texture and Quad 147 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 148 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, 1.0, 1.0); // Top Right Of The Texture and Quad 149 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 150 | c.glEnd(); 151 | 152 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 153 | 154 | xrot += 0.3; // X Axis Rotation 155 | yrot += 0.2; // Y Axis Rotation 156 | zrot += 0.4; // Z Axis Rotation 157 | } 158 | 159 | pub fn main() u8 { 160 | if (!init()) { 161 | return 1; 162 | } 163 | 164 | while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { 165 | // Actually draw stuff. 166 | draw(); 167 | 168 | // Swap buffers 169 | c.glfwSwapBuffers(window); 170 | 171 | c.glfwPollEvents(); 172 | } 173 | 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /Lesson06/src/png.zig: -------------------------------------------------------------------------------- 1 | const c = @import("c.zig"); 2 | 3 | // From https://github.com/andrewrk/tetris 4 | pub const PngImage = struct { 5 | width: u32, 6 | height: u32, 7 | pitch: u32, 8 | raw: []u8, 9 | 10 | pub fn destroy(pi: *PngImage) void { 11 | c.stbi_image_free(pi.raw.ptr); 12 | } 13 | 14 | pub fn create(compressed_bytes: []const u8) !PngImage { 15 | var pi: PngImage = undefined; 16 | 17 | var width: c_int = undefined; 18 | var height: c_int = undefined; 19 | 20 | if (c.stbi_info_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len), &width, &height, null) == 0) { 21 | return error.NotPngFile; 22 | } 23 | 24 | if (width <= 0 or height <= 0) return error.NoPixels; 25 | pi.width = @intCast(width); 26 | pi.height = @intCast(height); 27 | 28 | // Not validating channel_count because it gets auto-converted to 4 29 | 30 | if (c.stbi_is_16_bit_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len)) != 0) { 31 | return error.InvalidFormat; 32 | } 33 | const bits_per_channel = 8; 34 | const channel_count = 4; 35 | 36 | c.stbi_set_flip_vertically_on_load(1); 37 | const image_data = c.stbi_load_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len), &width, &height, null, channel_count); 38 | 39 | if (image_data == null) return error.NoMem; 40 | 41 | pi.pitch = pi.width * bits_per_channel * channel_count / 8; 42 | pi.raw = image_data[0 .. pi.height * pi.pitch]; 43 | 44 | return pi; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /Lesson06/stb_image-2.23/stb_image_impl.c: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #define STBI_ONLY_PNG 3 | #define STBI_NO_STDIO 4 | #include "stb_image.h" 5 | -------------------------------------------------------------------------------- /Lesson07/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const currentTarget = @import("builtin").target; 3 | 4 | pub fn build(b: *std.Build) void { 5 | const target = b.standardTargetOptions(.{}); 6 | const optimize = b.standardOptimizeOption(.{}); 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "Lesson07", 10 | .root_source_file = .{ .path = "src/main.zig" }, 11 | .target = target, 12 | .optimize = optimize, 13 | }); 14 | 15 | exe.addCSourceFile(.{ 16 | .file = .{ .path = "stb_image-2.23/stb_image_impl.c" }, 17 | .flags = &[_][]const u8{"-std=c99"}, 18 | }); 19 | 20 | switch (currentTarget.os.tag) { 21 | .macos => { 22 | exe.addFrameworkPath(.{ .path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" }); 23 | exe.addIncludePath("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/OpenGL.framework/Headers"); 24 | exe.linkFramework("OpenGL"); 25 | }, 26 | .freebsd => { 27 | exe.addIncludePath(.{ .path = "/usr/local/include/GL" }); 28 | exe.linkSystemLibrary("gl"); 29 | exe.linkSystemLibrary("glu"); 30 | }, 31 | .linux => { 32 | exe.addLibraryPath(.{ .path = "/usr/lib/x86_64-linux-gnu" }); 33 | exe.linkSystemLibrary("c"); 34 | exe.linkSystemLibrary("GL"); 35 | exe.linkSystemLibrary("GLU"); 36 | }, 37 | else => { 38 | @panic("don't know how to build on your system"); 39 | }, 40 | } 41 | exe.addIncludePath(.{ .path = "stb_image-2.23" }); 42 | exe.addIncludePath(.{ .path = "/usr/local/include" }); 43 | exe.linkSystemLibrary("glfw"); 44 | 45 | b.installArtifact(exe); 46 | 47 | const run_cmd = b.addRunArtifact(exe); 48 | run_cmd.step.dependOn(b.getInstallStep()); 49 | 50 | const run_step = b.step("run", "Run the app"); 51 | run_step.dependOn(&run_cmd.step); 52 | } 53 | -------------------------------------------------------------------------------- /Lesson07/src/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cInclude("GL/glu.h"); 3 | @cInclude("GLFW/glfw3.h"); 4 | @cDefine("STBI_ONLY_PNG", ""); 5 | @cDefine("STBI_NO_STDIO", ""); 6 | @cInclude("stb_image.h"); 7 | }); 8 | -------------------------------------------------------------------------------- /Lesson07/src/data/Crate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mypalmike/zigNeHe/97888ec41794d1ffde02f102416a7dfa2bb71f70/Lesson07/src/data/Crate.png -------------------------------------------------------------------------------- /Lesson07/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const warn = std.log.warn; 3 | const panic = std.debug.panic; 4 | const c = @import("c.zig"); 5 | const PngImage = @import("png.zig").PngImage; 6 | const crate_png = @embedFile("data/Crate.png"); 7 | 8 | const width: i32 = 1024; 9 | const height: i32 = 768; 10 | 11 | var window: *c.GLFWwindow = undefined; 12 | 13 | var light: bool = false; // Lighting ON/OFF 14 | 15 | var xrot: c.GLfloat = 0.0; // X Rotation 16 | var yrot: c.GLfloat = 0.0; // Y Rotation 17 | var xspeed: c.GLfloat = 0.0; // X Rotation Speed 18 | var yspeed: c.GLfloat = 0.0; // Y Rotation Speed 19 | var z: c.GLfloat = -5.0; // Depth Into The Screen 20 | 21 | var filter: c.GLuint = 0; // Which Filter To Use 22 | var texture: [3]c.GLuint = undefined; // Storage For 3 Textures 23 | 24 | const lightAmbient = [_]c.GLfloat {0.5, 0.5, 0.5, 1.0}; 25 | const lightDiffuse = [_]c.GLfloat {1.0, 1.0, 1.0, 1.0}; 26 | const lightPosition = [_]c.GLfloat {0.0, 0.0, 2.0, 1.0}; 27 | 28 | fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { 29 | _ = err; 30 | panic("Error: {s}\n", .{description}); 31 | } 32 | 33 | fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { 34 | _ = scancode; 35 | _ = mods; 36 | 37 | if (action == c.GLFW_PRESS) { 38 | switch (key) { 39 | c.GLFW_KEY_ESCAPE => c.glfwSetWindowShouldClose(win, c.GL_TRUE), 40 | 'L' => { 41 | light = !light; 42 | if (light) { 43 | c.glEnable(c.GL_LIGHTING); 44 | } else { 45 | c.glDisable(c.GL_LIGHTING); 46 | } 47 | }, 48 | 'F' => { 49 | filter += 1; 50 | filter = filter % 3; 51 | }, 52 | else => {}, 53 | } 54 | } else if (action == c.GLFW_REPEAT) { 55 | switch (key) { 56 | c.GLFW_KEY_PAGE_UP => z -= 0.02, 57 | c.GLFW_KEY_PAGE_DOWN => z += 0.02, 58 | c.GLFW_KEY_UP => xspeed -= 0.01, 59 | c.GLFW_KEY_DOWN => xspeed -= 0.01, 60 | c.GLFW_KEY_RIGHT => yspeed += 0.01, 61 | c.GLFW_KEY_LEFT => yspeed -= 0.01, 62 | else => {}, 63 | } 64 | } 65 | } 66 | 67 | fn perspectiveGL(fovY: f64, aspect: f64, zNear: f64, zFar: f64) void { 68 | const fH = std.math.tan(fovY / 360 * std.math.pi) * zNear; 69 | const fW = fH * aspect; 70 | c.glFrustum(-fW, fW, -fH, fH, zNear, zFar); 71 | } 72 | 73 | fn load_textures() !void { 74 | var img = try PngImage.create(crate_png); 75 | 76 | // Create 3 textures 77 | c.glGenTextures(3, &texture); 78 | // errdefer c.glDeleteTextures(3, &texture); 79 | 80 | c.glBindTexture(c.GL_TEXTURE_2D, texture[0]); 81 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST); 82 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST); 83 | c.glTexImage2D( 84 | c.GL_TEXTURE_2D, 85 | 0, 86 | c.GL_RGBA, 87 | @intCast(img.width), 88 | @intCast(img.height), 89 | 0, 90 | c.GL_RGBA, 91 | c.GL_UNSIGNED_BYTE, 92 | @ptrCast(&img.raw[0]), 93 | ); 94 | 95 | c.glBindTexture(c.GL_TEXTURE_2D, texture[1]); 96 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR); 97 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR); 98 | c.glTexImage2D( 99 | c.GL_TEXTURE_2D, 100 | 0, 101 | c.GL_RGBA, 102 | @intCast(img.width), 103 | @intCast(img.height), 104 | 0, 105 | c.GL_RGBA, 106 | c.GL_UNSIGNED_BYTE, 107 | @ptrCast(&img.raw[0]), 108 | ); 109 | 110 | c.glBindTexture(c.GL_TEXTURE_2D, texture[2]); 111 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR_MIPMAP_NEAREST); 112 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR); 113 | _ = c.gluBuild2DMipmaps( 114 | c.GL_TEXTURE_2D, 115 | c.GL_RGBA, 116 | @intCast(img.width), 117 | @intCast(img.height), 118 | c.GL_RGBA, 119 | c.GL_UNSIGNED_BYTE, 120 | @ptrCast(&img.raw[0]), 121 | ); 122 | } 123 | 124 | fn init_gl() void { 125 | load_textures() catch { 126 | warn("Failed to load textures.\n", .{}); 127 | }; 128 | 129 | c.glViewport(0, 0, width, height); 130 | c.glMatrixMode(c.GL_PROJECTION); // Select The Projection Matrix 131 | c.glLoadIdentity(); 132 | const fHeight: f32 = @floatFromInt(height); 133 | const fWidth: f32 = @floatFromInt(width); 134 | const aspect_ratio = fHeight / fWidth; 135 | perspectiveGL(45.0, (1.0 / aspect_ratio), 0.1, 100.0); 136 | c.glMatrixMode(c.GL_MODELVIEW); 137 | c.glLoadIdentity(); 138 | 139 | c.glEnable(c.GL_TEXTURE_2D); 140 | c.glShadeModel(c.GL_SMOOTH); // Enables Smooth Shading 141 | c.glClearColor(0.0, 0.0, 0.0, 0.5); // Black Background 142 | c.glClearDepth(1.0); // Depth Buffer Setup 143 | c.glEnable(c.GL_DEPTH_TEST); // Enables Depth Testing 144 | c.glDepthFunc(c.GL_LEQUAL); // The Type Of Depth Test To Do 145 | c.glHint(c.GL_PERSPECTIVE_CORRECTION_HINT, c.GL_NICEST); // Really Nice Perspective Calculations 146 | 147 | c.glLightfv(c.GL_LIGHT1, c.GL_AMBIENT, &lightAmbient[0]); // Setup The Ambient Light 148 | c.glLightfv(c.GL_LIGHT1, c.GL_DIFFUSE, &lightDiffuse[0]); // Setup The Diffuse Light 149 | c.glLightfv(c.GL_LIGHT1, c.GL_POSITION, &lightPosition[0]); // Position The Light 150 | c.glEnable(c.GL_LIGHT1); // Enable Light One 151 | } 152 | 153 | fn init() bool { 154 | _ = c.glfwSetErrorCallback(errorCallback); 155 | 156 | if (c.glfwInit() == c.GL_FALSE) { 157 | warn("Failed to initialize GLFW\n", .{}); 158 | return false; 159 | } 160 | 161 | c.glfwWindowHint(c.GLFW_SAMPLES, 4); // 4x antialiasing 162 | 163 | window = c.glfwCreateWindow(width, height, "Lesson07", null, null) orelse { 164 | panic("unable to create window\n", .{}); 165 | }; 166 | 167 | _ = c.glfwSetKeyCallback(window, keyCallback); 168 | c.glfwMakeContextCurrent(window); 169 | c.glfwSwapInterval(1); 170 | 171 | init_gl(); 172 | return true; 173 | } 174 | 175 | fn draw() void { // Here's Where We Do All The Drawing 176 | c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer 177 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 178 | 179 | c.glTranslatef(0.0, 0.0, z); 180 | c.glRotatef(xrot, 1.0, 0.0, 0.0); 181 | c.glRotatef(yrot, 0.0, 1.0, 0.0); 182 | 183 | c.glBindTexture(c.GL_TEXTURE_2D, texture[filter]); // Select Our Texture 184 | 185 | c.glBegin(c.GL_QUADS); 186 | // Front 187 | c.glNormal3f(0.0, 0.0, 1.0); 188 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 189 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 190 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, 1.0); // Top Right Of The Texture and Quad 191 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, 1.0); // Top Left Of The Texture and Quad 192 | // Back Face 193 | c.glNormal3f(0.0, 0.0, -1.0); 194 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Right Of The Texture and Quad 195 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 196 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 197 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Left Of The Texture and Quad 198 | // Top Face 199 | c.glNormal3f(0.0, 1.0, 0.0); 200 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 201 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, 1.0, 1.0); // Bottom Left Of The Texture and Quad 202 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, 1.0, 1.0); // Bottom Right Of The Texture and Quad 203 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 204 | // Bottom Face 205 | c.glNormal3f(0.0, -1.0, 0.0); 206 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, -1.0, -1.0); // Top Right Of The Texture and Quad 207 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, -1.0, -1.0); // Top Left Of The Texture and Quad 208 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 209 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 210 | // Right face 211 | c.glNormal3f(1.0, 0.0, 0.0); 212 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Right Of The Texture and Quad 213 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 214 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, 1.0, 1.0); // Top Left Of The Texture and Quad 215 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 216 | // Left Face 217 | c.glNormal3f(-1.0, 0.0, 0.0); 218 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Left Of The Texture and Quad 219 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 220 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, 1.0, 1.0); // Top Right Of The Texture and Quad 221 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 222 | c.glEnd(); 223 | 224 | xrot += xspeed; 225 | yrot += yspeed; 226 | } 227 | 228 | pub fn main() u8 { 229 | if (!init()) { 230 | return 1; 231 | } 232 | 233 | while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { 234 | // Actually draw stuff. 235 | draw(); 236 | 237 | // Swap buffers 238 | c.glfwSwapBuffers(window); 239 | 240 | c.glfwPollEvents(); 241 | } 242 | 243 | return 0; 244 | } 245 | -------------------------------------------------------------------------------- /Lesson07/src/png.zig: -------------------------------------------------------------------------------- 1 | const c = @import("c.zig"); 2 | 3 | // From https://github.com/andrewrk/tetris 4 | pub const PngImage = struct { 5 | width: u32, 6 | height: u32, 7 | pitch: u32, 8 | raw: []u8, 9 | 10 | pub fn destroy(pi: *PngImage) void { 11 | c.stbi_image_free(pi.raw.ptr); 12 | } 13 | 14 | pub fn create(compressed_bytes: []const u8) !PngImage { 15 | var pi: PngImage = undefined; 16 | 17 | var width: c_int = undefined; 18 | var height: c_int = undefined; 19 | 20 | if (c.stbi_info_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len), &width, &height, null) == 0) { 21 | return error.NotPngFile; 22 | } 23 | 24 | if (width <= 0 or height <= 0) return error.NoPixels; 25 | pi.width = @intCast(width); 26 | pi.height = @intCast(height); 27 | 28 | // Not validating channel_count because it gets auto-converted to 4 29 | 30 | if (c.stbi_is_16_bit_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len)) != 0) { 31 | return error.InvalidFormat; 32 | } 33 | const bits_per_channel = 8; 34 | const channel_count = 4; 35 | 36 | c.stbi_set_flip_vertically_on_load(1); 37 | const image_data = c.stbi_load_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len), &width, &height, null, channel_count); 38 | 39 | if (image_data == null) return error.NoMem; 40 | 41 | pi.pitch = pi.width * bits_per_channel * channel_count / 8; 42 | pi.raw = image_data[0 .. pi.height * pi.pitch]; 43 | 44 | return pi; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /Lesson07/stb_image-2.23/stb_image_impl.c: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #define STBI_ONLY_PNG 3 | #define STBI_NO_STDIO 4 | #include "stb_image.h" 5 | -------------------------------------------------------------------------------- /Lesson08/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const currentTarget = @import("builtin").target; 3 | 4 | pub fn build(b: *std.Build) void { 5 | const target = b.standardTargetOptions(.{}); 6 | const optimize = b.standardOptimizeOption(.{}); 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "Lesson08", 10 | .root_source_file = .{ .path = "src/main.zig" }, 11 | .target = target, 12 | .optimize = optimize, 13 | }); 14 | 15 | exe.addCSourceFile(.{ 16 | .file = .{ .path = "stb_image-2.23/stb_image_impl.c" }, 17 | .flags = &[_][]const u8{"-std=c99"}, 18 | }); 19 | 20 | switch (currentTarget.os.tag) { 21 | .macos => { 22 | exe.addFrameworkPath(.{ .path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" }); 23 | exe.addIncludePath("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/OpenGL.framework/Headers"); 24 | exe.linkFramework("OpenGL"); 25 | }, 26 | .freebsd => { 27 | exe.addIncludePath(.{ .path = "/usr/local/include/GL" }); 28 | exe.linkSystemLibrary("gl"); 29 | exe.linkSystemLibrary("glu"); 30 | }, 31 | .linux => { 32 | exe.addLibraryPath(.{ .path = "/usr/lib/x86_64-linux-gnu" }); 33 | exe.linkSystemLibrary("c"); 34 | exe.linkSystemLibrary("GL"); 35 | exe.linkSystemLibrary("GLU"); 36 | }, 37 | else => { 38 | @panic("don't know how to build on your system"); 39 | }, 40 | } 41 | exe.addIncludePath(.{ .path = "stb_image-2.23" }); 42 | exe.addIncludePath(.{ .path = "/usr/local/include" }); 43 | exe.linkSystemLibrary("glfw"); 44 | 45 | b.installArtifact(exe); 46 | 47 | const run_cmd = b.addRunArtifact(exe); 48 | run_cmd.step.dependOn(b.getInstallStep()); 49 | 50 | const run_step = b.step("run", "Run the app"); 51 | run_step.dependOn(&run_cmd.step); 52 | } 53 | -------------------------------------------------------------------------------- /Lesson08/src/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cInclude("GL/glu.h"); 3 | @cInclude("GLFW/glfw3.h"); 4 | @cDefine("STBI_ONLY_PNG", ""); 5 | @cDefine("STBI_NO_STDIO", ""); 6 | @cInclude("stb_image.h"); 7 | }); 8 | -------------------------------------------------------------------------------- /Lesson08/src/data/Glass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mypalmike/zigNeHe/97888ec41794d1ffde02f102416a7dfa2bb71f70/Lesson08/src/data/Glass.png -------------------------------------------------------------------------------- /Lesson08/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const warn = std.log.warn; 3 | const panic = std.debug.panic; 4 | const c = @import("c.zig"); 5 | const PngImage = @import("png.zig").PngImage; 6 | const crate_png = @embedFile("data/Glass.png"); 7 | 8 | const width: i32 = 1024; 9 | const height: i32 = 768; 10 | 11 | var window: *c.GLFWwindow = undefined; 12 | 13 | var light: bool = false; // Lighting ON/OFF 14 | var blend: bool = false; // Blending ON/OFF 15 | 16 | var xrot: c.GLfloat = 0.0; // X Rotation 17 | var yrot: c.GLfloat = 0.0; // Y Rotation 18 | var xspeed: c.GLfloat = 0.0; // X Rotation Speed 19 | var yspeed: c.GLfloat = 0.0; // Y Rotation Speed 20 | var z: c.GLfloat = -5.0; // Depth Into The Screen 21 | 22 | var filter: c.GLuint = 0; // Which Filter To Use 23 | var texture: [3]c.GLuint = undefined; // Storage For 3 Textures 24 | 25 | const lightAmbient = [_]c.GLfloat {0.5, 0.5, 0.5, 1.0}; 26 | const lightDiffuse = [_]c.GLfloat {1.0, 1.0, 1.0, 1.0}; 27 | const lightPosition = [_]c.GLfloat {0.0, 0.0, 2.0, 1.0}; 28 | 29 | fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { 30 | _ = err; 31 | panic("Error: {s}\n", .{description}); 32 | } 33 | 34 | fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { 35 | _ = scancode; 36 | _ = mods; 37 | 38 | if (action == c.GLFW_PRESS) { 39 | switch (key) { 40 | c.GLFW_KEY_ESCAPE => c.glfwSetWindowShouldClose(win, c.GL_TRUE), 41 | 'L' => { 42 | light = !light; 43 | if (light) { 44 | c.glEnable(c.GL_LIGHTING); 45 | } else { 46 | c.glDisable(c.GL_LIGHTING); 47 | } 48 | }, 49 | 'F' => { 50 | filter += 1; 51 | filter = filter % 3; 52 | }, 53 | 'B' => { 54 | blend = !blend; // Toggle blend TRUE / FALSE 55 | if (blend) { 56 | c.glEnable(c.GL_BLEND); // Turn Blending On 57 | c.glDisable(c.GL_DEPTH_TEST); // Turn Depth Testing Off 58 | } else { 59 | c.glDisable(c.GL_BLEND); // Turn Blending Off 60 | c.glEnable(c.GL_DEPTH_TEST); // Turn Depth Testing On 61 | } 62 | }, 63 | else => {}, 64 | } 65 | } else if (action == c.GLFW_REPEAT) { 66 | switch (key) { 67 | c.GLFW_KEY_PAGE_UP => z -= 0.02, 68 | c.GLFW_KEY_PAGE_DOWN => z += 0.02, 69 | c.GLFW_KEY_UP => xspeed -= 0.01, 70 | c.GLFW_KEY_DOWN => xspeed -= 0.01, 71 | c.GLFW_KEY_RIGHT => yspeed += 0.01, 72 | c.GLFW_KEY_LEFT => yspeed -= 0.01, 73 | else => {}, 74 | } 75 | } 76 | } 77 | 78 | fn perspectiveGL(fovY: f64, aspect: f64, zNear: f64, zFar: f64) void { 79 | const fH = std.math.tan(fovY / 360 * std.math.pi) * zNear; 80 | const fW = fH * aspect; 81 | c.glFrustum(-fW, fW, -fH, fH, zNear, zFar); 82 | } 83 | 84 | fn load_textures() !void { 85 | var img = try PngImage.create(crate_png); 86 | 87 | // Create 3 textures 88 | c.glGenTextures(3, &texture); 89 | // errdefer c.glDeleteTextures(3, &texture); 90 | 91 | c.glBindTexture(c.GL_TEXTURE_2D, texture[0]); 92 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST); 93 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST); 94 | c.glTexImage2D( 95 | c.GL_TEXTURE_2D, 96 | 0, 97 | c.GL_RGBA, 98 | @intCast(img.width), 99 | @intCast(img.height), 100 | 0, 101 | c.GL_RGBA, 102 | c.GL_UNSIGNED_BYTE, 103 | @ptrCast(&img.raw[0]), 104 | ); 105 | 106 | c.glBindTexture(c.GL_TEXTURE_2D, texture[1]); 107 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR); 108 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR); 109 | c.glTexImage2D( 110 | c.GL_TEXTURE_2D, 111 | 0, 112 | c.GL_RGBA, 113 | @intCast(img.width), 114 | @intCast(img.height), 115 | 0, 116 | c.GL_RGBA, 117 | c.GL_UNSIGNED_BYTE, 118 | @ptrCast(&img.raw[0]), 119 | ); 120 | 121 | c.glBindTexture(c.GL_TEXTURE_2D, texture[2]); 122 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR_MIPMAP_NEAREST); 123 | c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR); 124 | _ = c.gluBuild2DMipmaps( 125 | c.GL_TEXTURE_2D, 126 | c.GL_RGBA, 127 | @intCast(img.width), 128 | @intCast(img.height), 129 | c.GL_RGBA, 130 | c.GL_UNSIGNED_BYTE, 131 | @ptrCast(&img.raw[0]), 132 | ); 133 | } 134 | 135 | fn init_gl() void { 136 | load_textures() catch { 137 | warn("Failed to load textures.\n", .{}); 138 | }; 139 | 140 | c.glViewport(0, 0, width, height); 141 | c.glMatrixMode(c.GL_PROJECTION); // Select The Projection Matrix 142 | c.glLoadIdentity(); 143 | const fHeight: f32 = @floatFromInt(height); 144 | const fWidth: f32 = @floatFromInt(width); 145 | const aspect_ratio = fHeight / fWidth; 146 | perspectiveGL(45.0, (1.0 / aspect_ratio), 0.1, 100.0); 147 | c.glMatrixMode(c.GL_MODELVIEW); 148 | c.glLoadIdentity(); 149 | 150 | c.glEnable(c.GL_TEXTURE_2D); 151 | c.glShadeModel(c.GL_SMOOTH); // Enables Smooth Shading 152 | c.glClearColor(0.0, 0.0, 0.0, 0.5); // Black Background 153 | c.glClearDepth(1.0); // Depth Buffer Setup 154 | c.glEnable(c.GL_DEPTH_TEST); // Enables Depth Testing 155 | c.glDepthFunc(c.GL_LEQUAL); // The Type Of Depth Test To Do 156 | c.glHint(c.GL_PERSPECTIVE_CORRECTION_HINT, c.GL_NICEST); // Really Nice Perspective Calculations 157 | 158 | c.glLightfv(c.GL_LIGHT1, c.GL_AMBIENT, &lightAmbient[0]); // Setup The Ambient Light 159 | c.glLightfv(c.GL_LIGHT1, c.GL_DIFFUSE, &lightDiffuse[0]); // Setup The Diffuse Light 160 | c.glLightfv(c.GL_LIGHT1, c.GL_POSITION, &lightPosition[0]); // Position The Light 161 | c.glEnable(c.GL_LIGHT1); // Enable Light One 162 | 163 | c.glColor4f(1.0, 1.0, 1.0, 0.5); // Full Brightness, 50% Alpha 164 | c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE); // Blending Function For Translucency Based On Source Alpha Value 165 | } 166 | 167 | fn init() bool { 168 | _ = c.glfwSetErrorCallback(errorCallback); 169 | 170 | if (c.glfwInit() == c.GL_FALSE) { 171 | warn("Failed to initialize GLFW\n", .{}); 172 | return false; 173 | } 174 | 175 | c.glfwWindowHint(c.GLFW_SAMPLES, 4); // 4x antialiasing 176 | 177 | window = c.glfwCreateWindow(width, height, "Lesson08", null, null) orelse { 178 | panic("unable to create window\n", .{}); 179 | }; 180 | 181 | _ = c.glfwSetKeyCallback(window, keyCallback); 182 | c.glfwMakeContextCurrent(window); 183 | c.glfwSwapInterval(1); 184 | 185 | init_gl(); 186 | return true; 187 | } 188 | 189 | fn draw() void { // Here's Where We Do All The Drawing 190 | c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer 191 | c.glLoadIdentity(); // Reset The Current Modelview Matrix 192 | 193 | c.glTranslatef(0.0, 0.0, z); 194 | c.glRotatef(xrot, 1.0, 0.0, 0.0); 195 | c.glRotatef(yrot, 0.0, 1.0, 0.0); 196 | 197 | c.glBindTexture(c.GL_TEXTURE_2D, texture[filter]); // Select Our Texture 198 | 199 | c.glBegin(c.GL_QUADS); 200 | // Front 201 | c.glNormal3f(0.0, 0.0, 1.0); 202 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 203 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 204 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, 1.0); // Top Right Of The Texture and Quad 205 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, 1.0); // Top Left Of The Texture and Quad 206 | // Back Face 207 | c.glNormal3f(0.0, 0.0, -1.0); 208 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Right Of The Texture and Quad 209 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 210 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 211 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Left Of The Texture and Quad 212 | // Top Face 213 | c.glNormal3f(0.0, 1.0, 0.0); 214 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 215 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, 1.0, 1.0); // Bottom Left Of The Texture and Quad 216 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, 1.0, 1.0); // Bottom Right Of The Texture and Quad 217 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 218 | // Bottom Face 219 | c.glNormal3f(0.0, -1.0, 0.0); 220 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, -1.0, -1.0); // Top Right Of The Texture and Quad 221 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, -1.0, -1.0); // Top Left Of The Texture and Quad 222 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 223 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 224 | // Right face 225 | c.glNormal3f(1.0, 0.0, 0.0); 226 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f( 1.0, -1.0, -1.0); // Bottom Right Of The Texture and Quad 227 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f( 1.0, 1.0, -1.0); // Top Right Of The Texture and Quad 228 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f( 1.0, 1.0, 1.0); // Top Left Of The Texture and Quad 229 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f( 1.0, -1.0, 1.0); // Bottom Left Of The Texture and Quad 230 | // Left Face 231 | c.glNormal3f(-1.0, 0.0, 0.0); 232 | c.glTexCoord2f(0.0, 0.0); c.glVertex3f(-1.0, -1.0, -1.0); // Bottom Left Of The Texture and Quad 233 | c.glTexCoord2f(1.0, 0.0); c.glVertex3f(-1.0, -1.0, 1.0); // Bottom Right Of The Texture and Quad 234 | c.glTexCoord2f(1.0, 1.0); c.glVertex3f(-1.0, 1.0, 1.0); // Top Right Of The Texture and Quad 235 | c.glTexCoord2f(0.0, 1.0); c.glVertex3f(-1.0, 1.0, -1.0); // Top Left Of The Texture and Quad 236 | c.glEnd(); 237 | 238 | xrot += xspeed; 239 | yrot += yspeed; 240 | } 241 | 242 | pub fn main() u8 { 243 | if (!init()) { 244 | return 1; 245 | } 246 | 247 | while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { 248 | // Actually draw stuff. 249 | draw(); 250 | 251 | // Swap buffers 252 | c.glfwSwapBuffers(window); 253 | 254 | c.glfwPollEvents(); 255 | } 256 | 257 | return 0; 258 | } 259 | -------------------------------------------------------------------------------- /Lesson08/src/png.zig: -------------------------------------------------------------------------------- 1 | const c = @import("c.zig"); 2 | 3 | // From https://github.com/andrewrk/tetris 4 | pub const PngImage = struct { 5 | width: u32, 6 | height: u32, 7 | pitch: u32, 8 | raw: []u8, 9 | 10 | pub fn destroy(pi: *PngImage) void { 11 | c.stbi_image_free(pi.raw.ptr); 12 | } 13 | 14 | pub fn create(compressed_bytes: []const u8) !PngImage { 15 | var pi: PngImage = undefined; 16 | 17 | var width: c_int = undefined; 18 | var height: c_int = undefined; 19 | 20 | if (c.stbi_info_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len), &width, &height, null) == 0) { 21 | return error.NotPngFile; 22 | } 23 | 24 | if (width <= 0 or height <= 0) return error.NoPixels; 25 | pi.width = @intCast(width); 26 | pi.height = @intCast(height); 27 | 28 | // Not validating channel_count because it gets auto-converted to 4 29 | 30 | if (c.stbi_is_16_bit_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len)) != 0) { 31 | return error.InvalidFormat; 32 | } 33 | const bits_per_channel = 8; 34 | const channel_count = 4; 35 | 36 | c.stbi_set_flip_vertically_on_load(1); 37 | const image_data = c.stbi_load_from_memory(compressed_bytes.ptr, @intCast(compressed_bytes.len), &width, &height, null, channel_count); 38 | 39 | if (image_data == null) return error.NoMem; 40 | 41 | pi.pitch = pi.width * bits_per_channel * channel_count / 8; 42 | pi.raw = image_data[0 .. pi.height * pi.pitch]; 43 | 44 | return pi; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /Lesson08/stb_image-2.23/stb_image_impl.c: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #define STBI_ONLY_PNG 3 | #define STBI_NO_STDIO 4 | #include "stb_image.h" 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zigNeHe 2 | 3 | The ancient NeHe OpenGL tutorials, ported to the Zig language. 4 | 5 | Based largely on the C-based [glfw 2 NeHe tutorials by Joseph Redmon (pjreddie@)](https://github.com/pjreddie/NeHe-Tutorials-Using-GLFW) with updates for glfw 3. Other useful base material from [andrewrk/tetris](https://github.com/andrewrk/tetris). 6 | 7 | The build.zig files work on some versions of MacOS and FreeBSD, as well as Linux (tested on Debian 11-12 and Ubuntu 22.04). With a little effort they should build on other OSes - contributions welcome. Some tweaking of build and c.zig files might be required to build on non-Linux machines. 8 | 9 | ## Requirements 10 | 11 | Tested with Zig version 0.11.0. 12 | 13 | You will need to install [glfw](https://www.glfw.org/). 14 | 15 | ### MacOS 16 | 17 | ```sh 18 | brew install glfw 19 | ``` 20 | 21 | On MacOS, you will also need to install XCode in order to get the OpenGL framework. 22 | 23 | ### Debian 11-12 24 | 25 | ```sh 26 | apt install libglfw3-dev libglu1-mesa-dev 27 | ``` 28 | 29 | ## Building and running 30 | 31 | In each LessonXX directory, you can build and run the given tutorial by running: 32 | 33 | ```sh 34 | zig build run 35 | ``` 36 | 37 | On MacOS, you may run into linking problems with OpenGL. If this happens try: 38 | 39 | ```sh 40 | ZIG_SYSTEM_LINKER_HACK=1 zig build run 41 | ``` 42 | 43 | ## Screenshot 44 | 45 | From Lesson 6: 46 | 47 | ![Screenshot](zigNeHe.png) 48 | 49 | ## TODO 50 | 51 | * Should do error-handling in a more Zig-like way, and actually deal with gl initialization failing. 52 | * All the lessons. 53 | -------------------------------------------------------------------------------- /zigNeHe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mypalmike/zigNeHe/97888ec41794d1ffde02f102416a7dfa2bb71f70/zigNeHe.png --------------------------------------------------------------------------------