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:
parent
94cc76d36a
commit
981d68713b
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user