summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/editor/view3d.cpp1
-rw-r--r--src/render/model.h687
2 files changed, 329 insertions, 359 deletions
diff --git a/src/editor/view3d.cpp b/src/editor/view3d.cpp
index fd27cf3..a67e149 100644
--- a/src/editor/view3d.cpp
+++ b/src/editor/view3d.cpp
@@ -5,6 +5,7 @@
#include "../game/objlist.h"
#include "../game/world/draw.h"
#include "../game/world/bsp_draw.h"
+#include "../game/world/model_draw.h"
#include "../game.h"
const I32 EDITORVIEW_TITLE_OFFSET = 15;
diff --git a/src/render/model.h b/src/render/model.h
index 83a85bb..da3213a 100644
--- a/src/render/model.h
+++ b/src/render/model.h
@@ -16,6 +16,28 @@ struct MODEL {
LIST<U32> indices;
};
+enum LINE_TYPES : I32 {
+ comment = ( '#' | ( ' ' << 8 ) ),
+ d = ( 'd' | ( ' ' << 8 ) ),
+ f = ( 'f' | ( ' ' << 8 ) ),
+ illum = ( 'i' | ( 'l' << 8 ) ),
+ Ka = ( 'K' | ( 'a' << 8 ) ),
+ Kd = ( 'K' | ( 'd' << 8 ) ),
+ Ke = ( 'K' | ( 'e' << 8 ) ),
+ Ks = ( 'K' | ( 's' << 8 ) ),
+ map_Kd = ( 'm' | ( 'a' << 8 ) ),
+ mtllib = ( 'm' | ( 't' << 8 ) ),
+ newmtl = ( 'n' | ( 'e' << 8 ) ),
+ Ni = ( 'N' | ( 'i' << 8 ) ),
+ Ns = ( 'N' | ( 's' << 8 ) ),
+ o = ( 'o' | ( ' ' << 8 ) ),
+ s = ( 's' | ( ' ' << 8 ) ),
+ v = ( 'v' | ( ' ' << 8 ) ),
+ vn = ( 'v' | ( 'n' << 8 ) ),
+ vt = ( 'v' | ( 't' << 8 ) ),
+ usemtl = ( 'u' | ( 's' << 8 ) )
+};
+
static inline char* skip_space( char* s ) {
while( *s == ' ' || *s == '\t' ) ++s;
return s;
@@ -32,391 +54,338 @@ static inline VEC3 read_vec3( char* s ) {
return temp;
}
-namespace MTL {
- enum LINE_TYPES : U16 {
- comment = ( '#' | ( ' ' << 8 ) ),
- newmtl = ( 'n' | ( 'e' << 8 ) ),
- Ns = ( 'N' | ( 's' << 8 ) ),
- Ka = ( 'K' | ( 'a' << 8 ) ),
- Kd = ( 'K' | ( 'd' << 8 ) ),
- Ks = ( 'K' | ( 's' << 8 ) ),
- Ke = ( 'K' | ( 'e' << 8 ) ),
- Ni = ( 'N' | ( 'i' << 8 ) ),
- d = ( 'd' | ( ' ' << 8 ) ),
- illum = ( 'i' | ( 'l' << 8 ) ),
- map_Kd = ( 'm' | ( 'a' << 8 ) )
- };
-
- struct MTLDATA {
- STR name;
- F32 Ns;
- VEC3 Ka;
- VEC3 Kd;
- VEC3 Ks;
- VEC3 Ke;
- F32 Ni;
- F32 d;
- I32 illum;
- STR map_Kd;
- };
-
- struct MTLLIB {
- STR name;
- LIST<MTLDATA> data;
- };
-
- inline MTLLIB mtl_from_file( const char* path, const char* name ) {
- U64 mtl_size = 0;
- STR mtl_path( path );
- mtl_path += name;
- char* f_mtl = (char*)file_read( mtl_path.data, &mtl_size );
- if( !f_mtl ) {
- dlog( "mtl_from_file() : failed to read mtl file %s\n", mtl_path.data );
- return {};
- }
-
- MTLLIB mtl;
- mtl.name = name;
- for( U64 i = 0; i < mtl_size - 1 && f_mtl[i]; ++i ) {
- if( f_mtl[i] == '\n' )
- continue;
-
- I32 c0 = f_mtl[i];
- U16 c1 = f_mtl[i + 1];
- I32 first_two = c0 | c1 << 8;
+static inline LINE_TYPES get_first_two( char* s ) {
+ I32 c0 = *s;
+ U16 c1 = *(s + 1);
+ return (LINE_TYPES)( c0 | c1 << 8 );
+}
- switch( first_two ) {
- case LINE_TYPES::newmtl: {
- char* start = f_mtl + i + 7;
- char* end = start;
- while( *end && *end != '\n' ) ++end;
- U32 len = end - start;
- STR temp;
- temp.reserve( len + 1 );
- memcpy( temp, start, len );
- temp.data[len] = 0;
- mtl.data.resize( mtl.data.size + 1 );
- mtl.data[mtl.data.size - 1].name = temp.data;
- } break;
- case LINE_TYPES::d:
- case LINE_TYPES::Ni:
- case LINE_TYPES::Ns: {
- char* s = f_mtl + i + 2;
- s = skip_space( s );
- F32 temp = strtof( s, &s );
- switch( first_two ) {
- case LINE_TYPES::d:
- mtl.data[mtl.data.size - 1].d = temp;
- break;
- case LINE_TYPES::Ni:
- mtl.data[mtl.data.size - 1].Ni = temp;
- break;
- case LINE_TYPES::Ns:
- mtl.data[mtl.data.size - 1].Ns = temp;
- break;
- }
- } break;
- case LINE_TYPES::illum: {
- char* s = f_mtl + i + 6;
- mtl.data[mtl.data.size - 1].illum = (I32)strtol( s, &s, 10 );
- } break;
- case LINE_TYPES::Ka:
- case LINE_TYPES::Kd:
- case LINE_TYPES::Ke:
- case LINE_TYPES::Ks: {
- char* s = f_mtl + i + 3;
- switch( first_two ) {
- case LINE_TYPES::Ka:
- mtl.data[mtl.data.size - 1].Ka = read_vec3( s );
- break;
- case LINE_TYPES::Kd:
- mtl.data[mtl.data.size - 1].Kd = read_vec3( s );
- break;
- case LINE_TYPES::Ke:
- mtl.data[mtl.data.size - 1].Ke = read_vec3( s );
- break;
- case LINE_TYPES::Ks:
- mtl.data[mtl.data.size - 1].Ks = read_vec3( s );
- break;
- }
- } break;
- case LINE_TYPES::map_Kd: {
- char* start = f_mtl + i + 7;
- char* end = start;
- while( *end && *end != '\n' ) ++end;
- U32 len = end - start;
- STR temp;
- temp.reserve( len + 1 );
- memcpy( temp, start, len );
- temp.data[len] = 0;
- mtl.data[mtl.data.size - 1].map_Kd = temp.data;
- } break;
- case LINE_TYPES::comment: break;
- default: dlog( "mtl_from_file() : unhandled char combo %c%c\n", c0, c1 ); break;
- }
+struct MTLDATA {
+ STR name;
+ F32 Ns;
+ VEC3 Ka;
+ VEC3 Kd;
+ VEC3 Ks;
+ VEC3 Ke;
+ F32 Ni;
+ F32 d;
+ I32 illum;
+ STR map_Kd;
+};
- while( f_mtl[i] && f_mtl[i] != '\n' ) ++i;
- }
+struct MTLLIB {
+ STR name;
+ LIST<MTLDATA> data;
+};
- free( (void*)f_mtl );
- return mtl;
+inline I32 line_type_offset( LINE_TYPES first_two ) {
+ switch( first_two ) {
+ case d:
+ case f:
+ case o:
+ case s:
+ case v: return 2;
+ case Ka:
+ case Kd:
+ case Ke:
+ case Ks:
+ case Ni:
+ case Ns:
+ case vn:
+ case vt: return 3;
+ case illum: return 6;
+ case map_Kd:
+ case mtllib:
+ case newmtl:
+ case usemtl: return 7;
+ case comment: return 2;
}
-};
+}
-namespace OBJ {
- enum LINE_TYPES : U16 {
- comment = ( '#' | ( ' ' << 8 ) ),
- f = ( 'f' | ( ' ' << 8 ) ),
- mtllib = ( 'm' | ( 't' << 8 ) ),
- o = ( 'o' | ( ' ' << 8 ) ),
- s = ( 's' | ( ' ' << 8 ) ),
- v = ( 'v' | ( ' ' << 8 ) ),
- vn = ( 'v' | ( 'n' << 8 ) ),
- vt = ( 'v' | ( 't' << 8 ) ),
- usemtl = ( 'u' | ( 's' << 8 ) )
- };
+inline void mtl_parse_line( char* file, U64 idx, MTLLIB* mtl ) {
+ LINE_TYPES first_two = get_first_two( file + idx );
+ char* p = file + idx + line_type_offset( first_two );
+ U64 mtl_idx = mtl->data.size - 1;
+
+ switch( first_two ) {
+ case newmtl: {
+ char* end = p;
+ while( *end && *end != '\n' ) ++end;
+ U32 len = end - p;
+ STR temp;
+ temp.reserve( len + 1 );
+ memcpy( temp.data, p, len );
+ temp.data[len] = 0;
+ mtl->data.resize( mtl->data.size + 1 );
+ mtl->data[mtl->data.size - 1].name = temp.data;
+ } break;
+ case d: mtl->data[mtl_idx].d = strtof( p, &p ); break;
+ case Ni: mtl->data[mtl_idx].Ni = strtof( p, &p ); break;
+ case Ns: mtl->data[mtl_idx].Ns = strtof( p, &p ); break;
+ case illum: mtl->data[mtl_idx].illum = (I32)strtol( p, &p, 10 ); break;
+ case Ka: mtl->data[mtl_idx].Ka = read_vec3( p ); break;
+ case Kd: mtl->data[mtl_idx].Kd = read_vec3( p ); break;
+ case Ke: mtl->data[mtl_idx].Ke = read_vec3( p ); break;
+ case Ks: mtl->data[mtl_idx].Ks = read_vec3( p ); break;
+ case map_Kd: {
+ char* end = p;
+ while( *end && *end != '\n' ) ++end;
+ U32 len = end - p;
+ STR temp;
+ temp.reserve( len + 1 );
+ memcpy( temp.data, p, len );
+ temp.data[len] = 0;
+ mtl->data[mtl_idx].map_Kd = temp.data;
+ } break;
+ case comment: break;
+ default: {
+ dlog(
+ "mtl_from_file() : unhandled char combo %c%c\n",
+ first_two & 0xFF, ( first_two >> 8 ) & 0xFF
+ );
+ } break;
+ }
+}
- enum FACE_TYPES : U8 {
- V = 0,
- VVT = 1,
- VVN = 2,
- VVTVN = 3
- };
+inline MTLLIB mtl_from_file( const char* path, const char* name ) {
+ U64 mtl_size;
+ STR full_path( path );
+ full_path += name;
+ char* f_mtl = (char*)file_read( full_path.data, &mtl_size );
+ if( !f_mtl ) {
+ dlog( "mtl_from_file() : failed to read file %s\n", full_path.data );
+ return {};
+ }
- constexpr U32 STR_LEN = 0x40;
+ MTLLIB mtl;
+ mtl.name = name;
+ for( U64 i = 0; i < mtl_size - 1 && f_mtl[i]; ++i ) {
+ if( f_mtl[i] == '\n' )
+ continue;
+ mtl_parse_line( f_mtl, i, &mtl );
+ while( f_mtl[i] && f_mtl[i] != '\n' ) ++i;
+ }
- struct OBJFACE {
- OBJ::FACE_TYPES type;
- LIST<U32> indices;
- };
+ free( (void*)f_mtl );
+ return mtl;
+}
- struct OBJDATA {
- LIST<VEC2> uvs;
- LIST<VEC3> normals;
- LIST<VEC3> vertices;
+enum FACE_TYPES : U8 {
+ V = 0,
+ VVT = 1,
+ VVN = 2,
+ VVTVN = 3
+};
- LIST<MTL::MTLLIB> mtllib;
+constexpr U32 STR_LEN = 0x40;
- struct UseMtl {
- LIST<U32> face_start;
- LIST<STR> mtl_name;
- } usemtl;
+struct OBJFACE {
+ FACE_TYPES type;
+ LIST<U32> indices;
+};
- LIST<OBJFACE> faces;
- };
+struct OBJDATA {
+ LIST<VEC2> uvs;
+ LIST<VEC3> normals;
+ LIST<VEC3> vertices;
+ LIST<MTLLIB> mtllib;
+ struct UseMtl {
+ LIST<U32> face_start;
+ LIST<STR> mtl_name;
+ } usemtl;
+ LIST<OBJFACE> faces;
+};
- static inline U32 face_stride( FACE_TYPES t ) {
- switch( t ) {
- case FACE_TYPES::V: return 1;
- case FACE_TYPES::VVT: return 2;
- case FACE_TYPES::VVN: return 2;
- case FACE_TYPES::VVTVN: return 3;
- }
- return 0;
+static inline U32 face_stride( FACE_TYPES t ) {
+ switch( t ) {
+ case V: return 1;
+ case VVT: return 2;
+ case VVN: return 2;
+ case VVTVN: return 3;
}
+ return 0;
+}
- inline OBJDATA obj_from_file( const char* path, const char* name ) {
- char* f_obj = nullptr;
- STR obj_path( path );
- U64 obj_size = 0;
- obj_path += name;
- obj_path += ".obj";
-
- f_obj = (char*)file_read( obj_path.data, &obj_size );
- if( !f_obj ) {
- dlog( "obj_from_file() : failed to read obj file %s\n", obj_path.data );
- return {};
- }
+inline OBJFACE triangulate_face( OBJFACE ref, U32 idx, U32 stride, FACE_TYPES type ) {
+ OBJFACE tri{};
+ tri.type = type;
+ for( U32 ind = 0; ind < stride; ++ind )
+ tri.indices.push( ref.indices.data[ind] );
+ for( U32 ind = 0; ind < stride; ++ind )
+ tri.indices.push( ref.indices.data[idx * stride + ind] );
+ for( U32 ind = 0; ind < stride; ++ind )
+ tri.indices.push( ref.indices.data[( idx + 1 ) * stride + ind] );
+ return tri;
+}
- OBJDATA obj;
- for( U64 i = 0; i < obj_size - 1 && f_obj[i]; ++i ) {
- if( f_obj[i] == (I32)'#' ) {
- while( f_obj[i] && f_obj[i] != '\n' ) ++i;
- continue;
+inline void obj_parse_f_line( OBJDATA* obj, char* p ) {
+ FACE_TYPES type = (FACE_TYPES)0;
+ bool type_set = 0;
+ OBJFACE temp{};
+ while( *p && *p != '\n' ) {
+ bool has_vt = 0;
+ bool has_vn = 0;
+ U32 v = strtoul( p, &p, 10 );
+ temp.indices.push( --v );
+ if( *p == '/' ) {
+ ++p;
+ if( *p != '/' ) {
+ U32 vt = strtoul( p, &p, 10 );
+ temp.indices.push( --vt );
+ has_vt = 1;
}
-
- I32 c0 = f_obj[i];
- U16 c1 = f_obj[i + 1];
- I32 first_two = c0 | c1 << 8;
-
- switch( first_two ) {
- case LINE_TYPES::f: {
- FACE_TYPES type = (FACE_TYPES)0;
- char* s = f_obj + i + 2;
- bool type_set = 0;
- OBJFACE temp{};
-
- s = skip_space( s );
- while( *s && *s != '\n' ) {
- bool has_vt = 0;
- bool has_vn = 0;
-
- U32 v = strtoul( s, &s, 10 );
- temp.indices.push( --v );
-
- if( *s == '/' ) {
- ++s;
-
- if( *s != '/' ) {
- U32 vt = strtoul( s, &s, 10 );
- temp.indices.push( --vt );
- has_vt = 1;
- }
-
- if( *s == '/' ) {
- ++s;
- U32 vn = strtoul( s, &s, 10 );
- temp.indices.push( --vn );
- has_vn = 1;
- }
- }
-
- if( !type_set ) {
- type_set = 1;
- if( has_vt && has_vn ) type = FACE_TYPES::VVTVN;
- else if( has_vt ) type = FACE_TYPES::VVT;
- else if( has_vn ) type = FACE_TYPES::VVN;
- else type = FACE_TYPES::V;
- }
-
- while( *s && *s != ' ' && *s != '\n' ) ++s;
- s = skip_space( s );
- }
- temp.type = type;
- U32 stride = face_stride( type );
- U32 count = temp.indices.size / stride;
- if ( count <= 3 )
- obj.faces.push( temp );
- else {
- for( U32 idx = 1; idx < count - 1; ++idx ) {
- OBJFACE tri{};
- tri.type = type;
-
- for( U32 ind = 0; ind < stride; ++ind )
- tri.indices.push( temp.indices.data[ind] );
- for( U32 ind = 0; ind < stride; ++ind )
- tri.indices.push( temp.indices.data[idx * stride + ind] );
- for( U32 ind = 0; ind < stride; ++ind )
- tri.indices.push( temp.indices.data[( idx + 1 ) * stride + ind] );
- obj.faces.push( tri );
- }
- }
- } break;
- case LINE_TYPES::v:
- case LINE_TYPES::vn: {
- bool is_v = first_two == LINE_TYPES::v;
- U32 start = i + ( is_v ? 2 : 3 );
- char* s = f_obj + start;
- if( is_v )
- obj.vertices.push( read_vec3( s ) );
- else
- obj.normals.push( read_vec3( s ) );
- } break;
- case LINE_TYPES::vt: {
- char* s = f_obj + i + 3;
- VEC2 temp{};
- s = skip_space( s );
- temp.x = strtof( s, &s );
- s = skip_space( s );
- temp.y = strtof( s, &s );
- obj.uvs.push( temp );
- } break;
- case LINE_TYPES::mtllib:
- case LINE_TYPES::usemtl: {
- bool is_mtllib = first_two == LINE_TYPES::mtllib;
- char* start = f_obj + i + 7;
- char* end = start;
- while( *end && *end != '\n' ) ++end;
- U32 len = end - start;
- STR temp;
- temp.reserve( len + 1 );
- memcpy( temp, start, len );
- temp.data[len] = 0;
- if( !is_mtllib ) {
- if( obj.usemtl.mtl_name.size )
- obj.usemtl.face_start.push( obj.faces.size );
- obj.usemtl.mtl_name.push( temp.data );
- } else
- obj.mtllib.push( MTL::mtl_from_file( path, temp.data ) );
- } break;
- case LINE_TYPES::comment:
- case LINE_TYPES::o:
- case LINE_TYPES::s: break;
- default: dlog( "obj_from_file() : unhandled char combo %c%c\n", c0, c1 ); break;
+ if( *p == '/' ) {
+ ++p;
+ U32 vn = strtoul( p, &p, 10 );
+ temp.indices.push( --vn );
+ has_vn = 1;
}
-
- while( f_obj[i] && f_obj[i] != '\n' ) ++i;
}
- obj.usemtl.face_start.push( obj.faces.size );
- if ( !obj.usemtl.mtl_name.size )
- obj.usemtl.mtl_name.push( "default" );
- free( (void*)f_obj );
- return obj;
+ if( !type_set ) {
+ type_set = 1;
+ if( has_vt && has_vn ) type = VVTVN;
+ else if( has_vt ) type = VVT;
+ else if( has_vn ) type = VVN;
+ else type = V;
+ }
+ while( *p && *p != ' ' && *p != '\n' ) ++p;
+ p = skip_space( p );
}
+ temp.type = type;
+ U32 stride = face_stride( type );
+ U32 count = temp.indices.size / stride;
+ if ( count <= 3 )
+ obj->faces.push( temp );
+ else {
+ for( U32 idx = 1; idx < count - 1; ++idx )
+ obj->faces.push( triangulate_face( temp, idx, stride, type ) );
+ }
+}
- inline MODEL obj_to_model( OBJDATA obj ) {
- struct KEY { U32 v, vt, vn; };
- struct ENTRY { KEY key; U32 idx; };
-
- MODEL model;
- LIST<ENTRY> table;
- table.reserve( obj.faces.size * 3 );
- for( U32 f = 0; f < obj.faces.size; ++f ) {
- OBJFACE& face = obj.faces.data[f];
- U32 stride = face_stride( face.type );
- U32 count = face.indices.size / stride;
-
- for( U32 v = 0; v < count; ++v ) {
- KEY key = {
- 0xFFFFFFFF,
- 0xFFFFFFFF,
- 0xFFFFFFFF
- };
- U32 base = v * stride;
- key.v = face.indices.data[base + 0];
- if( face.type == FACE_TYPES::VVT || face.type == FACE_TYPES::VVTVN )
- key.vt = face.indices.data[base + 1];
- if( face.type == FACE_TYPES::VVN )
- key.vn = face.indices.data[base + 1];
- if( face.type == FACE_TYPES::VVTVN )
- key.vn = face.indices.data[base + 2];
-
- U32 idx = 0;
- bool found = 0;
- // this should be fine until ~1m triangles, right?
- for( U32 i = 0; i < table.size; ++i ) {
- ENTRY& e = table.data[i];
- if( e.key.vn != key.vn
- || e.key.vt != key.vt
- || e.key.v != key.v
- ) continue;
+inline void obj_parse_line( const char* path, char* file, U64 idx, OBJDATA* obj ) {
+ LINE_TYPES first_two = get_first_two( file + idx );
+ char* p = file + idx + line_type_offset( first_two );
+
+ switch( first_two ) {
+ case f: obj_parse_f_line( obj, p ); break;
+ case v:
+ case vn: {
+ if( first_two == v ) obj->vertices.push( read_vec3( p ) );
+ else obj->normals.push( read_vec3( p ) );
+ } break;
+ case vt: {
+ VEC2 temp{};
+ p = skip_space( p );
+ temp.x = strtof( p, &p );
+ p = skip_space( p );
+ temp.y = strtof( p, &p );
+ obj->uvs.push( temp );
+ } break;
+ case mtllib:
+ case usemtl: {
+ bool is_mtllib = first_two == mtllib;
+ char* end = p;
+ while( *end && *end != '\n' ) ++end;
+ U32 len = end - p;
+ STR temp;
+ temp.reserve( len + 1 );
+ memcpy( temp.data, p, len );
+ temp.data[len] = 0;
+ if( !is_mtllib ) {
+ if( obj->usemtl.mtl_name.size )
+ obj->usemtl.face_start.push( obj->faces.size );
+ obj->usemtl.mtl_name.push( temp.data );
+ } else
+ obj->mtllib.push( mtl_from_file( path, temp.data ) );
+ } break;
+ case comment:
+ case o:
+ case s: break;
+ default: {
+ dlog(
+ "obj_from_file() : unhandled char combo %c%c\n",
+ first_two & 0xFF, ( first_two >> 8 ) & 0xFF
+ );
+ } break;
+ }
+}
- idx = e.idx;
- found = 1;
- break;
- }
+inline OBJDATA obj_from_file( const char* path, const char* name ) {
+ char* f_obj = nullptr;
+ STR obj_path( path );
+ U64 obj_size = 0;
+ obj_path += name;
+ obj_path += ".obj";
+ f_obj = (char*)file_read( obj_path.data, &obj_size );
+ if( !f_obj ) {
+ dlog( "obj_from_file() : failed to read obj file %s\n", obj_path.data );
+ return {};
+ }
+ OBJDATA obj;
+ for( U64 i = 0; i < obj_size - 1 && f_obj[i]; ++i ) {
+ if( f_obj[i] == '\n' )
+ continue;
+ obj_parse_line( path, f_obj, i, &obj );
+ while( f_obj[i] && f_obj[i] != '\n' ) ++i;
+ }
+ obj.usemtl.face_start.push( obj.faces.size );
+ if ( !obj.usemtl.mtl_name.size )
+ obj.usemtl.mtl_name.push( "default" );
+ free( (void*)f_obj );
+ return obj;
+}
- if( !found ) {
- MODEL_DATA data{};
- data.position = obj.vertices.data[key.v];
- if( face.type == FACE_TYPES::VVTVN
- || face.type == FACE_TYPES::VVT )
- data.uv = obj.uvs.data[key.vt];
- if( face.type == FACE_TYPES::VVTVN
- || face.type == FACE_TYPES::VVN )
- data.normal = obj.normals.data[key.vn];
- idx = model.vertices.size;
- model.vertices.push( data );
- table.push({ key, idx });
- }
- model.indices.push( idx );
+inline MODEL obj_to_model( OBJDATA obj ) {
+ struct KEY { U32 v, vt, vn; };
+ struct ENTRY { KEY key; U32 idx; };
+ MODEL model;
+ LIST<ENTRY> table;
+ table.reserve( obj.faces.size * 3 );
+ for( U32 f = 0; f < obj.faces.size; ++f ) {
+ OBJFACE& face = obj.faces.data[f];
+ U32 stride = face_stride( face.type );
+ U32 count = face.indices.size / stride;
+ for( U32 v = 0; v < count; ++v ) {
+ KEY key = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ U32 base = v * stride;
+ key.v = face.indices.data[base + 0];
+ if( face.type == VVT || face.type == VVTVN )
+ key.vt = face.indices.data[base + 1];
+ if( face.type == VVN )
+ key.vn = face.indices.data[base + 1];
+ if( face.type == VVTVN )
+ key.vn = face.indices.data[base + 2];
+ U32 idx = 0;
+ bool found = 0;
+ // this should be fine until ~1m triangles, right?
+ for( U32 i = 0; i < table.size; ++i ) {
+ ENTRY& e = table.data[i];
+ if( e.key.vn != key.vn
+ || e.key.vt != key.vt
+ || e.key.v != key.v
+ ) continue;
+ idx = e.idx;
+ found = 1;
+ break;
}
+ if( !found ) {
+ MODEL_DATA data{};
+ data.position = obj.vertices.data[key.v];
+ if( face.type == VVTVN || face.type == VVT )
+ data.uv = obj.uvs.data[key.vt];
+ if( face.type == VVTVN || face.type == VVN )
+ data.normal = obj.normals.data[key.vn];
+ idx = model.vertices.size;
+ model.vertices.push( data );
+ table.push({ key, idx });
+ }
+ model.indices.push( idx );
}
- return model;
}
-};
+ return model;
+}
inline MODEL model_from_obj( const I8* path, const I8* name ) {
- OBJ::OBJDATA obj = OBJ::obj_from_file( path, name );
- return OBJ::obj_to_model( obj );
+ OBJDATA obj = obj_from_file( path, name );
+ return obj_to_model( obj );
}