Level hot reload working

This commit is contained in:
sergeypdev 2025-07-13 23:09:32 +04:00
parent bb6498a193
commit 8b8e4f9513
26 changed files with 3207 additions and 2702 deletions

Binary file not shown.

BIN
assets/blender/test_level_blend/Plane.glb (Stored with Git LFS)

Binary file not shown.

View File

@ -1,45 +1,45 @@
(inst
:model "assets/blender/testblend_blend/Bakery.glb"
:pos (0.000000 0.000000 12.000000)
:pos (1.000000 0.000000 -13.000000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000))
(inst
:model "assets/blender/test_level_blend/Plane.glb"
:pos (0.000000 -1.000000 0.000000)
:pos (0.000000 -1.000000 -0.000000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (22.469545 22.469545 22.469545))
(inst
:model "assets/blender/testblend_blend/Fire_Station.glb"
:pos (9.000000 0.000000 13.000000)
:pos (10.500000 0.000000 -22.500000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000))
(inst
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb"
:pos (-8.000000 0.000000 11.000000)
:pos (-7.000000 0.000000 -12.000000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000))
(inst
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb"
:pos (-16.000000 0.000000 11.000000)
:pos (-16.000000 0.000000 -11.000000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000))
(inst
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb"
:pos (-15.559284 1.609015 0.259853)
:pos (-20.000000 -1.000000 -1.000000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000))
(inst
:model "assets/blender/testblend_blend/Green_House.glb"
:pos (14.000000 0.000000 -7.000000)
:pos (14.000000 0.000000 7.000000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000))
(inst
:model "assets/blender/testblend_blend/Hotel.glb"
:pos (8.000000 0.000000 -18.000000)
:pos (8.000000 0.000000 18.000000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000))
(inst
:model "assets/blender/test_level_blend/NurbsPath.glb"
:pos (0.000000 1.000000 0.000000)
:pos (-4.000000 0.000000 12.000000)
:rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000))

BIN
assets/blender/testblend_blend/Bakery.glb (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/blender/testblend_blend/Hotel.glb (Stored with Git LFS)

Binary file not shown.

View File

@ -1,6 +1,7 @@
import bpy
import os
import pathlib
import contextlib
# Ensure blend file is saved
blend_filepath = bpy.data.filepath
@ -9,6 +10,26 @@ if not blend_filepath:
assert bpy.context.scene is not None
@contextlib.contextmanager
def temp_scene(name: str):
original_scene = bpy.context.scene
assert original_scene is not None
temp_scene = bpy.data.scenes.new(name)
assert bpy.context.window is not None
try:
bpy.context.window.scene = temp_scene
yield temp_scene
finally:
assert bpy.context.window is not None
bpy.context.window.scene = original_scene
print(f'removing scene {temp_scene}')
bpy.data.scenes.remove(temp_scene)
scene = bpy.context.scene
export_scene = bpy.data.scenes.new('__export')
def clean_blend_path(blend_path: str) -> str:
return os.path.join(os.path.dirname(blend_path), bpy.path.clean_name(os.path.basename(blend_path)))
@ -39,13 +60,18 @@ def export_object_as_glb(obj: bpy.types.Object, export_path: str):
full_export_path = os.path.join(assets_path, export_path)
pathlib.Path(os.path.dirname(full_export_path)).mkdir(parents=True, exist_ok=True)
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
if obj.instance_type == 'COLLECTION' and obj.instance_collection:
with temp_scene('__export') as scn:
scn.collection.children.link(obj.instance_collection)
bpy.ops.export_scene.gltf(filepath=full_export_path, use_active_scene=True, export_apply=True)
else:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
assert bpy.context.view_layer is not None
bpy.context.view_layer.objects.active = obj
assert bpy.context.view_layer is not None
bpy.context.view_layer.objects.active = obj
bpy.ops.export_scene.gltf(filepath=full_export_path, use_selection=True, export_apply=True)
bpy.ops.export_scene.gltf(filepath=full_export_path, use_selection=True, export_apply=True)
print(f"Exported {obj.name} -> {export_path}")
# Collect all visible, non-hidden objects in the scene
@ -70,7 +96,7 @@ for obj in visible_objects:
instance_sexpr = (
'(inst'
f'\n\t:model "assets/{model_path}"'
f'\n\t:pos ({loc.x:.6f} {loc.z:.6f} {loc.y:.6f})'
f'\n\t:pos ({loc.x:.6f} {loc.z:.6f} {-loc.y:.6f})'
f'\n\t:rot ({rot.x:.6f} {rot.y:.6f} {rot.z:.6f} {rot.w:.6f})'
f'\n\t:scale ({scale.x:.6f} {scale.y:.6f} {scale.z:.6f}))'
)

View File

@ -5,6 +5,7 @@ package name
import "core:mem"
import "core:strings"
import "core:sync"
import "libs:tracy"
// When enabled name globals will be initialized automatically
NAME_STATIC_INIT :: #config(NAME_STATIC_INIT, true)
@ -61,23 +62,36 @@ when NAME_STATIC_INIT {
}
from_string :: proc(str: string) -> Name {
sync.atomic_rw_mutex_guard(&global_container.lock)
existing, ok := global_container.names_lookup[str]
tracy.Zone()
existing: Name
ok: bool
{
sync.atomic_rw_mutex_shared_guard(&global_container.lock)
existing, ok = global_container.names_lookup[str]
}
if ok {
return existing
} else {
new_str := strings.clone(
sync.atomic_rw_mutex_guard(&global_container.lock)
new_str := strings.clone_to_cstring(
str,
mem.dynamic_arena_allocator(&global_container.names_allocator),
)
idx := u32(len(global_container.names_array))
append(&global_container.names_array, new_str)
append(&global_container.names_array, string(new_str))
global_container.names_lookup[str] = Name(idx)
return Name(idx)
}
}
from_cstring :: proc(str: cstring) -> Name {
return from_string(string(str))
}
to_string :: proc(name: Name) -> string {
tracy.Zone()
sync.atomic_rw_mutex_shared_guard(&global_container.lock)
return global_container.names_array[name]
}

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,13 @@ import "core:bytes"
import "core:encoding/csv"
import "core:io"
import "core:log"
import lg "core:math/linalg"
import "core:strconv"
import "game:debug"
import "game:halfedge"
import "game:physics/collision"
import rl "libs:raylib"
import rlgl "libs:raylib/rlgl"
CSV_Parse_Error :: enum {
Ok,
@ -69,7 +75,7 @@ parse_csv_2d :: proc(
data: []byte,
allocator := context.allocator,
) -> (
curve: Loaded_Curve_2D,
curve: Curve_2D,
error: CSV_Parse_Error,
) {
bytes_reader: bytes.Reader
@ -125,8 +131,400 @@ parse_csv_2d :: proc(
append(&tmp_result, [2]f32{f32(key), f32(val)})
}
curve.points = make([][2]f32, len(tmp_result), allocator)
copy(curve.points, tmp_result[:])
curve = make([][2]f32, len(tmp_result), allocator)
copy(curve, tmp_result[:])
return
}
parse_convex :: proc(bytes: []byte, allocator := context.allocator) -> (Loaded_Convex, bool) {
Parse_Ctx :: struct {
bytes: []byte,
it: int,
line: int,
}
advance :: proc(ctx: ^Parse_Ctx, by: int = 1) -> bool {
ctx.it = min(ctx.it + by, len(ctx.bytes) + 1)
return ctx.it < len(ctx.bytes)
}
is_whitespace :: proc(b: byte) -> bool {
return b == ' ' || b == '\t' || b == '\r' || b == '\n'
}
skip_line :: proc(ctx: ^Parse_Ctx) {
for ctx.it < len(ctx.bytes) && ctx.bytes[ctx.it] != '\n' {
advance(ctx) or_break
}
advance(ctx)
ctx.line += 1
}
skip_whitespase :: proc(ctx: ^Parse_Ctx) {
switch ctx.bytes[ctx.it] {
case ' ', '\t', '\r', '\n':
if ctx.bytes[ctx.it] == '\n' {
ctx.line += 1
}
advance(ctx) or_break
case '#':
skip_line(ctx)
}
}
Edge :: [2]u16
edges_map := make_map(map[Edge]halfedge.Edge_Index, context.temp_allocator)
edges := make_dynamic_array([dynamic]halfedge.Half_Edge, context.temp_allocator)
vertices := make_dynamic_array([dynamic]halfedge.Vertex, context.temp_allocator)
faces := make_dynamic_array([dynamic]halfedge.Face, context.temp_allocator)
min_pos, max_pos: rl.Vector3 = max(f32), min(f32)
// Parse obj file directly into halfedge data structure
{
ctx := Parse_Ctx {
bytes = bytes,
line = 1,
}
for ctx.it < len(ctx.bytes) {
skip_whitespase(&ctx)
switch ctx.bytes[ctx.it] {
case 'v':
// vertex
advance(&ctx) or_break
vertex: rl.Vector3
coord_idx := 0
for ctx.bytes[ctx.it] != '\n' && ctx.bytes[ctx.it] != '\r' {
skip_whitespase(&ctx)
s := string(ctx.bytes[ctx.it:])
coord_val, nr, ok := strconv.parse_f32_prefix(s)
if !ok {
log.errorf(
"failed to parse float %v %s at line %d",
coord_idx,
ctx.bytes[ctx.it:][:12],
ctx.line,
)
return {}, false
}
advance(&ctx, nr) or_break
vertex[coord_idx] = coord_val
coord_idx += 1
}
append(&vertices, halfedge.Vertex{pos = vertex, edge = -1})
min_pos = lg.min(vertex, min_pos)
max_pos = lg.max(vertex, max_pos)
if ctx.bytes[ctx.it] == '\r' {
advance(&ctx)
}
advance(&ctx)
ctx.line += 1
case 'f':
advance(&ctx) or_break
MAX_FACE_VERTS :: 10
indices_buf: [MAX_FACE_VERTS]u16
index_count := 0
for ctx.bytes[ctx.it] != '\n' && ctx.bytes[ctx.it] != '\r' {
skip_whitespase(&ctx)
index_f, nr, ok := strconv.parse_f32_prefix(string(ctx.bytes[ctx.it:]))
if !ok {
log.errorf("failed to parse index at line %d", ctx.line)
return {}, false
}
advance(&ctx, nr) or_break
index := u16(index_f) - 1
indices_buf[index_count] = u16(index)
index_count += 1
}
if ctx.bytes[ctx.it] == '\r' {
advance(&ctx)
}
advance(&ctx)
ctx.line += 1
assert(index_count >= 3)
indices := indices_buf[:index_count]
append(&faces, halfedge.Face{})
face_idx := len(faces) - 1
face := &faces[face_idx]
first_edge_idx := len(edges)
face.edge = halfedge.Edge_Index(first_edge_idx)
plane: collision.Plane
{
i1, i2, i3 := indices[0], indices[1], indices[2]
v1, v2, v3 := vertices[i1].pos, vertices[i2].pos, vertices[i3].pos
plane = collision.plane_from_point_normal(
v1,
lg.normalize0(lg.cross(v2 - v1, v3 - v1)),
)
}
face.normal = plane.normal
for index in indices[3:] {
assert(
abs(collision.signed_distance_plane(vertices[index].pos, plane)) < 0.01,
"mesh has non planar faces",
)
}
first_vert_pos := vertices[indices[0]].pos
for i in 0 ..< len(indices) {
edge_idx := halfedge.Edge_Index(first_edge_idx + i)
prev_edge_relative := i == 0 ? len(indices) - 1 : i - 1
next_edge_relative := (i + 1) % len(indices)
i1, i2 := indices[i], indices[next_edge_relative]
v1, v2 := &vertices[i1], &vertices[i2]
assert(
lg.dot(
lg.cross(v1.pos - first_vert_pos, v2.pos - first_vert_pos),
plane.normal,
) >=
0,
"non convex face or non ccw winding",
)
if v1.edge == -1 {
v1.edge = edge_idx
}
edge := halfedge.Half_Edge {
origin = halfedge.Vertex_Index(i1),
face = halfedge.Face_Index(face_idx),
twin = -1,
next = halfedge.Edge_Index(first_edge_idx + next_edge_relative),
prev = halfedge.Edge_Index(first_edge_idx + prev_edge_relative),
}
stable_index := [2]u16{min(i1, i2), max(i1, i2)}
if stable_index in edges_map {
edge.twin = edges_map[stable_index]
twin_edge := &edges[edge.twin]
assert(twin_edge.twin == -1, "edge has more than two faces attached")
twin_edge.twin = edge_idx
} else {
edges_map[stable_index] = edge_idx
}
append(&edges, edge)
}
case:
skip_line(&ctx)
}
}
}
center := (max_pos + min_pos) * 0.5
extent := (max_pos - min_pos) * 0.5
center_of_mass: rl.Vector3
final_vertices := make([]halfedge.Vertex, len(vertices), allocator)
final_edges := make([]halfedge.Half_Edge, len(edges), allocator)
final_faces := make([]halfedge.Face, len(faces), allocator)
copy(final_vertices, vertices[:])
copy(final_edges, edges[:])
copy(final_faces, faces[:])
mesh := halfedge.Half_Edge_Mesh {
vertices = final_vertices,
edges = final_edges,
faces = final_faces,
center = center,
extent = extent,
}
// Center of mass calculation
total_volume := f32(0.0)
{
tri_idx := 0
for face_idx in 0 ..< len(faces) {
face := faces[face_idx]
// for all triangles
it := halfedge.iterator_face_edges(mesh, halfedge.Face_Index(face_idx))
i := 0
tri: [3]rl.Vector3
for edge in halfedge.iterate_next_edge(&it) {
switch i {
case 0 ..< 3:
tri[i] = mesh.vertices[edge.origin].pos
case:
tri[1] = tri[2]
tri[2] = mesh.vertices[edge.origin].pos
}
if i >= 2 {
plane := collision.plane_from_point_normal(tri[0], -face.normal)
h := max(0, collision.signed_distance_plane(center, plane))
tri_area :=
lg.dot(lg.cross(tri[1] - tri[0], tri[2] - tri[0]), face.normal) * 0.5
tetra_volume := 1.0 / 3.0 * tri_area * h
total_volume += tetra_volume
tetra_centroid := (tri[0] + tri[1] + tri[2] + center) * 0.25
center_of_mass += tetra_volume * tetra_centroid
tri_idx += 1
}
i += 1
}
}
}
assert(total_volume > 0, "degenerate convex hull")
center_of_mass /= total_volume
inertia_tensor: lg.Matrix3f32
// Find inertia tensor
{
tri_idx := 0
for face_idx in 0 ..< len(faces) {
// for all triangles
it := halfedge.iterator_face_edges(mesh, halfedge.Face_Index(face_idx))
i := 0
tri: [3]rl.Vector3
for edge in halfedge.iterate_next_edge(&it) {
switch i {
case 0 ..< 3:
tri[i] = mesh.vertices[edge.origin].pos
case:
tri[1] = tri[2]
tri[2] = mesh.vertices[edge.origin].pos
}
if i >= 2 {
tet := Tetrahedron {
p = {tri[0], tri[1], tri[2], center_of_mass},
}
inertia_tensor += tetrahedron_inertia_tensor(tet, center_of_mass)
tri_idx += 1
}
i += 1
}
}
}
inertia_tensor = inertia_tensor
return Loaded_Convex {
mesh = mesh,
center_of_mass = center_of_mass,
inertia_tensor = inertia_tensor,
total_volume = total_volume,
},
true
}
// TODO: move convex stuff out of assets.odin
Tetrahedron :: struct {
p: [4]rl.Vector3,
}
tetrahedron_volume :: #force_inline proc(tet: Tetrahedron) -> f32 {
return(
1.0 /
6.0 *
abs(lg.dot(lg.cross(tet.p[1] - tet.p[0], tet.p[2] - tet.p[0]), tet.p[3] - tet.p[0])) \
)
}
square :: #force_inline proc(val: f32) -> f32 {
return val * val
}
tetrahedron_inertia_tensor :: proc(tet: Tetrahedron, o: rl.Vector3) -> lg.Matrix3f32 {
p1, p2, p3, p4 := tet.p[0] - o, tet.p[1] - o, tet.p[2] - o, tet.p[3] - o
// Jacobian determinant is 6*Volume
det_j := abs(6.0 * tetrahedron_volume(tet))
moment_of_inertia_term :: proc(p1, p2, p3, p4: rl.Vector3, axis: int) -> f32 {
return(
square(p1[axis]) +
p1[axis] * p2[axis] +
square(p2[axis]) +
p1[axis] * p3[axis] +
p2[axis] * p3[axis] +
square(p3[axis]) +
p1[axis] * p4[axis] +
p2[axis] * p4[axis] +
p3[axis] * p4[axis] +
square(p4[axis]) \
)
}
product_of_inertia_term :: proc(p1, p2, p3, p4: rl.Vector3, axis1, axis2: int) -> f32 {
return(
2.0 * p1[axis1] * p1[axis2] +
p2[axis1] * p1[axis2] +
p3[axis1] * p1[axis2] +
p4[axis1] * p1[axis2] +
p1[axis1] * p2[axis2] +
2.0 * p2[axis1] * p2[axis2] +
p3[axis1] * p2[axis2] +
p4[axis1] * p2[axis2] +
p1[axis1] * p3[axis2] +
p2[axis1] * p3[axis2] +
2.0 * p3[axis1] * p3[axis2] +
p4[axis1] * p3[axis2] +
p1[axis1] * p4[axis2] +
p2[axis1] * p4[axis2] +
p3[axis1] * p4[axis2] +
2.0 * p4[axis1] * p4[axis2] \
)
}
MOMENT_OF_INERTIA_DENOM :: 1.0 / 60.0
PRODUCT_OF_INERTIA_DENOM :: 1.0 / 120.0
x_term := moment_of_inertia_term(p1, p2, p3, p4, 0)
y_term := moment_of_inertia_term(p1, p2, p3, p4, 1)
z_term := moment_of_inertia_term(p1, p2, p3, p4, 2)
// Moments of intertia with respect to XYZ
// Integral(y^2 + z^2)
a := det_j * (y_term + z_term) * MOMENT_OF_INERTIA_DENOM
// Integral(x^2 + z^2)
b := det_j * (x_term + z_term) * MOMENT_OF_INERTIA_DENOM
// Integral(x^2 + y^2)
c := det_j * (x_term + y_term) * MOMENT_OF_INERTIA_DENOM
// Products of inertia
a_ := product_of_inertia_term(p1, p2, p3, p4, axis1 = 1, axis2 = 2) * PRODUCT_OF_INERTIA_DENOM
b_ := product_of_inertia_term(p1, p2, p3, p4, axis1 = 0, axis2 = 2) * PRODUCT_OF_INERTIA_DENOM
c_ := product_of_inertia_term(p1, p2, p3, p4, axis1 = 0, axis2 = 1) * PRODUCT_OF_INERTIA_DENOM
return {a, -b_, -c_, -b_, b, -a_, -c_, -a_, c}
}
debug_draw_tetrahedron_wires :: proc(tri: [3]rl.Vector3, p: rl.Vector3, color: rl.Color) {
rlgl.Begin(rlgl.LINES)
defer rlgl.End()
debug.rlgl_color(color)
debug.rlgl_vertex3v2(tri[0], tri[1])
debug.rlgl_vertex3v2(tri[1], tri[2])
debug.rlgl_vertex3v2(tri[2], tri[0])
debug.rlgl_vertex3v2(tri[0], p)
debug.rlgl_vertex3v2(tri[1], p)
debug.rlgl_vertex3v2(tri[2], p)
}

145
game/assets/watcher.odin Normal file
View File

@ -0,0 +1,145 @@
package assets
import "base:runtime"
import "common:name"
import "core:log"
import "core:sync/chan"
import "core:thread"
import "libs:physfs"
ASSET_WATCHER_OPS_BUFFER :: 256
// Add asset to watch list
Asset_Watcher_Op_Add :: struct {
type: Asset_Type,
path: name.Name,
modtime: physfs.sint64,
}
// Remove asset from watch list
Asset_Watcher_Op_Remove :: struct {
type: Asset_Type,
path: name.Name,
}
Asset_Watcher_Op :: union #no_nil {
Asset_Watcher_Op_Add,
Asset_Watcher_Op_Remove,
}
Watcher_Asset :: struct {
type: Asset_Type,
path: name.Name,
modtime: physfs.sint64,
}
Asset_Modtime_Watcher :: struct {
ops: chan.Chan(Asset_Watcher_Op),
modified_assets: chan.Chan(Watcher_Asset),
loaded_assets: [dynamic]Watcher_Asset,
thread: ^thread.Thread,
}
modtime_watcher_init :: proc(watcher: ^Asset_Modtime_Watcher, allocator := context.allocator) {
err: runtime.Allocator_Error
watcher.ops, err = chan.create_buffered(
chan.Chan(Asset_Watcher_Op),
ASSET_WATCHER_OPS_BUFFER,
allocator,
)
assert(err == nil)
watcher.modified_assets, err = chan.create_buffered(
chan.Chan(Watcher_Asset),
ASSET_WATCHER_OPS_BUFFER,
allocator,
)
watcher.loaded_assets = make_dynamic_array([dynamic]Watcher_Asset, allocator)
watcher.thread = thread.create(modtime_watcher_thread_proc)
watcher.thread.data = watcher
watcher_context := runtime.default_context()
watcher_context.logger = context.logger
watcher_context.allocator = context.allocator
watcher.thread.init_context = watcher_context
thread.start(watcher.thread)
}
modtime_watcher_deinit :: proc(watcher: ^Asset_Modtime_Watcher) {
if !chan.is_closed(&watcher.ops) {
chan.close(&watcher.ops)
thread.join(watcher.thread)
watcher.thread = nil
}
chan.destroy(&watcher.ops)
chan.close(&watcher.modified_assets)
chan.destroy(&watcher.modified_assets)
delete(watcher.loaded_assets)
}
@(private = "file")
modtime_watcher_thread_proc :: proc(t: ^thread.Thread) {
watcher := cast(^Asset_Modtime_Watcher)t.data
log.debugf("watcher thread")
for !chan.is_closed(&watcher.ops) {
for recv_op in chan.try_recv(watcher.ops) {
switch op in recv_op {
case Asset_Watcher_Op_Add:
log.debugf("add [{}] {}", op.type, name.to_string(op.path))
append(
&watcher.loaded_assets,
Watcher_Asset{type = op.type, path = op.path, modtime = op.modtime},
)
case Asset_Watcher_Op_Remove:
log.debugf("remove [{}] {}", op.type, name.to_string(op.path))
i := 0
for i < len(watcher.loaded_assets) {
if op.path == watcher.loaded_assets[i].path &&
op.type == watcher.loaded_assets[i].type {
unordered_remove(&watcher.loaded_assets, i)
} else {
i += 1
}
}
}
}
for &asset in watcher.loaded_assets {
modtime := physfs.getLastModTime(name.to_cstring(asset.path))
if asset.modtime != modtime {
log.debugf("change [{}] {}", asset.type, name.to_string(asset.path))
ok := chan.send(
watcher.modified_assets,
Watcher_Asset{type = asset.type, path = asset.path, modtime = modtime},
)
assert(ok)
}
asset.modtime = modtime
}
// To avoid busy loop just in case
thread.yield()
}
}
modtime_watcher_add_asset :: proc(
watcher: ^Asset_Modtime_Watcher,
type: Asset_Type,
path: name.Name,
modtime: physfs.sint64,
) -> bool {
return chan.send(
watcher.ops,
Asset_Watcher_Op_Add{type = type, path = path, modtime = modtime},
)
}
modtime_watcher_remove_asset :: proc(
watcher: ^Asset_Modtime_Watcher,
type: Asset_Type,
path: name.Name,
) -> bool {
return chan.send(watcher.ops, Asset_Watcher_Op_Remove{type = type, path = path})
}

View File

@ -63,7 +63,8 @@ scene_destroy :: proc(world: ^World, scene: ^Scene) {
}
immediate_scene :: proc(world: ^World, scene: ^Scene, path: cstring) {
path_name := name.from_string(string(path))
tracy.Zone()
path_name := name.from_cstring(path)
desc, reloaded := assets.get_scene_desc(&g_mem.assetman, path_name)
@ -71,15 +72,16 @@ immediate_scene :: proc(world: ^World, scene: ^Scene, path: cstring) {
scene_destroy(world, scene)
scene.scene_desc_path = path_name
scene.level_geoms = make([]physics.Level_Geom_Handle, len(desc.instances))
sim_state := physics.get_sim_state(&world.physics_scene)
for inst in desc.instances {
physics.add_level_geom(
for inst, i in desc.instances {
scene.level_geoms[i] = physics.add_level_geom(
sim_state,
physics.Level_Geom_Config {
position = inst.pos,
rotation = inst.rot,
source = physics.Level_Geometry_Asset(name.to_string(inst.model)),
source = physics.Level_Geometry_Asset(inst.model),
},
)
}
@ -87,6 +89,7 @@ immediate_scene :: proc(world: ^World, scene: ^Scene, path: cstring) {
}
scene_copy :: proc(dst, src: ^Scene) {
tracy.Zone()
dst.scene_desc_path = src.scene_desc_path
if len(dst.level_geoms) != len(src.level_geoms) {
delete(dst.level_geoms)
@ -101,7 +104,7 @@ scene_draw :: proc(scene: ^Scene) {
render.draw_model(
assets.get_model(&g_mem.assetman, name.to_cstring(geo.model)),
{},
auto_cast linalg.matrix4_from_trs(geo.pos, geo.rot, geo.scale),
auto_cast linalg.matrix4_from_trs(geo.pos, geo.rot, 1),
)
}
}
@ -1437,6 +1440,8 @@ game_update :: proc() -> bool {
tracy.Zone()
defer tracy.FrameMark()
assets.assetman_tick(&g_mem.assetman)
update()
draw()
@ -1474,7 +1479,6 @@ game_init :: proc() {
init_physifs_raylib_callbacks()
assets.assetman_init(&g_mem.assetman)
assets.init(&g_mem.assetman)
editor_state_init(&g_mem.es, 100)
runtime_world_init(&g_mem.runtime_world, DEV_BUILD ? 100 : 2)

View File

@ -265,8 +265,7 @@ query_separation_edges :: proc(
a_edge = -1
b_edge = -1
temp := runtime.default_temp_allocator_temp_begin()
defer runtime.default_temp_allocator_temp_end(temp)
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
checked_pairs: bit_array.Bit_Array
bit_array.init(&checked_pairs, len(a.edges) * len(b.edges), 0, context.temp_allocator)

View File

@ -1,5 +1,6 @@
package physics
import "base:runtime"
import "bvh"
import "common:name"
import "core:fmt"
@ -9,6 +10,7 @@ import lg "core:math/linalg"
import "core:mem"
import "core:slice"
import "core:strings"
import "game:assets"
import "game:debug"
import he "game:halfedge"
import "game:ui"
@ -61,7 +63,14 @@ init_debug_state :: proc(debug_state: ^Debug_State) {
draw_debug_scene :: proc(scene: ^Scene, debug_state: ^Debug_State) {
tracy.Zone()
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
sim_state := get_sim_state(scene)
sim_cache: Sim_Cache
sim_cache.level_geom_asset_bvh = make_map(
map[Level_Geom_Handle]assets.Loaded_BVH,
context.temp_allocator,
)
// Static_TLAS
if true && sim_state.static_tlas.built {
@ -73,22 +82,27 @@ draw_debug_scene :: proc(scene: ^Scene, debug_state: ^Debug_State) {
it := bvh.iterator(&sim_state.static_tlas.bvh_tree)
for node in bvh.iterator_next(&it) {
if bvh.is_leaf_node(node) {
prim_start := node.child_or_prim_start
if false {
for node in bvh.iterator_next(&it) {
if bvh.is_leaf_node(node) {
prim_start := node.child_or_prim_start
for level_geom_idx in prim_start ..< prim_start + node.prim_len {
level_geom_handle := index_to_level_geom(int(level_geom_idx))
level_geom := get_level_geom(sim_state, level_geom_handle)
blas := get_level_geom_blas(sim_state, level_geom_handle)
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
for level_geom_idx in prim_start ..< prim_start + node.prim_len {
level_geom_handle := index_to_level_geom(int(level_geom_idx))
level_geom := get_level_geom(sim_state, level_geom_handle)
blas, vertices, indices := get_level_geom_data(
sim_state,
&sim_cache,
level_geom_handle,
)
bvh.debug_draw_bvh_bounds_mesh(
&blas,
bvh.Mesh{vertices = vertices, indices = indices},
level_geom.x,
0,
)
bvh.debug_draw_bvh_bounds_mesh(
&blas,
bvh.Mesh{vertices = vertices, indices = indices},
level_geom.x,
0,
)
}
}
}
}

View File

@ -300,6 +300,7 @@ body_get_convex_shapes_world :: proc(
level_geom_get_convex_shape :: proc(
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
level_geom_handle: Level_Geom_Handle,
tri_idx: int,
allocator := context.temp_allocator,
@ -307,7 +308,7 @@ level_geom_get_convex_shape :: proc(
mesh: collision.Convex,
) {
level_geom := get_level_geom(sim_state, level_geom_handle)
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
_, vertices, indices := get_level_geom_data(sim_state, sim_cache, level_geom_handle)
return collision.double_sided_triangle_to_convex(
get_transformed_triangle(vertices, indices, tri_idx, level_geom.x, level_geom.q),
allocator,
@ -353,7 +354,7 @@ rotate_extent :: proc(extent: Vec3, q: Quat) -> Vec3 {
return result
}
aabb_transform :: proc(local_aabb: AABB, x: Vec3, q: Quat) -> (aabb: AABB) {
aabb_transform_phys :: proc(local_aabb: AABB, x: Vec3, q: Quat) -> (aabb: AABB) {
aabb.center = lg.quaternion_mul_vector3(q, local_aabb.center) + x
aabb.extent = rotate_extent(local_aabb.extent, q)
@ -361,6 +362,34 @@ aabb_transform :: proc(local_aabb: AABB, x: Vec3, q: Quat) -> (aabb: AABB) {
return
}
// TODO: consolidate formats, please
aabb_transform_bvh :: proc(local_aabb: bvh.AABB, x: Vec3, q: Quat) -> (aabb: bvh.AABB) {
phys_aabb := bvh_aabb_to_phys_aabb(local_aabb)
phys_aabb = aabb_transform(phys_aabb, x, q)
aabb.min = phys_aabb.center - phys_aabb.extent
aabb.max = phys_aabb.center + phys_aabb.extent
return
}
aabb_transform :: proc {
aabb_transform_phys,
aabb_transform_bvh,
}
aabb_inv_transform :: proc(local_aabb: bvh.AABB, x: Vec3, q: Quat) -> (aabb: bvh.AABB) {
phys_aabb := bvh_aabb_to_phys_aabb(local_aabb)
inv_q := lg.quaternion_inverse(q)
phys_aabb.center = lg.quaternion_mul_vector3(inv_q, phys_aabb.center - x)
phys_aabb.extent = rotate_extent(phys_aabb.extent, inv_q)
aabb.min = phys_aabb.center - phys_aabb.extent
aabb.max = phys_aabb.center + phys_aabb.extent
return
}
input_shape_get_aabb :: proc(shapes: []Input_Shape) -> (aabb: AABB) {
min, max: Vec3 = max(f32), min(f32)

View File

@ -4,7 +4,6 @@ import "bvh"
import "collision"
import "common:name"
import lg "core:math/linalg"
import "core:strings"
import "game:assets"
import "game:container/spanpool"
import "libs:tracy"
@ -476,9 +475,6 @@ Suspension_Constraint_Ptr :: #soa^#soa[]Suspension_Constraint
Engine_Ptr :: ^Engine
Level_Geom_Ptr :: ^Level_Geom
_invalid_body: #soa[1]Body
_invalid_body_slice := _invalid_body[:]
_invalid_suspension_constraint: #soa[1]Suspension_Constraint
_invalid_suspension_constraint_slice := _invalid_suspension_constraint[:]
@ -507,8 +503,12 @@ flip_sim_state :: proc(scene: ^Scene) {
/// Returns pointer to soa slice. NEVER STORE IT
get_body :: proc(sim_state: ^Sim_State, handle: Body_Handle) -> Body_Ptr {
@(static) _invalid_body: #soa[1]Body
@(static) _invalid_body_slice: #soa[]Body
index := int(handle) - 1
if index < 0 || index >= len(sim_state.bodies_slice) {
_invalid_body_slice = _invalid_body[:]
_invalid_body_slice[0] = {
alive = true,
q = lg.QUATERNIONF32_IDENTITY,
@ -602,7 +602,7 @@ Engine_Config :: struct {
axle: Drive_Axle_Config,
}
Level_Geometry_Asset :: distinct string
Level_Geometry_Asset :: distinct name.Name
Level_Geometry_Mesh :: struct {
vertices: []Vec3,
@ -949,8 +949,10 @@ get_level_geom :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) -> Leve
get_level_geom_data :: proc(
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
handle: Level_Geom_Handle,
) -> (
blas: bvh.BVH,
vertices: []Vec3,
indices: []u16,
) {
@ -958,17 +960,28 @@ get_level_geom_data :: proc(
switch s in level_geom.source {
case Level_Geom_Source_Local:
blas.nodes = spanpool.resolve_slice(&sim_state.blas_nodes_pool, s.blas.nodes)
blas.primitives = spanpool.resolve_slice(
&sim_state.blas_primitives_pool,
s.blas.primitives,
)
blas.nodes_used = i32(len(blas.nodes))
vertices = spanpool.resolve_slice(&sim_state.geometry_vertices_pool, s.geometry.vertices)
indices = spanpool.resolve_slice(&sim_state.geometry_indices_pool, s.geometry.indices)
case Level_Geom_Source_Asset:
loaded_bvh, reloaded := assets.get_bvh(
sim_state.scene.assetman,
strings.unsafe_string_to_cstring(name.to_string(s.assetpath)),
)
if reloaded {
level_geom.aabb = bvh_aabb_to_phys_aabb(loaded_bvh.aabb)
level_geom.aabb = aabb_transform(level_geom.aabb, level_geom.x, level_geom.q)
loaded_bvh, ok := sim_cache.level_geom_asset_bvh[handle]
if !ok {
reloaded: bool
loaded_bvh, reloaded = assets.get_bvh(sim_state.scene.assetman, s.assetpath)
if reloaded {
level_geom.aabb = bvh_aabb_to_phys_aabb(loaded_bvh.aabb)
level_geom.aabb = aabb_transform(level_geom.aabb, level_geom.x, level_geom.q)
}
// sim_cache.level_geom_asset_bvh[handle] = loaded_bvh
}
blas = loaded_bvh.bvh
vertices = loaded_bvh.vertices
indices = loaded_bvh.indices
}
@ -976,28 +989,6 @@ get_level_geom_data :: proc(
return
}
get_level_geom_blas :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) -> (bvh: bvh.BVH) {
level_geom := get_level_geom(sim_state, handle)
switch s in level_geom.source {
case Level_Geom_Source_Local:
bvh.nodes = spanpool.resolve_slice(&sim_state.blas_nodes_pool, s.blas.nodes)
bvh.primitives = spanpool.resolve_slice(&sim_state.blas_primitives_pool, s.blas.primitives)
bvh.nodes_used = i32(len(bvh.nodes))
case Level_Geom_Source_Asset:
loaded_bvh, reloaded := assets.get_bvh(
sim_state.scene.assetman,
strings.unsafe_string_to_cstring(name.to_string(s.assetpath)),
)
if reloaded {
level_geom.aabb = bvh_aabb_to_phys_aabb(loaded_bvh.aabb)
level_geom.aabb = aabb_transform(level_geom.aabb, level_geom.x, level_geom.q)
}
bvh = loaded_bvh.bvh
}
return
}
update_level_geom_from_config :: proc(
sim_state: ^Sim_State,
level_geom: Level_Geom_Ptr,
@ -1063,13 +1054,10 @@ add_level_geom :: proc(sim_state: ^Sim_State, config: Level_Geom_Config) -> Leve
level_geom.source = source
case Level_Geometry_Asset:
level_geom.source = Level_Geom_Source_Asset {
assetpath = name.from_string(string(s)),
assetpath = name.Name(s),
}
bvh, _ := assets.get_bvh(
sim_state.scene.assetman,
strings.unsafe_string_to_cstring(string(s)),
)
bvh, _ := assets.get_bvh(sim_state.scene.assetman, name.Name(s))
level_geom.aabb = AABB {
center = (bvh.aabb.max + bvh.aabb.min) * 0.5,
extent = (bvh.aabb.max - bvh.aabb.min) * 0.5,
@ -1104,6 +1092,11 @@ remove_level_geom :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) {
spanpool.free(&sim_state.blas_primitives_pool, s.blas.primitives)
case Level_Geom_Source_Asset:
}
level_geom.alive = false
level_geom.next_plus_one = sim_state.first_free_level_geom_plus_one
sim_state.first_free_level_geom_plus_one = i32(handle)
sim_state.num_level_geoms -= 1
}
_get_first_free_body :: proc(sim_state: ^Sim_State) -> i32 {

View File

@ -11,6 +11,7 @@ import "core:math"
import lg "core:math/linalg"
import "core:math/rand"
import "core:slice"
import "game:assets"
import "game:debug"
import he "game:halfedge"
import "libs:tracy"
@ -174,8 +175,10 @@ dynamic_tlas_destroy :: proc(dyn_tlas: ^Dynamic_TLAS) {
}
}
raycasts_level :: proc(
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
tlas: ^Static_TLAS,
origin, dir: Vec3,
distance := max(f32),
@ -201,32 +204,31 @@ raycasts_level :: proc(
int(tlas.bvh_tree.primitives[leaf_node.child_or_prim_start + j]),
)
level_geom := get_level_geom(sim_state, level_geom_handle)
blas := get_level_geom_blas(sim_state, level_geom_handle)
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
blas, vertices, indices := get_level_geom_data(sim_state, sim_cache, level_geom_handle)
// TODO: transform ray into blas space and back
blas_it := bvh.iterator_intersect_leaf_ray(&blas, ray, distance)
inv_q := lg.quaternion_inverse(level_geom.q)
local_ray := ray
local_ray.origin = lg.quaternion_mul_vector3(inv_q, ray.origin - level_geom.x)
local_ray.dir = lg.quaternion_mul_vector3(inv_q, ray.dir)
local_ray.dir_inv = 1.0 / local_ray.dir
blas_it := bvh.iterator_intersect_leaf_ray(&blas, local_ray, distance)
for blas_leaf_node in bvh.iterator_intersect_leaf_next(&blas_it) {
for k in 0 ..< blas_leaf_node.prim_len {
tri_idx := int(blas.primitives[blas_leaf_node.child_or_prim_start + k])
tri := get_transformed_triangle(
vertices,
indices,
tri_idx,
level_geom.x,
level_geom.q,
)
tri := get_triangle(vertices, indices, tri_idx)
hit_t, tmp_normal, _, ok := collision.intersect_ray_triangle(
{origin, origin + dir},
{local_ray.origin, local_ray.origin + local_ray.dir},
tri,
)
if ok && (!hit || hit_t < t) {
t = hit_t
normal = tmp_normal
normal = lg.quaternion_mul_vector3(level_geom.q, tmp_normal)
hit = true
}
}
@ -294,6 +296,7 @@ raycast_bodies :: proc(
raycast :: proc(
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: ^Static_TLAS,
dyn_tlas: ^Dynamic_TLAS,
origin, dir: Vec3,
@ -305,7 +308,7 @@ raycast :: proc(
) {
t = distance
t1, normal1, hit1 := raycasts_level(sim_state, static_tlas, origin, dir, t)
t1, normal1, hit1 := raycasts_level(sim_state, sim_cache, static_tlas, origin, dir, t)
t2, normal2, hit2 := raycast_bodies(sim_state, dyn_tlas, origin, dir, t)
hit = hit1 || hit2
@ -329,6 +332,14 @@ raycast :: proc(
return
}
// Cache used during simulation to avoid complex computations
Sim_Cache :: struct {
// Looking up bvh can be expensive because assetman touches the filesystem each time. We assume that during simulation it cannot change
// so it's safe to cache
level_geom_asset_bvh: map[Level_Geom_Handle]assets.Loaded_BVH,
}
get_triangle :: proc(vertices: []Vec3, indices: []u16, tri_idx: int) -> (tri: [3]Vec3) {
i1, i2, i3 := indices[tri_idx * 3 + 0], indices[tri_idx * 3 + 1], indices[tri_idx * 3 + 2]
tri[0], tri[1], tri[2] = vertices[i1], vertices[i2], vertices[i3]
@ -361,6 +372,7 @@ get_triangle_aabb :: proc(tri: [3]Vec3) -> (aabb: bvh.AABB) {
remove_invalid_contacts :: proc(
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: Static_TLAS,
dyn_tlas: Dynamic_TLAS,
) {
@ -394,7 +406,11 @@ remove_invalid_contacts :: proc(
if !should_remove {
tri_idx := int(contact.local_tri_idx)
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
_, vertices, indices := get_level_geom_data(
sim_state,
sim_cache,
level_geom_handle,
)
should_remove |= tri_idx * 3 >= len(indices)
if !should_remove {
@ -453,6 +469,7 @@ remove_invalid_contacts :: proc(
// TODO: free intermediate temp allocs
find_new_contacts :: proc(
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: ^Static_TLAS,
dyn_tlas: ^Dynamic_TLAS,
) {
@ -559,10 +576,16 @@ find_new_contacts :: proc(
)
level_geom := get_level_geom(sim_state, level_geom_handle)
if level_geom.alive {
blas := get_level_geom_blas(sim_state, level_geom_handle)
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
blas, vertices, indices := get_level_geom_data(
sim_state,
sim_cache,
level_geom_handle,
)
blas_it := bvh.iterator_intersect_leaf_aabb(&blas, body_aabb)
blas_it := bvh.iterator_intersect_leaf_aabb(
&blas,
aabb_inv_transform(body_aabb, level_geom.x, level_geom.q),
)
for blas_leaf_node in bvh.iterator_intersect_leaf_next(&blas_it) {
for k in 0 ..< blas_leaf_node.prim_len {
tri_idx := int(
@ -653,9 +676,16 @@ simulate :: proc(
prune_immediate(scene)
copy_sim_state(get_next_sim_state(scene), get_sim_state(scene))
sim_state := get_next_sim_state(scene)
// runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
sim_cache: Sim_Cache
sim_cache.level_geom_asset_bvh = make_map(
map[Level_Geom_Handle]assets.Loaded_BVH,
context.temp_allocator,
)
num_steps := 0
switch step_mode {
case .Accumulated_Time:
@ -666,11 +696,11 @@ simulate :: proc(
state.accumulated_time -= config.timestep
if num_steps < MAX_STEPS {
simulate_step(scene, sim_state, config)
simulate_step(scene, sim_state, &sim_cache, config)
}
}
case .Single:
simulate_step(scene, get_next_sim_state(scene), config)
simulate_step(scene, get_next_sim_state(scene), &sim_cache, config)
num_steps += 1
}
@ -718,7 +748,7 @@ Contact :: struct {
applied_normal_correction: [4]f32,
}
update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) {
update_contacts :: proc(sim_state: ^Sim_State, sim_cache: ^Sim_Cache, static_tlas: ^Static_TLAS) {
tracy.Zone()
temp := runtime.default_temp_allocator_temp_begin()
@ -824,7 +854,7 @@ update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) {
case .Body_vs_Level:
level_geom_handle := Level_Geom_Handle(contact.b)
level_geom := get_level_geom(sim_state, level_geom_handle)
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
_, vertices, indices := get_level_geom_data(sim_state, sim_cache, level_geom_handle)
tri := get_transformed_triangle(
vertices,
indices,
@ -1232,6 +1262,7 @@ calculate_ground_vel :: proc(
pgs_solve_suspension :: proc(
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: ^Static_TLAS,
dyn_tlas: ^Dynamic_TLAS,
config: Solver_Config,
@ -1249,6 +1280,7 @@ pgs_solve_suspension :: proc(
dir := body_local_to_world_vec(body, v.rel_dir)
v.hit_t, v.hit_normal, v.hit = raycast(
sim_state,
sim_cache,
static_tlas,
dyn_tlas,
wheel_world_pos,
@ -1438,6 +1470,7 @@ pgs_solve_suspension :: proc(
pgs_substep :: proc(
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: ^Static_TLAS,
dyn_tlas: ^Dynamic_TLAS,
config: Solver_Config,
@ -1559,7 +1592,7 @@ pgs_substep :: proc(
apply_bias := true
pgs_solve_contacts(sim_state, config, dt, inv_dt, apply_bias)
pgs_solve_engines(sim_state, config, dt, inv_dt)
pgs_solve_suspension(sim_state, static_tlas, dyn_tlas, config, dt, inv_dt)
pgs_solve_suspension(sim_state, sim_cache, static_tlas, dyn_tlas, config, dt, inv_dt)
for i in 0 ..< len(sim_state.bodies_slice) {
body := &sim_state.bodies_slice[i]
@ -1600,7 +1633,12 @@ pgs_substep :: proc(
// pgs_solve_suspension(sim_state, config, dt, inv_dt, apply_bias)
}
simulate_step :: proc(scene: ^Scene, sim_state: ^Sim_State, config: Solver_Config) {
simulate_step :: proc(
scene: ^Scene,
sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
config: Solver_Config,
) {
tracy.Zone()
substeps := config.substreps_minus_one + 1
@ -1614,9 +1652,9 @@ simulate_step :: proc(scene: ^Scene, sim_state: ^Sim_State, config: Solver_Confi
build_static_tlas(sim_state, &sim_state.static_tlas)
build_dynamic_tlas(sim_state, config, &sim_state.dynamic_tlas)
remove_invalid_contacts(sim_state, sim_state.static_tlas, sim_state.dynamic_tlas)
find_new_contacts(sim_state, &sim_state.static_tlas, &sim_state.dynamic_tlas)
update_contacts(sim_state, &sim_state.static_tlas)
remove_invalid_contacts(sim_state, sim_cache, sim_state.static_tlas, sim_state.dynamic_tlas)
find_new_contacts(sim_state, sim_cache, &sim_state.static_tlas, &sim_state.dynamic_tlas)
update_contacts(sim_state, sim_cache, &sim_state.static_tlas)
Solver :: enum {
XPBD,
@ -1634,6 +1672,7 @@ simulate_step :: proc(scene: ^Scene, sim_state: ^Sim_State, config: Solver_Confi
for _ in 0 ..< substeps {
pgs_substep(
sim_state,
sim_cache,
&sim_state.static_tlas,
&sim_state.dynamic_tlas,
config,

View File

@ -220,4 +220,4 @@ EaseElasticInOut :: proc(t, b, c, d: f32) -> f32 {
postFix := a*math.pow(2.0, -10.0*t)
return (postFix*math.sin((t*d-s)*(2.0*PI)/p)*0.5 + c + b)
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -523,7 +523,7 @@ Vector3Unproject :: proc "c" (source: Vector3, projection: Matrix, view: Matrix)
quat: Quaternion
quat.x = source.x
quat.y = source.z
quat.y = source.y
quat.z = source.z
quat.w = 1
@ -831,8 +831,8 @@ fmaxf :: proc "contextless" (x, y: f32) -> f32 {
return x
}
if math.signbit(x) != math.signbit(y) {
return y if math.signbit(x) else x
if math.sign_bit(x) != math.sign_bit(y) {
return y if math.sign_bit(x) else x
}
return y if x < y else x

View File

@ -107,8 +107,8 @@
package rlgl
import rl "../."
import "core:c"
import rl "../."
VERSION :: "5.0"
@ -132,17 +132,17 @@ when ODIN_OS == .Windows {
foreign import lib "system:raylib"
}
GRAPHICS_API_OPENGL_11 :: false
GRAPHICS_API_OPENGL_21 :: true
GRAPHICS_API_OPENGL_33 :: GRAPHICS_API_OPENGL_21 // default currently
GRAPHICS_API_OPENGL_11 :: false
GRAPHICS_API_OPENGL_21 :: true
GRAPHICS_API_OPENGL_33 :: GRAPHICS_API_OPENGL_21 // default currently
GRAPHICS_API_OPENGL_ES2 :: false
GRAPHICS_API_OPENGL_43 :: false
GRAPHICS_API_OPENGL_43 :: false
GRAPHICS_API_OPENGL_ES3 :: false
when GRAPHICS_API_OPENGL_ES3 {
GRAPHICS_API_OPENGL_ES2 :: true
}
when !GRAPHICS_API_OPENGL_ES2 {
// This is the maximum amount of elements (quads) per batch
// NOTE: Be careful with text, every letter maps to a quad
@ -154,100 +154,100 @@ when !GRAPHICS_API_OPENGL_ES2 {
DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048
}
DEFAULT_BATCH_BUFFERS :: 1 // Default number of batch buffers (multi-buffering)
DEFAULT_BATCH_DRAWCALLS :: 256 // Default number of batch draw calls (by state changes: mode, texture)
DEFAULT_BATCH_MAX_TEXTURE_UNITS :: 4 // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
DEFAULT_BATCH_BUFFERS :: 1 // Default number of batch buffers (multi-buffering)
DEFAULT_BATCH_DRAWCALLS :: 256 // Default number of batch draw calls (by state changes: mode, texture)
DEFAULT_BATCH_MAX_TEXTURE_UNITS :: 4 // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
// Internal Matrix stack
MAX_MATRIX_STACK_SIZE :: 32 // Maximum size of Matrix stack
MAX_MATRIX_STACK_SIZE :: 32 // Maximum size of Matrix stack
// Shader limits
MAX_SHADER_LOCATIONS :: 32 // Maximum number of shader locations supported
MAX_SHADER_LOCATIONS :: 32 // Maximum number of shader locations supported
// Projection matrix culling
CULL_DISTANCE_NEAR :: 0.01 // Default near cull distance
CULL_DISTANCE_FAR :: 1000.0 // Default far cull distance
CULL_DISTANCE_NEAR :: 0.01 // Default near cull distance
CULL_DISTANCE_FAR :: 1000.0 // Default far cull distance
// Texture parameters (equivalent to OpenGL defines)
TEXTURE_WRAP_S :: 0x2802 // GL_TEXTURE_WRAP_S
TEXTURE_WRAP_T :: 0x2803 // GL_TEXTURE_WRAP_T
TEXTURE_MAG_FILTER :: 0x2800 // GL_TEXTURE_MAG_FILTER
TEXTURE_MIN_FILTER :: 0x2801 // GL_TEXTURE_MIN_FILTER
TEXTURE_WRAP_S :: 0x2802 // GL_TEXTURE_WRAP_S
TEXTURE_WRAP_T :: 0x2803 // GL_TEXTURE_WRAP_T
TEXTURE_MAG_FILTER :: 0x2800 // GL_TEXTURE_MAG_FILTER
TEXTURE_MIN_FILTER :: 0x2801 // GL_TEXTURE_MIN_FILTER
TEXTURE_FILTER_NEAREST :: 0x2600 // GL_NEAREST
TEXTURE_FILTER_LINEAR :: 0x2601 // GL_LINEAR
TEXTURE_FILTER_MIP_NEAREST :: 0x2700 // GL_NEAREST_MIPMAP_NEAREST
TEXTURE_FILTER_NEAREST_MIP_LINEAR :: 0x2702 // GL_NEAREST_MIPMAP_LINEAR
TEXTURE_FILTER_LINEAR_MIP_NEAREST :: 0x2701 // GL_LINEAR_MIPMAP_NEAREST
TEXTURE_FILTER_MIP_LINEAR :: 0x2703 // GL_LINEAR_MIPMAP_LINEAR
TEXTURE_FILTER_ANISOTROPIC :: 0x3000 // Anisotropic filter (custom identifier)
TEXTURE_FILTER_NEAREST :: 0x2600 // GL_NEAREST
TEXTURE_FILTER_LINEAR :: 0x2601 // GL_LINEAR
TEXTURE_FILTER_MIP_NEAREST :: 0x2700 // GL_NEAREST_MIPMAP_NEAREST
TEXTURE_FILTER_NEAREST_MIP_LINEAR :: 0x2702 // GL_NEAREST_MIPMAP_LINEAR
TEXTURE_FILTER_LINEAR_MIP_NEAREST :: 0x2701 // GL_LINEAR_MIPMAP_NEAREST
TEXTURE_FILTER_MIP_LINEAR :: 0x2703 // GL_LINEAR_MIPMAP_LINEAR
TEXTURE_FILTER_ANISOTROPIC :: 0x3000 // Anisotropic filter (custom identifier)
TEXTURE_WRAP_REPEAT :: 0x2901 // GL_REPEAT
TEXTURE_WRAP_CLAMP :: 0x812F // GL_CLAMP_TO_EDGE
TEXTURE_WRAP_MIRROR_REPEAT :: 0x8370 // GL_MIRRORED_REPEAT
TEXTURE_WRAP_MIRROR_CLAMP :: 0x8742 // GL_MIRROR_CLAMP_EXT
TEXTURE_WRAP_REPEAT :: 0x2901 // GL_REPEAT
TEXTURE_WRAP_CLAMP :: 0x812F // GL_CLAMP_TO_EDGE
TEXTURE_WRAP_MIRROR_REPEAT :: 0x8370 // GL_MIRRORED_REPEAT
TEXTURE_WRAP_MIRROR_CLAMP :: 0x8742 // GL_MIRROR_CLAMP_EXT
// Matrix modes (equivalent to OpenGL)
MODELVIEW :: 0x1700 // GL_MODELVIEW
PROJECTION :: 0x1701 // GL_PROJECTION
TEXTURE :: 0x1702 // GL_TEXTURE
MODELVIEW :: 0x1700 // GL_MODELVIEW
PROJECTION :: 0x1701 // GL_PROJECTION
TEXTURE :: 0x1702 // GL_TEXTURE
// Primitive assembly draw modes
LINES :: 0x0001 // GL_LINES
TRIANGLES :: 0x0004 // GL_TRIANGLES
QUADS :: 0x0007 // GL_QUADS
LINES :: 0x0001 // GL_LINES
TRIANGLES :: 0x0004 // GL_TRIANGLES
QUADS :: 0x0007 // GL_QUADS
// GL equivalent data types
UNSIGNED_BYTE :: 0x1401 // GL_UNSIGNED_BYTE
FLOAT :: 0x1406 // GL_FLOAT
UNSIGNED_BYTE :: 0x1401 // GL_UNSIGNED_BYTE
FLOAT :: 0x1406 // GL_FLOAT
// Buffer usage hint
STREAM_DRAW :: 0x88E0 // GL_STREAM_DRAW
STREAM_READ :: 0x88E1 // GL_STREAM_READ
STREAM_COPY :: 0x88E2 // GL_STREAM_COPY
STATIC_DRAW :: 0x88E4 // GL_STATIC_DRAW
STATIC_READ :: 0x88E5 // GL_STATIC_READ
STATIC_COPY :: 0x88E6 // GL_STATIC_COPY
DYNAMIC_DRAW :: 0x88E8 // GL_DYNAMIC_DRAW
DYNAMIC_READ :: 0x88E9 // GL_DYNAMIC_READ
DYNAMIC_COPY :: 0x88EA // GL_DYNAMIC_COPY
STREAM_DRAW :: 0x88E0 // GL_STREAM_DRAW
STREAM_READ :: 0x88E1 // GL_STREAM_READ
STREAM_COPY :: 0x88E2 // GL_STREAM_COPY
STATIC_DRAW :: 0x88E4 // GL_STATIC_DRAW
STATIC_READ :: 0x88E5 // GL_STATIC_READ
STATIC_COPY :: 0x88E6 // GL_STATIC_COPY
DYNAMIC_DRAW :: 0x88E8 // GL_DYNAMIC_DRAW
DYNAMIC_READ :: 0x88E9 // GL_DYNAMIC_READ
DYNAMIC_COPY :: 0x88EA // GL_DYNAMIC_COPY
// GL Shader type
FRAGMENT_SHADER :: 0x8B30 // GL_FRAGMENT_SHADER
VERTEX_SHADER :: 0x8B31 // GL_VERTEX_SHADER
COMPUTE_SHADER :: 0x91B9 // GL_COMPUTE_SHADER
FRAGMENT_SHADER :: 0x8B30 // GL_FRAGMENT_SHADER
VERTEX_SHADER :: 0x8B31 // GL_VERTEX_SHADER
COMPUTE_SHADER :: 0x91B9 // GL_COMPUTE_SHADER
// GL blending factors
ZERO :: 0 // GL_ZERO
ONE :: 1 // GL_ONE
SRC_COLOR :: 0x0300 // GL_SRC_COLOR
ONE_MINUS_SRC_COLOR :: 0x0301 // GL_ONE_MINUS_SRC_COLOR
SRC_ALPHA :: 0x0302 // GL_SRC_ALPHA
ONE_MINUS_SRC_ALPHA :: 0x0303 // GL_ONE_MINUS_SRC_ALPHA
DST_ALPHA :: 0x0304 // GL_DST_ALPHA
ONE_MINUS_DST_ALPHA :: 0x0305 // GL_ONE_MINUS_DST_ALPHA
DST_COLOR :: 0x0306 // GL_DST_COLOR
ONE_MINUS_DST_COLOR :: 0x0307 // GL_ONE_MINUS_DST_COLOR
SRC_ALPHA_SATURATE :: 0x0308 // GL_SRC_ALPHA_SATURATE
CONSTANT_COLOR :: 0x8001 // GL_CONSTANT_COLOR
ONE_MINUS_CONSTANT_COLOR :: 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR
CONSTANT_ALPHA :: 0x8003 // GL_CONSTANT_ALPHA
ONE_MINUS_CONSTANT_ALPHA :: 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA
ZERO :: 0 // GL_ZERO
ONE :: 1 // GL_ONE
SRC_COLOR :: 0x0300 // GL_SRC_COLOR
ONE_MINUS_SRC_COLOR :: 0x0301 // GL_ONE_MINUS_SRC_COLOR
SRC_ALPHA :: 0x0302 // GL_SRC_ALPHA
ONE_MINUS_SRC_ALPHA :: 0x0303 // GL_ONE_MINUS_SRC_ALPHA
DST_ALPHA :: 0x0304 // GL_DST_ALPHA
ONE_MINUS_DST_ALPHA :: 0x0305 // GL_ONE_MINUS_DST_ALPHA
DST_COLOR :: 0x0306 // GL_DST_COLOR
ONE_MINUS_DST_COLOR :: 0x0307 // GL_ONE_MINUS_DST_COLOR
SRC_ALPHA_SATURATE :: 0x0308 // GL_SRC_ALPHA_SATURATE
CONSTANT_COLOR :: 0x8001 // GL_CONSTANT_COLOR
ONE_MINUS_CONSTANT_COLOR :: 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR
CONSTANT_ALPHA :: 0x8003 // GL_CONSTANT_ALPHA
ONE_MINUS_CONSTANT_ALPHA :: 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA
// GL blending functions/equations
FUNC_ADD :: 0x8006 // GL_FUNC_ADD
MIN :: 0x8007 // GL_MIN
MAX :: 0x8008 // GL_MAX
FUNC_SUBTRACT :: 0x800A // GL_FUNC_SUBTRACT
FUNC_REVERSE_SUBTRACT :: 0x800B // GL_FUNC_REVERSE_SUBTRACT
BLEND_EQUATION :: 0x8009 // GL_BLEND_EQUATION
BLEND_EQUATION_RGB :: 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION)
BLEND_EQUATION_ALPHA :: 0x883D // GL_BLEND_EQUATION_ALPHA
BLEND_DST_RGB :: 0x80C8 // GL_BLEND_DST_RGB
BLEND_SRC_RGB :: 0x80C9 // GL_BLEND_SRC_RGB
BLEND_DST_ALPHA :: 0x80CA // GL_BLEND_DST_ALPHA
BLEND_SRC_ALPHA :: 0x80CB // GL_BLEND_SRC_ALPHA
BLEND_COLOR :: 0x8005 // GL_BLEND_COLOR
FUNC_ADD :: 0x8006 // GL_FUNC_ADD
MIN :: 0x8007 // GL_MIN
MAX :: 0x8008 // GL_MAX
FUNC_SUBTRACT :: 0x800A // GL_FUNC_SUBTRACT
FUNC_REVERSE_SUBTRACT :: 0x800B // GL_FUNC_REVERSE_SUBTRACT
BLEND_EQUATION :: 0x8009 // GL_BLEND_EQUATION
BLEND_EQUATION_RGB :: 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION)
BLEND_EQUATION_ALPHA :: 0x883D // GL_BLEND_EQUATION_ALPHA
BLEND_DST_RGB :: 0x80C8 // GL_BLEND_DST_RGB
BLEND_SRC_RGB :: 0x80C9 // GL_BLEND_SRC_RGB
BLEND_DST_ALPHA :: 0x80CA // GL_BLEND_DST_ALPHA
BLEND_SRC_ALPHA :: 0x80CB // GL_BLEND_SRC_ALPHA
BLEND_COLOR :: 0x8005 // GL_BLEND_COLOR
//----------------------------------------------------------------------------------
// Types and Structures Definition
@ -258,13 +258,14 @@ VertexBufferIndexType :: c.ushort when GRAPHICS_API_OPENGL_ES2 else c.uint
// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
VertexBuffer :: struct {
elementCount: c.int, // Number of elements in the buffer (QUADS)
vertices: [^]f32, // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
texcoords: [^]f32, // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
colors: [^]u8, // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
indices: [^]VertexBufferIndexType, // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
vaoId: c.uint, // OpenGL Vertex Array Object id
vboId: [4]c.uint, // OpenGL Vertex Buffer Objects id (4 types of vertex data)
elementCount: c.int, // Number of elements in the buffer (QUADS)
vertices: [^]f32, // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
texcoords: [^]f32, // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
colors: [^]u8, // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
indices: [^]VertexBufferIndexType, // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
vaoId: c.uint, // OpenGL Vertex Array Object id
vboId: [4]c.uint, // OpenGL Vertex Buffer Objects id (4 types of vertex data)
}
// Draw call type
@ -272,30 +273,31 @@ VertexBuffer :: struct {
// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
// of those state-change happens (this is done in core module)
DrawCall :: struct {
mode: c.int, // Drawing mode: LINES, TRIANGLES, QUADS
vertexCount: c.int, // Number of vertex of the draw
vertexAlignment: c.int, // Number of vertex required for index alignment (LINES, TRIANGLES)
textureId: c.uint, // Texture id to be used on the draw -> Use to create new draw call if changes
mode: c.int, // Drawing mode: LINES, TRIANGLES, QUADS
vertexCount: c.int, // Number of vertex of the draw
vertexAlignment: c.int, // Number of vertex required for index alignment (LINES, TRIANGLES)
textureId: c.uint, // Texture id to be used on the draw -> Use to create new draw call if changes
}
// RenderBatch type
RenderBatch :: struct {
bufferCount: c.int, // Number of vertex buffers (multi-buffering support)
currentBuffer: c.int, // Current buffer tracking in case of multi-buffering
bufferCount: c.int, // Number of vertex buffers (multi-buffering support)
currentBuffer: c.int, // Current buffer tracking in case of multi-buffering
vertexBuffer: [^]VertexBuffer, // Dynamic buffer(s) for vertex data
draws: [^]DrawCall, // Draw calls array, depends on textureId
drawCounter: c.int, // Draw calls counter
currentDepth: f32, // Current depth value for next draw
draws: [^]DrawCall, // Draw calls array, depends on textureId
drawCounter: c.int, // Draw calls counter
currentDepth: f32, // Current depth value for next draw
}
// OpenGL version
GlVersion :: enum c.int {
OPENGL_11 = 1, // OpenGL 1.1
OPENGL_21, // OpenGL 2.1 (GLSL 120)
OPENGL_33, // OpenGL 3.3 (GLSL 330)
OPENGL_43, // OpenGL 4.3 (using GLSL 330)
OPENGL_ES_20, // OpenGL ES 2.0 (GLSL 100)
OPENGL_ES_30, // OpenGL ES 3.0 (GLSL 300 es)
OPENGL_11 = 1, // OpenGL 1.1
OPENGL_21, // OpenGL 2.1 (GLSL 120)
OPENGL_33, // OpenGL 3.3 (GLSL 330)
OPENGL_43, // OpenGL 4.3 (using GLSL 330)
OPENGL_ES_20, // OpenGL ES 2.0 (GLSL 100)
OPENGL_ES_30, // OpenGL ES 3.0 (GLSL 300 es)
}
PixelFormat :: rl.PixelFormat
@ -306,25 +308,25 @@ ShaderUniformDataType :: rl.ShaderUniformDataType
// Shader attribute data types
ShaderAttributeDataType :: enum c.int {
FLOAT = 0, // Shader attribute type: float
VEC2, // Shader attribute type: vec2 (2 float)
VEC3, // Shader attribute type: vec3 (3 float)
VEC4, // Shader attribute type: vec4 (4 float)
FLOAT = 0, // Shader attribute type: float
VEC2, // Shader attribute type: vec2 (2 float)
VEC3, // Shader attribute type: vec3 (3 float)
VEC4, // Shader attribute type: vec4 (4 float)
}
// Framebuffer attachment type
// NOTE: By default up to 8 color channels defined, but it can be more
FramebufferAttachType :: enum c.int {
COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0
COLOR_CHANNEL1 = 1, // Framebuffer attachment type: color 1
COLOR_CHANNEL2 = 2, // Framebuffer attachment type: color 2
COLOR_CHANNEL3 = 3, // Framebuffer attachment type: color 3
COLOR_CHANNEL4 = 4, // Framebuffer attachment type: color 4
COLOR_CHANNEL5 = 5, // Framebuffer attachment type: color 5
COLOR_CHANNEL6 = 6, // Framebuffer attachment type: color 6
COLOR_CHANNEL7 = 7, // Framebuffer attachment type: color 7
DEPTH = 100, // Framebuffer attachment type: depth
STENCIL = 200, // Framebuffer attachment type: stencil
COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0
COLOR_CHANNEL1 = 1, // Framebuffer attachment type: color 1
COLOR_CHANNEL2 = 2, // Framebuffer attachment type: color 2
COLOR_CHANNEL3 = 3, // Framebuffer attachment type: color 3
COLOR_CHANNEL4 = 4, // Framebuffer attachment type: color 4
COLOR_CHANNEL5 = 5, // Framebuffer attachment type: color 5
COLOR_CHANNEL6 = 6, // Framebuffer attachment type: color 6
COLOR_CHANNEL7 = 7, // Framebuffer attachment type: color 7
DEPTH = 100, // Framebuffer attachment type: depth
STENCIL = 200, // Framebuffer attachment type: stencil
}
// Framebuffer texture attachment type
@ -335,8 +337,8 @@ FramebufferAttachTextureType :: enum c.int {
CUBEMAP_NEGATIVE_Y = 3, // Framebuffer texture attachment type: cubemap, -Y side
CUBEMAP_POSITIVE_Z = 4, // Framebuffer texture attachment type: cubemap, +Z side
CUBEMAP_NEGATIVE_Z = 5, // Framebuffer texture attachment type: cubemap, -Z side
TEXTURE2D = 100, // Framebuffer texture attachment type: texture2d
RENDERBUFFER = 200, // Framebuffer texture attachment type: renderbuffer
TEXTURE2D = 100, // Framebuffer texture attachment type: texture2d
RENDERBUFFER = 200, // Framebuffer texture attachment type: renderbuffer
}
CullMode :: enum c.int {
@ -346,37 +348,39 @@ CullMode :: enum c.int {
Matrix :: rl.Matrix
@(default_calling_convention = "c", link_prefix = "rl")
@(default_calling_convention="c", link_prefix="rl")
foreign lib {
//------------------------------------------------------------------------------------
// Functions Declaration - Matrix operations
//------------------------------------------------------------------------------------
MatrixMode :: proc(mode: c.int) --- // Choose the current matrix to be transformed
PushMatrix :: proc() --- // Push the current matrix to stack
PopMatrix :: proc() --- // Pop lattest inserted matrix from stack
LoadIdentity :: proc() --- // Reset current matrix to identity matrix
Translatef :: proc(x, y, z: f32) --- // Multiply the current matrix by a translation matrix
Rotatef :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix
Scalef :: proc(x, y, z: f32) --- // Multiply the current matrix by a scaling matrix
MultMatrixf :: proc(matf: [^]f32) --- // Multiply the current matrix by another matrix
Frustum :: proc(left, right, bottom, top, znear, zfar: f64) ---
Ortho :: proc(left, right, bottom, top, znear, zfar: f64) ---
Viewport :: proc(x, y, width, height: c.int) --- // Set the viewport area
SetClipPlanes :: proc(nearPlane, farPlane: f64) --- // Set clip planes
MatrixMode :: proc(mode: c.int) --- // Choose the current matrix to be transformed
PushMatrix :: proc() --- // Push the current matrix to stack
PopMatrix :: proc() --- // Pop lattest inserted matrix from stack
LoadIdentity :: proc() --- // Reset current matrix to identity matrix
Translatef :: proc(x, y, z: f32) --- // Multiply the current matrix by a translation matrix
Rotatef :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix
Scalef :: proc(x, y, z: f32) --- // Multiply the current matrix by a scaling matrix
MultMatrixf :: proc(matf: [^]f32) --- // Multiply the current matrix by another matrix
Frustum :: proc(left, right, bottom, top, znear, zfar: f64) ---
Ortho :: proc(left, right, bottom, top, znear, zfar: f64) ---
Viewport :: proc(x, y, width, height: c.int) --- // Set the viewport area
SetClipPlanes :: proc(near, far: f64) --- // Set clip planes distances
GetCullDistanceNear :: proc() -> f64 --- // Get cull plane distance near
GetCullDistanceFar :: proc() -> f64 --- // Get cull plane distance far
//------------------------------------------------------------------------------------
// Functions Declaration - Vertex level operations
//------------------------------------------------------------------------------------
Begin :: proc(mode: c.int) --- // Initialize drawing mode (how to organize vertex)
End :: proc() --- // Finish vertex providing
Vertex2i :: proc(x, y: c.int) --- // Define one vertex (position) - 2 int
Vertex2f :: proc(x, y: f32) --- // Define one vertex (position) - 2 f32
Vertex3f :: proc(x, y, z: f32) --- // Define one vertex (position) - 3 f32
TexCoord2f :: proc(x, y: f32) --- // Define one vertex (texture coordinate) - 2 f32
Normal3f :: proc(x, y, z: f32) --- // Define one vertex (normal) - 3 f32
Color4ub :: proc(r, g, b, a: u8) --- // Define one vertex (color) - 4 byte
Color3f :: proc(x, y, z: f32) --- // Define one vertex (color) - 3 f32
Color4f :: proc(x, y, z, w: f32) --- // Define one vertex (color) - 4 f32
Begin :: proc(mode: c.int) --- // Initialize drawing mode (how to organize vertex)
End :: proc() --- // Finish vertex providing
Vertex2i :: proc(x, y: c.int) --- // Define one vertex (position) - 2 int
Vertex2f :: proc(x, y: f32) --- // Define one vertex (position) - 2 f32
Vertex3f :: proc(x, y, z: f32) --- // Define one vertex (position) - 3 f32
TexCoord2f :: proc(x, y: f32) --- // Define one vertex (texture coordinate) - 2 f32
Normal3f :: proc(x, y, z: f32) --- // Define one vertex (normal) - 3 f32
Color4ub :: proc(r, g, b, a: u8) --- // Define one vertex (color) - 4 byte
Color3f :: proc(x, y, z: f32) --- // Define one vertex (color) - 3 f32
Color4f :: proc(x, y, z, w: f32) --- // Define one vertex (color) - 4 f32
//------------------------------------------------------------------------------------
// Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2)
@ -385,176 +389,176 @@ foreign lib {
//------------------------------------------------------------------------------------
// Vertex buffers state
EnableVertexArray :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported)
DisableVertexArray :: proc() --- // Disable vertex array (VAO, if supported)
EnableVertexBuffer :: proc(id: c.uint) --- // Enable vertex buffer (VBO)
DisableVertexBuffer :: proc() --- // Disable vertex buffer (VBO)
EnableVertexBufferElement :: proc(id: c.uint) --- // Enable vertex buffer element (VBO element)
DisableVertexBufferElement :: proc() --- // Disable vertex buffer element (VBO element)
EnableVertexAttribute :: proc(index: c.uint) --- // Enable vertex attribute index
DisableVertexAttribute :: proc(index: c.uint) --- // Disable vertex attribute index
EnableVertexArray :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported)
DisableVertexArray :: proc() --- // Disable vertex array (VAO, if supported)
EnableVertexBuffer :: proc(id: c.uint) --- // Enable vertex buffer (VBO)
DisableVertexBuffer :: proc() --- // Disable vertex buffer (VBO)
EnableVertexBufferElement :: proc(id: c.uint) --- // Enable vertex buffer element (VBO element)
DisableVertexBufferElement :: proc() --- // Disable vertex buffer element (VBO element)
EnableVertexAttribute :: proc(index: c.uint) --- // Enable vertex attribute index
DisableVertexAttribute :: proc(index: c.uint) --- // Disable vertex attribute index
when GRAPHICS_API_OPENGL_11 {
EnableStatePointer :: proc(vertexAttribType: c.int, buffer: rawptr) ---
DisableStatePointer :: proc(vertexAttribType: c.int) ---
}
// Textures state
ActiveTextureSlot :: proc(slot: c.int) --- // Select and active a texture slot
EnableTexture :: proc(id: c.uint) --- // Enable texture
DisableTexture :: proc() --- // Disable texture
EnableTextureCubemap :: proc(id: c.uint) --- // Enable texture cubemap
DisableTextureCubemap :: proc() --- // Disable texture cubemap
TextureParameters :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
CubemapParameters :: proc(id: i32, param: c.int, value: c.int) --- // Set cubemap parameters (filter, wrap)
ActiveTextureSlot :: proc(slot: c.int) --- // Select and active a texture slot
EnableTexture :: proc(id: c.uint) --- // Enable texture
DisableTexture :: proc() --- // Disable texture
EnableTextureCubemap :: proc(id: c.uint) --- // Enable texture cubemap
DisableTextureCubemap :: proc() --- // Disable texture cubemap
TextureParameters :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
CubemapParameters :: proc(id: i32, param: c.int, value: c.int) --- // Set cubemap parameters (filter, wrap)
// Shader state
EnableShader :: proc(id: c.uint) --- // Enable shader program
DisableShader :: proc() --- // Disable shader program
EnableShader :: proc(id: c.uint) --- // Enable shader program
DisableShader :: proc() --- // Disable shader program
// Framebuffer state
EnableFramebuffer :: proc(id: c.uint) --- // Enable render texture (fbo)
DisableFramebuffer :: proc() --- // Disable render texture (fbo), return to default framebuffer
ActiveDrawBuffers :: proc(count: c.int) --- // Activate multiple draw color buffers
BlitFramebuffer :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer
EnableFramebuffer :: proc(id: c.uint) --- // Enable render texture (fbo)
DisableFramebuffer :: proc() --- // Disable render texture (fbo), return to default framebuffer
ActiveDrawBuffers :: proc(count: c.int) --- // Activate multiple draw color buffers
BlitFramebuffer :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer
// General render state
EnableColorBlend :: proc() --- // Enable color blending
DisableColorBlend :: proc() --- // Disable color blending
EnableDepthTest :: proc() --- // Enable depth test
DisableDepthTest :: proc() --- // Disable depth test
EnableDepthMask :: proc() --- // Enable depth write
DisableDepthMask :: proc() --- // Disable depth write
EnableBackfaceCulling :: proc() --- // Enable backface culling
DisableBackfaceCulling :: proc() --- // Disable backface culling
SetCullFace :: proc(mode: CullMode) --- // Set face culling mode
EnableScissorTest :: proc() --- // Enable scissor test
DisableScissorTest :: proc() --- // Disable scissor test
Scissor :: proc(x, y, width, height: c.int) --- // Scissor test
EnableWireMode :: proc() --- // Enable wire mode
EnablePointMode :: proc() --- // Enable point mode
DisableWireMode :: proc() --- // Disable wire and point modes
SetLineWidth :: proc(width: f32) --- // Set the line drawing width
GetLineWidth :: proc() -> f32 --- // Get the line drawing width
EnableSmoothLines :: proc() --- // Enable line aliasing
DisableSmoothLines :: proc() --- // Disable line aliasing
EnableStereoRender :: proc() --- // Enable stereo rendering
DisableStereoRender :: proc() --- // Disable stereo rendering
IsStereoRenderEnabled :: proc() -> bool --- // Check if stereo render is enabled
EnableColorBlend :: proc() --- // Enable color blending
DisableColorBlend :: proc() --- // Disable color blending
EnableDepthTest :: proc() --- // Enable depth test
DisableDepthTest :: proc() --- // Disable depth test
EnableDepthMask :: proc() --- // Enable depth write
DisableDepthMask :: proc() --- // Disable depth write
EnableBackfaceCulling :: proc() --- // Enable backface culling
DisableBackfaceCulling :: proc() --- // Disable backface culling
SetCullFace :: proc(mode: CullMode) --- // Set face culling mode
EnableScissorTest :: proc() --- // Enable scissor test
DisableScissorTest :: proc() --- // Disable scissor test
Scissor :: proc(x, y, width, height: c.int) --- // Scissor test
EnableWireMode :: proc() --- // Enable wire mode
EnablePointMode :: proc() --- // Enable point mode
DisableWireMode :: proc() --- // Disable wire and point modes
SetLineWidth :: proc(width: f32) --- // Set the line drawing width
GetLineWidth :: proc() -> f32 --- // Get the line drawing width
EnableSmoothLines :: proc() --- // Enable line aliasing
DisableSmoothLines :: proc() --- // Disable line aliasing
EnableStereoRender :: proc() --- // Enable stereo rendering
DisableStereoRender :: proc() --- // Disable stereo rendering
IsStereoRenderEnabled :: proc() -> bool --- // Check if stereo render is enabled
ClearColor :: proc(r, g, b, a: u8) --- // Clear color buffer with color
ClearScreenBuffers :: proc() --- // Clear used screen buffers (color and depth)
CheckErrors :: proc() --- // Check and log OpenGL error codes
SetBlendMode :: proc(mode: c.int) --- // Set blending mode
SetBlendFactors :: proc(glSrcFactor, glDstFactor, glEquation: c.int) --- // Set blending mode factor and equation (using OpenGL factors)
ClearColor :: proc(r, g, b, a: u8) --- // Clear color buffer with color
ClearScreenBuffers :: proc() --- // Clear used screen buffers (color and depth)
CheckErrors :: proc() --- // Check and log OpenGL error codes
SetBlendMode :: proc(mode: c.int) --- // Set blending mode
SetBlendFactors :: proc(glSrcFactor, glDstFactor, glEquation: c.int) --- // Set blending mode factor and equation (using OpenGL factors)
SetBlendFactorsSeparate :: proc(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha: c.int) --- // Set blending mode factors and equations separately (using OpenGL factors)
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
//------------------------------------------------------------------------------------
// rlgl initialization functions
@(link_prefix = "rlgl")
Init :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states)
@(link_prefix = "rlgl")
Close :: proc() --- // De-initialize rlgl (buffers, shaders, textures)
LoadExtensions :: proc(loader: rawptr) --- // Load OpenGL extensions (loader function required)
GetVersion :: proc() -> GlVersion --- // Get current OpenGL version
SetFramebufferWidth :: proc(width: c.int) --- // Set current framebuffer width
GetFramebufferWidth :: proc() -> c.int --- // Get default framebuffer width
SetFramebufferHeight :: proc(height: c.int) --- // Set current framebuffer height
GetFramebufferHeight :: proc() -> c.int --- // Get default framebuffer height
@(link_prefix="rlgl")
Init :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states)
@(link_prefix="rlgl")
Close :: proc() --- // De-initialize rlgl (buffers, shaders, textures)
LoadExtensions :: proc(loader: rawptr) --- // Load OpenGL extensions (loader function required)
GetVersion :: proc() -> GlVersion --- // Get current OpenGL version
SetFramebufferWidth :: proc(width: c.int) --- // Set current framebuffer width
GetFramebufferWidth :: proc() -> c.int --- // Get default framebuffer width
SetFramebufferHeight :: proc(height: c.int) --- // Set current framebuffer height
GetFramebufferHeight :: proc() -> c.int --- // Get default framebuffer height
GetTextureIdDefault :: proc() -> c.uint --- // Get default texture id
GetShaderIdDefault :: proc() -> c.uint --- // Get default shader id
GetTextureIdDefault :: proc() -> c.uint --- // Get default texture id
GetShaderIdDefault :: proc() -> c.uint --- // Get default shader id
GetShaderLocsDefault :: proc() -> [^]c.int --- // Get default shader locations
// Render batch management
// NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode
// but this render batch API is exposed in case of custom batches are required
LoadRenderBatch :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system
UnloadRenderBatch :: proc(batch: RenderBatch) --- // Unload render batch system
DrawRenderBatch :: proc(batch: ^RenderBatch) --- // Draw render batch data (Update->Draw->Reset)
SetRenderBatchActive :: proc(batch: ^RenderBatch) --- // Set the active render batch for rlgl (NULL for default internal)
DrawRenderBatchActive :: proc() --- // Update and draw internal render batch
CheckRenderBatchLimit :: proc(vCount: c.int) -> c.int --- // Check internal buffer overflow for a given number of vertex
LoadRenderBatch :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system
UnloadRenderBatch :: proc(batch: RenderBatch) --- // Unload render batch system
DrawRenderBatch :: proc(batch: ^RenderBatch) --- // Draw render batch data (Update->Draw->Reset)
SetRenderBatchActive :: proc(batch: ^RenderBatch) --- // Set the active render batch for rlgl (NULL for default internal)
DrawRenderBatchActive :: proc() --- // Update and draw internal render batch
CheckRenderBatchLimit :: proc(vCount: c.int) -> c.int --- // Check internal buffer overflow for a given number of vertex
SetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits
//------------------------------------------------------------------------------------------------------------------------
// Vertex buffers management
LoadVertexArray :: proc() -> c.uint --- // Load vertex array (vao) if supported
LoadVertexBuffer :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a vertex buffer attribute
LoadVertexBufferElement :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a new attributes element buffer
UpdateVertexBuffer :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update GPU buffer with new data
UpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data
UnloadVertexArray :: proc(vaoId: c.uint) ---
UnloadVertexBuffer :: proc(vboId: c.uint) ---
SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) ---
SetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) ---
SetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
DrawVertexArray :: proc(offset: c.int, count: c.int) ---
DrawVertexArrayElements :: proc(offset: c.int, count: c.int, buffer: rawptr) ---
DrawVertexArrayInstanced :: proc(offset: c.int, count: c.int, instances: c.int) ---
LoadVertexArray :: proc() -> c.uint --- // Load vertex array (vao) if supported
LoadVertexBuffer :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a vertex buffer attribute
LoadVertexBufferElement :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a new attributes element buffer
UpdateVertexBuffer :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update GPU buffer with new data
UpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data
UnloadVertexArray :: proc(vaoId: c.uint) ---
UnloadVertexBuffer :: proc(vboId: c.uint) ---
SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, offset: c.int) ---
SetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) ---
SetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
DrawVertexArray :: proc(offset: c.int, count: c.int) ---
DrawVertexArrayElements :: proc(offset: c.int, count: c.int, buffer: rawptr) ---
DrawVertexArrayInstanced :: proc(offset: c.int, count: c.int, instances: c.int) ---
DrawVertexArrayElementsInstanced :: proc(offset: c.int, count: c.int, buffer: rawptr, instances: c.int) ---
// Textures management
LoadTexture :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint --- // Load texture in GPU
LoadTextureDepth :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint --- // Load depth texture/renderbuffer (to be attached to fbo)
LoadTextureCubemap :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint --- // Load texture cubemap
UpdateTexture :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data
GetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) --- // Get OpenGL internal formats
GetPixelFormatName :: proc(format: c.uint) -> cstring --- // Get name string for pixel format
UnloadTexture :: proc(id: c.uint) --- // Unload texture from GPU memory
GenTextureMipmaps :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) --- // Generate mipmap data for selected texture
ReadTexturePixels :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr --- // Read texture pixel data
ReadScreenPixels :: proc(width, height: c.int) -> [^]byte --- // Read screen pixel data (color buffer)
LoadTexture :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint --- // Load texture in GPU
LoadTextureDepth :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint --- // Load depth texture/renderbuffer (to be attached to fbo)
LoadTextureCubemap :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint --- // Load texture cubemap
UpdateTexture :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data
GetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) --- // Get OpenGL internal formats
GetPixelFormatName :: proc(format: c.uint) -> cstring --- // Get name string for pixel format
UnloadTexture :: proc(id: c.uint) --- // Unload texture from GPU memory
GenTextureMipmaps :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) --- // Generate mipmap data for selected texture
ReadTexturePixels :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr --- // Read texture pixel data
ReadScreenPixels :: proc(width, height: c.int) -> [^]byte --- // Read screen pixel data (color buffer)
// Framebuffer management (fbo)
LoadFramebuffer :: proc(width, height: c.int) -> c.uint --- // Load an empty framebuffer
FramebufferAttach :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
FramebufferComplete :: proc(id: c.uint) -> bool --- // Verify framebuffer is complete
UnloadFramebuffer :: proc(id: c.uint) --- // Delete framebuffer from GPU
LoadFramebuffer :: proc() -> c.uint --- // Load an empty framebuffer
FramebufferAttach :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
FramebufferComplete :: proc(id: c.uint) -> bool --- // Verify framebuffer is complete
UnloadFramebuffer :: proc(id: c.uint) --- // Delete framebuffer from GPU
// Shaders management
LoadShaderCode :: proc(vsCode, fsCode: cstring) -> c.uint --- // Load shader from code strings
CompileShader :: proc(shaderCode: cstring, type: c.int) -> c.uint --- // Compile custom shader and return shader id (type: VERTEX_SHADER, FRAGMENT_SHADER, COMPUTE_SHADER)
LoadShaderProgram :: proc(vShaderId, fShaderId: c.uint) -> c.uint --- // Load custom shader program
UnloadShaderProgram :: proc(id: c.uint) --- // Unload shader program
GetLocationUniform :: proc(shaderId: c.uint, uniformName: cstring) -> c.int --- // Get shader location uniform
GetLocationAttrib :: proc(shaderId: c.uint, attribName: cstring) -> c.int --- // Get shader location attribute
SetUniform :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform
SetUniformMatrix :: proc(locIndex: c.int, mat: Matrix) --- // Set shader value matrix
SetUniformSampler :: proc(locIndex: c.int, textureId: c.uint) --- // Set shader value sampler
SetShader :: proc(id: c.uint, locs: [^]c.int) --- // Set shader currently active (id and locations)
LoadShaderCode :: proc(vsCode, fsCode: cstring) -> c.uint --- // Load shader from code strings
CompileShader :: proc(shaderCode: cstring, type: c.int) -> c.uint --- // Compile custom shader and return shader id (type: VERTEX_SHADER, FRAGMENT_SHADER, COMPUTE_SHADER)
LoadShaderProgram :: proc(vShaderId, fShaderId: c.uint) -> c.uint --- // Load custom shader program
UnloadShaderProgram :: proc(id: c.uint) --- // Unload shader program
GetLocationUniform :: proc(shaderId: c.uint, uniformName: cstring) -> c.int --- // Get shader location uniform
GetLocationAttrib :: proc(shaderId: c.uint, attribName: cstring) -> c.int --- // Get shader location attribute
SetUniform :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform
SetUniformMatrix :: proc(locIndex: c.int, mat: Matrix) --- // Set shader value matrix
SetUniformSampler :: proc(locIndex: c.int, textureId: c.uint) --- // Set shader value sampler
SetShader :: proc(id: c.uint, locs: [^]c.int) --- // Set shader currently active (id and locations)
// Compute shader management
LoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint --- // Load compute shader program
ComputeShaderDispatch :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
LoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint --- // Load compute shader program
ComputeShaderDispatch :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
// Shader buffer storage object management (ssbo)
LoadShaderBuffer :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint --- // Load shader storage buffer object (SSBO)
UnloadShaderBuffer :: proc(ssboId: c.uint) --- // Unload shader storage buffer object (SSBO)
UpdateShaderBuffer :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) --- // Update SSBO buffer data
BindShaderBuffer :: proc(id: c.uint, index: c.uint) --- // Bind SSBO buffer
ReadShaderBuffer :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) --- // Read SSBO buffer data (GPU->CPU)
CopyShaderBuffer :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers
GetShaderBufferSize :: proc(id: c.uint) -> c.uint --- // Get SSBO buffer size
LoadShaderBuffer :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint --- // Load shader storage buffer object (SSBO)
UnloadShaderBuffer :: proc(ssboId: c.uint) --- // Unload shader storage buffer object (SSBO)
UpdateShaderBuffer :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) --- // Update SSBO buffer data
BindShaderBuffer :: proc(id: c.uint, index: c.uint) --- // Bind SSBO buffer
ReadShaderBuffer :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) --- // Read SSBO buffer data (GPU->CPU)
CopyShaderBuffer :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers
GetShaderBufferSize :: proc(id: c.uint) -> c.uint --- // Get SSBO buffer size
// Buffer management
BindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) --- // Bind image texture
BindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) --- // Bind image texture
// Matrix state management
GetMatrixModelview :: proc() -> Matrix --- // Get internal modelview matrix
GetMatrixProjection :: proc() -> Matrix --- // Get internal projection matrix
GetMatrixTransform :: proc() -> Matrix --- // Get internal accumulated transform matrix
GetMatrixModelview :: proc() -> Matrix --- // Get internal modelview matrix
GetMatrixProjection :: proc() -> Matrix --- // Get internal projection matrix
GetMatrixTransform :: proc() -> Matrix --- // Get internal accumulated transform matrix
GetMatrixProjectionStereo :: proc(eye: c.int) -> Matrix --- // Get internal projection matrix for stereo render (selected eye)
GetMatrixViewOffsetStereo :: proc(eye: c.int) -> Matrix --- // Get internal view offset matrix for stereo render (selected eye)
SetMatrixProjection :: proc(proj: Matrix) --- // Set a custom projection matrix (replaces internal projection matrix)
SetMatrixModelview :: proc(view: Matrix) --- // Set a custom modelview matrix (replaces internal modelview matrix)
SetMatrixProjectionStereo :: proc(right, left: Matrix) --- // Set eyes projection matrices for stereo rendering
SetMatrixViewOffsetStereo :: proc(right, left: Matrix) --- // Set eyes view offsets matrices for stereo rendering
SetMatrixProjection :: proc(proj: Matrix) --- // Set a custom projection matrix (replaces internal projection matrix)
SetMatrixModelview :: proc(view: Matrix) --- // Set a custom modelview matrix (replaces internal modelview matrix)
SetMatrixProjectionStereo :: proc(right, left: Matrix) --- // Set eyes projection matrices for stereo rendering
SetMatrixViewOffsetStereo :: proc(right, left: Matrix) --- // Set eyes view offsets matrices for stereo rendering
// Quick and dirty cube/quad buffers load->draw->unload
LoadDrawCube :: proc() --- // Load and draw a cube

BIN
src_assets/test_level.blend (Stored with Git LFS)

Binary file not shown.

BIN
src_assets/test_level.blend1 (Stored with Git LFS)

Binary file not shown.