Added Light_t, Ambient_t, and began adding vanilla lvl geos to DynOS level gen

This commit is contained in:
MysterD 2022-04-04 21:25:40 -07:00
parent abce3b3afd
commit 2c11b8f686
11 changed files with 393 additions and 8 deletions

View file

@ -19,6 +19,8 @@ extern "C" {
enum {
DATA_TYPE_NONE = 0,
DATA_TYPE_LIGHT,
DATA_TYPE_LIGHT_T,
DATA_TYPE_AMBIENT_T,
DATA_TYPE_TEXTURE,
DATA_TYPE_VERTEX,
DATA_TYPE_DISPLAY_LIST,
@ -426,6 +428,8 @@ struct GfxData : NoCopy {
// Model data
DataNodes<Lights1> mLights;
DataNodes<Light_t> mLightTs;
DataNodes<Ambient_t> mAmbientTs;
DataNodes<TexData> mTextures;
DataNodes<Vtx> mVertices;
DataNodes<Gfx> mDisplayLists;
@ -691,6 +695,12 @@ void *DynOS_Geo_GetFunctionPointerFromIndex(s32 aIndex);
s32 DynOS_Geo_GetFunctionIndex(const void *aPtr);
void *DynOS_Geo_GetGraphNode(const void *aGeoLayout, bool aKeepInMemory);
s32 DynOS_Lvl_GetGeoCount();
const char *DynOS_Lvl_GetGeoName(s32 aIndex);
const void *DynOS_Lvl_GetGeoLayout(s32 aIndex);
const void *DynOS_Lvl_GetGeoLayoutFromName(const char *aGeoName);
s32 DynOS_Lvl_GetGeoIndex(const void *aGeoLayout);
//
// Levels
//
@ -763,6 +773,14 @@ DataNode<Lights1>* DynOS_Lights_Parse(GfxData* aGfxData, DataNode<Lights1>* aNod
void DynOS_Lights_Write(FILE* aFile, GfxData* aGfxData, DataNode<Lights1> *aNode);
void DynOS_Lights_Load(FILE *aFile, GfxData *aGfxData);
DataNode<Light_t>* DynOS_LightT_Parse(GfxData* aGfxData, DataNode<Light_t>* aNode);
void DynOS_LightT_Write(FILE* aFile, GfxData* aGfxData, DataNode<Light_t> *aNode);
void DynOS_LightT_Load(FILE *aFile, GfxData *aGfxData);
DataNode<Ambient_t>* DynOS_AmbientT_Parse(GfxData* aGfxData, DataNode<Ambient_t>* aNode);
void DynOS_AmbientT_Write(FILE* aFile, GfxData* aGfxData, DataNode<Ambient_t> *aNode);
void DynOS_AmbientT_Load(FILE *aFile, GfxData *aGfxData);
DataNode<MacroObject>* DynOS_MacroObject_Parse(GfxData* aGfxData, DataNode<MacroObject>* aNode, bool aDisplayPercent);
void DynOS_MacroObject_Write(FILE* aFile, GfxData* aGfxData, DataNode<MacroObject> *aNode);
DataNode<MacroObject>* DynOS_MacroObject_Load(FILE *aFile, GfxData *aGfxData);

View file

@ -26,6 +26,16 @@ static bool DynOS_Actor_WriteBinary(const SysPath &aOutputFilename, GfxData *aGf
DynOS_Lights_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mLightTs) {
if (_Node->mLoadIndex == i) {
DynOS_LightT_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mAmbientTs) {
if (_Node->mLoadIndex == i) {
DynOS_AmbientT_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mTextures) {
if (_Node->mLoadIndex == i) {
DynOS_Tex_Write(_File, aGfxData, _Node);
@ -88,6 +98,8 @@ GfxData *DynOS_Actor_LoadFromBinary(const SysPath &aPackFolder, const char *aAct
for (bool _Done = false; !_Done;) {
switch (ReadBytes<u8>(_File)) {
case DATA_TYPE_LIGHT: DynOS_Lights_Load (_File, _GfxData); break;
case DATA_TYPE_LIGHT_T: DynOS_LightT_Load (_File, _GfxData); break;
case DATA_TYPE_AMBIENT_T: DynOS_AmbientT_Load (_File, _GfxData); break;
case DATA_TYPE_TEXTURE: DynOS_Tex_Load (_File, _GfxData); break;
case DATA_TYPE_VERTEX: DynOS_Vtx_Load (_File, _GfxData); break;
case DATA_TYPE_DISPLAY_LIST: DynOS_Gfx_Load (_File, _GfxData); break;
@ -186,6 +198,8 @@ static void DynOS_Actor_Generate(const SysPath &aPackFolder, Array<Pair<u64, Str
}
// Clear data pointers
ClearGfxDataNodes(_GfxData->mLights);
ClearGfxDataNodes(_GfxData->mLightTs);
ClearGfxDataNodes(_GfxData->mAmbientTs);
ClearGfxDataNodes(_GfxData->mTextures);
ClearGfxDataNodes(_GfxData->mVertices);
ClearGfxDataNodes(_GfxData->mDisplayLists);

View file

@ -0,0 +1,63 @@
#include "dynos.cpp.h"
/////////////
// Parsing //
/////////////
DataNode<Ambient_t>* DynOS_AmbientT_Parse(GfxData* aGfxData, DataNode<Ambient_t>* aNode) {
if (aNode->mData) return aNode;
// Check tokens count
if (aNode->mTokens.Count() < 8) {
PrintError(" ERROR: %s: not enough data", aNode->mName.begin());
return aNode;
}
// Parse data tokens
u8 cr = (u8) aNode->mTokens[0].ParseInt();
u8 cg = (u8) aNode->mTokens[1].ParseInt();
u8 cb = (u8) aNode->mTokens[2].ParseInt();
u8 c2r = (u8) aNode->mTokens[4].ParseInt();
u8 c2g = (u8) aNode->mTokens[5].ParseInt();
u8 c2b = (u8) aNode->mTokens[6].ParseInt();
aNode->mData = New<Ambient_t>();
*aNode->mData = {
{ cr, cg, cb}, 0,
{ c2r, c2g, c2b}, 0
};
aNode->mLoadIndex = aGfxData->mLoadIndex++;
return aNode;
}
/////////////
// Writing //
/////////////
void DynOS_AmbientT_Write(FILE* aFile, GfxData* aGfxData, DataNode<Ambient_t> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_AMBIENT_T);
aNode->mName.Write(aFile);
// Data
WriteBytes<Ambient_t>(aFile, *aNode->mData);
}
/////////////
// Reading //
/////////////
void DynOS_AmbientT_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<Ambient_t> *_Node = New<DataNode<Ambient_t>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mData = New<Ambient_t>();
*_Node->mData = ReadBytes<Ambient_t>(aFile);
// Append
aGfxData->mAmbientTs.Add(_Node);
}

View file

@ -464,11 +464,13 @@ DataNode<Collision>* DynOS_Col_LoadFromBinary(const SysPath &aPackFolder, const
FILE *_File = fopen(_Filename.c_str(), "rb");
if (_File) {
// backwards compatibility
long prevPos = ftell(_File);
//long prevPos = ftell(_File);
u8 type = ReadBytes<u8>(_File);
if (type != DATA_TYPE_COLLISION) { fseek(_File, prevPos, SEEK_SET); }
collisionNode = DynOS_Col_Load(_File, NULL);
//if (type != DATA_TYPE_COLLISION) { fseek(_File, prevPos, SEEK_SET); }
if (type == DATA_TYPE_COLLISION) {
collisionNode = DynOS_Col_Load(_File, NULL);
}
// DO NOT COMMIT - figure out wtf is going on
fclose(_File);
}

View file

@ -310,6 +310,14 @@ static s64 ParseGfxSymbolArg(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pToke
gfx_constant(G_ZS_PIXEL);
gfx_constant(G_ZS_PRIM);
// MW constants
gfx_constant(G_MW_MATRIX);
gfx_constant(G_MW_NUMLIGHT);
gfx_constant(G_MW_CLIP);
gfx_constant(G_MW_SEGMENT);
gfx_constant(G_MW_FOG);
gfx_constant(G_MW_LIGHTCOL);
// Common values
gfx_constant((4-1)<<G_TEXTURE_IMAGE_FRAC);
gfx_constant((8-1)<<G_TEXTURE_IMAGE_FRAC);
@ -346,10 +354,10 @@ static s64 ParseGfxSymbolArg(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pToke
gfx_constant(CALC_DXT(64,G_IM_SIZ_32b_BYTES));
gfx_constant(CALC_DXT(128,G_IM_SIZ_32b_BYTES));
gfx_constant(CALC_DXT(256,G_IM_SIZ_32b_BYTES));
gfx_constant(G_CULL_BACK|G_LIGHTING);
// Lights
for (auto& _Node : aGfxData->mLights) {
// Light pointer
if (_Arg == _Node->mName) {
return (s64) DynOS_Lights_Parse(aGfxData, _Node)->mData;
@ -368,6 +376,50 @@ static s64 ParseGfxSymbolArg(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pToke
}
}
for (auto& _Node : aGfxData->mLightTs) {
// Light pointer
if (_Arg == _Node->mName) {
return (s64) DynOS_LightT_Parse(aGfxData, _Node)->mData;
}
// Diffuse pointer
String _Diffuse("&%s.col", _Node->mName.begin());
if (_Arg == _Diffuse) {
return (s64) &(DynOS_LightT_Parse(aGfxData, _Node)->mData->col[0]);
}
// Diffuse copy pointer
String _DiffuseC("&%s.colc", _Node->mName.begin());
if (_Arg == _DiffuseC) {
return (s64) &(DynOS_LightT_Parse(aGfxData, _Node)->mData->colc[0]);
}
// Dir pointer
String _Dir("&%s.dir", _Node->mName.begin());
if (_Arg == _Dir) {
return (s64) &(DynOS_LightT_Parse(aGfxData, _Node)->mData->dir[0]);
}
}
for (auto& _Node : aGfxData->mAmbientTs) {
// Light pointer
if (_Arg == _Node->mName) {
return (s64) DynOS_AmbientT_Parse(aGfxData, _Node)->mData;
}
// Diffuse pointer
String _Diffuse("&%s.col", _Node->mName.begin());
if (_Arg == _Diffuse) {
return (s64) &(DynOS_AmbientT_Parse(aGfxData, _Node)->mData->col[0]);
}
// Diffuse copy pointer
String _DiffuseC("&%s.colc", _Node->mName.begin());
if (_Arg == _DiffuseC) {
return (s64) &(DynOS_AmbientT_Parse(aGfxData, _Node)->mData->colc[0]);
}
}
// Textures
for (auto& _Node : aGfxData->mTextures) {
if (_Arg == _Node->mName) {
@ -662,6 +714,7 @@ static void ParseGfxSymbol(GfxData* aGfxData, DataNode<Gfx>* aNode, Gfx*& aHead,
gfx_symbol_2(gsSPCopyLightEXT, false);
gfx_symbol_2(gsSPFogFactor, false);
gfx_symbol_1(gsDPSetTextureLOD, false);
gfx_symbol_3(gsMoveWd, false);
// Special symbols
if (_Symbol == "gsSPTexture") {

View file

@ -0,0 +1,67 @@
#include "dynos.cpp.h"
/////////////
// Parsing //
/////////////
DataNode<Light_t>* DynOS_LightT_Parse(GfxData* aGfxData, DataNode<Light_t>* aNode) {
if (aNode->mData) return aNode;
// Check tokens count
if (aNode->mTokens.Count() < 12) {
PrintError(" ERROR: %s: not enough data", aNode->mName.begin());
return aNode;
}
// Parse data tokens
u8 cr = (u8) aNode->mTokens[0].ParseInt();
u8 cg = (u8) aNode->mTokens[1].ParseInt();
u8 cb = (u8) aNode->mTokens[2].ParseInt();
u8 c2r = (u8) aNode->mTokens[4].ParseInt();
u8 c2g = (u8) aNode->mTokens[5].ParseInt();
u8 c2b = (u8) aNode->mTokens[6].ParseInt();
s8 dx = (s8) aNode->mTokens[8].ParseInt();
s8 dy = (s8) aNode->mTokens[9].ParseInt();
s8 dz = (s8) aNode->mTokens[10].ParseInt();
aNode->mData = New<Light_t>();
*aNode->mData = {
{ cr, cg, cb}, 0,
{ c2r, c2g, c2b}, 0,
{ dx, dy, dz}, 0
};
aNode->mLoadIndex = aGfxData->mLoadIndex++;
return aNode;
}
/////////////
// Writing //
/////////////
void DynOS_LightT_Write(FILE* aFile, GfxData* aGfxData, DataNode<Light_t> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_LIGHT_T);
aNode->mName.Write(aFile);
// Data
WriteBytes<Light_t>(aFile, *aNode->mData);
}
/////////////
// Reading //
/////////////
void DynOS_LightT_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<Light_t> *_Node = New<DataNode<Light_t>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mData = New<Light_t>();
*_Node->mData = ReadBytes<Light_t>(aFile);
// Append
aGfxData->mLightTs.Add(_Node);
}

View file

@ -1391,7 +1391,7 @@ s64 DynOS_Lvl_ParseLevelScriptConstants(const String& _Arg, bool* found) {
lvl_constant(WARP_TRANSITION_FADE_FROM_BOWSER);
lvl_constant(WARP_TRANSITION_FADE_INTO_BOWSER);
// vanilla geos
// vanilla actors
s32 actorCount = DynOS_Geo_GetActorCount();
for (s32 i = 0; i < actorCount; i++) {
if (DynOS_Geo_IsCustomActor(i)) { break; }
@ -1400,6 +1400,14 @@ s64 DynOS_Lvl_ParseLevelScriptConstants(const String& _Arg, bool* found) {
}
}
// vanilla level geos
s32 lvlGeoCount = DynOS_Lvl_GetGeoCount();
for (s32 i = 0; i < lvlGeoCount; i++) {
if (!strcmp(_Arg.begin(), DynOS_Lvl_GetGeoName(i))) {
return (LevelScript)DynOS_Lvl_GetGeoLayout(i);
}
}
*found = false;
return 0;
}
@ -1847,6 +1855,16 @@ static bool DynOS_Lvl_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxD
DynOS_Lights_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mLightTs) {
if (_Node->mLoadIndex == i) {
DynOS_LightT_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mAmbientTs) {
if (_Node->mLoadIndex == i) {
DynOS_AmbientT_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mTextures) {
if (_Node->mLoadIndex == i) {
DynOS_Tex_Write(_File, aGfxData, _Node);
@ -1951,6 +1969,8 @@ GfxData *DynOS_Lvl_LoadFromBinary(const SysPath &aPackFolder, const char *aLevel
for (bool _Done = false; !_Done;) {
switch (ReadBytes<u8>(_File)) {
case DATA_TYPE_LIGHT: DynOS_Lights_Load (_File, _GfxData); break;
case DATA_TYPE_LIGHT_T: DynOS_LightT_Load (_File, _GfxData); break;
case DATA_TYPE_AMBIENT_T: DynOS_AmbientT_Load (_File, _GfxData); break;
case DATA_TYPE_TEXTURE: DynOS_Tex_Load (_File, _GfxData); break;
case DATA_TYPE_VERTEX: DynOS_Vtx_Load (_File, _GfxData); break;
case DATA_TYPE_DISPLAY_LIST: DynOS_Gfx_Load (_File, _GfxData); break;

View file

@ -43,6 +43,27 @@ static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) {
}
}
for (auto& _Node : aGfxData->mLightTs) {
if (&_Node->mData->col[0] == aPtr) {
return { _Node->mName, 1 };
}
if (&_Node->mData->colc[0] == aPtr) {
return { _Node->mName, 2 };
}
if (&_Node->mData->dir[0] == aPtr) {
return { _Node->mName, 3 };
}
}
for (auto& _Node : aGfxData->mAmbientTs) {
if (&_Node->mData->col[0] == aPtr) {
return { _Node->mName, 1 };
}
if (&_Node->mData->colc[0] == aPtr) {
return { _Node->mName, 2 };
}
}
// Textures
for (auto& _Node : aGfxData->mTextures) {
if (_Node == aPtr) {
@ -119,7 +140,7 @@ static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) {
return { get_behavior_name_from_id(id), 0 };
}
// Vanilla Geos
// Vanilla Actors
s32 actorCount = DynOS_Geo_GetActorCount();
for (s32 i = 0; i < actorCount; i++) {
if (DynOS_Geo_IsCustomActor(i)) { break; }
@ -128,6 +149,14 @@ static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) {
}
}
// Vanilla Lvl Geos
s32 lvlGeoCount = DynOS_Lvl_GetGeoCount();
for (s32 i = 0; i < lvlGeoCount; i++) {
if (aPtr == DynOS_Lvl_GetGeoLayout(i)) {
return { DynOS_Lvl_GetGeoName(i), 0 };
}
}
// Vanilla Pointers
s32 pointerCount = (s32) (sizeof(sDynosPointers) / (2 * sizeof(sDynosPointers[0])));
for (s32 i = 0; i < pointerCount; i++) {
@ -217,6 +246,33 @@ static void *GetPointerFromData(GfxData *aGfxData, const String &aPtrName, u32 a
}
}
for (auto& _Node : aGfxData->mLightTs) {
if (_Node->mName == aPtrName) {
if (aPtrData == 1) {
return (void *) &_Node->mData->col[0];
}
if (aPtrData == 2) {
return (void *) &_Node->mData->colc[0];
}
if (aPtrData == 3) {
return (void *) &_Node->mData->dir[0];
}
sys_fatal("Unknown Light type: %u", aPtrData);
}
}
for (auto& _Node : aGfxData->mAmbientTs) {
if (_Node->mName == aPtrName) {
if (aPtrData == 1) {
return (void *) &_Node->mData->col[0];
}
if (aPtrData == 2) {
return (void *) &_Node->mData->colc[0];
}
sys_fatal("Unknown Light type: %u", aPtrData);
}
}
// Textures
for (auto& _Node : aGfxData->mTextures) {
if (_Node->mName == aPtrName) {
@ -300,7 +356,7 @@ static void *GetPointerFromData(GfxData *aGfxData, const String &aPtrName, u32 a
return (void*)get_behavior_from_id(id);
}
// Vanilla Geos
// Vanilla Actors
s32 actorCount = DynOS_Geo_GetActorCount();
for (s32 i = 0; i < actorCount; i++) {
if (DynOS_Geo_IsCustomActor(i)) { break; }
@ -309,6 +365,14 @@ static void *GetPointerFromData(GfxData *aGfxData, const String &aPtrName, u32 a
}
}
// Vanilla Lvl Geos
s32 lvlGeoCount = DynOS_Lvl_GetGeoCount();
for (s32 i = 0; i < lvlGeoCount; i++) {
if (!strcmp(aPtrName.begin(), DynOS_Lvl_GetGeoName(i))) {
return (void*)DynOS_Lvl_GetGeoLayout(i);
}
}
// Vanilla Pointers
s32 pointerCount = (s32) (sizeof(sDynosPointers) / (2 * sizeof(sDynosPointers[0])));
for (s32 i = 0; i < pointerCount; i++) {

View file

@ -178,6 +178,10 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) {
_DataType = DATA_TYPE_UNUSED;
} else if (_Buffer == "Lights1") {
_DataType = DATA_TYPE_LIGHT;
} else if (_Buffer == "Light_t") {
_DataType = DATA_TYPE_LIGHT_T;
} else if (_Buffer == "Ambient_t") {
_DataType = DATA_TYPE_AMBIENT_T;
} else if (_Buffer == "u8") {
_DataType = strstr(aFilename.c_str(), "room")
? DATA_TYPE_ROOMS
@ -221,6 +225,8 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) {
else if (_Buffer.Length() != 0) {
switch (_DataType) {
case DATA_TYPE_LIGHT: AppendNewNode(aGfxData, aGfxData->mLights, _Buffer, pDataName, pDataTokens); break;
case DATA_TYPE_LIGHT_T: AppendNewNode(aGfxData, aGfxData->mLightTs, _Buffer, pDataName, pDataTokens); break;
case DATA_TYPE_AMBIENT_T: AppendNewNode(aGfxData, aGfxData->mAmbientTs, _Buffer, pDataName, pDataTokens); break;
case DATA_TYPE_TEXTURE: AppendNewNode(aGfxData, aGfxData->mTextures, _Buffer, pDataName, pDataTokens); break;
case DATA_TYPE_VERTEX: AppendNewNode(aGfxData, aGfxData->mVertices, _Buffer, pDataName, pDataTokens); break;
case DATA_TYPE_DISPLAY_LIST: AppendNewNode(aGfxData, aGfxData->mDisplayLists, _Buffer, pDataName, pDataTokens); break;

View file

@ -10,6 +10,14 @@ void DynOS_Gfx_Free(GfxData* aGfxData) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mLightTs) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mAmbientTs) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mTextures) {
Delete(_Node->mData);
Delete(_Node);

View file

@ -36,6 +36,7 @@ extern "C" {
#include "actors/group17.h"
#include "actors/custom0.h"
#include "actors/zcustom0.h"
#include "levels/bob/header.h"
#include "levels/wf/header.h"
}
@ -606,6 +607,75 @@ Collision* DynOS_Col_Get(const char* collisionName) {
// Levels //
////////////
#define define_lvl_geo(geo) (const void *) #geo, (const void *) geo
static const void *sDynosLevelGeos[] = {
define_lvl_geo(wf_geo_0007E0),
define_lvl_geo(wf_geo_000820),
define_lvl_geo(wf_geo_000860),
define_lvl_geo(wf_geo_000878),
define_lvl_geo(wf_geo_000890),
define_lvl_geo(wf_geo_0008A8),
define_lvl_geo(wf_geo_0008E8),
define_lvl_geo(wf_geo_000900),
define_lvl_geo(wf_geo_000940),
define_lvl_geo(wf_geo_000958),
define_lvl_geo(wf_geo_0009A0),
define_lvl_geo(wf_geo_0009B8),
define_lvl_geo(wf_geo_0009D0),
define_lvl_geo(wf_geo_0009E8),
define_lvl_geo(wf_geo_000A00),
define_lvl_geo(wf_geo_000A40),
define_lvl_geo(wf_geo_000A58),
define_lvl_geo(wf_geo_000A98),
define_lvl_geo(wf_geo_000AB0),
define_lvl_geo(wf_geo_000AC8),
define_lvl_geo(wf_geo_000AE0),
define_lvl_geo(wf_geo_000AF8),
define_lvl_geo(wf_geo_000B10),
define_lvl_geo(wf_geo_000B38),
define_lvl_geo(wf_geo_000B60),
define_lvl_geo(wf_geo_000B78),
define_lvl_geo(wf_geo_000B90),
define_lvl_geo(wf_geo_000BA8),
define_lvl_geo(wf_geo_000BC8),
define_lvl_geo(wf_geo_000BE0),
define_lvl_geo(wf_geo_000BF8),
define_lvl_geo(bob_geo_000440),
define_lvl_geo(bob_geo_000458),
define_lvl_geo(bob_geo_000470),
define_lvl_geo(bob_geo_000488),
};
s32 DynOS_Lvl_GetGeoCount() {
return (s32) (sizeof(sDynosLevelGeos) / (2 * sizeof(sDynosLevelGeos[0])));
}
const char *DynOS_Lvl_GetGeoName(s32 aIndex) {
return (const char *) sDynosLevelGeos[2 * aIndex];
}
const void *DynOS_Lvl_GetGeoLayout(s32 aIndex) {
return (const void *) sDynosLevelGeos[2 * aIndex + 1];
}
const void *DynOS_Lvl_GetGeoLayoutFromName(const char *aGeoName) {
for (s32 i = 0; i < DynOS_Lvl_GetGeoCount(); ++i) {
if (!strcmp(DynOS_Lvl_GetGeoName(i), aGeoName)) {
return DynOS_Lvl_GetGeoLayout(i);
}
}
return NULL;
}
s32 DynOS_Lvl_GetGeoIndex(const void *aGeoLayout) {
for (s32 i = 0; i < DynOS_Lvl_GetGeoCount(); ++i) {
if (DynOS_Lvl_GetGeoLayout(i) == aGeoLayout) {
return i;
}
}
return -1;
}
static Array<Pair<const char*, GfxData*>> sDynosCustomLevelScripts;
void DynOS_Lvl_Add(s32 modIndex, const SysPath &aPackFolder, const char *aLevelName) {