diff --git a/example/book.odin b/example/book.odin index d83c6ce..7bb8e69 100644 --- a/example/book.odin +++ b/example/book.odin @@ -3,6 +3,7 @@ package example import glm "core:math/linalg/glsl" import "core:strings" +import "core:slice" import gl "../wasm/webgl" import "../obj" @@ -30,17 +31,14 @@ setup_book :: proc(s: ^State_Book, program: gl.Program) { s.vao = gl.CreateVertexArray() - vertices := obj.object_to_triangles(data, data.objects[0], context.allocator) - - s.positions = vertices.pos[:len(vertices)] + + object := &data.objects[0] + s.positions = slice.clone(object.vertices.position[:len(object.vertices)]) extent_min, extent_max := get_extents(s.positions) correct_extents(s.positions, extent_min, extent_max, -140, 140) - s.colors = make([]rgba, len(vertices)) - for &col, i in s.colors { - col = to_rgba(vertices[i].col) - } + s.colors = vec3_slice_to_rgba(object.vertices.color[:len(object.vertices)]) gl.BindVertexArray(s.vao) diff --git a/example/chair.odin b/example/chair.odin index be5035f..173042e 100644 --- a/example/chair.odin +++ b/example/chair.odin @@ -43,10 +43,8 @@ setup_chair :: proc(s: ^State_Chair, program: gl.Program) { o := last(&objects) o.vao = gl.CreateVertexArray() - - vertices := obj.object_to_triangles(data, object, context.allocator) - o.positions = vertices.pos[:len(vertices)] + o.positions = slice.clone(object.vertices.position[:len(object.vertices)]) correct_extents(o.positions, extent_min, extent_max, -200, 200) o.colors = make([]rgba, len(o.positions)) diff --git a/example/suzanne.odin b/example/suzanne.odin index a63fb06..453c502 100644 --- a/example/suzanne.odin +++ b/example/suzanne.odin @@ -12,8 +12,7 @@ State_Suzanne :: struct { using locations: Input_Locations_Boxes, vao: VAO, rotation: mat4, - positions: []vec3, - colors: []u8vec4, + vertices: Vertices, } suzanne_obj_bytes := #load("./public/suzanne.obj", string) @@ -27,15 +26,19 @@ setup_suzanne :: proc(s: ^State_Suzanne, program: gl.Program) { obj.parse_line(&data, line) } - lines := obj.object_to_lines(data, data.objects[0], context.allocator) - - s.positions = lines.pos[:len(lines)] + object := &data.objects[0] - extent_min, extent_max := get_extents(s.positions) - correct_extents(s.positions, extent_min, extent_max, -200, 200) + vertices := make(Vertices, len(object.vertices), context.temp_allocator) - s.colors = make([]rgba, len(s.positions)) - slice.fill(s.colors, GREEN) + copy(vertices.position[:len(vertices)], + object.vertices.position[:len(object.vertices)]) + + extent_min, extent_max := get_extents(vertices.position[:len(vertices)]) + correct_extents(vertices.position[:len(vertices)], extent_min, extent_max, -200, 200) + + slice.fill(vertices.color[:len(vertices)], GREEN) + + s.vertices = vertices_to_lines(vertices) /* Init rotation */ s.rotation = 1 @@ -46,8 +49,8 @@ setup_suzanne :: proc(s: ^State_Suzanne, program: gl.Program) { input_locations_boxes(s, program) - attribute(s.a_position, gl.CreateBuffer(), s.positions) - attribute(s.a_color , gl.CreateBuffer(), s.colors) + attribute(s.a_position, gl.CreateBuffer(), s.vertices.position[:len(s.vertices)]) + attribute(s.a_color , gl.CreateBuffer(), s.vertices.color[:len(s.vertices)]) } @private @@ -74,5 +77,5 @@ frame_suzanne :: proc(s: ^State_Suzanne, delta: f32) { uniform(s.u_matrix, mat) - gl.DrawArrays(gl.LINES, 0, len(s.positions)) + gl.DrawArrays(gl.LINES, 0, len(s.vertices)) } diff --git a/example/utils.odin b/example/utils.odin index 7a3f51d..d881293 100644 --- a/example/utils.odin +++ b/example/utils.odin @@ -117,6 +117,13 @@ to_rgba_3_1 :: #force_inline proc "contextless" (color: $A/[3]u8, a: u8) -> rgba vec3_to_rgba :: #force_inline proc "contextless" (v: vec3, a: u8 = 255) -> rgba { return {u8(v.r*255), u8(v.g*255), u8(v.b*255), a} } +vec3_slice_to_rgba :: #force_inline proc (vecs: []vec3, a: u8 = 255, allocator := context.allocator) -> []rgba { + r := make([]rgba, len(vecs), allocator) + for &col, i in r { + col = to_rgba(vecs[i], a) + } + return r +} to_rgba :: proc {to_rgba_3_1, vec3_to_rgba} @@ -387,6 +394,10 @@ normals_from_positions :: proc (dst, src: []vec3) { get_extents :: proc (positions: []$T) -> (v_min, v_max: T) { + if len(positions) == 0 { + return + } + v_min = positions[0] v_max = positions[0] @@ -420,6 +431,28 @@ vec3_on_radius :: proc (r, a, y: f32) -> vec3 { return {r * cos(a), y, r * sin(a)} } +Vertex :: struct { + position: vec3, + color: rgba, +} +Vertices :: #soa[]Vertex + +vertices_to_lines :: proc (vecs: Vertices, allocator := context.allocator) -> Vertices #no_bounds_check { + + r := make(Vertices, 2*len(vecs), allocator) + + for i := 0; i < len(vecs); i += 3 { + r[i*2 + 0] = vecs[i + 0] + r[i*2 + 1] = vecs[i + 1] + r[i*2 + 2] = vecs[i + 1] + r[i*2 + 3] = vecs[i + 2] + r[i*2 + 4] = vecs[i + 2] + r[i*2 + 5] = vecs[i + 0] + } + + return r +} + Attribute_int :: distinct i32 Attribute_ivec2 :: distinct i32 diff --git a/obj/parser.odin b/obj/parser.odin index 074b18f..3757222 100644 --- a/obj/parser.odin +++ b/obj/parser.odin @@ -8,22 +8,18 @@ package obj vec3 :: [3]f32 vec2 :: [2]f32 -u8vec4 :: [4]u8 + +Vertex :: struct { + position: vec3, + color: vec3, +} +Vertices :: #soa[]Vertex // Texture :: struct { // name: string, // Texture name from .mtl file // path: string, // Resolved path to texture // } -Index :: struct { - /* - indices are base-1 - */ - position: int, - texcoord: int, - normal : int, -} - // Group :: struct { // name : string, // face_count : int, // Number of faces @@ -52,7 +48,7 @@ Index :: struct { Object :: struct { name: string, material: string, - indices: [dynamic][]Index, + vertices: #soa[dynamic]Vertex, } Data :: struct { @@ -102,7 +98,6 @@ init_data :: proc (data: ^Data, allocator := context.allocator) { data.positions = make([dynamic]vec3, 1, 32, allocator) data.texcoords = make([dynamic]vec2, 1, 32, allocator) data.normals = make([dynamic]vec3, 1, 32, allocator) - data.colors = make([dynamic]vec3, 0, 32, allocator) data.objects = make([dynamic]Object, 1, 4, allocator) data.objects[0] = object_make(data) @@ -115,7 +110,7 @@ data_make :: proc (allocator := context.allocator) -> (data: Data) { } object_make :: proc (data: ^Data) -> (g: Object) { - g.indices = make([dynamic][]Index, 0, 32, data.objects.allocator) + g.vertices = make(#soa[dynamic]Vertex, 0, 32, data.objects.allocator) return } @@ -196,7 +191,7 @@ parse_int :: proc (ptr: ^[^]byte) -> (val: int) parse_float :: proc (ptr: ^[^]byte) -> f32 { skip_whitespace(ptr) - + sign: f64 switch ptr[0] { case '+': @@ -255,7 +250,7 @@ parse_float :: proc (ptr: ^[^]byte) -> f32 eval = 10 * eval + int(ptr[0] - '0') move(ptr) } - + num *= eval >= MAX_POWER ? 0.0 : powers[eval] } @@ -298,42 +293,67 @@ parse_face :: proc (data: ^Data, ptr: ^[^]byte) { g := object_last(data) - indices := make([dynamic]Index, 0, 3, g.indices.allocator) + /* 1. + >----\ + x x ---------\ + x x ----> 2. + x x -/ + x x --/ + x x --/ a b c + x x -/ 1 2 3 + <-------------= 2 { + vertices: [3]Vertex + for &v, i in vertices { + idx := indices[i] + v.position = data.positions[idx.position] + // colors array is only filled if the colors data is in the file + v.color = data.colors[idx.position] if idx.position < len(data.colors) else 1 + } + append(&g.vertices, ..vertices[:]) + } } - assert(len(indices) >= 3) - append(&g.indices, indices[:]) - // append_soa(&data.faces, Face{ // verticis = count, // material = data.material, @@ -358,17 +378,17 @@ parse_object :: proc (data: ^Data, ptr: ^[^]byte) // parse_group :: proc (data: ^Data, ptr: ^[^]byte) // { // flush_group(data) - + // skip_whitespace(ptr) // data.group.name = parse_name(ptr) // } parse_usemtl :: proc (data: ^Data, ptr: ^[^]byte) { - + g := object_last(data) assert(g.material == "") - - skip_whitespace(ptr) + + skip_whitespace(ptr) g.material = parse_name(ptr) } @@ -435,7 +455,7 @@ parse_line :: proc (data: ^Data, str: string) case 'u': move(&ptr) - + if ptr[0] == 's' && ptr[1] == 'e' && ptr[2] == 'm' && @@ -447,55 +467,3 @@ parse_line :: proc (data: ^Data, str: string) } } } - -Vertex :: struct { - pos: vec3, - col: vec3, -} -Vertices :: #soa[]Vertex - -vertex_get_from_index :: proc (data: Data, idx: Index) -> (v: Vertex) { - v.pos = data.positions[idx.position] - // colors array is only filled if the colors data is in the file - v.col = data.colors[idx.position] if idx.position < len(data.colors) else 1 - return -} - -object_to_triangles :: proc (data: Data, g: Object, allocator := context.allocator) -> Vertices { - - vertices := make(#soa[dynamic]Vertex, 0, 3*len(g.indices), allocator) - - for indices in g.indices { - for i in 2 ..< len(indices) { - a, b, c := indices[0], indices[i-1], indices[i] - append(&vertices, ..[]Vertex{ - vertex_get_from_index(data, a), - vertex_get_from_index(data, b), - vertex_get_from_index(data, c), - }) - } - } - - return vertices[:] -} - -object_to_lines :: proc (data: Data, g: Object, allocator := context.allocator) -> Vertices { - - vertices := make(#soa[dynamic]Vertex, 0, 6*len(g.indices), allocator) - - for indices in g.indices { - for i in 2 ..< len(indices) { - a, b, c := indices[0], indices[i-1], indices[i] - append(&vertices, ..[]Vertex{ - vertex_get_from_index(data, a), - vertex_get_from_index(data, b), - vertex_get_from_index(data, b), - vertex_get_from_index(data, c), - vertex_get_from_index(data, c), - vertex_get_from_index(data, a), - }) - } - } - - return vertices[:] -}