mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-18 16:32:32 +02:00
Allow ModelFrame, Atomic, Geometry to exist outside of a Clump
This changes the Clump data structure to simplify it and move some of the concerns into the Atomic and Frame types.
This commit is contained in:
parent
a0eaf5b8b0
commit
34c70b0be2
@ -9,37 +9,78 @@ Geometry::Geometry() : flags(0) {
|
||||
Geometry::~Geometry() {
|
||||
}
|
||||
|
||||
ModelFrame::ModelFrame(unsigned int index, ModelFrame* parent, glm::mat3 dR,
|
||||
glm::vec3 dT)
|
||||
ModelFrame::ModelFrame(unsigned int index, glm::mat3 dR, glm::vec3 dT)
|
||||
: index(index)
|
||||
, defaultRotation(dR)
|
||||
, defaultTranslation(dT)
|
||||
, parentFrame(parent) {
|
||||
if (parent != nullptr) {
|
||||
parent->childs.push_back(this);
|
||||
}
|
||||
, parent_(nullptr) {
|
||||
reset();
|
||||
}
|
||||
|
||||
void ModelFrame::reset() {
|
||||
matrix = glm::translate(glm::mat4(), defaultTranslation) *
|
||||
glm::mat4(defaultRotation);
|
||||
updateHierarchyTransform();
|
||||
}
|
||||
|
||||
void ModelFrame::addGeometry(size_t idx) {
|
||||
geometries.push_back(idx);
|
||||
void ModelFrame::updateHierarchyTransform() {
|
||||
// Update our own transformation
|
||||
if (parent_) {
|
||||
worldtransform_ = parent_->getWorldTransform() * matrix;
|
||||
} else {
|
||||
worldtransform_ = matrix;
|
||||
}
|
||||
for (const auto& child : children_) {
|
||||
child->updateHierarchyTransform();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelFrame::addChild(ModelFramePtr& child) {
|
||||
// Make sure the child is an orphan
|
||||
if (child->getParent()) {
|
||||
auto& other_children = child->getParent()->children_;
|
||||
other_children.erase(
|
||||
std::remove(other_children.begin(), other_children.end(), child),
|
||||
other_children.end());
|
||||
}
|
||||
child->parent_ = this;
|
||||
children_.push_back(child);
|
||||
}
|
||||
|
||||
ModelFrame* ModelFrame::findDescendant(const std::string& name) const {
|
||||
for (const auto& frame : children_) {
|
||||
if (frame->getName() == name) {
|
||||
return frame.get();
|
||||
}
|
||||
|
||||
auto result = frame->findDescendant(name);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ModelFrame* Clump::findFrame(const std::string& name) const {
|
||||
if (rootframe_->getName() == name) {
|
||||
return rootframe_.get();
|
||||
}
|
||||
|
||||
return rootframe_->findDescendant(name);
|
||||
}
|
||||
|
||||
Clump::~Clump() {
|
||||
for (auto mf : frames) {
|
||||
delete mf;
|
||||
}
|
||||
}
|
||||
|
||||
void Clump::recalculateMetrics() {
|
||||
boundingRadius = std::numeric_limits<float>::min();
|
||||
for (size_t g = 0; g < geometries.size(); g++) {
|
||||
RW::BSGeometryBounds& bounds = geometries[g]->geometryBounds;
|
||||
for (const auto& atomic : atomics_) {
|
||||
const auto& geometry = atomic->getGeometry();
|
||||
if (!geometry) {
|
||||
continue;
|
||||
}
|
||||
const auto& bounds = geometry->geometryBounds;
|
||||
boundingRadius = std::max(boundingRadius,
|
||||
glm::length(bounds.center) + bounds.radius);
|
||||
}
|
||||
|
@ -12,26 +12,43 @@
|
||||
#include <gl/TextureData.hpp>
|
||||
#include <loaders/RWBinaryStream.hpp>
|
||||
|
||||
// Forward Declerations
|
||||
class ModelFrame;
|
||||
struct Geometry;
|
||||
class Atomic;
|
||||
class Clump;
|
||||
|
||||
// Pointer types
|
||||
using ModelFramePtr = std::shared_ptr<ModelFrame>;
|
||||
using GeometryPtr = std::shared_ptr<Geometry>;
|
||||
using AtomicPtr = std::shared_ptr<Atomic>;
|
||||
using AtomicList = std::vector<AtomicPtr>;
|
||||
using ClumpPtr = std::shared_ptr<Clump>;
|
||||
|
||||
/**
|
||||
* ModelFrame stores the hierarchy of a model's geometry as well as default
|
||||
* transformations.
|
||||
* ModelFrame stores transformation hierarchy
|
||||
*/
|
||||
class ModelFrame {
|
||||
unsigned int index;
|
||||
glm::mat3 defaultRotation;
|
||||
glm::vec3 defaultTranslation;
|
||||
glm::mat4 matrix;
|
||||
ModelFrame* parentFrame;
|
||||
glm::mat4 worldtransform_;
|
||||
ModelFrame* parent_;
|
||||
std::string name;
|
||||
std::vector<size_t> geometries;
|
||||
std::vector<ModelFrame*> childs;
|
||||
std::vector<ModelFramePtr> children_;
|
||||
|
||||
public:
|
||||
ModelFrame(unsigned int index, ModelFrame* parent, glm::mat3 dR,
|
||||
glm::vec3 dT);
|
||||
ModelFrame(unsigned int index = 0, glm::mat3 dR = glm::mat3(),
|
||||
glm::vec3 dT = glm::vec3());
|
||||
|
||||
void reset();
|
||||
void setTransform(const glm::mat4& m);
|
||||
|
||||
void setTransform(const glm::mat4& m) {
|
||||
matrix = m;
|
||||
updateHierarchyTransform();
|
||||
}
|
||||
|
||||
const glm::mat4& getTransform() const {
|
||||
return matrix;
|
||||
}
|
||||
@ -40,8 +57,6 @@ public:
|
||||
name = fname;
|
||||
}
|
||||
|
||||
void addGeometry(size_t idx);
|
||||
|
||||
unsigned int getIndex() const {
|
||||
return index;
|
||||
}
|
||||
@ -54,25 +69,45 @@ public:
|
||||
return defaultRotation;
|
||||
}
|
||||
|
||||
glm::mat4 getMatrix() const {
|
||||
return (parentFrame ? parentFrame->getMatrix() : glm::mat4()) * matrix;
|
||||
void setTranslation(const glm::vec3& t) {
|
||||
matrix[3] = glm::vec4(t, matrix[3][3]);
|
||||
updateHierarchyTransform();
|
||||
}
|
||||
|
||||
void setRotation(const glm::mat3& r) {
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
matrix[i] = glm::vec4(r[i], matrix[i][3]);
|
||||
}
|
||||
updateHierarchyTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cached matrix
|
||||
*/
|
||||
void updateHierarchyTransform();
|
||||
|
||||
/**
|
||||
* @return the cached world transformation for this Frame
|
||||
*/
|
||||
const glm::mat4& getWorldTransform() const {
|
||||
return worldtransform_;
|
||||
}
|
||||
|
||||
ModelFrame* getParent() const {
|
||||
return parentFrame;
|
||||
return parent_;
|
||||
}
|
||||
|
||||
const std::vector<ModelFrame*>& getChildren() const {
|
||||
return childs;
|
||||
void addChild(ModelFramePtr& child);
|
||||
|
||||
const std::vector<ModelFramePtr>& getChildren() const {
|
||||
return children_;
|
||||
}
|
||||
|
||||
const std::string& getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
const std::vector<size_t>& getGeometries() const {
|
||||
return geometries;
|
||||
}
|
||||
ModelFrame* findDescendant(const std::string& name) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -149,9 +184,27 @@ struct Geometry {
|
||||
/**
|
||||
* @brief The Atomic struct
|
||||
*/
|
||||
struct Atomic {
|
||||
uint32_t frame;
|
||||
uint32_t geometry;
|
||||
class Atomic {
|
||||
ModelFramePtr frame_;
|
||||
GeometryPtr geometry_;
|
||||
|
||||
public:
|
||||
|
||||
void setFrame(ModelFramePtr& frame) {
|
||||
frame_ = frame;
|
||||
}
|
||||
|
||||
const ModelFramePtr& getFrame() const {
|
||||
return frame_;
|
||||
}
|
||||
|
||||
void setGeometry(GeometryPtr& geom) {
|
||||
geometry_ = geom;
|
||||
}
|
||||
|
||||
const GeometryPtr& getGeometry() const {
|
||||
return geometry_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -159,22 +212,12 @@ struct Atomic {
|
||||
*/
|
||||
class Clump {
|
||||
public:
|
||||
std::uint32_t numAtomics;
|
||||
|
||||
// This should be gone
|
||||
std::vector<ModelFrame*> frames;
|
||||
// This should be gone
|
||||
std::vector<std::shared_ptr<Geometry>> geometries;
|
||||
std::vector<Atomic> atomics;
|
||||
|
||||
int32_t rootFrameIdx;
|
||||
|
||||
ModelFrame* findFrame(const std::string& name) const {
|
||||
auto fit =
|
||||
std::find_if(frames.begin(), frames.end(),
|
||||
[&](ModelFrame* f) { return f->getName() == name; });
|
||||
return fit != frames.end() ? *fit : nullptr;
|
||||
}
|
||||
/**
|
||||
* @brief findFrame Locates frame with name anywhere in the hierarchy
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
ModelFrame* findFrame(const std::string& name) const;
|
||||
|
||||
~Clump();
|
||||
|
||||
@ -184,8 +227,26 @@ public:
|
||||
return boundingRadius;
|
||||
}
|
||||
|
||||
void addAtomic(AtomicPtr& atomic) {
|
||||
atomics_.push_back(atomic);
|
||||
}
|
||||
|
||||
const AtomicList& getAtomics() const {
|
||||
return atomics_;
|
||||
}
|
||||
|
||||
void setFrame(ModelFramePtr& root) {
|
||||
rootframe_ = root;
|
||||
}
|
||||
|
||||
const ModelFramePtr& getFrame() const {
|
||||
return rootframe_;
|
||||
}
|
||||
|
||||
private:
|
||||
float boundingRadius;
|
||||
AtomicList atomics_;
|
||||
ModelFramePtr rootframe_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <data/Clump.hpp>
|
||||
#include <loaders/LoaderDFF.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@ -40,7 +41,7 @@ struct RWBSFrame {
|
||||
uint32_t matrixflags; // Not used
|
||||
};
|
||||
|
||||
void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) {
|
||||
LoaderDFF::FrameList LoaderDFF::readFrameList(const RWBStream &stream) {
|
||||
auto listStream = stream.getInnerStream();
|
||||
|
||||
auto listStructID = listStream.getNextChunk();
|
||||
@ -53,21 +54,22 @@ void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) {
|
||||
unsigned int numFrames = *(std::uint32_t *)headerPtr;
|
||||
headerPtr += sizeof(std::uint32_t);
|
||||
|
||||
model->frames.reserve(numFrames);
|
||||
FrameList framelist;
|
||||
framelist.reserve(numFrames);
|
||||
|
||||
for (size_t f = 0; f < numFrames; ++f) {
|
||||
auto data = (RWBSFrame *)headerPtr;
|
||||
headerPtr += sizeof(RWBSFrame);
|
||||
auto frame =
|
||||
std::make_shared<ModelFrame>(f, data->rotation, data->position);
|
||||
|
||||
ModelFrame *parent = nullptr;
|
||||
if (data->index != -1) {
|
||||
parent = model->frames[data->index];
|
||||
} else {
|
||||
model->rootFrameIdx = f;
|
||||
RW_CHECK(data->index < int(framelist.size()),
|
||||
"Frame parent out of bounds");
|
||||
if (data->index != -1 && data->index < int(framelist.size())) {
|
||||
framelist[data->index]->addChild(frame);
|
||||
}
|
||||
|
||||
auto frame = new ModelFrame(f, parent, data->rotation, data->position);
|
||||
model->frames.push_back(frame);
|
||||
framelist.push_back(frame);
|
||||
}
|
||||
|
||||
size_t namedFrames = 0;
|
||||
@ -87,8 +89,8 @@ void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) {
|
||||
std::transform(fname.begin(), fname.end(),
|
||||
fname.begin(), ::tolower);
|
||||
|
||||
if (namedFrames < model->frames.size()) {
|
||||
model->frames[namedFrames++]->setName(fname);
|
||||
if (namedFrames < framelist.size()) {
|
||||
framelist[namedFrames++]->setName(fname);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
@ -100,9 +102,11 @@ void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return framelist;
|
||||
}
|
||||
|
||||
void LoaderDFF::readGeometryList(Clump *model, const RWBStream &stream) {
|
||||
LoaderDFF::GeometryList LoaderDFF::readGeometryList(const RWBStream &stream) {
|
||||
auto listStream = stream.getInnerStream();
|
||||
|
||||
auto listStructID = listStream.getNextChunk();
|
||||
@ -115,21 +119,24 @@ void LoaderDFF::readGeometryList(Clump *model, const RWBStream &stream) {
|
||||
unsigned int numGeometries = *(std::uint32_t *)headerPtr;
|
||||
headerPtr += sizeof(std::uint32_t);
|
||||
|
||||
model->geometries.reserve(numGeometries);
|
||||
std::vector<GeometryPtr> geometrylist;
|
||||
geometrylist.reserve(numGeometries);
|
||||
|
||||
for (auto chunkID = listStream.getNextChunk(); chunkID != 0;
|
||||
chunkID = listStream.getNextChunk()) {
|
||||
switch (chunkID) {
|
||||
case CHUNK_GEOMETRY:
|
||||
readGeometry(model, listStream);
|
||||
break;
|
||||
case CHUNK_GEOMETRY: {
|
||||
geometrylist.push_back(readGeometry(listStream));
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return geometrylist;
|
||||
}
|
||||
|
||||
void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) {
|
||||
GeometryPtr LoaderDFF::readGeometry(const RWBStream &stream) {
|
||||
auto geomStream = stream.getInnerStream();
|
||||
|
||||
auto geomStructID = geomStream.getNextChunk();
|
||||
@ -137,7 +144,7 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) {
|
||||
throw DFFLoaderException("Geometry missing struct chunk");
|
||||
}
|
||||
|
||||
std::shared_ptr<Geometry> geom(new Geometry);
|
||||
auto geom = std::make_shared<Geometry>();
|
||||
|
||||
char *headerPtr = geomStream.getCursor();
|
||||
|
||||
@ -216,26 +223,24 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add the geometry to the model now so that it can be accessed.
|
||||
model->geometries.push_back(geom);
|
||||
|
||||
// Process the geometry child sections
|
||||
for (auto chunkID = geomStream.getNextChunk(); chunkID != 0;
|
||||
chunkID = geomStream.getNextChunk()) {
|
||||
switch (chunkID) {
|
||||
case CHUNK_MATERIALLIST:
|
||||
readMaterialList(model, geomStream);
|
||||
readMaterialList(geom, geomStream);
|
||||
break;
|
||||
case CHUNK_EXTENSION:
|
||||
readGeometryExtension(model, geomStream);
|
||||
readGeometryExtension(geom, geomStream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
geom->dbuff.setFaceType(
|
||||
geom->facetype == Geometry::Triangles ? GL_TRIANGLES : GL_TRIANGLE_STRIP);
|
||||
geom->dbuff.setFaceType(geom->facetype == Geometry::Triangles
|
||||
? GL_TRIANGLES
|
||||
: GL_TRIANGLE_STRIP);
|
||||
geom->gbuff.uploadVertices(verts);
|
||||
geom->dbuff.addGeometry(&geom->gbuff);
|
||||
|
||||
@ -251,9 +256,11 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) {
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sg.start * sizeof(uint32_t),
|
||||
sizeof(uint32_t) * sg.numIndices, sg.indices.data());
|
||||
}
|
||||
|
||||
return geom;
|
||||
}
|
||||
|
||||
void LoaderDFF::readMaterialList(Clump *model, const RWBStream &stream) {
|
||||
void LoaderDFF::readMaterialList(GeometryPtr &geom, const RWBStream &stream) {
|
||||
auto listStream = stream.getInnerStream();
|
||||
|
||||
auto listStructID = listStream.getNextChunk();
|
||||
@ -263,13 +270,13 @@ void LoaderDFF::readMaterialList(Clump *model, const RWBStream &stream) {
|
||||
|
||||
unsigned int numMaterials = *(std::uint32_t *)listStream.getCursor();
|
||||
|
||||
model->geometries.back()->materials.reserve(numMaterials);
|
||||
geom->materials.reserve(numMaterials);
|
||||
|
||||
RWBStream::ChunkID chunkID;
|
||||
while ((chunkID = listStream.getNextChunk())) {
|
||||
switch (chunkID) {
|
||||
case CHUNK_MATERIAL:
|
||||
readMaterial(model, listStream);
|
||||
readMaterial(geom, listStream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -277,7 +284,7 @@ void LoaderDFF::readMaterialList(Clump *model, const RWBStream &stream) {
|
||||
}
|
||||
}
|
||||
|
||||
void LoaderDFF::readMaterial(Clump *model, const RWBStream &stream) {
|
||||
void LoaderDFF::readMaterial(GeometryPtr &geom, const RWBStream &stream) {
|
||||
auto materialStream = stream.getInnerStream();
|
||||
|
||||
auto matStructID = materialStream.getNextChunk();
|
||||
@ -306,21 +313,22 @@ void LoaderDFF::readMaterial(Clump *model, const RWBStream &stream) {
|
||||
matData += sizeof(float);
|
||||
material.flags = 0;
|
||||
|
||||
model->geometries.back()->materials.push_back(material);
|
||||
|
||||
RWBStream::ChunkID chunkID;
|
||||
while ((chunkID = materialStream.getNextChunk())) {
|
||||
switch (chunkID) {
|
||||
case CHUNK_TEXTURE:
|
||||
readTexture(model, materialStream);
|
||||
readTexture(material, materialStream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
geom->materials.push_back(material);
|
||||
}
|
||||
|
||||
void LoaderDFF::readTexture(Clump *model, const RWBStream &stream) {
|
||||
void LoaderDFF::readTexture(Geometry::Material &material,
|
||||
const RWBStream &stream) {
|
||||
auto texStream = stream.getInnerStream();
|
||||
|
||||
auto texStructID = texStream.getNextChunk();
|
||||
@ -343,18 +351,18 @@ void LoaderDFF::readTexture(Clump *model, const RWBStream &stream) {
|
||||
|
||||
TextureData::Handle textureinst =
|
||||
texturelookup ? texturelookup(name, alpha) : nullptr;
|
||||
model->geometries.back()->materials.back().textures.push_back(
|
||||
{name, alpha, textureinst});
|
||||
material.textures.push_back({name, alpha, textureinst});
|
||||
}
|
||||
|
||||
void LoaderDFF::readGeometryExtension(Clump *model, const RWBStream &stream) {
|
||||
void LoaderDFF::readGeometryExtension(GeometryPtr &geom,
|
||||
const RWBStream &stream) {
|
||||
auto extStream = stream.getInnerStream();
|
||||
|
||||
RWBStream::ChunkID chunkID;
|
||||
while ((chunkID = extStream.getNextChunk())) {
|
||||
switch (chunkID) {
|
||||
case CHUNK_BINMESHPLG:
|
||||
readBinMeshPLG(model, extStream);
|
||||
readBinMeshPLG(geom, extStream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -362,11 +370,10 @@ void LoaderDFF::readGeometryExtension(Clump *model, const RWBStream &stream) {
|
||||
}
|
||||
}
|
||||
|
||||
void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) {
|
||||
void LoaderDFF::readBinMeshPLG(GeometryPtr &geom, const RWBStream &stream) {
|
||||
auto data = stream.getCursor();
|
||||
|
||||
model->geometries.back()->facetype =
|
||||
static_cast<Geometry::FaceType>(*(std::uint32_t *)data);
|
||||
geom->facetype = static_cast<Geometry::FaceType>(*(std::uint32_t *)data);
|
||||
data += sizeof(std::uint32_t);
|
||||
|
||||
unsigned int numSplits = *(std::uint32_t *)data;
|
||||
@ -375,7 +382,7 @@ void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) {
|
||||
// Number of triangles.
|
||||
data += sizeof(std::uint32_t);
|
||||
|
||||
model->geometries.back()->subgeom.reserve(numSplits);
|
||||
geom->subgeom.reserve(numSplits);
|
||||
|
||||
size_t start = 0;
|
||||
|
||||
@ -393,11 +400,13 @@ void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) {
|
||||
sizeof(std::uint32_t) * sg.numIndices);
|
||||
data += sizeof(std::uint32_t) * sg.numIndices;
|
||||
|
||||
model->geometries.back()->subgeom.push_back(sg);
|
||||
geom->subgeom.push_back(sg);
|
||||
}
|
||||
}
|
||||
|
||||
void LoaderDFF::readAtomic(Clump *model, const RWBStream &stream) {
|
||||
AtomicPtr LoaderDFF::readAtomic(FrameList &framelist,
|
||||
GeometryList &geometrylist,
|
||||
const RWBStream &stream) {
|
||||
auto atomicStream = stream.getInnerStream();
|
||||
|
||||
auto atomicStructID = atomicStream.getNextChunk();
|
||||
@ -405,15 +414,26 @@ void LoaderDFF::readAtomic(Clump *model, const RWBStream &stream) {
|
||||
throw DFFLoaderException("Atomic missing struct chunk");
|
||||
}
|
||||
|
||||
Atomic atom;
|
||||
auto data = atomicStream.getCursor();
|
||||
atom.frame = *(std::uint32_t *)data;
|
||||
auto frame = *(std::uint32_t *)data;
|
||||
data += sizeof(std::uint32_t);
|
||||
atom.geometry = *(std::uint32_t *)data;
|
||||
model->frames[atom.frame]->addGeometry(atom.geometry);
|
||||
model->atomics.push_back(atom);
|
||||
auto geometry = *(std::uint32_t *)data;
|
||||
|
||||
/// @todo are any atomic extensions important?
|
||||
// Verify the atomic's particulars
|
||||
RW_CHECK(frame < framelist.size(), "atomic frame " << frame
|
||||
<< " out of bounds");
|
||||
RW_CHECK(geometry < geometrylist.size(),
|
||||
"atomic geometry " << geometry << " out of bounds");
|
||||
|
||||
auto atomic = std::make_shared<Atomic>();
|
||||
if (geometry < geometrylist.size()) {
|
||||
atomic->setGeometry(geometrylist[geometry]);
|
||||
}
|
||||
if (frame < framelist.size()) {
|
||||
atomic->setFrame(framelist[frame]);
|
||||
}
|
||||
|
||||
return atomic;
|
||||
}
|
||||
|
||||
Clump *LoaderDFF::loadFromMemory(FileHandle file) {
|
||||
@ -434,26 +454,40 @@ Clump *LoaderDFF::loadFromMemory(FileHandle file) {
|
||||
}
|
||||
|
||||
// There is only one value in the struct section.
|
||||
model->numAtomics = *(std::uint32_t *)rootStream.getCursor();
|
||||
auto numAtomics = *(std::uint32_t *)rootStream.getCursor();
|
||||
RW_UNUSED(numAtomics);
|
||||
|
||||
GeometryList geometrylist;
|
||||
FrameList framelist;
|
||||
|
||||
// Process everything inside the clump stream.
|
||||
RWBStream::ChunkID chunkID;
|
||||
while ((chunkID = modelStream.getNextChunk())) {
|
||||
switch (chunkID) {
|
||||
case CHUNK_FRAMELIST:
|
||||
readFrameList(model, modelStream);
|
||||
framelist = readFrameList(modelStream);
|
||||
break;
|
||||
case CHUNK_GEOMETRYLIST:
|
||||
readGeometryList(model, modelStream);
|
||||
break;
|
||||
case CHUNK_ATOMIC:
|
||||
readAtomic(model, modelStream);
|
||||
geometrylist = readGeometryList(modelStream);
|
||||
break;
|
||||
case CHUNK_ATOMIC: {
|
||||
auto atomic = readAtomic(framelist, geometrylist, modelStream);
|
||||
RW_CHECK(atomic, "Failed to read atomic");
|
||||
if (!atomic) {
|
||||
// Abort reading the rest of the clump
|
||||
return nullptr;
|
||||
}
|
||||
model->addAtomic(atomic);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!framelist.empty()) {
|
||||
model->setFrame(framelist[0]);
|
||||
}
|
||||
|
||||
// Ensure the model has cached metrics
|
||||
model->recalculateMetrics();
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#ifndef _LOADERDFF_HPP_
|
||||
#define _LOADERDFF_HPP_
|
||||
|
||||
#include <data/Clump.hpp>
|
||||
#include <gl/TextureData.hpp>
|
||||
#include <loaders/RWBinaryStream.hpp>
|
||||
#include <platform/FileHandle.hpp>
|
||||
@ -9,8 +10,6 @@
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
class Clump;
|
||||
|
||||
class DFFLoaderException {
|
||||
std::string _message;
|
||||
|
||||
@ -24,40 +23,39 @@ public:
|
||||
};
|
||||
|
||||
class LoaderDFF {
|
||||
/**
|
||||
* @brief loads a Frame List chunk from stream into model.
|
||||
* @param model
|
||||
* @param stream
|
||||
*/
|
||||
void readFrameList(Clump* model, const RWBStream& stream);
|
||||
|
||||
void readGeometryList(Clump* model, const RWBStream& stream);
|
||||
|
||||
void readGeometry(Clump* model, const RWBStream& stream);
|
||||
|
||||
void readMaterialList(Clump* model, const RWBStream& stream);
|
||||
|
||||
void readMaterial(Clump* model, const RWBStream& stream);
|
||||
|
||||
void readTexture(Clump* model, const RWBStream& stream);
|
||||
|
||||
void readGeometryExtension(Clump* model, const RWBStream& stream);
|
||||
|
||||
void readBinMeshPLG(Clump* model, const RWBStream& stream);
|
||||
|
||||
void readAtomic(Clump* model, const RWBStream& stream);
|
||||
|
||||
public:
|
||||
using TextureLookupCallback = std::function<TextureData::Handle(
|
||||
const std::string&, const std::string&)>;
|
||||
using GeometryList = std::vector<GeometryPtr>;
|
||||
using FrameList = std::vector<ModelFramePtr>;
|
||||
|
||||
Clump* loadFromMemory(FileHandle file);
|
||||
|
||||
void setTextureLookupCallback(TextureLookupCallback tlc) {
|
||||
texturelookup = tlc;
|
||||
}
|
||||
|
||||
private:
|
||||
TextureLookupCallback texturelookup;
|
||||
|
||||
FrameList readFrameList(const RWBStream& stream);
|
||||
|
||||
GeometryList readGeometryList(const RWBStream& stream);
|
||||
|
||||
GeometryPtr readGeometry(const RWBStream& stream);
|
||||
|
||||
void readMaterialList(GeometryPtr& geom, const RWBStream& stream);
|
||||
|
||||
void readMaterial(GeometryPtr& geom, const RWBStream& stream);
|
||||
|
||||
void readTexture(Geometry::Material& material, const RWBStream& stream);
|
||||
|
||||
void readGeometryExtension(GeometryPtr& geom, const RWBStream& stream);
|
||||
|
||||
void readBinMeshPLG(GeometryPtr& geom, const RWBStream& stream);
|
||||
|
||||
AtomicPtr readAtomic(FrameList& framelist, GeometryList& geometrylist,
|
||||
const RWBStream& stream);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -15,22 +15,13 @@ BOOST_AUTO_TEST_CASE(test_load_dff) {
|
||||
|
||||
BOOST_REQUIRE(m != nullptr);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(m->frames.size(), 40);
|
||||
BOOST_REQUIRE(m->getFrame());
|
||||
|
||||
BOOST_REQUIRE_EQUAL(m->geometries.size(), 16);
|
||||
BOOST_REQUIRE(!m->getAtomics().empty());
|
||||
const auto& atomic = m->getAtomics()[0];
|
||||
|
||||
BOOST_REQUIRE_EQUAL(m->geometries[0]->subgeom.size(), 5);
|
||||
|
||||
for (auto& g : m->geometries) {
|
||||
BOOST_CHECK_GT(g->geometryBounds.radius, 0.f);
|
||||
}
|
||||
|
||||
BOOST_REQUIRE(m->atomics.size() > 0);
|
||||
|
||||
for (auto& a : m->atomics) {
|
||||
BOOST_CHECK(a.frame < m->frames.size());
|
||||
BOOST_CHECK(a.geometry < m->geometries.size());
|
||||
}
|
||||
BOOST_REQUIRE(atomic->getGeometry());
|
||||
BOOST_REQUIRE(atomic->getFrame());
|
||||
|
||||
delete m;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user