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