File include/fgc.h changed (mode: 100644) (index 9af3514..bad0078) |
... |
... |
FGCMesh fgcLoadOBJ( const char* filePath ){ |
994 |
994 |
return mesh; |
return mesh; |
995 |
995 |
} |
} |
996 |
996 |
|
|
|
997 |
|
size_t nverts = 0, ninds = 0, verts_capacity = 1, inds_capacity = 1; |
997 |
998 |
FGCVertex *verts = realloc( NULL, sizeof(FGCVertex) ); |
FGCVertex *verts = realloc( NULL, sizeof(FGCVertex) ); |
998 |
999 |
FGCIndex *inds = realloc( NULL, sizeof(FGCIndex) ); |
FGCIndex *inds = realloc( NULL, sizeof(FGCIndex) ); |
999 |
1000 |
|
|
1000 |
|
struct float3 { GLfloat x, y, z; }; |
|
1001 |
|
struct float2 { GLfloat u, v; }; |
|
1002 |
|
struct obdex { int v1, vt1, vn1, v2, vt2, vn2, v3, vt3, vn3; }; |
|
1003 |
|
|
|
1004 |
|
//std::vector<float3> obj_v, obj_vn; |
|
1005 |
|
//std::vector<float2> obj_vt; |
|
1006 |
|
//std::vector<obdex> obj_f; |
|
|
1001 |
|
typedef struct { GLfloat x, y, z; } float3; // 12 bytes |
|
1002 |
|
typedef struct { GLfloat u, v; } float2; // 8 bytes |
|
1003 |
|
typedef struct { int v1, vt1, vn1, v2, vt2, vn2, v3, vt3, vn3; } obdex; // 36+ bytes |
|
1004 |
|
|
|
1005 |
|
// Pre-allocate arrays on the heap since they won't fit on a 1 MB stack. |
|
1006 |
|
// This hack keeps the code simple and readable without stretchy buffers. |
|
1007 |
|
static const size_t array_capacity = 99999; |
|
1008 |
|
size_t nobj_v = 0; |
|
1009 |
|
float3 *obj_v = malloc(array_capacity); |
|
1010 |
|
size_t nobj_vn = 0; |
|
1011 |
|
float3 *obj_vn = malloc(array_capacity); |
|
1012 |
|
size_t nobj_vt = 0; |
|
1013 |
|
float2 *obj_vt = malloc(array_capacity); |
|
1014 |
|
size_t nobj_f = 0; |
|
1015 |
|
obdex *obj_f = malloc(array_capacity); |
1007 |
1016 |
|
|
1008 |
1017 |
char ln[1024]; |
char ln[1024]; |
1009 |
1018 |
|
|
|
... |
... |
FGCMesh fgcLoadOBJ( const char* filePath ){ |
1034 |
1043 |
while( start < len && ln[start] == '\x20' ){ |
while( start < len && ln[start] == '\x20' ){ |
1035 |
1044 |
start++; |
start++; |
1036 |
1045 |
} |
} |
1037 |
|
// Parse the line. |
|
|
1046 |
|
// Split the line into an array of numbers. |
|
1047 |
|
size_t num_numbers = 0; |
|
1048 |
|
float numbers[9]; // Max 9 numbers per line. |
1038 |
1049 |
for( size_t i = start; i <= len; i++ ){ |
for( size_t i = start; i <= len; i++ ){ |
1039 |
1050 |
size_t num_len = i - start; |
size_t num_len = i - start; |
1040 |
|
char num_str[32]; |
|
1041 |
|
if((i == len || ln[i] == '\x20' || ln[i] == '/') && num_len < sizeof(num_str)){ |
|
|
1051 |
|
char num_str[32]; // Max 32 characters per number. |
|
1052 |
|
if((i == len || ln[i] == '\x20' || ln[i] == '/') |
|
1053 |
|
&& num_len < sizeof(num_str) |
|
1054 |
|
&& num_numbers < sizeof(numbers)){ |
1042 |
1055 |
memcpy( num_str, ln + start, num_len ); |
memcpy( num_str, ln + start, num_len ); |
1043 |
1056 |
// Null-terminate the string for strtof. |
// Null-terminate the string for strtof. |
1044 |
1057 |
num_str[num_len] = '\0'; |
num_str[num_len] = '\0'; |
1045 |
1058 |
// Note: strtof is locale-dependent. Set locale in main() |
// Note: strtof is locale-dependent. Set locale in main() |
1046 |
|
// TODO. |
|
1047 |
|
//{strtof(str, str_end), strtof(str, str_end), strtof(str, str_end)} |
|
|
1059 |
|
char* p; |
|
1060 |
|
numbers[num_numbers] = strtof(num_str, &p); |
|
1061 |
|
num_numbers++; |
|
1062 |
|
if(*p){ |
|
1063 |
|
fprintf(stderr, "Failed to parse OBJ. Malformed number in %s\n", filePath); |
|
1064 |
|
free(verts); |
|
1065 |
|
free(inds); |
|
1066 |
|
free(obj_v); |
|
1067 |
|
free(obj_vn); |
|
1068 |
|
free(obj_vt); |
|
1069 |
|
free(obj_f); |
|
1070 |
|
FGCMesh mesh; |
|
1071 |
|
mesh.success = false; |
|
1072 |
|
return mesh; |
|
1073 |
|
} |
1048 |
1074 |
start = i + 1; |
start = i + 1; |
1049 |
1075 |
} |
} |
1050 |
1076 |
} |
} |
|
1077 |
|
// Append data to arrays. |
|
1078 |
|
if( type == 1 && num_numbers >= 4 && nobj_v < array_capacity ){ |
|
1079 |
|
obj_v[nobj_v] = (float3){ numbers[0], numbers[1], numbers[2] }; |
|
1080 |
|
nobj_v++; |
|
1081 |
|
}else if( type == 2 && num_numbers >= 3 && nobj_vt < array_capacity ){ |
|
1082 |
|
// Flip the vertical texture coordinate. |
|
1083 |
|
obj_vt[nobj_vt] = (float2){ numbers[0], 1.0f - numbers[1] }; |
|
1084 |
|
nobj_vt++; |
|
1085 |
|
}else if( type == 3 && num_numbers >= 4 && nobj_vn < array_capacity ){ |
|
1086 |
|
obj_vn[nobj_vn] = (float3){ numbers[0], numbers[1], numbers[2] }; |
|
1087 |
|
nobj_vn++; |
|
1088 |
|
}else if( type == 4 && num_numbers >= 10 && nobj_f < array_capacity ){ |
|
1089 |
|
obj_f[nobj_f] = (obdex){ |
|
1090 |
|
(int)numbers[0], |
|
1091 |
|
(int)numbers[1], |
|
1092 |
|
(int)numbers[2], |
|
1093 |
|
(int)numbers[3], |
|
1094 |
|
(int)numbers[4], |
|
1095 |
|
(int)numbers[5], |
|
1096 |
|
(int)numbers[6], |
|
1097 |
|
(int)numbers[7], |
|
1098 |
|
(int)numbers[8] |
|
1099 |
|
}; |
|
1100 |
|
nobj_f++; |
|
1101 |
|
} |
1051 |
1102 |
} |
} |
1052 |
1103 |
} |
} |
1053 |
1104 |
} |
} |
1054 |
1105 |
|
|
1055 |
1106 |
fclose( file ); |
fclose( file ); |
1056 |
1107 |
|
|
1057 |
|
/* |
|
1058 |
|
size_t head = 0, tail = 0; |
|
1059 |
|
|
|
1060 |
|
do{ |
|
1061 |
|
line++; |
|
1062 |
|
tail = text.find_first_of( "\n", head ); |
|
1063 |
|
if( tail == std::string::npos ) tail = text.size(); |
|
1064 |
|
if( text[ head ] != '#' ){ |
|
1065 |
|
std::string ln = text.substr( head, tail - head ); |
|
1066 |
|
|
|
1067 |
|
std::vector<std::string> s; |
|
1068 |
|
|
|
1069 |
|
size_t i1 = 0, i2 = 0; |
|
1070 |
|
|
|
1071 |
|
do{ |
|
1072 |
|
i2 = ln.find_first_of( " \r/", i1 ); |
|
1073 |
|
if( i2 == std::string::npos ) i2 = ln.size(); |
|
1074 |
|
std::string value = ln.substr( i1, i2 - i1 ); |
|
1075 |
|
if( value.length() > 0 ) s.push_back( value ); |
|
1076 |
|
i1 = i2 + 1; |
|
1077 |
|
}while( i1 < ln.size() ); |
|
1078 |
|
|
|
1079 |
|
if( s.size() > 0 ){ |
|
1080 |
|
if( s[0] == "v" && s.size() >= 4 ){ |
|
1081 |
|
obj_v.push_back( { std::stof(s[1]), std::stof(s[2]), std::stof(s[3]) } ); |
|
1082 |
|
}else if( s[0] == "vt" && s.size() >= 3 ){ |
|
1083 |
|
// Flip the vertical texture coordinate. |
|
1084 |
|
obj_vt.push_back( { std::stof(s[1]), 1.0f - std::stof(s[2]) } ); |
|
1085 |
|
}else if( s[0] == "vn" && s.size() >= 4 ){ |
|
1086 |
|
obj_vn.push_back( { std::stof(s[1]), std::stof(s[2]), std::stof(s[3]) } ); |
|
1087 |
|
}else if( s[0] == "f" && s.size() >= 10 ){ |
|
1088 |
|
obj_f.push_back( { |
|
1089 |
|
std::stoi(s[1]), |
|
1090 |
|
std::stoi(s[2]), |
|
1091 |
|
std::stoi(s[3]), |
|
1092 |
|
std::stoi(s[4]), |
|
1093 |
|
std::stoi(s[5]), |
|
1094 |
|
std::stoi(s[6]), |
|
1095 |
|
std::stoi(s[7]), |
|
1096 |
|
std::stoi(s[8]), |
|
1097 |
|
std::stoi(s[9]) |
|
1098 |
|
} ); |
|
1099 |
|
} |
|
1100 |
|
} |
|
1101 |
|
} |
|
1102 |
|
head = tail + 1; |
|
1103 |
|
}while( head < text.size() ); |
|
1104 |
|
|
|
1105 |
|
if( verbose ){ |
|
1106 |
|
printf( "Vertex positions: %lu\n", obj_v.size() ); |
|
1107 |
|
printf( "Vertex texcoords: %lu\n", obj_vt.size() ); |
|
1108 |
|
printf( "Vertex normals: %lu\n", obj_vn.size() ); |
|
1109 |
|
printf( "Faces: %lu\n", obj_f.size() ); |
|
|
1108 |
|
if( fgcVerbose ){ |
|
1109 |
|
printf( "Vertex positions: %lu\n", nobj_v ); |
|
1110 |
|
printf( "Vertex texcoords: %lu\n", nobj_vt ); |
|
1111 |
|
printf( "Vertex normals: %lu\n", nobj_vn ); |
|
1112 |
|
printf( "Faces: %lu\n", nobj_f ); |
1110 |
1113 |
} |
} |
1111 |
1114 |
|
|
|
1115 |
|
/* |
1112 |
1116 |
// Group vertex attributes by texture coordinates. |
// Group vertex attributes by texture coordinates. |
1113 |
1117 |
std::vector<Vertex> verts( obj_vt.size() ); |
std::vector<Vertex> verts( obj_vt.size() ); |
1114 |
1118 |
std::vector<Index> inds; |
std::vector<Index> inds; |
|
... |
... |
FGCMesh fgcLoadOBJ( const char* filePath ){ |
1137 |
1141 |
inds.insert( std::end( inds ), std::begin( i ), std::end( i ) ); |
inds.insert( std::end( inds ), std::begin( i ), std::end( i ) ); |
1138 |
1142 |
} |
} |
1139 |
1143 |
*/ |
*/ |
1140 |
|
// TODO: Use actual counts. |
|
1141 |
|
fgcNormalizeVertices( (size_t)1, verts ); |
|
|
1144 |
|
free(obj_v); |
|
1145 |
|
free(obj_vn); |
|
1146 |
|
free(obj_vt); |
|
1147 |
|
free(obj_f); |
|
1148 |
|
|
|
1149 |
|
fgcNormalizeVertices( nverts, verts ); |
1142 |
1150 |
|
|
1143 |
1151 |
if( fgcVerbose ){ |
if( fgcVerbose ){ |
1144 |
|
printf( "Vertices: %lu\n", (size_t)1 ); |
|
1145 |
|
printf( "Indices: %lu\n", (size_t)1 ); |
|
|
1152 |
|
printf( "Vertices: %lu\n", nverts ); |
|
1153 |
|
printf( "Indices: %lu\n", ninds ); |
1146 |
1154 |
} |
} |
1147 |
1155 |
|
|
1148 |
|
return fgcLoadMesh( 1, 1, verts, inds, false ); |
|
|
1156 |
|
return fgcLoadMesh( nverts, ninds, verts, inds, false ); |
1149 |
1157 |
} |
} |
1150 |
1158 |
|
|
1151 |
1159 |
// Free the VAO and buffers. |
// Free the VAO and buffers. |