Important information: this site is currently scheduled to go offline indefinitely by end of the year.

Make_obj (C source)

Read or post any tutorial related to file format analysis for modding purposes.
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Make_obj (C source)

Post by shakotay2 »

well, another year has come and gone and I think it's time to share some source (based on my Make_H2O project).
last updates: 14th Sept., 21th Nov., revised: 31st of March, 2021
Make_obj-src 21-11-19, Rev.zip
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. :D

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
shakotay2 wrote: Sun Dec 23, 2018 1:42 am
"One for all" *.pmd
shakotay2 wrote: Mon Sep 09, 2019 7:47 pm
Kamen Rider, 2nd submesh
shakotay2 wrote: Mon Mar 16, 2020 12:45 pm
(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) ;
    }
}
(code doesn't care for normals)
You do not have the required permissions to view the files attached to this post.
Last edited by shakotay2 on Wed Mar 31, 2021 9:18 pm, edited 9 times in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

Make_obj-SPMan3.zip
I've updated the source code for extracting an obj model from [CITY_PARAMEDIC-]dbd91b3e.36
which you need to extract from CITY_PARAMEDIC.PCPACK using chrrox' quickbms script.

The code can handle this one model only atm. (Feel free to expand it for other .36 models.)

This is a short and uncomplete description how it was coded:

Code: Select all

make a copy of the dummy function SM_of_DFF_loop()
rename it to SM_of_SpMan3_loop()

# we need a new entry for the select-game combobox:
in line 50: set model to 2, or active new model

In function DoFileOpenSave() in the SECOND
switch (model) selection for case 2: add SM_of_SpMan3_loop(hwnd, szFileName, 0) ;

In the callback function WndProc() in the case WM_CREATE: branch add
SendMessage(hwndCombo1, CB_ADDSTRING, 0, (LPARAM) "SpMan3") ;

as a new entry in the game-selection combo box.
Build and run to see how it works.
This was the simple part; now we have to fill our new function
SM_of_SpMan3_loop() with code to get all submeshes (SMs).

Best approach would be a full format analysis, but as you may know,
I really don't like such. But..

It's helpful to use magic tables, if any.
How to find them? Well, simply search for the counts.

hex2obj

If you're familiar with hex2obj you could try to extract the first submesh of the heli, [CA5_Heli-]63757bc7.36.
You can calculate the face indices count from (endaddr -startaddress) / 2, which is (0xecc52 - 0xe7974) / 2 = 10607 (0x296F)

Entering startaddr and count into the go1 editboxes and pressing that button
you'll get the assumed vertex count in the lower left list box: 6269 (0x187D)

getting the offsets of the magic tables:
----------------------------------------------
Those values (7D180000 and 6F290000) to be found at offsets 0x0DF4 and 0x0E04 in the CA5_Heli-63757bc7.36 file.

I'll use the patterns 04 00000000 and 02 000000 to find those tables.
(Understanding how to define patterns is a matter of experience; there's no general recipe.)

Code: Select all

Fill the nValue[] array with the first pattern (04 00 00 00 00).

The FindBytes() function will return the offset addr (offs2) of a found pattern,
if any, otherwise offs2 will be zero!

Once a pattern is found we'd check for the second one (byte per byte) to avoid using
FindBytes() again (which doesn't make too much sense here).
Look at 0xDFF, the address of the first find, to understand why we check for
(*(pFBuf+9)==2) to assure that we didn't meet a false find
(the 3 following bytes need to be checked for zero, too).

These are the results for the counts of each submesh then (vertex, FIs) in the log/obj file:
# 0. 6269 10607
# 1. 199 341
# 2. 898 1631
# 3. 208 422
# 4. 34 65
# 5. 548 919
# 6. 153 249
# 7. 34 65
# 8. 555 933
# 9. 153 253
# 10. 3582 6275
# 11. 1562 2761
# 12. 986 1787
# 13. 83 164
# 14. 58 103
# 15. 990 1809
# 16. 83 165
# 17. 58 103
# 18. 2440 4221

using a simpler model
---------------------------------

19 submeshes for CA5_Heli-]63757bc7.36, yeah, a little bit too many for a first approach, so let's stick to
CITY_PARAMEDIC-dbd91b3e.36, which has 5 only and, much more important, I've extraced
a proper texture for it.

We go for the face indices now, using 0000 0100 0200 as a well-known search pattern
(which doesn't apply for all 3D formats, as you may know already).

Well, for .36 character models it seems to be some kind of signature, too, so an additional
check for a following xx 00 is required, else we've get 60 findings!

Code: Select all

Create a copy of the search pattern loop in our SpMan3 function, it's important to
[b]reinitialize[/b] some variables: cnt= 0 ; pFBuf= pTmp; j= 0 ;
And setting the new search pattern, of course.
In FindBytes() the last parameter is 6 now, the number of bytes to be searched for.

Sadly we've too many finds for FIs' blocks, though, 7 instead of 5:
# 0. 2180 4169
# 1. 1132 2875
# 2. 86 207
# 3. 1290 2781
# 4. 798 1747

# 0xe78
# 0x1098
# 0x83740
# 0x92c14
# 0x95404
# 0xa4784
# 0xaf2e0

So we have to exclude the first two ones, with a simple check, that works for this
CITY_PARAMEDIC-dbd91b3e.36 file only.
The code change is expanding the if conditon if ((*(pFBuf+7)==0) by &&(j>0x40000),
where j is the actual address offset into the .36 file and pFBuf is just a char pointer to the file buffer.

(I'm sorry to say that this is my sloppy way to solve problems in a time saving manner.)

Now we have all we need: the counts, the FIs' starting addresses.
------------------------------------------------------------------------
We'll calculate the vertex address from FIstart - vCount * FVFsize,
where FVFsize is 48 for the PARAMEDIC character (52 for Fireman, for the Heli it was 36).

Sadly there's one different FVFsize to be found: 52 for submesh 3 (cnt==2).
(But we can replace this stupid solution by getting the FVFsize directly; it's 16 bytes before
the 0700000000000800 patterns.)

We need a loop controlled by SMcnt, the submesh count, to get all the submeshes.

I've placed some tristrips face index routine from my MakeH2O project in that loop.

We also need these vars:

Code: Select all

BYTE fCnt=0 ;
int faceDir= 1 ;
DWORD minFaceInd = 16777215, maxFaceInd = 0, lastFaceInd=0 ;
DWORD f1,f2,f3 ;
Provided as is, don't blame me.
Works for CITY_PARAMEDIC-dbd91b3e.36 only atm.



And well, I didn't care for the textures; just used the "camera button" in TextureFinder. :D
You do not have the required permissions to view the files attached to this post.
Last edited by shakotay2 on Fri Aug 09, 2019 9:18 pm, edited 1 time in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

again another year has come and gone, so here's a small update integrating Kamen Rider CW prefab models
(only two models tested so may badly fail on others)

Make_obj, C source included
(see
shakotay2 wrote: Mon Mar 06, 2017 11:01 am
)
Last edited by shakotay2 on Sat Sep 14, 2019 6:03 pm, edited 2 times in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
dswd2015
veteran
Posts: 87
Joined: Thu Sep 03, 2015 10:33 pm
Has thanked: 13 times
Been thanked: 7 times

Re: Make_obj (C source)

Post by dswd2015 »

shakotay2 wrote:again another year has come and gone, so here's a small update integrating Kamen Rider CW prefab models
(only two models tested so may badly fail on others)

Make_obj, C source included
Make_obj.zip

Thank you very much.
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

another month has come and gone :D so here's the next update (adding Skyforge mesh support)
see
shakotay2 wrote: Mon Mar 06, 2017 11:01 am
(where the lod (or whatever) submeshes are spoiled)
First and maybe 2nd SM should be okay; feel free to fix it in the source.
(The problem is that there's more vertex blocks than face indices blocks i.e. up to 4 vertex blocks share the same FIs block.)
Seems each submesh has one "copy" at least, up to a count of 4. But I have no idea how to get the count via code.
Even more annoying: the copies may not follow in sequence.
edit: seems it's 3 submeshes (dunno how I could assume 4)

The body sample (Base.Skin-Geometry.bin) to be found here (in slawdos' post as of Thu May 03, 2018 3:12 am):
http://forum.xentax.com/viewtopic.php?f ... 7&start=15

code for Skyforge mesh:

Code: Select all

void SM_of_Skyforge_loop(HWND hwnd, char szPathname[], DWORD dwStart)
{
   char * pFBuf, *pTmp ;            // , szNo[4]
   BYTE cnt= 0, i, SMcnt ;
   int nValue[16] ;
   //WORD wFaceIndCnt, wVertsCnt, wOffs2VBlock ;         //
   DWORD FIaddr_arr[999], FIcnt=0, FIcnt_arr[999], uvAddr_arr[999], uvCnt, Vaddr_arr[999], vCnt, vCnt_arr[999] ;
   DWORD minFaceInd = 16777215, maxFaceInd = 0, lastFaceInd=0, startFI ;
   DWORD addrFI=0, addrUV, addrV, jOld, lastJ, offs2 ;  //
   DWORD j=0 ;
   float *pFloat ;
   float fData = 0.0f;      // 
   bool bStop= false, bUV ;

   pFBuf = (char *) lpFBuf ; pTmp= pFBuf ;
   dwStart = 0 ; pFBuf += dwStart ;            //
   SendMessage(GetDlgItem(hwnd, ID_LIST), LB_ADDSTRING, 0, (LPARAM) " creating obj:") ;
   cnt = 0 ;
   nValue[0]= 0; nValue[1]= 0; nValue[2]= 1; nValue[3]= 0; nValue[4]= 2; //nValue[5]= 0;    // 0000 0100 02
   do {
        offs2 = FindBytes(lpFBuf, j, dwFileSize-j, nValue, 5) ;       // j is offset here
        if (offs2!=0) {
            pFBuf += offs2 ; j += offs2 ; fprintf( stream, "#") ;
            FIaddr_arr[cnt]= j ; if (cnt<511) cnt++ ; else chMB("Too many submeshes!") ;
            fprintf( stream, "%x\n", j) ;
            pFBuf += 6 ; j += 6 ;
        }
   } while ((offs2!=0)&&(j<dwFileSize)) ;
   FIaddr_arr[cnt] = dwFileSize ;               // but not sure if every Geometry.bin file has FIs 'til their ending!
   SMcnt = cnt ;
   for (i=0;i<SMcnt;i++) {
       FIcnt_arr[i] = (FIaddr_arr[i+1]-FIaddr_arr[i]) / 2 ;
            //fprintf( stream, "%d, ", FIcnt_arr[i]) ;
       FIcnt += FIcnt_arr[i] ;
   }
   pFBuf= pTmp ; pFBuf += 4 ;
   GetDW(pFBuf, j, vCnt, false) ;
   fprintf( stream, "\n# vCnt?: %d, FIs %d\n", vCnt/72, FIcnt) ;
   addrV = 8 ; startFI = 0;
   for (i=0;i<SMcnt;i++) {
        log_FIs(stream, FIaddr_arr[i], minFaceInd, maxFaceInd, lastFaceInd, FIcnt_arr, i) ;
        vCnt_arr[i] = lastFaceInd - startFI ; startFI = lastFaceInd ;
        fprintf( stream, "# vAddr: %x, %d\n", addrV, vCnt_arr[i]) ;
        log_short_Verts(addrV, vCnt_arr[i], 24) ;          // vertex stride: 24
       log_short_UVs(addrV+8, vCnt_arr[i], 24) ;
        addrV += vCnt_arr[i]*24 ;
   }
   fprintf( stream, "# v end: %x\n", addrV) ;
}
This line, calculating the address of the next vertex block, is the problematic one:
addrV += vCnt_arr*24 ;

There are more vertex blocks than face indices blocks, so some (nearly identical) vertex blocks have to be skipped.

edit: fixed a small bug "precalculating" vCnt
added uvs support in above code (zip not updated!)

in void log_short_UVs(DWORD addrUV, DWORD Vcnt, BYTE vStride)
you need to uncomment the following line and comment out the "big endian" one:
lPosXYZ= nValue[0] + nValue[1]*256 ;
//lPosXYZ= nValue[0]*256 + nValue[1] ; // big endian for BF3

(or introduce a parameter bool bIsBigEndian for example)
Last edited by shakotay2 on Sat Sep 14, 2019 6:06 pm, edited 2 times in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

here's an update to the code after akderebur gave some hint
('%" means: modulo, i.e. 5 % 3 is 2)

Update of the code of the previous post (replacement for the for (i=0;i<SMcnt;i++) {...} loop ):

Code: Select all

void SM_of_Skyforge_loop(HWND hwnd, char szPathname[], DWORD dwStart)
{
   char * pFBuf, *pTmp ;            // , szNo[4]
   BYTE vStride= 24 ;     			// stride autoset now
   int cnt= 0, i, ii, SMcnt, nValue[16] ;
   //WORD wFaceIndCnt, wVertsCnt, wOffs2VBlock ;         //
   DWORD FIaddr_arr[999], FIcnt=0, FIcnt_arr[999], vCnt, vCnt_arr[999], vCntSum=0 ;	// uvCnt,
   DWORD minFaceInd = 16777215, maxFaceInd = 0, lastFaceInd=0, startFI ;
   DWORD addrV, offs2 ;  //
   DWORD j=0 ;
   //bool bStop= false, bUV ;

   //chMB("vStride is 24 atm") ;
   pFBuf = (char *) lpFBuf ; pTmp= pFBuf ;
   dwStart = 0 ; pFBuf += dwStart ;            //Triangles 54 72 69 61 Positions  50 6F 73 69
   SendMessage(GetDlgItem(hwnd, ID_LIST), LB_ADDSTRING, 0, (LPARAM) " creating obj:") ;
   cnt = 0 ;
   nValue[0]= 0; nValue[1]= 0; nValue[2]= 1; nValue[3]= 0; nValue[4]= 2; //nValue[5]= 0;    // 0000 0100 02
   do {
        offs2 = FindBytes(lpFBuf, j, dwFileSize-j, nValue, 5) ;       // j is offset here
        if (offs2!=0) {
            pFBuf += offs2 ; j += offs2 ; fprintf( stream, "#") ;
            FIaddr_arr[cnt]= j ; if (cnt<511) cnt++ ; else chMB("Too many submeshes!") ;
            fprintf( stream, "%lx\n", j) ;
            pFBuf += 6 ; j += 6 ;
        }
   } while ((offs2!=0)&&(j<dwFileSize)) ;
   FIaddr_arr[cnt] = dwFileSize ;               // but not sure if every Geometry.bin file has FIs 'til their ending!
   SMcnt = cnt ; fprintf( stream, "#") ;
   for (i=0;i<SMcnt;i++) {
       FIcnt_arr[i] = (FIaddr_arr[i+1]-FIaddr_arr[i]) / 2 ;
            fprintf( stream, "%lu, ", FIcnt_arr[i]) ;
       FIcnt += FIcnt_arr[i] ;
   }
   pFBuf= pTmp ; pFBuf += 4 ;
   GetDW(pFBuf, j, vCnt, false) ;       // vCnt is size of the vertex block here; pFBuf increased

   fprintf( stream, "\n# vCnt?: %ld, FIs %ld\n", vCnt/vStride/3, FIcnt) ;

   addrV = 8 ; startFI = 0; i= 0 ;
    // erster Durchlauf zur Bestimg des ersten vertex
   	//fflush(stream) ;
   for (ii=0;ii<SMcnt*3;ii++) {
        i = ii / 3 ;
        if ((ii % 3)==0) {
            fprintf( stream, "# FIaddr: %lx, %lu\n", FIaddr_arr[i], FIcnt_arr[i]) ;
            log_FIs(stream, FIaddr_arr[i], minFaceInd, maxFaceInd, lastFaceInd, FIcnt_arr, i, false) ;
            vCnt_arr[i] = lastFaceInd - startFI ; startFI = lastFaceInd ;
        }
   }
   for (i=0;i<SMcnt;i++) vCntSum += vCnt_arr[i] ;
   vStride = (BYTE) (vCnt / vCntSum / 3) ;    // /3 doesn't apply for all Geometry.bin, you have been warned!
   for (ii=0;ii<SMcnt*3;ii++) {
        i = ii / 3 ;
        if ((ii % 3)==0) {
            fprintf( stream, "# vAddr: %lx, %lu\n", addrV, vCnt_arr[i]) ;
            log_short_Verts(addrV, vCnt_arr[i], vStride) ;          // vertex stride: 24
            log_short_UVs(addrV+8, vCnt_arr[i], vStride) ;
        }
        addrV += vCnt_arr[i]*vStride ;
        fprintf( stream, "# [%d] v end: %lx, vStride: %d\n", ii, addrV, vStride) ;
   }

}
edit: checked with Base.Skin-Geometry.bin, 960.928 bytes as of 10th of July 2012, 5:00
>>> worked, so don't blame me... :D

remark: the code may appear to be more complicated than it is. It's originally one loop only but it had to be split up into two loops because of the auto calculation of vStride which requires vCntSum.
The modulo thingie just chooses the first of the 3 mesh copies to be logged.

Pay attention to the line calculating the vStride:
vStride = (BYTE) (vCnt / vCntSum / 3) ;

The /3 doesn't apply for all Geometry.bin, this one for example has only one mesh "copy" (although it looks like two, hehehe):
Wings Geometry-bin.jpg
You do not have the required permissions to view the files attached to this post.
Last edited by shakotay2 on Wed Mar 31, 2021 6:54 pm, edited 1 time in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

added support for Super Hero Generation, PS3 (tested with 2 mbg files only)
(There's double submeshes for some unknown reason, so instead of 4 it's 2x2.)

(thread: viewtopic.php?f=16&t=16861)
PS3_SuperHeroGeneration.jpg
As you may know I'm not a friend of full 3D format analysing.
Lack of time, lack of knowledge, whatever.

So I'd like to give some advice for my kind of sloppy but time saving approach
to extract 3D data from mbg to wavefront obj.

You'll need some basic understanding of 'C' to use it with the Make_obj project.

(Feel free to use this approach with Noesis python or max script.)

First thing is the patterns, if any.

for mbg I found
a) "-mesh" which is 2D 6D 65 73 68 in hexadecimal notation
b) 01 000000 04
c) 01 000000 0C

and 0000 0001 0002 (big endian face indices)

getting the counts
With some experience you find the counts (see picture in post
viewtopic.php?f=16&t=16861&start=15)

and it's plain to see (for me at least) that the pattern search
01 000000 04 00 3F3F3F 01 000000 04 will help to get vertex count
and face indices count (where 3F being a wildcard for search in a hex editor)

(This is the idea, in the code I made a backwards search instead, to circumvent multiple findings)

getting the start of vertices
search for -mesh
search for the next 01 000000 0C

vertices start after the 0C of previous pattern

getting the start of face indices (see above)

To get all submeshes (it's 4 for the two mbg samples I have)
we have to do this in a loop.

exe with source in zip file:
(view attachment in next post)
You do not have the required permissions to view the files attached to this post.
Last edited by shakotay2 on Sat Jul 14, 2018 11:06 am, edited 1 time in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

Scion of Fate, 101.YOM tested only (may fail on others, adding of unrecognized FI blocks to the source is required then).
see
shakotay2 wrote: Mon Mar 06, 2017 11:01 am
yeah, that's not nice: all objects are clumped together. Maybe there's offsets in the 101.txt file to move them into correct positions (position in World Matrix is a candidate).
Also uvs of some objects seem to be missing.

You have the source, so don't complain, improve it.
Last edited by shakotay2 on Sat Sep 14, 2019 6:07 pm, edited 3 times in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

I've updated the code (see previous post) to load 101_type2.YOM sucessfully, though there is 8 QNANs (not a number).

The correction is simple but not logical, imho.
In Make_log.obj replace the 504 vertices after the two lines below by 504 lines with: v 0.0 0.0 0.0

# error vertex counts (calc versa file): 504 != 38
# (256dae) vAddr: 256da2, 504

The vts of this submesh are spoiled, too. But you don't need to correct them since you'll delete this submesh anyways.
(For those who don't read readmes: vStart is 0x21F8 for this YOM.)
101_type2-YOM.jpg
Technical background: the vertex counts are calculated automatically in the source (vCnt_arr). They may be different from the file data (vCnt).
I've commented out the "correction" in the source because it spoils the mesh.

Code: Select all

        if (vCnt_arr[i]!=vCnt) {
            fprintf( stream, "# error vertex counts (calc versa file): %d != %d\n", vCnt_arr[i], vCnt) ;
            //if (vCnt<128000) vCnt_arr[i] = vCnt ;
        }
btw: for those who REALLY do read the source: there's a copy&paste error in a comment // vertex stride: 94
It's 32 of course.
You do not have the required permissions to view the files attached to this post.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
youngmark
veteran
Posts: 145
Joined: Thu Sep 02, 2010 1:38 pm
Has thanked: 30 times
Been thanked: 6 times

Re: Make_obj (C source)

Post by youngmark »

Image

An error occurred while opening.
sample data
http://www.mediafire.com/file/sxmq277zzo5iyz4/mbg/file
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

thanks for reporting! :) This will take some time to fix.
You might use this H2O file with hex2obj (view 2nd link in my sig) to get that mbg mesh:

0x182E5 2010
Vb1
94 17
0x326 1045
120000
0x0 255

----------------------
I've added autocorrection for SuperHeroGen mbg files to the attached zip in the post as of Fri Jul 06, 2018 4:36 pm.
(Hopefully it doesn't spoil other mbgs.)
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
asphyxiazation
ultra-n00b
Posts: 3
Joined: Wed Sep 13, 2017 6:19 am
Has thanked: 2 times

Re: Make_obj (C source)

Post by asphyxiazation »

shakotay2 wrote:again another year has come and gone, so here's a small update integrating Kamen Rider CW prefab models
(only two models tested so may badly fail on others)

Make_obj, C source included
Make_obj.zip


shakotay2, I tried converting this prefab file (MDL__B00007_7.prefab) from this thread (forum.xentax.com/viewtopic.php?f=16&t=17900), but the resulting Makeobj_log.obj file is only 125kb and seems to be corrupted that it can't be opened in Windows 3D Builder.

the screenshot is in the attachment.

I've tried several times, the result is the same.

can you help me with this, shakotay2?

EDIT:
I forgot to mention the name of the game. it's Kamen Rider City Wars, Android version.
You do not have the required permissions to view the files attached to this post.
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

asphyxiazation wrote:shakotay2, I tried converting this prefab file (MDL__B00007_7.prefab) from this thread (forum.xentax.com/viewtopic.php?f=16&t=17900), but the resulting Makeobj_log.obj file is only 125kb and seems to be corrupted that it can't be opened in Windows 3D Builder.
No, it's not corrupted, it just starts with face indices instead of vertices:
# FIs: 5802
g SM_0
f 1/1 2/2 3/3
f 1/1 3/3 4/4
f 5/5 1/1 4/4
f 5/5 4/4 6/6

Some wavefront obj importers can't handle this.
Try blender, it's free and it works (using the importer from Campbell Barton et al.).

(As a simple workaround you might select and cut the face indices block in the obj file, then move it to file's end and save.)
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
asphyxiazation
ultra-n00b
Posts: 3
Joined: Wed Sep 13, 2017 6:19 am
Has thanked: 2 times

Re: Make_obj (C source)

Post by asphyxiazation »

shakotay2 wrote:
asphyxiazation wrote:shakotay2, I tried converting this prefab file (MDL__B00007_7.prefab) from this thread (forum.xentax.com/viewtopic.php?f=16&t=17900), but the resulting Makeobj_log.obj file is only 125kb and seems to be corrupted that it can't be opened in Windows 3D Builder.
No, it's not corrupted, it just starts with face indices instead of vertices:
# FIs: 5802
g SM_0
f 1/1 2/2 3/3
f 1/1 3/3 4/4
f 5/5 1/1 4/4
f 5/5 4/4 6/6

Some wavefront obj importers can't handle this.
Try blender, it's free and it works (using the importer from Campbell Barton et al.).

(As a simple workaround you might select and cut the face indices block in the obj file, then move it to file's end and save.)
I imported the resulting Makeobj_log.obj file into Rhino 5 and it stated:
"Encountered mesh face with bogus vertex index (count is 0). Search for "1/1" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "2/2" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "3/3" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "1/1" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "3/3" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "4/4" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "5/5" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "1/1" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "4/4" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "5/5" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "4/4" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "6/6" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "7/7" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "5/5" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "6/6" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "7/7" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "6/6" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "8/8" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "9/9" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "7/7" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "8/8" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "9/9" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "8/8" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "10/10" in your file.
Encountered mesh face with bogus vertex index (count is 0). Search for "11/11" in your file.
Encountered 25 bogus mesh faces. No longer displaying errors to command line.
File had 5802 bogus indexes in it."



then I followed your suggestion to cut the face indices block in the obj file and move it to the file's end, and imported to Rhino 5, and it worked! :keke:

so, out of curiosity, what are the other contents of the prefab file that its size reaches 1.829kb while the actual mesh is only 126kb?

thanks, shakotay2.
you're the man. 8)
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4284
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1146 times
Been thanked: 2242 times

Re: Make_obj (C source)

Post by shakotay2 »

asphyxiazation wrote:so, out of curiosity, what are the other contents of the prefab file that its size reaches 1.829kb while the actual mesh is only 126kb
It's normals which I usually skip; and weight data, I guess; there's positions and rotations for the skeleton bones, and some other data that would require a deeper look.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
Post Reply