Skip to content

Latest commit

 

History

History

hello_triangle

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Hello Triangle book chapter.


excercise 1

Exercise 1: Try to draw 2 triangles next to each other using glDrawArrays by adding more vertices to your data
excercise 1

Exercise 2: Now create the same 2 triangles using two different VAOs and VBOs for their data
excercise 1

Exercise 3: Create two shader programs where the second program uses a different fragment shader that outputs the color yellow; draw both triangles again where one outputs the color yellow.
excercise 1

const std = @import("std");
const glfw = @import("glfw");
const gl = @import("gl");

const vertexShaderSource =
    \\ #version 410 core
    \\ layout (location = 0) in vec3 aPos;
    \\ void main()
    \\ {
    \\   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    \\ }
;

const fragmentShaderSource_1 =
    \\ #version 410 core
    \\ out vec4 FragColor;
    \\ void main() {
    \\  FragColor = vec4(1.0, 0.5, 0.2, 1.0);   
    \\ }
;

const fragmentShaderSource_2 =
    \\ #version 410 core
    \\ out vec4 FragColor;
    \\ void main() {
    \\  FragColor = vec4(1.0, 1.0, 0.2, 1.0);   
    \\ }
;

const WindowSize = struct {
    pub const width: u32 = 800;
    pub const height: u32 = 600;
};

pub fn main() !void {

    // glfw: initialize and configure
    // ------------------------------
    if (!glfw.init(.{})) {
        std.log.err("GLFW initialization failed", .{});
        return;
    }
    defer glfw.terminate();

    // glfw window creation
    // --------------------
    const window = glfw.Window.create(WindowSize.width, WindowSize.height, "mach-glfw + zig-opengl", null, null, .{
        .opengl_profile = .opengl_core_profile,
        .context_version_major = 4,
        .context_version_minor = 1,
    }) orelse {
        std.log.err("GLFW Window creation failed", .{});
        return;
    };
    defer window.destroy();

    glfw.makeContextCurrent(window);
    glfw.Window.setFramebufferSizeCallback(window, framebuffer_size_callback);

    // Load all OpenGL function pointers
    // ---------------------------------------
    const proc: glfw.GLProc = undefined;
    try gl.load(proc, glGetProcAddress);

    // Create vertex shader
    var vertexShader: c_uint = undefined;
    vertexShader = gl.createShader(gl.VERTEX_SHADER);
    defer gl.deleteShader(vertexShader);

    // Attach the shader source to the vertex shader object and compile it
    gl.shaderSource(vertexShader, 1, @ptrCast([*c]const [*c]const u8, &vertexShaderSource), 0);
    gl.compileShader(vertexShader);

    // Check if vertex shader was compiled successfully
    var success: c_int = undefined;
    var infoLog: [512]u8 = [_]u8{0} ** 512;

    gl.getShaderiv(vertexShader, gl.COMPILE_STATUS, &success);

    if (success == 0) {
        gl.getShaderInfoLog(vertexShader, 512, 0, &infoLog);
        std.log.err("{s}", .{infoLog});
    }

    // Fragment shader
    var fragmentShader_1: c_uint = undefined;
    fragmentShader_1 = gl.createShader(gl.FRAGMENT_SHADER);
    defer gl.deleteShader(fragmentShader_1);

    gl.shaderSource(fragmentShader_1, 1, @ptrCast([*c]const [*c]const u8, &fragmentShaderSource_1), 0);
    gl.compileShader(fragmentShader_1);

    gl.getShaderiv(fragmentShader_1, gl.COMPILE_STATUS, &success);

    if (success == 0) {
        gl.getShaderInfoLog(fragmentShader_1, 512, 0, &infoLog);
        std.log.err("{s}", .{infoLog});
    }

    // Fragment shader
    var fragmentShader_2: c_uint = undefined;
    fragmentShader_2 = gl.createShader(gl.FRAGMENT_SHADER);
    defer gl.deleteShader(fragmentShader_2);

    gl.shaderSource(fragmentShader_2, 1, @ptrCast([*c]const [*c]const u8, &fragmentShaderSource_2), 0);
    gl.compileShader(fragmentShader_2);

    gl.getShaderiv(fragmentShader_2, gl.COMPILE_STATUS, &success);

    if (success == 0) {
        gl.getShaderInfoLog(fragmentShader_2, 512, 0, &infoLog);
        std.log.err("{s}", .{infoLog});
    }

    // create a program object
    var shaderProgram_1: c_uint = undefined;
    shaderProgram_1 = gl.createProgram();
    defer gl.deleteProgram(shaderProgram_1);

        // create a program object
    var shaderProgram_2: c_uint = undefined;
    shaderProgram_2 = gl.createProgram();
    defer gl.deleteProgram(shaderProgram_2);

    // attach compiled shader objects to the program object and link
    gl.attachShader(shaderProgram_1, vertexShader);
    gl.attachShader(shaderProgram_1, fragmentShader_1);
    gl.linkProgram(shaderProgram_1);

    // attach compiled shader objects to the program object and link
    gl.attachShader(shaderProgram_2, vertexShader);
    gl.attachShader(shaderProgram_2, fragmentShader_2);
    gl.linkProgram(shaderProgram_2);

    // check if shader linking was successfull
    gl.getProgramiv(shaderProgram_1, gl.LINK_STATUS, &success);
    if (success == 0) {
        gl.getProgramInfoLog(shaderProgram_1, 512, 0, &infoLog);
        std.log.err("{s}", .{infoLog});
    }

    // check if shader linking was successfull
    gl.getProgramiv(shaderProgram_2, gl.LINK_STATUS, &success);
    if (success == 0) {
        gl.getProgramInfoLog(shaderProgram_2, 512, 0, &infoLog);
        std.log.err("{s}", .{infoLog});
    }

    // set up vertex data (and buffer(s)) and configure vertex attributes
    // ------------------------------------------------------------------
    const vertices_1 = [9]f32 { 
        // Triangle 1
        -1.0, -0.5, 0.0, 0.0, -0.5, 0.0, -0.5, 0.5, 0.0,
    };
    
    const vertices_2 = [9]f32 {
        // Triangle 2 
         0.0, -0.5, 0.0, 1.0, -0.5, 0.0, 0.5, 0.5, 0.0
    };   

    var VBOs: [2]c_uint = undefined;
    var VAOs: [2]c_uint = undefined;

    gl.genVertexArrays(2, &VAOs);
    defer gl.deleteVertexArrays(2, &VAOs);

    gl.genBuffers(2, &VBOs);
    defer gl.deleteBuffers(1, &VBOs);

    // bind the Vertex Array Object for trangle 1 first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    gl.bindVertexArray(VAOs[0]);
    gl.bindBuffer(gl.ARRAY_BUFFER, VBOs[0]);
    // Fill our buffer with the vertex data for traingle 1
    gl.bufferData(gl.ARRAY_BUFFER, @sizeOf(f32) * vertices_1.len, &vertices_1, gl.STATIC_DRAW);
    // Specify and link our vertext attribute description
    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 3 * @sizeOf(f32), null);
    gl.enableVertexAttribArray(0);
    
    // bind the Vertex Array Object for triangle 2 first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    gl.bindVertexArray(VAOs[1]);
    gl.bindBuffer(gl.ARRAY_BUFFER, VBOs[1]);
    // Fill our buffer with the vertex data
    gl.bufferData(gl.ARRAY_BUFFER, @sizeOf(f32) * vertices_2.len, &vertices_2, gl.STATIC_DRAW);
    // Specify and link our vertext attribute description
    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 3 * @sizeOf(f32), null);
    gl.enableVertexAttribArray(0);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    gl.bindBuffer(gl.ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    gl.bindVertexArray(0);

    while (!window.shouldClose()) {
        processInput(window);

        gl.clearColor(0.2, 0.3, 0.3, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT);
        
        // Activate shaderProgram
        gl.useProgram(shaderProgram_1);
        // Draw triangle 1
        gl.bindVertexArray(VAOs[0]); 
        gl.drawArrays(gl.TRIANGLES, 0, 3);
        
        // Activate shaderProgram
        gl.useProgram(shaderProgram_2);
        // Draw triangle 2
        gl.bindVertexArray(VAOs[1]);
        gl.drawArrays(gl.TRIANGLES, 0, 3);

        window.swapBuffers();
        glfw.pollEvents();
    }
}

fn glGetProcAddress(p: glfw.GLProc, proc: [:0]const u8) ?gl.FunctionPointer {
    _ = p;
    return glfw.getProcAddress(proc);
}

fn framebuffer_size_callback(window: glfw.Window, width: u32, height: u32) void {
    _ = window;
    gl.viewport(0, 0, @intCast(c_int, width), @intCast(c_int, height));
}

fn processInput(window: glfw.Window) void {
    if (glfw.Window.getKey(window, glfw.Key.escape) == glfw.Action.press) {
        _ = glfw.Window.setShouldClose(window, true);
    }
}