Added support for custom skyboxes in DynOS level gen

This commit is contained in:
MysterD 2022-04-05 22:56:03 -07:00
parent d5770f1b55
commit 78a2e17d7c
16 changed files with 264 additions and 7 deletions

View file

@ -34,9 +34,9 @@ void dynos_add_collision(const char *modPath, const char* collisionName);
Collision* dynos_collision_get(const char* collisionName);
// -- levels -- //
void dynos_add_level(s32 modIndex, const char *modPath, const char* levelName);
LevelScript* dynos_level_get(const char* levelName);
void dynos_level_load_background(void *ptr);
#endif
#endif

View file

@ -37,6 +37,7 @@ enum {
DATA_TYPE_ROOMS,
DATA_TYPE_LIGHT_T,
DATA_TYPE_AMBIENT_T,
DATA_TYPE_TEXTURE_LIST,
DATA_TYPE_UNUSED,
};
@ -431,6 +432,7 @@ struct GfxData : NoCopy {
DataNodes<Light_t> mLightTs;
DataNodes<Ambient_t> mAmbientTs;
DataNodes<TexData> mTextures;
DataNodes<TexData*> mTextureLists;
DataNodes<Vtx> mVertices;
DataNodes<Gfx> mDisplayLists;
DataNodes<GeoLayout> mGeoLayouts;
@ -722,6 +724,7 @@ void DynOS_Lvl_Add(s32 modIndex, const SysPath &aPackFolder, const char *aLevelN
LevelScript* DynOS_Lvl_Get(const char* levelName);
s32 DynOS_Lvl_GetModIndex(void* levelScript);
DataNode<TexData> *DynOS_Lvl_Texture_Get(void *aPtr);
void DynOS_Lvl_Load_Background(void *aPtr);
//
// Warps
@ -812,6 +815,10 @@ void DynOS_Tex_Write(FILE* aFile, GfxData* aGfxData, DataNode<TexData> *aNode);
void DynOS_Tex_Load(FILE *aFile, GfxData *aGfxData);
void DynOS_Tex_ConvertTextureDataToPng(GfxData *aGfxData, TexData* aTexture);
DataNode<TexData*>* DynOS_TexList_Parse(GfxData* aGfxData, DataNode<TexData*>* aNode);
void DynOS_TexList_Write(FILE* aFile, GfxData* aGfxData, DataNode<TexData*> *aNode);
DataNode<TexData*>* DynOS_TexList_Load(FILE *aFile, GfxData *aGfxData);
DataNode<Vtx>* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode<Vtx>* aNode);
void DynOS_Vtx_Write(FILE* aFile, GfxData* aGfxData, DataNode<Vtx> *aNode);
void DynOS_Vtx_Load(FILE *aFile, GfxData *aGfxData);

View file

@ -41,6 +41,11 @@ static bool DynOS_Actor_WriteBinary(const SysPath &aOutputFilename, GfxData *aGf
DynOS_Tex_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mTextureLists) {
if (_Node->mLoadIndex == i) {
DynOS_TexList_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mVertices) {
if (_Node->mLoadIndex == i) {
DynOS_Vtx_Write(_File, aGfxData, _Node);
@ -101,6 +106,7 @@ GfxData *DynOS_Actor_LoadFromBinary(const SysPath &aPackFolder, const char *aAct
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_TEXTURE_LIST: DynOS_TexList_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;
case DATA_TYPE_GEO_LAYOUT: DynOS_Geo_Load (_File, _GfxData); break;
@ -202,6 +208,7 @@ static void DynOS_Actor_Generate(const SysPath &aPackFolder, Array<Pair<u64, Str
ClearGfxDataNodes(_GfxData->mLightTs);
ClearGfxDataNodes(_GfxData->mAmbientTs);
ClearGfxDataNodes(_GfxData->mTextures);
ClearGfxDataNodes(_GfxData->mTextureLists);
ClearGfxDataNodes(_GfxData->mVertices);
ClearGfxDataNodes(_GfxData->mDisplayLists);
ClearGfxDataNodes(_GfxData->mGeoLayouts);

View file

@ -282,7 +282,6 @@ static void ParseGeoSymbol(GfxData* aGfxData, DataNode<GeoLayout>* aNode, GeoLay
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);
@ -345,6 +344,40 @@ static void ParseGeoSymbol(GfxData* aGfxData, DataNode<GeoLayout>* aNode, GeoLay
return;
}
// Background
if (_Symbol == "GEO_BACKGROUND") {
// check if this is a custom background
const String& backgroundName = aNode->mTokens[aTokenIndex];
DataNode<TexData*>* node = NULL;
for (auto& _Node : aGfxData->mTextureLists) {
if (backgroundName == _Node->mName) {
node = _Node;
break;
}
}
if (node) {
// custom background cmd
node = DynOS_TexList_Parse(aGfxData, node);
aTokenIndex++; // skip background name
s64 func = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex);
aGfxData->mPointerList.Add(aHead + 1);
aGfxData->mPointerList.Add(aHead + 2);
GeoLayout _Gl[] = { GEO_BACKGROUND_EXT(node, func) };
memcpy(aHead, _Gl, sizeof(_Gl));
aHead += (sizeof(_Gl) / sizeof(_Gl[0]));
} else {
// regular background cmd
s64 background = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex);
s64 func = ParseGeoSymbolArg(aGfxData, aNode, aTokenIndex);
aGfxData->mPointerList.Add(aHead + 1);
GeoLayout _Gl[] = { GEO_BACKGROUND(background, func) };
memcpy(aHead, _Gl, sizeof(_Gl));
aHead += (sizeof(_Gl) / sizeof(_Gl[0]));
}
return;
}
// Unknown
PrintError(" ERROR: Unknown geo symbol: %s", _Symbol.begin());
}

View file

@ -1848,6 +1848,11 @@ static bool DynOS_Lvl_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxD
DynOS_Tex_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mTextureLists) {
if (_Node->mLoadIndex == i) {
DynOS_TexList_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mVertices) {
if (_Node->mLoadIndex == i) {
DynOS_Vtx_Write(_File, aGfxData, _Node);
@ -1950,6 +1955,7 @@ GfxData *DynOS_Lvl_LoadFromBinary(const SysPath &aPackFolder, const char *aLevel
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_TEXTURE_LIST: DynOS_TexList_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;
case DATA_TYPE_GEO_LAYOUT: DynOS_Geo_Load (_File, _GfxData); break;

View file

@ -71,6 +71,13 @@ static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) {
}
}
// Texture Lists
for (auto& _Node : aGfxData->mTextureLists) {
if (_Node == aPtr) {
return { _Node->mName, 0 };
}
}
// Display lists
for (auto& _Node : aGfxData->mDisplayLists) {
if (_Node == aPtr) {
@ -284,6 +291,13 @@ static void *GetPointerFromData(GfxData *aGfxData, const String &aPtrName, u32 a
}
}
// Texture Lists
for (auto& _Node : aGfxData->mTextureLists) {
if (_Node->mName == aPtrName) {
return (void *) _Node;
}
}
// Display lists
for (auto &_Node : aGfxData->mDisplayLists) {
if (_Node->mName == aPtrName) {

View file

@ -137,7 +137,7 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) {
// Scanning data type
if (_DataType == DATA_TYPE_NONE) {
// skip includes and externs
// skip entire line of includes and externs
if (!strncmp(c, "#include", 8) || !strncmp(c, "extern ", 7)) {
while (*c != '\n' && *c != '\0') {
c++;
@ -184,7 +184,12 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) {
? DATA_TYPE_ROOMS
: DATA_TYPE_TEXTURE;
} else if (_Buffer == "Texture") {
_DataType = DATA_TYPE_TEXTURE;
// check if this is a 'Texture*' or a 'Texture'
char* peek = c;
while(*peek == ' ') { peek++; }
_DataType = (*peek == '*')
? DATA_TYPE_TEXTURE_LIST
: DATA_TYPE_TEXTURE;
} else if (_Buffer == "Vtx") {
_DataType = DATA_TYPE_VERTEX;
} else if (_Buffer == "Gfx") {
@ -218,6 +223,11 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) {
_Buffer.Add(*c);
}
// Skip const
else if (_Buffer == "const") {
_Buffer.Clear();
}
// Adding new data node
else if (_Buffer.Length() != 0) {
switch (_DataType) {
@ -225,6 +235,7 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) {
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_TEXTURE_LIST: AppendNewNode(aGfxData, aGfxData->mTextureLists, _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;
case DATA_TYPE_GEO_LAYOUT: AppendNewNode(aGfxData, aGfxData->mGeoLayouts, _Buffer, pDataName, pDataTokens); break;

View file

@ -0,0 +1,93 @@
#include "dynos.cpp.h"
/////////////
// Parsing //
/////////////
static TexData* ParseTexListSymbol(GfxData* aGfxData, DataNode<TexData*>* aNode, String& aToken) {
// Textures
for (auto& _Node : aGfxData->mTextures) {
if (aToken == _Node->mName) {
return DynOS_Tex_Parse(aGfxData, _Node)->mData;
}
}
// Unknown
PrintError(" ERROR: Unknown texlist arg: %s", aToken.begin());
return NULL;
}
DataNode<TexData*>* DynOS_TexList_Parse(GfxData* aGfxData, DataNode<TexData*>* aNode) {
if (aNode->mData) return aNode;
// TexList data
aNode->mSize = (u32) (aNode->mTokens.Count());
aNode->mData = New<TexData*>(aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
aNode->mData[i] = ParseTexListSymbol(aGfxData, aNode, aNode->mTokens[i]);
aGfxData->mPointerList.Add(&aNode->mData[i]);
}
aNode->mLoadIndex = aGfxData->mLoadIndex++;
return aNode;
}
/////////////
// Writing //
/////////////
void DynOS_TexList_Write(FILE* aFile, GfxData* aGfxData, DataNode<TexData*> *aNode) {
if (!aNode->mData) return;
// Name
WriteBytes<u8>(aFile, DATA_TYPE_TEXTURE_LIST);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
// find node
bool found = false;
for (auto& _Node : aGfxData->mTextures) {
if (_Node->mData == aNode->mData[i]) {
DynOS_Pointer_Write(aFile, (const void *) (_Node), aGfxData);
found = true;
break;
}
}
if (!found) {
PrintError("Could not write texture in texlist");
}
}
}
/////////////
// Reading //
/////////////
DataNode<TexData*>* DynOS_TexList_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<TexData*> *_Node = New<DataNode<TexData*>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mSize = ReadBytes<u32>(aFile);
_Node->mData = New<TexData*>(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
u32 _Value = ReadBytes<u32>(aFile);
void *_Ptr = DynOS_Pointer_Load(aFile, aGfxData, _Value, false);
if (_Ptr == NULL) {
PrintError("Could not read texture in texlist");
} else {
_Node->mData[i] = ((DataNode<TexData>*)_Ptr)->mData;
}
}
// Add it
if (aGfxData != NULL) {
aGfxData->mTextureLists.Add(_Node);
}
return _Node;
}

View file

@ -22,6 +22,10 @@ void DynOS_Gfx_Free(GfxData* aGfxData) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mTextureLists) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mVertices) {
Delete(_Node->mData);
Delete(_Node);

View file

@ -107,4 +107,8 @@ LevelScript* dynos_level_get(const char* levelName) {
return DynOS_Lvl_Get(levelName);
}
void dynos_level_load_background(void *ptr) {
DynOS_Lvl_Load_Background(ptr);
}
}

View file

@ -14,6 +14,8 @@ extern "C" {
#include "game/object_list_processor.h"
#include "game/behavior_actions.h"
#include "game/rendering_graph_node.h"
#include "game/skybox.h"
#include "actors/common0.h"
#include "actors/common1.h"
#include "actors/group0.h"
@ -36,6 +38,7 @@ extern "C" {
#include "actors/group17.h"
#include "actors/custom0.h"
#include "actors/zcustom0.h"
#include "levels/bbh/header.h"
#include "levels/bitdw/header.h"
#include "levels/bitfs/header.h"
@ -1169,3 +1172,36 @@ DataNode<TexData> *DynOS_Lvl_Texture_Get(void *aPtr) {
}
return NULL;
}
void DynOS_Lvl_Load_Background(void *aPtr) {
// ensure this texture list exists
GfxData* foundGfxData = NULL;
DataNode<TexData*>* foundList = NULL;
for (auto& script : sDynosCustomLevelScripts) {
auto &textureLists = script.second->mTextureLists;
for (auto& textureList : textureLists) {
if (textureList == aPtr) {
foundGfxData = script.second;
foundList = textureList;
goto double_break;
}
}
}
double_break:
if (foundList == NULL) {
Print("Could not find custom background");
return;
}
// Load up custom background
for (s32 i = 0; i < 80; i++) {
// find texture
for (auto& tex : foundGfxData->mTextures) {
if (tex->mData == foundList->mData[i]) {
gCustomSkyboxPtrList[i] = (Texture*)tex;
break;
}
}
}
}

View file

@ -21,6 +21,7 @@
#define BACKGROUND_GREEN_SKY 7
#define BACKGROUND_ABOVE_CLOUDS 8
#define BACKGROUND_PURPLE_SKY 9
#define BACKGROUND_CUSTOM 10
// geo layout macros
@ -429,4 +430,13 @@
#define GEO_CULLING_RADIUS(cullingRadius) \
CMD_BBH(0x20, 0x00, cullingRadius)
/**
* 0x21: Custom backgrounds (skyboxes)
*/
#define GEO_BACKGROUND_EXT(background, function) \
CMD_BBH(0x21, 0x00, 0x00), \
CMD_PTR(background), \
CMD_PTR(function)
#endif // GEO_COMMANDS_H

View file

@ -5,6 +5,7 @@
#include "math_util.h"
#include "game/memory.h"
#include "graph_node.h"
#include "geo_commands.h"
typedef void (*GeoLayoutCommandProc)(void);
@ -42,6 +43,8 @@ GeoLayoutCommandProc GeoLayoutJumpTable[] = {
geo_layout_cmd_nop2,
geo_layout_cmd_nop3,
geo_layout_cmd_node_culling_radius,
// coop
geo_layout_cmd_node_background_ext,
};
struct GraphNode gObjParentGraphNode;
@ -767,6 +770,26 @@ void geo_layout_cmd_node_culling_radius(void) {
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
}
/*
0x21: Create custom background scene graph node
*/
void geo_layout_cmd_node_background_ext(void) {
struct GraphNodeBackground *graphNode;
void* bgPtr = cur_geo_cmd_ptr(0x04);
dynos_level_load_background(bgPtr);
graphNode = init_graph_node_background(
gGraphNodePool, NULL,
BACKGROUND_CUSTOM, // background ID, or RGBA5551 color if asm function is null
(GraphNodeFunc) cur_geo_cmd_ptr(0x08), // asm function
0);
register_scene_graph_node(&graphNode->fnNode.node);
gGeoLayoutCommand += 0x0C << CMD_SIZE_SHIFT;
}
struct GraphNode *process_geo_layout(struct AllocOnlyPool *pool, void *segptr) {
// set by register_scene_graph_node when gCurGraphNodeIndex is 0
// and gCurRootGraphNode is NULL

View file

@ -81,6 +81,7 @@ void geo_layout_cmd_nop(void);
void geo_layout_cmd_copy_view(void);
void geo_layout_cmd_node_held_obj(void);
void geo_layout_cmd_node_culling_radius(void);
void geo_layout_cmd_node_background_ext(void);
struct GraphNode *process_geo_layout(struct AllocOnlyPool *a0, void *segptr);

View file

@ -72,6 +72,7 @@ extern SkyboxTexture clouds_skybox_ptrlist;
extern SkyboxTexture ssl_skybox_ptrlist;
extern SkyboxTexture water_skybox_ptrlist;
extern SkyboxTexture wdw_skybox_ptrlist;
Texture* gCustomSkyboxPtrList[80] = { NULL };
SkyboxTexture *sSkyboxTextures[10] = {
&water_skybox_ptrlist,
@ -223,8 +224,13 @@ void draw_skybox_tile_grid(Gfx **dlist, s8 background, s8 player, s8 colorIndex)
s32 tileIndex = sSkyBoxInfo[player].upperLeftTile + row * SKYBOX_COLS + col;
// UGLY HACK: if the camera moves weird after a level transition this can go too high
if (tileIndex > 79) { tileIndex = 79; }
const u8 *const texture =
(*(SkyboxTexture *) segmented_to_virtual(sSkyboxTextures[background]))[tileIndex];
Texture* texture = NULL;
if (background >= 10) {
texture = gCustomSkyboxPtrList[tileIndex];
} else {
texture = (Texture*)(*(SkyboxTexture *) segmented_to_virtual(sSkyboxTextures[background]))[tileIndex];
}
Vtx *vertices = make_skybox_rect(tileIndex, colorIndex);
gLoadBlockTexture((*dlist)++, 32, 32, G_IM_FMT_RGBA, texture);

View file

@ -4,6 +4,8 @@
#include <PR/ultratypes.h>
#include <PR/gbi.h>
extern Texture* gCustomSkyboxPtrList[];
Gfx *create_skybox_facing_camera(s8 player, s8 background, f32 fov,
f32 posX, f32 posY, f32 posZ,
f32 focX, f32 focY, f32 focZ);