Initial pipeline work
This commit is contained in:
+239
-12
@@ -3,9 +3,29 @@ package engine
|
||||
import "core:fmt"
|
||||
import sdl "vendor:sdl3"
|
||||
|
||||
Vertex :: struct {
|
||||
pos: [2]f32, // clip space, -1..1
|
||||
uv: [2]f32, // 0..1 atlas coords (used later in draw_sprite)
|
||||
}
|
||||
|
||||
SPRITE_VERT_COUNT :: 6
|
||||
VERTEX_BUFFER_SIZE :: SPRITE_VERT_COUNT * size_of(Vertex)
|
||||
|
||||
VERT_SPV := #load("../shaders/sprite.vert.spv")
|
||||
FRAG_SPV := #load("../shaders/sprite.frag.spv")
|
||||
|
||||
App :: struct {
|
||||
window: ^sdl.Window,
|
||||
renderer: ^sdl.Renderer,
|
||||
device: ^sdl.GPUDevice,
|
||||
pipeline: ^sdl.GPUGraphicsPipeline,
|
||||
sampler: ^sdl.GPUSampler,
|
||||
cmd: ^sdl.GPUCommandBuffer,
|
||||
render_pass: ^sdl.GPURenderPass,
|
||||
swapchain_texture: ^sdl.GPUTexture,
|
||||
swapchain_w: u32,
|
||||
swapchain_h: u32,
|
||||
vertex_buffer: ^sdl.GPUBuffer,
|
||||
transfer_buffer: ^sdl.GPUTransferBuffer,
|
||||
}
|
||||
|
||||
init :: proc(app: ^App, title: cstring, width, height: i32) -> bool {
|
||||
@@ -14,8 +34,64 @@ init :: proc(app: ^App, title: cstring, width, height: i32) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if !sdl.CreateWindowAndRenderer(title, width, height, {}, &app.window, &app.renderer) {
|
||||
fmt.eprintfln("CreateWindowAndRenderer failed: %s", sdl.GetError())
|
||||
app.window = sdl.CreateWindow(title, width, height, {})
|
||||
|
||||
if app.window == nil {
|
||||
fmt.eprintfln("CreateWindow failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.device = sdl.CreateGPUDevice({.SPIRV}, true, nil)
|
||||
if app.device == nil {
|
||||
fmt.eprintfln("CreateGPUDevice failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
if !sdl.ClaimWindowForGPUDevice(app.device, app.window) {
|
||||
fmt.eprintfln("ClaimWindowForGPUDevice failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.pipeline = create_sprite_pipeline(app.device, app.window)
|
||||
if app.pipeline == nil {
|
||||
fmt.eprintfln("create_sprite_pipeline failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.sampler = sdl.CreateGPUSampler(
|
||||
app.device,
|
||||
{
|
||||
min_filter = .NEAREST,
|
||||
mag_filter = .NEAREST,
|
||||
mipmap_mode = .NEAREST,
|
||||
address_mode_u = .CLAMP_TO_EDGE,
|
||||
address_mode_v = .CLAMP_TO_EDGE,
|
||||
address_mode_w = .CLAMP_TO_EDGE,
|
||||
},
|
||||
)
|
||||
|
||||
if app.sampler == nil {
|
||||
fmt.eprintfln("CreateGPUSampler failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.vertex_buffer = sdl.CreateGPUBuffer(
|
||||
app.device,
|
||||
{usage = {.VERTEX}, size = VERTEX_BUFFER_SIZE},
|
||||
)
|
||||
|
||||
if app.vertex_buffer == nil {
|
||||
fmt.eprintfln("CreateGPUBuffer failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.transfer_buffer = sdl.CreateGPUTransferBuffer(
|
||||
app.device,
|
||||
{usage = .UPLOAD, size = VERTEX_BUFFER_SIZE},
|
||||
)
|
||||
|
||||
if app.transfer_buffer == nil {
|
||||
fmt.eprintfln("CreateGPUTransferBuffer failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -23,14 +99,43 @@ init :: proc(app: ^App, title: cstring, width, height: i32) -> bool {
|
||||
}
|
||||
|
||||
shutdown :: proc(app: ^App) {
|
||||
if app.renderer != nil do sdl.DestroyRenderer(app.renderer)
|
||||
if app.window != nil do sdl.DestroyWindow(app.window)
|
||||
if app.device != nil {
|
||||
ok := sdl.WaitForGPUIdle(app.device)
|
||||
if !ok {
|
||||
fmt.eprintfln("WaitForGPUIdle failed")
|
||||
}
|
||||
|
||||
if app.transfer_buffer != nil {
|
||||
sdl.ReleaseGPUTransferBuffer(app.device, app.transfer_buffer)
|
||||
}
|
||||
|
||||
if app.vertex_buffer != nil {
|
||||
sdl.ReleaseGPUBuffer(app.device, app.vertex_buffer)
|
||||
}
|
||||
|
||||
if app.sampler != nil {
|
||||
sdl.ReleaseGPUSampler(app.device, app.sampler)
|
||||
}
|
||||
|
||||
if app.pipeline != nil {
|
||||
sdl.ReleaseGPUGraphicsPipeline(app.device, app.pipeline)
|
||||
}
|
||||
|
||||
if app.window != nil {
|
||||
sdl.ReleaseWindowFromGPUDevice(app.device, app.window)
|
||||
}
|
||||
sdl.DestroyGPUDevice(app.device)
|
||||
}
|
||||
|
||||
if app.window != nil {
|
||||
sdl.DestroyWindow(app.window)
|
||||
}
|
||||
|
||||
sdl.Quit()
|
||||
app^ = {}
|
||||
}
|
||||
|
||||
pump_events :: proc() -> bool {
|
||||
events :: proc() -> bool {
|
||||
event: sdl.Event
|
||||
|
||||
for sdl.PollEvent(&event) {
|
||||
@@ -42,15 +147,137 @@ pump_events :: proc() -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
begin_frame :: proc(app: ^App, r: u8 = 30, g: u8 = 30, b: u8 = 40, a: u8 = 255) {
|
||||
sdl.SetRenderDrawColor(app.renderer, r, g, b, a)
|
||||
sdl.RenderClear(app.renderer)
|
||||
begin_frame :: proc(app: ^App, clear: sdl.FColor = {0.12, 0.12, 0.16, 1}) {
|
||||
app.cmd = sdl.AcquireGPUCommandBuffer(app.device)
|
||||
|
||||
if app.cmd == nil {
|
||||
fmt.eprintfln("AcquireGPUCommandBuffer failed: %s", sdl.GetError())
|
||||
return
|
||||
}
|
||||
|
||||
ok := sdl.WaitAndAcquireGPUSwapchainTexture(
|
||||
app.cmd,
|
||||
app.window,
|
||||
&app.swapchain_texture,
|
||||
&app.swapchain_w,
|
||||
&app.swapchain_h,
|
||||
)
|
||||
|
||||
if !ok || app.swapchain_texture == nil {
|
||||
return
|
||||
}
|
||||
|
||||
color_info := sdl.GPUColorTargetInfo {
|
||||
texture = app.swapchain_texture,
|
||||
clear_color = clear,
|
||||
load_op = .CLEAR,
|
||||
store_op = .STORE,
|
||||
}
|
||||
|
||||
app.render_pass = sdl.BeginGPURenderPass(app.cmd, &color_info, 1, nil)
|
||||
|
||||
sdl.BindGPUGraphicsPipeline(app.render_pass, app.pipeline)
|
||||
}
|
||||
|
||||
end_frame :: proc(app: ^App) {
|
||||
sdl.RenderPresent(app.renderer)
|
||||
if app.render_pass != nil {
|
||||
sdl.EndGPURenderPass(app.render_pass)
|
||||
app.render_pass = nil
|
||||
}
|
||||
|
||||
if app.cmd != nil {
|
||||
ok := sdl.SubmitGPUCommandBuffer(app.cmd)
|
||||
if !ok {
|
||||
fmt.eprintfln("SubmitGPUCommandBuffer failed")
|
||||
}
|
||||
app.cmd = nil
|
||||
}
|
||||
|
||||
app.swapchain_texture = nil
|
||||
}
|
||||
|
||||
renderer :: proc(app: ^App) -> ^sdl.Renderer {
|
||||
return app.renderer
|
||||
load_spirv_shader :: proc(
|
||||
device: ^sdl.GPUDevice,
|
||||
code: []u8,
|
||||
stage: sdl.GPUShaderStage,
|
||||
num_samplers: u32,
|
||||
) -> ^sdl.GPUShader {
|
||||
return sdl.CreateGPUShader(
|
||||
device,
|
||||
{
|
||||
code_size = len(code),
|
||||
code = raw_data(code),
|
||||
entrypoint = "main",
|
||||
format = {.SPIRV},
|
||||
stage = stage,
|
||||
num_samplers = num_samplers,
|
||||
num_storage_textures = 0,
|
||||
num_storage_buffers = 0,
|
||||
num_uniform_buffers = 0,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
create_sprite_pipeline :: proc(
|
||||
device: ^sdl.GPUDevice,
|
||||
window: ^sdl.Window,
|
||||
) -> ^sdl.GPUGraphicsPipeline {
|
||||
vert := load_spirv_shader(device, VERT_SPV[:], .VERTEX, 0)
|
||||
if vert == nil do return nil
|
||||
|
||||
frag := load_spirv_shader(device, FRAG_SPV[:], .FRAGMENT, 1)
|
||||
if frag == nil {
|
||||
sdl.ReleaseGPUShader(device, vert)
|
||||
return nil
|
||||
}
|
||||
|
||||
swap_format := sdl.GetGPUSwapchainTextureFormat(device, window)
|
||||
|
||||
|
||||
blend := sdl.GPUColorTargetBlendState {
|
||||
src_color_blendfactor = .SRC_ALPHA,
|
||||
dst_color_blendfactor = .ONE_MINUS_SRC_ALPHA,
|
||||
color_blend_op = .ADD,
|
||||
src_alpha_blendfactor = .ONE,
|
||||
dst_alpha_blendfactor = .ONE_MINUS_SRC_ALPHA,
|
||||
alpha_blend_op = .ADD,
|
||||
enable_blend = true,
|
||||
}
|
||||
|
||||
color_target := sdl.GPUColorTargetDescription {
|
||||
format = swap_format,
|
||||
blend_state = blend,
|
||||
}
|
||||
|
||||
vb_desc := sdl.GPUVertexBufferDescription {
|
||||
slot = 0,
|
||||
pitch = u32(size_of(Vertex)),
|
||||
input_rate = .VERTEX,
|
||||
}
|
||||
|
||||
attrs := [2]sdl.GPUVertexAttribute {
|
||||
{location = 0, buffer_slot = 0, format = .FLOAT2, offset = 0},
|
||||
{location = 1, buffer_slot = 0, format = .FLOAT2, offset = u32(offset_of(Vertex, uv))},
|
||||
}
|
||||
|
||||
pipeline_info := sdl.GPUGraphicsPipelineCreateInfo {
|
||||
vertex_shader = vert,
|
||||
fragment_shader = frag,
|
||||
vertex_input_state = {
|
||||
vertex_buffer_descriptions = &vb_desc,
|
||||
num_vertex_buffers = 1,
|
||||
vertex_attributes = raw_data(attrs[:]),
|
||||
num_vertex_attributes = 2,
|
||||
},
|
||||
primitive_type = .TRIANGLELIST,
|
||||
rasterizer_state = {fill_mode = .FILL},
|
||||
target_info = {color_target_descriptions = &color_target, num_color_targets = 1},
|
||||
}
|
||||
|
||||
pipeline := sdl.CreateGPUGraphicsPipeline(device, pipeline_info)
|
||||
|
||||
sdl.ReleaseGPUShader(device, vert)
|
||||
sdl.ReleaseGPUShader(device, frag)
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
+113
-14
@@ -2,6 +2,7 @@ package engine
|
||||
|
||||
import "core:encoding/json"
|
||||
import "core:fmt"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:path/filepath"
|
||||
import "core:strings"
|
||||
@@ -30,16 +31,12 @@ Char_Def :: struct {
|
||||
|
||||
Character_Data :: struct {
|
||||
def: Char_Def,
|
||||
texture: ^sdl.Texture,
|
||||
texture: ^sdl.GPUTexture,
|
||||
width: int,
|
||||
height: int,
|
||||
}
|
||||
|
||||
load_character_data :: proc(
|
||||
renderer: ^sdl.Renderer,
|
||||
character_json_path: string,
|
||||
) -> (
|
||||
Character_Data,
|
||||
bool,
|
||||
) {
|
||||
load_character_data :: proc(app: ^App, character_json_path: string) -> (Character_Data, bool) {
|
||||
file_data, read_err := os.read_entire_file(character_json_path, context.allocator)
|
||||
if read_err != nil {
|
||||
fmt.eprintfln("failed to read %s: %v", character_json_path, read_err)
|
||||
@@ -75,18 +72,120 @@ load_character_data :: proc(
|
||||
}
|
||||
defer sdl.DestroySurface(surface)
|
||||
|
||||
out.texture = sdl.CreateTextureFromSurface(renderer, surface)
|
||||
if out.texture == nil {
|
||||
fmt.eprintfln("CreateTextureFromSurface failed: %s", sdl.GetError())
|
||||
rgba_surface := surface
|
||||
converted_surface: ^sdl.Surface
|
||||
defer {
|
||||
if converted_surface != nil do sdl.DestroySurface(converted_surface)
|
||||
}
|
||||
if surface.format != .ABGR8888 {
|
||||
converted_surface = sdl.ConvertSurface(surface, .ABGR8888)
|
||||
if converted_surface == nil {
|
||||
fmt.eprintfln("ConvertSurface(ABGR8888) failed: %s", sdl.GetError())
|
||||
return {}, false
|
||||
}
|
||||
sdl.SetTextureScaleMode(out.texture, .NEAREST)
|
||||
rgba_surface = converted_surface
|
||||
}
|
||||
|
||||
out.width = int(rgba_surface.w)
|
||||
out.height = int(rgba_surface.h)
|
||||
|
||||
out.texture = sdl.CreateGPUTexture(
|
||||
app.device,
|
||||
{
|
||||
type = .D2,
|
||||
format = .R8G8B8A8_UNORM,
|
||||
usage = {.SAMPLER},
|
||||
width = u32(out.width),
|
||||
height = u32(out.height),
|
||||
layer_count_or_depth = 1,
|
||||
num_levels = 1,
|
||||
sample_count = ._1,
|
||||
},
|
||||
)
|
||||
|
||||
if out.texture == nil {
|
||||
fmt.eprintfln("CreateGPUTexture failed: %s", sdl.GetError())
|
||||
return {}, false
|
||||
}
|
||||
|
||||
upload_size := int(rgba_surface.pitch) * int(rgba_surface.h)
|
||||
tbuf := sdl.CreateGPUTransferBuffer(app.device, {usage = .UPLOAD, size = u32(upload_size)})
|
||||
|
||||
if tbuf == nil {
|
||||
fmt.eprintfln("CreateGPUTransferBuffer failed: %s", sdl.GetError())
|
||||
sdl.ReleaseGPUTexture(app.device, out.texture)
|
||||
return {}, false
|
||||
}
|
||||
|
||||
map_ptr := sdl.MapGPUTransferBuffer(app.device, tbuf, false)
|
||||
|
||||
if map_ptr == nil {
|
||||
fmt.eprintfln("MapGPUTransferBuffer failed: %s", sdl.GetError())
|
||||
sdl.ReleaseGPUTransferBuffer(app.device, tbuf)
|
||||
sdl.ReleaseGPUTexture(app.device, out.texture)
|
||||
return {}, false
|
||||
}
|
||||
|
||||
mem.copy(map_ptr, rgba_surface.pixels, upload_size)
|
||||
sdl.UnmapGPUTransferBuffer(app.device, tbuf)
|
||||
|
||||
cmd := sdl.AcquireGPUCommandBuffer(app.device)
|
||||
if cmd == nil {
|
||||
fmt.eprintfln("AcquireGPUCommandBuffer failed: %s", sdl.GetError())
|
||||
sdl.ReleaseGPUTransferBuffer(app.device, tbuf)
|
||||
sdl.ReleaseGPUTexture(app.device, out.texture)
|
||||
return {}, false
|
||||
}
|
||||
|
||||
copy_pass := sdl.BeginGPUCopyPass(cmd)
|
||||
|
||||
transfer := sdl.GPUTextureTransferInfo {
|
||||
transfer_buffer = tbuf,
|
||||
offset = 0,
|
||||
pixels_per_row = u32(rgba_surface.pitch / 4), // RGBA8888 => 4 bytes/pixel
|
||||
rows_per_layer = u32(rgba_surface.h),
|
||||
}
|
||||
region := sdl.GPUTextureRegion {
|
||||
texture = out.texture,
|
||||
mip_level = 0,
|
||||
layer = 0,
|
||||
x = 0,
|
||||
y = 0,
|
||||
z = 0,
|
||||
w = u32(rgba_surface.w),
|
||||
h = u32(rgba_surface.h),
|
||||
d = 1,
|
||||
}
|
||||
sdl.UploadToGPUTexture(copy_pass, transfer, region, false)
|
||||
sdl.EndGPUCopyPass(copy_pass)
|
||||
fence := sdl.SubmitGPUCommandBufferAndAcquireFence(cmd)
|
||||
if fence == nil {
|
||||
fmt.eprintfln("SubmitGPUCommandBufferAndAcquireFence (texture upload) failed: %s", sdl.GetError())
|
||||
sdl.ReleaseGPUTransferBuffer(app.device, tbuf)
|
||||
sdl.ReleaseGPUTexture(app.device, out.texture)
|
||||
return {}, false
|
||||
}
|
||||
defer sdl.ReleaseGPUFence(app.device, fence)
|
||||
|
||||
if !sdl.WaitForGPUFences(app.device, true, &fence, 1) {
|
||||
fmt.eprintfln("WaitForGPUFences (texture upload) failed: %s", sdl.GetError())
|
||||
sdl.ReleaseGPUTransferBuffer(app.device, tbuf)
|
||||
sdl.ReleaseGPUTexture(app.device, out.texture)
|
||||
return {}, false
|
||||
}
|
||||
|
||||
sdl.ReleaseGPUTransferBuffer(app.device, tbuf)
|
||||
|
||||
return out, true
|
||||
}
|
||||
|
||||
destroy_character_data :: proc(data: ^Character_Data) {
|
||||
destroy_character_data :: proc(app: ^App, data: ^Character_Data) {
|
||||
if data.texture != nil {
|
||||
sdl.DestroyTexture(data.texture)
|
||||
// Ensure no in-flight draw command is still sampling this texture.
|
||||
if app != nil && app.device != nil {
|
||||
_ = sdl.WaitForGPUIdle(app.device)
|
||||
}
|
||||
sdl.ReleaseGPUTexture(app.device, data.texture)
|
||||
}
|
||||
data^ = {}
|
||||
}
|
||||
|
||||
+95
-15
@@ -1,5 +1,6 @@
|
||||
package engine
|
||||
|
||||
import "core:mem"
|
||||
import sdl "vendor:sdl3"
|
||||
|
||||
Vec2 :: [2]f32
|
||||
@@ -26,26 +27,105 @@ update_sprite :: proc(sprite: ^Sprite, dt: f32) {
|
||||
_ = dt
|
||||
}
|
||||
|
||||
draw_sprite :: proc(renderer: ^sdl.Renderer, sprite: ^Sprite) {
|
||||
assert(sprite.data != nil)
|
||||
to_clip :: proc(px, py, sw, sh: f32) -> [2]f32 {
|
||||
return {
|
||||
px / sw * 2 - 1,
|
||||
1 - py / sh * 2, // flip y (window pixels are y-down)
|
||||
}
|
||||
}
|
||||
|
||||
draw_sprite :: proc(app: ^App, sprite: ^Sprite) {
|
||||
if app.render_pass == nil || app.cmd == nil || app.swapchain_texture == nil {
|
||||
return // begin_frame may have skipped (minimized window, etc.)
|
||||
}
|
||||
if sprite == nil || sprite.data == nil || sprite.data.texture == nil {
|
||||
return
|
||||
}
|
||||
|
||||
rect, ok := character_frame_rect(sprite.data, sprite.clip, sprite.frame)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
w := f32(rect[2])
|
||||
h := f32(rect[3])
|
||||
dst := sdl.FRect {
|
||||
x = sprite.position.x - w * 0.5,
|
||||
y = sprite.position.y - h,
|
||||
w = w,
|
||||
h = h,
|
||||
fw := f32(rect[2])
|
||||
fh := f32(rect[3])
|
||||
|
||||
// Feet-centered placement, same as renderer version
|
||||
x0_px := sprite.position.x - fw * 0.5
|
||||
y0_px := sprite.position.y - fh
|
||||
x1_px := x0_px + fw
|
||||
y1_px := y0_px + fh
|
||||
|
||||
sw := f32(app.swapchain_w)
|
||||
sh := f32(app.swapchain_h)
|
||||
p0 := to_clip(x0_px, y0_px, sw, sh) // top-left
|
||||
p1 := to_clip(x1_px, y0_px, sw, sh) // top-right
|
||||
p2 := to_clip(x1_px, y1_px, sw, sh) // bottom-right
|
||||
p3 := to_clip(x0_px, y1_px, sw, sh) // bottom-left
|
||||
|
||||
tex_w := f32(sprite.data.width)
|
||||
tex_h := f32(sprite.data.height)
|
||||
u0 := f32(rect[0]) / tex_w
|
||||
v0 := f32(rect[1]) / tex_h
|
||||
u1 := f32(rect[0] + rect[2]) / tex_w
|
||||
v1 := f32(rect[1] + rect[3]) / tex_h
|
||||
|
||||
// Two triangles: (0,1,2) and (0,2,3)
|
||||
verts := [6]Vertex {
|
||||
{pos = p0, uv = {u0, v0}},
|
||||
{pos = p1, uv = {u1, v0}},
|
||||
{pos = p2, uv = {u1, v1}},
|
||||
{pos = p0, uv = {u0, v0}},
|
||||
{pos = p2, uv = {u1, v1}},
|
||||
{pos = p3, uv = {u0, v1}},
|
||||
}
|
||||
src := sdl.FRect {
|
||||
x = f32(rect[0]),
|
||||
y = f32(rect[1]),
|
||||
w = w,
|
||||
h = h,
|
||||
|
||||
map_ptr := sdl.MapGPUTransferBuffer(app.device, app.transfer_buffer, false)
|
||||
if map_ptr == nil {
|
||||
return
|
||||
}
|
||||
sdl.RenderTexture(renderer, sprite.data.texture, &src, &dst)
|
||||
mem.copy(map_ptr, raw_data(verts[:]), size_of(verts))
|
||||
sdl.UnmapGPUTransferBuffer(app.device, app.transfer_buffer)
|
||||
|
||||
// IMPORTANT: SDL does not allow beginning a copy pass while a render pass
|
||||
// is active on the same command buffer. Upload on a separate command buffer.
|
||||
copy_cmd := sdl.AcquireGPUCommandBuffer(app.device)
|
||||
if copy_cmd == nil {
|
||||
return
|
||||
}
|
||||
copy_pass := sdl.BeginGPUCopyPass(copy_cmd)
|
||||
|
||||
src := sdl.GPUTransferBufferLocation {
|
||||
transfer_buffer = app.transfer_buffer,
|
||||
offset = 0,
|
||||
}
|
||||
dst := sdl.GPUBufferRegion {
|
||||
buffer = app.vertex_buffer,
|
||||
offset = 0,
|
||||
size = u32(size_of(verts)),
|
||||
}
|
||||
sdl.UploadToGPUBuffer(copy_pass, src, dst, false)
|
||||
sdl.EndGPUCopyPass(copy_pass)
|
||||
fence := sdl.SubmitGPUCommandBufferAndAcquireFence(copy_cmd)
|
||||
if fence == nil {
|
||||
return
|
||||
}
|
||||
defer sdl.ReleaseGPUFence(app.device, fence)
|
||||
if !sdl.WaitForGPUFences(app.device, true, &fence, 1) {
|
||||
return
|
||||
}
|
||||
|
||||
sampler_binding := sdl.GPUTextureSamplerBinding {
|
||||
texture = sprite.data.texture,
|
||||
sampler = app.sampler,
|
||||
}
|
||||
sdl.BindGPUFragmentSamplers(app.render_pass, 0, &sampler_binding, 1)
|
||||
|
||||
vb_binding := sdl.GPUBufferBinding {
|
||||
buffer = app.vertex_buffer,
|
||||
offset = 0,
|
||||
}
|
||||
sdl.BindGPUVertexBuffers(app.render_pass, 0, &vb_binding, 1)
|
||||
|
||||
sdl.DrawGPUPrimitives(app.render_pass, 6, 1, 0, 0)
|
||||
}
|
||||
|
||||
+7
-13
@@ -4,25 +4,19 @@ import eng "pkg:engine"
|
||||
|
||||
main :: proc() {
|
||||
app: eng.App
|
||||
if !eng.init(&app, "toad example", 800, 600) {
|
||||
return
|
||||
}
|
||||
if !eng.init(&app, "toad", 800, 600) do return
|
||||
defer eng.shutdown(&app)
|
||||
|
||||
data, ok := eng.load_character_data(
|
||||
app.renderer,
|
||||
"assets_baked/characters/toad/toad.char.json",
|
||||
)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
defer eng.destroy_character_data(&data)
|
||||
data, ok := eng.load_character_data(&app, "assets_baked/characters/toad/toad.char.json")
|
||||
if !ok do return
|
||||
|
||||
defer eng.destroy_character_data(&app, &data)
|
||||
|
||||
toad := eng.spawn_sprite(&data, {400, 500}, "idle", 0)
|
||||
|
||||
for eng.pump_events() {
|
||||
for eng.events() {
|
||||
eng.begin_frame(&app)
|
||||
eng.draw_sprite(app.renderer, &toad)
|
||||
eng.draw_sprite(&app, &toad)
|
||||
eng.end_frame(&app)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 2, binding = 0) uniform sampler2D u_tex; // SDL_GPU fragment sampler slot 0
|
||||
|
||||
layout(location = 0) in vec2 v_uv;
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
void main() {
|
||||
out_color = texture(u_tex, v_uv);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 in_pos;
|
||||
layout(location = 1) in vec2 in_uv;
|
||||
|
||||
layout(location = 0) out vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
v_uv = in_uv;
|
||||
gl_Position = vec4(in_pos, 0.0, 1.0);
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user