@@ -671,13 +671,13 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
671671 size_t c = rootBody;
672672 while (c + 12 <= rootEnd) {
673673 const uint32_t ct = ru32 (c), cs = ru32 (c + 4 );
674- if (ru32 (c + 8 ) != 0x1C020065 || cs == 0 || c + 12 + cs > rootEnd)
674+ if (cs == 0 || c + 12 + cs > rootEnd)
675675 break ;
676676 if (ct == 0x1A ) { // GeometryList -> Struct, then Geometry chunks
677677 size_t g = c + 12 ;
678678 while (g + 12 <= c + 12 + cs) {
679679 const uint32_t gt = ru32 (g), gs = ru32 (g + 4 );
680- if (ru32 (g + 8 ) != 0x1C020065 || gs == 0 || g + 12 + gs > c + 12 + cs)
680+ if (gs == 0 || g + 12 + gs > c + 12 + cs)
681681 break ;
682682 if (gt == 0x0F )
683683 collectFrom (g + 12 , g + 12 + gs);
@@ -782,7 +782,7 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
782782 bool hasSkin = false ;
783783 for (size_t c = extBegin; c + 12 <= extEnd;) {
784784 const uint32_t ct = ru32 (c), cs = ru32 (c + 4 );
785- if (ru32 (c + 8 ) != 0x1C020065 || cs == 0 || c + 12 + cs > extEnd)
785+ if (cs == 0 || c + 12 + cs > extEnd)
786786 break ;
787787 if (ct == 0x050E ) { binMesh = c + 12 ; binMeshEnd = c + 12 + cs; }
788788 else if (ct == 0x0510 ) { native = c + 12 ; nativeEnd = c + 12 + cs; }
@@ -875,11 +875,21 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
875875
876876 std::vector<uint8_t > boneIds;
877877 std::vector<float > boneWeights;
878- if (hasSkin && meshType == 0 && vifEnd + numIdx * 16 <= blockEnd) {
878+ if (hasSkin) {
879+ if (meshType != 0 ) {
880+ std::fprintf (stderr, " Skipping weights: meshType is %u, not 0\n " , meshType);
881+ } else if (vifEnd + numIdx * 16 > blockEnd) {
882+ std::fprintf (stderr, " Skipping weights: vifEnd + numIdx*16 (%zu + %u) > blockEnd (%zu)\n " , vifEnd, numIdx*16 , blockEnd);
883+ }
884+ }
885+
886+ size_t weightRecords = (blockEnd > vifEnd) ? (blockEnd - vifEnd) / 16 : 0 ;
887+
888+ if (hasSkin && meshType == 0 && weightRecords > 0 ) {
879889 size_t wp = vifEnd;
880- boneIds.resize (numIdx * 4 );
881- boneWeights.resize (numIdx * 4 );
882- for (uint32_t v = 0 ; v < numIdx ; ++v) {
890+ boneIds.resize (weightRecords * 4 );
891+ boneWeights.resize (weightRecords * 4 );
892+ for (size_t v = 0 ; v < weightRecords ; ++v) {
883893 for (int w = 0 ; w < 4 ; ++w) {
884894 // The byte is the matrix's address in VU memory. A bone
885895 // matrix spans four quadwords, so dividing by four gives the
@@ -917,7 +927,7 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
917927 if (hasSkin && meshType == 0 && !boneWeights.empty ()) {
918928 for (size_t v = 0 ; v < rawVerts.size (); ++v) {
919929 const size_t wi = base + v;
920- if (wi >= numIdx ) break ;
930+ if (wi >= boneWeights. size () / 4 ) break ;
921931 for (int w = 0 ; w < 4 ; ++w) {
922932 rawVerts[v].boneIds [w] = boneIds[wi * 4 + w];
923933 rawVerts[v].boneWeights [w] = boneWeights[wi * 4 + w];
@@ -985,7 +995,7 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
985995 size_t st = 0 , stEnd = 0 ;
986996 for (size_t c = a; c + 12 <= b;) {
987997 const uint32_t ct = ru32 (c), cs = ru32 (c + 4 );
988- if (ru32 (c + 8 ) != 0x1C020065 || cs == 0 || c + 12 + cs > b)
998+ if (cs == 0 || c + 12 + cs > b)
989999 break ;
9901000 if (ct == 0x0001 ) { st = c + 12 ; stEnd = c + 12 + cs; break ; }
9911001 c += 12 + cs;
@@ -1071,7 +1081,7 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
10711081 bool sawNative = false ;
10721082 for (size_t c = a; c + 12 <= b;) {
10731083 const uint32_t ct = ru32 (c), cs = ru32 (c + 4 );
1074- if (ru32 (c + 8 ) != 0x1C020065 || cs == 0 || c + 12 + cs > b)
1084+ if (cs == 0 || c + 12 + cs > b)
10751085 break ;
10761086 if (ct == 0x0003 ) {
10771087 for (size_t x = c + 12 ; x + 12 <= c + 12 + cs;) {
@@ -1092,7 +1102,7 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
10921102 }
10931103 for (size_t c = a; c + 12 <= b;) {
10941104 const uint32_t ct = ru32 (c), cs = ru32 (c + 4 );
1095- if (ru32 (c + 8 ) != 0x1C020065 || cs == 0 || c + 12 + cs > b)
1105+ if (cs == 0 || c + 12 + cs > b)
10961106 break ;
10971107 if (ct == 0x0003 )
10981108 buildFromExtension (c + 12 , c + 12 + cs, (int )si, localMats, localCols, localBlend);
@@ -1161,7 +1171,7 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
11611171 std::map<uint32_t , uint32_t > geomFrame;
11621172 for (size_t c = rootBody; c + 12 <= rootEnd;) {
11631173 const uint32_t ct = ru32 (c), cs = ru32 (c + 4 );
1164- if (ru32 (c + 8 ) != 0x1C020065 || cs == 0 || c + 12 + cs > rootEnd)
1174+ if (cs == 0 || c + 12 + cs > rootEnd)
11651175 break ;
11661176 if (ct == 0x0014 && ru32 (c + 12 ) == 0x01 )
11671177 geomFrame[ru32 (c + 28 )] = ru32 (c + 24 ); // struct: frameIdx, geomIdx
@@ -1171,20 +1181,20 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
11711181 uint32_t geomIndex = 0 ;
11721182 for (size_t c = rootBody; c + 12 <= rootEnd;) {
11731183 const uint32_t ct = ru32 (c), cs = ru32 (c + 4 );
1174- if (ru32 (c + 8 ) != 0x1C020065 || cs == 0 || c + 12 + cs > rootEnd)
1184+ if (cs == 0 || c + 12 + cs > rootEnd)
11751185 break ;
11761186 if (ct == 0x001A ) {
11771187 for (size_t g = c + 12 ; g + 12 <= c + 12 + cs;) {
11781188 const uint32_t gt = ru32 (g), gs = ru32 (g + 4 );
1179- if (ru32 (g + 8 ) != 0x1C020065 || gs == 0 || g + 12 + gs > c + 12 + cs)
1189+ if (gs == 0 || g + 12 + gs > c + 12 + cs)
11801190 break ;
11811191 if (gt == 0x000F ) {
11821192 std::vector<std::string> geomMats;
11831193 std::vector<glm::vec4> geomCols;
11841194 std::vector<uint32_t > geomBlend;
11851195 for (size_t gc = g + 12 ; gc + 12 <= g + 12 + gs;) {
11861196 const uint32_t gct = ru32 (gc), gcs = ru32 (gc + 4 );
1187- if (ru32 (gc + 8 ) != 0x1C020065 || gcs == 0 || gc + 12 + gcs > g + 12 + gs)
1197+ if (gcs == 0 || gc + 12 + gcs > g + 12 + gs)
11881198 break ;
11891199 if (gct == 0x08 ) {
11901200 geomMats = parseMaterialList (gc);
@@ -1216,19 +1226,39 @@ void DecodeRenderWareGeometry(const std::string& name, const uint8_t* payload, s
12161226 if (cl && !cl->skeleton .bones .empty ()) {
12171227 for (size_t gx = g + 12 ; gx + 12 <= g + 12 + gs;) {
12181228 const uint32_t xt = ru32 (gx), xs = ru32 (gx + 4 );
1219- if (ru32 (gx + 8 ) != 0x1C020065 || xs == 0 || gx + 12 + xs > g + 12 + gs)
1229+ if (xs == 0 || gx + 12 + xs > g + 12 + gs)
12201230 break ;
12211231 if (xt == 0x03 ) {
12221232 for (size_t sk = gx + 12 ; sk + 12 <= gx + 12 + xs;) {
12231233 const uint32_t st = ru32 (sk), ss = ru32 (sk + 4 );
12241234 if (ss == 0 || sk + 12 + ss > gx + 12 + xs) break ;
1225- if (st == 0x0116 && ss > 24 && ru32 (sk + 12 ) == 0x01 ) {
1226- const size_t base = sk + 24 ; // past inner Struct header
1227- const uint8_t used = payload[base + 5 ];
1228- if (used == 1 ) {
1229- const int want = payload[base + 8 ]; // usedBoneIds[0]
1230- for (size_t b = 0 ; b < cl->skeleton .bones .size (); b++)
1231- if (cl->skeleton .bones [b].trackIndex == want) { fi = (int )b; break ; }
1235+ if (st == 0x0116 && ss > 4 ) {
1236+ if (ru32 (sk + 12 ) == 0x01 && ss > 24 ) {
1237+ const size_t base = sk + 24 ; // past inner Struct header
1238+ const uint8_t used = payload[base + 5 ];
1239+ if (used == 1 ) {
1240+ const int want = payload[base + 8 ]; // usedBoneIds[0]
1241+ for (size_t b = 0 ; b < cl->skeleton .bones .size (); b++)
1242+ if (cl->skeleton .bones [b].trackIndex == want) { fi = (int )b; break ; }
1243+ }
1244+ } else {
1245+ // Custom Climax format: raw bone IDs directly in the chunk.
1246+ // Search the first few bytes for a non-zero bone ID.
1247+ int want = -1 ;
1248+ for (size_t i = 0 ; i < 32 && i + 24 < ss; ++i) {
1249+ if (payload[sk + 24 + i] != 0 ) {
1250+ want = payload[sk + 24 + i];
1251+ break ;
1252+ }
1253+ }
1254+ if (want != -1 ) {
1255+ for (size_t b = 0 ; b < cl->skeleton .bones .size (); b++) {
1256+ if (cl->skeleton .bones [b].trackIndex == want) {
1257+ fi = (int )b;
1258+ break ;
1259+ }
1260+ }
1261+ }
12321262 }
12331263 }
12341264 sk += 12 + ss;
0 commit comments