323 lines
8.7 KiB
Odin
323 lines
8.7 KiB
Odin
package ecs
|
|
|
|
import "base:runtime"
|
|
import "base:intrinsics"
|
|
|
|
import "core:log"
|
|
import "core:mem"
|
|
import "core:time"
|
|
import "core:fmt"
|
|
import "core:testing"
|
|
import "core:strings"
|
|
import "core:path/filepath"
|
|
import "core:math"
|
|
import "core:math/linalg"
|
|
import "core:os"
|
|
|
|
import stbi "vendor:stb/image"
|
|
|
|
import sa "../sokol/app"
|
|
import sh "../sokol/helpers"
|
|
import sg "../sokol/gfx"
|
|
|
|
import program_config "../config"
|
|
|
|
import shaders "../shaders/out"
|
|
|
|
VertexData :: struct {
|
|
x, y, z: f32,
|
|
}
|
|
|
|
Mesh :: struct {
|
|
vertex_buffer: sg.Buffer,
|
|
index_buffer: sg.Buffer,
|
|
}
|
|
|
|
Material :: struct {
|
|
pipeline: sg.Pipeline,
|
|
shader: sg.Shader,
|
|
}
|
|
|
|
RenderSystem :: struct {
|
|
using _: SystemBase,
|
|
user_entity: EntityID,
|
|
|
|
materials: map[MaterialID]Material,
|
|
meshes : map[MeshID]Mesh,
|
|
}
|
|
|
|
@(private="file")
|
|
init_outline_material :: proc(render_system: ^RenderSystem) {
|
|
shader := sg.make_shader(shaders.outline_shader_desc(sg.query_backend()))
|
|
pipeline := sg.make_pipeline({
|
|
shader = shader,
|
|
layout = {
|
|
attrs = {
|
|
shaders.ATTR_outline_pos = { format = .FLOAT3 },
|
|
},
|
|
},
|
|
index_type = .UINT16,
|
|
cull_mode = .FRONT,
|
|
depth = {
|
|
pixel_format = .DEFAULT,
|
|
write_enabled = true,
|
|
bias = 0.001,
|
|
bias_clamp = 0.0,
|
|
bias_slope_scale = 1.0,
|
|
compare = .LESS_EQUAL,
|
|
},
|
|
sample_count = 4,
|
|
})
|
|
|
|
render_system.materials[.Outline] = Material{
|
|
shader = shader,
|
|
pipeline = pipeline,
|
|
}
|
|
}
|
|
|
|
@(private="file")
|
|
init_cube_material :: proc(render_system: ^RenderSystem) {
|
|
shader := sg.make_shader(shaders.cube_shader_desc(sg.query_backend()))
|
|
pipeline := sg.make_pipeline({
|
|
shader = shader,
|
|
layout = {
|
|
attrs = {
|
|
shaders.ATTR_cube_pos = { format = .FLOAT3 },
|
|
},
|
|
},
|
|
index_type = .UINT16,
|
|
cull_mode = .BACK,
|
|
depth = {
|
|
pixel_format = .DEFAULT,
|
|
write_enabled = true,
|
|
bias = 0.001,
|
|
bias_clamp = 0.0,
|
|
bias_slope_scale = 1.0,
|
|
compare = .LESS_EQUAL,
|
|
},
|
|
sample_count = 4,
|
|
})
|
|
|
|
render_system.materials[.Cube] = Material{
|
|
shader = shader,
|
|
pipeline = pipeline,
|
|
}
|
|
}
|
|
|
|
@(private="file")
|
|
init_cube_mesh :: proc (render_system: ^RenderSystem) {
|
|
cube_vertices := []VertexData {
|
|
{ -0.5, -0.5, 0.5 },
|
|
{ 0.5, -0.5, 0.5 },
|
|
{ 0.5, 0.5, 0.5 },
|
|
{ -0.5, 0.5, 0.5 },
|
|
|
|
{ -0.5, -0.5, -0.5 },
|
|
{ 0.5, -0.5, -0.5 },
|
|
{ 0.5, 0.5, -0.5 },
|
|
{ -0.5, 0.5, -0.5 },
|
|
|
|
{ -0.5, 0.5, 0.5 },
|
|
{ 0.5, 0.5, 0.5 },
|
|
{ 0.5, 0.5, -0.5 },
|
|
{ -0.5, 0.5, -0.5 },
|
|
|
|
{ -0.5, -0.5, 0.5 },
|
|
{ 0.5, -0.5, 0.5 },
|
|
{ 0.5, -0.5, -0.5 },
|
|
{ -0.5, -0.5, -0.5 },
|
|
|
|
{ 0.5, -0.5, 0.5 },
|
|
{ 0.5, -0.5, -0.5 },
|
|
{ 0.5, 0.5, -0.5 },
|
|
{ 0.5, 0.5, 0.5 },
|
|
|
|
{ -0.5, -0.5, 0.5 },
|
|
{ -0.5, -0.5, -0.5 },
|
|
{ -0.5, 0.5, -0.5 },
|
|
{ -0.5, 0.5, 0.5 },
|
|
}
|
|
vertex_buffer := sg.make_buffer({
|
|
data = sg_range(cube_vertices)
|
|
})
|
|
|
|
cube_indices := []u16 {
|
|
0, 1, 2, 0, 2, 3,
|
|
6, 5, 4, 7, 6, 4,
|
|
8, 9, 10, 8, 10, 11,
|
|
14, 13, 12, 15, 14, 12,
|
|
16, 17, 18, 16, 18, 19,
|
|
22, 21, 20, 23, 22, 20,
|
|
}
|
|
|
|
index_buffer := sg.make_buffer({
|
|
usage = { index_buffer = true },
|
|
data = sg_range(cube_indices),
|
|
})
|
|
|
|
render_system.meshes[.Cube] = Mesh{
|
|
vertex_buffer = vertex_buffer,
|
|
index_buffer = index_buffer,
|
|
}
|
|
}
|
|
|
|
render_system_init :: proc(render_system: ^RenderSystem, user_entity: EntityID) {
|
|
default_context := runtime.default_context()
|
|
|
|
sg.setup({
|
|
environment = sh.glue_environment(),
|
|
allocator = sg.Allocator(sh.allocator(&default_context)),
|
|
logger = sg.Logger(sh.logger(&default_context)),
|
|
})
|
|
|
|
render_system.materials = make(map[MaterialID]Material)
|
|
render_system.meshes = make(map[MeshID]Mesh)
|
|
render_system.user_entity = user_entity
|
|
|
|
init_cube_mesh(render_system)
|
|
init_cube_material(render_system)
|
|
|
|
init_outline_material(render_system)
|
|
}
|
|
|
|
render_system_delete :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator) {
|
|
cube_mesh := render_system.meshes[.Cube]
|
|
sg.destroy_buffer(cube_mesh.index_buffer)
|
|
sg.destroy_buffer(cube_mesh.vertex_buffer)
|
|
|
|
cube_material := render_system.materials[.Cube]
|
|
sg.destroy_pipeline(cube_material.pipeline)
|
|
sg.destroy_shader(cube_material.shader)
|
|
|
|
outline_material := render_system.materials[.Outline]
|
|
sg.destroy_pipeline(outline_material.pipeline)
|
|
sg.destroy_shader(outline_material.shader)
|
|
|
|
delete(render_system.materials)
|
|
delete(render_system.meshes)
|
|
|
|
sg.shutdown()
|
|
}
|
|
|
|
@(private="file")
|
|
CLEAR_SCREEN_ACTION :: sg.Pass_Action{
|
|
colors = {
|
|
0 = {
|
|
load_action = .CLEAR,
|
|
clear_value = program_config.BACKGROUND_COLOR,
|
|
}
|
|
}
|
|
}
|
|
|
|
@(private="file")
|
|
outline_pass :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, proj: Mat4, view: Mat4) {
|
|
for entity_id in render_system.entities {
|
|
transform := coordinator_get_component(coordinator, TransformComponent, entity_id)
|
|
mesh_id := coordinator_get_component(coordinator, MeshComponent, entity_id).mesh_id
|
|
mesh := render_system.meshes[mesh_id]
|
|
|
|
scale_mat := linalg.matrix4_scale_f32(transform.scale * 1.2)
|
|
rot_mat := linalg.matrix4_from_yaw_pitch_roll_f32(
|
|
transform.rotation.y,
|
|
transform.rotation.x,
|
|
transform.rotation.z
|
|
)
|
|
pos_mat := linalg.matrix4_translate_f32(transform.position)
|
|
model := pos_mat * rot_mat * scale_mat
|
|
mvp := proj * view * model
|
|
|
|
outline_material := render_system.materials[.Outline]
|
|
sg.apply_pipeline(outline_material.pipeline)
|
|
|
|
sg.apply_bindings({
|
|
vertex_buffers = { 0 = mesh.vertex_buffer },
|
|
index_buffer = mesh.index_buffer,
|
|
})
|
|
|
|
sg.apply_uniforms(shaders.UB_VsParamsOutline, sg_range(&shaders.Vsparamsoutline{
|
|
mvp = mvp,
|
|
}))
|
|
|
|
sg.apply_uniforms(shaders.UB_FsParamsOutline, sg_range(&shaders.Fsparamsoutline{
|
|
col = program_config.BORDER_COLOR,
|
|
}))
|
|
|
|
|
|
sg.draw(0, 36, 1)
|
|
}
|
|
}
|
|
|
|
|
|
@(private="file")
|
|
cube_pass :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator, proj: Mat4, view: Mat4) {
|
|
for entity_id in render_system.entities {
|
|
transform := coordinator_get_component(coordinator, TransformComponent, entity_id)
|
|
|
|
mesh_id := coordinator_get_component(coordinator, MeshComponent, entity_id).mesh_id
|
|
mesh := render_system.meshes[mesh_id]
|
|
|
|
material_id := coordinator_get_component(coordinator, MaterialComponent, entity_id).material_id
|
|
material := render_system.materials[material_id]
|
|
|
|
color := coordinator_get_component(coordinator, ColorComponent, entity_id)
|
|
|
|
scale_mat := linalg.matrix4_scale_f32(transform.scale)
|
|
rot_mat := linalg.matrix4_from_yaw_pitch_roll_f32(
|
|
transform.rotation.y,
|
|
transform.rotation.x,
|
|
transform.rotation.z
|
|
)
|
|
pos_mat := linalg.matrix4_translate_f32(transform.position)
|
|
model := pos_mat * rot_mat * scale_mat
|
|
mvp := proj * view * model
|
|
|
|
sg.apply_pipeline(material.pipeline)
|
|
sg.apply_bindings({
|
|
vertex_buffers = { 0 = mesh.vertex_buffer },
|
|
index_buffer = mesh.index_buffer,
|
|
})
|
|
|
|
sg.apply_uniforms(shaders.UB_VsParamsCube, sg_range(&shaders.Vsparamscube{
|
|
mvp = mvp,
|
|
col = color.color,
|
|
}))
|
|
|
|
sg.draw(0, 36, 1)
|
|
}
|
|
}
|
|
|
|
render_system_update :: proc(render_system: ^RenderSystem, coordinator: ^Coordinator) {
|
|
camera := coordinator_get_component(coordinator, CameraComponent, render_system.user_entity)
|
|
|
|
proj := linalg.matrix4_perspective_f32(70, sa.widthf() / sa.heightf(), 0.001, 1000)
|
|
view := linalg.matrix4_look_at_f32(camera.position, camera.target, { 0, 1, 0 } )
|
|
|
|
sg.begin_pass({ swapchain = sh.glue_swapchain(), action = CLEAR_SCREEN_ACTION })
|
|
outline_pass(render_system, coordinator, proj, view)
|
|
cube_pass(render_system, coordinator, proj, view)
|
|
sg.end_pass()
|
|
|
|
sg.commit()
|
|
}
|
|
|
|
@(private="file")
|
|
sg_range :: proc {
|
|
sg_range_from_slice,
|
|
sg_range_from_struct,
|
|
}
|
|
|
|
@(private="file")
|
|
sg_range_from_slice :: proc(s: []$T) -> sg.Range {
|
|
return {
|
|
ptr = raw_data(s),
|
|
size = len(s) * size_of(T),
|
|
}
|
|
}
|
|
|
|
@(private="file")
|
|
sg_range_from_struct :: proc(s: ^$T) -> sg.Range where intrinsics.type_is_struct(T) {
|
|
return {
|
|
ptr = s,
|
|
size = size_of(T),
|
|
}
|
|
}
|