mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-08 17:44:56 +00:00
Add VISIGen utility
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
#include "zeus/Math.hpp"
|
||||
#include "zeus/CAABox.hpp"
|
||||
#include "DataSpec/DNACommon/AROTBuilder.hpp"
|
||||
#include "ScriptObjects/ScriptTypes.hpp"
|
||||
|
||||
extern const hecl::SystemString ExeDir;
|
||||
|
||||
namespace DataSpec
|
||||
{
|
||||
@@ -162,6 +165,26 @@ bool MREA::Extract(const SpecBase& dataSpec,
|
||||
ReadBabeDeadToBlender_1_2(os, rs);
|
||||
rs.seek(secStart + head.secSizes[curSec++], athena::Begin);
|
||||
|
||||
/* Dump VISI entities */
|
||||
if (head.secSizes[curSec] && rs.readUint32Big() == 'VISI')
|
||||
{
|
||||
athena::io::YAMLDocWriter visiWriter("VISI");
|
||||
if (auto __vec = visiWriter.enterSubVector("entities"))
|
||||
{
|
||||
rs.seek(18, athena::Current);
|
||||
uint32_t entityCount = rs.readUint32Big();
|
||||
rs.seek(8, athena::Current);
|
||||
for (int i=0 ; i<entityCount ; ++i)
|
||||
{
|
||||
uint32_t entityId = rs.readUint32Big();
|
||||
visiWriter.writeUint16(nullptr, entityId & 0xffff);
|
||||
}
|
||||
}
|
||||
hecl::ProjectPath visiMetadataPath(outPath.getParentPath(), _S("!visi.yaml"));
|
||||
athena::io::FileWriter visiMetadata(visiMetadataPath.getAbsolutePath());
|
||||
visiWriter.finish(&visiMetadata);
|
||||
}
|
||||
|
||||
/* Origins to center of mass */
|
||||
os << "bpy.context.scene.layers[1] = True\n"
|
||||
"bpy.ops.object.select_by_type(type='MESH')\n"
|
||||
@@ -251,7 +274,8 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
||||
const hecl::ProjectPath& inPath,
|
||||
const std::vector<DNACMDL::Mesh>& meshes,
|
||||
const ColMesh& cMesh,
|
||||
const std::vector<Light>& lights)
|
||||
const std::vector<Light>& lights,
|
||||
hecl::BlenderToken& btok)
|
||||
{
|
||||
/* Discover area layers */
|
||||
hecl::ProjectPath areaDirPath = inPath.getParentPath();
|
||||
@@ -322,13 +346,13 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
||||
|
||||
/* AROT */
|
||||
{
|
||||
AROTBuilder builder;
|
||||
builder.build(secs, fullAabb, meshAabbs, meshes);
|
||||
AROTBuilder arotBuilder;
|
||||
arotBuilder.build(secs, fullAabb, meshAabbs, meshes);
|
||||
}
|
||||
|
||||
/* SCLY */
|
||||
DNAMP1::SCLY sclyData = {};
|
||||
{
|
||||
DNAMP1::SCLY sclyData = {};
|
||||
sclyData.fourCC = 'SCLY';
|
||||
sclyData.version = 1;
|
||||
for (const hecl::ProjectPath& layer : layerScriptPaths)
|
||||
@@ -373,13 +397,13 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
||||
}
|
||||
|
||||
/* Lights */
|
||||
std::vector<atVec3f> lightsVisi;
|
||||
{
|
||||
int actualCount = 0;
|
||||
for (const Light& l : lights)
|
||||
{
|
||||
if (l.layer == 0 || l.layer == 1)
|
||||
++actualCount;
|
||||
}
|
||||
lightsVisi.reserve(actualCount);
|
||||
|
||||
secs.emplace_back(12 + 65 * actualCount, 0);
|
||||
athena::io::MemoryWriter w(secs.back().data(), secs.back().size());
|
||||
@@ -401,15 +425,100 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
||||
BabeDeadLight light = {};
|
||||
WriteBabeDeadLightFromBlender(light, l);
|
||||
light.write(w);
|
||||
lightsVisi.push_back(light.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* VISI */
|
||||
hecl::ProjectPath visiMetadataPath(areaDirPath, _S("!visi.yaml"));
|
||||
if (visiMetadataPath.isFile())
|
||||
{
|
||||
/* Empty (for now) */
|
||||
secs.emplace_back(0, 0);
|
||||
bool good = false;
|
||||
athena::io::FileReader visiReader(visiMetadataPath.getAbsolutePath());
|
||||
athena::io::YAMLDocReader r;
|
||||
if (r.parse(&visiReader))
|
||||
{
|
||||
size_t entityCount;
|
||||
std::vector<std::pair<uint16_t, zeus::CAABox>> entities;
|
||||
if (auto __vec = r.enterSubVector("entities", entityCount))
|
||||
{
|
||||
entities.reserve(entityCount);
|
||||
uint16_t entityId = r.readUint16(nullptr);
|
||||
for (const SCLY::ScriptLayer& layer : sclyData.layers)
|
||||
{
|
||||
for (const std::unique_ptr<IScriptObject>& obj : layer.objects)
|
||||
{
|
||||
if ((obj->id & 0xffff) == entityId)
|
||||
{
|
||||
zeus::CAABox entAABB = obj->getVISIAABB(btok);
|
||||
if (entAABB.min.x < entAABB.max.x)
|
||||
entities.emplace_back(entityId, entAABB);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hecl::ProjectPath visiIntOut = outPath.getWithExtension(_S(".visiint"));
|
||||
hecl::ProjectPath visiIn = outPath.getWithExtension(_S(".visi"));
|
||||
athena::io::FileWriter w(visiIntOut.getAbsolutePath());
|
||||
w.writeUint32Big(meshes.size());
|
||||
for (const DNACMDL::Mesh& mesh : meshes)
|
||||
{
|
||||
w.writeUint32Big(uint32_t(mesh.topology));
|
||||
|
||||
w.writeUint32Big(mesh.pos.size());
|
||||
for (const auto& v : mesh.pos)
|
||||
{
|
||||
atVec3f xfPos = hecl::BlenderConnection::DataStream::MtxVecMul4RM(mesh.sceneXf, v);
|
||||
w.writeVec3fBig(xfPos);
|
||||
}
|
||||
|
||||
w.writeUint32Big(mesh.surfaces.size());
|
||||
for (const DNACMDL::Mesh::Surface& surf : mesh.surfaces)
|
||||
{
|
||||
w.writeUint32Big(surf.verts.size());
|
||||
for (const DNACMDL::Mesh::Surface::Vert& vert : surf.verts)
|
||||
w.writeUint32Big(vert.iPos);
|
||||
const DNACMDL::Mesh::Material& mat = mesh.materialSets[0][surf.materialIdx];
|
||||
w.writeBool(mat.transparent);
|
||||
}
|
||||
}
|
||||
|
||||
w.writeUint32Big(entities.size());
|
||||
for (const auto& ent : entities)
|
||||
{
|
||||
w.writeUint32Big(ent.first);
|
||||
w.writeVec3fBig(ent.second.min);
|
||||
w.writeVec3fBig(ent.second.max);
|
||||
}
|
||||
|
||||
w.writeUint32Big(lightsVisi.size());
|
||||
for (const auto& light : lightsVisi)
|
||||
w.writeVec3fBig(light);
|
||||
|
||||
w.close();
|
||||
|
||||
hecl::SystemString VisiGenPath = ExeDir + _S("/visigen");
|
||||
#if _WIN32
|
||||
VisiGenPath += _S(".exe");
|
||||
#endif
|
||||
const hecl::SystemChar* args[] = {VisiGenPath.c_str(),
|
||||
visiIntOut.getAbsolutePath().c_str(),
|
||||
visiIn.getAbsolutePath().c_str(),
|
||||
nullptr};
|
||||
if (0 == hecl::RunProcess(VisiGenPath.c_str(), args))
|
||||
{
|
||||
athena::io::FileReader r(visiIn.getAbsolutePath());
|
||||
size_t length = r.length();
|
||||
secs.emplace_back(length, 0);
|
||||
r.readBytesToBuf(secs.back().data(), length);
|
||||
good = true;
|
||||
}
|
||||
}
|
||||
if (!good)
|
||||
secs.emplace_back(0, 0);
|
||||
}
|
||||
|
||||
/* PATH */
|
||||
|
||||
@@ -135,7 +135,8 @@ struct MREA
|
||||
const hecl::ProjectPath& inPath,
|
||||
const std::vector<DNACMDL::Mesh>& meshes,
|
||||
const ColMesh& cMesh,
|
||||
const std::vector<Light>& lights);
|
||||
const std::vector<Light>& lights,
|
||||
hecl::BlenderToken& btok);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ struct Actor : IScriptObject
|
||||
Value<atVec3f> orientation;
|
||||
Value<atVec3f> scale;
|
||||
Value<atVec3f> collisionExtent;
|
||||
Value<atVec3f> centroid;
|
||||
Value<atVec3f> collisionOffset;
|
||||
Value<float> unknown2;
|
||||
Value<float> unknown3;
|
||||
HealthInfo healthInfo;
|
||||
@@ -64,6 +64,36 @@ struct Actor : IScriptObject
|
||||
{
|
||||
actorParameters.scanIDs(scansOut);
|
||||
}
|
||||
|
||||
zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const
|
||||
{
|
||||
hecl::BlenderConnection& conn = btok.getBlenderConnection();
|
||||
zeus::CAABox aabbOut;
|
||||
|
||||
if (model)
|
||||
{
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(model);
|
||||
conn.openBlend(path);
|
||||
hecl::BlenderConnection::DataStream ds = conn.beginData();
|
||||
auto aabb = ds.getMeshAABB();
|
||||
aabbOut = zeus::CAABox(aabb.first, aabb.second);
|
||||
}
|
||||
else if (animationParameters.animationCharacterSet)
|
||||
{
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(
|
||||
animationParameters.animationCharacterSet);
|
||||
conn.openBlend(path.getWithExtension(_S(".blend"), true));
|
||||
hecl::BlenderConnection::DataStream ds = conn.beginData();
|
||||
auto aabb = ds.getMeshAABB();
|
||||
aabbOut = zeus::CAABox(aabb.first, aabb.second);
|
||||
}
|
||||
|
||||
if (aabbOut.min.x > aabbOut.max.x)
|
||||
return {};
|
||||
|
||||
zeus::CTransform xf = ConvertEditorEulerToTransform4f(scale, orientation, location);
|
||||
return aabbOut.getTransformedAABox(xf);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,13 @@ struct DamageableTrigger : IScriptObject
|
||||
g_curSpec->flattenDependencies(texture2, pathsOut);
|
||||
g_curSpec->flattenDependencies(texture3, pathsOut);
|
||||
}
|
||||
|
||||
zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const
|
||||
{
|
||||
zeus::CVector3f halfExtent = zeus::CVector3f(volume) / 2.f;
|
||||
zeus::CVector3f loc(location);
|
||||
return zeus::CAABox(loc - halfExtent, loc + halfExtent);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ struct DoorArea : IScriptObject
|
||||
AnimationParameters animationParameters;
|
||||
ActorParameters actorParameters;
|
||||
Value<atVec3f> unknown1;
|
||||
Value<atVec3f> unknown2;
|
||||
Value<atVec3f> unknown3;
|
||||
Value<atVec3f> collisionExtent;
|
||||
Value<atVec3f> collisionOffset;
|
||||
Value<bool> unknown4;
|
||||
Value<bool> unknown5;
|
||||
Value<bool> unknown6;
|
||||
@@ -49,6 +49,28 @@ struct DoorArea : IScriptObject
|
||||
{
|
||||
actorParameters.scanIDs(scansOut);
|
||||
}
|
||||
|
||||
zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const
|
||||
{
|
||||
hecl::BlenderConnection& conn = btok.getBlenderConnection();
|
||||
zeus::CAABox aabbOut;
|
||||
|
||||
if (animationParameters.animationCharacterSet)
|
||||
{
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(
|
||||
animationParameters.animationCharacterSet);
|
||||
conn.openBlend(path.getWithExtension(_S(".blend"), true));
|
||||
hecl::BlenderConnection::DataStream ds = conn.beginData();
|
||||
auto aabb = ds.getMeshAABB();
|
||||
aabbOut = zeus::CAABox(aabb.first, aabb.second);
|
||||
}
|
||||
|
||||
if (aabbOut.min.x > aabbOut.max.x)
|
||||
return {};
|
||||
|
||||
zeus::CTransform xf = ConvertEditorEulerToTransform4f(scale, orientation, location);
|
||||
return aabbOut.getTransformedAABox(xf);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,5 +267,16 @@ const std::vector<const struct ScriptObjectSpec*> SCRIPT_OBJECT_DB =
|
||||
&priv::WorldTeleporterx62Ent,
|
||||
};
|
||||
|
||||
zeus::CTransform ConvertEditorEulerToTransform4f(const zeus::CVector3f& scale,
|
||||
const zeus::CVector3f& orientation,
|
||||
const zeus::CVector3f& position)
|
||||
{
|
||||
return zeus::CTransform::RotateZ(zeus::degToRad(orientation.z)) *
|
||||
zeus::CTransform::RotateY(zeus::degToRad(orientation.y)) *
|
||||
zeus::CTransform::RotateX(zeus::degToRad(orientation.x)) *
|
||||
zeus::CTransform::Scale(scale) +
|
||||
position;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,18 @@
|
||||
#include "../../DNACommon/DNACommon.hpp"
|
||||
#include "../DNAMP1.hpp"
|
||||
#include "../SAVW.hpp"
|
||||
#include "zeus/CAABox.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace DataSpec
|
||||
{
|
||||
namespace DNAMP1
|
||||
{
|
||||
|
||||
zeus::CTransform ConvertEditorEulerToTransform4f(const zeus::CVector3f& scale,
|
||||
const zeus::CVector3f& orientation,
|
||||
const zeus::CVector3f& position);
|
||||
|
||||
struct IScriptObject : BigYAML
|
||||
{
|
||||
DECL_YAML
|
||||
@@ -32,6 +38,7 @@ struct IScriptObject : BigYAML
|
||||
virtual void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {}
|
||||
virtual void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const {}
|
||||
virtual void gatherScans(std::vector<Scan>& scansOut) const {}
|
||||
virtual zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const { return {}; }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,36 @@ struct Platform : IScriptObject
|
||||
{
|
||||
actorParameters.scanIDs(scansOut);
|
||||
}
|
||||
|
||||
zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const
|
||||
{
|
||||
hecl::BlenderConnection& conn = btok.getBlenderConnection();
|
||||
zeus::CAABox aabbOut;
|
||||
|
||||
if (model)
|
||||
{
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(model);
|
||||
conn.openBlend(path);
|
||||
hecl::BlenderConnection::DataStream ds = conn.beginData();
|
||||
auto aabb = ds.getMeshAABB();
|
||||
aabbOut = zeus::CAABox(aabb.first, aabb.second);
|
||||
}
|
||||
else if (animationParameters.animationCharacterSet)
|
||||
{
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(
|
||||
animationParameters.animationCharacterSet);
|
||||
conn.openBlend(path.getWithExtension(_S(".blend"), true));
|
||||
hecl::BlenderConnection::DataStream ds = conn.beginData();
|
||||
auto aabb = ds.getMeshAABB();
|
||||
aabbOut = zeus::CAABox(aabb.first, aabb.second);
|
||||
}
|
||||
|
||||
if (aabbOut.min.x > aabbOut.max.x)
|
||||
return {};
|
||||
|
||||
zeus::CTransform xf = ConvertEditorEulerToTransform4f(scale, orientation, location);
|
||||
return aabbOut.getTransformedAABox(xf);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,13 @@ struct Trigger : IScriptObject
|
||||
Value<bool> active;
|
||||
Value<bool> unknown2;
|
||||
Value<bool> unknown3;
|
||||
|
||||
zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const
|
||||
{
|
||||
zeus::CVector3f halfExtent = zeus::CVector3f(volume) / 2.f;
|
||||
zeus::CVector3f loc(location);
|
||||
return zeus::CAABox(loc - halfExtent, loc + halfExtent);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +173,13 @@ struct Water : IScriptObject
|
||||
g_curSpec->flattenDependencies(particle4, pathsOut);
|
||||
g_curSpec->flattenDependencies(particle5, pathsOut);
|
||||
}
|
||||
|
||||
zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const
|
||||
{
|
||||
zeus::CVector3f halfExtent = zeus::CVector3f(volume) / 2.f;
|
||||
zeus::CVector3f loc(location);
|
||||
return zeus::CAABox(loc - halfExtent, loc + halfExtent);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user