Author Topic: Decent FF7 Model Viewer  (Read 116713 times)

Cyberman

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #125 on: 2004-09-01 16:23:23 »
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:
[list=1]
  • Draw object
  • rotate object
  • offset object
  • Goto next sibling
  • start at 1 again
  • if no more siblings, goto parent
  • start at 1 again
  • [/list:o]

    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

mirex

  • *
  • Posts: 1645
    • View Profile
    • http://mirex.mypage.sk
Decent FF7 Model Viewer
« Reply #126 on: 2004-09-02 05:46:15 »
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



Quote
Code: [Select]

   #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.

Cyberman

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #127 on: 2004-09-02 17:01:57 »
Quote from: mirex

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

sfx1999

  • *
  • Posts: 1142
    • View Profile
Decent FF7 Model Viewer
« Reply #128 on: 2004-09-02 23:19:53 »
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.

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Decent FF7 Model Viewer
« Reply #129 on: 2004-09-03 12:58:35 »
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

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #130 on: 2004-09-03 15:27:38 »
Quote from: L. Spiro
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

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Decent FF7 Model Viewer
« Reply #131 on: 2004-09-03 16:13:51 »
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.

Cyberman

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #132 on: 2004-09-03 18:48:04 »
Quote from: L. Spiro
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

mirex

  • *
  • Posts: 1645
    • View Profile
    • http://mirex.mypage.sk
Decent FF7 Model Viewer
« Reply #133 on: 2004-09-05 09:26:46 »
Quote from: L.Spiro
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

Cyberman

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #134 on: 2004-09-05 16:18:44 »
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

halkun

  • Global moderator
  • *
  • Posts: 2097
  • NicoNico :)
    • View Profile
    • Q-Gears Homepage
Decent FF7 Model Viewer
« Reply #135 on: 2004-09-05 17:59:45 »
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.

mirex

  • *
  • Posts: 1645
    • View Profile
    • http://mirex.mypage.sk
Decent FF7 Model Viewer
« Reply #136 on: 2004-09-06 08:39:59 »
Quote from: Cyb
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]

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

Cyberman

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #137 on: 2004-09-06 12:16:51 »
Quote from: mirex
Yea parent does not know its children but you can get them easily because children know their parent.

Quote from: mirex
You could make an simple recursive function:
Code: [Select]
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

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Decent FF7 Model Viewer
« Reply #138 on: 2004-09-06 12:41:31 »
After I load a model file (including all bones, etc.) I make a called called SetBoneChildren() which looks like this:

Code: [Select]
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]
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]
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

mirex

  • *
  • Posts: 1645
    • View Profile
    • http://mirex.mypage.sk
Decent FF7 Model Viewer
« Reply #139 on: 2004-09-06 13:10:43 »
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.

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Decent FF7 Model Viewer
« Reply #140 on: 2004-09-06 14:08:12 »
Those are the rotations I get when I use Windows® Calculator but for my code it’s just not coming together, even when I reverse the bytes.

I wrote a very simple script to parse these files before diving into C++ with it and the output in the scripts are perfectly fine:

Code: [Select]
< 0 0 0 >
< 270 333.105469 0 >
< 348.925781 357.626953 327.128906 >
< 16.435547 17.578125 61.523438 >
< 332.050781 337.675781 245.214844 >
…



I guess you can post your code if you like.  Much appreciated mi amigo.

L. Spiro

P. S.: 0x0FC8EB30 through 0x0FC8EC44 is one full frame of Cloud’s kneeling animation (near death).  I do not yet know how many frames precede this one in this animation so I do not know the exact start of his kneeling animation.
When unpacked, rtda should contain one frame that matches this one exactly (I will post a dump).


Code: [Select]
0FC8EB30 0. (Base-rtam)
0FC8EB34 12.48047
0FC8EB38 1.669922

0FC8EB3C 329.7656 (Body-rtan)
0FC8EB40 16.43555
0FC8EB44 17.57813

0FC8EB48 61.52344 (Head-rtao)
0FC8EB4C 355.166
0FC8EB50 343.3008

0FC8EB54 239.6777
0FC8EB58 33.13477
0FC8EB5C 87.80273

0FC8EB60 56.86523
0FC8EB64 54.75586
0FC8EB68 51.32813

0FC8EB6C 344.0918 (Shoulder-rtar)
0FC8EB70 320.3613
0FC8EB74 0.

0FC8EB78 0. (Lower Arm-rtas)
0FC8EB7C 0.9667969
0FC8EB80 7.207031

0FC8EB84 334.5117 (Hand-rtat)
0FC8EB88 18.98438
0FC8EB8C 26.98242

0FC8EB90 65.47852
0FC8EB94 61.875
0FC8EB98 357.9785

0FC8EB9C 13.62305
0FC8EBA0 39.11133
0FC8EBA4 255.0586

0FC8EBA8 328.7109 (Shoulder-rtaw)
0FC8EBAC 338.9063
0FC8EBB0 0.

0FC8EBB4 0. (Lower Arm-rtax)
0FC8EBB8 352.9688
0FC8EBBC 359.6484

0FC8EBC0 329.502 (Hand-rtay)
0FC8EBC4 0.
0FC8EBC8 199.7754

0FC8EBCC 0.
0FC8EBD0 61.17188
0FC8EBD4 20.03906

0FC8EBD8 247.7637 (Upper Leg-rtba)
0FC8EBDC 71.80664
0FC8EBE0 0.

0FC8EBE4 0. (Lower Leg-rtbb)
0FC8EBE8 349.0137
0FC8EBEC 344.8828

0FC8EBF0 75.67383 (Upper Foot-rtbc)
0FC8EBF4 298.125
0FC8EBF8 0.

0FC8EBFC 0. (Lower Foot-rtbd)
0FC8EC00 0.
0FC8EC04 47.90039

0FC8EC08 0.
0FC8EC0C 3.867188
0FC8EC10 293.7305

0FC8EC14 2.988281 (Upper Leg-rtbf)
0FC8EC18 70.57617
0FC8EC1C 180.

0FC8EC20 180. (Lower Leg-rtbg)
0FC8EC24 307.9688
0FC8EC28 357.1875

0FC8EC2C 2.197266 (Upper Foot-rtbh)
0FC8EC30 300.0586
0FC8EC34 0.

0FC8EC38 0. (Lower Foot-rtbi)
0FC8EC3C 0.
0FC8EC40 0.


I can post as many frames ahead and behind this as you like but I just can’t tell when this animation ends and the next begins.

When I get my program to load things correctly I can track down the first frame of the first animation in RAM and then export all the following frames so we can see how each should appear, and that should help decode the format much more easily, don’t you think?

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Decent FF7 Model Viewer
« Reply #141 on: 2004-09-06 16:24:28 »
mirex, I think maybe you should definitely post that code.

After looking more closely at my list (generated by script) and yours on the other page, and compared to Cyberman’s, my list matches Cyberman’s exactly and yours is way off in left field.

Quote
So here goes the first animation rotation data of battle cloud:

bones = 23

AnimHdr:
rec_a = 24
rec_b = 90
block_len = 5656
block_a = 90
real_data_len = 5650
translat = < 0, 65024, 62 >
u1 = 0

<270, 333, 0>
<356, 353, 327>
<16, 17, 61>
<338, 334, 243>
<34, 89, 61>


I get 24 for rec_a, sure.
rec_b is 20.  Where did you get 90?
block_len is 5656??  Is this rtda?

So when I decoded mine, all of my values matched Cyberman’s exactly.
So obviously Cyberman and I made the same mistake(s).

I modified my loader to perform a 4-bit swap chain at various times during the shifting of the bits but no combination of swapping/shifting/reversing works to get either the results of my script/Cyberman’s results or your results.
One attempt was close but he was mounting a horse and looking over his shoulder.

L. Spiro

Cyberman

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #142 on: 2004-09-06 18:49:41 »
Spiro I can't find my data in this thread, where did you find it?!
In any case mine almost exactly matches mirex's now.

Are you reading the data in by bytes from the file or loading it into a structure? If the later be sure you have your structure alignment in your copilor optimizations set to BYTE instead of double or quad word. It will never look right otherwise.

My structures that I've posted won't work without that little detail :)

As for reading the 12 bit ints.  I do it thus.
Code: [Select]
     if (Odd)
      {
         AI[0] = (*A_Decode <<8) & 0xFF00 | *(A_Decode + 1);
         AI[0]&= 0xFFF;
         A_Decode+=2;
         AI[1] = (*A_Decode <<8) & 0xFF00 | *(A_Decode + 1);
         AI[1]>>= 4;
         A_Decode++;
         AI[2] = (*A_Decode <<8) & 0xFF00 | *(A_Decode + 1);
         AI[2]&= 0xFFF;
         A_Decode +=2;
      }
      else
      {
         AI[0] = (*A_Decode <<8) & 0xFF00 | *(A_Decode + 1);
         AI[0] >>= 4;
         A_Decode++;
         AI[1] = (*A_Decode <<8) & 0xFF00 | *(A_Decode + 1);
         AI[1]&=0xFFF;
         A_Decode+=2;
         AI[2] = (*A_Decode <<8) & 0xFF00 | *(A_Decode + 1);
         AI[2] >>= 4;
         A_Decode++;
      }
      Odd = !Odd;
      Bone->Alpha =  AI[0] * 360.0/4096.0;
      Bone->Beta =   AI[1] * 360.0/4096.0;
      Bone->Gamma =  AI[2] * 360.0/4096.0;


Where A_Decode is a unsigned char array.
AI is an array of ints
Odd is boolean and initialized to false.
Most of my problems were silly mistakes so look at what your code is doing and be sure it's what it's supposed to be doing :D

Cyb

Cyberman

  • *
  • Posts: 1572
    • View Profile
Some success
« Reply #143 on: 2004-09-06 23:45:59 »
All right I have had some success with getting CLOUD.LZS working however I think I'm translating the wrong direction or something :lol: because it looks a bit wrong (after using the original data). Hmmm looks OK just the wrong direction I suspect for translating.  I've tried X and Y I suppose all that's left is Z (this is Y).


I also need to be sure to have the quads and triangles ordered right, something isn't working right with that, I believe I'm missing a gl cull call.  Hmmm.

Cyb

sfx1999

  • *
  • Posts: 1142
    • View Profile
Decent FF7 Model Viewer
« Reply #144 on: 2004-09-07 00:01:13 »
I've had things look like that once. I was drawing quads in the wrong order. Doh!

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Decent FF7 Model Viewer
« Reply #145 on: 2004-09-07 05:11:53 »
Cyberman, I posted your code exactly and it’s not working for me.

Code: [Select]
if ( Odd ) {
baEachNumber[0] = (*baData <<8) & 0xFF00 | *(baData + 1);
baEachNumber[0] &= 0xFFF;
baData += 2;
baEachNumber[1] = (*baData <<8) & 0xFF00 | *(baData + 1);
baEachNumber[1] >>= 4;
baData++;
baEachNumber[2] = (*baData <<8) & 0xFF00 | *(baData + 1);
baEachNumber[2] &= 0xFFF;
baData +=2;
}
else {
baEachNumber[0] = (*baData <<8) & 0xFF00 | *(baData + 1);
baEachNumber[0] >>= 4;
baData++;
baEachNumber[1] = (*baData <<8) & 0xFF00 | *(baData + 1);
baEachNumber[1] &=0xFFF;
baData += 2;
baEachNumber[2] = (*baData <<8) & 0xFF00 | *(baData + 1);
baEachNumber[2] >>= 4;
baData++;
}
Odd = !Odd;
fTemp0 = baEachNumber[0] * 360.0f / 4096.0f;
fTemp1 = baEachNumber[1] * 360.0f / 4096.0f;
fTemp2 = baEachNumber[2] * 360.0f / 4096.0f;
AttachRotationToBone( 0, iCount, fTemp0, fTemp1, fTemp2 );




baData is your A_Decode and it is where I stored the entire list of data bytes for the animation.
baEachNumber is clearly where I have store each byte from that array temporarily.
In this case I am doing exactly as you were (shifting my pointer up along the line to get each byte) but I rewrote it to use an index instead but the results were exactly the same.

As for how I am loading it…
I am creating a dynamic byte array

Code: [Select]
byte * baData = new byte[iChunkSize];

and then reading directly into it

Code: [Select]
if ( !fread( baData, iChunkSize, 1, file ) ) { return; }.


The bytes are aligned correctly because I can walk them in the debugger and view them with my hex viewer to see that they match the data file exactly.
I am reading at the correct offset inside the file as well.  baData starts as “00 00 00 00 0C…”.

Your method is giving me these results:

Code: [Select]
< 0.000 0.000 0.000 >
< 0.000 1.230 0.000 >
< 0.126 20.13 0.879 >
< 16.44 0.703 16.52 >


These numers are all so low it makes me suspect your shifts are in the opposite direction of mine.

In my original code, I shifted << (left) to decrease the bytes.
I notice in your code you shift by 4’s going right.

Sigh.  This is the whole reason for any confusion at all.  If machines and operating systems didn’t switch the lower-end bits all the time…

I tried switching your >>’s to <<’s and <<’s to >>’s but that failed also.







For a moment, I am going back to my original code.



Code: [Select]
iCurrentBit = I * 12; // Calculate the current bit.
iBytewiseOffset = iCurrentBit / 8; // Get the offset of the byte that has that bit.
iBitwiseOffset = iCurrentBit % 8; // Calculate how many bits we need to shift.
iTemp = * (unsigned int *)(&baData[iBytewiseOffset]);
iTemp = iTemp << iBitwiseOffset;
SwapAllBytes( (byte *) &iTemp, sizeof( iTemp ) );
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++;
}



What this does is…

Calculate the current bit.
Calculate which byte has that bit (iCurrentBit / 8).
Calculate the shifting offset (iCurrentBit % 8).
Cast a 4-byte unsigned integer to the value at “iBytewiseOffset” in the array.
Code: [Select]
iTemp = * (unsigned int *)(&baData[iBytewiseOffset]);
Now the four bytes that make up “iTemp” are the same four bytes that are in the “iBytewiseOffset” location in the stored data array.
baData[3] is “00 0C 00 EC” (EC 00 0C 00 on Windows® Calculator) which makes iTemp 3959426048.
We shift those four bytes left by “iBitwiseOffset” (which toggles between 0 and 4 appropriately, via the math used).
3959426048 becomes 3221274624, or “00 C0 00 C0” (C0 00 C0 00 on Windows® Calculator).

Then we take only the first three byte halves, so we “iTemp &= 0xFFF;”.

Do the math from there to get the results.


How can this not work?  We go right to the byte that holds our data and shift it by either 0 or 4 appropriately.  Then take only the first 12 bits and do the math on them.  It’s perfectly logical.  Check the formulas to see that my math to go to the appropriate byte and to calculate between 0 and 4 bitwise shift IS correct and it works perfectly.


I have modified this in every way.  I changed the unsigned int to an unsigned short (to read only the first two bytes).  I have changed the order and directiono f the shifting.

Everything.

Cyberman

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #146 on: 2004-09-07 05:39:06 »
Did you initialize Odd to false?

Let's say your first set of numbers are
Code: [Select]
00 00 00 00 0C 00 EC E0 00
And they are numbered
Code: [Select]
00 01 02 03 04 05 06 07 08
from left to right


first you start off at 0 which is EVEN (see odd is false).
You have 3 ints to load the data into (lets say).
A B and C

A = byte 00 << 8
That is byte 0 is shifted left 8 place.
A |= byte 01
So now A has the value 00 00 in it
the hexdecimal numbers are ordered like this
Code: [Select]
01 23
00 00

You only want the upper 12 bits and they need to be right justified so
A >>=4;
and
Code: [Select]
-0 12
00 00

is left
The lower 4 bites of byte 1 and all of byte 2 make up the next 12 bit integer.
So
B = Byte 1 << 8
B |= Byte 2
B &= 0xFFF;

This removes the upper four bits we don't want.
again we get 0 in this case but HEY! :)
The next 12 bit in it's
C = Byte 3 << 8
C |= Byte 4;
C is now 000C
C >>=4;
C is now 000

Now we are ODD yep it's bone 1 now

A = Byte 4 << 8
A |= Byte 5
A &= 0xFFF
A = C00
or 3072 * 360.0 / 4096
or 270.0 degrees.

etc etc.. that's how I decode them at least

Cyb

mirex

  • *
  • Posts: 1645
    • View Profile
    • http://mirex.mypage.sk
Decent FF7 Model Viewer
« Reply #147 on: 2004-09-07 08:37:03 »
Hmmmm here is my code, only from what i remember ... i forgot to put it on the floppy and to bring it here on internet pc ... duh why i dont have internet at home...  -_-
Code: [Select]

unsigned char* data;
int odd;
unsinged long data_pointer;

odd = 0;
data_pointer = 0;

for( i=0; i<bones_count; i++ ) {

    //  these comments are zero indexed as arrays in c++ :)
    // x - take 0st byte and higher 4 bits of 1nd byte
    // y - take lower 4 bits of 1nd and whole 2rd
    // z - take 3th byte and higher 4 bits of 4th  
    if ( odd == 0 ) {
       x = data[ data_pointer ] << 4 + data[ data_pointer + 1 ] >> 4;
       y = ( data[ data_pointer+1 ] & 0xF ) << 8 + data[ data_pointer + 2 ];
       z = data[ data_pointer + 3 ]  << 4 + data[ data_pointer + 4 ] >> 4;
       data_pointer += 4;
    } else {
       x = ( data[ data_pointer ] & 0xF ) << 8 + data[ data_pointer + 1 ];
       y = data[ data_pointer + 2 ] << 4 + data[ data_pointer + 3 ] >> 4;
       z = ( data[ data_pointer + 3 ] & 0xF ) << 8 + data[ data_pointer + 4 ];
       data_pointer += 5;
    }

  odd = 1 - odd;
}


hmm now when i compare some data from RTDA (http://bin.mypage.sk/FILES/RTDA) i see that my documentation is maybe wrong ... but anyhow when i take data from RTDA offset 0x24:
Code: [Select]
FD 2F B2 E9;  10 BB 0C 82
split it by 12 bits:
FD2 FB2 E91   0BB 0C8  (notice relation to original data, and compare it to your calculations results)
and then multiply it by * 360 / 4096 to get angles i get
355,353,327; 16,17...
which are right the data from the animation
<270, 333, 0>
<356, 353, 327>     <---
<16, 17, 61>          <---
<338, 334, 243>
<34, 89, 61>

So i'll have to take a look at the documents and update them.

--edited lotsa times--

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Decent FF7 Model Viewer
« Reply #148 on: 2004-09-07 14:39:13 »
I am finally getting the correct rotations (khob khun krap) but I remembered something from a long time ago (this was not affecting my results with getting the correct animation data).

Something was wrong when I loaded models that forced me to load their inverse Y and Z coordinates (per vertex and normal) in order to get their animations to align properly.

When animating, ficedula had told me to do this:
Code: [Select]
dxRotatef( -fTempYr, 0, 1, 0 );
dxRotatef( fTempXr, 1, 0, 0 );
dxRotatef( -fTempZr, 0, 0, 1 );

He said you had to rotate in that order and by the inverse of the Y and Z (strange how those were the same coordinates I had to reverse to get my model to align properly!).

Now that my battle models have loaded with the correct data, they aren’t displaying properly.
I can’t perform this same translation on them for whatever reason, even though it worked perfectly on all overworld models.

Since you have mentioned how to rotate them but did not mention anything about inverses or order, I am wondering now how to correct whatever was wrong back then (the correct way, instead of loading inverted vertices).


I'm rotating in YXZ order, by negative Y and Z, and then translating by (+)bone length along the Z:
Code: [Select]
dxTranslatef( 0, 0, m_pBone[I].GetLength() );


Anything wrong with this?
None of my models align at all anymore when I load without inverting each Y and Z vertex/normal.

This is all called in the same manner as you had posted, with each per bone per child, recursively.  Consistant motion is created but the ends of each 3D model don’t end where the bones end.

Cyberman

  • *
  • Posts: 1572
    • View Profile
Decent FF7 Model Viewer
« Reply #149 on: 2004-09-08 02:43:28 »
Quote from: mirex
Hmmmm here is my code, only from what i remember ... i forgot to put it on the floppy and to bring it here on internet pc ... duh why i dont have internet at home...  -_-

USB flash drive time?

Have an idea why my pieces aren't too integrated with cloud mirex? :)

I need to be sure I am doing back face removal! DOH!

Cyb/Stephen