Author Topic: FF7 - PSX battle scenes  (Read 4090 times)

Cyberman

  • *
  • Posts: 1572
    • View Profile
FF7 - PSX battle scenes
« on: 2005-07-01 19:58:09 »
I've been twiddling with some code to get these to work, however my main problem appears to be
[list=1]Misalignment of textured sections while processing the UV information
Incorrect palettes being selected[/list:o]
Here is an example of the TIM from STAGE001.LZS decoded it's kind of nasty looking in my humble opinion.  So what should it look like first of all?
Micky's palette selection:

Cyb's palette selection:

They both look wrong to be honest. However Zangan doesn't have lighting and too much camera control so Hmmm.  Anyhow I'm pretty sure I have the pallete selection wrong for both cases.

Code: [Select]
  BM = Image1->Picture->Bitmap;
   Image1->Width = 256;
   Image1->Height= 256;
   BM->Width = 768;
   BM->Height= 256;
   TIM(BM, Dat + Offsets[*Sections - 1]);
   Image1->Width = BM->Width;
   Image1->Height= BM->Height;
   XOff = 0;
   for(Index = 0; Index < 3; Index++)
   {
      if(Textures[Index].ImageData != NULL)
      {
         delete Textures[Index].ImageData;
      }
      // create 256x256 textures
      Textures[Index].ImageData = (GLubyte *)new RGBA[256*256];
   }
   // we use 3 seperate textures
   for (Index = 1; Index < (*Sections -1); Index++)
   {
      VertC =        (int *)(Dat + Offsets[Index]);
      Verts =        (PSX_FF7_VERTEX *)(VertC + 1);
      TriP =         (PSX_FF7_PCNT *)&Verts[*VertC/8];
      TTriangles =   (PSX_FF7_TTRI *)(TriP + 1);
      QuadP =        (PSX_FF7_PCNT *)&TTriangles[TriP->Count];
      TQuads =       (PSX_FF7_TQUAD *)(QuadP + 1);
      XOff = ((TriP->TPage & 0x0E) - 6)<<7;
      for (PIndex = 0; PIndex < TriP->Count; PIndex++)
      {
         TTri = TTriangles[Index];
         TX = TTri.U0;
         TY = TTri.V0;
         TW = TX;//TTri.U0;
         TH = TW;//TTri.V0;
         //if (TTri.U0 < TX) TX = TTri.U0;
         if (TTri.U1 < TX) TX = TTri.U1;
         if (TTri.U2 < TX) TX = TTri.U2;
         //if (TTri.U0 > TW) TW = TTri.U0;
         if (TTri.U1 > TW) TW = TTri.U1;
         if (TTri.U2 > TW) TW = TTri.U2;
         //if (TTri.V0 < TY) TY = TTri.V0;
         if (TTri.V1 < TY) TY = TTri.V1;
         if (TTri.V2 < TY) TY = TTri.V2;
         //if (TTri.V0 > TH) TH = TTri.V0;
         if (TTri.V1 > TH) TH = TTri.V1;
         if (TTri.V2 > TH) TH = TTri.V2;
         // Micky's method
         //PalIdx = (TTri.PAL >> 6) & 7;
         // Cyb's Method
         PalIdx = (TTri.PAL >> 7) & 7;
         if (PalIdx != CPal)
            CPal = PalIdx;
         //TW+=XOff;
         //TX+=XOff;
         TIM(
            BM,
            Dat + Offsets[*Sections - 1],
            &Textures[XOff>>8],
            //(GLubyte *)NULL,//Textures[0].ImageData,
            TX + XOff, TY,
            TW + XOff, TH
            //TY + XOff, TX,
            //TH + XOff, TW
            );
         //Model->Add
      }
      XOff = ((QuadP->TPage & 0x0E)-6) << 7;
      for (PIndex = 0; PIndex < QuadP->Count; PIndex++)
      {
         TQuad = TQuads[Index];
         TX = TQuad.U0;
         TY = TQuad.V0;
         TW = TX;//TQuad.U0;
         TH = TY;//TQuad.V0;
         //if (TQuad.U0 < TX) TX = TQuad.U0;
         if (TQuad.U1 < TX) TX = TQuad.U1;
         if (TQuad.U2 < TX) TX = TQuad.U2;
         if (TQuad.U3 < TX) TX = TQuad.U3;
         //if (TQuad.U0 > TW) TW = TQuad.U0;
         if (TQuad.U1 > TW) TW = TQuad.U1;
         if (TQuad.U2 > TW) TW = TQuad.U2;
         if (TQuad.U3 > TW) TW = TQuad.U3;
         //if (TQuad.V0 < TY) TY = TQuad.V0;
         if (TQuad.V1 < TY) TY = TQuad.V1;
         if (TQuad.V2 < TY) TY = TQuad.V2;
         if (TQuad.V3 < TY) TY = TQuad.V3;
         //if (TQuad.V0 > TH) TH = TQuad.V0;
         if (TQuad.V1 > TH) TH = TQuad.V1;
         if (TQuad.V2 > TH) TH = TQuad.V2;
         if (TQuad.V3 > TH) TH = TQuad.V3;
         // Micky's method
         //PalIdx = (TQuad.PAL >> 6) & 7;
         // Cyb's Method
         PalIdx = (TQuad.PAL >> 7) & 7;
         if (PalIdx != CPal)
            CPal = PalIdx;
         //TW+=XOff;
         //TX+=XOff;
         TIM(
            BM,
            Dat + Offsets[*Sections - 1],
            &Textures[XOff>>8],
            //(GLubyte *)NULL,//Textures[0].ImageData,
            TX + XOff, TY,
            TW + XOff, TH
            //TY + XOff, TX,
            //TH + XOff, TW
            );
      }
   }

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
FF7 - PSX battle scenes
« Reply #1 on: 2005-07-02 08:43:54 »
Since I don't have any of the PSX files here to look at, I unfortunately can't examine the problem closer. Also I don't really know how your TIM function works. I notice that in the included code you don't actually use the CPal value, but I assume you just left out those parts.

I don't have the PSX_FF7_TTRI or PSX_FF7_TQUAD structure to look at, but I notice that you seem to be looking for a single 'palette index'. It is well worth to remember that on the PSX, the TIM files include specific coordinates in the frame buffer, where the CLUT and image data will be loaded, and the CLUT is then referred to by those coordinates (see halkun's PSX doc for closer info on exactly how these coordinates are fed in GPU drawing commands). It is very common (among Square games, at least) to simply mirror the required information in the data files to minimize processing overhead, thus you're most likely looking for a set of CLUT coordinates instead of a single index. These usually are stored in order and can thus be sort of handled as an index as well, but it's by no means a fool-proof method.

Cyberman

  • *
  • Posts: 1572
    • View Profile
FF7 - PSX battle scenes
« Reply #2 on: 2005-07-02 18:21:50 »
CPal is a global value that's used to 'Current Palette' bad programing style but .. it was done 2 years ago.  Also it was used for 'sorting' through TIMs palettes.

The TIM function has a few incarnations.
The first incarnation specifically reads through and decodes a TIM file to a bitmap.
The second incarnation of TIM specifically targets CPal and ecodes a specific rectangular section of the TIM using that Palette.
The first parameter for this tim is the target bitmap
The second parameter is the TIM data.
The third is a Texture structure (defined elsewhere).
The remaining parameters are
X1/ Start X
Y1/ Start Y
X2/ End X
Y2/ End Y
This incarnation does NOT read the palettes it assumes they are already decoded (hence the first TIM call decodes the palettes and sets the bitmaps height and width) the remaining TIM calls actually decode the TIM data by taking the MINX MINY MAXX MAXY UV values and using the palette used with that polygon (triangle or quadric).
XOff is computed as what section of the TIM is being converted as the UV values only have a range of 0-255.
It first sets the bitmaps width and height values (of course!) then decodes each palette to the global palette cache (surprisinly named PAL). PAL contains 16 ot 256 entry palettes used for 4 and 8 bit TIMs.   All the palettes of a TIM are dumped into this.  

PSX_FF7 definitions you were wondering about:
Code: [Select]
typedef struct
{
   UINT16   Parent;
   INT16    Length;
   UINT32   Offset;
}
PSX_UNK_BM;

typedef struct
{
   UINT8 R;
   UINT8 G;
   UINT8 B;
   UINT8 U;
}
PSX_FF7_CLR;

typedef struct
{
   INT16   X;
   INT16   Y;
   INT16   Z;
   UINT16  U;

}
PSX_FF7_VERTEX;

typedef struct
{
   UINT16   A;
   UINT16   B;
   UINT16   C;
   UINT16   D;
}
PSX_FF7_POLY;

typedef struct
{
   UINT16   Count;
   UINT16   TPage;
}
PSX_FF7_PCNT;

typedef struct
{
   PSX_FF7_POLY  Vertexs;
   PSX_FF7_CLR   Colors[3];
}
PSX_FF7_TRI;

typedef struct
{
   PSX_FF7_POLY  Vertexs;
   PSX_FF7_CLR   Colors[4];
}
PSX_FF7_QUAD;

typedef struct
{
   PSX_FF7_POLY   Vertexs;
   UINT8          U0, V0;
   UINT16         PAL;
   UINT8          U1, V1;
   UINT8          U2, V2;
}
PSX_FF7_TTRI;

typedef struct
{
   PSX_FF7_POLY   Vertexs;
   UINT8          U0, V0;
   UINT16         PAL;
   UINT8          U1, V1;
   UINT8          U2, V2;
   UINT8          U3, V3;
   UINT16         ZZ1;
}
PSX_FF7_TQUAD;


Anyhow, I think your suggestion on the palette index computation, might prove to be quite useful, I'll have to examine if they are using the 'index' as a Y value from the base index of the pallets in the VRAM of the PSX memory.  I suppose 'emulating' the VRAM might be more helpful in dealing with PSX FF7 information decoding? :D

Cyb

Cyberman

  • *
  • Posts: 1572
    • View Profile
FF7 - PSX battle scenes
« Reply #3 on: 2005-07-03 04:17:18 »
Qhimm it doesn't appear to be the case that it is relative to the Y value.. at all.  The numbers are impossible to corelate so that's not it.  Stuff happens I guess.
It may be just a direct offset. I'll have to start 'examining' PSX memory with my debuger again (bleah).
However I do believe I spoted par of what is wrong believe it or not.

Instead of :
Code: [Select]
TTri = Triangles[Index];
it should be:
Code: [Select]
TTri = Triangles[PIndex];
that's part of it.
The second issue seems to be with the Quadrics. Here is a layout based on my current UV usage. It seems rather strange some of the odd layout issues with the UV coords.  It might be that the quads mirror some of the triangles in some cases (ponders).

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
FF7 - PSX battle scenes
« Reply #4 on: 2005-07-03 09:50:57 »
I don't suppose you could upload or mail me a copy of the code, along with that particular LZS file? I could probably help spot it better if I could see it running, as well.

Cyberman

  • *
  • Posts: 1572
    • View Profile
Interesting.. info
« Reply #5 on: 2005-07-05 17:23:29 »
All right I modified the 'BMP" file output to turn all things that are set transparent magenta here is the result.
Cyan outlines are the first object and then the system goes all the way to the 24.. if there are more than 24 the remaining are White

I've mostly fixed the palette usage and I believe I've done the same with the outlining of the UV coordinates.  It appears that my strange problem was due the fact multiple poly sets use the same texture.  SO there you have it.  I've hopefully corrected transparent textures.  This example one I've been using is number 'oh' on the PC if you have Zangan handy.
I'll now be trying to actually show the battle scene polygons as well as fix the texture generating issues on battle models.

Cyb