main.odin (4534B)
1 package ufbx_test 2 3 import "../ufbx" 4 import "core:fmt" 5 import rl "vendor:raylib" 6 import "core:math" 7 8 main :: proc() { 9 rl.InitWindow(1280, 720, "ufbx test") 10 meshes := load_fbx_meshes("box.fbx") 11 12 camera := rl.Camera3D { 13 position = {2, 2, -5}, 14 target = {0, 0, 0}, 15 up = {0, 1, 0}, 16 fovy = 70, 17 projection = .PERSPECTIVE, 18 } 19 20 default_material := rl.LoadMaterialDefault() 21 22 for !rl.WindowShouldClose() { 23 rl.BeginDrawing() 24 rl.ClearBackground(rl.SKYBLUE) 25 rl.BeginMode3D(camera) 26 t := f32(rl.GetTime()) 27 28 for m in meshes { 29 pos := rl.MatrixTranslate(math.cos(t), math.sin(t*2+20), 0) 30 rot := rl.MatrixRotate({1, 2, 3}, t*3) 31 scl := rl.MatrixScale(1 + math.cos(t) * 0.5, 1 + math.sin(t*5+123) * 0.5, 1) 32 rl.DrawMesh(m, default_material, pos * rot * scl) 33 } 34 35 rl.EndMode3D() 36 rl.EndDrawing() 37 free_all(context.temp_allocator) 38 } 39 40 for m in meshes { 41 rl.UnloadMesh(m) 42 } 43 44 delete(meshes) 45 rl.CloseWindow() 46 } 47 48 /* 49 Loads raylib meshes using ufbx. 50 51 The returned array is allocated using `allocator`. The meshes themselves are 52 allocated using raylib's allocator, destroy each using `rl.UnloadMesh(mesh)`. 53 54 Does triangulation using `ufbx.triangulate_face`. Note that the triangulated 55 faces are put into an `vertices` array. That's an intermediate array, used for 56 de-duplicating vertices and also calculating indices using. That's all done 57 using `ufbx.generate_indices`. 58 */ 59 load_fbx_meshes :: proc(filename: string, allocator := context.allocator, loc := #caller_location) -> []rl.Mesh { 60 opts: ufbx.Load_Opts 61 error: ufbx.Error 62 scene := ufbx.load_file(fmt.ctprint(filename), &opts, &error) 63 64 if scene == nil { 65 fmt.eprintf("Failed loading model %v, error: %v", filename, error.description.data) 66 return {} 67 } 68 69 res := make([dynamic]rl.Mesh, allocator, loc) 70 71 for i in 0..<scene.nodes.count { 72 node := scene.nodes.data[i] 73 74 if node.mesh == nil { 75 continue 76 } 77 78 m := node.mesh 79 80 Vertex :: struct { 81 pos: [3]f32, 82 normal: [3]f32, 83 texcoord: [2]f32, 84 color: [4]f32, 85 } 86 87 vertices := make([]Vertex, m.num_triangles * 3, context.temp_allocator) 88 num_vertices := 0 89 face_indices := make([]u32, m.max_face_triangles * 3, context.temp_allocator) 90 91 for fidx in 0..<m.faces.count { 92 f := m.faces.data[fidx] 93 num_face_triangles := ufbx.triangulate_face(raw_data(face_indices), len(face_indices), m, f) 94 95 for tidx in 0..<num_face_triangles*3 { 96 tris_idx := face_indices[tidx] 97 98 get_or_default :: proc(vertex: $T, idx: u32, default: $R) -> R { 99 if !vertex.exists { 100 return default 101 } 102 103 return vertex.values.data[vertex.indices.data[idx]] 104 } 105 106 vertices[num_vertices] = { 107 pos = m.vertex_position.values.data[m.vertex_position.indices.data[tris_idx]], 108 color = get_or_default(m.vertex_color, tris_idx, [4]f32 {1, 1, 1, 1}), 109 texcoord = get_or_default(m.vertex_uv, tris_idx, [2]f32 {0, 0}), 110 normal = get_or_default(m.vertex_normal, tris_idx, [3]f32 {0, 0, 0}), 111 } 112 113 num_vertices += 1 114 } 115 } 116 117 vertex_stream := ufbx.Vertex_Stream { 118 data = raw_data(vertices), 119 vertex_count = len(vertices), 120 vertex_size = size_of(Vertex), 121 } 122 123 num_indices := m.num_triangles * 3 124 indices := make([]u32, num_indices, context.temp_allocator) 125 num_vertices = int(ufbx.generate_indices(&vertex_stream, 1, raw_data(indices), num_indices, nil, nil)) 126 vertices = vertices[:num_vertices] 127 128 rm := rl.Mesh { 129 triangleCount = i32(m.num_triangles), 130 vertexCount = i32(len(vertices)), 131 indices = ([^]u16)(rl.MemAlloc(u32(size_of(u16) * num_indices))), 132 vertices = ([^]f32)(rl.MemAlloc(u32(size_of(f32) * 3 * len(vertices)))), 133 colors = ([^]u8)(rl.MemAlloc(u32(size_of(u8) * 4 * len(vertices)))), 134 normals = ([^]f32)(rl.MemAlloc(u32(size_of(f32) * 3 * len(vertices)))), 135 texcoords = ([^]f32)(rl.MemAlloc(u32(size_of(f32) * 2 * len(vertices)))), 136 } 137 138 for i, iidx in indices { 139 rm.indices[iidx] = u16(i) 140 } 141 142 for v, vidx in vertices { 143 rm.vertices[vidx * 3 + 0] = v.pos.x 144 rm.vertices[vidx * 3 + 1] = v.pos.y 145 rm.vertices[vidx * 3 + 2] = v.pos.z 146 147 rm.normals[vidx * 3 + 0] = v.normal.x 148 rm.normals[vidx * 3 + 1] = v.normal.y 149 rm.normals[vidx * 3 + 2] = v.normal.z 150 151 rm.texcoords[vidx * 2 + 0] = v.texcoord.x 152 rm.texcoords[vidx * 2 + 1] = v.texcoord.y 153 154 rm.colors[vidx * 4 + 0] = u8(v.color.r*255) 155 rm.colors[vidx * 4 + 1] = u8(v.color.g*255) 156 rm.colors[vidx * 4 + 2] = u8(v.color.b*255) 157 rm.colors[vidx * 4 + 3] = u8(v.color.a*255) 158 } 159 160 rl.UploadMesh(&rm, false) 161 append(&res, rm) 162 } 163 164 ufbx.free_scene(scene) 165 return res[:] 166 }