182 lines
5.2 KiB
Odin
182 lines
5.2 KiB
Odin
package model
|
|
|
|
import "../image"
|
|
import "../texture"
|
|
import "../vertex"
|
|
import "core:fmt"
|
|
import glm "core:math/linalg/glsl"
|
|
import "core:os"
|
|
import "core:strconv"
|
|
import "core:strings"
|
|
|
|
Error :: union {
|
|
os.Error,
|
|
string,
|
|
}
|
|
|
|
Index_Range :: struct {
|
|
first: u32,
|
|
count: i32,
|
|
}
|
|
|
|
Material :: struct {
|
|
name: string,
|
|
texture: texture.Texture,
|
|
ranges: [dynamic]Index_Range,
|
|
// first_index: u32,
|
|
// index_count: i32,
|
|
}
|
|
|
|
load_mtl_string :: proc(text: string, texture_map: map[string]string) -> (materials: map[string]Material) {
|
|
lines := strings.split_lines(text)
|
|
default, _ := texture.load(image.default_image)
|
|
current_material: string
|
|
for line in lines {
|
|
parts := strings.split(line, " ")
|
|
switch parts[0] {
|
|
case "newmtl":
|
|
current_material = strings.join(parts[1:], " ")
|
|
materials[current_material] = Material {
|
|
name = current_material,
|
|
texture = default,
|
|
}
|
|
case "map_Kd":
|
|
filename := strings.join(parts[1:], " ")
|
|
img_data := texture_map[filename]
|
|
fmt.printfln("\"{}\" = #load(\"{}\")", filename, filename)
|
|
tex, err := texture.load(image.load_string(img_data))
|
|
mat := materials[current_material]
|
|
mat.texture = tex
|
|
materials[current_material] = mat
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
load_mtl :: proc(filename: string, texture_map: map[string]string) -> (materials: map[string]Material) {
|
|
bytes, _ := os.read_entire_file_or_err(filename)
|
|
|
|
lines := strings.split_lines(string(bytes))
|
|
default, _ := texture.load(image.default_image)
|
|
current_material: string
|
|
for line in lines {
|
|
parts := strings.split(line, " ")
|
|
switch parts[0] {
|
|
case "newmtl":
|
|
current_material = strings.join(parts[1:], " ")
|
|
materials[current_material] = Material {
|
|
name = current_material,
|
|
texture = default,
|
|
}
|
|
case "map_Kd":
|
|
filename := strings.join(parts[1:], " ")
|
|
// img_data := texture_map[filename]
|
|
// fmt.printfln("\"{}\" = #load(\"{}\")", filename, filename)
|
|
tex, err := texture.load(image.load(filename))
|
|
mat := materials[current_material]
|
|
mat.texture = tex
|
|
materials[current_material] = mat
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
load_obj_string :: proc(
|
|
text: string,
|
|
mtl: string,
|
|
textures_map: map[string]string,
|
|
) -> (
|
|
Maybe(Model),
|
|
Error,
|
|
) {
|
|
vertices: [dynamic]vertex.Vertex
|
|
texcoords: [dynamic]glm.vec2
|
|
indices: [dynamic]u32
|
|
materials: map[string]Material
|
|
|
|
current_material: string
|
|
current_range := 0
|
|
|
|
lines := strings.split_lines(text)
|
|
for line in lines {
|
|
parts := strings.split(line, " ")
|
|
switch parts[0] {
|
|
case "v":
|
|
vert: vertex.Vertex
|
|
vert.pos = glm.vec4(1)
|
|
for part, i in parts[1:] {
|
|
val, ok := strconv.parse_f32(part)
|
|
if !ok {
|
|
return nil, "Failed to parse f32"
|
|
}
|
|
vert.pos[i] = val
|
|
}
|
|
|
|
append(&vertices, vert)
|
|
case "vt":
|
|
texcoord: glm.vec2
|
|
for part, i in parts[1:] {
|
|
val, ok := strconv.parse_f32(part)
|
|
if !ok {
|
|
return nil, "Failed to parse f32"
|
|
}
|
|
texcoord[i] = val
|
|
}
|
|
|
|
append(&texcoords, texcoord)
|
|
case "f":
|
|
for part in parts[1:] {
|
|
slashes := strings.split(part, "/")
|
|
v, ok := strconv.parse_u64(slashes[0])
|
|
if !ok {
|
|
return nil, "Failed to parse u64"
|
|
}
|
|
v -= 1
|
|
|
|
if len(slashes) > 1 {
|
|
vt: u64
|
|
vt, ok = strconv.parse_u64(slashes[1])
|
|
if !ok {
|
|
return nil, "Failed to parse u64"
|
|
}
|
|
vt -= 1
|
|
|
|
vertices[v].texcoord = texcoords[vt]
|
|
}
|
|
|
|
append(&indices, u32(v))
|
|
if current_material != "" {
|
|
mtl := materials[current_material]
|
|
mtl.ranges[len(mtl.ranges) - 1].count += 1
|
|
materials[current_material] = mtl
|
|
}
|
|
}
|
|
case "mtllib":
|
|
filename := strings.join(parts[1:], " ")
|
|
mtl_materials := load_mtl_string(mtl, textures_map)
|
|
for material_name, material in mtl_materials {
|
|
materials[material_name] = material
|
|
}
|
|
case "usemtl":
|
|
current_material = strings.join(parts[1:], " ")
|
|
mtl := materials[current_material]
|
|
append(&mtl.ranges, Index_Range{first = u32(len(indices))})
|
|
materials[current_material] = mtl
|
|
}
|
|
}
|
|
|
|
model := create(vertices[:], indices[:], materials)
|
|
|
|
return model, nil
|
|
}
|
|
|
|
// load_obj :: proc(filename: string) -> (Maybe(Model), Error) {
|
|
// bytes, err := os.read_entire_file_or_err(filename)
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
//
|
|
// return load_obj_string(string(bytes))
|
|
// }
|