odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

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 }