List of commits:
Subject Hash Author Date (UTC)
Work on fgcLoadOBJ some more 3429e9a2b8fef4700ea61eede2974c532b6b4a5d fluffrabbit 2024-09-17 06:56:23
Work on fgcLoadOBJ e1d3eb6f3b0d009a30d1f2931f9d548cc8d14967 fluffrabbit 2024-09-14 06:37:16
Add fgcNormalizeVertices 7d7dfbf70275dc5cd3529e3755a2301ba06cb6fe fluffrabbit 2024-09-10 01:44:33
Draw scene color 12354112add161591f2801600ffc592faddef502 fluffrabbit 2024-07-11 22:18:26
Put framebuffer textures in an array ad44ec442db02cbb194559948d7183580b488cec fluffrabbit 2024-07-11 19:33:58
Initial commit cd1f3278f6f9a79255ba17b3b9eb0c224c8fd091 fluffrabbit 2024-07-10 17:32:30
Commit 3429e9a2b8fef4700ea61eede2974c532b6b4a5d - Work on fgcLoadOBJ some more
Author: fluffrabbit
Author date (UTC): 2024-09-17 06:56
Committer name: fluffrabbit
Committer date (UTC): 2024-09-17 06:56
Parent(s): e1d3eb6f3b0d009a30d1f2931f9d548cc8d14967
Signer:
Signing key:
Signing status: N
Tree: 269222512052a883ede6fa97ac7967cfaad21e17
File Lines added Lines deleted
include/fgc.h 78 70
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.
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/fluffrabbit/cfps

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/fluffrabbit/cfps

Clone this repository using git:
git clone git://git.rocketgit.com/user/fluffrabbit/cfps

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main