lots of updates!
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 20 Dec 2021 23:58:24 +0000 (17:58 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 20 Dec 2021 23:58:24 +0000 (17:58 -0600)
16 files changed:
lib/stb_truetype.c
lib/stb_truetype.onyx
run_tree/assets/shaders/basic_vertex.glsl
run_tree/assets/shaders/font_fragment.glsl [new file with mode: 0644]
run_tree/assets/shaders/font_vertex.glsl [new file with mode: 0644]
run_tree/assets/shaders/world_vertex.glsl
run_tree/lib/onyx_opengles.so
src/build.onyx
src/camera.onyx
src/chunk.onyx
src/font.onyx [new file with mode: 0644]
src/main.onyx
src/mesh.onyx
src/shader.onyx [new file with mode: 0644]
src/vecmath.onyx
src/world.onyx [new file with mode: 0644]

index 37ddff898a2898c9d418609e10270a05cda11354..0ae528aa0f1527177370e4aaf9740619dcd6fc97 100644 (file)
@@ -87,4 +87,4 @@ ONYX_LIBRARY {
     ONYX_FUNC(stbtt_GetPackedQuad)
 
     NULL
-};
\ No newline at end of file
+};
index a40ffd9b23e58978d900130c1a07512820cbf156..a2be6c4014d608e1c14571ddf54fefee49857125 100644 (file)
@@ -10,12 +10,19 @@ stbtt_packedchar :: struct #size 28 {
     xoff2, yoff2: f32;
 }
 
+stbtt_aligned_quad :: struct #size 32 {
+    x0, y0, s0, t0 : f32;
+    x1, y1, s1, t1 : f32;
+}
+
 #foreign "stb_truetype" {
     stbtt_PackBegin           :: (ctx: ^stbtt_pack_context, pixels: ^u8, width, height, stride_in_bytes, padding: i32) -> i32 ---
     stbtt_PackEnd             :: (ctx: ^stbtt_pack_context) -> void ---
     stbtt_PackFontRange       :: (ctx: ^stbtt_pack_context, fontdata: ^u8, font_index: i32, font_size: f32, first_unicode_char_in_range: i32, num_chars_in_range: i32, chardata_for_range: ^stbtt_packedchar) -> i32 ---
     stbtt_PackSetOversampling :: (ctx: ^stbtt_pack_context, h_oversample, v_oversample: i32) -> void ---
+
+    stbtt_GetPackedQuad       :: (chardata: ^stbtt_packedchar, pw, ph: i32, char_index: i32, xpos, ypos: ^f32, quad: ^stbtt_aligned_quad, align_to_integer: bool) -> void ---
 }
 
 #export "stbtt_heap_alloc" calloc
-#export "stbtt_heap_free"  cfree
\ No newline at end of file
+#export "stbtt_heap_free"  cfree
index 5efc2ecf2c95b2a891a3abd03951e3a9503f0ed2..67d8d32b42739363026903531a962d3776418ad4 100644 (file)
@@ -2,7 +2,7 @@
 layout(location = 0) in vec3 a_pos;
 layout(location = 1) in vec2 a_tex;
 
-layout(std140) uniform u_matrix_block {
+layout(std140) uniform u_world_matrix_block {
     mat4 u_view;
     mat4 u_world;
     mat4 u_model;
diff --git a/run_tree/assets/shaders/font_fragment.glsl b/run_tree/assets/shaders/font_fragment.glsl
new file mode 100644 (file)
index 0000000..553d9f6
--- /dev/null
@@ -0,0 +1,13 @@
+#version 300 es
+precision mediump float;
+
+in vec4 v_color;
+in vec2 v_texture;
+
+uniform sampler2D u_texture;
+
+out vec4 fragColor;
+
+void main() {
+    fragColor = vec4(v_color.rgb, v_color.a * texture(u_texture, v_texture).a);
+}
diff --git a/run_tree/assets/shaders/font_vertex.glsl b/run_tree/assets/shaders/font_vertex.glsl
new file mode 100644 (file)
index 0000000..4e58e4b
--- /dev/null
@@ -0,0 +1,21 @@
+#version 300 es
+precision mediump float;
+layout(location = 0) in vec2 a_interp;
+layout(location = 1) in vec2 a_pos_top_left;
+layout(location = 2) in vec2 a_pos_bottom_right;
+layout(location = 3) in vec2 a_tex_top_left;
+layout(location = 4) in vec2 a_tex_bottom_right;
+
+layout(std140) uniform u_window_matrix_block {
+    mat4 u_window;
+};
+
+out vec4 v_color;
+out vec2 v_texture;
+
+void main() {
+    gl_Position = u_window * vec4(mix(a_pos_top_left, a_pos_bottom_right, a_interp), 0, 1);
+    v_texture = mix(a_tex_top_left, a_tex_bottom_right, a_interp);
+    v_color   = vec4(0, 0, 0, 1);
+}
+
index d93598aa9e1ea034eb67d38788087c41bd6200c5..8f50ed8f2ecc164bd57cf34b44783194c9d46a7f 100644 (file)
@@ -2,7 +2,7 @@
 layout(location = 0) in vec3 a_pos;
 layout(location = 1) in uint a_data;
 
-layout(std140) uniform u_matrix_block {
+layout(std140) uniform u_world_matrix_block {
     mat4 u_view;
     mat4 u_world;
     mat4 u_model;
@@ -11,7 +11,7 @@ layout(std140) uniform u_matrix_block {
 out vec4 v_color;
 
 void main() {
-    gl_Position = u_view * u_world * vec4(a_pos, 1);
+    gl_Position = u_view * u_world * u_model * vec4(a_pos, 1);
 
     vec3 block_color = vec3(
         float((a_data & 0x0000FU) >>  0U) / 15.0,
index 71591b0922cef35fce573675c5eda80c5347170c..393e39ffa4675376eb0aa7d2a7f7d30540f470de 100755 (executable)
Binary files a/run_tree/lib/onyx_opengles.so and b/run_tree/lib/onyx_opengles.so differ
index f2c978a6e6eaab0f1abf545c1007ed689ff6fa74..310b3d434be6172bd6a8e3760fa4674274a53b55 100644 (file)
@@ -13,6 +13,9 @@
 #load "mesh"
 #load "vecmath"
 #load "chunk"
+#load "world"
+#load "font"
+#load "shader"
 
 // Onyx library code
 #load "stb_truetype"
index f0b38fe56f650754be996c51f2566b43582f50cc..070d41be8bf6a7ffcf0efd86bf4c45d4a93decac 100644 (file)
@@ -5,7 +5,7 @@ Camera :: struct {
     window_width, window_height: f32;
 
     z_near := 0.01f;
-    z_far  := 100.0f;
+    z_far  := 300.0f;
     
     x_rot, y_rot: f32;
     position: Vector3;
@@ -68,3 +68,21 @@ camera_get_world_matrix :: (use cam: ^Camera, out: [16] f32) {
     out[14] = Vector3.dot(neg_forward, neg_pos);
     out[15] = 1;
 }
+
+camera_get_window_matrix :: (use cam: ^Camera, out: [16] f32) {
+    top    := 0.0f;
+    left   := 0.0f;
+    right  := cast(f32) window_width;
+    bottom := cast(f32) window_height;
+    far    := 10.0f;
+    near   := 0f;
+    
+    out[0] = 2 / (right - left);
+    out[5] = 2 / (top - bottom);
+    out[10] = -2 / (far - near);
+    out[12] = -(right + left) / (right - left);
+    out[13] = -(top + bottom) / (top - bottom);
+    out[14] = -(far + near) / (far - near);
+    out[15] = 1;
+}
+
index f592b24aae62896a8585e17d1da2d2e91e2667bd..45c8b1c222c7decf5846739266fb024d3d432b4e 100644 (file)
@@ -1,8 +1,8 @@
 use package core
 
 Block :: #distinct u32;
-#operator == (b1, b2: Block) => cast(u32) b1 == cast(u32) b2;
-#operator != (b1, b2: Block) => cast(u32) b1 != cast(u32) b2;
+#operator == macro (b1, b2: Block) => cast(u32) b1 == cast(u32) b2;
+#operator != macro (b1, b2: Block) => cast(u32) b1 != cast(u32) b2;
 
 Block_Empty :: cast(Block) 0;
 
@@ -15,18 +15,37 @@ block_make :: (red, green, blue: f32, brightness: f32) -> Block {
     return ~~((i << 12) | (b << 8) | (g << 4) | r);
 }
 
+Chunk_Vertex :: struct {
+    position: Vector3;
+
+    // This field is broken up by bit, but Onyx does not (nor ever will) support bit-fields.
+    //
+    //  4-bits (0..3) - red color
+    //  4-bits (4..7) - green color
+    //  4-bits (8..11) - blue color
+    //  4-bits (12..15) - intensity
+    data: u32;
+}
+
 Chunk_Size :: 32
 
 Chunk :: struct {
+    position: Vector3;
     blocks: [] Block;
 
-    mesh: ^Mesh = null;
+    mesh: ^Mesh(Chunk_Vertex) = null;
+    mesh_dirty := false;
 }
 
-chunk_make :: (allocator := context.allocator) -> ^Chunk {
+chunk_make :: (x, y, z: i32, allocator := context.allocator) -> ^Chunk {
     chunk := new(Chunk, allocator);
+    chunk.position = .{
+        ~~(x * Chunk_Size),
+        ~~(y * Chunk_Size),
+        ~~(z * Chunk_Size),
+    };
     memory.alloc_slice(^chunk.blocks, Chunk_Size * Chunk_Size * Chunk_Size);
-    memory.fill_slice(chunk.blocks, block_make(0,0,0,0));
+    memory.fill_slice(chunk.blocks, Block_Empty);
     return chunk;
 }
 
@@ -43,6 +62,7 @@ chunk_make :: (allocator := context.allocator) -> ^Chunk {
 chunk_set :: (use chunk: ^Chunk, x, y, z: i32, block: Block) {
     if !in_chunk_bounds(x, y, z) do return;
     blocks[x * Chunk_Size * Chunk_Size + y * Chunk_Size + z] = block;
+    mesh_dirty = true;
 }
 
 chunk_get :: (use chunk: ^Chunk, x, y, z: i32) -> Block {
@@ -79,11 +99,17 @@ chunk_get :: (use chunk: ^Chunk, x, y, z: i32) -> Block {
     u32.[ 0, 4, 7, 0, 7, 3 ]
 ];
 
-chunk_build_mesh :: (use chunk: ^Chunk) -> ^Mesh {
-    verticies := array.make(Vertex, capacity=512);
+chunk_build_mesh :: (use chunk: ^Chunk) {
+    if mesh != null && mesh_dirty == false do return;
+    if mesh != null {
+        mesh_free(mesh);
+        mesh = null;
+    }
+
+    verticies := array.make(Chunk_Vertex, capacity=512);
     defer array.free(^verticies);
 
-    chunk_foreach(chunk) #{
+    chunk_foreach(chunk) {
         if block == Block_Empty do continue;
 
         for i: 6 {
@@ -104,14 +130,19 @@ chunk_build_mesh :: (use chunk: ^Chunk) -> ^Mesh {
             indicies := cast([] u32) block_indicies[i];
             for j: 6 {
                 v := block_verticies[indicies[j]];
-                verticies << .{ ~~x+v.x, ~~y+v.y, ~~z+v.z, ~~color };
+                verticies << .{ .{ ~~x+v.x, ~~y+v.y, ~~z+v.z }, ~~color };
             }
         }
-    };
+    }
 
-    return mesh_make(verticies, .[]);
+    mesh = mesh_make(verticies, .[]);
+    mesh_dirty = false;
 }
 
+chunk_draw :: (chunk: ^Chunk) {
+    update_model_matrix(chunk.position);
+    mesh_draw(chunk.mesh);
+}
 
 
 chunk_foreach :: macro (chunk: ^Chunk, body: Code) {
diff --git a/src/font.onyx b/src/font.onyx
new file mode 100644 (file)
index 0000000..6e91de4
--- /dev/null
@@ -0,0 +1,163 @@
+
+use package core
+use package core.intrinsics.onyx {__zero_value}
+use package stb_truetype
+use package opengles
+
+#local {
+    font_registry: Map(FontDescriptor, Font);
+    font_vbo:      GLint;
+    font_vao:      GLint;
+
+    font_shader:   Shader;
+}
+
+fonts_init :: () {
+    map.init(^font_registry);
+
+    font_shader = shader_make("./assets/shaders/font_vertex.glsl", "./assets/shaders/font_fragment.glsl");
+    shader_use(font_shader);
+    shader_link_window_matrix_block(font_shader);
+
+    glGenVertexArrays(1, ^font_vao);
+    glBindVertexArray(font_vao);
+
+    font_interp_buffer: GLint;
+    glGenBuffers(1, ^font_interp_buffer);
+    glBindBuffer(GL_ARRAY_BUFFER, font_interp_buffer);
+    font_interp_data := f32.[
+        0.0, 0.0,
+        1.0, 0.0,
+        1.0, 1.0,
+        0.0, 1.0,
+    ];
+    glBufferData(GL_ARRAY_BUFFER, sizeof typeof font_interp_data, ~~^font_interp_data, GL_STATIC_DRAW);
+    glEnableVertexAttribArray(0);
+    glVertexAttribPointer(0, 2, GL_FLOAT, false, 2 * sizeof f32, ~~0);
+
+    font_index_buffer: GLint;
+    glGenBuffers(1, ^font_index_buffer);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_index_buffer);
+    font_index_data := u8.[ 0, 1, 2, 0, 2, 3 ];
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof typeof font_index_data, ~~^font_index_data, GL_STATIC_DRAW);
+
+    glGenBuffers(1, ^font_vbo);
+    glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
+    glBufferData(GL_ARRAY_BUFFER, 1024 * sizeof stbtt_aligned_quad, null, GL_STREAM_DRAW);
+
+    for 1..5 {
+        glEnableVertexAttribArray(it);
+        glVertexAttribDivisor(it, 1);
+    }
+    glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof stbtt_aligned_quad, ~~ 0);
+    glVertexAttribPointer(2, 2, GL_FLOAT, false, sizeof stbtt_aligned_quad, ~~16);
+    glVertexAttribPointer(3, 2, GL_FLOAT, false, sizeof stbtt_aligned_quad, ~~8);
+    glVertexAttribPointer(4, 2, GL_FLOAT, false, sizeof stbtt_aligned_quad, ~~24);
+
+    glBindBuffer(GL_ARRAY_BUFFER, -1);
+    glBindVertexArray(-1);
+}
+
+
+Font :: struct {
+    texture: GLint;
+    texture_width, texture_height: i32;
+    chars: [] stbtt_packedchar;
+}
+
+font_make :: (fd: FontDescriptor) -> Font {
+    texture_size :: 512;
+
+    char_data := memory.make_slice(stbtt_packedchar, 96);
+
+    ttf_file := os.get_contents(fd.path);
+    if ttf_file.count == 0 {
+        println("Bad font");
+        return __zero_value(Font);
+    }
+    defer cfree(ttf_file.data);
+
+    pixels := calloc(texture_size * texture_size);
+    defer cfree(pixels);
+
+    ctx: stbtt_pack_context;
+    stbtt_PackBegin(^ctx, pixels, texture_size, texture_size, 0, 1);
+    stbtt_PackFontRange(^ctx, ttf_file.data, 0, ~~fd.size, #char " ", 96, char_data.data); 
+    stbtt_PackEnd(^ctx);
+
+    texture: GLint;
+    glGenTextures(1, ^texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture_size, texture_size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glBindTexture(GL_TEXTURE_2D, -1);
+
+    font := Font.{
+        texture = texture,
+        texture_width = texture_size,
+        texture_height = texture_size,
+        chars = char_data
+    };
+
+    return font;
+}
+
+alloca :: macro (size: u32) -> rawptr {
+    defer __stack_top = ~~(cast(^u8) __stack_top + size);
+    return __stack_top;
+}
+
+font_draw :: (font: Font, x, y: f32, msg: str) {
+    quads: ^stbtt_aligned_quad = alloca(msg.count * sizeof stbtt_aligned_quad);
+    quad_num := 0;
+
+    x_, y_ := x, y;
+
+    for msg {
+        stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height,
+            ~~(it - #char " "), ^x_, ^y_, ^quads[quad_num], false);
+
+        quad_num += 1;
+    }
+
+    glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, quad_num * sizeof stbtt_aligned_quad, quads);
+    glBindBuffer(GL_ARRAY_BUFFER, -1);
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, font.texture);
+    shader_use(font_shader);
+    shader_set_uniform(font_shader, #cstr "u_texture", 0);
+
+    glBindVertexArray(font_vao);
+    glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, ~~0, quad_num);
+    glBindTexture(GL_TEXTURE_2D, -1);
+    glBindVertexArray(-1);
+}
+
+
+
+FontDescriptor :: struct {
+    path : str;
+    size : u32;
+}
+
+#match hash.to_u32 (fd: FontDescriptor) => {
+    name_hash := hash.to_u32(fd.path);
+    size_hash := hash.to_u32(fd.size);
+    return name_hash * 13 + size_hash * 17;
+}
+
+#operator == (f1, f2: FontDescriptor) => f1.path == f2.path && f1.size == f2.size;
+
+font_lookup :: (fd := FontDescriptor.{ "assets/calibri.ttf", 12 }) -> Font {
+    if font_registry->has(fd) {
+        return font_registry[fd];
+    }
+    
+    font := font_make(fd);
+    font_registry[fd] = font;
+    return font;
+}
+
index b3146b0efd0ef497c3c06c5b71157e47a61f3f0d..e6be5afc0a99d6b25d2c07342ceb2aaa06cc5aa5 100644 (file)
@@ -10,7 +10,8 @@ camera: Camera;
 
 create_window :: () => {
     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
+    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
     window = glfwCreateWindow(1200, 720, #cstr "Voxel Shooter");
 
     glfwMakeContextCurrent(window);
@@ -23,6 +24,7 @@ create_window :: () => {
     glViewport(0, 0, width, height);
     camera_set_window_size(^camera, ~~width, ~~height);
     update_view_matrix();
+    update_window_matrix();
 }
 
 #export "on_key" (window: GLFWwindow_p, key, scancode, action, mod: u32) {
@@ -51,83 +53,35 @@ toggle_cursor_grabbed :: () {
     }
 }
 
-chunk: ^Chunk;
-matrix_block_buffer: GLuint;
+world: ^World;
+world_shader: Shader;
+font: Font;
 
 setup_opengl :: () {
     glInit(glfwGetLoadProcAddress());
 
+    glEnable(GL_TEXTURE);
     glEnable(GL_DEPTH_TEST);
     glEnable(GL_CULL_FACE);
     glFrontFace(GL_CW);
     glCullFace(GL_BACK);
     glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-    compile_shader :: (source: str, type: GLenum) -> GLint {
-        shader := glCreateShader(type);
-        source_data := source.data;
-        source_len  := source.count;
-        glShaderSource(shader, 1, ^source_data, ^source_len);
-        glCompileShader(shader);
-
-        success: GLint;
-        if glGetShaderiv(shader, GL_COMPILE_STATUS, ^success); success == GL_FALSE {
-            buf_data: [1024] u8;
-            buf := str.{ ~~buf_data, 0 };
-            glGetShaderInfoLog(shader, 1024, ^buf.count, buf.data);
-            println(buf);
-        }
-
-        return shader;
-    }
-
-    link_program :: (vertex_shader, fragment_shader: GLint) -> GLuint {
-        prog := glCreateProgram();
-        glAttachShader(prog, vertex_shader);
-        glAttachShader(prog, fragment_shader);
-        glLinkProgram(prog);
-
-        success: GLint;
-        if glGetProgramiv(prog, GL_LINK_STATUS, ^success); success == GL_FALSE {
-            buf_data: [1024] u8;
-            buf := str.{ ~~buf_data, 0 };
-            glGetProgramInfoLog(prog, 1024, ^buf.count, buf.data);
-            println(buf);
-        }
+    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 
-        return prog;
-    }
-
-    vertex_shader := os.get_contents("assets/shaders/world_vertex.glsl");    
-    fragment_shader := os.get_contents("assets/shaders/world_fragment.glsl");
-    vs := compile_shader(vertex_shader, GL_VERTEX_SHADER);
-    fs := compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
-
-    prog := link_program(vs, fs);
-    glUseProgram(prog);
+    shaders_init();
+    fonts_init();
 
-    matrix: [32] GLfloat;
-    glGenBuffers(1, ^matrix_block_buffer);
-    glBindBuffer(GL_UNIFORM_BUFFER, matrix_block_buffer);
-    glBufferData(GL_UNIFORM_BUFFER, sizeof f32 * (16 + 16 + 16), ^matrix, GL_DYNAMIC_DRAW);
-    glBindBuffer(GL_UNIFORM_BUFFER, -1);
+    world_shader = shader_make(
+        "assets/shaders/world_vertex.glsl",
+        "assets/shaders/world_fragment.glsl");
 
-    glBindBufferBase(GL_UNIFORM_BUFFER, 0, matrix_block_buffer);
-
-    matrix_block_index := glGetUniformBlockIndex(prog, #cstr "u_matrix_block");
-    glUniformBlockBinding(prog, matrix_block_index, 0);
-
-    chunk = chunk_make();
-    for z: 32 do for x: 32 {
-        chunk_set(chunk, x, 0, z, block_make(0.2, 1, 0.2, 0.8));
-    }
-    for z: 32 do for x: 32 {
-        if random.between(0, 10) >= 7 do continue;
-        chunk_set(chunk, x, 1, z, block_make(random.float(0, 1), random.float(0, 1), random.float(0, 1), 1));
-    }
-    chunk.mesh = chunk_build_mesh(chunk);
+    shader_link_world_matrix_block(world_shader);
 
+    font = font_lookup(.{"./assets/calibri.ttf", 32});
+    
+    shader_use(world_shader);
+    world = world_make();
+    
     __initialize(^camera);
     camera.position = .{5,5,5};
     camera_set_fov(^camera, 75);
@@ -137,24 +91,8 @@ setup_opengl :: () {
 
     update_view_matrix();
     update_world_matrix();
-}
-
-update_view_matrix :: () {
-    view_mat: [16] f32;
-    camera_get_view_matrix(^camera, view_mat);
-
-    glBindBuffer(GL_UNIFORM_BUFFER, matrix_block_buffer);
-    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof typeof view_mat, ^view_mat);
-    glBindBuffer(GL_UNIFORM_BUFFER, -1);
-}
-
-update_world_matrix :: () {
-    world_mat: [16] f32;
-    camera_get_world_matrix(^camera, world_mat);
-
-    glBindBuffer(GL_UNIFORM_BUFFER, matrix_block_buffer);
-    glBufferSubData(GL_UNIFORM_BUFFER, 16 * sizeof f32, sizeof typeof world_mat, ^world_mat);
-    glBindBuffer(GL_UNIFORM_BUFFER, -1);
+    update_model_matrix(.{0, 0, 0});
+    update_window_matrix();
 }
 
 update :: (dt: f32) {
@@ -179,9 +117,9 @@ update :: (dt: f32) {
     camera.x_rot += ~~(my - last_mouse_y) / 400.0f;
     camera.x_rot = math.clamp(camera.x_rot, -math.PI / 2 + 0.1, math.PI / 2 - 0.1);
 
-    speed := 3 * dt;
+    speed := 5 * dt;
     if glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS {
-        speed = 8 * dt;
+        speed = 15 * dt;
     }
 
     facing := camera_get_forward(^camera);
@@ -205,23 +143,10 @@ draw :: () {
     glClearColor(.7, .7, .9, 1);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-/*
-    #persist forward : Vector3;
-    forward = camera_get_forward(^camera);
-    array.sort(cubes, (x, y) => {
-        v := Vector3.dot(forward, *(cast(^Vector3) ^y.verticies[0]) - camera.position) - Vector3.dot(forward, *(cast(^Vector3) ^x.verticies[0]) - camera.position); 
-        if v < 0 do return -1;
-        if v > 0 do return 1;
-        return 0;
-    });
-
-    for cubes {
-        // if Vector3.dot(forward, *(cast(^Vector3) ^it.verticies[0]) - camera.position) < 0 do continue;
-        mesh_draw(it);
-    }
-    */
+    shader_use(world_shader);
+    world_draw(world);
 
-    mesh_draw(chunk.mesh);
+    font_draw(font, 100, 100, "Hello!");
 
     glfwSwapBuffers(window);
 }
index feb3b79862144a3ef80607c90c5e384af60cadce..42859a99ba6cae61a47b2f0bf1eb2990046f7896 100644 (file)
@@ -1,19 +1,7 @@
 use package core
 use package opengles
 
-Vertex :: struct {
-    x, y, z: f32;
-
-    // This field is broken up by bit, but Onyx does not (nor ever will) support bit-fields.
-    //
-    //  4-bits (0..3) - red color
-    //  4-bits (4..7) - green color
-    //  4-bits (8..11) - blue color
-    //  4-bits (12..15) - intensity
-    data: u32;
-}
-
-Mesh :: struct {
+Mesh :: struct (T: type_expr) {
     handle: GLint;
     vertex_handle: GLint;
     index_handle: GLint;
@@ -22,8 +10,8 @@ Mesh :: struct {
     index_count: u32;
 }
 
-mesh_make :: (verticies: [] Vertex, indicies: [] u32) -> ^Mesh {
-    mesh := new(Mesh);
+mesh_make :: (verticies: [] $T, indicies: [] u32) -> ^Mesh(T) {
+    mesh := new(Mesh(T));
     mesh.vertex_count = verticies.count;
     mesh.index_count  = indicies.count;
 
@@ -32,23 +20,39 @@ mesh_make :: (verticies: [] Vertex, indicies: [] u32) -> ^Mesh {
 
     glGenBuffers(1, ^mesh.vertex_handle);
     glBindBuffer(GL_ARRAY_BUFFER, mesh.vertex_handle);
-    glBufferData(GL_ARRAY_BUFFER, sizeof Vertex * verticies.count, verticies.data, GL_STATIC_DRAW);
-
-    glEnableVertexAttribArray(0);
-    glEnableVertexAttribArray(1);
-    glVertexAttribPointer(0, 3, GL_FLOAT,        false, sizeof Vertex, ~~0);
-    glVertexAttribIPointer(1, 1, GL_UNSIGNED_INT, sizeof Vertex, ~~12);
+    glBufferData(GL_ARRAY_BUFFER, sizeof T * verticies.count, verticies.data, GL_STATIC_DRAW);
+
+    vertex_info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(T);
+    vertex_attr := 0;
+    for attr: vertex_info.members {
+        defer vertex_attr += 1;
+        glEnableVertexAttribArray(vertex_attr);
+
+        switch attr.type {
+            case Vector2 do glVertexAttribPointer(vertex_attr, 2, GL_FLOAT, false, sizeof T, ~~attr.offset);
+            case Vector3 do glVertexAttribPointer(vertex_attr, 3, GL_FLOAT, false, sizeof T, ~~attr.offset);
+            case u32 do glVertexAttribIPointer(vertex_attr, 1, GL_UNSIGNED_INT, sizeof T, ~~attr.offset);
+            case i32 do glVertexAttribIPointer(vertex_attr, 1, GL_INT, sizeof T, ~~attr.offset);
+            case #default {
+                buf: [256] u8;
+                msg := conv.str_format(buf, "Unknown type for GL vertex attribute, {}.", attr.type);
+                assert(false, msg);
+            }
+        }
+    }
 
-    glGenBuffers(1, ^mesh.index_handle);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.index_handle);
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof i32 * indicies.count, indicies.data, GL_STATIC_DRAW);
+    if indicies.count > 0 {
+        glGenBuffers(1, ^mesh.index_handle);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.index_handle);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof i32 * indicies.count, indicies.data, GL_STATIC_DRAW);
+    }
 
     glBindVertexArray(-1);
 
     return mesh;
 }
 
-mesh_draw :: (use mesh: ^Mesh) {
+mesh_draw :: (use mesh: ^Mesh($T)) {
     glBindVertexArray(handle);
     if index_count > 0 {
         glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, ~~0);
@@ -58,6 +62,17 @@ mesh_draw :: (use mesh: ^Mesh) {
     glBindVertexArray(-1);
 }
 
+mesh_free :: (mesh: ^Mesh($T)) {
+    glDeleteBuffers(1, ^mesh.vertex_handle);
+    glDeleteBuffers(1, ^mesh.index_handle);
+    glDeleteVertexArrays(1, ^mesh.handle);
+    cfree(mesh);
+}
+
+
+
+#if false {
+// Old code for making a single cube
 mesh_make_cube :: (x, y, z: f32) -> ^Mesh {
     data := random.between(0x0000, 0xffff);
 
@@ -93,9 +108,4 @@ mesh_make_cube :: (x, y, z: f32) -> ^Mesh {
 
     return mesh_make(vertex_data, index_data);
 }
-
-mesh_free :: (mesh: ^Mesh) {
-    glDeleteBuffers(1, ^mesh.vertex_handle);
-    glDeleteBuffers(1, ^mesh.index_handle);
-    glDeleteVertexArrays(1, ^mesh.handle);
-}
+}
\ No newline at end of file
diff --git a/src/shader.onyx b/src/shader.onyx
new file mode 100644 (file)
index 0000000..2b3279d
--- /dev/null
@@ -0,0 +1,146 @@
+
+use package core
+use package opengles
+
+Shader :: struct {
+    vs, fs: GLuint;
+    prog: GLuint;
+}
+
+window_matrix_block_buffer: GLuint;
+world_matrix_block_buffer:  GLuint;
+
+shaders_init :: () {
+    glGenBuffers(1, ^window_matrix_block_buffer);
+    glGenBuffers(1, ^world_matrix_block_buffer);
+
+    glBindBuffer(GL_UNIFORM_BUFFER, window_matrix_block_buffer);
+    glBufferData(GL_UNIFORM_BUFFER, sizeof f32 * 16, null, GL_DYNAMIC_DRAW);
+
+    glBindBuffer(GL_UNIFORM_BUFFER, world_matrix_block_buffer);
+    glBufferData(GL_UNIFORM_BUFFER, sizeof f32 * (16 + 16 + 16), null, GL_DYNAMIC_DRAW);
+
+    glBindBuffer(GL_UNIFORM_BUFFER, -1);
+
+    glBindBufferBase(GL_UNIFORM_BUFFER, WINDOW_MATRIX_BLOCK, window_matrix_block_buffer);
+    glBindBufferBase(GL_UNIFORM_BUFFER, WORLD_MATRIX_BLOCK, world_matrix_block_buffer);
+}
+
+shader_make :: (vertex_path, fragment_path: str) -> Shader {
+    vertex_shader := os.get_contents(vertex_path);
+    fragment_shader := os.get_contents(fragment_path);
+    vs := compile_shader(vertex_shader, GL_VERTEX_SHADER);
+    fs := compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
+
+    prog := link_program(vs, fs);
+
+    return Shader.{vs, fs, prog};
+}
+
+shader_use :: (shader: Shader) {
+    glUseProgram(shader.prog);
+}
+
+WINDOW_MATRIX_BLOCK :: 0;
+WORLD_MATRIX_BLOCK  :: 1;
+
+shader_link_window_matrix_block :: (use shader: Shader) {
+    matrix_block_index := glGetUniformBlockIndex(prog, #cstr "u_window_matrix_block");
+    glUniformBlockBinding(prog, matrix_block_index, WINDOW_MATRIX_BLOCK);
+}
+
+shader_link_world_matrix_block :: (use shader: Shader) {
+    matrix_block_index := glGetUniformBlockIndex(prog, #cstr "u_world_matrix_block");
+    glUniformBlockBinding(prog, matrix_block_index, WORLD_MATRIX_BLOCK);
+}
+
+shader_set_uniform :: (shader: Shader, uniform: cstr, value: $T) {
+    glUseProgram(shader.prog);
+    location := glGetUniformLocation(shader.prog, uniform);
+
+    switch T {
+        case i32, u32 do glUniform1i(location, value);
+        case #default do assert(false, "Bad case.");
+    }
+}
+
+update_view_matrix :: () {
+    view_mat: [16] f32;
+    camera_get_view_matrix(^camera, view_mat);
+
+    glBindBuffer(GL_UNIFORM_BUFFER, world_matrix_block_buffer);
+    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof typeof view_mat, ^view_mat);
+    glBindBuffer(GL_UNIFORM_BUFFER, -1);
+}
+
+update_world_matrix :: () {
+    world_mat: [16] f32;
+    camera_get_world_matrix(^camera, world_mat);
+
+    glBindBuffer(GL_UNIFORM_BUFFER, world_matrix_block_buffer);
+    glBufferSubData(GL_UNIFORM_BUFFER, 16 * sizeof f32, sizeof typeof world_mat, ^world_mat);
+    glBindBuffer(GL_UNIFORM_BUFFER, -1);
+}
+
+update_window_matrix :: () {
+    window_mat: [16] f32;
+    camera_get_window_matrix(^camera, window_mat);
+
+    glBindBuffer(GL_UNIFORM_BUFFER, window_matrix_block_buffer);
+    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof typeof window_mat, ^window_mat);
+    glBindBuffer(GL_UNIFORM_BUFFER, -1);
+}
+
+update_model_matrix :: (v: Vector3) {
+    model_mat: [16] f32;
+    model_mat[0]  = 1;
+    model_mat[5]  = 1;
+    model_mat[10]  = 1;
+    model_mat[12] = v.x;
+    model_mat[13] = v.y;
+    model_mat[14] = v.z;
+    model_mat[15] = 1;
+
+    glBindBuffer(GL_UNIFORM_BUFFER, world_matrix_block_buffer);
+    glBufferSubData(GL_UNIFORM_BUFFER, 32 * sizeof f32, sizeof typeof model_mat, ^model_mat);
+    glBindBuffer(GL_UNIFORM_BUFFER, -1);
+}
+
+
+#local {
+    compile_shader :: (source: str, type: GLenum) -> GLint {
+        shader := glCreateShader(type);
+        source_data := source.data;
+        source_len  := source.count;
+        glShaderSource(shader, 1, ^source_data, ^source_len);
+        glCompileShader(shader);
+
+        success: GLint;
+        if glGetShaderiv(shader, GL_COMPILE_STATUS, ^success); success == GL_FALSE {
+            buf_data: [1024] u8;
+            buf := str.{ ~~buf_data, 0 };
+            glGetShaderInfoLog(shader, 1024, ^buf.count, buf.data);
+            println(buf);
+        }
+
+        return shader;
+    }
+
+    link_program :: (vertex_shader, fragment_shader: GLint) -> GLuint {
+        prog := glCreateProgram();
+        glAttachShader(prog, vertex_shader);
+        glAttachShader(prog, fragment_shader);
+        glLinkProgram(prog);
+
+        success: GLint;
+        if glGetProgramiv(prog, GL_LINK_STATUS, ^success); success == GL_FALSE {
+            buf_data: [1024] u8;
+            buf := str.{ ~~buf_data, 0 };
+            glGetProgramInfoLog(prog, 1024, ^buf.count, buf.data);
+            println(buf);
+        }
+
+        return prog;
+    }
+}
+
index bded1157f4f9baf8a9f16800e2e4a43b9edabcdc..e6bf75d1dd8b41b018a0c227c3d504a5dd905841 100644 (file)
@@ -1,3 +1,7 @@
+Vector2 :: struct {
+    x, y: f32;
+}
+
 Vector3i :: struct {
     x, y, z: i32;
 }
diff --git a/src/world.onyx b/src/world.onyx
new file mode 100644 (file)
index 0000000..c740e6d
--- /dev/null
@@ -0,0 +1,36 @@
+
+use package core
+
+World :: struct {
+    chunk_dist: u32;
+    chunks: [] ^Chunk;
+}
+
+world_make :: (allocator := context.allocator) -> ^World {
+    world := new(World, allocator);
+    world.chunk_dist = 3;
+    memory.alloc_slice(^world.chunks, world.chunk_dist * world.chunk_dist * world.chunk_dist);
+
+    for x: 0 .. 3 do for y: 0 .. 3 do for z: 0 .. 3 {
+        chunk := chunk_make(x, y, z);
+
+        for z: 32 do for x: 32 {
+            chunk_set(chunk, x, 0, z, block_make(0.2, 1, 0.2, 0.8));
+        }
+        for z: 32 do for x: 32 {
+            if random.between(0, 10) >= 7 do continue;
+            chunk_set(chunk, x, 1, z, block_make(random.float(0, 1), random.float(0, 1), random.float(0, 1), 1));
+        }
+
+        world.chunks[x * world.chunk_dist * world.chunk_dist + y * world.chunk_dist + z] = chunk;
+    }
+
+    return world;
+}
+
+world_draw :: (use world: ^World) {
+    for chunks {
+        chunk_build_mesh(it);
+        chunk_draw(it);
+    }
+}
\ No newline at end of file