Arb_Tri :: struct { pos : [3]Vector3; col : [3]Vector4; uv : [3]Vector2; } Arb_Draw_Command_Type :: enum { INVALID; DRAW_TEXT; FLUSH_TRI; SET_TEXTURE; PREPARE_TEXT; FONT_BOUNDARY; QUAD_OCCLUDER; REMOVE_TEXTURE; SET_SCISSOR; REMOVE_SCISSOR; } Arb_Draw_Command :: struct { type : Arb_Draw_Command_Type = .INVALID; // for triangles tri_offset : int = 0; tri_count : int = 0; texture : *Ui_Texture; // for text layer: s32 = 0; scissor: Ui_Rect; } Arb_Tri_State :: struct { active : bool = false; trilist : [..]Arb_Tri; command_list : [..]Arb_Draw_Command; latest_flush : int = 0; } arbTriState : Arb_Tri_State; init_arb_state :: () { gPipelines.arbtri.bind.images[0] = default_texture.tex; array_reset_keeping_memory(*arbTriState.trilist); array_reset_keeping_memory(*arbTriState.command_list); arbTriState.active = true; arbTriState.latest_flush = 0; } arb_tri_command_add :: (command: Arb_Draw_Command) { if !arbTriState.active { init_arb_state(); } array_add(*arbTriState.command_list, command); } arb_tri_add :: (tri: Arb_Tri) { if !arbTriState.active { init_arb_state(); } array_add(*arbTriState.trilist, tri); } transform_to_screen_x :: (coord: float) -> float { w, h := get_window_size(); return (coord / cast(float) w) * 2.0 - 1.0; } transform_to_screen_y :: (coord: float) -> float { w, h := get_window_size(); return (coord / cast(float) h) * 2.0 - 1.0; } arb_tri_flush :: () { if !arbTriState.active { return; } arbTriState.active = false; for tri, i : arbTriState.trilist { bgn := i * 3 * 9; for 0..2 { gArbtriMem[bgn + it * 9 + 0] = transform_to_screen_x(tri.pos[it].x); gArbtriMem[bgn + it * 9 + 1] = transform_to_screen_y(tri.pos[it].y) * -1.0; gArbtriMem[bgn + it * 9 + 2] = 0; gArbtriMem[bgn + it * 9 + 3] = tri.col[it].x; gArbtriMem[bgn + it * 9 + 4] = tri.col[it].y; gArbtriMem[bgn + it * 9 + 5] = tri.col[it].z; gArbtriMem[bgn + it * 9 + 6] = tri.col[it].w; gArbtriMem[bgn + it * 9 + 7] = tri.uv[it].x; gArbtriMem[bgn + it * 9 + 8] = tri.uv[it].y; } } sg_update_buffer(gPipelines.arbtri.bind.vertex_buffers[0], *(sg_range.{ ptr = gArbtriMem.data, size = size_of(type_of(gArbtriMem)) })); flush_arb_commands(); } debug_arb_flush : bool : false; layer : s32 = 0; flush_arb_commands :: () { sfons_flush(state.fons); // All the text has been drawn, now flush it to the atlas. layer = 0; if debug_arb_flush then print(" --- !BEGIN FLUSH! ---- \n"); for arbTriState.command_list { if debug_arb_flush then print("[command] %\n", it.type); if it.type == { case .SET_TEXTURE; gPipelines.arbtri.bind.images[0] = it.texture.tex; gCurrentTexture = it.texture; case .REMOVE_TEXTURE; gCurrentTexture = null; case .FLUSH_TRI; sg_apply_pipeline(gPipelines.arbtri.pipeline); sg_apply_bindings(*gPipelines.arbtri.bind); sg_draw(xx (it.tri_offset * 3), xx (it.tri_count * 3), 1); case .PREPARE_TEXT; case .SET_SCISSOR; s := it.scissor; w,h := get_window_size(); sgl_viewport(0,0,w,h,true); sg_apply_scissor_rect(s.x, s.y, s.w, s.h, true); case .REMOVE_SCISSOR; w,h := get_window_size(); sg_apply_scissor_rect(0, 0, w, w, true); case .DRAW_TEXT; sgl_draw_layer(it.layer); } } }