362 lines
15 KiB
C++
362 lines
15 KiB
C++
#include "dynos.cpp.h"
|
|
extern "C" {
|
|
#include "sm64.h"
|
|
#include "geo_commands.h"
|
|
#include "src/game/camera.h"
|
|
#include "src/game/envfx_snow.h"
|
|
}
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wnarrowing"
|
|
|
|
/////////////
|
|
// Parsing //
|
|
/////////////
|
|
|
|
#define GEO_LAYOUT_SIZE_PER_TOKEN 4
|
|
|
|
#define geo_constant(x) if (_Arg == #x) { return (s64) (x); }
|
|
static s64 ParseGeoSymbolArg(GfxData* aGfxData, DataNode<GeoLayout>* aNode, u64& aTokenIndex) {
|
|
const String& _Arg = aNode->mTokens[aTokenIndex++];
|
|
|
|
// Geo functions
|
|
void *_GeoFunctionPtr = DynOS_Geo_GetFunctionPointerFromName(_Arg);
|
|
if (_GeoFunctionPtr != NULL) {
|
|
return (s64) _GeoFunctionPtr;
|
|
}
|
|
|
|
// Layer constants
|
|
geo_constant(LAYER_FORCE);
|
|
geo_constant(LAYER_OPAQUE);
|
|
geo_constant(LAYER_OPAQUE_DECAL);
|
|
geo_constant(LAYER_OPAQUE_INTER);
|
|
geo_constant(LAYER_ALPHA);
|
|
geo_constant(LAYER_TRANSPARENT);
|
|
geo_constant(LAYER_TRANSPARENT_DECAL);
|
|
geo_constant(LAYER_TRANSPARENT_INTER);
|
|
|
|
// Background constants
|
|
geo_constant(BACKGROUND_OCEAN_SKY);
|
|
geo_constant(BACKGROUND_FLAMING_SKY);
|
|
geo_constant(BACKGROUND_UNDERWATER_CITY);
|
|
geo_constant(BACKGROUND_BELOW_CLOUDS);
|
|
geo_constant(BACKGROUND_SNOW_MOUNTAINS);
|
|
geo_constant(BACKGROUND_DESERT);
|
|
geo_constant(BACKGROUND_HAUNTED);
|
|
geo_constant(BACKGROUND_GREEN_SKY);
|
|
geo_constant(BACKGROUND_ABOVE_CLOUDS);
|
|
geo_constant(BACKGROUND_PURPLE_SKY);
|
|
|
|
// Shadow constants
|
|
geo_constant(SHADOW_CIRCLE_9_VERTS);
|
|
geo_constant(SHADOW_CIRCLE_4_VERTS);
|
|
geo_constant(SHADOW_CIRCLE_4_VERTS_FLAT_UNUSED);
|
|
geo_constant(SHADOW_SQUARE_PERMANENT);
|
|
geo_constant(SHADOW_SQUARE_SCALABLE);
|
|
geo_constant(SHADOW_SQUARE_TOGGLABLE);
|
|
geo_constant(SHADOW_RECTANGLE_HARDCODED_OFFSET);
|
|
geo_constant(SHADOW_CIRCLE_PLAYER);
|
|
|
|
// Envfx constants
|
|
geo_constant(ENVFX_MODE_NONE);
|
|
geo_constant(ENVFX_SNOW_NORMAL);
|
|
geo_constant(ENVFX_SNOW_WATER);
|
|
geo_constant(ENVFX_SNOW_BLIZZARD);
|
|
geo_constant(ENVFX_BUBBLE_START);
|
|
geo_constant(ENVFX_FLOWERS);
|
|
geo_constant(ENVFX_LAVA_BUBBLES);
|
|
geo_constant(ENVFX_WHIRLPOOL_BUBBLES);
|
|
geo_constant(ENVFX_JETSTREAM_BUBBLES);
|
|
|
|
|
|
// Camera constants
|
|
geo_constant(CAMERA_MODE_NONE);
|
|
geo_constant(CAMERA_MODE_RADIAL);
|
|
geo_constant(CAMERA_MODE_OUTWARD_RADIAL);
|
|
geo_constant(CAMERA_MODE_BEHIND_MARIO);
|
|
geo_constant(CAMERA_MODE_CLOSE);
|
|
geo_constant(CAMERA_MODE_C_UP);
|
|
geo_constant(CAMERA_MODE_WATER_SURFACE);
|
|
geo_constant(CAMERA_MODE_SLIDE_HOOT);
|
|
geo_constant(CAMERA_MODE_INSIDE_CANNON);
|
|
geo_constant(CAMERA_MODE_BOSS_FIGHT);
|
|
geo_constant(CAMERA_MODE_PARALLEL_TRACKING);
|
|
geo_constant(CAMERA_MODE_FIXED);
|
|
geo_constant(CAMERA_MODE_8_DIRECTIONS);
|
|
geo_constant(CAMERA_MODE_FREE_ROAM);
|
|
geo_constant(CAMERA_MODE_SPIRAL_STAIRS);
|
|
|
|
// Other constants
|
|
geo_constant(NULL);
|
|
geo_constant(SCREEN_WIDTH);
|
|
geo_constant(SCREEN_HEIGHT);
|
|
geo_constant(SCREEN_WIDTH/2);
|
|
geo_constant(SCREEN_HEIGHT/2);
|
|
|
|
// Display lists
|
|
for (auto& _Node : aGfxData->mDisplayLists) {
|
|
if (_Arg == _Node->mName) {
|
|
return (s64) DynOS_Gfx_Parse(aGfxData, _Node);
|
|
}
|
|
}
|
|
|
|
// Geo layouts
|
|
for (auto& _Node : aGfxData->mGeoLayouts) {
|
|
if (_Arg == _Node->mName) {
|
|
return (s64) DynOS_Geo_Parse(aGfxData, _Node, false)->mData;
|
|
}
|
|
}
|
|
|
|
// Integers
|
|
s32 x;
|
|
if ((_Arg[1] == 'x' && sscanf(_Arg.begin(), "%x", &x) == 1) || (sscanf(_Arg.begin(), "%d", &x) == 1)) {
|
|
return (s64) x;
|
|
}
|
|
|
|
// Unknown
|
|
PrintError(" ERROR: Unknown geo arg: %s", _Arg.begin());
|
|
return 0;
|
|
}
|
|
|
|
#define geo_symbol_0(symb) \
|
|
if (_Symbol == #symb) { \
|
|
GeoLayout _Gl[] = { symb() }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
#define geo_symbol_1(symb, n) \
|
|
if (_Symbol == #symb) { \
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
|
|
GeoLayout _Gl[] = { symb(_Arg0) }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
#define geo_symbol_2(symb, n) \
|
|
if (_Symbol == #symb) { \
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg1 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
|
|
GeoLayout _Gl[] = { symb(_Arg0, _Arg1) }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
#define geo_symbol_3(symb, n) \
|
|
if (_Symbol == #symb) { \
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg1 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg2 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
|
|
GeoLayout _Gl[] = { symb(_Arg0, _Arg1, _Arg2) }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
#define geo_symbol_4(symb, n) \
|
|
if (_Symbol == #symb) { \
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg1 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg2 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg3 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
|
|
GeoLayout _Gl[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3) }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
#define geo_symbol_5(symb, n) \
|
|
if (_Symbol == #symb) { \
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg1 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg2 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg3 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg4 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
|
|
GeoLayout _Gl[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4) }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
#define geo_symbol_6(symb, n) \
|
|
if (_Symbol == #symb) { \
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg1 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg2 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg3 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg4 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg5 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
|
|
GeoLayout _Gl[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5) }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
#define geo_symbol_7(symb, n) \
|
|
if (_Symbol == #symb) { \
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg1 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg2 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg3 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg4 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg5 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg6 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
|
|
GeoLayout _Gl[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5, _Arg6) }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
#define geo_symbol_8(symb, n) \
|
|
if (_Symbol == #symb) { \
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg1 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg2 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg3 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg4 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg5 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg6 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
s64 _Arg7 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex); \
|
|
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
|
|
GeoLayout _Gl[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5, _Arg6, _Arg7) }; \
|
|
memcpy(aHead, _Gl, sizeof(_Gl)); \
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0])); \
|
|
return; \
|
|
}
|
|
|
|
static void ParseGeoSymbol(GfxData* aGfxData, DataNode<GeoLayout>* aNode, GeoLayout*& aHead, u64& aTokenIndex, Array<u64>& aSwitchNodes) {
|
|
const String& _Symbol = aNode->mTokens[aTokenIndex++];
|
|
|
|
// Restore context after each command if inside a switch
|
|
if (!aSwitchNodes.Empty() && !aGfxData->mGeoNodeStack.Empty()) {
|
|
aGfxData->mGfxContext = aGfxData->mGeoNodeStack[aGfxData->mGeoNodeStack.Count() - 1];
|
|
}
|
|
|
|
geo_symbol_1(GEO_BRANCH_AND_LINK, 1);
|
|
geo_symbol_0(GEO_END);
|
|
geo_symbol_2(GEO_BRANCH, 1);
|
|
geo_symbol_0(GEO_RETURN);
|
|
geo_symbol_5(GEO_NODE_SCREEN_AREA, 0);
|
|
geo_symbol_1(GEO_NODE_ORTHO, 0);
|
|
geo_symbol_3(GEO_CAMERA_FRUSTUM, 0);
|
|
geo_symbol_4(GEO_CAMERA_FRUSTUM_WITH_FUNC, 2);
|
|
geo_symbol_0(GEO_NODE_START);
|
|
geo_symbol_1(GEO_ZBUFFER, 0);
|
|
geo_symbol_2(GEO_RENDER_RANGE, 0);
|
|
geo_symbol_8(GEO_CAMERA, 4);
|
|
geo_symbol_7(GEO_TRANSLATE_ROTATE, 0);
|
|
geo_symbol_8(GEO_TRANSLATE_ROTATE_WITH_DL, 4);
|
|
geo_symbol_4(GEO_TRANSLATE, 0);
|
|
geo_symbol_5(GEO_TRANSLATE_WITH_DL, 2);
|
|
geo_symbol_4(GEO_ROTATE, 0);
|
|
geo_symbol_5(GEO_ROTATE_WITH_DL, 2);
|
|
geo_symbol_2(GEO_ROTATE_Y, 0);
|
|
geo_symbol_3(GEO_ROTATE_Y_WITH_DL, 1);
|
|
geo_symbol_4(GEO_TRANSLATE_NODE, 0);
|
|
geo_symbol_5(GEO_TRANSLATE_NODE_WITH_DL, 2);
|
|
geo_symbol_4(GEO_ROTATION_NODE, 0);
|
|
geo_symbol_5(GEO_ROTATION_NODE_WITH_DL, 2);
|
|
geo_symbol_5(GEO_ANIMATED_PART, 2);
|
|
geo_symbol_4(GEO_BILLBOARD_WITH_PARAMS, 0);
|
|
geo_symbol_5(GEO_BILLBOARD_WITH_PARAMS_AND_DL, 2);
|
|
geo_symbol_0(GEO_BILLBOARD);
|
|
geo_symbol_2(GEO_DISPLAY_LIST, 1);
|
|
geo_symbol_3(GEO_SHADOW, 0);
|
|
geo_symbol_0(GEO_RENDER_OBJ);
|
|
geo_symbol_2(GEO_ASM, 1);
|
|
geo_symbol_2(GEO_BACKGROUND, 1);
|
|
geo_symbol_1(GEO_BACKGROUND_COLOR, 0);
|
|
geo_symbol_0(GEO_NOP_1A);
|
|
geo_symbol_5(GEO_HELD_OBJECT, 2);
|
|
geo_symbol_2(GEO_SCALE, 0);
|
|
geo_symbol_3(GEO_SCALE_WITH_DL, 2);
|
|
geo_symbol_0(GEO_NOP_1E);
|
|
geo_symbol_0(GEO_NOP_1F);
|
|
geo_symbol_1(GEO_CULLING_RADIUS, 0);
|
|
|
|
// Switch node
|
|
if (_Symbol == "GEO_SWITCH_CASE") {
|
|
|
|
// Start a switch
|
|
aSwitchNodes.Add(0);
|
|
|
|
s64 _Arg0 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex);
|
|
s64 _Arg1 = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex);
|
|
aGfxData->mPointerList.Add(aHead + 1);
|
|
GeoLayout _Gl[] = { GEO_SWITCH_CASE(_Arg0, _Arg1) };
|
|
memcpy(aHead, _Gl, sizeof(_Gl));
|
|
aHead += (sizeof(_Gl) / sizeof(_Gl[0]));
|
|
return;
|
|
}
|
|
|
|
// Open node
|
|
if (_Symbol == "GEO_OPEN_NODE") {
|
|
|
|
// We're inside a switch
|
|
if (!aSwitchNodes.Empty()) {
|
|
aSwitchNodes[aSwitchNodes.Count() - 1]++;
|
|
}
|
|
|
|
// Push context
|
|
aGfxData->mGeoNodeStack.Add(aGfxData->mGfxContext);
|
|
|
|
*(aHead++) = GEO_OPEN_NODE();
|
|
return;
|
|
}
|
|
|
|
// Close node
|
|
if (_Symbol == "GEO_CLOSE_NODE") {
|
|
|
|
// Are we still inside a switch?
|
|
if (!aSwitchNodes.Empty()) {
|
|
aSwitchNodes[aSwitchNodes.Count() - 1]--;
|
|
|
|
// We're not anymore
|
|
if (aSwitchNodes[aSwitchNodes.Count() - 1] == 0) {
|
|
aSwitchNodes.Pop();
|
|
}
|
|
}
|
|
|
|
// Pop context
|
|
if (!aGfxData->mGeoNodeStack.Empty()) {
|
|
aGfxData->mGfxContext = aGfxData->mGeoNodeStack[aGfxData->mGeoNodeStack.Count() - 1];
|
|
aGfxData->mGeoNodeStack.Pop();
|
|
}
|
|
|
|
*(aHead++) = GEO_CLOSE_NODE();
|
|
return;
|
|
}
|
|
|
|
// Unknown
|
|
PrintError(" ERROR: Unknown geo symbol: %s", _Symbol.begin());
|
|
}
|
|
|
|
DataNode<GeoLayout>* DynOS_Geo_Parse(GfxData* aGfxData, DataNode<GeoLayout>* aNode, bool aDisplayPercent) {
|
|
if (aNode->mData) return aNode;
|
|
|
|
// Geo layout data
|
|
aNode->mData = New<GeoLayout>(aNode->mTokens.Count() * GEO_LAYOUT_SIZE_PER_TOKEN);
|
|
GeoLayout* _Head = aNode->mData;
|
|
Array<u64> _SwitchNodes;
|
|
for (u64 _TokenIndex = 0; _TokenIndex < aNode->mTokens.Count();) { // Don't increment _TokenIndex here!
|
|
ParseGeoSymbol(aGfxData, aNode, _Head, _TokenIndex, _SwitchNodes);
|
|
if (aDisplayPercent && aGfxData->mErrorCount == 0) { PrintNoNewLine("%3d%%\b\b\b\b", (s32) (_TokenIndex * 100) / aNode->mTokens.Count()); }
|
|
}
|
|
if (aDisplayPercent && aGfxData->mErrorCount == 0) { Print("100%%"); }
|
|
aNode->mSize = (u32)(_Head - aNode->mData);
|
|
aNode->mLoadIndex = aGfxData->mLoadIndex++;
|
|
return aNode;
|
|
}
|
|
|
|
#pragma GCC diagnostic pop
|