mirror of https://github.com/PrimeDecomp/prime.git
244 lines
7.6 KiB
C++
244 lines
7.6 KiB
C++
#include "MetroidPrime/CMapArea.hpp"
|
|
|
|
#include "MetroidPrime/CWorld.hpp"
|
|
#include "MetroidPrime/Tweaks/CTweakAutoMapper.hpp"
|
|
|
|
#include "Kyoto/Alloc/CMemory.hpp"
|
|
#include "Kyoto/CFrameDelayedKiller.hpp"
|
|
#include "Kyoto/CResFactory.hpp"
|
|
#include "Kyoto/Graphics/CGX.hpp"
|
|
#include "Kyoto/Graphics/CGraphics.hpp"
|
|
#include "Kyoto/Streams/CInputStream.hpp"
|
|
#include "Kyoto/Streams/CMemoryInStream.hpp"
|
|
|
|
#include "dolphin/os.h"
|
|
#include "limits.h"
|
|
#include "stdint.h"
|
|
|
|
static const CVector3f MinesPostTransforms[3] = {
|
|
CVector3f(0.f, 0.f, 200.f),
|
|
CVector3f(0.f, 0.f, 0.f),
|
|
CVector3f(0.f, 0.f, -200.f),
|
|
};
|
|
|
|
static const uchar MinesPostTransformIndices[42] = {
|
|
0, // 00 Transport to Tallon Overworld South
|
|
0, // 01 Quarry Access
|
|
0, // 02 Main Quarry
|
|
0, // 03 Waste Disposal
|
|
0, // 04 Save Station Mines A
|
|
0, // 05 Security Access A
|
|
0, // 06 Ore Processing
|
|
0, // 07 Mine Security Station
|
|
0, // 08 Research Access
|
|
0, // 09 Storage Depot B
|
|
0, // 10 Elevator Access A
|
|
0, // 11 Security Access B
|
|
0, // 12 Storage Depot A
|
|
0, // 13 Elite Research
|
|
0, // 14 Elevator A
|
|
1, // 15 Elite Control Access
|
|
1, // 16 Elite Control
|
|
1, // 17 Maintenance Tunnel
|
|
1, // 18 Ventilation Shaft
|
|
2, // 19 Phazon Processing Center
|
|
1, // 20 Omega Research
|
|
2, // 21 Transport Access
|
|
2, // 22 Processing Center Access
|
|
1, // 23 Map Station Mines
|
|
1, // 24 Dynamo Access
|
|
2, // 25 Transport to Magmoor Caverns South
|
|
2, // 26 Elite Quarters
|
|
1, // 27 Central Dynamo
|
|
2, // 28 Elite Quarters Access
|
|
1, // 29 Quarantine Access A
|
|
1, // 30 Save Station Mines B
|
|
2, // 31 Metroid Quarantine B
|
|
1, // 32 Metroid Quarantine A
|
|
2, // 33 Quarantine Access B
|
|
2, // 34 Save Station Mines C
|
|
1, // 35 Elevator Access B
|
|
2, // 36 Fungal Hall B
|
|
1, // 37 Elevator B
|
|
2, // 38 Missile Station Mines
|
|
2, // 39 Phazon Mining Tunnel
|
|
2, // 40 Fungal Hall Access
|
|
2, // 41 Fungal Hall A
|
|
};
|
|
|
|
static CAssetId gHackAssetId = kInvalidAssetId;
|
|
|
|
CMapArea::CMapArea(CInputStream& in, uint size)
|
|
: x0_magic(in.ReadLong())
|
|
, x4_version(in.ReadLong())
|
|
, x8_(in.ReadLong())
|
|
, xc_visibilityMode(EVisMode(in.ReadLong()))
|
|
, x10_box(in)
|
|
, x28_mappableObjCount(in.ReadLong())
|
|
, x2c_vertexCount(in.ReadLong())
|
|
, x30_surfaceCount(in.ReadLong())
|
|
, x34_size(size - 52) {
|
|
x44_buf = rs_new u8[x34_size];
|
|
in.Get(x44_buf.get(), x34_size);
|
|
PostConstruct();
|
|
|
|
DCFlushRange(x3c_vertexStart, x2c_vertexCount * 0xc);
|
|
lbl_805A8EB0 += x34_size + sizeof(*this);
|
|
}
|
|
|
|
CMapArea::~CMapArea() {
|
|
lbl_805A8EB0 -= x34_size + sizeof(*this);
|
|
CFrameDelayedKiller::fn_8036CC1C(true, x44_buf.release());
|
|
}
|
|
|
|
void CMapArea::PostConstruct() {
|
|
x38_moStart = (CMappableObject*)(x44_buf.get());
|
|
void* vertexStart = x38_moStart + x28_mappableObjCount;
|
|
x3c_vertexStart = (CVector3f*)(vertexStart);
|
|
x40_surfaceStart = (CMapAreaSurface*)((CVector3f*)(vertexStart) + x2c_vertexCount);
|
|
|
|
for (int i = 0; i < x28_mappableObjCount; ++i) {
|
|
x38_moStart[i].PostConstruct(x44_buf.get());
|
|
}
|
|
for (int i = 0; i < x2c_vertexCount * 3; ++i) {
|
|
// Somehow this empty loop generates a lot worse code than it should...
|
|
}
|
|
for (int i = 0; i < x30_surfaceCount; ++i) {
|
|
x40_surfaceStart[i].PostConstruct(x44_buf.get());
|
|
}
|
|
}
|
|
|
|
bool CMapArea::GetIsVisibleToAutoMapper(bool worldVis, bool areaVis) const {
|
|
switch (xc_visibilityMode) {
|
|
case kVM_Always:
|
|
return true;
|
|
case kVM_MapStationOrVisit:
|
|
return worldVis || areaVis;
|
|
case kVM_Visit:
|
|
return areaVis;
|
|
case kVM_Never:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
CVector3f CMapArea::GetAreaCenterPoint() const { return x10_box.GetCenterPoint(); }
|
|
|
|
void CMapArea::CMapAreaSurface::PostConstruct(const void* buf) {
|
|
x18_surfOffset = (const int*)((const uchar*)buf + reinterpret_cast< uintptr_t >(x18_surfOffset));
|
|
x1c_outlineOffset =
|
|
(const int*)((const uchar*)buf + reinterpret_cast< uintptr_t >(x1c_outlineOffset));
|
|
|
|
int numSurfaces = *x18_surfOffset;
|
|
for (int i = 0; i < numSurfaces; ++i) {
|
|
// Nothing?
|
|
}
|
|
|
|
int numOutlines = *x1c_outlineOffset;
|
|
for (int i = 0; i < numOutlines; ++i) {
|
|
// Nothing?
|
|
}
|
|
}
|
|
|
|
struct Surface {
|
|
GXPrimitive primitive;
|
|
int numVertices;
|
|
};
|
|
|
|
void CMapArea::CMapAreaSurface::Draw(const CVector3f* verts, const CColor& surfColor,
|
|
const CColor& lineColor, float lineWidth) const {
|
|
bool hasSurfAlpha = surfColor.GetAlpha() > 0.0f;
|
|
bool hasLineAlpha = lineColor.GetAlpha() > 0.0f;
|
|
int numSurfaces = *x18_surfOffset;
|
|
int numOutlines = *x1c_outlineOffset;
|
|
if (verts) {
|
|
CGX::SetArray(GX_VA_POS, verts, '\f');
|
|
}
|
|
if (hasSurfAlpha) {
|
|
CGX::SetTevKColor(GX_KCOLOR0, surfColor.GetGXColor());
|
|
const int* surface = &x18_surfOffset[1];
|
|
for (int i = 0; i < numSurfaces; ++i) {
|
|
GXPrimitive primType = GXPrimitive(*surface++);
|
|
int numVertices = *surface++;
|
|
const u8* data = reinterpret_cast< const u8* >(surface);
|
|
surface += (numVertices + 3) / 4;
|
|
|
|
CGX::Begin(primType, GX_VTXFMT0, numVertices);
|
|
for (int v = 0; v < numVertices; ++v) {
|
|
GXPosition1x8(data[v]);
|
|
}
|
|
CGX::End();
|
|
}
|
|
}
|
|
if (hasLineAlpha) {
|
|
bool thickLine = 1.0f < lineWidth;
|
|
for (int j = 0; j < 1 + !!thickLine; ++j) {
|
|
const int* outline = &x1c_outlineOffset[1];
|
|
|
|
if (thickLine) {
|
|
CGraphics::SetLineWidth(lineWidth - j, ERglTexOffset(5));
|
|
}
|
|
CGX::SetTevKColor(GX_KCOLOR0,
|
|
lineColor.WithAlphaModulatedBy(thickLine ? 0.5f : 1.0f).GetGXColor());
|
|
|
|
for (int i = 0; i < numOutlines; ++i) {
|
|
int numVertices = *outline++;
|
|
const u8* data = reinterpret_cast< const u8* >(outline);
|
|
outline += (numVertices + 3) / 4;
|
|
|
|
CGX::Begin(GX_LINESTRIP, GX_VTXFMT0, numVertices);
|
|
for (int v = 0; v < numVertices; ++v) {
|
|
GXPosition1x8(data[v]);
|
|
}
|
|
CGX::End();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMapArea::CMapAreaSurface::SetupGXMaterial() {
|
|
const GXVtxDescList list[2] = {
|
|
{GX_VA_POS, GX_INDEX8},
|
|
{GX_VA_NULL, GX_NONE},
|
|
};
|
|
CGX::SetVtxDescv(list);
|
|
CGX::SetNumChans(1);
|
|
CGX::SetNumTexGens(0);
|
|
CGX::SetNumTevStages(1);
|
|
CGX::SetChanCtrl(CGX::Channel0, false, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE,
|
|
GX_AF_NONE);
|
|
CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_KONST);
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST);
|
|
CGX::SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
|
|
CGX::SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
|
|
CGX::SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0);
|
|
CGX::SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K0_A);
|
|
}
|
|
|
|
CTransform4f CMapArea::GetAreaPostTransform(const CWorld& world, TAreaId aid) {
|
|
if (world.IGetWorldAssetId() == 0xB1AC4D65) // Phazon Mines
|
|
{
|
|
const CTransform4f& areaXf = world.IGetAreaAlways(aid)->IGetTM();
|
|
const CVector3f& postVec = MinesPostTransforms[MinesPostTransformIndices[aid.value]];
|
|
return CTransform4f::Translate(postVec) * areaXf;
|
|
} else {
|
|
return world.IGetAreaAlways(aid)->IGetTM();
|
|
}
|
|
}
|
|
|
|
const CVector3f& CMapArea::GetAreaPostTranslate(const IWorld& world, TAreaId aid) {
|
|
if (world.IGetWorldAssetId() == 0xB1AC4D65) // Phazon Mines
|
|
{
|
|
return MinesPostTransforms[MinesPostTransformIndices[aid.Value()]];
|
|
} else {
|
|
return CVector3f::Zero();
|
|
}
|
|
}
|
|
|
|
CFactoryFnReturn FMapAreaFactory(const SObjectTag& objTag, CInputStream& in,
|
|
const CVParamTransfer&) {
|
|
gHackAssetId = objTag.mId;
|
|
return CFactoryFnReturn(rs_new CMapArea(in, gpResourceFactory->ResourceSize(objTag)));
|
|
}
|