Skip to content

Commit

Permalink
Fixed TSP rendering code not accounting for non-textured faces,fixed …
Browse files Browse the repository at this point in the history
…typos in the README file,added a new section about the animated light block inside the BSD file
  • Loading branch information
AdrianoDiDio committed Apr 14, 2024
1 parent c879362 commit 7cb6352
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 32 deletions.
51 changes: 41 additions & 10 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Table of contents
* [UV Coordinates](#uv-coordinates)
+ [BSD Files](#bsd-files)
- [File Format](#file-format)
* [Animated Lights Block](#animated-lights-block)
* [RenderObject Block](#renderobject-block)
+ [Color Mode](#color-mode)
+ [Texture Page](#texture-page)
Expand Down Expand Up @@ -272,17 +273,47 @@ probably contains a list of CD sectors that were required by the PSX in
order to correctly read the file.
**Note that all the offset contained inside the file starts from 2048.**

Right after the header the information about the corresponding TSP file is
found if it is a level file otherwise it's replaced by zeroes.
##### Animated Lights Block

This block is found at position 64 (excluding the header) or 2112
(including the header) and contains information about animated lights that
can be used by the TSP file in order to render special effects like running
water from a river,a blinking light etc...
Each animated lights is contained in a structure that has a fixed size of
20 bytes:

| Type | Size | Description |
| ---- | ------- | ------------------- |
| int | 4 bytes | NumColors |
| int | 4 bytes | StartingColorOffset |
| int | 4 bytes | ColorIndex |
| int | 4 bytes | CurrentColor |
| int | 4 bytes | Delay |

Every animated light has a number of colors that are loaded at the
specified StartingColorOffset (to which you would add 4-bytes until all
colors are read).
Each color is just a 4-byte integer that represents the 3 components (RGB)
plus a constant value that it is used to restart the animation ( by setting
the Delay value to this constant ).
Every frame the animated light structure is updated only if the Delay
reaches zero, after which the ColorIndex is incremented wrapping around
only when it reaches the maximum value represented by NumColors.
ColorIndex is used to select the current color that will be used by the
surface during rendering time.
The list of colors can be actually found after the RenderObject block and
it is not meant to be read sequentially but loaded when parsing this
block.


##### RenderObject Block

At the offset 0x1D8 (472) after the header,we find the number of RenderObject stored as an int
(4 bytes).
A RenderObject, as the name implies , are all the objects that can be rendered by the
game (the main level, models, powerups etc...)
Each RenderObject has a fixed size of 2124 bytes containing several fields that depending by the type of
the RenderObject can be NULL or contains an offset to the data stored inside the BSD file.
At the offset 0x1D8 (472) after the header,we find the number of
RenderObject stored as an int (4 bytes).
A RenderObject, as the name implies, are all the objects that can be
rendered by the game (the main level, models, powerups etc...)
Each RenderObject has a fixed size of 2124 bytes containing several fields
that, depending by the type of the RenderObject, can be NULL or contains an offset to the data stored inside the BSD file.

| Type | Size | Description |
| -------------- | -------- | ------------------------------------------------------------------ |
Expand Down Expand Up @@ -310,8 +341,8 @@ the RenderObject can be NULL or contains an offset to the data stored inside the
**NOTE that ScaleX/Y/Z Values must be divided by 16 and the value found is
in fixed point format where 4096 is equal to 1.**

Textured face data contains two identical data structure followed by the encoded
vertex indices:
Textured face data contains two identical data structure followed by the
encoded vertex indices:

| Type | Size | Description |
| --------------------- | ------- | -------------------------- |
Expand Down
33 changes: 19 additions & 14 deletions src/JPModelViewer/TSP.c
Original file line number Diff line number Diff line change
Expand Up @@ -595,11 +595,11 @@ void TSPCreateFaceVAO(TSP_t *TSP,TSPNode_t *Node)
U2,V2);
if( (TSB & 0x4000) != 0) {
TSPFillFaceVertexBuffer(TransparentVertexData,&TransparentVertexPointer,TSP->Vertex[Vert0],
TSP->Color[Vert0],U0,V0,CLUTDestX,CLUTDestY,ColorMode,true);
TSP->Color[Vert0],U0,V0,CLUTDestX,CLUTDestY,ColorMode,Node->FaceList[i].IsTextured);
TSPFillFaceVertexBuffer(TransparentVertexData,&TransparentVertexPointer,TSP->Vertex[Vert1],
TSP->Color[Vert1],U1,V1,CLUTDestX,CLUTDestY,ColorMode,true);
TSP->Color[Vert1],U1,V1,CLUTDestX,CLUTDestY,ColorMode,Node->FaceList[i].IsTextured);
TSPFillFaceVertexBuffer(TransparentVertexData,&TransparentVertexPointer,TSP->Vertex[Vert2],
TSP->Color[Vert2],U2,V2,CLUTDestX,CLUTDestY,ColorMode,true);
TSP->Color[Vert2],U2,V2,CLUTDestX,CLUTDestY,ColorMode,Node->FaceList[i].IsTextured);
RenderingFace->VAOBufferOffset = TSP->TransparentVAO->CurrentSize;
RenderingFace->BlendingMode = (TSB >> 5 ) & 3;
RenderingFace->Flags |= TSP_FX_TRANSPARENT_FACE;
Expand All @@ -610,11 +610,11 @@ void TSPCreateFaceVAO(TSP_t *TSP,TSPNode_t *Node)

} else {
TSPFillFaceVertexBuffer(VertexData,&VertexPointer,TSP->Vertex[Vert0],
TSP->Color[Vert0],U0,V0,CLUTDestX,CLUTDestY,ColorMode,true);
TSP->Color[Vert0],U0,V0,CLUTDestX,CLUTDestY,ColorMode,Node->FaceList[i].IsTextured);
TSPFillFaceVertexBuffer(VertexData,&VertexPointer,TSP->Vertex[Vert1],
TSP->Color[Vert1],U1,V1,CLUTDestX,CLUTDestY,ColorMode,true);
TSP->Color[Vert1],U1,V1,CLUTDestX,CLUTDestY,ColorMode,Node->FaceList[i].IsTextured);
TSPFillFaceVertexBuffer(VertexData,&VertexPointer,TSP->Vertex[Vert2],
TSP->Color[Vert2],U2,V2,CLUTDestX,CLUTDestY,ColorMode,true);
TSP->Color[Vert2],U2,V2,CLUTDestX,CLUTDestY,ColorMode,Node->FaceList[i].IsTextured);

RenderingFace->VAOBufferOffset = Node->OpaqueFacesVAO->CurrentSize;
RenderingFace->Flags |= TSP_FX_NONE;
Expand Down Expand Up @@ -1043,7 +1043,7 @@ void TSPDrawTransparentFaces(TSP_t *TSP,VRAM_t *VRAM)
return;
}

if( 0/*LevelEnableWireFrameMode->IValue*/ ) {
if( EnableWireFrameMode->IValue ) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
Expand Down Expand Up @@ -1078,7 +1078,7 @@ void TSPDrawTransparentFaces(TSP_t *TSP,VRAM_t *VRAM)
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D,0);
glDisable(GL_BLEND);
if( 0/*LevelEnableWireFrameMode->IValue*/ ) {
if( EnableWireFrameMode->IValue ) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
Expand Down Expand Up @@ -1185,7 +1185,6 @@ int TSPReadNodeChunk(TSP_t *TSP,FILE *InFile,int TSPOffset)
int CurrentFaceIndex;
int PrevFilePosition;
unsigned short PrimitiveType;
TSPUv_t Pad;
int i;

if( !TSP || !InFile ) {
Expand Down Expand Up @@ -1246,21 +1245,27 @@ int TSPReadNodeChunk(TSP_t *TSP,FILE *InFile,int TSPOffset)
case 2:
case 4:
case 6:
//Triangle, Texture On If 0 Off 4
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].V0,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].V0),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].V1,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].V1),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].V2,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].V2),1,InFile);
TSP->Node[i].FaceList[CurrentFaceIndex].IsTextured = false;
CurrentFaceIndex++;
break;
case 1:
case 3:
case 5:
case 7:
//Quad, Texture On If 1 Off 5
fread(&TSP->Node[i].FaceList[CurrentFaceIndex],sizeof(TSPFace_t),1,InFile);
fread(&Pad,sizeof(Pad),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].V0,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].V0),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].V1,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].V1),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].V2,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].V2),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].UV0,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].UV0),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].CBA,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].CBA),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].UV1,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].UV1),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].TSB,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].TSB),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].UV2,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].UV2),1,InFile);
fread(&TSP->Node[i].FaceList[CurrentFaceIndex].Pad,sizeof(TSP->Node[i].FaceList[CurrentFaceIndex].Pad),1,InFile);
TSP->Node[i].FaceList[CurrentFaceIndex].IsTextured = true;
TSPPrintFace(&TSP->Node[i].FaceList[CurrentFaceIndex]);
DPrintf("Pad %i;%i\n",Pad.u,Pad.v);
CurrentFaceIndex++;
break;
default:
Expand Down
18 changes: 10 additions & 8 deletions src/JPModelViewer/TSP.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,16 @@ typedef struct TSPRenderingFace_s {

//16 Bytes.
typedef struct TSPFace_s {
unsigned short V0;
unsigned short V1;
unsigned short V2;
TSPUv_t UV0;
unsigned short CBA;
TSPUv_t UV1;
unsigned short TSB;
TSPUv_t UV2;
unsigned short V0;
unsigned short V1;
unsigned short V2;
TSPUv_t UV0;
unsigned short CBA;
TSPUv_t UV1;
unsigned short TSB;
TSPUv_t UV2;
short Pad;
bool IsTextured;
} TSPFace_t;

//36 Bytes.
Expand Down

0 comments on commit 7cb6352

Please sign in to comment.