EvilEngine/JSP: Difference between revisions

From Heavy Iron Modding
Content added Content deleted
m (Seil moved page JSP to EvilEngine/JSP)
(Begin version 5 jsp)
Line 10: Line 10:
{{AutoAssetInfobox}}
{{AutoAssetInfobox}}


JSP is an asset type which defines a 3D model. It's a RenderWare binary stream file. There are two types of JSP: the normal (model) has a format much similar to a DFF. They can be opened by RWAnalyze and other tools that work with RenderWare models. [https://gtamods.com/wiki/RenderWare_binary_stream_file GTAModding] has a lot of useful information regarding this format. The other format is used for visibility and collision data and is very different from a normal JSP/DFF, but still follows the layout of a RenderWare binary stream file, with three custom sections.
JSP is an asset type which defines a 3D model. It's a RenderWare binary stream file. There are two types of JSP: the normal (model) has a format much similar to a DFF and is stored in the BSP layer. They can be opened by RWAnalyze and other tools that work with RenderWare models. [https://gtamods.com/wiki/RenderWare_binary_stream_file GTAModding] has a lot of useful information regarding this format. The other format is used for visibility and collision data and is very different from a normal JSP/DFF, but still follows the layout of a RenderWare binary stream file with four custom sections and is stored in the JSP Info layer.


===Format (Visibility/Collision JSP)===
===Format (Visibility/Collision JSP)===
Line 31: Line 31:
__rwMark mark; // type = 0xBEEF01
__rwMark mark; // type = 0xBEEF01


unsigned int magic = 'CCOL'; // 'LOCC' on GameCube
unsigned int magic;
unsigned int numBranchNodes;
unsigned int numBranchNodes;
unsigned int numTriangles;
unsigned int numTriangles;
Line 38: Line 38:
xClumpCollBSPTriangle triangles[numTriangles];
xClumpCollBSPTriangle triangles[numTriangles];
</source>
</source>

{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || u32 || magic || "CCOL" (little-endian, PS2/XBOX)<br>"LOCC" (big-endian, GameCube)
|-
| 0x04 || u32 || '''numBranchNodes''' || Amount of xClumpCollBSPBranchNode entries
|-
| 0x08 || u32 || '''numTriangles''' || Amount of xClumpCollBSPTriangle entries
|-
| 0x0C || xClumpCollBSPBranchNode[] || '''branchNodes''' ||
|-
| 0x0C + (0x10*numBranchNodes) || xClumpCollBSPTriangle[] || '''triangles''' ||
|}



<source lang=cpp>
<source lang=cpp>
Line 47: Line 62:
float rightValue;
float rightValue;
};
};
</source>
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || u32 || '''leftInfo''' ||
|-
| 0x04 || u32 || '''rightInfo''' ||
|-
| 0x08 || f32 || '''leftValue''' ||
|-
| 0x0C || f32 || '''rightValue''' ||
|}



<source lang=cpp>
struct xClumpCollBSPTriangle
struct xClumpCollBSPTriangle
{
{
unsigned short atomIndex; // atomic index in all JSPs combined
unsigned short atomIndex;
unsigned short meshVertIndex; // vertex index in atomic's mesh
unsigned short meshVertIndex;
unsigned char flags;
unsigned char flags;
unsigned char platData;
unsigned char platData; // BFBB
unsigned char detailed_info_cache_index // TSSM-RatProto
unsigned short matIndex;
unsigned short matIndex;
};
};
</source>
</source>
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || u16 || '''atomIndex''' || Atomic index in all JSPs combined
|-
| 0x02 || u16 || '''meshVertIndex''' || Vertex index in atomic's mesh
|-
| 0x04 || u8 || '''flags''' ||
|-
| 0x05 || u8 || '''platData''' / '''detailed_info_cache_index''' ||
|-
| 0x06 || u16 || '''matIndex'''
|}



====Section 2 (JSP Info)====
====Section 2 (JSP Info)====
This section contains rendering info for all of the RW Atomics ("nodes") in the other JSPs.
This section contains rendering info for all of the RW Atomics ("nodes") in the other JSPs.


=====Version 3 (BFBB)=====
<source lang=cpp>
<source lang=cpp>
__rwMark mark; // type = 0xBEEF02
__rwMark mark; // type = 0xBEEF02


char idtag[4] = "JSP\0";
char idtag[4];
unsigned int version; // usually 3
unsigned int version;
unsigned int jspNodeCount;
unsigned int jspNodeCount;
RpClump* clump;
void* unused[3]; // always null (0), used interally as C++ pointers at runtime
xClumpCollBSPTree* colltree;
xJSPNodeInfo* jspNodeList;


xJSPNodeInfo jspNodeList[jspNodeCount];
xJSPNodeInfo jspNodeList[jspNodeCount];
</source>
</source>
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || char[4] || '''idtag''' || "JSP\0"
|-
| 0x04 || u32 || '''version ''' || Always 3 in BFBB
|-
| 0x08 || u32 || '''jspNodeCount''' || Amount of xJSPNodeInfo entries
|-
| 0x0C || u32*[3] || - || Always null (0), used internally as C++ pointers at runtime
|-
| 0x18 || xJSPNodeInfo[] || '''jspNodeList''' ||
|}



<source lang=cpp>
<source lang=cpp>
Line 79: Line 140:
};
};
</source>
</source>
{| class="wikitable"

! Offset !! Type !! Variable !! Description
<code>xJSPNodeInfo::nodeFlags</code> is used to toggle various rendering states:
|-
| 0x00 || s32 || ''' originalMatIndex''' ||
|-
| 0x04 || s32 || '''nodeFlags''' || Used to toggle various rendering states:
* 0x2 - Toggle Z-Buffer write on/off. Starting state is on.
* 0x2 - Toggle Z-Buffer write on/off. Starting state is on.
* 0x4 - Toggle Cull Mode between Front/Back face. Starting state is Back.
* 0x4 - Toggle Cull Mode between Front/Back face. Starting state is Back.
|}



====Section 3 (Pre-calculated Vertices, GCN only)====
=====Version 5 (TSSM - RatProto)=====
This section contains a list of vertices extracted from every mesh in every JSP's atomic combined. This is used for collision checking on GameCube only.
<source lang=cpp>
__rwMark mark; // type = 0xBEEF02

char idtag[4];
unsigned int version;
unsigned int jspNodeCount;
RpClump* clump;
xClumpCollBSPTree* colltree;
xJSPNodeInfo* jspNodeList;
unsigned int stripVecCount;
RwV3d* stripVecList;
unsigned short vertDataFlags;
unsigned short vertDataStride;
xJSPNodeTree* nodetree;
xJSPNodeLight* nodelight;

xJSPNodeInfo jspNodeList[jspNodeCount];

int numBranchNodes;
xJSPNodeTreeBranch* branchNodes;
int numLeafNodes;
xJSPNodeTreeLeaf* leafNodes;

xJSPNodeTreeBranch branchNodes[numBranchNodes];
xJSPNodeTreeLeaf leafNodes[numLeafNodes];

//This is the same as Section 3 in BFBB
unsigned int stripVecCount;
RwV3d stripVecList[vertCount];
</source>
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || char[4] || '''idtag''' || "JSP\0"
|-
| 0x04 || u32 || '''version''' || Always 5
|-
| 0x08 || u32 || '''jspNodeCount''' || Amount of xJSPNodeInfo entries
|-
| 0x0C || RpClump* || '''clump''' || Always null
|-
| 0x10 || xClumpCollBSPTree* || '''colltree''' || Always null
|-
| 0x14 || xJSPNodeInfo* || '''jspNodeList''' || Always null
|-
| 0x18 || u32 || '''stripVecCount''' || Always null
|-
| 0x1C || RwV3d* || '''stripVecList''' || Always null
|-
| 0x20 || u16 || '''vertDataFlags''' || Always null
|-
| 0x22 || u16 || '''vertDataStride''' || Always null
|-
| 0x24 || xJSPNodeTree* || '''nodetree''' || Always null
|-
| 0x28 || xJSPNodeLight* || '''nodelight''' || Always null
|-
| 0x2C || xJSPNodeInfo[] || '''jspNodeList''' || Array of xJSPNodeInfo entries
|-
| || s32 || '''numBranchNodes''' || Amount of xJSPNodeTreeBranch entries
|-
| || xJSPNodeTreeBranch* || '''branchNodes''' || Always null
|-
| || s32 || '''numLeafNodes''' || Amount of xJSPTreeLeaf entries
|-
| || xJSPNodeTreeLeaf* || '''leafNodes''' || Always null
|-
| || xJSPNodeTreeBranch[] || '''branchNodes''' || Array of xJSPNodeTreeBranch entries
|-
| || xJSPNodeTreeLeaf[] || '''leafNodes''' || Array of xJSPNodeTreeLeaf entries
|-
| || u32 || '''stripVecCount''' || Amount of array entries
|-
| || RwV3d[] || '''stripVecList''' || Vector3 array of pre-calculated vertices
|}


<source lang=cpp>
struct xJSPNodeInfo
{
int originalMatIndex;
unsigned short nodeFlags;
signed short sortOrder;
};
</source>
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || s32 || '''originalMatIndex''' ||
|-
| 0x04 || u16 || '''nodeFlags''' ||
|-
| 0x06 || s16 || '''sortOrder''' ||
|}

<source lang=cpp>
struct xJSPNodeTreeBranch
{
unsigned short leftNode;
unsigned short rightNode;
unsigned char leftType;
unsigned char rightType;
unsigned short coord;
float leftValue;
float rightValue;
};
</source>
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || u16 || '''leftNode''' ||
|-
| 0x02 || u16 || '''rightNode''' ||
|-
| 0x04 || u8 || '''leftType''' ||
|-
| 0x05 || u8 || '''rightType''' ||
|-
| 0x06 || u16 || '''coord''' ||
|-
| 0x08 || f32 || '''leftValue''' ||
|-
| 0x0C || f32 || '''rightValue''' ||
|}
<source lang=cpp>
struct xJSPNodeTreeLeaf
{
int nodeIndex;
int leafCount;
RwBBox box;
};

struct RwBBox
{
RwV3d sup;
RwV3d inf;
};
</source>
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || s32 || '''nodeIndex''' ||
|-
| 0x04 || s32 || '''leafCount''' ||
|-
| 0x08 || RwBBox || '''box''' ||
|}


====Section 3 (Pre-calculated Vertices, BFBB GCN only)====
This section contains a list of vertices extracted from every mesh in every JSP's atomic combined. This is used for collision checking on BFBB GameCube only.
<source lang=cpp>
<source lang=cpp>
__rwMark mark; // type = 0xBEEF03
__rwMark mark; // type = 0xBEEF03
Line 99: Line 316:
};
};
</source>
</source>


====Section 4 (Extra Info)====
Not present in BFBB.

<source lang=cpp>
__rwMark mark; // type = 0xBEEF04

char idtag[4] = "JSP\0";
xBox bounds;
</source>

<source lang=cpp>
struct xBox
{
xVec3 upper;
xVec3 lower;
};
</source>




==Jason Hoerner's information on the custom JSP==
==Jason Hoerner's information on the custom JSP==

Revision as of 15:10, 8 October 2023

JSP
JSP
TypeRenderWare
Games usedBattle for Bikini Bottom

The SpongeBob SquarePants Movie
The Incredibles
Rise of the Underminer

Ratatouille Prototype
Source codexJSP.h

JSP is an asset type which defines a 3D model. It's a RenderWare binary stream file. There are two types of JSP: the normal (model) has a format much similar to a DFF and is stored in the BSP layer. They can be opened by RWAnalyze and other tools that work with RenderWare models. GTAModding has a lot of useful information regarding this format. The other format is used for visibility and collision data and is very different from a normal JSP/DFF, but still follows the layout of a RenderWare binary stream file with four custom sections and is stored in the JSP Info layer.

Format (Visibility/Collision JSP)

Section header format

This is the standard format for RenderWare section headers.

struct __rwMark
{
  unsigned int type; // section type
  unsigned int length; // section size
  unsigned int libraryID; // renderware version
};

Section 1 (BSP Tree)

This section contains a k-d tree, used for collision checking.

__rwMark mark; // type = 0xBEEF01

unsigned int magic;
unsigned int numBranchNodes;
unsigned int numTriangles;

xClumpCollBSPBranchNode branchNodes[numBranchNodes];
xClumpCollBSPTriangle triangles[numTriangles];
Offset Type Variable Description
0x00 u32 magic "CCOL" (little-endian, PS2/XBOX)
"LOCC" (big-endian, GameCube)
0x04 u32 numBranchNodes Amount of xClumpCollBSPBranchNode entries
0x08 u32 numTriangles Amount of xClumpCollBSPTriangle entries
0x0C xClumpCollBSPBranchNode[] branchNodes
0x0C + (0x10*numBranchNodes) xClumpCollBSPTriangle[] triangles


struct xClumpCollBSPBranchNode
{
  unsigned int leftInfo;
  unsigned int rightInfo;
  float leftValue;
  float rightValue;
};
Offset Type Variable Description
0x00 u32 leftInfo
0x04 u32 rightInfo
0x08 f32 leftValue
0x0C f32 rightValue


struct xClumpCollBSPTriangle
{
  unsigned short atomIndex;
  unsigned short meshVertIndex;
  unsigned char flags;
  unsigned char platData; // BFBB
  unsigned char detailed_info_cache_index // TSSM-RatProto
  unsigned short matIndex;
};
Offset Type Variable Description
0x00 u16 atomIndex Atomic index in all JSPs combined
0x02 u16 meshVertIndex Vertex index in atomic's mesh
0x04 u8 flags
0x05 u8 platData / detailed_info_cache_index
0x06 u16 matIndex


Section 2 (JSP Info)

This section contains rendering info for all of the RW Atomics ("nodes") in the other JSPs.

Version 3 (BFBB)
__rwMark mark; // type = 0xBEEF02

char idtag[4];
unsigned int version;
unsigned int jspNodeCount;
RpClump* clump;
xClumpCollBSPTree* colltree;
xJSPNodeInfo* jspNodeList;

xJSPNodeInfo jspNodeList[jspNodeCount];
Offset Type Variable Description
0x00 char[4] idtag "JSP\0"
0x04 u32 version Always 3 in BFBB
0x08 u32 jspNodeCount Amount of xJSPNodeInfo entries
0x0C u32*[3] - Always null (0), used internally as C++ pointers at runtime
0x18 xJSPNodeInfo[] jspNodeList


struct xJSPNodeInfo
{
  int originalMatIndex;
  int nodeFlags;
};
Offset Type Variable Description
0x00 s32 originalMatIndex
0x04 s32 nodeFlags Used to toggle various rendering states:
  • 0x2 - Toggle Z-Buffer write on/off. Starting state is on.
  • 0x4 - Toggle Cull Mode between Front/Back face. Starting state is Back.


Version 5 (TSSM - RatProto)
__rwMark mark; // type = 0xBEEF02

char idtag[4];
unsigned int version; 
unsigned int jspNodeCount; 
RpClump* clump;
xClumpCollBSPTree* colltree;
xJSPNodeInfo* jspNodeList;
unsigned int stripVecCount;
RwV3d* stripVecList;
unsigned short vertDataFlags;
unsigned short vertDataStride;
xJSPNodeTree* nodetree;
xJSPNodeLight* nodelight; 

xJSPNodeInfo jspNodeList[jspNodeCount];

int numBranchNodes;
xJSPNodeTreeBranch* branchNodes;
int numLeafNodes;
xJSPNodeTreeLeaf* leafNodes; 

xJSPNodeTreeBranch branchNodes[numBranchNodes];
xJSPNodeTreeLeaf leafNodes[numLeafNodes];

//This is the same as Section 3 in BFBB
unsigned int stripVecCount;
RwV3d stripVecList[vertCount];
Offset Type Variable Description
0x00 char[4] idtag "JSP\0"
0x04 u32 version Always 5
0x08 u32 jspNodeCount Amount of xJSPNodeInfo entries
0x0C RpClump* clump Always null
0x10 xClumpCollBSPTree* colltree Always null
0x14 xJSPNodeInfo* jspNodeList Always null
0x18 u32 stripVecCount Always null
0x1C RwV3d* stripVecList Always null
0x20 u16 vertDataFlags Always null
0x22 u16 vertDataStride Always null
0x24 xJSPNodeTree* nodetree Always null
0x28 xJSPNodeLight* nodelight Always null
0x2C xJSPNodeInfo[] jspNodeList Array of xJSPNodeInfo entries
s32 numBranchNodes Amount of xJSPNodeTreeBranch entries
xJSPNodeTreeBranch* branchNodes Always null
s32 numLeafNodes Amount of xJSPTreeLeaf entries
xJSPNodeTreeLeaf* leafNodes Always null
xJSPNodeTreeBranch[] branchNodes Array of xJSPNodeTreeBranch entries
xJSPNodeTreeLeaf[] leafNodes Array of xJSPNodeTreeLeaf entries
u32 stripVecCount Amount of array entries
RwV3d[] stripVecList Vector3 array of pre-calculated vertices


struct xJSPNodeInfo
{
    int originalMatIndex;
    unsigned short nodeFlags;
    signed short sortOrder;
};
Offset Type Variable Description
0x00 s32 originalMatIndex
0x04 u16 nodeFlags
0x06 s16 sortOrder
struct xJSPNodeTreeBranch
{
    unsigned short leftNode;
    unsigned short rightNode;
    unsigned char leftType;
    unsigned char rightType;
    unsigned short coord; 
    float leftValue;
    float rightValue;
};
Offset Type Variable Description
0x00 u16 leftNode
0x02 u16 rightNode
0x04 u8 leftType
0x05 u8 rightType
0x06 u16 coord
0x08 f32 leftValue
0x0C f32 rightValue
struct xJSPNodeTreeLeaf
{
    int nodeIndex;
    int leafCount;
    RwBBox box;
};

struct RwBBox
{
    RwV3d sup; 
    RwV3d inf;
};
Offset Type Variable Description
0x00 s32 nodeIndex
0x04 s32 leafCount
0x08 RwBBox box


Section 3 (Pre-calculated Vertices, BFBB GCN only)

This section contains a list of vertices extracted from every mesh in every JSP's atomic combined. This is used for collision checking on BFBB GameCube only.

__rwMark mark; // type = 0xBEEF03

unsigned int vertCount;
RwV3d verts[vertCount];
struct RwV3d
{
  float x, y, z;
};


Section 4 (Extra Info)

Not present in BFBB.

__rwMark mark; // type = 0xBEEF04

char idtag[4] = "JSP\0";
xBox bounds;
struct xBox
{
    xVec3 upper;
    xVec3 lower;
};


Jason Hoerner's information on the custom JSP

JSP is actually self-named after me.  It stands for “Jason Space Partition”, a replacement for the “Binary Space Partition” supported by RenderWare.  It was based on RenderWare’s BSP format, but the key difference was that my version referenced external data also used for rendering, rather than storing a complete separate copy, saving memory.  And I wrote more efficient tool code to generate it, and runtime intersection code, but that’s more of an optimization, rather than something that directly affects how the format works.

The BSP/JSP format itself is a KD tree with overlap regions, used for spatial queries (like player collision or shadow intersection).  You can look up how a KD tree works on Wikipedia or whatever – I’ll try to explain the specifics of the overlap regions.  Here’s a diagram:

The overlap region is defined by a pair of axis aligned planes (you’ll probably see two floating point numbers, kind of close to one another), which divide space into three regions, left, right, and overlap.  There is another value (probably 0,1,2 integer) that selects which axis it represents.  The blue triangles all go in the right branch of the KD tree, while the green triangles all go in the left branch.

When doing a spatial query, if your query is entirely to the right of right plane, you only need to go down the right branch of the tree.  If your query is entirely to the left of the left plane, you only go down the left branch.  If your query touches the overlap region, you need to go down both sides of the tree, because some triangles on both sides could be intersected.  If you’re doing a long thin query (like a ray or capsule), you can clip the ray or capsule to the overlap plane before recursing (which makes it smaller for the next query).

Regarding DFF, besides the JSP replacing BSP, and some post optimizations specific to PS2 command buffers, we didn’t do anything with the DFF importer, and used what RenderWare created verbatim.  So I can’t give details on the contents or import of a DFF.  But hopefully those basic details of the KD tree implementation will help some.

The editor we used for the game was called the “EvilEditor”, and I didn’t do any work on it myself.  It was named after Evil Dead, the first game Heavy Iron worked on, which was before I started working there.  I did do a lot of work on its successor, the “GoodEditor” (which was used for all of Heavy Iron’s post RenderWare games).  I can tell you all 3D geometry was built in Maya, and the EvilEditor itself was only used for object placement, setting object parameters, and scripting.

The scripting was all event based, there was no actual scripting language.  Objects could send events to other objects, and an FNV hash of the string name of each object was used as an identifier for the object to send it to.  Maybe searching for things that look like hashes (obviously not floats or integers) will make it obvious where events are present in the code.  The game included a system where updates of distant objects were turned off for performance, including a feature where you could group objects to all update together.  The “group update together” feature was used to ensure synced objects (like moving patterns of Tikis) would stay in the same pattern, and dependent objects (like teleport box pairs) would activate together.

I did the collision system.  It includes an outer sphere which does “move and de-penetrate” (let the character move and go inside triangles a bit, then try to push him back out), and an inner sphere which attempts to do continuous capsule based collision, so when moving very fast, he hopefully doesn’t go through anything, but obviously speed runners have figured out how to break that!  The outer sphere categorizes primitives as if the player is a cube, and picks the nearest collision along each face of the cube, and solves for where to place the character that’s outside of any collision.  With lots of special cases to try to make it not jitter, and hard to get stuck (if you compare to Scooby Doo, the previous game where I didn’t do the collision, that has nasty jitter).  I think Patrick has a second smaller sphere for the head, but I’m not sure…

Anyway, that’s the stuff I thought of for now, I’ll let you know if I think of anything else interesting…

--Jason