1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-06-08 17:41:56 +00:00
oot/tools/ZAPD/ZAPD/ZCollision.cpp
EllipticEllipsis 9b67778a00
Building on Macs (#1086)
* git subrepo pull (merge) tools/ZAPD

subrepo:
  subdir:   "tools/ZAPD"
  merged:   "945e6ca1a"
upstream:
  origin:   "https://github.com/zeldaret/ZAPD.git"
  branch:   "master"
  commit:   "50242eca9"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"

* Fix extract_assets.py multithreading

* Update binutils doc a bit

* Remove * import, add multiprocessing option
and way to pass arguments to ZAPD

* Update format.sh to be more platform-independent

* git subrepo pull --force tools/ZAPD

subrepo:
  subdir:   "tools/ZAPD"
  merged:   "fd5a7f434"
upstream:
  origin:   "https://github.com/zeldaret/ZAPD.git"
  branch:   "master"
  commit:   "fd5a7f434"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"

* Remove ;

* Update formatting script to not just use 11

* Add Python requirements,
move the Mac stuff in the README into its own doc

* Fix readme link

* Minor format thing

* .

* Move ZAPDArgs into its own function

* Update readme and remove requirements.txt

* Dragorn-inspired rewrite of processZAPDArgs

* git subrepo pull --force tools/ZAPD

subrepo:
  subdir:   "tools/ZAPD"
  merged:   "a0d3f7b68"
upstream:
  origin:   "https://github.com/zeldaret/ZAPD.git"
  branch:   "master"
  commit:   "a0d3f7b68"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"

* Fix function definition

* Building docs overhaul

* Add Python packages to Mac and Cygwin

* Heading number

* format format.sh (!)

* Replace "currently"

* Remove Debian

* git subrepo pull (merge) --force tools/ZAPD

subrepo:
  subdir:   "tools/ZAPD"
  merged:   "0ba781304"
upstream:
  origin:   "https://github.com/zeldaret/ZAPD.git"
  branch:   "master"
  commit:   "0ba781304"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"
2022-01-16 19:43:07 -05:00

392 lines
12 KiB
C++

#include "ZCollision.h"
#include <cassert>
#include <cstdint>
#include <string>
#include "Globals.h"
#include "Utils/BitConverter.h"
#include "Utils/StringHelper.h"
REGISTER_ZFILENODE(Collision, ZCollisionHeader);
ZCollisionHeader::ZCollisionHeader(ZFile* nParent) : ZResource(nParent)
{
}
ZCollisionHeader::~ZCollisionHeader()
{
delete camData;
}
void ZCollisionHeader::ParseRawData()
{
const auto& rawData = parent->GetRawData();
absMinX = BitConverter::ToInt16BE(rawData, rawDataIndex + 0);
absMinY = BitConverter::ToInt16BE(rawData, rawDataIndex + 2);
absMinZ = BitConverter::ToInt16BE(rawData, rawDataIndex + 4);
absMaxX = BitConverter::ToInt16BE(rawData, rawDataIndex + 6);
absMaxY = BitConverter::ToInt16BE(rawData, rawDataIndex + 8);
absMaxZ = BitConverter::ToInt16BE(rawData, rawDataIndex + 10);
numVerts = BitConverter::ToUInt16BE(rawData, rawDataIndex + 12);
vtxAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 16);
numPolygons = BitConverter::ToUInt16BE(rawData, rawDataIndex + 20);
polyAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 24);
polyTypeDefAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 28);
camDataAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 32);
numWaterBoxes = BitConverter::ToUInt16BE(rawData, rawDataIndex + 36);
waterBoxAddress = BitConverter::ToInt32BE(rawData, rawDataIndex + 40);
vtxSegmentOffset = Seg2Filespace(vtxAddress, parent->baseAddress);
polySegmentOffset = Seg2Filespace(polyAddress, parent->baseAddress);
polyTypeDefSegmentOffset = Seg2Filespace(polyTypeDefAddress, parent->baseAddress);
camDataSegmentOffset = Seg2Filespace(camDataAddress, parent->baseAddress);
waterBoxSegmentOffset = Seg2Filespace(waterBoxAddress, parent->baseAddress);
vertices.reserve(numVerts);
polygons.reserve(numPolygons);
uint32_t currentPtr = vtxSegmentOffset;
for (uint16_t i = 0; i < numVerts; i++)
{
ZVector vec(parent);
vec.ExtractFromBinary(currentPtr, ZScalarType::ZSCALAR_S16, 3);
currentPtr += vec.GetRawDataSize();
vertices.push_back(vec);
}
for (uint16_t i = 0; i < numPolygons; i++)
polygons.push_back(PolygonEntry(rawData, polySegmentOffset + (i * 16)));
uint16_t highestPolyType = 0;
for (PolygonEntry poly : polygons)
{
if (poly.type > highestPolyType)
highestPolyType = poly.type;
}
for (uint16_t i = 0; i < highestPolyType + 1; i++)
polygonTypes.push_back(
BitConverter::ToUInt64BE(rawData, polyTypeDefSegmentOffset + (i * 8)));
if (camDataAddress != SEGMENTED_NULL)
{
// Try to guess how many elements the CamDataList array has.
// The "guessing algorithm" is basically a "best effort" one and it
// is error-prone.
// This is based mostly on observation of how CollisionHeader data is
// usually ordered. If for some reason the data was in some other funny
// order, this would probably break.
// The most common ordering is:
// - *CamData*
// - SurfaceType
// - CollisionPoly
// - Vertices
// - WaterBoxes
// - CollisionHeader
offset_t upperCameraBoundary = polyTypeDefSegmentOffset;
if (upperCameraBoundary == 0)
{
upperCameraBoundary = polySegmentOffset;
}
if (upperCameraBoundary == 0)
{
upperCameraBoundary = vtxSegmentOffset;
}
if (upperCameraBoundary == 0)
{
upperCameraBoundary = waterBoxSegmentOffset;
}
if (upperCameraBoundary == 0)
{
upperCameraBoundary = rawDataIndex;
}
camData =
new CameraDataList(parent, name, rawData, camDataSegmentOffset, upperCameraBoundary);
}
for (uint16_t i = 0; i < numWaterBoxes; i++)
waterBoxes.push_back(WaterBoxHeader(
rawData,
waterBoxSegmentOffset + (i * (Globals::Instance->game == ZGame::OOT_SW97 ? 12 : 16))));
}
void ZCollisionHeader::DeclareReferences(const std::string& prefix)
{
std::string declaration = "";
std::string auxName = name;
if (name == "")
auxName = GetDefaultName(prefix);
if (waterBoxes.size() > 0)
{
for (size_t i = 0; i < waterBoxes.size(); i++)
{
declaration +=
StringHelper::Sprintf("\t{ %s },", waterBoxes[i].GetBodySourceCode().c_str());
if (i + 1 < waterBoxes.size())
declaration += "\n";
}
parent->AddDeclarationArray(
waterBoxSegmentOffset, DeclarationAlignment::Align4, 16 * waterBoxes.size(), "WaterBox",
StringHelper::Sprintf("%sWaterBoxes", auxName.c_str()), waterBoxes.size(), declaration);
}
if (polygons.size() > 0)
{
declaration.clear();
for (size_t i = 0; i < polygons.size(); i++)
{
declaration += StringHelper::Sprintf(
"\t{ 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X },",
polygons[i].type, polygons[i].vtxA, polygons[i].vtxB, polygons[i].vtxC,
polygons[i].a, polygons[i].b, polygons[i].c, polygons[i].d);
if (i + 1 < polygons.size())
declaration += "\n";
}
parent->AddDeclarationArray(
polySegmentOffset, DeclarationAlignment::Align4, polygons.size() * 16, "CollisionPoly",
StringHelper::Sprintf("%sPolygons", auxName.c_str()), polygons.size(), declaration);
}
declaration.clear();
for (size_t i = 0; i < polygonTypes.size(); i++)
{
declaration += StringHelper::Sprintf("\t{ 0x%08lX, 0x%08lX },", polygonTypes[i] >> 32,
polygonTypes[i] & 0xFFFFFFFF);
if (i < polygonTypes.size() - 1)
declaration += "\n";
}
if (polyTypeDefAddress != 0)
parent->AddDeclarationArray(polyTypeDefSegmentOffset, DeclarationAlignment::Align4,
polygonTypes.size() * 8, "SurfaceType",
StringHelper::Sprintf("%sSurfaceType", auxName.c_str()),
polygonTypes.size(), declaration);
declaration.clear();
if (vertices.size() > 0)
{
declaration.clear();
for (size_t i = 0; i < vertices.size(); i++)
{
declaration +=
StringHelper::Sprintf("\t{ %s },", vertices[i].GetBodySourceCode().c_str());
if (i < vertices.size() - 1)
declaration += "\n";
}
const auto& first = vertices.front();
if (vtxAddress != 0)
parent->AddDeclarationArray(
vtxSegmentOffset, first.GetDeclarationAlignment(),
vertices.size() * first.GetRawDataSize(), first.GetSourceTypeName(),
StringHelper::Sprintf("%sVertices", auxName.c_str()), vertices.size(), declaration);
}
}
std::string ZCollisionHeader::GetBodySourceCode() const
{
std::string declaration = "";
declaration += "\n";
declaration += StringHelper::Sprintf("\t{ %i, %i, %i },\n", absMinX, absMinY, absMinZ);
declaration += StringHelper::Sprintf("\t{ %i, %i, %i },\n", absMaxX, absMaxY, absMaxZ);
std::string vtxName;
Globals::Instance->GetSegmentedPtrName(vtxAddress, parent, "Vec3s", vtxName);
declaration += StringHelper::Sprintf("\t%i, %s,\n", numVerts, vtxName.c_str());
std::string polyName;
Globals::Instance->GetSegmentedPtrName(polyAddress, parent, "CollisionPoly", polyName);
declaration += StringHelper::Sprintf("\t%i, %s,\n", numPolygons, polyName.c_str());
std::string surfaceName;
Globals::Instance->GetSegmentedPtrName(polyTypeDefAddress, parent, "SurfaceType", surfaceName);
declaration += StringHelper::Sprintf("\t%s,\n", surfaceName.c_str());
std::string camName;
Globals::Instance->GetSegmentedPtrName(camDataAddress, parent, "CamData", camName);
declaration += StringHelper::Sprintf("\t%s,\n", camName.c_str());
std::string waterBoxName;
Globals::Instance->GetSegmentedPtrName(waterBoxAddress, parent, "WaterBox", waterBoxName);
declaration += StringHelper::Sprintf("\t%i, %s\n", numWaterBoxes, waterBoxName.c_str());
return declaration;
}
std::string ZCollisionHeader::GetDefaultName(const std::string& prefix) const
{
return StringHelper::Sprintf("%sCol_%06X", prefix.c_str(), rawDataIndex);
}
std::string ZCollisionHeader::GetSourceTypeName() const
{
return "CollisionHeader";
}
ZResourceType ZCollisionHeader::GetResourceType() const
{
return ZResourceType::CollisionHeader;
}
size_t ZCollisionHeader::GetRawDataSize() const
{
return 44;
}
PolygonEntry::PolygonEntry(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex)
{
const uint8_t* data = rawData.data();
type = BitConverter::ToUInt16BE(data, rawDataIndex + 0);
vtxA = BitConverter::ToUInt16BE(data, rawDataIndex + 2);
vtxB = BitConverter::ToUInt16BE(data, rawDataIndex + 4);
vtxC = BitConverter::ToUInt16BE(data, rawDataIndex + 6);
a = BitConverter::ToUInt16BE(data, rawDataIndex + 8);
b = BitConverter::ToUInt16BE(data, rawDataIndex + 10);
c = BitConverter::ToUInt16BE(data, rawDataIndex + 12);
d = BitConverter::ToUInt16BE(data, rawDataIndex + 14);
}
WaterBoxHeader::WaterBoxHeader(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex)
{
const uint8_t* data = rawData.data();
xMin = BitConverter::ToInt16BE(data, rawDataIndex + 0);
ySurface = BitConverter::ToInt16BE(data, rawDataIndex + 2);
zMin = BitConverter::ToInt16BE(data, rawDataIndex + 4);
xLength = BitConverter::ToInt16BE(data, rawDataIndex + 6);
zLength = BitConverter::ToInt16BE(data, rawDataIndex + 8);
if (Globals::Instance->game == ZGame::OOT_SW97)
properties = BitConverter::ToInt16BE(data, rawDataIndex + 10);
else
properties = BitConverter::ToInt32BE(data, rawDataIndex + 12);
}
std::string WaterBoxHeader::GetBodySourceCode() const
{
return StringHelper::Sprintf("%i, %i, %i, %i, %i, 0x%08X", xMin, ySurface, zMin, xLength,
zLength, properties);
}
CameraDataList::CameraDataList(ZFile* parent, const std::string& prefix,
const std::vector<uint8_t>& rawData, offset_t rawDataIndex,
offset_t upperCameraBoundary)
{
std::string declaration;
// Parse CameraDataEntries
size_t numElements = (upperCameraBoundary - rawDataIndex) / 8;
assert(numElements < 10000);
offset_t cameraPosDataSeg = rawDataIndex;
for (size_t i = 0; i < numElements; i++)
{
CameraDataEntry* entry = new CameraDataEntry();
entry->cameraSType =
BitConverter::ToInt16BE(rawData, rawDataIndex + (entries.size() * 8) + 0);
entry->numData = BitConverter::ToInt16BE(rawData, rawDataIndex + (entries.size() * 8) + 2);
entry->cameraPosDataSeg =
BitConverter::ToInt32BE(rawData, rawDataIndex + (entries.size() * 8) + 4);
if (entry->cameraPosDataSeg != 0 && GETSEGNUM(entry->cameraPosDataSeg) != SEGMENT_SCENE)
{
cameraPosDataSeg = rawDataIndex + (entries.size() * 8);
break;
}
if (entry->cameraPosDataSeg != 0 && cameraPosDataSeg > (entry->cameraPosDataSeg & 0xFFFFFF))
cameraPosDataSeg = (entry->cameraPosDataSeg & 0xFFFFFF);
entries.push_back(entry);
}
// Setting cameraPosDataAddr to rawDataIndex give a pos list length of 0
uint32_t cameraPosDataOffset = cameraPosDataSeg & 0xFFFFFF;
for (size_t i = 0; i < entries.size(); i++)
{
char camSegLine[2048];
if (entries[i]->cameraPosDataSeg != 0)
{
int32_t index =
((entries[i]->cameraPosDataSeg & 0x00FFFFFF) - cameraPosDataOffset) / 0x6;
sprintf(camSegLine, "&%sCamPosData[%i]", prefix.c_str(), index);
}
else
sprintf(camSegLine, "NULL");
declaration +=
StringHelper::Sprintf(" { 0x%04X, %i, %s },", entries[i]->cameraSType,
entries[i]->numData, camSegLine, rawDataIndex + (i * 8));
if (i < entries.size() - 1)
declaration += "\n";
}
parent->AddDeclarationArray(
rawDataIndex, DeclarationAlignment::Align4, entries.size() * 8, "CamData",
StringHelper::Sprintf("%sCamDataList", prefix.c_str(), rawDataIndex), entries.size(),
declaration);
uint32_t numDataTotal = (rawDataIndex - cameraPosDataOffset) / 0x6;
if (numDataTotal > 0)
{
declaration.clear();
for (uint32_t i = 0; i < numDataTotal; i++)
{
CameraPositionData* data =
new CameraPositionData(rawData, cameraPosDataOffset + (i * 6));
cameraPositionData.push_back(data);
declaration += StringHelper::Sprintf("\t{ %6i, %6i, %6i },", data->x, data->y, data->z);
if (i + 1 < numDataTotal)
declaration += "\n";
}
int32_t cameraPosDataIndex = GETSEGOFFSET(cameraPosDataSeg);
uint32_t entrySize = numDataTotal * 0x6;
parent->AddDeclarationArray(cameraPosDataIndex, DeclarationAlignment::Align4, entrySize,
"Vec3s", StringHelper::Sprintf("%sCamPosData", prefix.c_str()),
numDataTotal, declaration);
}
}
CameraDataList::~CameraDataList()
{
for (auto entry : entries)
delete entry;
for (auto camPosData : cameraPositionData)
delete camPosData;
}
CameraPositionData::CameraPositionData(const std::vector<uint8_t>& rawData, uint32_t rawDataIndex)
{
x = BitConverter::ToInt16BE(rawData, rawDataIndex + 0);
y = BitConverter::ToInt16BE(rawData, rawDataIndex + 2);
z = BitConverter::ToInt16BE(rawData, rawDataIndex + 4);
}