ONYX_FUNC(stbtt_GetPackedQuad)
NULL
-};
\ No newline at end of file
+};
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
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;
--- /dev/null
+#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);
+}
--- /dev/null
+#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);
+}
+
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;
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,
#load "mesh"
#load "vecmath"
#load "chunk"
+#load "world"
+#load "font"
+#load "shader"
// Onyx library code
#load "stb_truetype"
window_width, window_height: f32;
z_near := 0.01f;
- z_far := 100.0f;
+ z_far := 300.0f;
x_rot, y_rot: f32;
position: Vector3;
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;
+}
+
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;
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;
}
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 {
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 {
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) {
--- /dev/null
+
+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;
+}
+
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);
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) {
}
}
-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);
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) {
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);
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);
}
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;
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;
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);
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);
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
--- /dev/null
+
+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;
+ }
+}
+
+Vector2 :: struct {
+ x, y: f32;
+}
+
Vector3i :: struct {
x, y, z: i32;
}
--- /dev/null
+
+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