last updates: 14th Sept., 21th Nov., revised: 31st of March, 2021 This project shall help to extract multi mesh models so is some kind of follow up to hex2obj.
You don't need to use hex2obj for analysing the model before (but it's recommended).
Feel free to use Make_obj.exe in the zip (and ignore the source) if that fulfills your needs.
Analysing of the (few) supported formats is far from being complete/perfect!
So it's up to you to improve the source but you can't make too much use of this project if you don't understand 'C', though.
(btw: it doesn't contain the Make_H2O_ForzaHor3 source, if you thought of that. Just some basic functions.)
-----------------------------------------------------------------------------------------------------
(hidden in this thread, so better link this here:)
SuperHeroGeneration auto correction
"One for all" *.pmd
Kamen Rider, 2nd submesh
(This Kamen Rider patch is for people who know how to use code: "compile this project with CodeBlocks 13.12 for example".)
-----------------------------------------------------------------------------------------------------
Very rough explanation how the code was created using [X360] Star Wars Battlefront III pre-alpha (*.rax)
as an example:
I used the Han_stormtrooper.rax model as a startup which can be found here:
http://forum.xentax.com/viewtopic.php?f ... er#p126467
(Thx to AceWell)
I've tested this one character model only so might not work for other characters
and will NOT work for static objects, I guess. Feel free to expand the code to do so.
The FVFsize is fixed; you might use the editbox to support different sizes (not implemented so far).
I'm a great fan of pattern (byte sequence) searching so here we go:
Find the counts (behind pattern 00 00 10 03, so search for that first)
find first "FACE " (46 41 43 45 00) after uvs
then find "pos ", get verts and uvs startaddress
and skip to the face indices table
--------------------------
I'm pretty sure we'll need some data alignment here (function DWORD dataAlignment(DWORD j) for example)
instead of simply adding 40 bytes here to skip to the face indices table:
pFBuf= pTmp + addrUV + 40 ; j= addrUV + 40 ; fprintf( stream, "# start of FIs: %x\n", j) ;
(where addrUV is the last uv's address +1)
https://www.pic-upload.de/view-32802746 ... r.jpg.html
here's the "main" function of the code, it's ugly and simple, but it works:
Code: Select all
void SM_of_SW_BF3_loop(HWND hwnd, char szPathname[], DWORD dwStart) // scanning the submeshes
{ // only one model tested
char * pFBuf, *pTmp, szNo[4] ;
BYTE cnt, fCnt=0, i, SMcnt, FVFsize= 24 ;
int k, nValue[16] ;
WORD FI[3] ;
DWORD FIcnt, FIcnt_arr[999], vCnt, vCnt_arr[999] ; //
DWORD addrUV, addrV, j=0, jOld, lastJ, offs2 ; //
DWORD minFaceInd = 16777215, maxFaceInd = 0, lastFaceInd=0 ;
pFBuf = (char *) lpFBuf ; pTmp= pFBuf ;
pFBuf += dwStart ;
SendMessage(GetDlgItem(hwnd, ID_LIST), LB_ADDSTRING, 0, (LPARAM) " creating obj:") ;
cnt= 0 ; lastJ= 0 ; j= 0 ;
// get counts of submeshes
nValue[0]= 0; nValue[1]= 0; nValue[2]= 0x10; nValue[3]= 3; // there's counts behind that pattern
do {
offs2 = FindBytes(lpFBuf, j, dwFileSize-j, nValue, 4) ; // j is offset here
if (offs2!=0) {
pFBuf += offs2 + 4 ; j += offs2 + 4 ;
GetDW(pFBuf, j, vCnt, true) ; GetDW(pFBuf, j, FIcnt, true) ; // j not used here
vCnt_arr[cnt]= vCnt ; FIcnt_arr[cnt]= FIcnt ; fprintf( stream, "# %d %d\n", vCnt, FIcnt) ;
if (cnt<999) cnt++ ; else chMB("Too many submeshes!") ;
pFBuf += 8 ; j += 8 ;
}
} while ((offs2!=0)&&(j<dwFileSize)) ;
// get counts of last submesh
offs2 = FindBytes(lpFBuf, j, dwFileSize-j, nValue, 3) ; // j is offset here
if (offs2!=0) {
pFBuf += offs2 + 4 ; j += offs2 + 4 ;
GetDW(pFBuf, j, vCnt, true) ; GetDW(pFBuf, j, FIcnt, true) ; // j not used here
vCnt_arr[cnt]= vCnt ; FIcnt_arr[cnt]= FIcnt ; fprintf( stream, "# %d %d\n", vCnt, FIcnt) ;
pFBuf += 8 ; j += 8 ; cnt++ ;
} else chMB("Error, last submesh not found!") ;
// where's the stzartaddresses for vertices and uvs?
nValue[0]= 0x46; nValue[1]= 0x41; nValue[2]= 0x43; nValue[3]= 0x45; nValue[4]= 0; // 'FACE'
offs2 = FindBytes(lpFBuf, j, dwFileSize-j, nValue, 5) ; // j is offset here
if (offs2!=0) {
pFBuf += offs2 ; j += offs2 ;
pFBuf += 8 ; j += 8 ;
} else chMB("Error, 'FACE ' after last counts not found!") ; // evtl. erste von 2 'FACE'
nValue[0]= 0x50; nValue[1]= 0x4F; nValue[2]= 0x53; nValue[3]= 0; // 'POS '
offs2 = FindBytes(lpFBuf, j, dwFileSize-j, nValue, 4) ; // j is offset here
if (offs2!=0) {
pFBuf += offs2 -32 ; j += offs2 - 32 ; //
GetDW(pFBuf, j, addrV, true) ; pFBuf += 16 ; j += 16 ;
GetDW(pFBuf, j, addrUV, true) ; fprintf( stream, "# %x %x\n", addrV, addrUV) ;
pFBuf += 72 ; j += 72 ;
} else chMB("Error, 'POS ' after 'FACE' not found!") ;
if (j!=addrV) {chMB("address calculation went wrong! break...") ; return ;}
SMcnt= cnt ;
for (i=0;i < SMcnt;i++) {
fprintf( stream, "# %x, %d\n", addrV, vCnt_arr[i]) ;
log_short_Verts(addrV, vCnt_arr[i], FVFsize) ; addrV += FVFsize*vCnt_arr[i] ;
}
if (addrV!=addrUV) {chMB("UV address calculation went wrong! break...") ; return ;}
// go for uvs, blocksize is 4
for (i=0;i < SMcnt;i++) {
log_short_UVs(addrUV, vCnt_arr[i], 4) ; addrUV += 4*vCnt_arr[i] ;
}
pFBuf= pTmp + addrUV + 40 ; j= addrUV + 40 ; fprintf( stream, "# start of FIs: %x\n", j) ;
// go for face indices
for (i=0;i < SMcnt;i++) {
_itoa(i, szNo, 10) ; fprintf( stream, "g SM_%s\n", szNo) ; // separating the submeshes (building groups)
for (k=0;k<FIcnt_arr[i];k++) { //
// adding lastFaceInd in that function to get absolute FIs
FI[fCnt]= (WORD) GetFaceIndexBigE(pFBuf, j, minFaceInd, maxFaceInd, lastFaceInd, false) ; //
fCnt++ ;
if (fCnt==3) {
fCnt=0 ; //
fprintf( stream, "f %d/%d %d/%d %d/%d\n", FI[0],FI[0],FI[1],FI[1],FI[2],FI[2]) ;
}
}
if (maxFaceInd<lastFaceInd) {
fprintf( stream, "error! maxFI %d < lastFI %d\n\n", maxFaceInd, lastFaceInd) ;
}
else lastFaceInd = maxFaceInd ; // needed to "convert" relative to absolute face indices
fprintf( stream, "# next FI block: %x\n", j) ;
}
}