From: Brendan Hansen Date: Wed, 7 Jul 2021 18:09:12 +0000 (-0500) Subject: world transformation matrix X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=963fe52d14fbf31c137c8ecfbb258ef9755e2c91;p=onyx.git world transformation matrix --- diff --git a/core/container/array.onyx b/core/container/array.onyx index 6dad7f08..7ec75b8d 100644 --- a/core/container/array.onyx +++ b/core/container/array.onyx @@ -145,6 +145,15 @@ get :: (arr: ^[..] $T, idx: i32) -> T { return arr.data[idx]; } +get_ptr :: (arr: ^[..] $T, idx: i32) -> ^T { + if arr.count == 0 do return null; + + while idx < 0 do idx += arr.count; + while idx >= arr.count do idx -= arr.count; + + return ^arr.data[idx]; +} + set :: (arr: ^[..] $T, idx: i32, value: T) { if arr.count == 0 do return; diff --git a/modules/immediate_mode/gl_utils.onyx b/modules/immediate_mode/gl_utils.onyx index 9abbcb49..67185ebf 100644 --- a/modules/immediate_mode/gl_utils.onyx +++ b/modules/immediate_mode/gl_utils.onyx @@ -6,6 +6,9 @@ use package core // This Shader represents an OpenGL program, not a shader. The name // is confusing but conceptually for most people, shaders are a bundled // version of the vertex and fragment shader. + +@Todo // Rewrite this so members that start with "uniform_" are automatically detected and the uniform location +// is automatically retrieved. Same thing with vertex attributes. Shader :: struct { program : gl.GLProgram; diff --git a/modules/immediate_mode/immediate_renderer.onyx b/modules/immediate_mode/immediate_renderer.onyx index d31a40e2..8be8a5a6 100644 --- a/modules/immediate_mode/immediate_renderer.onyx +++ b/modules/immediate_mode/immediate_renderer.onyx @@ -24,6 +24,9 @@ Immediate_Vertex :: struct { } Immediate_Renderer :: struct { + // Needs to be a multiple of 6!! + Default_Max_Verticies :: 1020; + active_shader : ^Shader; simple_shader, textured_shader : Shader; @@ -42,15 +45,15 @@ Immediate_Renderer :: struct { vertex_array : gl.GLVertexArrayObject; vertex_buffer : gl.GLBuffer; - // Needs to be a multiple of 6!! - Default_Max_Verticies :: 1020; - mode := Immediate_Mode.Triangles; canvas: ^Canvas = null; window_width, window_height: i32; + world_transform_stack : [..] Transform; + world_transform_dirty := false; // If the world transform matrix should be pushed to the shader uniform. + make :: (max_verticies := Default_Max_Verticies) -> Immediate_Renderer { ir : Immediate_Renderer; __initialize(^ir); @@ -78,7 +81,11 @@ Immediate_Renderer :: struct { vertex_buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); gl.bufferData(gl.ARRAY_BUFFER, cast(gl.GLsizei) (max_verticies * sizeof Immediate_Vertex), gl.STREAM_DRAW); - + + world_transform_stack = array.make(Transform, capacity=1); + array.insert_empty(^world_transform_stack, 0); + transform_identity(array.get_ptr(^world_transform_stack, -1)); + ir->init_shader_params(^simple_shader); ir->init_shader_params(^textured_shader); ir->init_shader_params(^alpha_shader); @@ -111,12 +118,10 @@ Immediate_Renderer :: struct { gl.bindBuffer(gl.ARRAY_BUFFER, -1); - // TEMPORARY - gl.uniformMatrix4(shader.world_uniform, false, - f32.[ 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 ]); + world_transform := array.get_ptr(^world_transform_stack, -1); + world_matrix := transform_to_matrix(world_transform); + + gl.uniformMatrix4(shader.world_uniform, false, world_matrix); } free :: (use ir: ^Immediate_Renderer) { @@ -131,6 +136,17 @@ Immediate_Renderer :: struct { flush :: (use ir: ^Immediate_Renderer) { if vertex_count == 0 do return; + if world_transform_dirty || true { + world_transform_dirty = false; + world_transform := array.get_ptr(^world_transform_stack, -1); + world_matrix := transform_to_matrix(world_transform); + + for shader: (#type ^Shader).[ ^simple_shader, ^textured_shader, ^alpha_shader ] { + gl.useProgram(shader.program); + gl.uniformMatrix4(shader.world_uniform, false, world_matrix); + } + } + gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); gl.bufferSubData(gl.ARRAY_BUFFER, 0, .{ count = vertex_count * sizeof Immediate_Vertex, data = ~~verticies.data }); gl.bindBuffer(gl.ARRAY_BUFFER, -1); @@ -327,6 +343,29 @@ Immediate_Renderer :: struct { ir->use_ortho_projection(0, ~~window_width, 0, ~~window_height); } } + + push_matrix :: (use ir: ^Immediate_Renderer) { + if vertex_count > 0 do flush(ir); + world_transform_dirty = true; + + array.push(^world_transform_stack, world_transform_stack[world_transform_stack.count - 1]); + transform_identity(array.get_ptr(^world_transform_stack, -1)); + } + + pop_matrix :: (use ir: ^Immediate_Renderer) { + if vertex_count > 0 do flush(ir); + world_transform_dirty = true; + + array.pop(^world_transform_stack); + } + + identity :: (use ir: ^Immediate_Renderer) { + transform_identity(array.get_ptr(^world_transform_stack, -1)); + } + + get_transform :: (use ir: ^Immediate_Renderer) -> ^Transform { + return array.get_ptr(^world_transform_stack, -1); + } } @@ -336,40 +375,39 @@ Immediate_Renderer :: struct { // that operate on a global immediate renderer. This is probably the most common way that // it will be used. -#private -immediate_renderer : Immediate_Renderer; +global_renderer : Immediate_Renderer; immediate_renderer_init :: () { - immediate_renderer = Immediate_Renderer.make(); + global_renderer = Immediate_Renderer.make(); } immediate_renderer_free :: () { - Immediate_Renderer.free(^immediate_renderer); + Immediate_Renderer.free(^global_renderer); } vertex :: #match { - (position: Vector2) { immediate_renderer->push_vertex(position); }, - (position: Vector2, color: Color4) { immediate_renderer->push_vertex(position, color); }, + (position: Vector2) { global_renderer->push_vertex(position); }, + (position: Vector2, color: Color4) { global_renderer->push_vertex(position, color); }, } rect :: (position: Vector2, size: Vector2, color: Color4 = .{1,1,1}) { - immediate_renderer->rect(position, size, color); + global_renderer->rect(position, size, color); } textured_rect :: (position: Vector2, size: Vector2, texture_position: Vector2, texture_size: Vector2, color: Color4 = .{1,1,1}) { - immediate_renderer->textured_rect(position, size, texture_position, texture_size, color); + global_renderer->textured_rect(position, size, texture_position, texture_size, color); } circle :: (center: Vector2, radius: f32, color: Color4 = .{1,1,1}, segments := 12) { - immediate_renderer->circle(center, radius, color, segments); + global_renderer->circle(center, radius, color, segments); } -flush :: () do immediate_renderer->flush(); +flush :: () do global_renderer->flush(); set_texture :: #match { - (texture_id: i32 = -1) { immediate_renderer->set_texture(texture_id); }, + (texture_id: i32 = -1) { global_renderer->set_texture(texture_id); }, (texture: ^Texture, texture_index := 0) { - immediate_renderer->set_texture(texture_index); + global_renderer->set_texture(texture_index); if texture_index >= 0 { gl.activeTexture(gl.TEXTURE0 + texture_index); @@ -382,29 +420,33 @@ set_texture :: #match { } use_ortho_projection :: (left: f32, right: f32, top: f32, bottom: f32) { - immediate_renderer->use_ortho_projection(left, right, top, bottom); + global_renderer->use_ortho_projection(left, right, top, bottom); } use_alpha_shader :: (texture_id: i32 = -1) { - immediate_renderer->use_alpha_shader(texture_id); + global_renderer->use_alpha_shader(texture_id); } scissor :: (x: f32, y: f32, w: f32, h: f32) { - immediate_renderer->scissor(x, y, w, h); + global_renderer->scissor(x, y, w, h); } scissor_disable :: () { - immediate_renderer->scissor_disable(); + global_renderer->scissor_disable(); } set_mode :: (mode: Immediate_Mode) { - immediate_renderer->set_mode(mode); + global_renderer->set_mode(mode); } use_canvas :: (canvas: ^Canvas) { - immediate_renderer->use_canvas(canvas); + global_renderer->use_canvas(canvas); } set_window_size :: (width: i32, height: i32) { - immediate_renderer->set_window_size(width, height); + global_renderer->set_window_size(width, height); } + +push_matrix :: () do global_renderer->push_matrix(); +pop_matrix :: () do global_renderer->pop_matrix(); +identity :: () do global_renderer->identity(); diff --git a/modules/immediate_mode/module.onyx b/modules/immediate_mode/module.onyx index 3c72307f..47fae0fa 100644 --- a/modules/immediate_mode/module.onyx +++ b/modules/immediate_mode/module.onyx @@ -5,5 +5,6 @@ package immediate_mode #load "./gl_utils" #load "./canvas" #load "./texture" +#load "./transform" #private gl :: package gl diff --git a/modules/immediate_mode/texture.onyx b/modules/immediate_mode/texture.onyx index 9982e134..c6825be2 100644 --- a/modules/immediate_mode/texture.onyx +++ b/modules/immediate_mode/texture.onyx @@ -28,10 +28,10 @@ create_texture :: (width: i32, height: i32, format: gl.GLenum) -> Texture { }; } -load_texture :: (width: i32, height: i32, data: [] u8, format: gl.GLenum, internal_type := gl.UNSIGNED_BYTE) -> Texture { +load_texture :: (width: i32, height: i32, data: [] u8, format: gl.GLenum, internal_format: gl.GLenum, internal_type := gl.UNSIGNED_BYTE) -> Texture { texture := gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, internal_type, data); + gl.texImage2D(gl.TEXTURE_2D, 0, internal_format, width, height, 0, format, internal_type, data); // Setting some reasonable defaults for the texture parameters gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); diff --git a/modules/immediate_mode/transform.onyx b/modules/immediate_mode/transform.onyx new file mode 100644 index 00000000..28b54ccb --- /dev/null +++ b/modules/immediate_mode/transform.onyx @@ -0,0 +1,34 @@ +package immediate_mode + + +Transform :: struct { + translation: Vector2; + scale: Vector2; + rotation: f32; // In radians +} + +transform_identity :: (use t: ^Transform) { + translation = .{ 0, 0 }; + scale = .{ 1, 1 }; + rotation = 0; +} + +transform_to_matrix :: (use t: ^Transform) -> [16] f32 { + math :: package core.math + + st := math.sin(rotation); + ct := math.cos(rotation); + + sx := scale.x; + sy := scale.y; + + tx := translation.x; + ty := translation.y; + + return f32.[ + sx * ct, -sy * st, 0, 0, + sx * st, sy * ct, 0, 0, + 0, 0, 1, 0, + tx, ty, 0, 1 + ]; +} \ No newline at end of file diff --git a/modules/ui/ui.onyx b/modules/ui/ui.onyx index aef9b0fe..dcb5027a 100644 --- a/modules/ui/ui.onyx +++ b/modules/ui/ui.onyx @@ -285,7 +285,7 @@ get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 { tex_width, tex_height := font.common.scale_width, font.common.scale_height; - font_texture = gfx.load_texture(tex_width, tex_height, texture_data, gl.ALPHA); + font_texture = gfx.load_texture(tex_width, tex_height, texture_data, gl.ALPHA, gl.ALPHA); }