package main import "base:runtime" import "core:fmt" import "core:log" import glm "core:math/linalg/glsl" import "core:math/rand" import sapp "sokol/app" import sg "sokol/gfx" import sglue "sokol/glue" import slog "sokol/log" MAX_QUADS :: 1_000_000 Quad :: struct #packed { transform: glm.mat4, color: glm.vec3, } ctx: runtime.Context state: struct { pip: sg.Pipeline, bind: sg.Bindings, pass_action: sg.Pass_Action, quads: [MAX_QUADS]Quad, quad_count: uint, proj: glm.mat4, } player_pos: glm.vec2 init :: proc "c" () { ctx = runtime.default_context() context = ctx context.logger = log.create_console_logger() sg.setup({environment = sglue.environment(), logger = {func = slog.func}}) vertices := [?]glm.vec2{{-0.5, 0.5}, {-0.5, -0.5}, {0.5, -0.5}, {0.5, 0.5}} indicies := [?]u16{0, 1, 2, 0, 2, 3} state.bind.vertex_buffers[0] = sg.make_buffer({data = {ptr = &vertices, size = size_of(vertices)}}) state.bind.vertex_buffers[1] = sg.make_buffer({size = MAX_QUADS * size_of(Quad), usage = .STREAM}) state.bind.index_buffer = sg.make_buffer( {type = .INDEXBUFFER, data = {ptr = &indicies, size = size_of(indicies)}}, ) state.pip = sg.make_pipeline( { shader = sg.make_shader(quad_shader_desc(sg.query_backend())), layout = { buffers = {1 = {step_func = .PER_INSTANCE}}, attrs = { ATTR_quad_position = {format = .FLOAT2, buffer_index = 0}, ATTR_quad_inst_mat0 = {format = .FLOAT4, buffer_index = 1}, ATTR_quad_inst_mat1 = {format = .FLOAT4, buffer_index = 1}, ATTR_quad_inst_mat2 = {format = .FLOAT4, buffer_index = 1}, ATTR_quad_inst_mat3 = {format = .FLOAT4, buffer_index = 1}, ATTR_quad_color = {format = .FLOAT3, buffer_index = 1}, }, }, depth = {write_enabled = false}, index_type = .UINT16, }, ) state.pass_action = { colors = {0 = {load_action = .CLEAR, clear_value = {r = 0, g = 0, b = 0, a = 1}}}, } } draw_quad :: proc(pos, size: glm.vec2, rotation := f32(0), color := glm.vec3(1)) { model := glm.mat4Translate({pos.x + size.x / 2, pos.y + size.y / 2, 0}) model *= glm.mat4Rotate({0, 0, 1}, glm.radians(rotation)) model *= glm.mat4Scale({size.x, size.y, 0}) mvp := state.proj * model state.quads[state.quad_count] = { transform = mvp, color = color, } state.quad_count += 1 } flush_quads :: proc() { sg.update_buffer( state.bind.vertex_buffers[1], {ptr = &state.quads, size = size_of(Quad) * state.quad_count}, ) sg.begin_pass({action = state.pass_action, swapchain = sglue.swapchain()}) sg.apply_pipeline(state.pip) sg.apply_bindings(state.bind) sg.draw(0, 6, state.quad_count) sg.end_pass() sg.commit() state.quad_count = 0 } frame :: proc "c" () { context = ctx state.proj = glm.mat4Ortho3d(0, f32(sapp.width()), f32(sapp.height()), 0, -1, 1) draw_quad(player_pos, {50, 100}, 0) flush_quads() } event :: proc "c" (event: ^sapp.Event) { context = ctx #partial switch event.type { case .KEY_DOWN: if event.key_code == .ESCAPE { sapp.quit() } if event.key_code == .W { player_pos.y -= 10 } if event.key_code == .S { player_pos.y += 10 } if event.key_code == .A { player_pos.x -= 10 } if event.key_code == .D { player_pos.x += 10 } } } cleanup :: proc "c" () { context = ctx sg.shutdown() } main :: proc() { sapp.run( { init_cb = init, frame_cb = frame, cleanup_cb = cleanup, event_cb = event, width = 640, height = 480, window_title = "triangle", icon = {sokol_default = true}, logger = {func = slog.func}, }, ) }