Add objdiff setup

This is intended more as a proof of concept as we figure things out
than the start of an actual decompilation in this repository.  Target
object files are currently "bring your own."
This commit is contained in:
KeybadeBlox 2025-12-14 19:27:11 -05:00
parent 10b3c8c273
commit 7e1785e466
12 changed files with 151 additions and 27 deletions

10
objdiff/Makefile Normal file
View file

@ -0,0 +1,10 @@
all: src/Jet2.obj
# Simple inference rule for producing object files
.SUFFIXES: .cpp .obj
.cpp.obj:
CL.EXE /nologo /Wall /TP /W3 /O2 /G6 /MT /GX /Fo$@ /c $<
# Header files used for each object
src/Jet2.obj: src/Core.hpp src/D3D.hpp src/MMatrix.hpp src/Std.hpp\
src/Win32.hpp

22
objdiff/objdiff.json Normal file
View file

@ -0,0 +1,22 @@
{
"custom_make": "NMAKE.EXE",
"watch_patterns": [
"*.cpp",
"*.hpp"
],
"units": [
{
"name": "Jet2",
"target_path": "target/Jet2.obj",
"base_path": "src/Jet2.obj",
"complete": true,
"metadata": {
"source_path": "src/Jet2.cpp"
},
"symbol_mappings": {
"FUN_00187710": "$L514",
"FUN_0018771b": "$L522"
}
}
]
}

1
objdiff/src/Core.cpp Normal file
View file

@ -0,0 +1 @@
#include "Core.hpp"

189
objdiff/src/Core.hpp Normal file
View file

@ -0,0 +1,189 @@
/* JSRF Decompilation: Core.hpp
Game and GameObj classes that form the foundation of the JSRF game code.
*/
#ifndef CORE_HPP
#define CORE_HPP
#include "D3D.hpp"
#include "MMatrix.hpp"
#include "Std.hpp"
#include "Win32.hpp"
// TODO; move to header for Graphics COM object in Smilebit libraries
struct GraphicsPerformanceCounters {
unsigned fps;
unsigned trianglesPerSecond;
unsigned frameTriangleCnt;
unsigned unknown0xC;
unsigned unknown0x10;
unsigned unknown0x14;
};
// Base class of most objects (and everything in g_game->objects)
class GameObj {
enum GameObjFlags {
GOF_SOMETHINGLINKED_ALTLIST = 1 << 0,
GOF_SKIPDRAWCHILDREN = 1 << 16,
GOF_SKIPDRAWASCHILD = 1 << 18,
GOF_SKIPDRAWASROOT = 1 << 22,
GOF_EXCLUDEFROMSOMETHINGLINKED = 1 << 30,
GOF_DELETEAFTEREXEC = 1 << 31
} flags;
// Position in g_game->objects array
// Different indices and ranges are dedicated to different kinds of
// objecs.
enum GameObjIndex {
OBJ_NOTINDEXED = -1, // Not stored in array
OBJ_DIRECTOR = 0
// TODO
} index;
unsigned otherBitfield;
float reverseSortKey; // Sign flipped to produced sortKey
unsigned sortKey; // Four-level key, one byte each
D3DVECTOR someTranslation;
// Links forming a tree of objects
GameObj * parent;
GameObj * firstChild;
GameObj * prevSibling;
GameObj * nextSibling;
// Some kind of linked list walked during rendering
GameObj * somethingLinkedNext;
GameObj * * somethingLinkedPrevNext;
GameObj * * * somethingLinkedEndNextPtr;
// Another linked list sort of arrangement
GameObj * someKindOfNextObj;
public:
virtual ~GameObj();
GameObj(GameObj * parent, GameObjIndex index, GameObjFlags flags);
// Each frame, one of these trios of methods is called depending on
// which state the game is in
// Default implementation of each does nothing; inheriting objects
// override these methods to run some code during each phase of each
// frame.
virtual void execDefault();
virtual void postExecDefault();
virtual void drawDefault();
virtual void execEvent();
virtual void postExecEvent();
virtual void drawEvent();
virtual void execCoveredPause();
virtual void postExecCoveredPause();
virtual void drawCoveredPause();
virtual void execFreezeCam();
virtual void postExecFreezeCam();
virtual void drawFreezeCam();
virtual void execUncoveredPause();
virtual void postExecUncoveredPause();
virtual void drawUncoveredPause();
// TODO: non-virtual methods
};
// Top-level globally-accessible "god object" that runs the main loop and
// provides global access to most other objects and many variables
extern class Game {
char unknown0x4[4];
unsigned unknown0x8;
unsigned * unknown0xC;
int initState;
unsigned unknown0x14;
BOOL drawProfilingInfo;
int unknown0x1C;
BOOL logosStarted;
BOOL fatalErr;
D3DCOLOR colour;
D3DCOLOR ambientColour;
D3DCOLOR shadowColour;
D3DCOLOR bgColour;
D3DCOLOR bgColourFallback;
BOOL useFallbackBgColour;
// Game state used to select GameObj methods to call in main loop
// If multiple states are acivated, the precedence is
// coveredPause > Event > FreezeCam > UncoveredPause > Default
BOOL coveredPause; // Game paused with world not visible
BOOL event; // Events (cutscenes)
BOOL freezeCam; // Time-frozen camera shots
BOOL uncoveredPause; // Game paused with world visible, or
// automatic pause at start of mission
BOOL setCoveredPauseNextFrame;
BOOL unsetCoveredPauseNextFrame;
BOOL setEventNextFrame;
BOOL unsetEventNextFrame;
BOOL setFreezeCamNextFrame;
BOOL unsetFreezeCamNextFrame;
BOOL setUncoveredPauseNextFrame;
BOOL unsetUncoveredPauseNextFrame;
unsigned unknown0x70;
BOOL skipDraw;
int zeroedByExec;
GraphicsPerformanceCounters perfCounters;
enum DrawMode {
DRAW_YES,
DRAW_WAITVBLANK,
DRAW_NO
} drawMode;
// Globally accessible objects and variables
GameObj * objects[7668];
unsigned globals[461]; // Items may be any 32-bit type, e.g. ptr
GameObj * somethingLinkedBHead;
GameObj * * somethingLinkedBEndNext;
GameObj * somethingLinkedAHead;
GameObj * * somethingLinkedAEndNext;
GameObj * sortedLinkedListHead;
GameObj * * sortedLinkedListEndNext;
GameObj * linkedListsByKeyHeads [256];
GameObj * * linkedListByKeyEndNexts[256];
LARGE_INTEGER execPerfCount;
LARGE_INTEGER drawPerfCount;
unsigned unknown0x87C8;
unsigned unknown0x87CC;
unsigned frameCnt1;
unsigned unknown0x87D4;
unsigned unknown0x87D8;
GameObj * rootExecObj;
int frameCnt2;
int frameCnt3;
unsigned gameObjCnt;
GameObj * rootDrawObj;
int unknown0x87F0;
int unknown0x87F4;
Mat4 unknown0x87F8;
unsigned unknown0x8838;
unsigned unknown0x883C;
public:
Game(unsigned *, unsigned);
virtual ~Game();
void initExecRootObj();
void mainLoop();
// TODO: other methods
} * g_game;
#endif

16
objdiff/src/D3D.hpp Normal file
View file

@ -0,0 +1,16 @@
/* JSRF Decompilation: D3D.hpp
Direct3D8 declarations.
*/
#ifndef D3D_HPP
#define D3D_HPP
#include "Win32.hpp"
typedef DWORD D3DCOLOR;
struct D3DVECTOR { float x, y, z ; };
struct D3DVECTOR4 { float x, y, z, w; };
#endif

19
objdiff/src/Jet2.cpp Normal file
View file

@ -0,0 +1,19 @@
#pragma bss_seg(".data")
#include "Core.hpp"
// Address: 0x0022FCE0
// Core.cpp really seems like a more natural place to put this, but it doesn't
// appear to be with Core.cpp's other data in .data
Game * g_game;
// Address: 0x0006F9E0
// Matching: yes
void main(void) {
g_game = new Game(NULL, 0);
g_game->initExecRootObj();
g_game->mainLoop();
delete g_game;
}

56
objdiff/src/MMatrix.cpp Normal file
View file

@ -0,0 +1,56 @@
#pragma code_seg("MMATRIX")
// Address: 0x00264C04
Mat4 * * g_matricesHead;
// Address: 0x00264C08
Mat4 * g_matrices[3];
// Address: 0x001BB690
// Matching: yes
HRESULT __stdcall initMatrices(unsigned const count) {
/* Initialize the matrix stack with the given number of matrices.
The requested number of matrices is rounded up to the nearest multiple of two.
The initialized matrices are accessible through g_matrices.
*/
// Allocate matrices
unsigned i = (count + 1) & 0xFFFFFFFE; // Round up
Mat4 * const mats = (Mat4 *)VirtualAlloc(
NULL,
(i + 2) * sizeof *mats,
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE
);
if (mats != NULL) {
Mat4 * mat = mats + 2;
// Initialize each matrix to identity
if (i > 0) for (; i > 0; i--) {
float * entry = (float *)mat;
for (unsigned j = 0; j < sizeof *mat/sizeof *entry; j++) {
*entry = 0;
entry += 1;
}
(*mat)[3].w = 1;
(*mat)[2].z = 1;
(*mat)[1].y = 1;
(*mat)[0].x = 1;
mat++;
}
// Assign to g_matrices for later access
mat = mats + 2;
g_matrices[1] = mats;
g_matrices[2] = mat;
g_matrices[0] = mats;
g_matricesHead = g_matrices + 2;
return ERROR_SUCCESS;
}
return E_OUTOFMEMORY;
}

14
objdiff/src/MMatrix.hpp Normal file
View file

@ -0,0 +1,14 @@
/* JSRF Decompilation: MMatrix.hpp
Smilebit's stack-based matrix math library.
*/
#ifndef MMATRIX_HPP
#define MMATRIX_HPP
#include "D3D.hpp"
// 4x4 matrix type
typedef D3DVECTOR4 Mat4[4];
#endif

12
objdiff/src/Std.hpp Normal file
View file

@ -0,0 +1,12 @@
/* JSRF Decompilation: Std.hpp
C(++) standard library definitions. Implemented in the repository instead of
linking to an outside stdlib to ensure consistency (this may not actually be
possible to accomplish, but we'll go for it for now).
*/
#ifndef STD_HPP
#define STD_HPP
#define NULL 0
#endif

40
objdiff/src/Win32.hpp Normal file
View file

@ -0,0 +1,40 @@
/* JSRF Decompilation: Win32.hpp
Definitions normally provided by Windows headers.
*/
#ifndef WIN32_HPP
#define WIN32_HPP
// The famous Win32 typedefs
typedef unsigned char UCHAR;
typedef char CHAR;
typedef unsigned short USHORT;
typedef short SHORT;
typedef unsigned int UINT;
typedef int INT;
typedef unsigned long ULONG;
typedef long LONG;
typedef unsigned __int64 ULONGLONG;
typedef __int64 LONGLONG;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef int BOOL;
typedef float FLOAT;
// 64-bit integer compatibility type
union LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
};
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
};
#endif

0
objdiff/target/.gitkeep Normal file
View file