From: Brendan Hansen Date: Mon, 20 Dec 2021 23:58:24 +0000 (-0600) Subject: lots of updates! X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=6b0270602777efb57b2713c9297ae462698c1bee;p=voxel-shooter.git lots of updates! --- diff --git a/lib/stb_truetype.c b/lib/stb_truetype.c index 37ddff8..0ae528a 100644 --- a/lib/stb_truetype.c +++ b/lib/stb_truetype.c @@ -87,4 +87,4 @@ ONYX_LIBRARY { ONYX_FUNC(stbtt_GetPackedQuad) NULL -}; \ No newline at end of file +}; diff --git a/lib/stb_truetype.onyx b/lib/stb_truetype.onyx index a40ffd9..a2be6c4 100644 --- a/lib/stb_truetype.onyx +++ b/lib/stb_truetype.onyx @@ -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 diff --git a/run_tree/assets/shaders/basic_vertex.glsl b/run_tree/assets/shaders/basic_vertex.glsl index 5efc2ec..67d8d32 100644 --- a/run_tree/assets/shaders/basic_vertex.glsl +++ b/run_tree/assets/shaders/basic_vertex.glsl @@ -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 index 0000000..553d9f6 --- /dev/null +++ b/run_tree/assets/shaders/font_fragment.glsl @@ -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 index 0000000..4e58e4b --- /dev/null +++ b/run_tree/assets/shaders/font_vertex.glsl @@ -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); +} + diff --git a/run_tree/assets/shaders/world_vertex.glsl b/run_tree/assets/shaders/world_vertex.glsl index d93598a..8f50ed8 100644 --- a/run_tree/assets/shaders/world_vertex.glsl +++ b/run_tree/assets/shaders/world_vertex.glsl @@ -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, diff --git a/run_tree/lib/onyx_opengles.so b/run_tree/lib/onyx_opengles.so index 71591b0..393e39f 100755 Binary files a/run_tree/lib/onyx_opengles.so and b/run_tree/lib/onyx_opengles.so differ diff --git a/src/build.onyx b/src/build.onyx index f2c978a..310b3d4 100644 --- a/src/build.onyx +++ b/src/build.onyx @@ -13,6 +13,9 @@ #load "mesh" #load "vecmath" #load "chunk" +#load "world" +#load "font" +#load "shader" // Onyx library code #load "stb_truetype" diff --git a/src/camera.onyx b/src/camera.onyx index f0b38fe..070d41b 100644 --- a/src/camera.onyx +++ b/src/camera.onyx @@ -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; +} + diff --git a/src/chunk.onyx b/src/chunk.onyx index f592b24..45c8b1c 100644 --- a/src/chunk.onyx +++ b/src/chunk.onyx @@ -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 index 0000000..6e91de4 --- /dev/null +++ b/src/font.onyx @@ -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; +} + diff --git a/src/main.onyx b/src/main.onyx index b3146b0..e6be5af 100644 --- a/src/main.onyx +++ b/src/main.onyx @@ -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); } diff --git a/src/mesh.onyx b/src/mesh.onyx index feb3b79..42859a9 100644 --- a/src/mesh.onyx +++ b/src/mesh.onyx @@ -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 index 0000000..2b3279d --- /dev/null +++ b/src/shader.onyx @@ -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; + } +} + diff --git a/src/vecmath.onyx b/src/vecmath.onyx index bded115..e6bf75d 100644 --- a/src/vecmath.onyx +++ b/src/vecmath.onyx @@ -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 index 0000000..c740e6d --- /dev/null +++ b/src/world.onyx @@ -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