Decent FF7 Model Viewer

  • Thread starter Thread starter Sephiroth2000
  • Start date Start date
Status
Not open for further replies.
Can you put in the list "find the #%#* field walkmesh and camera locations". I'm about ready to put a bounty on that data for a really nice prize *COUGH* US PSOne *COUGH*
 
Can you put in the list "find the #%#* field walkmesh and camera locations". I'm about ready to put a bounty on that data for a really nice prize *COUGH* US PSOne *COUGH*
Well I think the walk mesh is possibly in 2 places most likely only in 1 really.

The BSX files we know contain the NPC field models. I think that's all it contains.
The MIM files are the background images, and that's it.
That leeaves the DAT files which also contain the script.  I think it would make sense to have the walk meshes there really and likely the camera locations as well. As you only need one angle per scene this shouldn't require a whole lot of data storage.


A PSOne.. I have one of older units you can hook all sorts of things too :D

I use to play FF7 for HOURS on that thing!

Cyb/Stephen
 
The animation method would most likely be whatever is fastest on a PS1.

Anyway, I saw a project a while back that used OGRE (a free 3d engine) to render Tomb Raider cutscenes and levels. You might want to check it out.

It's here: http://www.evpopov.com/
 
sfx1999:
I'm not sure what you are getting at with what's fastest on the PS1.. most of square FF7 engine is a combination of ideas.

    • Compactness of data
    • Mixed 3d data with CGI animation.
    • Simultaneous operation of several things at once.
    • Ease of switching between different views and programs handling those views.
    Basically the thing was designed that way.  Animation data they include isn't necessarily the fastest method by far, they included bones and rotation angles for each stage of the animation.  Fastest would be to precalculate each polygons position.  I believe they choose this method because it got them to the goal of ease of animation, and wasted less space in the game.  FF8 and FF9 didn't bother using compression and split the disks at FMV story intervals :)  Which works just fine it's just kind of funny.

    Yes the TRX site is interesting, though I don't know what the CORE engine has to do with what Square used for FF7 (and they updated it, for FF8 and then again for FF9 it seems it was quite modular so they merely need to make tweaks).

    Halkun:
    I'll be beating on the new TV over the weekend, a few more hours of redoing the classes and such and I think I'll be able to get it to assimilate model data (woo hoo) after that.  Rendering time, hopefully the textures will work after all this (never did before though).  It's been such a pain with Win98 and doing any form of developement on the platform ARGH.  Hopefully I'll have win2K installed and that will aleviate the anoyance of memory leaks under win98 and thus not have programs cause resource errors while compiling.

    Cyb
 
Hey hey. Thanks to Cyberman and his description and also thanks to Kislinskiy i've added reader of LZS's into Biturn ... yet not complete, it cannot read animations and textured polygons coords properly.
Also I cannot read some polygons of HICLOUD.lzs model; but i'll work on that.
Here are some progress pics from cloud.lzs:
psx_cl1.png

psx_cl2.png

psx_cl3.png


here is report what have i read:
Code: [Select]
Code:
 reading 23 bones reading objects    start offset: 0000028C  reading 26 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 48 triangles  reading 0 quads    ending offset: 00000730    start offset: 00000730  reading 76 vertices  reading 0 groups, flag 0020  skipping 0 lines  reading 108 triangles  reading 20 quads    ending offset: 000013F4    start offset: 000013F4  reading 131 vertices  reading 11 groups, flag 0025   #00: 10 2E8 78 80 600 7840 2036 39   #01: 198 10 08 80 2036 7840 600 3A   #02: 2F0 2E8 10 80 380C 7840 2036 600   #03: 2E8 2F0 308 80 2036 7840 380C 3932   #04: 10 198 318 80 600 7840 2036 380D   #05: 300 368 320 80 AB 7800 37B5 1583   #06: 10 2F8 2F0 80 600 7840 3400 380C   #07: 300 310 368 80 AB 7800 BF 37B5   #08: 2F8 10 318 80 3400 7840 600 380D   #09: 368 310 3E0 80 37B5 7800 BF 15E6   #10: 318 198 48 80 380D 7840 2036 3932  skipping 0 lines  reading 248 triangles  reading 5 quads    ending offset: 00002CA8    start offset: 00002CA8  reading 25 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 40 triangles  reading 3 quads    ending offset: 000030EC    start offset: 000030EC  reading 19 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 8 triangles  reading 11 quads    ending offset: 00003340    start offset: 00003340  reading 32 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 40 triangles  reading 10 quads    ending offset: 00003864    start offset: 00003864  reading 24 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 38 triangles  reading 3 quads    ending offset: 00003C78    start offset: 00003C78  reading 11 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 10 triangles  reading 4 quads    ending offset: 00003E0C    start offset: 00003E0C  reading 32 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 40 triangles  reading 10 quads    ending offset: 00004330    start offset: 00004330  reading 14 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 24 triangles  reading 0 quads    ending offset: 00004594    start offset: 00004594  reading 35 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 50 triangles  reading 5 quads    ending offset: 00004B20    start offset: 00004B20  reading 17 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 25 triangles  reading 1 quads    ending offset: 00004DC8    start offset: 00004DC8  reading 11 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 13 triangles  reading 1 quads    ending offset: 00004F50    start offset: 00004F50  reading 14 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 24 triangles  reading 0 quads    ending offset: 000051B4    start offset: 000051B4  reading 35 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 50 triangles  reading 5 quads    ending offset: 00005740    start offset: 00005740  reading 17 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 25 triangles  reading 1 quads    ending offset: 000059E8    start offset: 000059E8  reading 11 vertices  reading 0 groups, flag 0025  skipping 0 lines  reading 13 triangles  reading 1 quads    ending offset: 00005B70

specially to the 'groups' part
Code: [Select]
Code:
   #00: 10 2E8 78 80 600 7840 2036 39   #01: 198 10 08 80 2036 7840 600 3A   #02: 2F0 2E8 10 80 380C 7840 2036 600   #03: 2E8 2F0 308 80 2036 7840 380C 3932   #04: 10 198 318 80 600 7840 2036 380D   #05: 300 368 320 80 AB 7800 37B5 1583   #06: 10 2F8 2F0 80 600 7840 3400 380C   #07: 300 310 368 80 AB 7800 BF 37B5   #08: 2F8 10 318 80 3400 7840 600 380D   #09: 368 310 3E0 80 37B5 7800 BF 15E6   #10: 318 198 48 80 380D 7840 2036 3932
first 3 numbers are vertice references (not indexes but offsets, as in polygons) and the rest should be tex coords. i'd say that repeating value '80' and '7840' are just fillers so only rest 3 nums are texture coords (which is enough, 2 bytes for each vertex)
 
Hehehe good stuff Mirex!

About those animations :D
I can't get those working tell I can find out why my vertex data is being corrupted, otherwise things would work. I haven't been able to figure out why or what is corrupting the data. However at least I know it's the vertex data being corrupted. (even if it's been driving me crazy)

After that comes rotating the data and information properly.
My current idea for drawing the whole model is kind of questionable but here it is:

    • Draw object
    • rotate object
    • offset object
    • Goto next sibling
    • start at 1 again
    • if no more siblings, goto parent
    • start at 1 again

    I'm assuming that the skeleton is treated as a tree and it's drawn by a depth first traversal of the nods, that is they are drawn rotated and translated, when there are no children.  This is a recursive algorythm.  Let me know if I have this wrong.

    I'll send you the information on extracting the animation data. It's, thank goodness, REALLY simple.

    Cyb
 
Yes rotations are parent-relative; if you work in opengl you can use code like this

1) for the main bone do this:

2) glPushMatrix();

glRotate( this bone's x rotation );
glRotate( this bone's y rotation );
glRotate( this bone's z rotation );
glTranslate( this bone's position );

3) draw models attached to this bone

4) find all children of this bone
5) for each child bone do 2)-6)

6)  glPopMatrix


Code: [Select]
Code:
   #00: 10 2E8 78 80 600 7840 2036 39    #01: 198 10 08 80 2036 7840 600 3A    #02: 2F0 2E8 10 80 380C 7840 2036 600    #03: 2E8 2F0 308 80 2036 7840 380C 3932    #04: 10 198 318 80 600 7840 2036 380D    #05: 300 368 320 80 AB 7800 37B5 1583    #06: 10 2F8 2F0 80 600 7840 3400 380C    #07: 300 310 368 80 AB 7800 BF 37B5    #08: 2F8 10 318 80 3400 7840 600 380D    #09: 368 310 3E0 80 37B5 7800 BF 15E6    #10: 318 198 48 80 380D 7840 2036 3932
first 3 numbers are vertice references (not indexes but offsets, as in polygons) and the rest should be tex coords. i'd say that repeating value '80' and '7840' are just fillers so only rest 3 nums are texture coords (which is enough, 2 bytes for each vertex)

so those texture coords are correct;  only thing buggin me is that they are correct only when number at offset 12 is '7840'  (the number is actually size of the texture 120x64 ) ... those coords stand for cloud's eyes; but when the number is '7800' (at records #5, #7, #9) then the Y coord is way too big, out of picture. That should stand for cloud's mouth.
 
so those texture coords are correct;  only thing buggin me is that they are correct only when number at offset 12 is '7840'  (the number is actually size of the texture 120x64 ) ... those coords stand for cloud's eyes; but when the number is '7800' (at records #5, #7, #9) then the Y coord is way too big, out of picture. That should stand for cloud's mouth.
Thanks for the clue, as soon as I fix my corrupted vertex information problem I'll try to see if I can get a whole looking cloud! :)

All right here is how you extract the palette index information You take the palette word and >> 6 then and it with 7. In other words. bit 8:6 are the palette number.  Those are the ONLY bits you need for the palette number being used. No X or Y UV value should be > 255 as they are all unsigned bytes.  They are relative to the dimensions of the texture of course.

Cyb
 
What happens if you run out of matrixes (over 32)? Most likely wouldn't happen, but you never know if you are using something custom.

Well, you most likely don't need more than 6, because of the root node controlling the other ones.
 
Cyberman, when you mentioned (two posts back) that you would send mirex the animation data, are you talking about the normal .a files from fchar.lgp or the **da ones in battle.lgp?

If you’re talking about the **da ones I would like a copy.

I have been out of the loop for so long, so let me just take a moment to ask a few newbie questions and get caught up.

What is the status on the **da files?  More frames working than just the first?
Do we know what is inside **ab files?

How much do we know about the files that store each 2-D map location?
 
Cyberman, when you mentioned (two posts back) that you would send mirex the animation data, are you talking about the normal .a files from fchar.lgp or the **da ones in battle.lgp?

If you’re talking about the **da ones I would like a copy.

I have been out of the loop for so long, so let me just take a moment to ask a few newbie questions and get caught up.

What is the status on the **da files?  More frames working than just the first?
Do we know what is inside **ab files?

How much do we know about the files that store each 2-D map location?
No Mirex has that already outlined somewhat I'm refering to the data in the PS1 version of FF7 as with a little help from mirex I have it decoding from the PS1 version of FF7.  The animation data is compiled with the models in the PS1 version.  However the data isn't completely understood as yet (IE it's not animated yet just the basic information).  I still have to fix some bugs in the new object system.  Cloud's head currently looks like a yllow and blue flat plate LOL.  The PC information you might want to look at halkun's GEAR's project it's pretty up to date as far as I know :)

sfx1999
Only 8 palettes are ever used,  as for matrices.. hmmm don't know of the use of any matrix within the model information :)  the closest thing might be the animation information :D
 
That’s Cloud’s head from fchar.lgp or cloud.lzs?
Maybe my head is screwed (and it is) but I have never heard of cloud.lzs.

Where is it used (not in battle, not in cinemas, and not on the world map, so where)?

I feel like such a newbie, I’m not going to put my signature on this post.
 
That’s Cloud’s head from fchar.lgp or cloud.lzs?
Maybe my head is screwed (and it is) but I have never heard of cloud.lzs.

Where is it used (not in battle, not in cinemas, and not on the world map, so where)?

I feel like such a newbie, I’m not going to put my signature on this post.
CLOUD.LZS is in the PS1 version of FF7 in ENEMY006 directory on the CD's. That's what we are examining. It contains very similiar data to the PC version (of which data is stuck in an LGP archive). Instead of a bunch of archived sections the data is compacted into something the playstation can load into memory and directly use to draw the information.  The file includes all the animation weapon models and the texture for the eyes and mouth.  There is some addition information in the CLOUD.LZS but I've yet to figure out what exactly it is or means.

Cyb
 
Cyberman, when you mentioned (two posts back) that you would send mirex the animation data, are you talking about the normal .a files from fchar.lgp or the **da ones in battle.lgp?

If you’re talking about the **da ones I would like a copy.

I have been out of the loop for so long, so let me just take a moment to ask a few newbie questions and get caught up.

What is the status on the **da files? More frames working than just the first?
Do we know what is inside **ab files?
Yup we are now working on the Playstation version of FF7 ... no great progress in FF7 PC .. we still have only 1st frame from DA anim files, no idea about AB files ... but maybe we can get to more information if we compare PC and PSX files.

Oh and Cyberman ... for the displaying of rotations of bones you don't have to use OpenGl functions ... Im using them in the Leviathan (as you can see it works that way too) but in Biturn i'm recalculating the positions by the simple math ... first i calculate positions of all the joints (by rotating the length of the bones) and absolute rotations of the bones, then i rotate body-part-models by these rotations and add bone's position ... and its all set up for displaying
 
Mirex
Yes I originally thought of doing things that way but I prefer to keep things simple so I might as well use that method.

There is one disturbing problem. The parent doesn't know it's children, so I assumed everything was depth first traversed. I suppose the playstation handles rendering this by creating a tree from the bone data and applying the animation data acordingly.

There really is no SIMPLE way to do it looks like.

Cyb
 
You have to think about how the PSX renders things:

When a model is sent to the GPU for render, the GPU packets are placed into an Ordering Table. This is a glorified Linked list with a little hardware help (A free Root Counter is used to transverce the OT to place data within it) When the model is done, the OT is linked to DMA and the whole Linked List is streamed to the GPU like a train.

Most of the time the GPU packets in the OT is orginazed via the Z coordinate, but the packets can have zeroed data for things not calculated yet. As long as the packets are the correct size, with null data in the place that where you will insert data later, everything should be OK. It's bad juju to "expand" a packet in the OT as it messes up the addresses in the Linked list and the Root Counter spins off into oblivion.

After the packets are lined up, you would use the the Root Counter in conjuction with the GTE to insert the correct rotation data. When the root counter is done, you send the thing to the GPU. That's how it's done.

Looks like you might have to make two passes.

I don't know much about 3d graphics, just how the PSX works.
 
There is one disturbing problem. The parent doesn't know it's children, so I assumed everything was depth first traversed. I suppose the playstation handles rendering this by creating a tree from the bone data and applying the animation data acordingly.
Yea parent does not know its children but you can get them easily because children know their parent.

You could make an simple recursive function:
Code: [Select]
Code:
draw_bone( int index, float posx, posy, posz ){   rotate bone   display bone's body part   calculate bone's minor_joint_position   for( i=0; i<bones_count; i++ ) {     if ( bone[ i ].parent == index )       draw_bone( i, minor_joint_position );   }}and call it draw_bone( 0, 0, 0, 0 );
or you could precalculate the order of bones into some stack
 
Yea parent does not know its children but you can get them easily because children know their parent.
You could make an simple recursive function:
Code: [Select]
Code:
draw_bone( int index, float posx, posy, posz ){   rotate bone   display bone's body part   calculate bone's minor_joint_position   for( i=0; i<bones_count; i++ ) {     if ( bone[ i ].parent == index )       draw_bone( i, minor_joint_position );   }}and call it draw_bone( 0, 0, 0, 0 );
or you could precalculate the order of bones into some stack
What axis do you translate on by default the model? Currently I'm assuming X, however I'll worry more once things begin to actually render correctly. Amazingly the C++ with gl code seems to work rather neatly. I just need to hunt down this damnable vertex corruption bug.

I've at least stoped most of the exception errors :D

Cyb
 
After I load a model file (including all bones, etc.) I make a called called SetBoneChildren() which looks like this:

Code: [Select]
Code:
VOID FF7Model::SetBoneChildren() { char szBuffer[32]; int iIndex; for ( int I = 0; I < m_iBones; I++ ) {  m_pBone[I].GetParentName( szBuffer );  iIndex = GetBoneIndexByName( szBuffer );  m_pBone[I].SetParentIndex( iIndex );  if ( iIndex != -1 ) {   m_pBone[iIndex].AddChild( I );  } }}


This is for the regular overworld models whose parents are stored by name.  GetBoneIndexByName() checks the list of bones for a name matching the one supplied and returns its index.
That index (as you can see from the code clearly) is the applied as the current bone’s parent, and then the current bone is added as a child to the same index.


But now I have a question also.
So far, all the overworld models I open with my program load and display perfectly.  They are constructed and animated perfectly as well.

I recently downloaded mirex’s document on the battle animation files and used it to start making my program load battle models.

Each part of the model loads and draws perfectly fine.
When applied to an animation frame (and always only the first frame, since that is all that works anyway), however, they go crazy.

My modified animation file loader is temporary just to see how things work with just the first frame, and this is where I have problems.


Here is what I am doing:
My animation loader takes the **da file and reads the appropriate bytes (size determined by the “block_len” [this doesn’t matter since I only read enough vertices to cover the first frame of animation]).
When it parses each into their 12-bit types, this is the code:

Code: [Select]
Code:
 for ( int I = 0; I < iBones * 3; I++ ) {  // 3 floats per bone.  iCurrentBit = I * 12;  iBytewiseOffset = iCurrentBit / 8;  iBitwiseOffset = iCurrentBit % 8;  iTemp = * (unsigned int *)(&baData[iBytewiseOffset]);    iTemp = iTemp << iBitwiseOffset;  iTemp = iTemp & 0xFFF;  if ( I % 3 == 0 ) {   fTemp0 = (float)iTemp * 360.0f / 4096.0f;  }  if ( I % 3 == 1 ) {   fTemp1 = (float)iTemp * 360.0f / 4096.0f;  }  if ( I % 3 == 2 ) {   fTemp2 = (float)iTemp * 360.0f / 4096.0f;   AttachRotationToBone( 0, iCount, fTemp0, fTemp1, fTemp2 );   iCount++;  } }

I know this is fairly sloppy but it is piecemill.
On every 3rd read it takes the current read and the previous 2 (as floats) and adds them with AttachRotationToBone().  0 is used because the frame is always 0 (I am only loading the first frame, remember).  iCount represents the bone number.  I’ll optimize it when get it working.


Well, the bones, when loaded with the first frame, do not even connect to each other.
I mean, it isn’t even as if they are going to random places, connected to each other.
I can’t quite tell yet how it is deciding to plot one of the 3-D parts, but it is certainly incorrect.

The parts that apply animations to model bones is tried-and-true as shown by hundreds of char.lpg files.  So, as long as the animations are loaded correctly, things should work.

Is the code doing what it should?  I go to the relative byte (the formula to calculate the current bytes to read and to shift them work) and then shift either by 0 or by 4.

Here are the bytes in rtda (Cloud’s file) as shown by Visual Studio .NET (meaning reverse order of the Windows® Calculator):
00 00 00 00 0C 00 EC E0 00
which translates into:
0.000 0.000 270.000 || 16.875 20.742 315.000 (Generated by my code)

If you take these bytes in this order, the answer would be:
0.000 0.000 0.000 || 270.000 333.106 0.000 (Generated by Windows® Calculator)


Which of these ouputs is correct?  In order for my code to generate the second output, I would need to reverse the bytes, then shift (in the opposite direction), then reverse back, and then translate.  I am positive this is the correct way to do it.


If the animations are loading correctly, what about the rest of the formats?
The bone lengths on battle models are always nagative.  Do they go off a different axis from the overworld models?
When I attach normally, I go to the next bone by translating along the Z axis according to the bone length.
Should I translate along a different axis?  Should I translate by -BoneLength?
Are the rotations supposed to be in a different order?
For overworld models I rotate by X, -Y, -Z:

Code: [Select]
Code:
   tempXr = m_pBone[I].GetXRotation();   tempYr = m_pBone[I].GetYRotation();   tempZr = m_pBone[I].GetZRotation();   dxRotatef( -tempYr, 0, 1, 0 );    dxRotatef( tempXr, 1, 0, 0 );    dxRotatef( -tempZr, 0, 0, 1 );   m_pBone[I].SetMatrix( mDXMatrixStack[mDXStackPointer] );   dxTranslatef( 0, 0, m_pBone[I].GetLength() );

Are there any special exceptions in the formats for battle models?

L. Spiro
 
L.Spiro: You can compare your rotation values to ones in this thread FF7 Animation information <more about it>, i've posted there the cloud's (RTDA) rotation values of 1st frame from PC and Cyberman posted values from PSX.
If it won't work out i can post you my piece of c++ code that decodes it properly. I dont think it has any other special expections.
 
Status
Not open for further replies.
Back
Top