44 std::ifstream inFile( aFilePath.ToStdString(), std::ios::binary );
49 std::vector<uint8_t> fileData( ( std::istreambuf_iterator<char>( inFile ) ),
50 std::istreambuf_iterator<char>() );
53 if( fileData.size() < 20 )
58 uint32_t totalLength = 0;
59 std::memcpy( &magic, &fileData[0], 4 );
60 std::memcpy( &version, &fileData[4], 4 );
61 std::memcpy( &totalLength, &fileData[8], 4 );
65 if( magic !=
GLB_MAGIC || version != 2 || totalLength > fileData.size() )
68 uint32_t jsonChunkLength = 0;
69 uint32_t jsonChunkType = 0;
70 std::memcpy( &jsonChunkLength, &fileData[12], 4 );
71 std::memcpy( &jsonChunkType, &fileData[16], 4 );
77 size_t jsonStart = 20;
78 size_t jsonEnd = jsonStart + jsonChunkLength;
80 if( jsonEnd > totalLength )
83 std::string jsonStr( fileData.begin() + jsonStart, fileData.begin() + jsonEnd );
89 gltf = nlohmann::json::parse( jsonStr );
91 catch(
const nlohmann::json::parse_error& )
96 if( !gltf.contains(
"meshes" ) || !gltf.contains(
"accessors" ) )
99 bool modified =
false;
103 if( !gltf[
"meshes"].is_array() || !gltf[
"accessors"].is_array() )
106 auto& accessors = gltf[
"accessors"];
110 std::map<size_t, int> accessorRefCount;
112 for(
auto& mesh : gltf[
"meshes"] )
114 if( !mesh.is_object() || !mesh.contains(
"primitives" )
115 || !mesh[
"primitives"].is_array() )
118 for(
auto& prim : mesh[
"primitives"] )
120 if( prim.is_object() && prim.contains(
"indices" )
121 && prim[
"indices"].is_number_unsigned() )
122 accessorRefCount[prim[
"indices"].get<
size_t>()]++;
126 for(
auto& mesh : gltf[
"meshes"] )
128 if( !mesh.is_object() || !mesh.contains(
"primitives" )
129 || !mesh[
"primitives"].is_array() )
132 auto& primitives = mesh[
"primitives"];
134 for(
auto primIt = primitives.begin(); primIt != primitives.end(); )
136 auto& prim = *primIt;
138 if( !prim.is_object() )
144 int mode = prim.value(
"mode", 4 );
147 || !prim[
"indices"].is_number_unsigned() )
153 size_t accessorIdx = prim[
"indices"].get<
size_t>();
155 if( accessorIdx >= accessors.size() || !accessors[accessorIdx].is_object()
156 || !accessors[accessorIdx][
"count"].is_number_unsigned() )
162 size_t count = accessors[accessorIdx][
"count"].get<
size_t>();
177 if( primitives.size() <= 1 )
180 primIt = primitives.erase( primIt );
187 if( accessorRefCount[accessorIdx] > 1 )
189 accessorRefCount[accessorIdx]--;
190 nlohmann::json clone = accessors[accessorIdx];
191 clone[
"count"] = count - 1;
192 accessors.push_back( std::move( clone ) );
193 prim[
"indices"] = accessors.size() - 1;
197 accessors[accessorIdx][
"count"] = count - 1;
205 catch(
const nlohmann::json::exception& )
213 std::string fixedJson = gltf.dump();
216 while( fixedJson.size() % 4 != 0 )
217 fixedJson.push_back(
' ' );
219 size_t newJsonChunkLength = fixedJson.size();
223 size_t binChunkStart = jsonEnd;
224 size_t remainingSize = totalLength - binChunkStart;
225 size_t newTotalLength = 12 + 8 + newJsonChunkLength + remainingSize;
227 if( newTotalLength > UINT32_MAX )
230 std::vector<uint8_t> outData;
231 outData.reserve( newTotalLength );
233 uint32_t newJsonChunkLength32 =
static_cast<uint32_t
>( newJsonChunkLength );
234 uint32_t newTotalLength32 =
static_cast<uint32_t
>( newTotalLength );
237 outData.resize( 12 );
238 std::memcpy( &outData[0], &magic, 4 );
239 std::memcpy( &outData[4], &version, 4 );
240 std::memcpy( &outData[8], &newTotalLength32, 4 );
243 size_t pos = outData.size();
244 outData.resize( pos + 8 );
245 std::memcpy( &outData[pos], &newJsonChunkLength32, 4 );
246 std::memcpy( &outData[pos + 4], &jsonChunkType, 4 );
249 outData.insert( outData.end(), fixedJson.begin(), fixedJson.end() );
252 if( remainingSize > 0 )
253 outData.insert( outData.end(), fileData.begin() + binChunkStart,
254 fileData.begin() + totalLength );