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)
add_subdirectory(DataSpec)
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_
#define _DNACOMMON_ANCS_HPP_
#include <unordered_set>
#include "DNACommon.hpp"
#include "BlenderConnection.hpp"
#include "CMDL.hpp"
@ -28,7 +29,7 @@ bool ReadANCSToBlender(HECL::BlenderConnection& conn,
const HECL::ProjectPath& masterShader,
bool force=false)
{
/* Extract characters first */
/* Extract character CMDL/CSKR first */
std::vector<CharacterResInfo<typename PAKRouter::IDType>> chResInfo;
ancs.getCharacterResInfo(chResInfo);
for (const auto& info : chResInfo)
@ -40,12 +41,17 @@ bool ReadANCSToBlender(HECL::BlenderConnection& conn,
{
if (!conn.createBlend(cmdlPath.getAbsolutePath()))
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);
const typename PAKRouter::EntryType* cinfE = pakRouter.lookupEntry(info.cinf);
typename ANCSDNA::CSKRType cskr;
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();
}
@ -56,14 +62,76 @@ bool ReadANCSToBlender(HECL::BlenderConnection& conn,
return false;
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 */
std::unordered_set<typename PAKRouter::IDType> animResInfo;
std::map<atUint32, std::pair<std::string, typename PAKRouter::IDType>> animResInfo;
ancs.getAnimationResInfo(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;
}

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,
Athena::io::IStreamReader& reader,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
const HECL::ProjectPath& masterShader)
const HECL::ProjectPath& masterShader,
const RIGPAIR* rp=nullptr)
{
reader.setEndian(Athena::BigEndian);
@ -401,6 +402,9 @@ bool ReadCMDLToBlender(HECL::BlenderConnection& conn,
"bm = bmesh.new()\n"
"\n", pakRouter.getBestEntryName(entry).c_str());
if (rp)
os << "dvert_lay = bm.verts.layers.deform.verify()\n";
/* Link master shader library */
os.format("# Master shader library\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)
{
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]);
if (rp)
rp->first->weightVertex(os, *rp->second, i);
}
break;
}
@ -817,6 +823,9 @@ bool ReadCMDLToBlender(HECL::BlenderConnection& conn,
"bm.free()\n"
"\n", head.matSetCount);
if (rp)
rp->second->sendVertexGroupsToBlender(os);
return true;
}

View File

@ -571,6 +571,21 @@ public:
*nodeOut = 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 */

View File

@ -1,11 +1,14 @@
#ifndef _DNAMP1_ANCS_HPP_
#define _DNAMP1_ANCS_HPP_
#include <unordered_set>
#include <map>
#include "../DNACommon/DNACommon.hpp"
#include "../DNACommon/ANCS.hpp"
#include "CMDLMaterials.hpp"
#include "BlenderConnection.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
#include "ANIM.hpp"
namespace Retro
{
@ -14,6 +17,10 @@ namespace DNAMP1
struct ANCS : BigYAML
{
using CINFType = CINF;
using CSKRType = CSKR;
using ANIMType = ANIM;
DECL_YAML
Value<atUint16> version;
@ -163,7 +170,7 @@ struct ANCS : BigYAML
const char* m_typeStr;
IMetaAnim(Type type, const char* 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
{
@ -181,9 +188,9 @@ struct ANCS : BigYAML
Value<float> unk1;
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
@ -195,7 +202,7 @@ struct ANCS : BigYAML
Value<float> unkFloat;
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);
animB.m_anim->gatherPrimitives(out);
@ -210,7 +217,7 @@ struct ANCS : BigYAML
Value<float> unkFloat;
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);
animB.m_anim->gatherPrimitives(out);
@ -229,7 +236,7 @@ struct ANCS : BigYAML
};
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)
child.anim.m_anim->gatherPrimitives(out);
@ -242,7 +249,7 @@ struct ANCS : BigYAML
Value<atUint32> animCount;
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)
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();
for (const AnimationSet::Animation& ai : animationSet.animations)

View File

@ -5,6 +5,72 @@ namespace Retro
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)
{
Header head;
@ -174,6 +240,7 @@ void ANIM::ANIM2::read(Athena::io::IStreamReader& reader)
times.push_back(timeAccum);
timeAccum += head.interval;
}
reader.seek(8);
bones.clear();
bones.reserve(head.boneChannelCount);
@ -256,6 +323,8 @@ void ANIM::ANIM2::write(Athena::io::IStreamWriter& writer) const
head.write(writer);
keyBmp.write(writer);
writer.writeUint32(head.boneChannelCount);
writer.writeUint32(head.boneChannelCount);
auto cit = qChannels.begin();
for (const std::pair<atUint32, bool>& bone : bones)
{

View File

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

View File

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

View File

@ -1,7 +1,9 @@
#ifndef _DNAMP1_CSKR_HPP_
#define _DNAMP1_CSKR_HPP_
#include "BlenderConnection.hpp"
#include "../DNACommon/DNACommon.hpp"
#include "CINF.hpp"
namespace Retro
{
@ -26,6 +28,20 @@ struct CSKR : BigDNA
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 && 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)
{
switch (entry.type.toUint32())
switch (entry.type)
{
case SBIG('STRG'):
return {STRG::Extract, nullptr, ".yaml"};
case SBIG('TXTR'):
return {TXTR::Extract, nullptr, ".png"};
case SBIG('CMDL'):
return {nullptr, CMDL::Extract, ".blend", 1};
return {nullptr, CMDL::Extract, ".blend", 2};
case SBIG('ANCS'):
return {nullptr, ANCS::Extract, nullptr};
return {nullptr, ANCS::Extract, nullptr, 1};
case SBIG('MLVL'):
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 "CMDLMaterials.hpp"
#include "DNAMP2.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
namespace Retro
{
@ -23,7 +25,7 @@ struct CMDL
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
if (!conn.createBlend(outPath.getAbsolutePath()))
return false;
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, 4>
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, std::pair<CSKR*,CINF*>, 4>
(conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath());
return conn.saveBlend();
}

View File

@ -1,6 +1,8 @@
make_dnalist(liblist
MLVL
CMDLMaterials)
CMDLMaterials
CINF
CSKR)
add_library(DNAMP2
DNAMP2.hpp DNAMP2.cpp
${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)
{
switch (entry.type.toUint32())
switch (entry.type)
{
case SBIG('STRG'):
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 "CMDLMaterials.hpp"
#include "DNAMP3.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
namespace Retro
{
@ -23,7 +25,7 @@ struct CMDL
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
if (!conn.createBlend(outPath.getAbsolutePath()))
return false;
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, 5>
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, std::pair<CSKR*,CINF*>, 5>
(conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath());
return conn.saveBlend();
}

View File

@ -1,7 +1,9 @@
make_dnalist(liblist
PAK
MLVL
CMDLMaterials)
CMDLMaterials
CINF
CSKR)
add_library(DNAMP3
DNAMP3.hpp DNAMP3.cpp
${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)
{
switch (entry.type.toUint32())
switch (entry.type)
{
case SBIG('STRG'):
return {STRG::Extract, nullptr, ".yaml"};