diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 000000000..c59141097 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 000000000..79ee123c2 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/DataSpec/DNACommon/AROTBuilder.cpp b/DataSpec/DNACommon/AROTBuilder.cpp index 00f188dfe..1b9788dd5 100644 --- a/DataSpec/DNACommon/AROTBuilder.cpp +++ b/DataSpec/DNACommon/AROTBuilder.cpp @@ -4,9 +4,110 @@ namespace DataSpec { logvisor::Module Log("AROTBuilder"); -#define AROT_MAX_LEVEL 7 +#define AROT_MAX_LEVEL 6 +#define COLLISION_MIN_NODE_TRIANGLES 16 -static const uint32_t AROTChildCounts[] = { 0, 2, 2, 4, 2, 4, 4, 8 }; +static zeus::CAABox SplitAABB(const zeus::CAABox& aabb, int i) +{ + zeus::CAABox pos, neg; + aabb.splitZ(neg, pos); + if (i & 4) + { + zeus::CAABox(pos).splitY(neg, pos); + if (i & 2) + { + zeus::CAABox(pos).splitX(neg, pos); + if (i & 1) + return pos; + else + return neg; + } + else + { + zeus::CAABox(neg).splitX(neg, pos); + if (i & 1) + return pos; + else + return neg; + } + } + else + { + zeus::CAABox(neg).splitY(neg, pos); + if (i & 2) + { + zeus::CAABox(pos).splitX(neg, pos); + if (i & 1) + return pos; + else + return neg; + } + else + { + zeus::CAABox(neg).splitX(neg, pos); + if (i & 1) + return pos; + else + return neg; + } + } +} + +void AROTBuilder::Node::addChild(int level, int minChildren, const std::vector& triBoxes, + const zeus::CAABox& curAABB, BspNodeType& typeOut) +{ + /* Gather intersecting faces */ + for (int i=0 ; i(); + flags = 0; + } +} size_t AROTBuilder::BitmapPool::addIndices(const std::set& indices) { @@ -17,95 +118,49 @@ size_t AROTBuilder::BitmapPool::addIndices(const std::set& indices) return m_pool.size() - 1; } -bool AROTBuilder::Node::addChild(int level, const zeus::CAABox& curAabb, const zeus::CAABox& childAabb, int idx) -{ - if (childAabb.intersects(curAabb)) - { - childIndices.insert(idx); - if (!curAabb.inside(childAabb) && level < AROT_MAX_LEVEL) - { - childNodes.resize(8); - zeus::CAABox X[2]; - curAabb.splitX(X[0], X[1]); - bool inX[2] = {}; - for (int i=0 ; i<2 ; ++i) - { - zeus::CAABox Y[2]; - X[i].splitY(Y[0], Y[1]); - bool inY[2] = {}; - for (int j=0 ; j<2 ; ++j) - { - zeus::CAABox Z[2]; - Y[j].splitZ(Z[0], Z[1]); - bool inZ[2] = {}; - inZ[0] = childNodes[i*4 + j*2].addChild(level + 1, Z[0], childAabb, idx); - inZ[1] = childNodes[i*4 + j*2 + 1].addChild(level + 1, Z[1], childAabb, idx); - if (inZ[0] ^ inZ[1]) - flags |= 0x4; - if (inZ[0] | inZ[1]) - inY[j] = true; - } - if (inY[0] ^ inY[1]) - flags |= 0x2; - if (inY[0] | inY[1]) - inX[i] = true; - } - if (inX[0] ^ inX[1]) - flags |= 0x1; - - if (!flags) - childNodes.clear(); - } - return true; - } - return false; -} +static const uint32_t AROTChildCounts[] = { 0, 2, 2, 4, 2, 4, 4, 8 }; void AROTBuilder::Node::nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPool, size_t& curOff) { - if (childIndices.size()) - { - sz += 1; - poolIdx = bmpPool.addIndices(childIndices); - if (poolIdx > 65535) - Log.report(logvisor::Fatal, "AROT bitmap exceeds 16-bit node addressing; area too complex"); + sz += 1; + poolIdx = bmpPool.addIndices(childIndices); + if (poolIdx > 65535) + Log.report(logvisor::Fatal, "AROT bitmap exceeds 16-bit node addressing; area too complex"); - uint32_t childCount = AROTChildCounts[flags]; - nodeOff = curOff; - nodeSz = childCount * 2 + 4; - curOff += nodeSz; - if (childNodes.size()) + uint32_t childCount = AROTChildCounts[compSubdivs]; + nodeOff = curOff; + nodeSz = childCount * 2 + 4; + curOff += nodeSz; + if (childNodes.size()) + { + for (int k=0 ; k < 1 + ((compSubdivs & 0x1) != 0) ; ++k) { - for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) + for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j) { - for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) + for (int i=0 ; i < 1 + ((compSubdivs & 0x4) != 0) ; ++i) { - for (int k=0 ; k < 1 + ((flags & 0x4) != 0) ; ++k) - { - childNodes[i*4 + j*2 + k].nodeCount(sz, idxRefs, bmpPool, curOff); - } + int idx = k*4 + j*2 + i; + childNodes[idx].nodeCount(sz, idxRefs, bmpPool, curOff); } } - idxRefs += childCount; } + idxRefs += childCount; } } void AROTBuilder::Node::writeIndirectionTable(athena::io::MemoryWriter& w) { - if (childIndices.size()) + w.writeUint32Big(nodeOff); + if (childNodes.size()) { - w.writeUint32Big(nodeOff); - if (childNodes.size()) + for (int k=0 ; k < 1 + ((compSubdivs & 0x1) != 0) ; ++k) { - for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) + for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j) { - for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) + for (int i=0 ; i < 1 + ((compSubdivs & 0x4) != 0) ; ++i) { - for (int k=0 ; k < 1 + ((flags & 0x4) != 0) ; ++k) - { - childNodes[i*4 + j*2 + k].writeIndirectionTable(w); - } + int idx = k*4 + j*2 + i; + childNodes[idx].writeIndirectionTable(w); } } } @@ -114,41 +169,39 @@ void AROTBuilder::Node::writeIndirectionTable(athena::io::MemoryWriter& w) void AROTBuilder::Node::writeNodes(athena::io::MemoryWriter& w, int nodeIdx) { - if (childIndices.size()) + w.writeUint16Big(poolIdx); + w.writeUint16Big(compSubdivs); + + if (childNodes.size()) { - w.writeUint16Big(poolIdx); - w.writeUint16Big(flags); - if (childNodes.size()) + int curIdx = nodeIdx + 1; + if (curIdx > 65535) + Log.report(logvisor::Fatal, "AROT node exceeds 16-bit node addressing; area too complex"); + + int childIndices[8]; + + for (int k=0 ; k < 1 + ((compSubdivs & 0x1) != 0) ; ++k) { - int curIdx = nodeIdx + 1; - if (curIdx > 65535) - Log.report(logvisor::Fatal, "AROT node exceeds 16-bit node addressing; area too complex"); - - int childIndices[8]; - - for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) + for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j) { - for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) + for (int i=0 ; i < 1 + ((compSubdivs & 0x4) != 0) ; ++i) { - for (int k=0 ; k < 1 + ((flags & 0x4) != 0) ; ++k) - { - int ch = i*4 + j*2 + k; - w.writeUint16Big(curIdx); - childIndices[ch] = curIdx; - childNodes[ch].advanceIndex(curIdx); - } + int idx = k*4 + j*2 + i; + w.writeUint16Big(curIdx); + childIndices[idx] = curIdx; + childNodes[idx].advanceIndex(curIdx); } } + } - for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) + for (int k=0 ; k < 1 + ((compSubdivs & 0x1) != 0) ; ++k) + { + for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j) { - for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) + for (int i=0 ; i < 1 + ((compSubdivs & 0x4) != 0) ; ++i) { - for (int k=0 ; k < 1 + ((flags & 0x4) != 0) ; ++k) - { - int ch = i*4 + j*2 + k; - childNodes[ch].writeNodes(w, childIndices[ch]); - } + int idx = k*4 + j*2 + i; + childNodes[idx].writeNodes(w, childIndices[idx]); } } } @@ -157,19 +210,17 @@ void AROTBuilder::Node::writeNodes(athena::io::MemoryWriter& w, int nodeIdx) void AROTBuilder::Node::advanceIndex(int& nodeIdx) { - if (childIndices.size()) + ++nodeIdx; + if (childNodes.size()) { - ++nodeIdx; - if (childNodes.size()) + for (int k=0 ; k < 1 + ((compSubdivs & 0x1) != 0) ; ++k) { - for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) + for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j) { - for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) + for (int i=0 ; i < 1 + ((compSubdivs & 0x4) != 0) ; ++i) { - for (int k=0 ; k < 1 + ((flags & 0x4) != 0) ; ++k) - { - childNodes[i*4 + j*2 + k].advanceIndex(nodeIdx); - } + int idx = k*4 + j*2 + i; + childNodes[idx].advanceIndex(nodeIdx); } } } @@ -188,16 +239,8 @@ void AROTBuilder::Node::colSize(size_t& totalSz) else { totalSz += 36; - for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) - { - for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) - { - for (int k=0 ; k < 1 + ((flags & 0x4) != 0) ; ++k) - { - childNodes[i*4 + j*2 + k].colSize(totalSz); - } - } - } + for (int i=0 ; i<8 ; ++i) + childNodes[i].colSize(totalSz); } } } @@ -226,90 +269,31 @@ void AROTBuilder::Node::writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB uint16_t* pflags = reinterpret_cast(ptr); uint32_t* offsets = reinterpret_cast(ptr + 4); memset(pflags, 0, sizeof(uint32_t) * 9); - for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) + for (int i=0 ; i<8 ; ++i) { - for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) - { - for (int k=0 ; k < 1 + ((flags & 0x4) != 0) ; ++k) - { - int idx = i*4 + j*2 + k; - uint32_t thisOffset; - uint16_t thisFlags = childNodes[idx].getColRef(thisOffset); - if (thisFlags) - { - *pflags |= thisFlags << (idx * 2); - offsets[idx] = hecl::SBig(uint32_t(thisOffset - nodeOff - 36)); - } - } - } + const Node& chNode = childNodes[i]; + BspNodeType type = BspNodeType((flags >> (i * 2)) & 0x3); + if (type != BspNodeType::Invalid) + offsets[i] = hecl::SBig(uint32_t(chNode.nodeOff - nodeOff - 36)); } - *pflags = hecl::SBig(*pflags); + + *pflags = hecl::SBig(flags); ptr += 36; - zeus::CAABox X[2]; - if (flags & 0x1) - curAABB.splitX(X[0], X[1]); - else - { - X[0] = curAABB; - X[1] = curAABB; - } - - for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) - { - zeus::CAABox Y[2]; - if (flags & 0x2) - X[i].splitY(Y[0], Y[1]); - else - { - Y[0] = X[i]; - Y[1] = X[i]; - } - - for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) - { - zeus::CAABox Z[2]; - if (flags & 0x4) - Y[j].splitZ(Z[0], Z[1]); - else - { - Z[0] = Y[j]; - Z[1] = Y[j]; - } - - for (int k=0 ; k < 1 + ((flags & 0x4) != 0) ; ++k) - { - int idx = i*4 + j*2 + k; - childNodes[idx].writeColNodes(ptr, Z[k]); - } - } - } + for (int i=0 ; i<8 ; ++i) + childNodes[i].writeColNodes(ptr, SplitAABB(curAABB, i)); } } } -uint16_t AROTBuilder::Node::getColRef(uint32_t& offset) -{ - if (childIndices.size()) - { - offset = nodeOff; - if (childNodes.empty()) - return 2; - else - return 1; - } - return 0; -} - void AROTBuilder::build(std::vector>& secs, const zeus::CAABox& fullAabb, const std::vector& meshAabbs, const std::vector& meshes) { - for (int i=0 ; i>& secs, const zeus::CAA size_t bmpWordCount = ROUND_UP_32(meshes.size()) / 32; size_t arotSz = 64 + bmpWordCount * bmpPool.m_pool.size() * 4 + totalNodeCount * 8 + idxRefCount * 2; + /* Write header */ secs.emplace_back(arotSz, 0); athena::io::MemoryWriter w(secs.back().data(), secs.back().size()); w.writeUint32Big('AROT'); @@ -328,6 +313,7 @@ void AROTBuilder::build(std::vector>& secs, const zeus::CAA w.writeVec3fBig(fullAabb.max); w.seekAlign32(); + /* Write bitmap */ std::vector bmpWords; bmpWords.reserve(bmpWordCount); for (const std::set& bmp : bmpPool.m_pool) @@ -361,20 +347,25 @@ void AROTBuilder::build(std::vector>& secs, const zeus::CAA w.writeUint32Big(word); } + /* Write the rest */ rootNode.writeIndirectionTable(w); rootNode.writeNodes(w, 0); } std::pair, uint32_t> AROTBuilder::buildCol(const ColMesh& mesh, BspNodeType& rootOut) { - zeus::CAABox fullAabb; + /* Accumulate total AABB */ + zeus::CAABox fullAABB; for (const auto& vert : mesh.verts) - fullAabb.accumulateBounds(zeus::CVector3f(vert)); + fullAABB.accumulateBounds(zeus::CVector3f(vert)); - int t = 0; + /* Predetermine triangle AABBs */ + std::vector triBoxes; + triBoxes.reserve(mesh.trianges.size()); for (const ColMesh::Triangle& tri : mesh.trianges) { - zeus::CAABox aabb; + triBoxes.emplace_back(); + zeus::CAABox& aabb = triBoxes.back(); for (int e=0 ; e<3 ; ++e) { const ColMesh::Edge& edge = mesh.edges[tri.edges[e]]; @@ -384,17 +375,17 @@ std::pair, uint32_t> AROTBuilder::buildCol(const ColM aabb.accumulateBounds(zeus::CVector3f(vert)); } } - rootNode.addChild(0, fullAabb, aabb, t); - ++t; } + /* Recursively split */ + rootNode.addChild(0, COLLISION_MIN_NODE_TRIANGLES, triBoxes, fullAABB, rootOut); + + /* Calculate offsets and write out */ size_t totalSize = 0; rootNode.colSize(totalSize); std::unique_ptr ret(new uint8_t[totalSize]); - uint32_t dummy; - rootOut = BspNodeType(rootNode.getColRef(dummy)); uint8_t* ptr = ret.get(); - rootNode.writeColNodes(ptr, fullAabb); + rootNode.writeColNodes(ptr, fullAABB); return {std::move(ret), totalSize}; } diff --git a/DataSpec/DNACommon/AROTBuilder.hpp b/DataSpec/DNACommon/AROTBuilder.hpp index 3776144a8..c4357c470 100644 --- a/DataSpec/DNACommon/AROTBuilder.hpp +++ b/DataSpec/DNACommon/AROTBuilder.hpp @@ -12,6 +12,8 @@ namespace DataSpec struct AROTBuilder { + using ColMesh = hecl::BlenderConnection::DataStream::ColMesh; + struct BitmapPool { std::vector> m_pool; @@ -23,12 +25,14 @@ struct AROTBuilder std::vector childNodes; std::set childIndices; size_t poolIdx = 0; - uint8_t flags = 0; + uint16_t flags = 0; + uint16_t compSubdivs = 0; size_t nodeOff = 0; size_t nodeSz = 4; - bool addChild(int level, const zeus::CAABox& curAabb, const zeus::CAABox& childAabb, int idx); + void addChild(int level, int minChildren, const std::vector& triBoxes, + const zeus::CAABox& curAABB, BspNodeType& typeOut); void nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPool, size_t& curOff); void writeIndirectionTable(athena::io::MemoryWriter& w); void writeNodes(athena::io::MemoryWriter& w, int nodeIdx); @@ -36,12 +40,10 @@ struct AROTBuilder void colSize(size_t& totalSz); void writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB); - uint16_t getColRef(uint32_t& offset); } rootNode; void build(std::vector>& secs, const zeus::CAABox& fullAabb, const std::vector& meshAabbs, const std::vector& meshes); - using ColMesh = hecl::BlenderConnection::DataStream::ColMesh; std::pair, uint32_t> buildCol(const ColMesh& mesh, BspNodeType& rootOut); }; diff --git a/DataSpec/DNACommon/TXTR.cpp b/DataSpec/DNACommon/TXTR.cpp index f7fc36c6d..f197eb359 100644 --- a/DataSpec/DNACommon/TXTR.cpp +++ b/DataSpec/DNACommon/TXTR.cpp @@ -896,6 +896,10 @@ bool TXTR::CookPC(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outP return false; } + /* Track alpha values for DXT1 eligibility */ + bool doDXT1 = (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) && + width >= 4 && height >= 4; + /* Read and make RGBA */ for (int r=height-1 ; r>=0 ; --r) { @@ -943,6 +947,8 @@ bool TXTR::CookPC(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outP bufOut[outbase+1] = rowBuf[inbase+1]; bufOut[outbase+2] = rowBuf[inbase+2]; bufOut[outbase+3] = rowBuf[inbase+3]; + if (rowBuf[inbase+3] != 0 && rowBuf[inbase+3] != 255) + doDXT1 = false; } break; case PNG_COLOR_TYPE_PALETTE: @@ -973,6 +979,44 @@ bool TXTR::CookPC(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outP } } + /* Do DXT1 compression */ + std::unique_ptr compOut; + size_t compLen = 0; + if (doDXT1) + { + int filterWidth = width; + int filterHeight = height; + size_t i; + for (i=0 ; i> (i * 2)) & 0x3; + + zeus::CAABox pos, neg, res; + aabb.splitZ(neg, pos); + if (i & 4) + { + zeus::CAABox(pos).splitY(neg, pos); + if (i & 2) + { + zeus::CAABox(pos).splitX(neg, pos); + if (i & 1) + res = pos; + else + res = neg; + } + else + { + zeus::CAABox(neg).splitX(neg, pos); + if (i & 1) + res = pos; + else + res = neg; + } + } + else + { + zeus::CAABox(neg).splitY(neg, pos); + if (i & 2) + { + zeus::CAABox(pos).splitX(neg, pos); + if (i & 1) + res = pos; + else + res = neg; + } + else + { + zeus::CAABox(neg).splitX(neg, pos); + if (i & 1) + res = pos; + else + res = neg; + } + } + + OutputOctreeNode(os, r, BspNodeType(chFlags), res); + } + } + else if (type == BspNodeType::Leaf) + { + zeus::CVector3f pos = aabb.center(); + zeus::CVector3f extent = aabb.extents(); + os.format("obj = bpy.data.objects.new('Leaf', None)\n" + "bpy.context.scene.objects.link(obj)\n" + "obj.location = (%f,%f,%f)\n" + "obj.scale = (%f,%f,%f)\n" + "obj.empty_draw_type = 'CUBE'\n" + "obj.layers[1] = True\n" + "obj.layers[0] = False\n", + pos.x, pos.y, pos.z, extent.x, extent.y, extent.z); + } +} + +static const uint32_t AROTChildCounts[] = { 0, 2, 2, 4, 2, 4, 4, 8 }; + +/* AROT octree dumper */ +static void OutputOctreeNode(hecl::BlenderConnection::PyOutStream& os, athena::io::MemoryReader& r, + const zeus::CAABox& aabb) +{ + r.readUint16Big(); + u16 flags = r.readUint16Big(); + if (flags) + { + u32 childCount = AROTChildCounts[flags]; + r.seek(2 * childCount); + + zeus::CAABox Z[2] = {aabb}; + if ((flags & 0x1) != 0) + aabb.splitZ(Z[0], Z[1]); + for (int k=0 ; k < 1 + ((flags & 0x1) != 0) ; ++k) + { + zeus::CAABox Y[2] = {Z[0]}; + if ((flags & 0x2) != 0) + Z[k].splitY(Y[0], Y[1]); + for (int j=0 ; j < 1 + ((flags & 0x2) != 0) ; ++j) + { + zeus::CAABox X[2] = {Y[0]}; + if ((flags & 0x4) != 0) + Y[j].splitX(X[0], X[1]); + for (int i=0 ; i < 1 + ((flags & 0x4) != 0) ; ++i) + { + OutputOctreeNode(os, r, X[i]); + } + } + } + } + else + { + zeus::CVector3f pos = aabb.center(); + zeus::CVector3f extent = aabb.extents(); + os.format("obj = bpy.data.objects.new('Leaf', None)\n" + "bpy.context.scene.objects.link(obj)\n" + "obj.location = (%f,%f,%f)\n" + "obj.scale = (%f,%f,%f)\n" + "obj.empty_draw_type = 'CUBE'\n" + "obj.layers[1] = True\n" + "obj.layers[0] = False\n", + pos.x, pos.y, pos.z, extent.x, extent.y, extent.z); + } +} + bool MREA::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath, @@ -143,7 +269,8 @@ bool MREA::Extract(const SpecBase& dataSpec, } /* Skip AROT */ - rs.seek(head.secSizes[curSec++], athena::Current); + secStart = rs.position(); + rs.seek(secStart + head.secSizes[curSec++], athena::Begin); /* Read SCLY layers */ secStart = rs.position(); @@ -360,6 +487,38 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath, { AROTBuilder arotBuilder; arotBuilder.build(secs, fullAabb, meshAabbs, meshes); + +#if 0 + hecl::BlenderConnection& conn = btok.getBlenderConnection(); + if (!conn.createBlend(inPath.getWithExtension(_S(".octree.blend"), true), hecl::BlenderConnection::BlendType::Area)) + return false; + + /* Open Py Stream and read sections */ + hecl::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); + os.format("import bpy\n" + "import bmesh\n" + "from mathutils import Vector\n" + "\n" + "bpy.context.scene.name = '%s'\n", + inPath.getLastComponentUTF8().data()); + + athena::io::MemoryReader reader(secs.back().data(), secs.back().size()); + reader.readUint32Big(); + reader.readUint32Big(); + u32 numMeshBitmaps = reader.readUint32Big(); + u32 meshBitCount = reader.readUint32Big(); + u32 numNodes = reader.readUint32Big(); + auto aabbMin = reader.readVec3fBig(); + auto aabbMax = reader.readVec3fBig(); + reader.seekAlign32(); + reader.seek(ROUND_UP_32(meshBitCount) / 8 * numMeshBitmaps + numNodes * 4); + zeus::CAABox arotAABB(aabbMin, aabbMax); + OutputOctreeNode(os, reader, arotAABB); + + os.centerView(); + os.close(); + conn.saveBlend(); +#endif } /* SCLY */ @@ -396,6 +555,29 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath, DeafBabe collision = {}; DeafBabeBuildFromBlender(collision, cMesh); +#if 0 + hecl::BlenderConnection& conn = btok.getBlenderConnection(); + if (!conn.createBlend(inPath.getWithExtension(_S(".octree.blend"), true), hecl::BlenderConnection::BlendType::Area)) + return false; + + /* Open Py Stream and read sections */ + hecl::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); + os.format("import bpy\n" + "import bmesh\n" + "from mathutils import Vector\n" + "\n" + "bpy.context.scene.name = '%s'\n", + inPath.getLastComponentUTF8().data()); + + athena::io::MemoryReader reader(collision.bspTree.get(), collision.bspSize); + zeus::CAABox colAABB(collision.aabb[0], collision.aabb[1]); + OutputOctreeNode(os, reader, collision.rootNodeType, colAABB); + + os.centerView(); + os.close(); + conn.saveBlend(); +#endif + secs.emplace_back(collision.binarySize(0), 0); athena::io::MemoryWriter w(secs.back().data(), secs.back().size()); collision.write(w); diff --git a/Runtime/Collision/CAreaOctTree.cpp b/Runtime/Collision/CAreaOctTree.cpp index 64f32ba45..7886fa142 100644 --- a/Runtime/Collision/CAreaOctTree.cpp +++ b/Runtime/Collision/CAreaOctTree.cpp @@ -478,13 +478,13 @@ CAreaOctTree::Node CAreaOctTree::Node::GetChild(int idx) const if (type == ETreeType::Branch) { zeus::CAABox pos, neg, res; - x0_aabb.splitZ(pos, neg); + x0_aabb.splitZ(neg, pos); if (idx & 4) { - pos.splitY(pos, neg); + zeus::CAABox(pos).splitY(neg, pos); if (idx & 2) { - pos.splitX(pos, neg); + zeus::CAABox(pos).splitX(neg, pos); if (idx & 1) res = pos; else @@ -492,7 +492,7 @@ CAreaOctTree::Node CAreaOctTree::Node::GetChild(int idx) const } else { - neg.splitX(pos, neg); + zeus::CAABox(neg).splitX(neg, pos); if (idx & 1) res = pos; else @@ -501,10 +501,10 @@ CAreaOctTree::Node CAreaOctTree::Node::GetChild(int idx) const } else { - neg.splitY(pos, neg); + zeus::CAABox(neg).splitY(neg, pos); if (idx & 2) { - pos.splitX(pos, neg); + zeus::CAABox(pos).splitX(neg, pos); if (idx & 1) res = pos; else @@ -512,7 +512,7 @@ CAreaOctTree::Node CAreaOctTree::Node::GetChild(int idx) const } else { - neg.splitX(pos, neg); + zeus::CAABox(neg).splitX(neg, pos); if (idx & 1) res = pos; else diff --git a/Runtime/Graphics/CGraphics.hpp b/Runtime/Graphics/CGraphics.hpp index 531e276b3..77a5a6bcd 100644 --- a/Runtime/Graphics/CGraphics.hpp +++ b/Runtime/Graphics/CGraphics.hpp @@ -202,7 +202,8 @@ enum class ETexelFormat RGBA8 = 9, CMPR = 10, RGBA8PC = 16, - C8PC = 17 + C8PC = 17, + CMPRPC = 18, }; class CGraphics diff --git a/Runtime/Graphics/CTexture.hpp b/Runtime/Graphics/CTexture.hpp index 7aa845446..888836fbb 100644 --- a/Runtime/Graphics/CTexture.hpp +++ b/Runtime/Graphics/CTexture.hpp @@ -52,6 +52,7 @@ private: void BuildRGBA8(const void* data, size_t length); void BuildC8(const void* data, size_t length); void BuildC8Font(const void* data, EFontType ftype); + void BuildDXT1(const void* data, size_t length); public: CTexture(ETexelFormat, s16, s16, s32); diff --git a/Runtime/Graphics/CTextureBoo.cpp b/Runtime/Graphics/CTextureBoo.cpp index 260d8671a..87ef4dccf 100644 --- a/Runtime/Graphics/CTextureBoo.cpp +++ b/Runtime/Graphics/CTextureBoo.cpp @@ -786,6 +786,16 @@ void CTexture::BuildC8Font(const void* data, EFontType ftype) }); } +void CTexture::BuildDXT1(const void* data, size_t length) +{ + CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + m_booTex = ctx.newStaticTexture(x4_w, x6_h, x8_mips, boo::TextureFormat::DXT1, + boo::TextureClampMode::Repeat, data, length).get(); + return true; + }); +} + CTexture::CTexture(ETexelFormat fmt, s16 w, s16 h, s32 mips) : x0_fmt(fmt) , x4_w(w) @@ -850,6 +860,9 @@ CTexture::CTexture(std::unique_ptr&& in, u32 length, bool otex) BuildC8(owned.get() + 12, length - 12); otex = true; break; + case ETexelFormat::CMPRPC: + BuildDXT1(owned.get() + 12, length - 12); + break; default: Log.report(logvisor::Fatal, "invalid texture type %d for boo", int(x0_fmt)); } diff --git a/Runtime/MP1/CPauseScreen.cpp b/Runtime/MP1/CPauseScreen.cpp index 37a58a208..2149fee57 100644 --- a/Runtime/MP1/CPauseScreen.cpp +++ b/Runtime/MP1/CPauseScreen.cpp @@ -86,6 +86,7 @@ bool CPauseScreen::CheckLoadComplete(const CStateManager& mgr) if (!x28_pauseScreenInstructions->GetIsFinishedLoading()) return false; x34_loadedPauseScreenInstructions = x28_pauseScreenInstructions.GetObj(); + x34_loadedPauseScreenInstructions->SetMaxAspect(1.77f); InitializeFrameGlue(); } if (x60_loadTok) @@ -96,6 +97,7 @@ bool CPauseScreen::CheckLoadComplete(const CStateManager& mgr) { CMemoryInStream s(x5c_frmePauseScreenBuf.get(), x58_frmePauseScreenBufSz); x64_frameInsts.push_back(CGuiFrame::CreateFrame(x54_frmePauseScreenId, *g_GuiSys, s, g_SimplePool)); + x64_frameInsts.back()->SetMaxAspect(1.77f); } x5c_frmePauseScreenBuf.reset(); x60_loadTok.reset(); diff --git a/Runtime/World/CPlayer.cpp b/Runtime/World/CPlayer.cpp index a631c3175..c20f7f741 100644 --- a/Runtime/World/CPlayer.cpp +++ b/Runtime/World/CPlayer.cpp @@ -1762,6 +1762,9 @@ void CPlayer::ProcessInput(const CFinalInput& input, CStateManager& mgr) if (input.ControllerIdx() != 0) return; + if (input.PLTrigger()) + Teleport(zeus::CTransform::Translate(-73.1577f, 155.273f, 0.f), mgr, true); + if (x2f8_morphBallState != EPlayerMorphBallState::Morphed) UpdateScanningState(input, mgr, input.DeltaTime()); @@ -5658,7 +5661,7 @@ float CPlayer::JumpInput(const CFinalInput& input, CStateManager& mgr) return (vDoubleJumpAccel - (vDoubleJumpAccel - hDoubleJumpAccel) * forwards) * xe8_mass * jumpFactor; } - return GetGravity() / xe8_mass; + return GetGravity() * xe8_mass; } if (ControlMapper::GetDigitalInput(ControlMapper::ECommands::JumpOrBoost, input) || diff --git a/hecl b/hecl index 97c3a4918..a6340b03f 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit 97c3a4918e32015988328fda625a46e925fa2764 +Subproject commit a6340b03f77f8e753e0f381a335987d7b53747a3 diff --git a/specter b/specter index d78b1bf64..5b3a0be13 160000 --- a/specter +++ b/specter @@ -1 +1 @@ -Subproject commit d78b1bf64087bf82133b1de71bfca9f9128fbf78 +Subproject commit 5b3a0be1354a0542f1001d6b83e143fa633b673f