204 lines
6.5 KiB
C++
204 lines
6.5 KiB
C++
#include <cassert>
|
|
|
|
#include "ObjDecoder.hh"
|
|
#include "exceptions.hh"
|
|
#include "util.hh"
|
|
|
|
ObjDecoder::ObjDecoder(uint8_t const* base, size_t length)
|
|
: iff_(base, length)
|
|
{
|
|
auto& root = iff_.getRoot();
|
|
if (!root.isForm())
|
|
throw FormatException{"Root node not FORM"};
|
|
|
|
auto& rootForm = dynamic_cast<IffFile::Form const&>(root);
|
|
if (rootForm.getSubtype() != "REAL")
|
|
throw FormatException{"Root form not REAL"};
|
|
|
|
for (auto realIt = rootForm.childrenBegin();realIt != rootForm.childrenEnd();++realIt) {
|
|
if (realIt->getType() == "INFO") {
|
|
name_ = *realIt;
|
|
printf("Name: %s\n", name_.c_str());
|
|
} else if (realIt->isForm()) {
|
|
auto& itForm = dynamic_cast<IffFile::Form const&>(*realIt);
|
|
if (itForm.getSubtype() == "OBJT")
|
|
parseOBJT_(itForm);
|
|
else if (itForm.getSubtype() == "APPR")
|
|
parseAPPR_(itForm);
|
|
else
|
|
throw FormatException{"Unknown FORM type " + itForm.getSubtype()};
|
|
} else
|
|
throw FormatException{"Unknown chunk type " + realIt->getType()};
|
|
}
|
|
}
|
|
|
|
void ObjDecoder::parseOBJT_(IffFile::Form const& form)
|
|
{
|
|
}
|
|
|
|
void ObjDecoder::parseAPPR_(IffFile::Form const& form)
|
|
{
|
|
if (form.getChildCount() != 1)
|
|
throw FormatException{"Unexpected child count in APPR"};
|
|
|
|
auto& child = *form.childrenBegin();
|
|
if (!child.isForm())
|
|
throw FormatException{"APPR child not FORM"};
|
|
|
|
auto& childForm = dynamic_cast<IffFile::Form const&>(child);
|
|
if (childForm.getSubtype() != "POLY")
|
|
throw FormatException{"APPR child form not POLY"};
|
|
|
|
parsePOLY_(childForm);
|
|
}
|
|
|
|
void ObjDecoder::parsePOLY_(IffFile::Form const& form)
|
|
{
|
|
for (auto it = form.childrenBegin();it != form.childrenEnd();++it) {
|
|
if (it->getType() == "INFO") {
|
|
} else if (it->getType() == "VERT") {
|
|
if (it->getSize()%12 != 0)
|
|
throw FormatException{"Unexpected VERT size"};
|
|
for (size_t i = 0;i < it->getSize();i+=12) {
|
|
std::array<int32_t, 3> vertex;
|
|
for (size_t j = 0;j < 3;++j)
|
|
vertex[j] = readU32LE(it->begin()+i+j*4);
|
|
printf("V: %d %d %d\n", vertex[0], vertex[1], vertex[2]);
|
|
vertices_.push_back(vertex);
|
|
}
|
|
} else if (it->isForm()) {
|
|
auto& itForm = dynamic_cast<IffFile::Form const&>(*it);
|
|
if (itForm.getSubtype() == "TRIS") {
|
|
parseTRIS_(itForm);
|
|
} else if (itForm.getSubtype() == "QUAD") {
|
|
parseQUAD_(itForm);
|
|
} else if (itForm.getSubtype() == "DETA") {
|
|
// NYI
|
|
} else if (itForm.getSubtype() == "TXMS") {
|
|
parseTXMS_(itForm);
|
|
} else if (itForm.getSubtype() == "GRUP") {
|
|
// NYI
|
|
} else
|
|
throw FormatException{"Unknown POLY subform " + itForm.getSubtype()};
|
|
} else if (it->getType() == "ATTR") {
|
|
// NYI
|
|
} else if (it->getType() == "XATR") {
|
|
// NYI
|
|
} else
|
|
throw FormatException{"Unknown POLY child " + it->getType()};
|
|
}
|
|
}
|
|
|
|
void ObjDecoder::parseTRIS_(IffFile::Form const& form)
|
|
{
|
|
if (form.getChildCount() != 2)
|
|
throw FormatException{"Unexpected child count in TRIS"};
|
|
|
|
auto vertCount = vertices_.size();
|
|
printf("VC: %lu\n", vertCount);
|
|
|
|
IffFile::Object const *face = nullptr, *maps = nullptr;
|
|
for (auto it = form.childrenBegin();it != form.childrenEnd();++it) {
|
|
if (it->getType() == "FACE") {
|
|
if (face)
|
|
throw FormatException{"Multiple FACE in TRIS"};
|
|
face = &*it;
|
|
} else if (it->getType() == "MAPS") {
|
|
if (maps)
|
|
throw FormatException{"Multiple MAPS in TRIS"};
|
|
maps = &*it;
|
|
} else
|
|
throw FormatException{"Unknown TRIS child " + it->getType()};
|
|
}
|
|
|
|
assert(face && maps);
|
|
|
|
if (face->getSize()%8 != 0)
|
|
throw FormatException{"Unexpected FACE size"};
|
|
auto numTriangles = face->getSize()/8;
|
|
if (maps->getSize() != numTriangles*16)
|
|
throw FormatException{"Unexpected MAPS size"};
|
|
|
|
for (unsigned i = 0;i < numTriangles;++i) {
|
|
Triangle tri;
|
|
for (unsigned j = 0;j < 3;++j)
|
|
tri.vertIdx[j] = readU16LE(face->begin()+i*8+2+j*2);
|
|
tri.id = readU16LE(maps->begin()+i*16);
|
|
tri.tex = readU16LE(maps->begin()+i*16+2);
|
|
for (unsigned j = 0;j < 3;++j) {
|
|
tri.texCoords[j][0] = readU16LE(maps->begin()+i*16+4+j*4);
|
|
tri.texCoords[j][1] = readU16LE(maps->begin()+i*16+4+j*4+2);
|
|
}
|
|
printf("T%u: (%hu (%hu %hu)), (%hu (%hu %hu)), (%hu (%hu %hu))\n", tri.id,
|
|
tri.vertIdx[0], tri.texCoords[0][0], tri.texCoords[0][1],
|
|
tri.vertIdx[1], tri.texCoords[1][0], tri.texCoords[1][1],
|
|
tri.vertIdx[2], tri.texCoords[2][0], tri.texCoords[2][1]);
|
|
triangles_.push_back(tri);
|
|
}
|
|
}
|
|
|
|
void ObjDecoder::parseQUAD_(IffFile::Form const& form)
|
|
{
|
|
if (form.getChildCount() != 2)
|
|
throw FormatException{"Unexpected child count in QUAD"};
|
|
|
|
IffFile::Object const *face = nullptr, *maps = nullptr;
|
|
for (auto it = form.childrenBegin();it != form.childrenEnd();++it) {
|
|
if (it->getType() == "FACE") {
|
|
if (face)
|
|
throw FormatException{"Multiple FACE in QUAD"};
|
|
face = &*it;
|
|
} else if (it->getType() == "MAPS") {
|
|
if (maps)
|
|
throw FormatException{"Multiple MAPS in QUAD"};
|
|
maps = &*it;
|
|
} else
|
|
throw FormatException{"Unknown TRIS child " + it->getType()};
|
|
}
|
|
|
|
assert(face && maps);
|
|
|
|
if (face->getSize()%10 != 0)
|
|
throw FormatException{"Unexpected FACE size"};
|
|
auto numQuads = face->getSize()/10;
|
|
if (maps->getSize() != numQuads*20)
|
|
throw FormatException{"Unexpected MAPS size"};
|
|
|
|
for (unsigned i = 0;i < numQuads;++i) {
|
|
Quad quad;
|
|
for (unsigned j = 0;j < 4;++j)
|
|
quad.vertIdx[j] = readU16LE(face->begin()+i*10+2+j*2);
|
|
quad.id = readU16LE(maps->begin()+i*20);
|
|
quad.tex = readU16LE(maps->begin()+i*20+2);
|
|
for (unsigned j = 0;j < 4;++j) {
|
|
quad.texCoords[j][0] = readU16LE(maps->begin()+i*20+4+j*4);
|
|
quad.texCoords[j][1] = readU16LE(maps->begin()+i*20+4+j*4+2);
|
|
}
|
|
printf("Q%u: (%hu (%hu %hu)), (%hu (%hu %hu)), (%hu (%hu %hu)), (%hu (%hu %hu))\n", quad.id,
|
|
quad.vertIdx[0], quad.texCoords[0][0], quad.texCoords[0][1],
|
|
quad.vertIdx[1], quad.texCoords[1][0], quad.texCoords[1][1],
|
|
quad.vertIdx[2], quad.texCoords[2][0], quad.texCoords[2][1],
|
|
quad.vertIdx[3], quad.texCoords[3][0], quad.texCoords[3][1]);
|
|
quads_.push_back(quad);
|
|
}
|
|
}
|
|
|
|
void ObjDecoder::parseTXMS_(IffFile::Form const& form)
|
|
{
|
|
if (form.getChildCount() < 1)
|
|
throw FormatException{"Unexpected child count in TXMS"};
|
|
|
|
auto it = form.childrenBegin();
|
|
auto& info = *it;
|
|
if (info.getType() != "INFO")
|
|
throw FormatException{"Missing INFO in TXMS"};
|
|
if (info.getSize() != 4)
|
|
throw FormatException{"Unexpected INFO size in TXMS"};
|
|
|
|
uint16_t numTXMP, numTXMA;
|
|
numTXMP = readU16LE(info.begin());
|
|
numTXMA = readU16LE(info.begin()+2);
|
|
if (form.getChildCount() != 1+numTXMP+numTXMA)
|
|
throw FormatException{"Unexpected child count in TXMS"};
|
|
}
|