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 (inst
:model "assets/blender/testblend_blend/Bakery.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000)) :scale (1.000000 1.000000 1.000000))
(inst (inst
:model "assets/blender/test_level_blend/Plane.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (22.469545 22.469545 22.469545)) :scale (22.469545 22.469545 22.469545))
(inst (inst
:model "assets/blender/testblend_blend/Fire_Station.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000)) :scale (1.000000 1.000000 1.000000))
(inst (inst
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000)) :scale (1.000000 1.000000 1.000000))
(inst (inst
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000)) :scale (1.000000 1.000000 1.000000))
(inst (inst
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000)) :scale (1.000000 1.000000 1.000000))
(inst (inst
:model "assets/blender/testblend_blend/Green_House.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000)) :scale (1.000000 1.000000 1.000000))
(inst (inst
:model "assets/blender/testblend_blend/Hotel.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.000000 1.000000)) :scale (1.000000 1.000000 1.000000))
(inst (inst
:model "assets/blender/test_level_blend/NurbsPath.glb" :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) :rot (0.000000 0.000000 0.000000 1.000000)
:scale (1.000000 1.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 bpy
import os import os
import pathlib import pathlib
import contextlib
# Ensure blend file is saved # Ensure blend file is saved
blend_filepath = bpy.data.filepath blend_filepath = bpy.data.filepath
@ -9,6 +10,26 @@ if not blend_filepath:
assert bpy.context.scene is not None 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: 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))) 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) full_export_path = os.path.join(assets_path, export_path)
pathlib.Path(os.path.dirname(full_export_path)).mkdir(parents=True, exist_ok=True) pathlib.Path(os.path.dirname(full_export_path)).mkdir(parents=True, exist_ok=True)
bpy.ops.object.select_all(action='DESELECT') if obj.instance_type == 'COLLECTION' and obj.instance_collection:
obj.select_set(True) 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.ops.export_scene.gltf(filepath=full_export_path, use_selection=True, export_apply=True)
bpy.context.view_layer.objects.active = obj
bpy.ops.export_scene.gltf(filepath=full_export_path, use_selection=True, export_apply=True)
print(f"Exported {obj.name} -> {export_path}") print(f"Exported {obj.name} -> {export_path}")
# Collect all visible, non-hidden objects in the scene # Collect all visible, non-hidden objects in the scene
@ -70,7 +96,7 @@ for obj in visible_objects:
instance_sexpr = ( instance_sexpr = (
'(inst' '(inst'
f'\n\t:model "assets/{model_path}"' 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: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}))' 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:mem"
import "core:strings" import "core:strings"
import "core:sync" import "core:sync"
import "libs:tracy"
// When enabled name globals will be initialized automatically // When enabled name globals will be initialized automatically
NAME_STATIC_INIT :: #config(NAME_STATIC_INIT, true) NAME_STATIC_INIT :: #config(NAME_STATIC_INIT, true)
@ -61,23 +62,36 @@ when NAME_STATIC_INIT {
} }
from_string :: proc(str: string) -> Name { from_string :: proc(str: string) -> Name {
sync.atomic_rw_mutex_guard(&global_container.lock) tracy.Zone()
existing, ok := global_container.names_lookup[str]
existing: Name
ok: bool
{
sync.atomic_rw_mutex_shared_guard(&global_container.lock)
existing, ok = global_container.names_lookup[str]
}
if ok { if ok {
return existing return existing
} else { } else {
new_str := strings.clone( sync.atomic_rw_mutex_guard(&global_container.lock)
new_str := strings.clone_to_cstring(
str, str,
mem.dynamic_arena_allocator(&global_container.names_allocator), mem.dynamic_arena_allocator(&global_container.names_allocator),
) )
idx := u32(len(global_container.names_array)) 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) global_container.names_lookup[str] = Name(idx)
return Name(idx) return Name(idx)
} }
} }
from_cstring :: proc(str: cstring) -> Name {
return from_string(string(str))
}
to_string :: proc(name: Name) -> string { to_string :: proc(name: Name) -> string {
tracy.Zone()
sync.atomic_rw_mutex_shared_guard(&global_container.lock) sync.atomic_rw_mutex_shared_guard(&global_container.lock)
return global_container.names_array[name] 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:encoding/csv"
import "core:io" import "core:io"
import "core:log" import "core:log"
import lg "core:math/linalg"
import "core:strconv" 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 { CSV_Parse_Error :: enum {
Ok, Ok,
@ -69,7 +75,7 @@ parse_csv_2d :: proc(
data: []byte, data: []byte,
allocator := context.allocator, allocator := context.allocator,
) -> ( ) -> (
curve: Loaded_Curve_2D, curve: Curve_2D,
error: CSV_Parse_Error, error: CSV_Parse_Error,
) { ) {
bytes_reader: bytes.Reader bytes_reader: bytes.Reader
@ -125,8 +131,400 @@ parse_csv_2d :: proc(
append(&tmp_result, [2]f32{f32(key), f32(val)}) append(&tmp_result, [2]f32{f32(key), f32(val)})
} }
curve.points = make([][2]f32, len(tmp_result), allocator) curve = make([][2]f32, len(tmp_result), allocator)
copy(curve.points, tmp_result[:]) copy(curve, tmp_result[:])
return 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) { 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) 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_destroy(world, scene)
scene.scene_desc_path = path_name 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) sim_state := physics.get_sim_state(&world.physics_scene)
for inst in desc.instances { for inst, i in desc.instances {
physics.add_level_geom( scene.level_geoms[i] = physics.add_level_geom(
sim_state, sim_state,
physics.Level_Geom_Config { physics.Level_Geom_Config {
position = inst.pos, position = inst.pos,
rotation = inst.rot, 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) { scene_copy :: proc(dst, src: ^Scene) {
tracy.Zone()
dst.scene_desc_path = src.scene_desc_path dst.scene_desc_path = src.scene_desc_path
if len(dst.level_geoms) != len(src.level_geoms) { if len(dst.level_geoms) != len(src.level_geoms) {
delete(dst.level_geoms) delete(dst.level_geoms)
@ -101,7 +104,7 @@ scene_draw :: proc(scene: ^Scene) {
render.draw_model( render.draw_model(
assets.get_model(&g_mem.assetman, name.to_cstring(geo.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() tracy.Zone()
defer tracy.FrameMark() defer tracy.FrameMark()
assets.assetman_tick(&g_mem.assetman)
update() update()
draw() draw()
@ -1474,7 +1479,6 @@ game_init :: proc() {
init_physifs_raylib_callbacks() init_physifs_raylib_callbacks()
assets.assetman_init(&g_mem.assetman) assets.assetman_init(&g_mem.assetman)
assets.init(&g_mem.assetman)
editor_state_init(&g_mem.es, 100) editor_state_init(&g_mem.es, 100)
runtime_world_init(&g_mem.runtime_world, DEV_BUILD ? 100 : 2) runtime_world_init(&g_mem.runtime_world, DEV_BUILD ? 100 : 2)

View File

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

View File

@ -1,5 +1,6 @@
package physics package physics
import "base:runtime"
import "bvh" import "bvh"
import "common:name" import "common:name"
import "core:fmt" import "core:fmt"
@ -9,6 +10,7 @@ import lg "core:math/linalg"
import "core:mem" import "core:mem"
import "core:slice" import "core:slice"
import "core:strings" import "core:strings"
import "game:assets"
import "game:debug" import "game:debug"
import he "game:halfedge" import he "game:halfedge"
import "game:ui" 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) { draw_debug_scene :: proc(scene: ^Scene, debug_state: ^Debug_State) {
tracy.Zone() tracy.Zone()
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
sim_state := get_sim_state(scene) 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 // Static_TLAS
if true && sim_state.static_tlas.built { 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) it := bvh.iterator(&sim_state.static_tlas.bvh_tree)
for node in bvh.iterator_next(&it) { if false {
if bvh.is_leaf_node(node) { for node in bvh.iterator_next(&it) {
prim_start := node.child_or_prim_start 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 { 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_handle := index_to_level_geom(int(level_geom_idx))
level_geom := get_level_geom(sim_state, level_geom_handle) level_geom := get_level_geom(sim_state, level_geom_handle)
blas := get_level_geom_blas(sim_state, level_geom_handle) blas, vertices, indices := get_level_geom_data(
vertices, indices := get_level_geom_data(sim_state, level_geom_handle) sim_state,
&sim_cache,
level_geom_handle,
)
bvh.debug_draw_bvh_bounds_mesh( bvh.debug_draw_bvh_bounds_mesh(
&blas, &blas,
bvh.Mesh{vertices = vertices, indices = indices}, bvh.Mesh{vertices = vertices, indices = indices},
level_geom.x, level_geom.x,
0, 0,
) )
}
} }
} }
} }

View File

@ -300,6 +300,7 @@ body_get_convex_shapes_world :: proc(
level_geom_get_convex_shape :: proc( level_geom_get_convex_shape :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
level_geom_handle: Level_Geom_Handle, level_geom_handle: Level_Geom_Handle,
tri_idx: int, tri_idx: int,
allocator := context.temp_allocator, allocator := context.temp_allocator,
@ -307,7 +308,7 @@ level_geom_get_convex_shape :: proc(
mesh: collision.Convex, mesh: collision.Convex,
) { ) {
level_geom := get_level_geom(sim_state, level_geom_handle) 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( return collision.double_sided_triangle_to_convex(
get_transformed_triangle(vertices, indices, tri_idx, level_geom.x, level_geom.q), get_transformed_triangle(vertices, indices, tri_idx, level_geom.x, level_geom.q),
allocator, allocator,
@ -353,7 +354,7 @@ rotate_extent :: proc(extent: Vec3, q: Quat) -> Vec3 {
return result 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.center = lg.quaternion_mul_vector3(q, local_aabb.center) + x
aabb.extent = rotate_extent(local_aabb.extent, q) 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 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) { input_shape_get_aabb :: proc(shapes: []Input_Shape) -> (aabb: AABB) {
min, max: Vec3 = max(f32), min(f32) min, max: Vec3 = max(f32), min(f32)

View File

@ -4,7 +4,6 @@ import "bvh"
import "collision" import "collision"
import "common:name" import "common:name"
import lg "core:math/linalg" import lg "core:math/linalg"
import "core:strings"
import "game:assets" import "game:assets"
import "game:container/spanpool" import "game:container/spanpool"
import "libs:tracy" import "libs:tracy"
@ -476,9 +475,6 @@ Suspension_Constraint_Ptr :: #soa^#soa[]Suspension_Constraint
Engine_Ptr :: ^Engine Engine_Ptr :: ^Engine
Level_Geom_Ptr :: ^Level_Geom 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: #soa[1]Suspension_Constraint
_invalid_suspension_constraint_slice := _invalid_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 /// Returns pointer to soa slice. NEVER STORE IT
get_body :: proc(sim_state: ^Sim_State, handle: Body_Handle) -> Body_Ptr { 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 index := int(handle) - 1
if index < 0 || index >= len(sim_state.bodies_slice) { if index < 0 || index >= len(sim_state.bodies_slice) {
_invalid_body_slice = _invalid_body[:]
_invalid_body_slice[0] = { _invalid_body_slice[0] = {
alive = true, alive = true,
q = lg.QUATERNIONF32_IDENTITY, q = lg.QUATERNIONF32_IDENTITY,
@ -602,7 +602,7 @@ Engine_Config :: struct {
axle: Drive_Axle_Config, axle: Drive_Axle_Config,
} }
Level_Geometry_Asset :: distinct string Level_Geometry_Asset :: distinct name.Name
Level_Geometry_Mesh :: struct { Level_Geometry_Mesh :: struct {
vertices: []Vec3, vertices: []Vec3,
@ -949,8 +949,10 @@ get_level_geom :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) -> Leve
get_level_geom_data :: proc( get_level_geom_data :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
handle: Level_Geom_Handle, handle: Level_Geom_Handle,
) -> ( ) -> (
blas: bvh.BVH,
vertices: []Vec3, vertices: []Vec3,
indices: []u16, indices: []u16,
) { ) {
@ -958,17 +960,28 @@ get_level_geom_data :: proc(
switch s in level_geom.source { switch s in level_geom.source {
case Level_Geom_Source_Local: 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) vertices = spanpool.resolve_slice(&sim_state.geometry_vertices_pool, s.geometry.vertices)
indices = spanpool.resolve_slice(&sim_state.geometry_indices_pool, s.geometry.indices) indices = spanpool.resolve_slice(&sim_state.geometry_indices_pool, s.geometry.indices)
case Level_Geom_Source_Asset: case Level_Geom_Source_Asset:
loaded_bvh, reloaded := assets.get_bvh( loaded_bvh, ok := sim_cache.level_geom_asset_bvh[handle]
sim_state.scene.assetman,
strings.unsafe_string_to_cstring(name.to_string(s.assetpath)), if !ok {
) reloaded: bool
if reloaded { loaded_bvh, reloaded = assets.get_bvh(sim_state.scene.assetman, s.assetpath)
level_geom.aabb = bvh_aabb_to_phys_aabb(loaded_bvh.aabb) if reloaded {
level_geom.aabb = aabb_transform(level_geom.aabb, level_geom.x, level_geom.q) 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 vertices = loaded_bvh.vertices
indices = loaded_bvh.indices indices = loaded_bvh.indices
} }
@ -976,28 +989,6 @@ get_level_geom_data :: proc(
return 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( update_level_geom_from_config :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
level_geom: Level_Geom_Ptr, 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 level_geom.source = source
case Level_Geometry_Asset: case Level_Geometry_Asset:
level_geom.source = Level_Geom_Source_Asset { level_geom.source = Level_Geom_Source_Asset {
assetpath = name.from_string(string(s)), assetpath = name.Name(s),
} }
bvh, _ := assets.get_bvh( bvh, _ := assets.get_bvh(sim_state.scene.assetman, name.Name(s))
sim_state.scene.assetman,
strings.unsafe_string_to_cstring(string(s)),
)
level_geom.aabb = AABB { level_geom.aabb = AABB {
center = (bvh.aabb.max + bvh.aabb.min) * 0.5, center = (bvh.aabb.max + bvh.aabb.min) * 0.5,
extent = (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) spanpool.free(&sim_state.blas_primitives_pool, s.blas.primitives)
case Level_Geom_Source_Asset: 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 { _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 lg "core:math/linalg"
import "core:math/rand" import "core:math/rand"
import "core:slice" import "core:slice"
import "game:assets"
import "game:debug" import "game:debug"
import he "game:halfedge" import he "game:halfedge"
import "libs:tracy" import "libs:tracy"
@ -174,8 +175,10 @@ dynamic_tlas_destroy :: proc(dyn_tlas: ^Dynamic_TLAS) {
} }
} }
raycasts_level :: proc( raycasts_level :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
tlas: ^Static_TLAS, tlas: ^Static_TLAS,
origin, dir: Vec3, origin, dir: Vec3,
distance := max(f32), distance := max(f32),
@ -201,32 +204,31 @@ raycasts_level :: proc(
int(tlas.bvh_tree.primitives[leaf_node.child_or_prim_start + j]), int(tlas.bvh_tree.primitives[leaf_node.child_or_prim_start + j]),
) )
level_geom := get_level_geom(sim_state, level_geom_handle) level_geom := get_level_geom(sim_state, level_geom_handle)
blas := get_level_geom_blas(sim_state, level_geom_handle) blas, vertices, indices := get_level_geom_data(sim_state, sim_cache, level_geom_handle)
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
// TODO: transform ray into blas space and back // 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 blas_leaf_node in bvh.iterator_intersect_leaf_next(&blas_it) {
for k in 0 ..< blas_leaf_node.prim_len { for k in 0 ..< blas_leaf_node.prim_len {
tri_idx := int(blas.primitives[blas_leaf_node.child_or_prim_start + k]) tri_idx := int(blas.primitives[blas_leaf_node.child_or_prim_start + k])
tri := get_transformed_triangle( tri := get_triangle(vertices, indices, tri_idx)
vertices,
indices,
tri_idx,
level_geom.x,
level_geom.q,
)
hit_t, tmp_normal, _, ok := collision.intersect_ray_triangle( hit_t, tmp_normal, _, ok := collision.intersect_ray_triangle(
{origin, origin + dir}, {local_ray.origin, local_ray.origin + local_ray.dir},
tri, tri,
) )
if ok && (!hit || hit_t < t) { if ok && (!hit || hit_t < t) {
t = hit_t t = hit_t
normal = tmp_normal normal = lg.quaternion_mul_vector3(level_geom.q, tmp_normal)
hit = true hit = true
} }
} }
@ -294,6 +296,7 @@ raycast_bodies :: proc(
raycast :: proc( raycast :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: ^Static_TLAS, static_tlas: ^Static_TLAS,
dyn_tlas: ^Dynamic_TLAS, dyn_tlas: ^Dynamic_TLAS,
origin, dir: Vec3, origin, dir: Vec3,
@ -305,7 +308,7 @@ raycast :: proc(
) { ) {
t = distance 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) t2, normal2, hit2 := raycast_bodies(sim_state, dyn_tlas, origin, dir, t)
hit = hit1 || hit2 hit = hit1 || hit2
@ -329,6 +332,14 @@ raycast :: proc(
return 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) { 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] 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] 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( remove_invalid_contacts :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: Static_TLAS, static_tlas: Static_TLAS,
dyn_tlas: Dynamic_TLAS, dyn_tlas: Dynamic_TLAS,
) { ) {
@ -394,7 +406,11 @@ remove_invalid_contacts :: proc(
if !should_remove { if !should_remove {
tri_idx := int(contact.local_tri_idx) 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) should_remove |= tri_idx * 3 >= len(indices)
if !should_remove { if !should_remove {
@ -453,6 +469,7 @@ remove_invalid_contacts :: proc(
// TODO: free intermediate temp allocs // TODO: free intermediate temp allocs
find_new_contacts :: proc( find_new_contacts :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: ^Static_TLAS, static_tlas: ^Static_TLAS,
dyn_tlas: ^Dynamic_TLAS, dyn_tlas: ^Dynamic_TLAS,
) { ) {
@ -559,10 +576,16 @@ find_new_contacts :: proc(
) )
level_geom := get_level_geom(sim_state, level_geom_handle) level_geom := get_level_geom(sim_state, level_geom_handle)
if level_geom.alive { if level_geom.alive {
blas := get_level_geom_blas(sim_state, level_geom_handle) blas, vertices, indices := get_level_geom_data(
vertices, indices := get_level_geom_data(sim_state, level_geom_handle) 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 blas_leaf_node in bvh.iterator_intersect_leaf_next(&blas_it) {
for k in 0 ..< blas_leaf_node.prim_len { for k in 0 ..< blas_leaf_node.prim_len {
tri_idx := int( tri_idx := int(
@ -653,9 +676,16 @@ simulate :: proc(
prune_immediate(scene) prune_immediate(scene)
copy_sim_state(get_next_sim_state(scene), get_sim_state(scene)) copy_sim_state(get_next_sim_state(scene), get_sim_state(scene))
sim_state := get_next_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 num_steps := 0
switch step_mode { switch step_mode {
case .Accumulated_Time: case .Accumulated_Time:
@ -666,11 +696,11 @@ simulate :: proc(
state.accumulated_time -= config.timestep state.accumulated_time -= config.timestep
if num_steps < MAX_STEPS { if num_steps < MAX_STEPS {
simulate_step(scene, sim_state, config) simulate_step(scene, sim_state, &sim_cache, config)
} }
} }
case .Single: 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 num_steps += 1
} }
@ -718,7 +748,7 @@ Contact :: struct {
applied_normal_correction: [4]f32, 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() tracy.Zone()
temp := runtime.default_temp_allocator_temp_begin() 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: case .Body_vs_Level:
level_geom_handle := Level_Geom_Handle(contact.b) level_geom_handle := Level_Geom_Handle(contact.b)
level_geom := get_level_geom(sim_state, level_geom_handle) 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( tri := get_transformed_triangle(
vertices, vertices,
indices, indices,
@ -1232,6 +1262,7 @@ calculate_ground_vel :: proc(
pgs_solve_suspension :: proc( pgs_solve_suspension :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: ^Static_TLAS, static_tlas: ^Static_TLAS,
dyn_tlas: ^Dynamic_TLAS, dyn_tlas: ^Dynamic_TLAS,
config: Solver_Config, config: Solver_Config,
@ -1249,6 +1280,7 @@ pgs_solve_suspension :: proc(
dir := body_local_to_world_vec(body, v.rel_dir) dir := body_local_to_world_vec(body, v.rel_dir)
v.hit_t, v.hit_normal, v.hit = raycast( v.hit_t, v.hit_normal, v.hit = raycast(
sim_state, sim_state,
sim_cache,
static_tlas, static_tlas,
dyn_tlas, dyn_tlas,
wheel_world_pos, wheel_world_pos,
@ -1438,6 +1470,7 @@ pgs_solve_suspension :: proc(
pgs_substep :: proc( pgs_substep :: proc(
sim_state: ^Sim_State, sim_state: ^Sim_State,
sim_cache: ^Sim_Cache,
static_tlas: ^Static_TLAS, static_tlas: ^Static_TLAS,
dyn_tlas: ^Dynamic_TLAS, dyn_tlas: ^Dynamic_TLAS,
config: Solver_Config, config: Solver_Config,
@ -1559,7 +1592,7 @@ pgs_substep :: proc(
apply_bias := true apply_bias := true
pgs_solve_contacts(sim_state, config, dt, inv_dt, apply_bias) pgs_solve_contacts(sim_state, config, dt, inv_dt, apply_bias)
pgs_solve_engines(sim_state, config, dt, inv_dt) 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) { for i in 0 ..< len(sim_state.bodies_slice) {
body := &sim_state.bodies_slice[i] body := &sim_state.bodies_slice[i]
@ -1600,7 +1633,12 @@ pgs_substep :: proc(
// pgs_solve_suspension(sim_state, config, dt, inv_dt, apply_bias) // 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() tracy.Zone()
substeps := config.substreps_minus_one + 1 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_static_tlas(sim_state, &sim_state.static_tlas)
build_dynamic_tlas(sim_state, config, &sim_state.dynamic_tlas) build_dynamic_tlas(sim_state, config, &sim_state.dynamic_tlas)
remove_invalid_contacts(sim_state, sim_state.static_tlas, sim_state.dynamic_tlas) remove_invalid_contacts(sim_state, sim_cache, sim_state.static_tlas, sim_state.dynamic_tlas)
find_new_contacts(sim_state, &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_state.static_tlas) update_contacts(sim_state, sim_cache, &sim_state.static_tlas)
Solver :: enum { Solver :: enum {
XPBD, XPBD,
@ -1634,6 +1672,7 @@ simulate_step :: proc(scene: ^Scene, sim_state: ^Sim_State, config: Solver_Confi
for _ in 0 ..< substeps { for _ in 0 ..< substeps {
pgs_substep( pgs_substep(
sim_state, sim_state,
sim_cache,
&sim_state.static_tlas, &sim_state.static_tlas,
&sim_state.dynamic_tlas, &sim_state.dynamic_tlas,
config, config,

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: Quaternion
quat.x = source.x quat.x = source.x
quat.y = source.z quat.y = source.y
quat.z = source.z quat.z = source.z
quat.w = 1 quat.w = 1
@ -831,8 +831,8 @@ fmaxf :: proc "contextless" (x, y: f32) -> f32 {
return x return x
} }
if math.signbit(x) != math.signbit(y) { if math.sign_bit(x) != math.sign_bit(y) {
return y if math.signbit(x) else x return y if math.sign_bit(x) else x
} }
return y if x < y else x return y if x < y else x

View File

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