Skip to content

Instantly share code, notes, and snippets.

@Kiokiok
Last active September 2, 2024 19:22
Show Gist options
  • Select an option

  • Save Kiokiok/b891f69e68ac7985b8f935e1ce11fe11 to your computer and use it in GitHub Desktop.

Select an option

Save Kiokiok/b891f69e68ac7985b8f935e1ce11fe11 to your computer and use it in GitHub Desktop.
package main
import "core:os";
import "core:fmt";
import "core:strconv";
import "core:strings"
Vec3 :: [3]f32
Vec2 :: [2]f32
Model_Data :: struct {
vertex_positions: [dynamic]Vec3,
vertex_normals: [dynamic]Vec3,
vertex_uvs: [dynamic]Vec2,
indices_positions: [dynamic]u32,
indices_normals: [dynamic]u32,
indices_uvs: [dynamic]u32,
}
free_model_data :: proc(using model_data: Model_Data) {
delete(vertex_positions);
delete(vertex_normals);
delete(vertex_uvs);
delete(indices_positions);
delete(indices_normals);
delete(indices_uvs);
}
stream: string;
is_whitespace :: proc(c: u8) -> bool {
switch c {
case ' ', '\t', '\n', '\v', '\f', '\r', '/': return true;
}
return false;
}
to_f32 :: proc(str : string) -> f32 {
val, _ := strconv.parse_f32(str)
return val
}
to_u32 :: proc(str: string) -> u32 {
val, _ := strconv.parse_int(str)
return cast(u32)val
}
get_next_word :: proc (i : ^int, line : string) -> string {
skip_whitespace(i, line)
start := i^
for {
if is_whitespace(line[i^]) || i^ == len(line)-1 {
current_word := line[start:i^];
return current_word;
}
i^ += 1
}
return "";
}
skip_whitespace :: proc(i : ^int, line : string) {
for {
if !is_whitespace(line[i^]) {
return
}
i^ += 1
}
for stream != "" && is_whitespace(stream[0]) do stream = stream[1:];
}
// @WARNING! This assumes the obj file is well formed.
//
// Each v, vn line has to have at least 3 elements. Every element after the third is discarded
// Each vt line has to have at least 2 elements. Every element after the second is discarded
// Each f line has to have at least 9 elements. Every element after the ninth is discarded
//
// Note that we only support files where the faces are specified as A/A/A B/B/B C/C/C
// Note also that '/' is regarded as whitespace, to simplify the face parsing
read_obj_simple :: proc(file_path : string) -> Model_Data {
data, _ := os.read_entire_file_from_filename(file_path, context.temp_allocator)
defer delete(data, context.temp_allocator)
data_str : string = string(data)
vertex_positions: [dynamic]Vec3
vertex_normals: [dynamic]Vec3
vertex_uvs: [dynamic]Vec2
indices_positions: [dynamic]u32
indices_normals: [dynamic]u32
indices_uvs: [dynamic]u32
for line in strings.split_lines_after_iterator(&data_str) {
count := 0
curr_word := get_next_word(&count, line)
switch curr_word {
case "v":
append(&vertex_positions, Vec3{to_f32(get_next_word(&count, line)), to_f32(get_next_word(&count, line)), to_f32(get_next_word(&count, line))})
case "vn":
append(&vertex_normals, Vec3{to_f32(get_next_word(&count, line)), to_f32(get_next_word(&count, line)), to_f32(get_next_word(&count, line))})
case "vt":
append(&vertex_uvs, Vec2{to_f32(get_next_word(&count, line)), to_f32(get_next_word(&count, line))})
case "f":
indices: [9]u32
for i in 0..<9 do indices[i] = to_u32(get_next_word(&count, line))-1
append(&indices_positions, indices[0], indices[3], indices[6])
append(&indices_normals, indices[2], indices[5], indices[8])
append(&indices_uvs, indices[1], indices[4], indices[7])
}
}
fmt.printf("vertex positions = %d, vertex normals = %d, vertex uvs = %d\n", len(vertex_positions), len(vertex_normals), len(vertex_uvs))
fmt.printf("indices positions = %d, indices normals = %d, indices uvs = %d\n", len(indices_positions), len(indices_normals), len(indices_uvs))
return Model_Data {
vertex_positions,
vertex_normals,
vertex_uvs,
indices_positions,
indices_normals,
indices_uvs }
}
@Kiokiok
Copy link
Author

Kiokiok commented Sep 2, 2024

Based on :
https://gist.github.com/vassvik/f4c19c35ba72ad52eaa51d1091d379d8
Made up to date with current Odin version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment