2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-06-05 07:13:27 +00:00

Added HMDL outputting from blender intermediate

This commit is contained in:
Jack Andersen 2015-11-13 16:26:06 -10:00
parent 7c0206bd39
commit db335e5d98
8 changed files with 347 additions and 38 deletions

View File

@ -503,8 +503,8 @@ void BlenderConnection::PyOutStream::linkBackground(const char* target,
}
BlenderConnection::DataStream::Mesh::Mesh
(BlenderConnection& conn, OutputMode outMode, int skinSlotCount, SurfProgFunc& surfProg)
: outputMode(outMode), aabbMin(conn), aabbMax(conn)
(BlenderConnection& conn, HMDLTopology topologyIn, int skinSlotCount, SurfProgFunc& surfProg)
: topology(topologyIn), aabbMin(conn), aabbMax(conn)
{
uint32_t matSetCount;
conn._readBuf(&matSetCount, 4);
@ -587,12 +587,12 @@ BlenderConnection::DataStream::Mesh::Mesh
{
for (Surface& surf : surfaces)
{
std::vector<uint32_t>& bank = skinBanks.banks[surf.skinBankIdx];
SkinBanks::Bank& bank = skinBanks.banks[surf.skinBankIdx];
for (Surface::Vert& vert : surf.verts)
{
for (uint32_t i=0 ; i<bank.size() ; ++i)
for (uint32_t i=0 ; i<bank.m_skinIdxs.size() ; ++i)
{
if (bank[i] == vert.iSkin)
if (bank.m_skinIdxs[i] == vert.iSkin)
{
vert.iBankSkin = i;
break;
@ -706,7 +706,7 @@ BlenderConnection::DataStream::Mesh::Surface::Surface
}
if (parent.boneNames.size())
skinBankIdx = parent.skinBanks.addSurface(*this, skinSlotCount);
skinBankIdx = parent.skinBanks.addSurface(parent, *this, skinSlotCount);
}
BlenderConnection::DataStream::Mesh::Surface::Vert::Vert
@ -730,27 +730,27 @@ static bool VertInBank(const std::vector<uint32_t>& bank, uint32_t sIdx)
}
uint32_t BlenderConnection::DataStream::Mesh::SkinBanks::addSurface
(const Surface& surf, int skinSlotCount)
(const Mesh& mesh, const Surface& surf, int skinSlotCount)
{
if (banks.empty())
addSkinBank(skinSlotCount);
std::vector<uint32_t> toAdd;
if (skinSlotCount > 0)
toAdd.reserve(skinSlotCount);
std::vector<std::vector<uint32_t>>::iterator bankIt = banks.begin();
std::vector<Bank>::iterator bankIt = banks.begin();
for (;;)
{
bool done = true;
for (; bankIt != banks.end() ; ++bankIt)
{
std::vector<uint32_t>& bank = *bankIt;
Bank& bank = *bankIt;
done = true;
for (const Surface::Vert& v : surf.verts)
{
if (!VertInBank(bank, v.iSkin) && !VertInBank(toAdd, v.iSkin))
if (!VertInBank(bank.m_skinIdxs, v.iSkin) && !VertInBank(toAdd, v.iSkin))
{
toAdd.push_back(v.iSkin);
if (skinSlotCount > 0 && bank.size() + toAdd.size() > skinSlotCount)
if (skinSlotCount > 0 && bank.m_skinIdxs.size() + toAdd.size() > skinSlotCount)
{
toAdd.clear();
done = false;
@ -760,8 +760,7 @@ uint32_t BlenderConnection::DataStream::Mesh::SkinBanks::addSurface
}
if (toAdd.size())
{
for (uint32_t a : toAdd)
bank.push_back(a);
bank.addSkins(mesh, toAdd);
toAdd.clear();
}
if (done)

View File

@ -21,13 +21,16 @@
#include <unordered_map>
#include "HECL/HECL.hpp"
#include "HECL/HMDLMeta.hpp"
#include <Athena/Types.hpp>
#include <Athena/MemoryWriter.hpp>
namespace HECL
{
extern LogVisor::LogModule BlenderLog;
extern class BlenderConnection* SharedBlenderConnection;
class HMDLBuffers;
class BlenderConnection
{
@ -374,11 +377,7 @@ public:
/** Intermediate mesh representation prepared by blender from a single mesh object */
struct Mesh
{
enum OutputMode
{
OutputTriangles,
OutputTriStrips,
} outputMode;
enum HMDLTopology topology;
/* Cumulative AABB */
Vector3f aabbMin;
@ -436,6 +435,23 @@ public:
uint32_t iBankSkin = -1;
Vert(BlenderConnection& conn, const Mesh& parent);
bool operator==(const Vert& other) const
{
if (iPos != other.iPos)
return false;
if (iNorm != other.iNorm)
return false;
for (int i=0 ; i<4 ; ++i)
if (iColor[i] != other.iColor[i])
return false;
for (int i=0 ; i<8 ; ++i)
if (iUv[i] != other.iUv[i])
return false;
if (iSkin != other.iSkin)
return false;
return true;
}
};
std::vector<Vert> verts;
@ -445,33 +461,73 @@ public:
struct SkinBanks
{
std::vector<std::vector<uint32_t>> banks;
std::vector<std::vector<uint32_t>>::iterator addSkinBank(int skinSlotCount)
struct Bank
{
std::vector<uint32_t> m_skinIdxs;
std::vector<uint32_t> m_boneIdxs;
void addSkins(const Mesh& parent, const std::vector<uint32_t>& skinIdxs)
{
for (uint32_t sidx : skinIdxs)
{
m_skinIdxs.push_back(sidx);
for (const SkinBind& bind : parent.skins[sidx])
{
bool found = false;
for (uint32_t bidx : m_boneIdxs)
{
if (bidx == bind.boneIdx)
{
found = true;
break;
}
}
if (!found)
m_boneIdxs.push_back(bind.boneIdx);
}
}
}
size_t lookupLocalBoneIdx(uint32_t boneIdx) const
{
for (size_t i=0 ; i<m_boneIdxs.size() ; ++i)
if (m_boneIdxs[i] == boneIdx)
return i;
return -1;
}
};
std::vector<Bank> banks;
std::vector<Bank>::iterator addSkinBank(int skinSlotCount)
{
banks.emplace_back();
if (skinSlotCount > 0)
banks.back().reserve(skinSlotCount);
banks.back().m_skinIdxs.reserve(skinSlotCount);
return banks.end() - 1;
}
uint32_t addSurface(const Surface& surf, int skinSlotCount);
uint32_t addSurface(const Mesh& mesh, const Surface& surf, int skinSlotCount);
} skinBanks;
using SurfProgFunc = std::function<void(int)>;
Mesh(BlenderConnection& conn, OutputMode outMode, int skinSlotCount, SurfProgFunc& surfProg);
Mesh(BlenderConnection& conn, HMDLTopology topology, int skinSlotCount, SurfProgFunc& surfProg);
Mesh getContiguousSkinningVersion() const;
/** Prepares mesh representation for indexed access on modern APIs.
* Mesh must remain resident for accessing reference members
*/
HMDLBuffers getHMDLBuffers() const;
};
static const char* MeshOutputModeString(Mesh::OutputMode mode)
static const char* MeshOutputModeString(HMDLTopology topology)
{
static const char* STRS[] = {"TRIANGLES", "TRISTRIPS"};
return STRS[mode];
return STRS[topology];
}
/** Compile mesh by context (MESH blends only) */
Mesh compileMesh(Mesh::OutputMode outMode, int skinSlotCount=10,
Mesh compileMesh(HMDLTopology topology, int skinSlotCount=10,
Mesh::SurfProgFunc surfProg=[](int){})
{
if (m_parent->m_loadedType != TypeMesh)
@ -480,7 +536,7 @@ public:
char req[128];
snprintf(req, 128, "MESHCOMPILE %s %d",
MeshOutputModeString(outMode), skinSlotCount);
MeshOutputModeString(topology), skinSlotCount);
m_parent->_writeLine(req);
char readBuf[256];
@ -488,11 +544,11 @@ public:
if (strcmp(readBuf, "OK"))
BlenderLog.report(LogVisor::FatalError, "unable to cook mesh: %s", readBuf);
return Mesh(*m_parent, outMode, skinSlotCount, surfProg);
return Mesh(*m_parent, topology, skinSlotCount, surfProg);
}
/** Compile mesh by name (AREA blends only) */
Mesh compileMesh(const std::string& name, Mesh::OutputMode outMode, int skinSlotCount=10,
Mesh compileMesh(const std::string& name, HMDLTopology topology, int skinSlotCount=10,
Mesh::SurfProgFunc surfProg=[](int){})
{
if (m_parent->m_loadedType != TypeArea)
@ -501,7 +557,7 @@ public:
char req[128];
snprintf(req, 128, "MESHCOMPILENAME %s %s %d", name.c_str(),
MeshOutputModeString(outMode), skinSlotCount);
MeshOutputModeString(topology), skinSlotCount);
m_parent->_writeLine(req);
char readBuf[256];
@ -509,11 +565,11 @@ public:
if (strcmp(readBuf, "OK"))
BlenderLog.report(LogVisor::FatalError, "unable to cook mesh '%s': %s", name.c_str(), readBuf);
return Mesh(*m_parent, outMode, skinSlotCount, surfProg);
return Mesh(*m_parent, topology, skinSlotCount, surfProg);
}
/** Compile all meshes into one (AREA blends only) */
Mesh compileAllMeshes(Mesh::OutputMode outMode, int skinSlotCount=10, float maxOctantLength=5.0,
Mesh compileAllMeshes(HMDLTopology topology, int skinSlotCount=10, float maxOctantLength=5.0,
Mesh::SurfProgFunc surfProg=[](int){})
{
if (m_parent->m_loadedType != TypeArea)
@ -522,7 +578,7 @@ public:
char req[128];
snprintf(req, 128, "MESHCOMPILEALL %s %d %f",
MeshOutputModeString(outMode),
MeshOutputModeString(topology),
skinSlotCount, maxOctantLength);
m_parent->_writeLine(req);
@ -531,7 +587,7 @@ public:
if (strcmp(readBuf, "OK"))
BlenderLog.report(LogVisor::FatalError, "unable to cook all meshes: %s", readBuf);
return Mesh(*m_parent, outMode, skinSlotCount, surfProg);
return Mesh(*m_parent, topology, skinSlotCount, surfProg);
}
/** Intermediate actor representation prepared by blender from a single HECL actor blend */
@ -651,6 +707,52 @@ public:
};
class HMDLBuffers
{
public:
struct Surface;
private:
friend struct BlenderConnection::DataStream::Mesh;
HMDLBuffers(const HMDLMeta& meta,
size_t vboSz, const std::vector<atUint32>& iboData,
std::vector<Surface>&& surfaces,
const BlenderConnection::DataStream::Mesh::SkinBanks& skinBanks)
: m_metaSz(HECL_HMDL_META_SZ), m_metaData(new uint8_t[HECL_HMDL_META_SZ]),
m_vboSz(vboSz), m_vboData(new uint8_t[vboSz]),
m_iboSz(iboData.size()*4), m_iboData(new uint8_t[iboData.size()*4]),
m_surfaces(std::move(surfaces)), m_skinBanks(skinBanks)
{
{
Athena::io::MemoryWriter w(m_metaData.get(), HECL_HMDL_META_SZ);
meta.write(w);
}
{
Athena::io::MemoryWriter w(m_iboData.get(), m_iboSz);
w.enumerateLittle(iboData);
}
}
public:
size_t m_metaSz;
std::unique_ptr<uint8_t[]> m_metaData;
size_t m_vboSz;
std::unique_ptr<uint8_t[]> m_vboData;
size_t m_iboSz;
std::unique_ptr<uint8_t[]> m_iboData;
struct Surface
{
Surface(const BlenderConnection::DataStream::Mesh::Surface& origSurf,
atUint32 start, atUint32 count)
: m_origSurf(origSurf), m_start(start), m_count(count) {}
const BlenderConnection::DataStream::Mesh::Surface& m_origSurf;
atUint32 m_start;
atUint32 m_count;
};
std::vector<Surface> m_surfaces;
const BlenderConnection::DataStream::Mesh::SkinBanks& m_skinBanks;
};
}
#endif // BLENDERCONNECTION_HPP

View File

@ -25,6 +25,7 @@ bintoc(hecl_startup.c hecl_startup.blend HECL_STARTUP)
add_library(HECLBlender
BlenderConnection.cpp
BlenderConnection.hpp
HMDL.cpp
hecl_blendershell.py
hecl_blendershell.c
zip_package.py

121
hecl/blender/HMDL.cpp Normal file
View File

@ -0,0 +1,121 @@
#include "BlenderConnection.hpp"
namespace HECL
{
HMDLBuffers BlenderConnection::DataStream::Mesh::getHMDLBuffers() const
{
/* If skinned, compute max weight vec count */
size_t weightCount = 0;
for (const SkinBanks::Bank& bank : skinBanks.banks)
weightCount = std::max(weightCount, bank.m_boneIdxs.size());
size_t weightVecCount = weightCount / 4;
if (weightCount % 4)
++weightVecCount;
/* Prepare HMDL meta */
HMDLMeta metaOut;
metaOut.topology = topology;
metaOut.vertStride = (3 + 3 + colorLayerCount + uvLayerCount * 2 + weightVecCount * 4) * 4;
metaOut.colorCount = colorLayerCount;
metaOut.uvCount = uvLayerCount;
metaOut.weightCount = weightVecCount;
/* Total all verts from all surfaces (for ibo length) */
size_t boundVerts = 0;
for (const Surface& surf : surfaces)
boundVerts += surf.verts.size();
/* Maintain unique vert pool for VBO */
std::vector<std::pair<const Surface*, const Surface::Vert*>> vertPool;
vertPool.reserve(boundVerts);
/* Target surfaces representation */
std::vector<HMDLBuffers::Surface> outSurfaces;
outSurfaces.reserve(surfaces.size());
/* Index buffer */
std::vector<atUint32> iboData;
iboData.reserve(boundVerts);
for (const Surface& surf : surfaces)
{
size_t iboStart = iboData.size();
for (const Surface::Vert& v : surf.verts)
{
size_t ti = 0;
bool found = false;
for (const std::pair<const Surface*, const Surface::Vert*>& tv : vertPool)
{
if (v == *tv.second)
{
iboData.push_back(ti);
found = true;
break;
}
++ti;
}
if (!found)
{
iboData.push_back(vertPool.size());
vertPool.emplace_back(&surf, &v);
}
}
outSurfaces.emplace_back(surf, iboStart, iboData.size() - iboStart);
}
metaOut.vertCount = vertPool.size();
metaOut.indexCount = iboData.size();
size_t vboSz = metaOut.vertCount * metaOut.vertStride;
HMDLBuffers ret(metaOut, vboSz, iboData, std::move(outSurfaces), skinBanks);
Athena::io::MemoryWriter vboW(ret.m_vboData.get(), vboSz);
for (const std::pair<const Surface*, const Surface::Vert*>& sv : vertPool)
{
const Surface& s = *sv.first;
const Surface::Vert& v = *sv.second;
vboW.writeVec3fLittle(pos[v.iPos]);
vboW.writeVec3fLittle(norm[v.iNorm]);
for (int i=0 ; i<colorLayerCount ; ++i)
{
const Vector3f& c = color[v.iColor[i]];
vboW.writeUByte(std::max(0, std::min(255, int(c.val.vec[0] * 255))));
vboW.writeUByte(std::max(0, std::min(255, int(c.val.vec[1] * 255))));
vboW.writeUByte(std::max(0, std::min(255, int(c.val.vec[2] * 255))));
vboW.writeUByte(255);
}
for (int i=0 ; i<uvLayerCount ; ++i)
vboW.writeVec2fLittle(uv[v.iUv[i]]);
if (weightVecCount)
{
const SkinBanks::Bank& bank = skinBanks.banks[s.skinBankIdx];
const std::vector<SkinBind>& binds = skins[v.iSkin];
auto it = bank.m_boneIdxs.cbegin();
for (int i=0 ; i<weightVecCount ; ++i)
{
atVec4f vec = {};
for (int j=0 ; j<4 ; ++j)
{
if (it == bank.m_boneIdxs.cend())
break;
for (const SkinBind& bind : binds)
if (bind.boneIdx == *it)
{
vec.vec[j] = bind.weight;
break;
}
++it;
}
vboW.writeVec4fLittle(vec);
}
}
}
return ret;
}
}

View File

@ -0,0 +1,33 @@
#ifndef HMDLMETA_HPP
#define HMDLMETA_HPP
#include <HECL/HECL.hpp>
#include <Athena/DNA.hpp>
namespace HECL
{
enum HMDLTopology : atUint32
{
TopologyTriangles,
TopologyTriStrips,
};
#define HECL_HMDL_META_SZ 32
struct HMDLMeta : Athena::io::DNA<Athena::BigEndian>
{
DECL_DNA
Value<atUint32> magic = SBIG('TACO');
Value<HMDLTopology> topology;
Value<atUint32> vertStride;
Value<atUint32> vertCount;
Value<atUint32> indexCount;
Value<atUint32> colorCount;
Value<atUint32> uvCount;
Value<atUint32> weightCount;
};
}
#endif // HMDLMETA_HPP

View File

@ -115,10 +115,14 @@ public:
/**
* @brief Integrated reader/constructor/container for HMDL data
*/
class HMDLData
struct HMDLData
{
public:
HMDLData(boo::IGraphicsDataFactory* factory, const void* data);
boo::IGraphicsBufferS* m_vbo;
boo::IGraphicsBufferS* m_ibo;
boo::IVertexFormat* m_vtxFmt;
HMDLData(boo::IGraphicsDataFactory* factory,
const void* metaData, const void* vbo, const void* ibo);
};
}

View File

@ -7,6 +7,7 @@ if(WIN32)
list(APPEND PLAT_SRCS winsupport.cpp ../include/HECL/winsupport.hpp)
endif()
atdna(atdna_HMDLMeta.cpp ../include/HECL/HMDLMeta.hpp)
atdna(atdna_Frontend.cpp ../include/HECL/Frontend.hpp)
atdna(atdna_Runtime.cpp ../include/HECL/Runtime.hpp)
@ -15,6 +16,7 @@ add_library(HECLCommon
ProjectPath.cpp
WideStringConvert.cpp
../include/HECL/HECL.hpp
../include/HECL/HMDLMeta.hpp
../include/HECL/Backend/Backend.hpp
../include/HECL/Backend/GX.hpp
../include/HECL/Backend/ProgrammableCommon.hpp
@ -22,6 +24,7 @@ add_library(HECLCommon
../include/HECL/Frontend.hpp
../include/HECL/Database.hpp
../include/HECL/Runtime.hpp
atdna_HMDLMeta.cpp
atdna_Frontend.cpp
atdna_Runtime.cpp
${PLAT_SRCS})

View File

@ -1,12 +1,58 @@
#include "HECL/HMDLMeta.hpp"
#include "HECL/Runtime.hpp"
#include <Athena/MemoryReader.hpp>
namespace HECL
{
namespace Runtime
{
static LogVisor::LogModule Log("HMDL");
HMDLData::HMDLData(boo::IGraphicsDataFactory* factory, const void *data)
HMDLData::HMDLData(boo::IGraphicsDataFactory* factory,
const void* metaData, const void* vbo, const void* ibo)
{
HMDLMeta meta;
{
Athena::io::MemoryReader r((atUint8*)metaData, HECL_HMDL_META_SZ);
meta.read(r);
}
if (meta.magic != FOURCC('TACO'))
Log.report(LogVisor::FatalError, "invalid HMDL magic");
m_vbo = factory->newStaticBuffer(boo::BufferUseVertex, vbo, meta.vertStride, meta.vertCount);
m_ibo = factory->newStaticBuffer(boo::BufferUseIndex, ibo, 4, meta.indexCount);
size_t elemCount = 2 + meta.colorCount + meta.uvCount + meta.weightCount;
std::unique_ptr<boo::VertexElementDescriptor[]> vdescs(new boo::VertexElementDescriptor[elemCount]);
for (size_t i=0 ; i<elemCount ; ++i)
{
vdescs[i].vertBuffer = m_vbo;
vdescs[i].indexBuffer = m_ibo;
}
vdescs[0].semantic = boo::VertexSemanticPosition;
vdescs[1].semantic = boo::VertexSemanticNormal;
size_t e = 2;
for (size_t i=0 ; i<meta.colorCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemanticColor;
vdescs[e].semanticIdx = i;
}
for (size_t i=0 ; i<meta.uvCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemanticUV;
vdescs[e].semanticIdx = i;
}
for (size_t i=0 ; i<meta.weightCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemanticWeight;
vdescs[e].semanticIdx = i;
}
m_vtxFmt = factory->newVertexFormat(elemCount, vdescs.get());
}
}