Files
wc3re/ObjDecoder.cc

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"};
}