CINF/CSKR integration

This commit is contained in:
Jack Andersen 2015-08-12 21:29:00 -10:00
parent cdd7b45394
commit fd550702e1
21 changed files with 604 additions and 36 deletions

View File

@ -7,8 +7,3 @@ include_directories(${ATHENA_INCLUDE_DIR} ${LOG_VISOR_INCLUDE_DIR} ${ANGELSCRIPT
set(NOD_LIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/NODLib/include) set(NOD_LIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/NODLib/include)
add_subdirectory(DataSpec) add_subdirectory(DataSpec)
add_subdirectory(Runtime) add_subdirectory(Runtime)
include_directories(include)
add_library(RetroCommon
src/RetroCommon.cpp include/RetroCommon.hpp
src/MREADecompress.cpp)

View File

@ -1,6 +1,7 @@
#ifndef _DNACOMMON_ANCS_HPP_ #ifndef _DNACOMMON_ANCS_HPP_
#define _DNACOMMON_ANCS_HPP_ #define _DNACOMMON_ANCS_HPP_
#include <unordered_set>
#include "DNACommon.hpp" #include "DNACommon.hpp"
#include "BlenderConnection.hpp" #include "BlenderConnection.hpp"
#include "CMDL.hpp" #include "CMDL.hpp"
@ -28,7 +29,7 @@ bool ReadANCSToBlender(HECL::BlenderConnection& conn,
const HECL::ProjectPath& masterShader, const HECL::ProjectPath& masterShader,
bool force=false) bool force=false)
{ {
/* Extract characters first */ /* Extract character CMDL/CSKR first */
std::vector<CharacterResInfo<typename PAKRouter::IDType>> chResInfo; std::vector<CharacterResInfo<typename PAKRouter::IDType>> chResInfo;
ancs.getCharacterResInfo(chResInfo); ancs.getCharacterResInfo(chResInfo);
for (const auto& info : chResInfo) for (const auto& info : chResInfo)
@ -40,12 +41,17 @@ bool ReadANCSToBlender(HECL::BlenderConnection& conn,
{ {
if (!conn.createBlend(cmdlPath.getAbsolutePath())) if (!conn.createBlend(cmdlPath.getAbsolutePath()))
return false; return false;
PAKEntryReadStream rs = cmdlE->beginReadStream(*node);
DNACMDL::ReadCMDLToBlender<PAKRouter, MaterialSet, CMDLVersion>
(conn, rs, pakRouter, entry, masterShader);
const typename PAKRouter::EntryType* cskrE = pakRouter.lookupEntry(info.cskr); typename ANCSDNA::CSKRType cskr;
const typename PAKRouter::EntryType* cinfE = pakRouter.lookupEntry(info.cinf); pakRouter.lookupAndReadDNA(info.cskr, cskr);
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(info.cinf, cinf);
using RIGPair = std::pair<typename ANCSDNA::CSKRType*, typename ANCSDNA::CINFType*>;
RIGPair rigPair(&cskr, &cinf);
PAKEntryReadStream rs = cmdlE->beginReadStream(*node);
DNACMDL::ReadCMDLToBlender<PAKRouter, MaterialSet, RIGPair, CMDLVersion>
(conn, rs, pakRouter, *cmdlE, masterShader, &rigPair);
conn.saveBlend(); conn.saveBlend();
} }
@ -56,14 +62,76 @@ bool ReadANCSToBlender(HECL::BlenderConnection& conn,
return false; return false;
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
os.format("import bpy\n"
"from mathutils import Vector\n"
"bpy.context.scene.name = '%s'\n"
"bpy.context.scene.hecl_type = 'ACTOR'\n"
"bpy.context.scene.hecl_mesh_obj = bpy.context.scene.name\n"
"\n"
"# Using 'Blender Game'\n"
"bpy.context.scene.render.engine = 'BLENDER_GAME'\n"
"\n"
"# Clear Scene\n"
"for ob in bpy.data.objects:\n"
" if ob.type != 'LAMP':\n"
" bpy.context.scene.objects.unlink(ob)\n"
" bpy.data.objects.remove(ob)\n"
"\n"
"actor_data = bpy.context.scene.hecl_sact_data\n",
pakRouter.getBestEntryName(entry).c_str());
typename ANCSDNA::CINFType cinf;
std::unordered_set<typename PAKRouter::IDType> cinfsDone;
for (const auto& info : chResInfo)
{
/* Build CINF if needed */
if (cinfsDone.find(info.cinf) == cinfsDone.end())
{
pakRouter.lookupAndReadDNA(info.cinf, cinf);
cinf.sendCINFToBlender(os, info.cinf);
cinfsDone.insert(info.cinf);
}
else
os.format("arm_obj = bpy.data.objects['CINF_%08X']\n", info.cinf.toUint32());
/* Link CMDL */
const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(info.cmdl);
HECL::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkBlend(cmdlPath.getAbsolutePath(), pakRouter.getBestEntryName(*cmdlE), true);
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"\n";
/* Provide data to add-on */
os.format("actor_subtype = actor_data.subtypes.add()\n"
"actor_subtype.name = '%s'\n"
"actor_subtype.linked_armature = arm_obj.name\n"
"actor_subtype.linked_mesh = obj.name\n\n",
info.name.c_str());
}
/* Get animation primitives */ /* Get animation primitives */
std::unordered_set<typename PAKRouter::IDType> animResInfo; std::map<atUint32, std::pair<std::string, typename PAKRouter::IDType>> animResInfo;
ancs.getAnimationResInfo(animResInfo); ancs.getAnimationResInfo(animResInfo);
for (const auto& id : animResInfo) for (const auto& id : animResInfo)
{ {
const typename PAKRouter::EntryType* animE = pakRouter.lookupEntry(id); typename ANCSDNA::ANIMType anim;
pakRouter.lookupAndReadDNA(id.second.second, anim);
os.format("act = bpy.data.actions.new('%s')\n"
"act.use_fake_user = True\n", id.second.first.c_str());
anim.sendANIMToBlender(os, cinf);
os.format("actor_action = actor_data.actions.add()\n"
"actor_action.name = '%s'\n", id.second.first.c_str());
} }
os.close();
conn.saveBlend();
return true; return true;
} }

View File

@ -293,12 +293,13 @@ public:
} }
}; };
template <class PAKRouter, class MaterialSet, atUint32 Version> template <class PAKRouter, class MaterialSet, class RIGPAIR, atUint32 Version>
bool ReadCMDLToBlender(HECL::BlenderConnection& conn, bool ReadCMDLToBlender(HECL::BlenderConnection& conn,
Athena::io::IStreamReader& reader, Athena::io::IStreamReader& reader,
PAKRouter& pakRouter, PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry, const typename PAKRouter::EntryType& entry,
const HECL::ProjectPath& masterShader) const HECL::ProjectPath& masterShader,
const RIGPAIR* rp=nullptr)
{ {
reader.setEndian(Athena::BigEndian); reader.setEndian(Athena::BigEndian);
@ -401,6 +402,9 @@ bool ReadCMDLToBlender(HECL::BlenderConnection& conn,
"bm = bmesh.new()\n" "bm = bmesh.new()\n"
"\n", pakRouter.getBestEntryName(entry).c_str()); "\n", pakRouter.getBestEntryName(entry).c_str());
if (rp)
os << "dvert_lay = bm.verts.layers.deform.verify()\n";
/* Link master shader library */ /* Link master shader library */
os.format("# Master shader library\n" os.format("# Master shader library\n"
"with bpy.data.libraries.load('%s', link=True, relative=True) as (data_from, data_to):\n" "with bpy.data.libraries.load('%s', link=True, relative=True) as (data_from, data_to):\n"
@ -520,8 +524,10 @@ bool ReadCMDLToBlender(HECL::BlenderConnection& conn,
for (size_t i=0 ; i<=maxIdxs.pos ; ++i) for (size_t i=0 ; i<=maxIdxs.pos ; ++i)
{ {
atVec3f pos = reader.readVec3f(); atVec3f pos = reader.readVec3f();
os.format("bm.verts.new((%f,%f,%f))\n", os.format("vert = bm.verts.new((%f,%f,%f))\n",
pos.vec[0], pos.vec[1], pos.vec[2]); pos.vec[0], pos.vec[1], pos.vec[2]);
if (rp)
rp->first->weightVertex(os, *rp->second, i);
} }
break; break;
} }
@ -817,6 +823,9 @@ bool ReadCMDLToBlender(HECL::BlenderConnection& conn,
"bm.free()\n" "bm.free()\n"
"\n", head.matSetCount); "\n", head.matSetCount);
if (rp)
rp->second->sendVertexGroupsToBlender(os);
return true; return true;
} }

View File

@ -571,6 +571,21 @@ public:
*nodeOut = nullptr; *nodeOut = nullptr;
return nullptr; return nullptr;
} }
template <typename DNA>
bool lookupAndReadDNA(const typename BRIDGETYPE::PAKType::IDType& id, DNA& out)
{
const NOD::DiscBase::IPartition::Node* node;
const typename BRIDGETYPE::PAKType::Entry* entry = lookupEntry(id, &node);
if (!entry)
{
LogDNACommon.report(LogVisor::Error, "unable to find PAK entry %s", id.toString().c_str());
return false;
}
PAKEntryReadStream rs = entry->beginReadStream(*node);
out.read(rs);
return true;
}
}; };
/* Resource cooker function */ /* Resource cooker function */

View File

@ -1,11 +1,14 @@
#ifndef _DNAMP1_ANCS_HPP_ #ifndef _DNAMP1_ANCS_HPP_
#define _DNAMP1_ANCS_HPP_ #define _DNAMP1_ANCS_HPP_
#include <unordered_set> #include <map>
#include "../DNACommon/DNACommon.hpp" #include "../DNACommon/DNACommon.hpp"
#include "../DNACommon/ANCS.hpp" #include "../DNACommon/ANCS.hpp"
#include "CMDLMaterials.hpp" #include "CMDLMaterials.hpp"
#include "BlenderConnection.hpp" #include "BlenderConnection.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
#include "ANIM.hpp"
namespace Retro namespace Retro
{ {
@ -14,6 +17,10 @@ namespace DNAMP1
struct ANCS : BigYAML struct ANCS : BigYAML
{ {
using CINFType = CINF;
using CSKRType = CSKR;
using ANIMType = ANIM;
DECL_YAML DECL_YAML
Value<atUint16> version; Value<atUint16> version;
@ -163,7 +170,7 @@ struct ANCS : BigYAML
const char* m_typeStr; const char* m_typeStr;
IMetaAnim(Type type, const char* typeStr) IMetaAnim(Type type, const char* typeStr)
: m_type(type), m_typeStr(typeStr) {} : m_type(type), m_typeStr(typeStr) {}
virtual void gatherPrimitives(std::unordered_set<UniqueID32>& out)=0; virtual void gatherPrimitives(std::map<atUint32, std::pair<std::string, UniqueID32>>& out)=0;
}; };
struct MetaAnimFactory : BigYAML struct MetaAnimFactory : BigYAML
{ {
@ -181,9 +188,9 @@ struct ANCS : BigYAML
Value<float> unk1; Value<float> unk1;
Value<atUint32> unk2; Value<atUint32> unk2;
void gatherPrimitives(std::unordered_set<UniqueID32>& out) void gatherPrimitives(std::map<atUint32, std::pair<std::string, UniqueID32>>& out)
{ {
out.insert(animId); out[animIdx] = std::make_pair(animName, animId);
} }
}; };
struct MetaAnimBlend : IMetaAnim struct MetaAnimBlend : IMetaAnim
@ -195,7 +202,7 @@ struct ANCS : BigYAML
Value<float> unkFloat; Value<float> unkFloat;
Value<atUint8> unk; Value<atUint8> unk;
void gatherPrimitives(std::unordered_set<UniqueID32>& out) void gatherPrimitives(std::map<atUint32, std::pair<std::string, UniqueID32>>& out)
{ {
animA.m_anim->gatherPrimitives(out); animA.m_anim->gatherPrimitives(out);
animB.m_anim->gatherPrimitives(out); animB.m_anim->gatherPrimitives(out);
@ -210,7 +217,7 @@ struct ANCS : BigYAML
Value<float> unkFloat; Value<float> unkFloat;
Value<atUint8> unk; Value<atUint8> unk;
void gatherPrimitives(std::unordered_set<UniqueID32>& out) void gatherPrimitives(std::map<atUint32, std::pair<std::string, UniqueID32>>& out)
{ {
animA.m_anim->gatherPrimitives(out); animA.m_anim->gatherPrimitives(out);
animB.m_anim->gatherPrimitives(out); animB.m_anim->gatherPrimitives(out);
@ -229,7 +236,7 @@ struct ANCS : BigYAML
}; };
Vector<Child, DNA_COUNT(animCount)> children; Vector<Child, DNA_COUNT(animCount)> children;
void gatherPrimitives(std::unordered_set<UniqueID32>& out) void gatherPrimitives(std::map<atUint32, std::pair<std::string, UniqueID32>>& out)
{ {
for (const auto& child : children) for (const auto& child : children)
child.anim.m_anim->gatherPrimitives(out); child.anim.m_anim->gatherPrimitives(out);
@ -242,7 +249,7 @@ struct ANCS : BigYAML
Value<atUint32> animCount; Value<atUint32> animCount;
Vector<MetaAnimFactory, DNA_COUNT(animCount)> children; Vector<MetaAnimFactory, DNA_COUNT(animCount)> children;
void gatherPrimitives(std::unordered_set<UniqueID32>& out) void gatherPrimitives(std::map<atUint32, std::pair<std::string, UniqueID32>>& out)
{ {
for (const auto& child : children) for (const auto& child : children)
child.m_anim->gatherPrimitives(out); child.m_anim->gatherPrimitives(out);
@ -359,7 +366,7 @@ struct ANCS : BigYAML
} }
} }
void getAnimationResInfo(std::unordered_set<UniqueID32>& out) const void getAnimationResInfo(std::map<atUint32, std::pair<std::string, UniqueID32>>& out) const
{ {
out.clear(); out.clear();
for (const AnimationSet::Animation& ai : animationSet.animations) for (const AnimationSet::Animation& ai : animationSet.animations)

View File

@ -5,6 +5,72 @@ namespace Retro
namespace DNAMP1 namespace DNAMP1
{ {
void ANIM::IANIM::sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const
{
os.format("bone_trans_heads = []\n"
"act.hecl_fps = round(%f)\n", (1.0f / mainInterval));
auto kit = chanKeys.begin();
for (const std::pair<atUint32, bool>& bone : bones)
{
os.format("bone_string = '%s'\n", cinf.getBoneNameFromId(bone.first)->c_str());
os << "action_group = act.groups.new(bone_string)\n"
"\n"
"crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=0, action_group=bone_string)\n"
"crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=1, action_group=bone_string)\n"
"crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=2, action_group=bone_string)\n"
"crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=3, action_group=bone_string)\n"
"\n";
if (bone.second)
os << "bone_parent_head = (0.0,0.0,0.0)\n"
"if arm_obj.data.bones[bone_string].parent is not None:\n"
" bone_parent_head = Vector(arm_obj.data.bones[bone_string].head_local) - Vector(arm_obj.data.bones[bone_string].parent.head_local)\n"
"bone_trans_heads.append(bone_parent_head)\n"
"crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=0, action_group=bone_string)\n"
"crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=1, action_group=bone_string)\n"
"crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=2, action_group=bone_string)\n"
"\n";
else
os << "bone_trans_heads.append((0,0,0))\n";
os << "crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_mode', action_group=bone_string)\n"
"crv.keyframe_points.add()\n"
"crv.keyframe_points[-1].co = (0, 0)\n"
"crv.keyframe_points[-1].interpolation = 'LINEAR'\n"
"\n";
const std::vector<DNAANIM::Value>& rotKeys = *kit++;
auto timeit = times.begin();
for (const DNAANIM::Value& val : rotKeys)
{
float time = *timeit++;
for (int c=0 ; c<4 ; ++c)
os.format("crv = act.fcurves[%d]\n"
"crv.keyframe_points.add()\n"
"crv.keyframe_points[-1].interpolation = 'LINEAR'\n"
"crv.keyframe_points[-1].co = (%f, %f)\n",
c, time, val.v4.vec[c]);
}
if (bone.second)
{
const std::vector<DNAANIM::Value>& transKeys = *kit++;
auto timeit = times.begin();
for (const DNAANIM::Value& val : transKeys)
{
float time = *timeit++;
for (int c=0 ; c<3 ; ++c)
os.format("crv = act.fcurves[%d+4]\n"
"crv.keyframe_points.add()\n"
"crv.keyframe_points[-1].interpolation = 'LINEAR'\n"
"crv.keyframe_points[-1].co = (%f, %f)\n",
c, time, val.v4.vec[c]);
}
}
}
}
void ANIM::ANIM0::read(Athena::io::IStreamReader& reader) void ANIM::ANIM0::read(Athena::io::IStreamReader& reader)
{ {
Header head; Header head;
@ -174,6 +240,7 @@ void ANIM::ANIM2::read(Athena::io::IStreamReader& reader)
times.push_back(timeAccum); times.push_back(timeAccum);
timeAccum += head.interval; timeAccum += head.interval;
} }
reader.seek(8);
bones.clear(); bones.clear();
bones.reserve(head.boneChannelCount); bones.reserve(head.boneChannelCount);
@ -256,6 +323,8 @@ void ANIM::ANIM2::write(Athena::io::IStreamWriter& writer) const
head.write(writer); head.write(writer);
keyBmp.write(writer); keyBmp.write(writer);
writer.writeUint32(head.boneChannelCount);
writer.writeUint32(head.boneChannelCount);
auto cit = qChannels.begin(); auto cit = qChannels.begin();
for (const std::pair<atUint32, bool>& bone : bones) for (const std::pair<atUint32, bool>& bone : bones)
{ {

View File

@ -1,8 +1,10 @@
#ifndef _DNAMP1_ANIM_HPP_ #ifndef _DNAMP1_ANIM_HPP_
#define _DNAMP1_ANIM_HPP_ #define _DNAMP1_ANIM_HPP_
#include "BlenderConnection.hpp"
#include "DNAMP1.hpp" #include "DNAMP1.hpp"
#include "../DNACommon/ANIM.hpp" #include "../DNACommon/ANIM.hpp"
#include "CINF.hpp"
namespace Retro namespace Retro
{ {
@ -25,6 +27,8 @@ struct ANIM : BigDNA
std::vector<std::vector<DNAANIM::Value>> chanKeys; std::vector<std::vector<DNAANIM::Value>> chanKeys;
float mainInterval = 0.0; float mainInterval = 0.0;
UniqueID32 evnt; UniqueID32 evnt;
void sendANIMToBlender(HECL::BlenderConnection::PyOutStream&, const CINF&) const;
}; };
struct ANIM0 : IANIM struct ANIM0 : IANIM
@ -134,6 +138,7 @@ struct ANIM : BigDNA
std::unique_ptr<IANIM> m_anim; std::unique_ptr<IANIM> m_anim;
void read(Athena::io::IStreamReader& reader) void read(Athena::io::IStreamReader& reader)
{ {
reader.setEndian(Athena::BigEndian);
atUint32 version = reader.readUint32(); atUint32 version = reader.readUint32();
switch (version) switch (version)
{ {
@ -153,9 +158,16 @@ struct ANIM : BigDNA
void write(Athena::io::IStreamWriter& writer) const void write(Athena::io::IStreamWriter& writer) const
{ {
writer.setEndian(Athena::BigEndian);
writer.writeUint32(m_anim->m_version); writer.writeUint32(m_anim->m_version);
m_anim->write(writer); m_anim->write(writer);
} }
void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const
{
m_anim->sendANIMToBlender(os, cinf);
}
}; };
} }

View File

@ -1,6 +1,7 @@
#ifndef _DNAMP1_CINF_HPP_ #ifndef _DNAMP1_CINF_HPP_
#define _DNAMP1_CINF_HPP_ #define _DNAMP1_CINF_HPP_
#include "BlenderConnection.hpp"
#include "../DNACommon/DNACommon.hpp" #include "../DNACommon/DNACommon.hpp"
namespace Retro namespace Retro
@ -34,6 +35,66 @@ struct CINF : BigDNA
Value<atUint32> boneId; Value<atUint32> boneId;
}; };
Vector<Name, DNA_COUNT(nameCount)> names; Vector<Name, DNA_COUNT(nameCount)> names;
atUint32 getBoneIdxFromId(atUint32 id) const
{
atUint32 idx = 0;
for (atUint32 bid : boneIds)
{
if (bid == id)
return idx;
++idx;
}
return 0;
}
const std::string* getBoneNameFromId(atUint32 id) const
{
for (const Name& name : names)
if (id == name.boneId)
return &name.name;
return nullptr;
}
void sendVertexGroupsToBlender(HECL::BlenderConnection::PyOutStream& os) const
{
for (atUint32 bid : boneIds)
{
for (const Name& name : names)
{
if (name.boneId == bid)
{
os.format("obj.vertex_groups.new('%s')\n", name.name.c_str());
break;
}
}
}
}
void sendCINFToBlender(HECL::BlenderConnection::PyOutStream& os, const UniqueID32& cinfId) const
{
os.format("arm = bpy.data.armatures.new('CINF_%08X')\n"
"arm_obj = bpy.data.objects.new(arm.name, arm)\n"
"bpy.context.scene.objects.link(arm_obj)\n"
"bpy.context.scene.objects.active = arm_obj\n"
"bpy.ops.object.mode_set(mode='EDIT')\n"
"arm_bone_table = {}\n",
cinfId.toUint32());
for (const Bone& bone : bones)
os.format("bone = arm.edit_bones.new('%s')\n"
"bone.head = (%f,%f,%f)\n"
"bone.tail = bone.head\n"
"bone.tail[1] += 0.5\n"
"arm_bone_table[%u] = bone\n", getBoneNameFromId(bone.id)->c_str(),
bone.origin.vec[0], bone.origin.vec[1], bone.origin.vec[2], bone.id);
for (const Bone& bone : bones)
if (bone.parentId != 2)
os.format("arm_bone_table[%u].parent = arm_bone_table[%u]\n", bone.id, bone.parentId);
os << "bpy.ops.object.mode_set(mode='OBJECT')\n";
}
}; };
} }

View File

@ -5,6 +5,8 @@
#include "../DNACommon/CMDL.hpp" #include "../DNACommon/CMDL.hpp"
#include "CMDLMaterials.hpp" #include "CMDLMaterials.hpp"
#include "DNAMP1.hpp" #include "DNAMP1.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
namespace Retro namespace Retro
{ {
@ -23,7 +25,7 @@ struct CMDL
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
if (!conn.createBlend(outPath.getAbsolutePath())) if (!conn.createBlend(outPath.getAbsolutePath()))
return false; return false;
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, 2> DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, std::pair<CSKR*,CINF*>, 2>
(conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath()); (conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath());
return conn.saveBlend(); return conn.saveBlend();
} }

View File

@ -1,7 +1,9 @@
#ifndef _DNAMP1_CSKR_HPP_ #ifndef _DNAMP1_CSKR_HPP_
#define _DNAMP1_CSKR_HPP_ #define _DNAMP1_CSKR_HPP_
#include "BlenderConnection.hpp"
#include "../DNACommon/DNACommon.hpp" #include "../DNACommon/DNACommon.hpp"
#include "CINF.hpp"
namespace Retro namespace Retro
{ {
@ -26,6 +28,20 @@ struct CSKR : BigDNA
Value<atUint32> vertCount; Value<atUint32> vertCount;
}; };
Vector<SkinningRule, DNA_COUNT(skinningRuleCount)> skinningRules; Vector<SkinningRule, DNA_COUNT(skinningRuleCount)> skinningRules;
void weightVertex(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf, atUint32 idx) const
{
atUint32 accum = 0;
for (const SkinningRule& rule : skinningRules)
{
if (idx >= accum && idx < accum + rule.vertCount)
for (const SkinningRule::Weight& weight : rule.weights)
os.format("vert[dvert_lay][%u] = %f\n",
cinf.getBoneIdxFromId(weight.boneId),
weight.weight);
accum += rule.vertCount;
}
}
}; };
} }

View File

@ -174,16 +174,16 @@ void PAKBridge::build()
ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const PAK::Entry& entry) ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const PAK::Entry& entry)
{ {
switch (entry.type.toUint32()) switch (entry.type)
{ {
case SBIG('STRG'): case SBIG('STRG'):
return {STRG::Extract, nullptr, ".yaml"}; return {STRG::Extract, nullptr, ".yaml"};
case SBIG('TXTR'): case SBIG('TXTR'):
return {TXTR::Extract, nullptr, ".png"}; return {TXTR::Extract, nullptr, ".png"};
case SBIG('CMDL'): case SBIG('CMDL'):
return {nullptr, CMDL::Extract, ".blend", 1}; return {nullptr, CMDL::Extract, ".blend", 2};
case SBIG('ANCS'): case SBIG('ANCS'):
return {nullptr, ANCS::Extract, nullptr}; return {nullptr, ANCS::Extract, nullptr, 1};
case SBIG('MLVL'): case SBIG('MLVL'):
return {MLVL::Extract, nullptr, ".yaml"}; return {MLVL::Extract, nullptr, ".yaml"};
} }

103
DataSpec/DNAMP2/CINF.hpp Normal file
View File

@ -0,0 +1,103 @@
#ifndef _DNAMP2_CINF_HPP_
#define _DNAMP2_CINF_HPP_
#include "BlenderConnection.hpp"
#include "../DNACommon/DNACommon.hpp"
namespace Retro
{
namespace DNAMP2
{
struct CINF : BigDNA
{
DECL_DNA
Value<atUint32> boneCount;
struct Bone : BigDNA
{
DECL_DNA
Value<atUint32> id;
Value<atUint32> parentId;
Value<atVec3f> origin;
Value<atUint32> linkedCount;
Vector<atUint32, DNA_COUNT(linkedCount)> linked;
};
Vector<Bone, DNA_COUNT(boneCount)> bones;
Value<atUint32> boneIdCount;
Vector<atUint32, DNA_COUNT(boneIdCount)> boneIds;
Value<atUint32> nameCount;
struct Name : BigDNA
{
DECL_DNA
String<-1> name;
Value<atUint32> boneId;
};
Vector<Name, DNA_COUNT(nameCount)> names;
atUint32 getBoneIdxFromId(atUint32 id) const
{
atUint32 idx = 0;
for (atUint32 bid : boneIds)
{
if (bid == id)
return idx;
++idx;
}
return 0;
}
const std::string* getBoneNameFromId(atUint32 id) const
{
for (const Name& name : names)
if (id == name.boneId)
return &name.name;
return nullptr;
}
void sendVertexGroupsToBlender(HECL::BlenderConnection::PyOutStream& os) const
{
for (atUint32 bid : boneIds)
{
for (const Name& name : names)
{
if (name.boneId == bid)
{
os.format("obj.vertex_groups.new('%s')\n", name.name.c_str());
break;
}
}
}
}
void sendCINFToBlender(HECL::BlenderConnection::PyOutStream& os, const UniqueID32& cinfId) const
{
os.format("arm = bpy.data.armatures.new('CINF_%08X')\n"
"arm_obj = bpy.data.objects.new(arm.name, arm)\n"
"bpy.context.scene.objects.link(arm_obj)\n"
"bpy.context.scene.objects.active = arm_obj\n"
"bpy.ops.object.mode_set(mode='EDIT')\n"
"arm_bone_table = {}\n",
cinfId.toUint32());
for (const Bone& bone : bones)
os.format("bone = arm.edit_bones.new('%s')\n"
"bone.head = (%f,%f,%f)\n"
"bone.tail = bone.head\n"
"bone.tail[1] += 0.5\n"
"arm_bone_table[%u] = bone\n", getBoneNameFromId(bone.id)->c_str(),
bone.origin.vec[0], bone.origin.vec[1], bone.origin.vec[2], bone.id);
for (const Bone& bone : bones)
if (bone.parentId != 2)
os.format("arm_bone_table[%u].parent = arm_bone_table[%u]\n", bone.id, bone.parentId);
os << "bpy.ops.object.mode_set(mode='OBJECT')\n";
}
};
}
}
#endif // _DNAMP2_CINF_HPP_

View File

@ -5,6 +5,8 @@
#include "../DNACommon/CMDL.hpp" #include "../DNACommon/CMDL.hpp"
#include "CMDLMaterials.hpp" #include "CMDLMaterials.hpp"
#include "DNAMP2.hpp" #include "DNAMP2.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
namespace Retro namespace Retro
{ {
@ -23,7 +25,7 @@ struct CMDL
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
if (!conn.createBlend(outPath.getAbsolutePath())) if (!conn.createBlend(outPath.getAbsolutePath()))
return false; return false;
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, 4> DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, std::pair<CSKR*,CINF*>, 4>
(conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath()); (conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath());
return conn.saveBlend(); return conn.saveBlend();
} }

View File

@ -1,6 +1,8 @@
make_dnalist(liblist make_dnalist(liblist
MLVL MLVL
CMDLMaterials) CMDLMaterials
CINF
CSKR)
add_library(DNAMP2 add_library(DNAMP2
DNAMP2.hpp DNAMP2.cpp DNAMP2.hpp DNAMP2.cpp
${liblist} ${liblist}

50
DataSpec/DNAMP2/CSKR.hpp Normal file
View File

@ -0,0 +1,50 @@
#ifndef _DNAMP2_CSKR_HPP_
#define _DNAMP2_CSKR_HPP_
#include "BlenderConnection.hpp"
#include "../DNACommon/DNACommon.hpp"
#include "CINF.hpp"
namespace Retro
{
namespace DNAMP2
{
struct CSKR : BigDNA
{
DECL_DNA
Value<atUint32> skinningRuleCount;
struct SkinningRule : BigDNA
{
DECL_DNA
Value<atUint32> weightCount;
struct Weight : BigDNA
{
DECL_DNA
Value<atUint32> boneId;
Value<float> weight;
};
Vector<Weight, DNA_COUNT(weightCount)> weights;
Value<atUint32> vertCount;
};
Vector<SkinningRule, DNA_COUNT(skinningRuleCount)> skinningRules;
void weightVertex(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf, atUint32 idx) const
{
atUint32 accum = 0;
for (const SkinningRule& rule : skinningRules)
{
if (idx < accum + rule.vertCount)
for (const SkinningRule::Weight& weight : rule.weights)
os.format("vert[dvert_lay][%u] = %f\n",
cinf.getBoneIdxFromId(weight.boneId),
weight.weight);
accum += rule.vertCount;
}
}
};
}
}
#endif // _DNAMP2_CSKR_HPP_

View File

@ -181,7 +181,7 @@ void PAKBridge::build()
ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const DNAMP1::PAK::Entry& entry) ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const DNAMP1::PAK::Entry& entry)
{ {
switch (entry.type.toUint32()) switch (entry.type)
{ {
case SBIG('STRG'): case SBIG('STRG'):
return {STRG::Extract, nullptr, ".yaml"}; return {STRG::Extract, nullptr, ".yaml"};

103
DataSpec/DNAMP3/CINF.hpp Normal file
View File

@ -0,0 +1,103 @@
#ifndef _DNAMP3_CINF_HPP_
#define _DNAMP3_CINF_HPP_
#include "BlenderConnection.hpp"
#include "../DNACommon/DNACommon.hpp"
namespace Retro
{
namespace DNAMP3
{
struct CINF : BigDNA
{
DECL_DNA
Value<atUint32> boneCount;
struct Bone : BigDNA
{
DECL_DNA
Value<atUint32> id;
Value<atUint32> parentId;
Value<atVec3f> origin;
Value<atUint32> linkedCount;
Vector<atUint32, DNA_COUNT(linkedCount)> linked;
};
Vector<Bone, DNA_COUNT(boneCount)> bones;
Value<atUint32> boneIdCount;
Vector<atUint32, DNA_COUNT(boneIdCount)> boneIds;
Value<atUint32> nameCount;
struct Name : BigDNA
{
DECL_DNA
String<-1> name;
Value<atUint32> boneId;
};
Vector<Name, DNA_COUNT(nameCount)> names;
atUint32 getBoneIdxFromId(atUint32 id) const
{
atUint32 idx = 0;
for (atUint32 bid : boneIds)
{
if (bid == id)
return idx;
++idx;
}
return 0;
}
const std::string* getBoneNameFromId(atUint32 id) const
{
for (const Name& name : names)
if (id == name.boneId)
return &name.name;
return nullptr;
}
void sendVertexGroupsToBlender(HECL::BlenderConnection::PyOutStream& os) const
{
for (atUint32 bid : boneIds)
{
for (const Name& name : names)
{
if (name.boneId == bid)
{
os.format("obj.vertex_groups.new('%s')\n", name.name.c_str());
break;
}
}
}
}
void sendCINFToBlender(HECL::BlenderConnection::PyOutStream& os, const UniqueID32& cinfId) const
{
os.format("arm = bpy.data.armatures.new('CINF_%08X')\n"
"arm_obj = bpy.data.objects.new(arm.name, arm)\n"
"bpy.context.scene.objects.link(arm_obj)\n"
"bpy.context.scene.objects.active = arm_obj\n"
"bpy.ops.object.mode_set(mode='EDIT')\n"
"arm_bone_table = {}\n",
cinfId.toUint32());
for (const Bone& bone : bones)
os.format("bone = arm.edit_bones.new('%s')\n"
"bone.head = (%f,%f,%f)\n"
"bone.tail = bone.head\n"
"bone.tail[1] += 0.5\n"
"arm_bone_table[%u] = bone\n", getBoneNameFromId(bone.id)->c_str(),
bone.origin.vec[0], bone.origin.vec[1], bone.origin.vec[2], bone.id);
for (const Bone& bone : bones)
if (bone.parentId != 2)
os.format("arm_bone_table[%u].parent = arm_bone_table[%u]\n", bone.id, bone.parentId);
os << "bpy.ops.object.mode_set(mode='OBJECT')\n";
}
};
}
}
#endif // _DNAMP3_CINF_HPP_

View File

@ -5,6 +5,8 @@
#include "../DNACommon/CMDL.hpp" #include "../DNACommon/CMDL.hpp"
#include "CMDLMaterials.hpp" #include "CMDLMaterials.hpp"
#include "DNAMP3.hpp" #include "DNAMP3.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
namespace Retro namespace Retro
{ {
@ -23,7 +25,7 @@ struct CMDL
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
if (!conn.createBlend(outPath.getAbsolutePath())) if (!conn.createBlend(outPath.getAbsolutePath()))
return false; return false;
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, 5> DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, std::pair<CSKR*,CINF*>, 5>
(conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath()); (conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath());
return conn.saveBlend(); return conn.saveBlend();
} }

View File

@ -1,7 +1,9 @@
make_dnalist(liblist make_dnalist(liblist
PAK PAK
MLVL MLVL
CMDLMaterials) CMDLMaterials
CINF
CSKR)
add_library(DNAMP3 add_library(DNAMP3
DNAMP3.hpp DNAMP3.cpp DNAMP3.hpp DNAMP3.cpp
${liblist} ${liblist}

50
DataSpec/DNAMP3/CSKR.hpp Normal file
View File

@ -0,0 +1,50 @@
#ifndef _DNAMP3_CSKR_HPP_
#define _DNAMP3_CSKR_HPP_
#include "BlenderConnection.hpp"
#include "../DNACommon/DNACommon.hpp"
#include "CINF.hpp"
namespace Retro
{
namespace DNAMP3
{
struct CSKR : BigDNA
{
DECL_DNA
Value<atUint32> skinningRuleCount;
struct SkinningRule : BigDNA
{
DECL_DNA
Value<atUint32> weightCount;
struct Weight : BigDNA
{
DECL_DNA
Value<atUint32> boneId;
Value<float> weight;
};
Vector<Weight, DNA_COUNT(weightCount)> weights;
Value<atUint32> vertCount;
};
Vector<SkinningRule, DNA_COUNT(skinningRuleCount)> skinningRules;
void weightVertex(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf, atUint32 idx) const
{
atUint32 accum = 0;
for (const SkinningRule& rule : skinningRules)
{
if (idx < accum + rule.vertCount)
for (const SkinningRule::Weight& weight : rule.weights)
os.format("vert[dvert_lay][%u] = %f\n",
cinf.getBoneIdxFromId(weight.boneId),
weight.weight);
accum += rule.vertCount;
}
}
};
}
}
#endif // _DNAMP3_CSKR_HPP_

View File

@ -55,7 +55,7 @@ void PAKBridge::build()
ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const PAK::Entry& entry) ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const PAK::Entry& entry)
{ {
switch (entry.type.toUint32()) switch (entry.type)
{ {
case SBIG('STRG'): case SBIG('STRG'):
return {STRG::Extract, nullptr, ".yaml"}; return {STRG::Extract, nullptr, ".yaml"};