1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 18:32:44 +01:00

clang-format files in rwlib/source/loaders

This commit is contained in:
Daniel Evans 2016-09-09 21:13:21 +01:00
parent 94cc76d36a
commit 981d68713b
9 changed files with 1142 additions and 1228 deletions

View File

@ -1,30 +1,29 @@
#include <loaders/LoaderDFF.hpp>
#include <data/Model.hpp>
#include <loaders/LoaderDFF.hpp>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <numeric>
#include <set>
#include <cstring>
enum DFFChunks
{
CHUNK_STRUCT = 0x0001,
CHUNK_EXTENSION = 0x0003,
CHUNK_TEXTURE = 0x0006,
CHUNK_MATERIAL = 0x0007,
CHUNK_MATERIALLIST = 0x0008,
CHUNK_FRAMELIST = 0x000E,
CHUNK_GEOMETRY = 0x000F,
CHUNK_CLUMP = 0x0010,
enum DFFChunks {
CHUNK_STRUCT = 0x0001,
CHUNK_EXTENSION = 0x0003,
CHUNK_TEXTURE = 0x0006,
CHUNK_MATERIAL = 0x0007,
CHUNK_MATERIALLIST = 0x0008,
CHUNK_FRAMELIST = 0x000E,
CHUNK_GEOMETRY = 0x000F,
CHUNK_CLUMP = 0x0010,
CHUNK_ATOMIC = 0x0014,
CHUNK_ATOMIC = 0x0014,
CHUNK_GEOMETRYLIST = 0x001A,
CHUNK_GEOMETRYLIST = 0x001A,
CHUNK_BINMESHPLG = 0x050E,
CHUNK_BINMESHPLG = 0x050E,
CHUNK_NODENAME = 0x0253F2FE,
CHUNK_NODENAME = 0x0253F2FE,
};
// These structs are used to interpret raw bytes from the stream.
@ -34,439 +33,427 @@ typedef glm::vec3 BSTVector3;
typedef glm::mat3 BSTMatrix;
typedef glm::i8vec4 BSTColour;
struct RWBSFrame
{
BSTMatrix rotation;
BSTVector3 position;
int32_t index;
uint32_t matrixflags; // Not used
struct RWBSFrame {
BSTMatrix rotation;
BSTVector3 position;
int32_t index;
uint32_t matrixflags; // Not used
};
void LoaderDFF::readFrameList(Model *model, const RWBStream &stream)
{
auto listStream = stream.getInnerStream();
void LoaderDFF::readFrameList(Model *model, const RWBStream &stream) {
auto listStream = stream.getInnerStream();
auto listStructID = listStream.getNextChunk();
if( listStructID != CHUNK_STRUCT ) {
throw DFFLoaderException("Frame List missing struct chunk");
}
auto listStructID = listStream.getNextChunk();
if (listStructID != CHUNK_STRUCT) {
throw DFFLoaderException("Frame List missing struct chunk");
}
char* headerPtr = listStream.getCursor();
char *headerPtr = listStream.getCursor();
unsigned int numFrames = *(std::uint32_t*)headerPtr;
headerPtr += sizeof(std::uint32_t);
unsigned int numFrames = *(std::uint32_t *)headerPtr;
headerPtr += sizeof(std::uint32_t);
model->frames.reserve(numFrames);
model->frames.reserve(numFrames);
for( size_t f = 0; f < numFrames; ++f ) {
auto data = (RWBSFrame*)headerPtr;
headerPtr += sizeof(RWBSFrame);
for (size_t f = 0; f < numFrames; ++f) {
auto data = (RWBSFrame *)headerPtr;
headerPtr += sizeof(RWBSFrame);
ModelFrame* parent = nullptr;
if( data->index != -1 ) {
parent = model->frames[data->index];
}
else {
model->rootFrameIdx = f;
}
ModelFrame *parent = nullptr;
if (data->index != -1) {
parent = model->frames[data->index];
} else {
model->rootFrameIdx = f;
}
auto frame = new ModelFrame(f, parent, data->rotation, data->position);
model->frames.push_back(frame);
}
auto frame = new ModelFrame(f, parent, data->rotation, data->position);
model->frames.push_back(frame);
}
size_t namedFrames = 0;
size_t namedFrames = 0;
/// @todo perhaps flatten this out a little
for( auto chunkID = listStream.getNextChunk(); chunkID != 0; chunkID = listStream.getNextChunk() )
{
switch(chunkID) {
case CHUNK_EXTENSION: {
auto extStream = listStream.getInnerStream();
for( auto chunkID = extStream.getNextChunk(); chunkID != 0; chunkID = extStream.getNextChunk() )
{
switch( chunkID ) {
case CHUNK_NODENAME: {
std::string fname(extStream.getCursor(), extStream.getCurrentChunkSize());
std::transform(fname.begin(), fname.end(), fname.begin(), ::tolower );
/// @todo perhaps flatten this out a little
for (auto chunkID = listStream.getNextChunk(); chunkID != 0;
chunkID = listStream.getNextChunk()) {
switch (chunkID) {
case CHUNK_EXTENSION: {
auto extStream = listStream.getInnerStream();
for (auto chunkID = extStream.getNextChunk(); chunkID != 0;
chunkID = extStream.getNextChunk()) {
switch (chunkID) {
case CHUNK_NODENAME: {
std::string fname(extStream.getCursor(),
extStream.getCurrentChunkSize());
std::transform(fname.begin(), fname.end(),
fname.begin(), ::tolower);
if( namedFrames < model->frames.size() ) {
model->frames[namedFrames++]->setName(fname);
}
}
break;
default:
break;
}
}
}
break;
default:
break;
}
}
if (namedFrames < model->frames.size()) {
model->frames[namedFrames++]->setName(fname);
}
} break;
default:
break;
}
}
} break;
default:
break;
}
}
}
void LoaderDFF::readGeometryList(Model *model, const RWBStream &stream)
{
auto listStream = stream.getInnerStream();
void LoaderDFF::readGeometryList(Model *model, const RWBStream &stream) {
auto listStream = stream.getInnerStream();
auto listStructID = listStream.getNextChunk();
if( listStructID != CHUNK_STRUCT ) {
throw DFFLoaderException("Geometry List missing struct chunk");
}
auto listStructID = listStream.getNextChunk();
if (listStructID != CHUNK_STRUCT) {
throw DFFLoaderException("Geometry List missing struct chunk");
}
char* headerPtr = listStream.getCursor();
char *headerPtr = listStream.getCursor();
unsigned int numGeometries = *(std::uint32_t*)headerPtr;
headerPtr += sizeof(std::uint32_t);
unsigned int numGeometries = *(std::uint32_t *)headerPtr;
headerPtr += sizeof(std::uint32_t);
model->geometries.reserve(numGeometries);
model->geometries.reserve(numGeometries);
for( auto chunkID = listStream.getNextChunk(); chunkID != 0; chunkID = listStream.getNextChunk() )
{
switch(chunkID) {
case CHUNK_GEOMETRY:
readGeometry(model, listStream);
break;
default:
break;
}
}
for (auto chunkID = listStream.getNextChunk(); chunkID != 0;
chunkID = listStream.getNextChunk()) {
switch (chunkID) {
case CHUNK_GEOMETRY:
readGeometry(model, listStream);
break;
default:
break;
}
}
}
void LoaderDFF::readGeometry(Model *model, const RWBStream &stream)
{
auto geomStream = stream.getInnerStream();
void LoaderDFF::readGeometry(Model *model, const RWBStream &stream) {
auto geomStream = stream.getInnerStream();
auto geomStructID = geomStream.getNextChunk();
if( geomStructID != CHUNK_STRUCT ) {
throw DFFLoaderException("Geometry missing struct chunk");
}
auto geomStructID = geomStream.getNextChunk();
if (geomStructID != CHUNK_STRUCT) {
throw DFFLoaderException("Geometry missing struct chunk");
}
std::shared_ptr<Model::Geometry> geom(new Model::Geometry);
std::shared_ptr<Model::Geometry> geom(new Model::Geometry);
char* headerPtr = geomStream.getCursor();
char *headerPtr = geomStream.getCursor();
geom->flags = *(std::uint16_t*)headerPtr;
headerPtr += sizeof(std::uint16_t);
geom->flags = *(std::uint16_t *)headerPtr;
headerPtr += sizeof(std::uint16_t);
/*unsigned short numUVs = *(std::uint8_t*)headerPtr;*/
headerPtr += sizeof(std::uint8_t);
/*unsigned short moreFlags = *(std::uint8_t*)headerPtr;*/
headerPtr += sizeof(std::uint8_t);
/*unsigned short numUVs = *(std::uint8_t*)headerPtr;*/
headerPtr += sizeof(std::uint8_t);
/*unsigned short moreFlags = *(std::uint8_t*)headerPtr;*/
headerPtr += sizeof(std::uint8_t);
unsigned int numTris = *(std::uint32_t*)headerPtr;
headerPtr += sizeof(std::uint32_t);
unsigned int numVerts = *(std::uint32_t*)headerPtr;
headerPtr += sizeof(std::uint32_t);
/*unsigned int numFrames = *(std::uint32_t*)headerPtr;*/
headerPtr += sizeof(std::uint32_t);
unsigned int numTris = *(std::uint32_t *)headerPtr;
headerPtr += sizeof(std::uint32_t);
unsigned int numVerts = *(std::uint32_t *)headerPtr;
headerPtr += sizeof(std::uint32_t);
/*unsigned int numFrames = *(std::uint32_t*)headerPtr;*/
headerPtr += sizeof(std::uint32_t);
std::vector<Model::GeometryVertex> verts;
verts.resize(numVerts);
std::vector<Model::GeometryVertex> verts;
verts.resize(numVerts);
if( geomStream.getChunkVersion() < 0x1003FFFF ) {
headerPtr += sizeof(RW::BSGeometryColor);
}
if (geomStream.getChunkVersion() < 0x1003FFFF) {
headerPtr += sizeof(RW::BSGeometryColor);
}
/// @todo extract magic numbers.
/// @todo extract magic numbers.
if( (geom->flags & 8) == 8 ) {
for(size_t v = 0; v < numVerts; ++v) {
verts[v].colour = *(glm::u8vec4*)headerPtr;
headerPtr += sizeof(glm::u8vec4);
}
}
else {
for(size_t v = 0; v < numVerts; ++v) {
verts[v].colour = {255, 255, 255, 255};
}
}
if ((geom->flags & 8) == 8) {
for (size_t v = 0; v < numVerts; ++v) {
verts[v].colour = *(glm::u8vec4 *)headerPtr;
headerPtr += sizeof(glm::u8vec4);
}
} else {
for (size_t v = 0; v < numVerts; ++v) {
verts[v].colour = {255, 255, 255, 255};
}
}
if( (geom->flags & 4) == 4 || (geom->flags & 128) == 128) {
for(size_t v = 0; v < numVerts; ++v) {
verts[v].texcoord = *(glm::vec2*)headerPtr;
headerPtr += sizeof(glm::vec2);
}
}
if ((geom->flags & 4) == 4 || (geom->flags & 128) == 128) {
for (size_t v = 0; v < numVerts; ++v) {
verts[v].texcoord = *(glm::vec2 *)headerPtr;
headerPtr += sizeof(glm::vec2);
}
}
// Grab indicies data to generate normals (if applicable).
RW::BSGeometryTriangle* triangles = (RW::BSGeometryTriangle*)headerPtr;
headerPtr += sizeof(RW::BSGeometryTriangle) * numTris;
// Grab indicies data to generate normals (if applicable).
RW::BSGeometryTriangle *triangles = (RW::BSGeometryTriangle *)headerPtr;
headerPtr += sizeof(RW::BSGeometryTriangle) * numTris;
geom->geometryBounds = *(RW::BSGeometryBounds*)headerPtr;
geom->geometryBounds.radius = std::abs(geom->geometryBounds.radius);
headerPtr += sizeof(RW::BSGeometryBounds);
geom->geometryBounds = *(RW::BSGeometryBounds *)headerPtr;
geom->geometryBounds.radius = std::abs(geom->geometryBounds.radius);
headerPtr += sizeof(RW::BSGeometryBounds);
for(size_t v = 0; v < numVerts; ++v) {
verts[v].position = *(glm::vec3*)headerPtr;
headerPtr += sizeof(glm::vec3);
}
for (size_t v = 0; v < numVerts; ++v) {
verts[v].position = *(glm::vec3 *)headerPtr;
headerPtr += sizeof(glm::vec3);
}
if( (geom->flags & 16) == 16 ) {
for(size_t v = 0; v < numVerts; ++v) {
verts[v].normal = *(glm::vec3*)headerPtr;
headerPtr += sizeof(glm::vec3);
}
}
else {
// Use triangle data to calculate normals for each vert.
for (size_t t = 0; t < numTris; ++t) {
auto& triangle = triangles[t];
auto& A = verts[triangle.first];
auto& B = verts[triangle.second];
auto& C = verts[triangle.third];
auto normal = glm::normalize(glm::cross(C.position-A.position, B.position-A.position));
A.normal = normal;
B.normal = normal;
C.normal = normal;
}
}
if ((geom->flags & 16) == 16) {
for (size_t v = 0; v < numVerts; ++v) {
verts[v].normal = *(glm::vec3 *)headerPtr;
headerPtr += sizeof(glm::vec3);
}
} else {
// Use triangle data to calculate normals for each vert.
for (size_t t = 0; t < numTris; ++t) {
auto &triangle = triangles[t];
auto &A = verts[triangle.first];
auto &B = verts[triangle.second];
auto &C = verts[triangle.third];
auto normal = glm::normalize(
glm::cross(C.position - A.position, B.position - A.position));
A.normal = normal;
B.normal = normal;
C.normal = normal;
}
}
// Add the geometry to the model now so that it can be accessed.
model->geometries.push_back(geom);
// 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);
break;
case CHUNK_EXTENSION:
readGeometryExtension(model, geomStream);
break;
default:
break;
}
}
// Process the geometry child sections
for (auto chunkID = geomStream.getNextChunk(); chunkID != 0;
chunkID = geomStream.getNextChunk()) {
switch (chunkID) {
case CHUNK_MATERIALLIST:
readMaterialList(model, geomStream);
break;
case CHUNK_EXTENSION:
readGeometryExtension(model, geomStream);
break;
default:
break;
}
}
geom->dbuff.setFaceType(geom->facetype == Model::Triangles ?
GL_TRIANGLES : GL_TRIANGLE_STRIP);
geom->gbuff.uploadVertices(verts);
geom->dbuff.addGeometry(&geom->gbuff);
geom->dbuff.setFaceType(
geom->facetype == Model::Triangles ? GL_TRIANGLES : GL_TRIANGLE_STRIP);
geom->gbuff.uploadVertices(verts);
geom->dbuff.addGeometry(&geom->gbuff);
glGenBuffers(1, &geom->EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geom->EBO);
size_t icount = std::accumulate(geom->subgeom.begin(), geom->subgeom.end(),
0u,
[](size_t a, const Model::SubGeometry& b) {return a + b.numIndices;});
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * icount, 0, GL_STATIC_DRAW);
for(auto& sg : geom->subgeom) {
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,
sg.start * sizeof(uint32_t),
sizeof(uint32_t) * sg.numIndices,
sg.indices.data());
}
glGenBuffers(1, &geom->EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geom->EBO);
size_t icount = std::accumulate(
geom->subgeom.begin(), geom->subgeom.end(), 0u,
[](size_t a, const Model::SubGeometry &b) { return a + b.numIndices; });
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * icount, 0,
GL_STATIC_DRAW);
for (auto &sg : geom->subgeom) {
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sg.start * sizeof(uint32_t),
sizeof(uint32_t) * sg.numIndices, sg.indices.data());
}
}
void LoaderDFF::readMaterialList(Model *model, const RWBStream &stream)
{
auto listStream = stream.getInnerStream();
void LoaderDFF::readMaterialList(Model *model, const RWBStream &stream) {
auto listStream = stream.getInnerStream();
auto listStructID = listStream.getNextChunk();
if( listStructID != CHUNK_STRUCT ) {
throw DFFLoaderException("MaterialList missing struct chunk");
}
auto listStructID = listStream.getNextChunk();
if (listStructID != CHUNK_STRUCT) {
throw DFFLoaderException("MaterialList missing struct chunk");
}
unsigned int numMaterials = *(std::uint32_t*)listStream.getCursor();
unsigned int numMaterials = *(std::uint32_t *)listStream.getCursor();
model->geometries.back()->materials.reserve(numMaterials);
model->geometries.back()->materials.reserve(numMaterials);
RWBStream::ChunkID chunkID;
while( (chunkID = listStream.getNextChunk()) ) {
switch( chunkID ) {
case CHUNK_MATERIAL:
readMaterial(model, listStream);
break;
default:
break;
}
}
RWBStream::ChunkID chunkID;
while ((chunkID = listStream.getNextChunk())) {
switch (chunkID) {
case CHUNK_MATERIAL:
readMaterial(model, listStream);
break;
default:
break;
}
}
}
void LoaderDFF::readMaterial(Model *model, const RWBStream &stream)
{
auto materialStream = stream.getInnerStream();
void LoaderDFF::readMaterial(Model *model, const RWBStream &stream) {
auto materialStream = stream.getInnerStream();
auto matStructID = materialStream.getNextChunk();
if( matStructID != CHUNK_STRUCT ) {
throw DFFLoaderException("Material missing struct chunk");
}
auto matStructID = materialStream.getNextChunk();
if (matStructID != CHUNK_STRUCT) {
throw DFFLoaderException("Material missing struct chunk");
}
char* matData = materialStream.getCursor();
char *matData = materialStream.getCursor();
Model::Material material;
Model::Material material;
// Unkown
matData += sizeof(std::uint32_t);
material.colour = *(glm::u8vec4*)matData;
matData += sizeof(std::uint32_t);
// Unkown
matData += sizeof(std::uint32_t);
/*bool usesTexture = *(std::uint32_t*)matData;*/
matData += sizeof(std::uint32_t);
// Unkown
matData += sizeof(std::uint32_t);
material.colour = *(glm::u8vec4 *)matData;
matData += sizeof(std::uint32_t);
// Unkown
matData += sizeof(std::uint32_t);
/*bool usesTexture = *(std::uint32_t*)matData;*/
matData += sizeof(std::uint32_t);
material.ambientIntensity = *(float*)matData;
matData += sizeof(float);
/*float specular = *(float*)matData;*/
matData += sizeof(float);
material.diffuseIntensity = *(float*)matData;
matData += sizeof(float);
material.flags = 0;
material.ambientIntensity = *(float *)matData;
matData += sizeof(float);
/*float specular = *(float*)matData;*/
matData += sizeof(float);
material.diffuseIntensity = *(float *)matData;
matData += sizeof(float);
material.flags = 0;
model->geometries.back()->materials.push_back(material);
model->geometries.back()->materials.push_back(material);
RWBStream::ChunkID chunkID;
while( ( chunkID = materialStream.getNextChunk() ) ) {
switch( chunkID ) {
case CHUNK_TEXTURE:
readTexture(model, materialStream);
break;
default:
break;
}
}
RWBStream::ChunkID chunkID;
while ((chunkID = materialStream.getNextChunk())) {
switch (chunkID) {
case CHUNK_TEXTURE:
readTexture(model, materialStream);
break;
default:
break;
}
}
}
void LoaderDFF::readTexture(Model *model, const RWBStream &stream)
{
auto texStream = stream.getInnerStream();
void LoaderDFF::readTexture(Model *model, const RWBStream &stream) {
auto texStream = stream.getInnerStream();
auto texStructID = texStream.getNextChunk();
if( texStructID != CHUNK_STRUCT ) {
throw DFFLoaderException("Texture missing struct chunk");
}
auto texStructID = texStream.getNextChunk();
if (texStructID != CHUNK_STRUCT) {
throw DFFLoaderException("Texture missing struct chunk");
}
// There's some data in the Texture's struct, but we don't know what it is.
// There's some data in the Texture's struct, but we don't know what it is.
/// @todo improve how these strings are read.
std::string name, alpha;
/// @todo improve how these strings are read.
std::string name, alpha;
texStream.getNextChunk();
name = texStream.getCursor();
texStream.getNextChunk();
alpha = texStream.getCursor();
texStream.getNextChunk();
name = texStream.getCursor();
texStream.getNextChunk();
alpha = texStream.getCursor();
std::transform(name.begin(), name.end(), name.begin(), ::tolower );
std::transform(alpha.begin(), alpha.end(), alpha.begin(), ::tolower );
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
std::transform(alpha.begin(), alpha.end(), alpha.begin(), ::tolower);
model->geometries.back()->materials.back().textures.push_back({name, alpha, nullptr});
model->geometries.back()->materials.back().textures.push_back(
{name, alpha, nullptr});
}
void LoaderDFF::readGeometryExtension(Model *model, const RWBStream &stream)
{
auto extStream = stream.getInnerStream();
void LoaderDFF::readGeometryExtension(Model *model, const RWBStream &stream) {
auto extStream = stream.getInnerStream();
RWBStream::ChunkID chunkID;
while( (chunkID = extStream.getNextChunk()) ) {
switch( chunkID ) {
case CHUNK_BINMESHPLG:
readBinMeshPLG(model, extStream);
break;
default:
break;
}
}
RWBStream::ChunkID chunkID;
while ((chunkID = extStream.getNextChunk())) {
switch (chunkID) {
case CHUNK_BINMESHPLG:
readBinMeshPLG(model, extStream);
break;
default:
break;
}
}
}
void LoaderDFF::readBinMeshPLG(Model *model, const RWBStream &stream)
{
auto data = stream.getCursor();
void LoaderDFF::readBinMeshPLG(Model *model, const RWBStream &stream) {
auto data = stream.getCursor();
model->geometries.back()->facetype = static_cast<Model::FaceType>(
*(std::uint32_t*)data);
data += sizeof(std::uint32_t);
model->geometries.back()->facetype =
static_cast<Model::FaceType>(*(std::uint32_t *)data);
data += sizeof(std::uint32_t);
unsigned int numSplits = *(std::uint32_t*)data;
data += sizeof(std::uint32_t);
unsigned int numSplits = *(std::uint32_t *)data;
data += sizeof(std::uint32_t);
// Number of triangles.
data += sizeof(std::uint32_t);
// Number of triangles.
data += sizeof(std::uint32_t);
model->geometries.back()->subgeom.reserve(numSplits);
model->geometries.back()->subgeom.reserve(numSplits);
size_t start = 0;
size_t start = 0;
for(size_t s = 0; s < numSplits; ++s) {
Model::SubGeometry sg;
sg.numIndices = *(std::uint32_t*)data;
data += sizeof(std::uint32_t);
sg.material = *(std::uint32_t*)data;
data += sizeof(std::uint32_t);
sg.start = start;
start += sg.numIndices;
for (size_t s = 0; s < numSplits; ++s) {
Model::SubGeometry sg;
sg.numIndices = *(std::uint32_t *)data;
data += sizeof(std::uint32_t);
sg.material = *(std::uint32_t *)data;
data += sizeof(std::uint32_t);
sg.start = start;
start += sg.numIndices;
sg.indices.resize(sg.numIndices);
std::memcpy(sg.indices.data(), data, sizeof(std::uint32_t) * sg.numIndices);
data += sizeof(std::uint32_t) * sg.numIndices;
sg.indices.resize(sg.numIndices);
std::memcpy(sg.indices.data(), data,
sizeof(std::uint32_t) * sg.numIndices);
data += sizeof(std::uint32_t) * sg.numIndices;
model->geometries.back()->subgeom.push_back(sg);
}
model->geometries.back()->subgeom.push_back(sg);
}
}
void LoaderDFF::readAtomic(Model *model, const RWBStream &stream)
{
auto atomicStream = stream.getInnerStream();
void LoaderDFF::readAtomic(Model *model, const RWBStream &stream) {
auto atomicStream = stream.getInnerStream();
auto atomicStructID = atomicStream.getNextChunk();
if( atomicStructID != CHUNK_STRUCT ) {
throw DFFLoaderException("Atomic missing struct chunk");
}
auto atomicStructID = atomicStream.getNextChunk();
if (atomicStructID != CHUNK_STRUCT) {
throw DFFLoaderException("Atomic missing struct chunk");
}
Model::Atomic atom;
auto data = atomicStream.getCursor();
atom.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);
Model::Atomic atom;
auto data = atomicStream.getCursor();
atom.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);
/// @todo are any atomic extensions important?
/// @todo are any atomic extensions important?
}
Model* LoaderDFF::loadFromMemory(FileHandle file)
{
auto model = new Model;
Model *LoaderDFF::loadFromMemory(FileHandle file) {
auto model = new Model;
RWBStream rootStream(file->data, file->length);
RWBStream rootStream(file->data, file->length);
auto rootID = rootStream.getNextChunk();
if( rootID != CHUNK_CLUMP ) {
throw DFFLoaderException("Invalid root section ID " + std::to_string(rootID));
}
auto rootID = rootStream.getNextChunk();
if (rootID != CHUNK_CLUMP) {
throw DFFLoaderException("Invalid root section ID " +
std::to_string(rootID));
}
RWBStream modelStream = rootStream.getInnerStream();
auto rootStructID = modelStream.getNextChunk();
if( rootStructID != CHUNK_STRUCT ) {
throw DFFLoaderException("Clump missing struct chunk");
}
RWBStream modelStream = rootStream.getInnerStream();
auto rootStructID = modelStream.getNextChunk();
if (rootStructID != CHUNK_STRUCT) {
throw DFFLoaderException("Clump missing struct chunk");
}
// There is only one value in the struct section.
model->numAtomics = *(std::uint32_t*)rootStream.getCursor();
// There is only one value in the struct section.
model->numAtomics = *(std::uint32_t *)rootStream.getCursor();
// Process everything inside the clump stream.
RWBStream::ChunkID chunkID;
while( ( chunkID = modelStream.getNextChunk() ) ) {
switch( chunkID ) {
case CHUNK_FRAMELIST:
readFrameList(model, modelStream);
break;
case CHUNK_GEOMETRYLIST:
readGeometryList(model, modelStream);
break;
case CHUNK_ATOMIC:
readAtomic(model, modelStream);
break;
default:
break;
}
}
// Process everything inside the clump stream.
RWBStream::ChunkID chunkID;
while ((chunkID = modelStream.getNextChunk())) {
switch (chunkID) {
case CHUNK_FRAMELIST:
readFrameList(model, modelStream);
break;
case CHUNK_GEOMETRYLIST:
readGeometryList(model, modelStream);
break;
case CHUNK_ATOMIC:
readAtomic(model, modelStream);
break;
default:
break;
}
}
// Ensure the model has cached metrics
model->recalculateMetrics();
// Ensure the model has cached metrics
model->recalculateMetrics();
return model;
return model;
}

View File

@ -4,54 +4,52 @@
#include <loaders/RWBinaryStream.hpp>
#include <vector>
#include <string>
#include <platform/FileHandle.hpp>
#include <data/ResourceHandle.hpp>
#include <platform/FileHandle.hpp>
#include <string>
#include <vector>
class Model;
class GameData;
class DFFLoaderException
{
std::string _message;
class DFFLoaderException {
std::string _message;
public:
DFFLoaderException(const std::string& message) : _message(message) {
}
DFFLoaderException(const std::string& message)
: _message(message)
{}
const std::string& which() { return _message; }
const std::string& which() {
return _message;
}
};
class LoaderDFF
{
class LoaderDFF {
/**
* @brief loads a Frame List chunk from stream into model.
* @param model
* @param stream
*/
void readFrameList(Model* model, const RWBStream& stream);
/**
* @brief loads a Frame List chunk from stream into model.
* @param model
* @param stream
*/
void readFrameList(Model* model, const RWBStream &stream);
void readGeometryList(Model* model, const RWBStream& stream);
void readGeometryList(Model* model, const RWBStream& stream);
void readGeometry(Model* model, const RWBStream& stream);
void readGeometry(Model* model, const RWBStream& stream);
void readMaterialList(Model* model, const RWBStream& stream);
void readMaterialList(Model* model, const RWBStream& stream);
void readMaterial(Model* model, const RWBStream& stream);
void readMaterial(Model* model, const RWBStream& stream);
void readTexture(Model* model, const RWBStream& stream);
void readTexture(Model* model, const RWBStream& stream);
void readGeometryExtension(Model* model, const RWBStream& stream);
void readGeometryExtension(Model* model, const RWBStream& stream);
void readBinMeshPLG(Model* model, const RWBStream& stream);
void readBinMeshPLG(Model* model, const RWBStream& stream);
void readAtomic(Model* model, const RWBStream& stream);
void readAtomic(Model* model, const RWBStream& stream);
public:
Model* loadFromMemory(FileHandle file);
Model* loadFromMemory(FileHandle file);
};
#endif

View File

@ -2,128 +2,108 @@
#include <boost/algorithm/string/predicate.hpp>
LoaderIMG::LoaderIMG()
: m_version(GTAIIIVC)
, m_assetCount(0)
{
LoaderIMG::LoaderIMG() : m_version(GTAIIIVC), m_assetCount(0) {
}
bool LoaderIMG::load(const std::string& filename)
{
auto baseName = filename;
auto extpos = filename.find(".img");
if (extpos != std::string::npos)
{
baseName.erase(extpos);
}
auto dirName = baseName + ".dir";
auto imgName = baseName + ".img";
bool LoaderIMG::load(const std::string& filename) {
auto baseName = filename;
auto extpos = filename.find(".img");
if (extpos != std::string::npos) {
baseName.erase(extpos);
}
auto dirName = baseName + ".dir";
auto imgName = baseName + ".img";
FILE* fp = fopen(dirName.c_str(), "rb");
if(fp)
{
fseek(fp, 0, SEEK_END);
unsigned long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
FILE* fp = fopen(dirName.c_str(), "rb");
if (fp) {
fseek(fp, 0, SEEK_END);
unsigned long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
m_assetCount = fileSize / 32;
m_assets.resize(m_assetCount);
m_assetCount = fileSize / 32;
m_assets.resize(m_assetCount);
if ((m_assetCount = fread(&m_assets[0], sizeof(LoaderIMGFile), m_assetCount, fp)) != fileSize / 32) {
m_assets.resize(m_assetCount);
std::cout << "Error reading records in IMG archive" << std::endl;
}
if ((m_assetCount = fread(&m_assets[0], sizeof(LoaderIMGFile),
m_assetCount, fp)) != fileSize / 32) {
m_assets.resize(m_assetCount);
std::cout << "Error reading records in IMG archive" << std::endl;
}
fclose(fp);
m_archive = imgName;
return true;
}
else
{
return false;
}
fclose(fp);
m_archive = imgName;
return true;
} else {
return false;
}
}
/// Get the information of a asset in the examining archive
bool LoaderIMG::findAssetInfo(const std::string& assetname, LoaderIMGFile& out)
{
for(size_t i = 0; i < m_assets.size(); ++i)
{
if(boost::iequals(m_assets[i].name, assetname))
{
out = m_assets[i];
return true;
}
}
return false;
bool LoaderIMG::findAssetInfo(const std::string& assetname,
LoaderIMGFile& out) {
for (size_t i = 0; i < m_assets.size(); ++i) {
if (boost::iequals(m_assets[i].name, assetname)) {
out = m_assets[i];
return true;
}
}
return false;
}
char* LoaderIMG::loadToMemory(const std::string& assetname)
{
LoaderIMGFile assetInfo;
bool found = findAssetInfo(assetname, assetInfo);
char* LoaderIMG::loadToMemory(const std::string& assetname) {
LoaderIMGFile assetInfo;
bool found = findAssetInfo(assetname, assetInfo);
if (!found) {
std::cerr << "Asset '" << assetname << "' not found!" << std::endl;
return nullptr;
}
std::string imgName = m_archive;
if (!found) {
std::cerr << "Asset '" << assetname << "' not found!" << std::endl;
return nullptr;
}
FILE* fp = fopen(imgName.c_str(), "rb");
if(fp)
{
char* raw_data = new char[assetInfo.size * 2048];
std::string imgName = m_archive;
fseek(fp, assetInfo.offset * 2048, SEEK_SET);
if( fread(raw_data, 2048, assetInfo.size, fp) != assetInfo.size ) {
std::cerr << "Error reading asset " << assetInfo.name << std::endl;
}
FILE* fp = fopen(imgName.c_str(), "rb");
if (fp) {
char* raw_data = new char[assetInfo.size * 2048];
fclose(fp);
return raw_data;
}
else
return 0;
fseek(fp, assetInfo.offset * 2048, SEEK_SET);
if (fread(raw_data, 2048, assetInfo.size, fp) != assetInfo.size) {
std::cerr << "Error reading asset " << assetInfo.name << std::endl;
}
fclose(fp);
return raw_data;
} else
return 0;
}
/// Writes the contents of assetname to filename
bool LoaderIMG::saveAsset(const std::string& assetname, const std::string& filename)
{
char* raw_data = loadToMemory(assetname);
if(!raw_data)
return false;
bool LoaderIMG::saveAsset(const std::string& assetname,
const std::string& filename) {
char* raw_data = loadToMemory(assetname);
if (!raw_data) return false;
FILE* dumpFile = fopen(filename.c_str(), "wb");
if(dumpFile)
{
LoaderIMGFile asset;
if( findAssetInfo( assetname, asset ) )
{
fwrite(raw_data, 2048, asset.size, dumpFile);
printf("=> IMG: Saved %s to disk with filename %s\n", assetname.c_str(), filename.c_str());
}
fclose(dumpFile);
FILE* dumpFile = fopen(filename.c_str(), "wb");
if (dumpFile) {
LoaderIMGFile asset;
if (findAssetInfo(assetname, asset)) {
fwrite(raw_data, 2048, asset.size, dumpFile);
printf("=> IMG: Saved %s to disk with filename %s\n",
assetname.c_str(), filename.c_str());
}
fclose(dumpFile);
delete[] raw_data;
return true;
}
else
{
delete[] raw_data;
return false;
}
delete[] raw_data;
return true;
} else {
delete[] raw_data;
return false;
}
}
/// Get the information of an asset by its index
const LoaderIMGFile &LoaderIMG::getAssetInfoByIndex(size_t index) const
{
return m_assets[index];
const LoaderIMGFile& LoaderIMG::getAssetInfoByIndex(size_t index) const {
return m_assets[index];
}
uint32_t LoaderIMG::getAssetCount() const
{
return m_assetCount;
uint32_t LoaderIMG::getAssetCount() const {
return m_assetCount;
}

View File

@ -2,65 +2,63 @@
#ifndef _LOADERIMG_HPP_
#define _LOADERIMG_HPP_
#include <cstdint>
#include <iostream>
#include <vector>
#include <cstdint>
/// \brief Points to one file within the archive
class LoaderIMGFile
{
class LoaderIMGFile {
public:
uint32_t offset;
uint32_t size;
char name[24];
uint32_t offset;
uint32_t size;
char name[24];
};
/**
\class LoaderIMG
\brief Parses the structure of GTA .IMG archives and loads the files in it
\class LoaderIMG
\brief Parses the structure of GTA .IMG archives and loads the files in it
*/
class LoaderIMG
{
class LoaderIMG {
public:
/// Multiple versions of .IMG files
enum Versions
{
GTAIIIVC, ///< GTA III and GTA VC archives -- only this one is implemented
GTASA,
GTAIV
};
/// Multiple versions of .IMG files
enum Versions {
GTAIIIVC, ///< GTA III and GTA VC archives -- only this one is
///implemented
GTASA,
GTAIV
};
/// Construct
LoaderIMG();
/// Construct
LoaderIMG();
/// Load the structure of the archive
/// Omit the extension in filename so both .dir and .img are loaded when appropriate
bool load(const std::string& filename);
/// Load the structure of the archive
/// Omit the extension in filename so both .dir and .img are loaded when
/// appropriate
bool load(const std::string& filename);
/// Load a file from the archive to memory and pass a pointer to it
/// Warning: Please delete[] the memory in the end.
/// Warning: Returns NULL (0) if by any reason it can't load the file
char* loadToMemory(const std::string& assetname);
/// Load a file from the archive to memory and pass a pointer to it
/// Warning: Please delete[] the memory in the end.
/// Warning: Returns NULL (0) if by any reason it can't load the file
char* loadToMemory(const std::string& assetname);
/// Writes the contents of assetname to filename
bool saveAsset(const std::string& assetname, const std::string& filename);
/// Writes the contents of assetname to filename
bool saveAsset(const std::string& assetname, const std::string& filename);
/// Get the information of an asset in the examining archive
bool findAssetInfo(const std::string& assetname, LoaderIMGFile& out);
/// Get the information of an asset in the examining archive
bool findAssetInfo(const std::string& assetname, LoaderIMGFile& out);
/// Get the information of an asset by its index
const LoaderIMGFile &getAssetInfoByIndex(size_t index) const;
/// Get the information of an asset by its index
const LoaderIMGFile& getAssetInfoByIndex(size_t index) const;
/// Returns the number of asset files in the archive
uint32_t getAssetCount() const;
/// Returns the number of asset files in the archive
uint32_t getAssetCount() const;
private:
Versions m_version; ///< Version of this IMG archive
uint32_t m_assetCount; ///< Number of assets in the current archive
std::string m_archive; ///< Path to the archive being used (no extension)
Versions m_version; ///< Version of this IMG archive
uint32_t m_assetCount; ///< Number of assets in the current archive
std::string m_archive; ///< Path to the archive being used (no extension)
std::vector<LoaderIMGFile> m_assets; ///< Asset info of the archive
std::vector<LoaderIMGFile> m_assets; ///< Asset info of the archive
};
#endif // LoaderIMG_h__
#endif // LoaderIMG_h__

View File

@ -3,155 +3,148 @@
#include <cstring>
#include <string>
LoaderSDT::LoaderSDT()
: m_version(GTAIIIVC)
, m_assetCount(0)
{
}
LoaderSDT::LoaderSDT() : m_version(GTAIIIVC), m_assetCount(0) {
}
typedef struct {
char chunkId[4];
uint32_t chunkSize;
char format[4];
struct {
char id[4];
uint32_t size;
uint16_t audioFormat;
uint16_t numChannels;
uint32_t sampleRate;
uint32_t byteRate;
uint16_t blockAlign;
uint16_t bitsPerSample;
} fmt;
struct {
char id[4];
uint32_t size;
} data;
char chunkId[4];
uint32_t chunkSize;
char format[4];
struct {
char id[4];
uint32_t size;
uint16_t audioFormat;
uint16_t numChannels;
uint32_t sampleRate;
uint32_t byteRate;
uint16_t blockAlign;
uint16_t bitsPerSample;
} fmt;
struct {
char id[4];
uint32_t size;
} data;
} WaveHeader;
bool LoaderSDT::load(const std::string& filename)
{
auto baseName = filename;
auto sdtName = baseName + ".SDT";
auto rawName = baseName + ".RAW";
bool LoaderSDT::load(const std::string& filename) {
auto baseName = filename;
auto sdtName = baseName + ".SDT";
auto rawName = baseName + ".RAW";
FILE* fp = fopen(sdtName.c_str(), "rb");
if (fp) {
fseek(fp, 0, SEEK_END);
unsigned long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
FILE* fp = fopen(sdtName.c_str(), "rb");
if (fp) {
fseek(fp, 0, SEEK_END);
unsigned long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
m_assetCount = fileSize / 20;
m_assets.resize(m_assetCount);
m_assetCount = fileSize / 20;
m_assets.resize(m_assetCount);
if ((m_assetCount = fread(&m_assets[0], sizeof(LoaderSDTFile), m_assetCount, fp)) != fileSize / 20) {
m_assets.resize(m_assetCount);
std::cout << "Error reading records in SDT archive" << std::endl;
}
if ((m_assetCount = fread(&m_assets[0], sizeof(LoaderSDTFile),
m_assetCount, fp)) != fileSize / 20) {
m_assets.resize(m_assetCount);
std::cout << "Error reading records in SDT archive" << std::endl;
}
fclose(fp);
m_archive = rawName;
return true;
} else {
return false;
}
fclose(fp);
m_archive = rawName;
return true;
} else {
return false;
}
}
/// Get the information of a asset in the examining archive
bool LoaderSDT::findAssetInfo(size_t index, LoaderSDTFile& out)
{
if (index < m_assets.size()) {
out = m_assets[index];
return true;
}
return false;
bool LoaderSDT::findAssetInfo(size_t index, LoaderSDTFile& out) {
if (index < m_assets.size()) {
out = m_assets[index];
return true;
}
return false;
}
char* LoaderSDT::loadToMemory(size_t index, bool asWave)
{
LoaderSDTFile assetInfo;
bool found = findAssetInfo(index, assetInfo);
char* LoaderSDT::loadToMemory(size_t index, bool asWave) {
LoaderSDTFile assetInfo;
bool found = findAssetInfo(index, assetInfo);
if(!found) {
std::cerr << "Asset " << std::to_string(index) << " not found!" << std::endl;
return nullptr;
}
if (!found) {
std::cerr << "Asset " << std::to_string(index) << " not found!"
<< std::endl;
return nullptr;
}
std::string rawName = m_archive;
std::string rawName = m_archive;
FILE* fp = fopen(rawName.c_str(), "rb");
if (fp) {
char* raw_data;
char* sample_data;
if (asWave) {
raw_data = new char[sizeof(WaveHeader) + assetInfo.size];
FILE* fp = fopen(rawName.c_str(), "rb");
if (fp) {
char* raw_data;
char* sample_data;
if (asWave) {
raw_data = new char[sizeof(WaveHeader) + assetInfo.size];
WaveHeader* header = reinterpret_cast<WaveHeader*>(raw_data);
memcpy(header->chunkId, "RIFF", 4);
header->chunkSize = sizeof(WaveHeader) - 8 + assetInfo.size;
memcpy(header->format, "WAVE", 4);
memcpy(header->fmt.id, "fmt ", 4);
header->fmt.size = sizeof(WaveHeader::fmt) - 8;
header->fmt.audioFormat = 1; // PCM
header->fmt.numChannels = 1; // Mono
header->fmt.sampleRate = assetInfo.sampleRate;
header->fmt.byteRate = assetInfo.sampleRate * 2;
header->fmt.blockAlign = 2;
header->fmt.bitsPerSample = 16;
memcpy(header->data.id, "data", 4);
header->data.size = assetInfo.size;
WaveHeader* header = reinterpret_cast<WaveHeader*>(raw_data);
memcpy(header->chunkId, "RIFF", 4);
header->chunkSize = sizeof(WaveHeader) - 8 + assetInfo.size;
memcpy(header->format, "WAVE", 4);
memcpy(header->fmt.id, "fmt ", 4);
header->fmt.size = sizeof(WaveHeader::fmt) - 8;
header->fmt.audioFormat = 1; // PCM
header->fmt.numChannels = 1; // Mono
header->fmt.sampleRate = assetInfo.sampleRate;
header->fmt.byteRate = assetInfo.sampleRate * 2;
header->fmt.blockAlign = 2;
header->fmt.bitsPerSample = 16;
memcpy(header->data.id, "data", 4);
header->data.size = assetInfo.size;
sample_data = raw_data + sizeof(WaveHeader);
} else {
raw_data = new char[assetInfo.size];
sample_data = raw_data;
}
sample_data = raw_data + sizeof(WaveHeader);
} else {
raw_data = new char[assetInfo.size];
sample_data = raw_data;
}
fseek(fp, assetInfo.offset, SEEK_SET);
if (fread(sample_data, 1, assetInfo.size, fp) != assetInfo.size) {
std::cerr << "Error reading asset " << std::to_string(index) << std::endl;
}
fseek(fp, assetInfo.offset, SEEK_SET);
if (fread(sample_data, 1, assetInfo.size, fp) != assetInfo.size) {
std::cerr << "Error reading asset " << std::to_string(index)
<< std::endl;
}
fclose(fp);
return raw_data;
}
else
return 0;
fclose(fp);
return raw_data;
} else
return 0;
}
/// Writes the contents of assetname to filename
bool LoaderSDT::saveAsset(size_t index, const std::string& filename, bool asWave)
{
char* raw_data = loadToMemory(index, asWave);
if(!raw_data)
return false;
bool LoaderSDT::saveAsset(size_t index, const std::string& filename,
bool asWave) {
char* raw_data = loadToMemory(index, asWave);
if (!raw_data) return false;
FILE* dumpFile = fopen(filename.c_str(), "wb");
if(dumpFile) {
LoaderSDTFile asset;
if(findAssetInfo(index, asset)) {
fwrite(raw_data, 1, asset.size + (asWave ? sizeof(WaveHeader) : 0), dumpFile);
printf("=> SDT: Saved %zu to disk with filename %s\n", index, filename.c_str());
}
fclose(dumpFile);
FILE* dumpFile = fopen(filename.c_str(), "wb");
if (dumpFile) {
LoaderSDTFile asset;
if (findAssetInfo(index, asset)) {
fwrite(raw_data, 1, asset.size + (asWave ? sizeof(WaveHeader) : 0),
dumpFile);
printf("=> SDT: Saved %zu to disk with filename %s\n", index,
filename.c_str());
}
fclose(dumpFile);
delete[] raw_data;
return true;
} else {
delete[] raw_data;
return false;
}
delete[] raw_data;
return true;
} else {
delete[] raw_data;
return false;
}
}
/// Get the information of an asset by its index
const LoaderSDTFile &LoaderSDT::getAssetInfoByIndex(size_t index) const
{
return m_assets[index];
const LoaderSDTFile& LoaderSDT::getAssetInfoByIndex(size_t index) const {
return m_assets[index];
}
uint32_t LoaderSDT::getAssetCount() const
{
return m_assetCount;
uint32_t LoaderSDT::getAssetCount() const {
return m_assetCount;
}

View File

@ -2,66 +2,67 @@
#ifndef _LOADERSDT_HPP_
#define _LOADERSDT_HPP_
#include <cstdint>
#include <iostream>
#include <vector>
#include <cstdint>
/// \brief Points to one file within the archive
class LoaderSDTFile
{
class LoaderSDTFile {
public:
uint32_t offset; // offset of audio file in sfx.raw
uint32_t size; // size of audio file in bytes
uint32_t sampleRate; // the speed of audio
uint32_t loopStart; /// loop start, where looping would begin relative to audio file's position, 0 for beginning of audio file
uint32_t loopEnd; /// where looping would end relative to audio file's position, -1 for end of audio file
uint32_t offset; // offset of audio file in sfx.raw
uint32_t size; // size of audio file in bytes
uint32_t sampleRate; // the speed of audio
uint32_t loopStart; /// loop start, where looping would begin relative to
/// audio file's position, 0 for beginning of audio
/// file
uint32_t loopEnd; /// where looping would end relative to audio file's
/// position, -1 for end of audio file
};
/**
\class LoaderSDT
\brief Parses the structure of GTA .SDT archives and loads the files in it
\class LoaderSDT
\brief Parses the structure of GTA .SDT archives and loads the files in it
*/
class LoaderSDT
{
class LoaderSDT {
public:
/// Multiple versions of .SDT files
enum Versions
{
GTA2,
GTAIIIVC ///< GTA III and GTA VC archives -- only this one is implemented
};
/// Multiple versions of .SDT files
enum Versions {
GTA2,
GTAIIIVC ///< GTA III and GTA VC archives -- only this one is
///implemented
};
/// Construct
LoaderSDT();
/// Construct
LoaderSDT();
/// Load the structure of the archive
/// Omit the extension in filename
bool load(const std::string& filename);
/// Load the structure of the archive
/// Omit the extension in filename
bool load(const std::string& filename);
/// Load a file from the archive to memory and pass a pointer to it
/// Warning: Please delete[] the memory in the end.
/// Warning: Returns NULL (0) if by any reason it can't load the file
char* loadToMemory(size_t index, bool asWave = true);
/// Load a file from the archive to memory and pass a pointer to it
/// Warning: Please delete[] the memory in the end.
/// Warning: Returns NULL (0) if by any reason it can't load the file
char* loadToMemory(size_t index, bool asWave = true);
/// Writes the contents of index to filename
bool saveAsset(size_t index, const std::string& filename, bool asWave = true);
/// Writes the contents of index to filename
bool saveAsset(size_t index, const std::string& filename,
bool asWave = true);
/// Get the information of an asset in the examining archive
bool findAssetInfo(size_t index, LoaderSDTFile& out);
/// Get the information of an asset in the examining archive
bool findAssetInfo(size_t index, LoaderSDTFile& out);
/// Get the information of an asset by its index
const LoaderSDTFile &getAssetInfoByIndex(size_t index) const;
/// Get the information of an asset by its index
const LoaderSDTFile& getAssetInfoByIndex(size_t index) const;
/// Returns the number of asset files in the archive
uint32_t getAssetCount() const;
/// Returns the number of asset files in the archive
uint32_t getAssetCount() const;
private:
Versions m_version; ///< Version of this SDT archive
uint32_t m_assetCount; ///< Number of assets in the current archive
std::string m_archive; ///< Path to the archive being used (no extension)
Versions m_version; ///< Version of this SDT archive
uint32_t m_assetCount; ///< Number of assets in the current archive
std::string m_archive; ///< Path to the archive being used (no extension)
std::vector<LoaderSDTFile> m_assets; ///< Asset info of the archive
std::vector<LoaderSDTFile> m_assets; ///< Asset info of the archive
};
#endif // LoaderSDT_h__
#endif // LoaderSDT_h__

View File

@ -1,226 +1,214 @@
#include <loaders/LoaderTXD.hpp>
#include <gl/TextureData.hpp>
#include <loaders/LoaderTXD.hpp>
#include <iostream>
#include <algorithm>
#include <iostream>
GLuint gErrorTextureData[] = { 0xFFFF00FF, 0xFF000000, 0xFF000000, 0xFFFF00FF };
GLuint gErrorTextureData[] = {0xFFFF00FF, 0xFF000000, 0xFF000000, 0xFFFF00FF};
GLuint gDebugTextureData[] = {0xFF0000FF, 0xFF00FF00};
GLuint gTextureRed[] = {0xFF0000FF};
GLuint gTextureGreen[] = {0xFF00FF00};
GLuint gTextureBlue[] = {0xFFFF0000};
TextureData::Handle getErrorTexture()
{
static GLuint errTexName = 0;
static TextureData::Handle tex;
if(errTexName == 0)
{
glGenTextures(1, &errTexName);
glBindTexture(GL_TEXTURE_2D, errTexName);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
2, 2, 0,
GL_RGBA, GL_UNSIGNED_BYTE, gErrorTextureData
);
glGenerateMipmap(GL_TEXTURE_2D);
TextureData::Handle getErrorTexture() {
static GLuint errTexName = 0;
static TextureData::Handle tex;
if (errTexName == 0) {
glGenTextures(1, &errTexName);
glBindTexture(GL_TEXTURE_2D, errTexName);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA,
GL_UNSIGNED_BYTE, gErrorTextureData);
glGenerateMipmap(GL_TEXTURE_2D);
tex = TextureData::create(errTexName, {2, 2}, false);
}
return tex;
tex = TextureData::create(errTexName, {2, 2}, false);
}
return tex;
}
const size_t paletteSize = 1024;
void processPalette(uint32_t* fullColor, RW::BinaryStreamSection& rootSection)
{
uint8_t* dataBase = reinterpret_cast<uint8_t*>(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) - 4);
void processPalette(uint32_t* fullColor, RW::BinaryStreamSection& rootSection) {
uint8_t* dataBase = reinterpret_cast<uint8_t*>(
rootSection.raw() + sizeof(RW::BSSectionHeader) +
sizeof(RW::BSTextureNative) - 4);
uint8_t* coldata = (dataBase + paletteSize + sizeof(uint32_t));
uint32_t raster_size = *reinterpret_cast<uint32_t*>(dataBase + paletteSize);
uint32_t* palette = reinterpret_cast<uint32_t*>(dataBase);
for(size_t j = 0; j < raster_size; ++j)
{
*(fullColor++) = palette[coldata[j]];
}
uint8_t* coldata = (dataBase + paletteSize + sizeof(uint32_t));
uint32_t raster_size = *reinterpret_cast<uint32_t*>(dataBase + paletteSize);
uint32_t* palette = reinterpret_cast<uint32_t*>(dataBase);
for (size_t j = 0; j < raster_size; ++j) {
*(fullColor++) = palette[coldata[j]];
}
}
TextureData::Handle createTexture(RW::BSTextureNative& texNative, RW::BinaryStreamSection& rootSection)
{
// TODO: Exception handling.
if(texNative.platform != 8) {
std::cerr << "Unsupported texture platform " << std::dec << texNative.platform << std::endl;
return getErrorTexture();
}
TextureData::Handle createTexture(RW::BSTextureNative& texNative,
RW::BinaryStreamSection& rootSection) {
// TODO: Exception handling.
if (texNative.platform != 8) {
std::cerr << "Unsupported texture platform " << std::dec
<< texNative.platform << std::endl;
return getErrorTexture();
}
bool isPal8 = (texNative.rasterformat & RW::BSTextureNative::FORMAT_EXT_PAL8) == RW::BSTextureNative::FORMAT_EXT_PAL8;
bool isFulc = texNative.rasterformat == RW::BSTextureNative::FORMAT_1555 ||
texNative.rasterformat == RW::BSTextureNative::FORMAT_8888 ||
texNative.rasterformat == RW::BSTextureNative::FORMAT_888;
// Export this value
bool transparent = !((texNative.rasterformat&RW::BSTextureNative::FORMAT_888) == RW::BSTextureNative::FORMAT_888);
bool isPal8 =
(texNative.rasterformat & RW::BSTextureNative::FORMAT_EXT_PAL8) ==
RW::BSTextureNative::FORMAT_EXT_PAL8;
bool isFulc = texNative.rasterformat == RW::BSTextureNative::FORMAT_1555 ||
texNative.rasterformat == RW::BSTextureNative::FORMAT_8888 ||
texNative.rasterformat == RW::BSTextureNative::FORMAT_888;
// Export this value
bool transparent =
!((texNative.rasterformat & RW::BSTextureNative::FORMAT_888) ==
RW::BSTextureNative::FORMAT_888);
if(! (isPal8 || isFulc)) {
std::cerr << "Unsuported raster format " << std::dec << texNative.rasterformat << std::endl;
return getErrorTexture();
}
if (!(isPal8 || isFulc)) {
std::cerr << "Unsuported raster format " << std::dec
<< texNative.rasterformat << std::endl;
return getErrorTexture();
}
GLuint textureName = 0;
GLuint textureName = 0;
if(isPal8)
{
std::vector<uint32_t> fullColor(texNative.width * texNative.height);
if (isPal8) {
std::vector<uint32_t> fullColor(texNative.width * texNative.height);
processPalette(fullColor.data(), rootSection);
processPalette(fullColor.data(), rootSection);
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
texNative.width, texNative.height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, fullColor.data()
);
}
else if(isFulc)
{
auto coldata = rootSection.raw() + sizeof(RW::BSTextureNative);
coldata += sizeof(uint32_t);
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texNative.width,
texNative.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
fullColor.data());
} else if (isFulc) {
auto coldata = rootSection.raw() + sizeof(RW::BSTextureNative);
coldata += sizeof(uint32_t);
GLenum type = GL_UNSIGNED_BYTE, format = GL_RGBA;
switch(texNative.rasterformat)
{
case RW::BSTextureNative::FORMAT_1555:
format = GL_RGBA;
type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
break;
case RW::BSTextureNative::FORMAT_8888:
format = GL_BGRA;
//type = GL_UNSIGNED_INT_8_8_8_8_REV;
coldata += 8;
type = GL_UNSIGNED_BYTE;
break;
case RW::BSTextureNative::FORMAT_888:
format = GL_BGRA;
type = GL_UNSIGNED_BYTE;
break;
default:
break;
}
GLenum type = GL_UNSIGNED_BYTE, format = GL_RGBA;
switch (texNative.rasterformat) {
case RW::BSTextureNative::FORMAT_1555:
format = GL_RGBA;
type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
break;
case RW::BSTextureNative::FORMAT_8888:
format = GL_BGRA;
// type = GL_UNSIGNED_INT_8_8_8_8_REV;
coldata += 8;
type = GL_UNSIGNED_BYTE;
break;
case RW::BSTextureNative::FORMAT_888:
format = GL_BGRA;
type = GL_UNSIGNED_BYTE;
break;
default:
break;
}
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
texNative.width, texNative.height, 0,
format, type, coldata
);
}
else {
return getErrorTexture();
}
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texNative.width,
texNative.height, 0, format, type, coldata);
} else {
return getErrorTexture();
}
GLenum texFilter = GL_LINEAR;
switch(texNative.filterflags & 0xFF) {
default:
case RW::BSTextureNative::FILTER_LINEAR:
texFilter = GL_LINEAR;
break;
case RW::BSTextureNative::FILTER_NEAREST:
texFilter = GL_NEAREST;
break;
}
GLenum texFilter = GL_LINEAR;
switch (texNative.filterflags & 0xFF) {
default:
case RW::BSTextureNative::FILTER_LINEAR:
texFilter = GL_LINEAR;
break;
case RW::BSTextureNative::FILTER_NEAREST:
texFilter = GL_NEAREST;
break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texFilter);
GLenum texwrap = GL_REPEAT;
switch(texNative.wrapU) {
default:
case RW::BSTextureNative::WRAP_WRAP:
texwrap = GL_REPEAT;
break;
case RW::BSTextureNative::WRAP_CLAMP:
texwrap = GL_CLAMP_TO_EDGE;
break;
case RW::BSTextureNative::WRAP_MIRROR:
texwrap = GL_MIRRORED_REPEAT;
break;
}
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texwrap );
GLenum texwrap = GL_REPEAT;
switch (texNative.wrapU) {
default:
case RW::BSTextureNative::WRAP_WRAP:
texwrap = GL_REPEAT;
break;
case RW::BSTextureNative::WRAP_CLAMP:
texwrap = GL_CLAMP_TO_EDGE;
break;
case RW::BSTextureNative::WRAP_MIRROR:
texwrap = GL_MIRRORED_REPEAT;
break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texwrap);
switch(texNative.wrapV) {
default:
case RW::BSTextureNative::WRAP_WRAP:
texwrap = GL_REPEAT;
break;
case RW::BSTextureNative::WRAP_CLAMP:
texwrap = GL_CLAMP_TO_EDGE;
break;
case RW::BSTextureNative::WRAP_MIRROR:
texwrap = GL_MIRRORED_REPEAT;
break;
}
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texwrap );
switch (texNative.wrapV) {
default:
case RW::BSTextureNative::WRAP_WRAP:
texwrap = GL_REPEAT;
break;
case RW::BSTextureNative::WRAP_CLAMP:
texwrap = GL_CLAMP_TO_EDGE;
break;
case RW::BSTextureNative::WRAP_MIRROR:
texwrap = GL_MIRRORED_REPEAT;
break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texwrap);
glGenerateMipmap(GL_TEXTURE_2D);
glGenerateMipmap(GL_TEXTURE_2D);
return TextureData::create( textureName, { texNative.width, texNative.height }, transparent );
return TextureData::create(textureName, {texNative.width, texNative.height},
transparent);
}
bool TextureLoader::loadFromMemory(FileHandle file, TextureArchive &inTextures)
{
auto data = file->data;
RW::BinaryStreamSection root(data);
/*auto texDict =*/ root.readStructure<RW::BSTextureDictionary>();
bool TextureLoader::loadFromMemory(FileHandle file,
TextureArchive& inTextures) {
auto data = file->data;
RW::BinaryStreamSection root(data);
/*auto texDict =*/root.readStructure<RW::BSTextureDictionary>();
size_t rootI = 0;
while (root.hasMoreData(rootI)) {
auto rootSection = root.getNextChildSection(rootI);
size_t rootI = 0;
while (root.hasMoreData(rootI)) {
auto rootSection = root.getNextChildSection(rootI);
if (rootSection.header.id != RW::SID_TextureNative)
continue;
if (rootSection.header.id != RW::SID_TextureNative) continue;
RW::BSTextureNative texNative = rootSection.readStructure<RW::BSTextureNative>();
std::string name = std::string(texNative.diffuseName);
std::string alpha = std::string(texNative.alphaName);
std::transform(name.begin(), name.end(), name.begin(), ::tolower );
std::transform(alpha.begin(), alpha.end(), alpha.begin(), ::tolower );
RW::BSTextureNative texNative =
rootSection.readStructure<RW::BSTextureNative>();
std::string name = std::string(texNative.diffuseName);
std::string alpha = std::string(texNative.alphaName);
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
std::transform(alpha.begin(), alpha.end(), alpha.begin(), ::tolower);
auto texture = createTexture(texNative, rootSection);
auto texture = createTexture(texNative, rootSection);
inTextures[{name, alpha}] = texture;
inTextures[{name, alpha}] = texture;
if( !alpha.empty() ) {
inTextures[{name, ""}] = texture;
}
}
if (!alpha.empty()) {
inTextures[{name, ""}] = texture;
}
}
return true;
return true;
}
// TODO Move the Job system out of the loading code
#include <platform/FileIndex.hpp>
LoadTextureArchiveJob::LoadTextureArchiveJob(WorkContext *context, FileIndex* index, TextureArchive &inTextures, const std::string &file)
: WorkJob(context)
, archive(inTextures)
, fileIndex(index)
, _file(file)
{
LoadTextureArchiveJob::LoadTextureArchiveJob(WorkContext* context,
FileIndex* index,
TextureArchive& inTextures,
const std::string& file)
: WorkJob(context), archive(inTextures), fileIndex(index), _file(file) {
}
void LoadTextureArchiveJob::work()
{
data = fileIndex->openFile(_file);
void LoadTextureArchiveJob::work() {
data = fileIndex->openFile(_file);
}
void LoadTextureArchiveJob::complete()
{
// TODO error status
if(data) {
TextureLoader loader;
loader.loadFromMemory(data, archive);
}
void LoadTextureArchiveJob::complete() {
// TODO error status
if (data) {
TextureLoader loader;
loader.loadFromMemory(data, archive);
}
}

View File

@ -4,39 +4,40 @@
#include <loaders/RWBinaryStream.hpp>
#include <job/WorkContext.hpp>
#include <platform/FileHandle.hpp>
#include <functional>
#include <string>
#include <job/WorkContext.hpp>
#include <map>
#include <platform/FileHandle.hpp>
#include <string>
// This might suffice
#include <gl/TextureData.hpp>
typedef std::map<std::pair<std::string, std::string>, TextureData::Handle> TextureArchive;
typedef std::map<std::pair<std::string, std::string>, TextureData::Handle>
TextureArchive;
class FileIndex;
class TextureLoader
{
class TextureLoader {
public:
bool loadFromMemory(FileHandle file, TextureArchive& inTextures);
bool loadFromMemory(FileHandle file, TextureArchive& inTextures);
};
// TODO: refactor this interface to be more like ModelLoader so they can be rolled into one.
class LoadTextureArchiveJob : public WorkJob
{
// TODO: refactor this interface to be more like ModelLoader so they can be
// rolled into one.
class LoadTextureArchiveJob : public WorkJob {
private:
TextureArchive& archive;
FileIndex* fileIndex;
std::string _file;
FileHandle data;
TextureArchive& archive;
FileIndex* fileIndex;
std::string _file;
FileHandle data;
public:
LoadTextureArchiveJob(WorkContext* context, FileIndex* index,
TextureArchive& inTextures, const std::string& file);
LoadTextureArchiveJob(WorkContext* context, FileIndex* index, TextureArchive& inTextures, const std::string& file);
void work();
void work();
void complete();
void complete();
};
#endif

View File

@ -3,8 +3,8 @@
#include <cstdint>
#include <glm/glm.hpp>
#include <cstddef>
#include <cassert>
#include <cstddef>
/**
* @brief Class for working with RenderWare binary streams.
@ -13,371 +13,339 @@
* child chunks (in particular, the "struct" chunk which is used to store
* data relating to the parent chunk).
*/
class RWBStream
{
char* _data;
std::ptrdiff_t _size;
char* _dataCur;
char* _nextChunk;
std::uint32_t _chunkVersion;
std::ptrdiff_t _currChunkSz;
class RWBStream {
char* _data;
std::ptrdiff_t _size;
char* _dataCur;
char* _nextChunk;
std::uint32_t _chunkVersion;
std::ptrdiff_t _currChunkSz;
public:
typedef std::uint32_t ChunkID;
typedef std::uint32_t ChunkID;
RWBStream(char* data, size_t size)
: _data(data), _size(size), _dataCur(data), _nextChunk(data) {
}
RWBStream(char* data, size_t size)
: _data(data), _size(size), _dataCur(data), _nextChunk(data)
{}
/**
* Moves the stream to the next chunk and returns it's ID
*/
ChunkID getNextChunk() {
// Check that there's any data left
if ((_dataCur - _data) >= _size) return 0;
/**
* Moves the stream to the next chunk and returns it's ID
*/
ChunkID getNextChunk()
{
// Check that there's any data left
if((_dataCur - _data) >= _size ) return 0;
// _nextChunk is initally = to _data, making this a non-op
_dataCur = _nextChunk;
// _nextChunk is initally = to _data, making this a non-op
_dataCur = _nextChunk;
ChunkID id = *(ChunkID*)(_dataCur);
_dataCur += sizeof(ChunkID);
_currChunkSz = *(std::uint32_t*)(_dataCur);
_dataCur += sizeof(std::uint32_t);
_chunkVersion = *(std::uint32_t*)(_dataCur);
_dataCur += sizeof(std::uint32_t);
ChunkID id = *(ChunkID*)(_dataCur);
_dataCur += sizeof(ChunkID);
_currChunkSz = *(std::uint32_t*)(_dataCur);
_dataCur += sizeof(std::uint32_t);
_chunkVersion = *(std::uint32_t*)(_dataCur);
_dataCur += sizeof(std::uint32_t);
_nextChunk = _dataCur + _currChunkSz;
_nextChunk = _dataCur + _currChunkSz;
return id;
}
return id;
}
char* getCursor() const {
return _dataCur;
}
char* getCursor() const
{
return _dataCur;
}
size_t getCurrentChunkSize() const {
return _currChunkSz;
}
size_t getCurrentChunkSize() const
{
return _currChunkSz;
}
std::uint32_t getChunkVersion() const {
return _chunkVersion;
}
std::uint32_t getChunkVersion() const
{
return _chunkVersion;
}
/**
* @brief Returns a new stream for the data inside this one.
*/
RWBStream getInnerStream() const
{
return RWBStream(_dataCur, _currChunkSz);
}
/**
* @brief Returns a new stream for the data inside this one.
*/
RWBStream getInnerStream() const {
return RWBStream(_dataCur, _currChunkSz);
}
};
/**
* @file rwbinarystream.h
* @file rwbinarystream.h
* Deprecated RenderWare binary stream interface.
* Contains the structs for the shared Render Ware binary stream data.
* Many thanks to http://www.gtamodding.com/index.php?title=RenderWare_binary_stream_file
* Many thanks to
* http://www.gtamodding.com/index.php?title=RenderWare_binary_stream_file
*/
namespace RW
{
enum {
SID_Struct = 0x0001,
SID_String = 0x0002,
SID_Extension = 0x0003,
SID_Texture = 0x0006,
SID_Material = 0x0007,
SID_MaterialList = 0x0008,
SID_FrameList = 0x000E,
SID_Geometry = 0x000F,
SID_Clump = 0x0010,
SID_Atomic = 0x0014,
SID_TextureNative = 0x0015,
SID_TextureDictionary = 0x0016,
SID_GeometryList = 0x001A,
SID_HAnimPLG = 0x011E,
SID_BinMeshPLG = 0x50E,
SID_NodeName = 0x0253F2FE
};
namespace RW {
enum {
SID_Struct = 0x0001,
SID_String = 0x0002,
SID_Extension = 0x0003,
typedef glm::vec3 BSTVector3;
SID_Texture = 0x0006,
SID_Material = 0x0007,
SID_MaterialList = 0x0008,
typedef glm::mat3 BSTMatrix;
SID_FrameList = 0x000E,
SID_Geometry = 0x000F,
SID_Clump = 0x0010,
struct BSSectionHeader
{
uint32_t id;
uint32_t size;
uint32_t versionid;
};
struct BSExtension
{
};
struct BSFrameList
{
uint32_t numframes;
};
SID_Atomic = 0x0014,
SID_TextureNative = 0x0015,
SID_TextureDictionary = 0x0016,
struct BSClump
{
uint32_t numatomics;
};
struct BSStruct
{
uint32_t id; // = 0x0001
};
struct BSGeometryList
{
uint32_t numgeometry;
};
struct BSGeometry
{
uint16_t flags;
uint8_t numuvs;
uint8_t geomflags;
uint32_t numtris;
uint32_t numverts;
uint32_t numframes;
enum {
IsTriangleStrip = 0x1,
VertexTranslation = 0x2,
TexCoords1 = 0x4,
VertexColors = 0x8,
StoreNormals = 0x16,
DynamicVertexLighting = 0x32,
ModuleMaterialColor = 0x64,
TexCoords2 = 0x128
};
};
typedef glm::u8vec4 BSColor;
struct BSGeometryColor
{
BSColor ambient;
BSColor diffuse;
BSColor specular;
};
struct BSGeometryUV
{
float u;
float v;
};
struct BSGeometryTriangle
{
uint16_t first;
uint16_t second;
uint16_t attrib; // Who designed this nonsense.
uint16_t third;
};
struct BSGeometryBounds
{
BSTVector3 center;
float radius;
uint32_t positions;
uint32_t normals;
};
struct BSMaterialList
{
uint32_t nummaterials;
};
struct BSMaterial
{
uint32_t unknown;
BSColor color;
uint32_t alsounknown;
uint32_t numtextures;
float ambient;
float specular;
float diffuse;
};
struct BSTexture
{
uint16_t filterflags;
uint16_t unknown;
};
struct BSBinMeshPLG
{
uint32_t facetype;
uint32_t numsplits;
uint32_t numfaces;
};
struct BSMaterialSplit
{
uint32_t numverts;
uint32_t index;
};
/**
* Texture Dictionary Structures (TXD)
*/
struct BSTextureDictionary
{
uint16_t numtextures;
uint16_t unknown;
};
struct BSTextureNative
{
uint32_t platform;
uint16_t filterflags;
uint8_t wrapV;
uint8_t wrapU;
char diffuseName[32];
char alphaName[32];
uint32_t rasterformat;
uint32_t alpha;
uint16_t width;
uint16_t height;
uint8_t bpp;
uint8_t nummipmaps;
uint8_t rastertype;
uint8_t dxttype;
uint32_t datasize;
enum {
FILTER_NONE = 0x0,
FILTER_NEAREST = 0x01,
FILTER_LINEAR = 0x02,
FILTER_MIP_NEAREST = 0x03,
FILTER_MIP_LINEAR = 0x04,
FILTER_LINEAR_MIP_NEAREST = 0x05,
FILTER_LINEAR_MIP_LINEAR = 0x06,
FILTER_MYSTERY_OPTION = 0x1101
};
enum {
WRAP_NONE = 0x00,
WRAP_WRAP = 0x01,
WRAP_MIRROR = 0x02,
WRAP_CLAMP = 0x03
};
enum {
FORMAT_DEFAULT = 0x0000, // helpful
FORMAT_1555 = 0x0100, // Alpha 1, RGB 5 b
FORMAT_565 = 0x0200, // 5r6g5b
FORMAT_4444 = 0x0300, // 4 bits each
FORMAT_LUM8 = 0x0400, // Greyscale
FORMAT_8888 = 0x0500, // 8 bits each
FORMAT_888 = 0x0600, // RGB 8 bits each
FORMAT_555 = 0x0A00, // do not use
FORMAT_EXT_AUTO_MIPMAP = 0x1000, // Generate mipmaps
FORMAT_EXT_PAL8 = 0x2000, // 256 colour palette
FORMAT_EXT_PAL4 = 0x4000, // 16 color palette
FORMAT_EXT_MIPMAP = 0x8000 // Mipmaps included
};
};
struct BSPaletteData
{
uint32_t palette[256];
uint32_t rastersize;
};
/**
* Structure object
*/
class BinaryStreamSection
{
public:
/**
* Data pointer
*/
char* data;
/**
* Offset of this section in the data
*/
size_t offset;
/**
* The BSSectionHeader for the section
*/
BSSectionHeader header;
/**
* Structure header
*/
BSSectionHeader* structure;
BinaryStreamSection(char* data, size_t offset = 0)
: data(data), offset(offset), structure(nullptr)
{
header = *reinterpret_cast<BSSectionHeader*>(data+offset);
if(header.size > sizeof(structure))
{
structure = reinterpret_cast<BSSectionHeader*>(data+offset+sizeof(BSSectionHeader));
if(structure->id != SID_Struct)
{
structure = nullptr;
}
}
}
template<class T> T readStructure()
{
return *reinterpret_cast<T*>(data+offset+sizeof(BSSectionHeader)*2);
}
template<class T> T& readSubStructure(size_t internalOffset)
{
return *reinterpret_cast<T*>(data+offset+sizeof(BSSectionHeader)+internalOffset);
}
template<class T> T readRaw(size_t internalOffset)
{
return *reinterpret_cast<T*>(data+offset+internalOffset);
}
char* raw()
{
return data + offset + sizeof(BSSectionHeader);
}
bool hasMoreData(size_t length)
{
return (length) < (header.size);
}
BinaryStreamSection getNextChildSection(size_t& internalOffset)
{
size_t realOffset = internalOffset;
assert(realOffset < header.size);
BinaryStreamSection sec(data, offset + sizeof(BSSectionHeader) + realOffset);
internalOffset += sec.header.size + sizeof(BSSectionHeader);
return sec;
}
};
SID_GeometryList = 0x001A,
SID_HAnimPLG = 0x011E,
SID_BinMeshPLG = 0x50E,
SID_NodeName = 0x0253F2FE
};
typedef glm::vec3 BSTVector3;
typedef glm::mat3 BSTMatrix;
struct BSSectionHeader {
uint32_t id;
uint32_t size;
uint32_t versionid;
};
struct BSExtension {};
struct BSFrameList {
uint32_t numframes;
};
struct BSClump {
uint32_t numatomics;
};
struct BSStruct {
uint32_t id; // = 0x0001
};
struct BSGeometryList {
uint32_t numgeometry;
};
struct BSGeometry {
uint16_t flags;
uint8_t numuvs;
uint8_t geomflags;
uint32_t numtris;
uint32_t numverts;
uint32_t numframes;
enum {
IsTriangleStrip = 0x1,
VertexTranslation = 0x2,
TexCoords1 = 0x4,
VertexColors = 0x8,
StoreNormals = 0x16,
DynamicVertexLighting = 0x32,
ModuleMaterialColor = 0x64,
TexCoords2 = 0x128
};
};
typedef glm::u8vec4 BSColor;
struct BSGeometryColor {
BSColor ambient;
BSColor diffuse;
BSColor specular;
};
struct BSGeometryUV {
float u;
float v;
};
struct BSGeometryTriangle {
uint16_t first;
uint16_t second;
uint16_t attrib; // Who designed this nonsense.
uint16_t third;
};
struct BSGeometryBounds {
BSTVector3 center;
float radius;
uint32_t positions;
uint32_t normals;
};
struct BSMaterialList {
uint32_t nummaterials;
};
struct BSMaterial {
uint32_t unknown;
BSColor color;
uint32_t alsounknown;
uint32_t numtextures;
float ambient;
float specular;
float diffuse;
};
struct BSTexture {
uint16_t filterflags;
uint16_t unknown;
};
struct BSBinMeshPLG {
uint32_t facetype;
uint32_t numsplits;
uint32_t numfaces;
};
struct BSMaterialSplit {
uint32_t numverts;
uint32_t index;
};
/**
* Texture Dictionary Structures (TXD)
*/
struct BSTextureDictionary {
uint16_t numtextures;
uint16_t unknown;
};
struct BSTextureNative {
uint32_t platform;
uint16_t filterflags;
uint8_t wrapV;
uint8_t wrapU;
char diffuseName[32];
char alphaName[32];
uint32_t rasterformat;
uint32_t alpha;
uint16_t width;
uint16_t height;
uint8_t bpp;
uint8_t nummipmaps;
uint8_t rastertype;
uint8_t dxttype;
uint32_t datasize;
enum {
FILTER_NONE = 0x0,
FILTER_NEAREST = 0x01,
FILTER_LINEAR = 0x02,
FILTER_MIP_NEAREST = 0x03,
FILTER_MIP_LINEAR = 0x04,
FILTER_LINEAR_MIP_NEAREST = 0x05,
FILTER_LINEAR_MIP_LINEAR = 0x06,
FILTER_MYSTERY_OPTION = 0x1101
};
enum {
WRAP_NONE = 0x00,
WRAP_WRAP = 0x01,
WRAP_MIRROR = 0x02,
WRAP_CLAMP = 0x03
};
enum {
FORMAT_DEFAULT = 0x0000, // helpful
FORMAT_1555 = 0x0100, // Alpha 1, RGB 5 b
FORMAT_565 = 0x0200, // 5r6g5b
FORMAT_4444 = 0x0300, // 4 bits each
FORMAT_LUM8 = 0x0400, // Greyscale
FORMAT_8888 = 0x0500, // 8 bits each
FORMAT_888 = 0x0600, // RGB 8 bits each
FORMAT_555 = 0x0A00, // do not use
FORMAT_EXT_AUTO_MIPMAP = 0x1000, // Generate mipmaps
FORMAT_EXT_PAL8 = 0x2000, // 256 colour palette
FORMAT_EXT_PAL4 = 0x4000, // 16 color palette
FORMAT_EXT_MIPMAP = 0x8000 // Mipmaps included
};
};
struct BSPaletteData {
uint32_t palette[256];
uint32_t rastersize;
};
/**
* Structure object
*/
class BinaryStreamSection {
public:
/**
* Data pointer
*/
char* data;
/**
* Offset of this section in the data
*/
size_t offset;
/**
* The BSSectionHeader for the section
*/
BSSectionHeader header;
/**
* Structure header
*/
BSSectionHeader* structure;
BinaryStreamSection(char* data, size_t offset = 0)
: data(data), offset(offset), structure(nullptr) {
header = *reinterpret_cast<BSSectionHeader*>(data + offset);
if (header.size > sizeof(structure)) {
structure = reinterpret_cast<BSSectionHeader*>(
data + offset + sizeof(BSSectionHeader));
if (structure->id != SID_Struct) {
structure = nullptr;
}
}
}
template <class T>
T readStructure() {
return *reinterpret_cast<T*>(data + offset +
sizeof(BSSectionHeader) * 2);
}
template <class T>
T& readSubStructure(size_t internalOffset) {
return *reinterpret_cast<T*>(data + offset + sizeof(BSSectionHeader) +
internalOffset);
}
template <class T>
T readRaw(size_t internalOffset) {
return *reinterpret_cast<T*>(data + offset + internalOffset);
}
char* raw() {
return data + offset + sizeof(BSSectionHeader);
}
bool hasMoreData(size_t length) {
return (length) < (header.size);
}
BinaryStreamSection getNextChildSection(size_t& internalOffset) {
size_t realOffset = internalOffset;
assert(realOffset < header.size);
BinaryStreamSection sec(data,
offset + sizeof(BSSectionHeader) + realOffset);
internalOffset += sec.header.size + sizeof(BSSectionHeader);
return sec;
}
};
}
#endif