1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-15 06:52:34 +02:00

Initial engine framework

This commit is contained in:
Daniel Evans 2013-07-02 07:06:03 +01:00
parent 92c8f6a10c
commit c214f07c2b
17 changed files with 1391 additions and 71 deletions

View File

@ -1,3 +1,20 @@
add_library(renderware BinaryStream.cpp TextureArchive.cpp )
add_library(renderware
# RenderWare related
BinaryStream.cpp
TextureArchive.cpp
LoaderDFF.cpp
TextureLoader.cpp
# Game data related
LoaderCOL.cpp
LoaderIMG.cpp
LoaderIPL.cpp
GTAData.cpp
GTAEngine.cpp
)
target_link_libraries(renderware sfml-window)
include_directories(include)

150
framework2/GTAData.cpp Normal file
View File

@ -0,0 +1,150 @@
#include "engine/GTAData.h"
#include "loaders/LoaderIPL.h"
#include <loaders/LoaderDFF.h>
#include <iostream>
#include <fstream>
#include <bits/algorithmfwd.h>
GTAData::GTAData(const std::string& path)
: datpath(path)
{
}
void GTAData::load()
{
std::ifstream datfile((datpath+"/data/gta3.dat").c_str());
if(!datfile.is_open())
{
std::cerr << "Failed to open gta.dat" << std::endl;
}
else
{
for(std::string line, cmd; std::getline(datfile, line);)
{
if(line.size() == 0 || line[0] == '#') continue;
line.erase(line.size()-1);
size_t space = line.find_first_of(' ');
if(space != line.npos)
{
cmd = line.substr(0, space);
if(cmd == "IDE")
{
loadIDE(line.substr(space+1));
}
else if(cmd == "SPLASH")
{
splash = line.substr(space+1);
}
else if(cmd == "COLFILE")
{
int zone = atoi(line.substr(space+1,1).c_str());
std::string file = line.substr(space+3);
loadCOL(zone, file);
}
else if(cmd == "IPL")
{
loadIPL(line.substr(space+1));
}
}
}
}
}
void GTAData::loadIDE(const std::string& name)
{
std::cout << "IDE File " << name << std::endl;
}
void GTAData::loadCOL(const size_t zone, const std::string& name)
{
std::cout << "COL File " << name << " for zone " << zone << std::endl;
}
void GTAData::loadIMG(const std::string& name)
{
LoaderIMG imgLoader;
std::string archivePath = datpath + name;
if (imgLoader.load(archivePath)) {
for (int i = 0; i < imgLoader.getAssetCount(); i++) {
auto &asset = imgLoader.getAssetInfoByIndex(i);
std::string filename = asset.name;
if(asset.size == 0)
{
std::cerr << "Asset " << filename << " has no size, ignoring." << std::endl;
}
else
{
// Load TXDs immediatley
auto filetype = filename.substr(filename.size() - 3);
for(size_t t = 0; t < filetype.size(); ++t)
{
filetype[t] = tolower(filetype[t]);
}
if (filetype == "txd")
{
char *file = imgLoader.loadToMemory(filename);
if(file) {
textureLoader.loadFromMemory(file);
}
}
else if(filetype == "dff")
{
std::string modelname = filename.substr(0, filename.size() - 4);
char *file = imgLoader.loadToMemory(filename);
if(file)
{
LoaderDFF dffLoader;
models[modelname] = std::move(dffLoader.loadFromMemory(file));
delete[] file;
}
}
else
{
fileLocations.insert({ filename, { true, archivePath }});
}
}
}
std::cout << "Archive loaded" << std::endl;
archives.insert({name, imgLoader});
std::cout << "Archive copied" << std::endl;
}
}
char* GTAData::loadFile(const std::string& name)
{
auto i = fileLocations.find(name);
if(i != fileLocations.end())
{
if(i->second.archived)
{
// Find the archive
auto ai = archives.find(i->second.path);
if(ai != archives.end())
{
return ai->second.loadToMemory(name);
}
}
else
{
std::cerr << "Cannot load unarchived files yet" << std::endl;
}
}
return nullptr;
}
void GTAData::loadIPL(const std::string& name)
{
std::string lowername = name;
for(size_t t = 0; t < lowername.size(); ++t)
{
lowername[t] = tolower(lowername[t]);
}
iplLocations.insert({lowername, datpath + "/" + lowername});
}

46
framework2/GTAEngine.cpp Normal file
View File

@ -0,0 +1,46 @@
#include "engine/GTAEngine.h"
#include "loaders/LoaderIPL.h"
GTAEngine::GTAEngine(const std::string& path)
: gameData(path)
{
}
bool GTAEngine::load()
{
gameData.load();
return true;
}
bool GTAEngine::loadItems(const std::string& name)
{
auto i = gameData.iplLocations.find(name);
std::string path = name;
if(i != gameData.iplLocations.end())
{
path = i->second;
}
else
{
std::cout << "IPL not pre-listed" << std::endl;
}
LoaderIPL ipll;
if(ipll.load(path))
{
instances.insert(instances.end(), ipll.m_instances.begin(), ipll.m_instances.end());
itemCentroid += ipll.centroid;
return true;
}
else
{
std::cerr << "Failed to load IPL: " << path << std::endl;
return false;
}
return false;
}

84
framework2/LoaderCOL.cpp Normal file
View File

@ -0,0 +1,84 @@
#include "loaders/LoaderCOL.h"
#include <string>
#include <fstream>
template<class T> T readType(char* data, size_t* offset)
{
size_t orgoff = *offset; *offset += sizeof(T);
return *reinterpret_cast<T*>(data+orgoff);
}
bool LoaderCOL::load(const std::string& file)
{
std::ifstream dfile(file.c_str());
if ( ! dfile.is_open()) {
return false;
}
dfile.seekg(0, std::ios_base::end);
size_t length = dfile.tellg();
dfile.seekg(0);
char* data = new char[length];
dfile.read(data, length);
char* dataptr = data;
int version = 1;
std::string verstr(dataptr, 4);
if(verstr == "COLL")
{
}
else if(verstr == "COL2")
{
version = 2;
}
else if(verstr == "COL3")
{
version = 3;
}
size_t dataI = 4;
auto filesize = readType<uint32_t>(data, &dataI);
CollTHeader head = readType<CollTHeader>(data, &dataI);
CollTHeaderV2 head2;
CollTHeaderV3 head3;
if(version >= 2)
{
head2 = readType<CollTHeaderV2>(data, &dataI);
if(version >= 3)
{
head3 = readType<CollTHeaderV3>(data, &dataI);
}
}
if(version == 1)
{
head2.numspheres = readType<uint32_t>(data, &dataI);
head2.offsetspheres = dataI-4;
}
// Read spheres
dataI += sizeof(CollTSphere) * head2.numspheres;
if(version == 1)
{
// skip unused bytes
dataI += sizeof(uint32_t);
}
if(version == 1)
{
head2.numboxes = readType<uint32_t>(data, &dataI);
head2.offsetboxes = dataI-4;
}
dataI += sizeof(CollTBox) * head2.numboxes;
if(version == 1)
{
uint32_t numverts = readType<uint32_t>(data, &dataI);
dataI += sizeof(CollTVertex) * numverts;
}
return true;
}

232
framework2/LoaderDFF.cpp Normal file
View File

@ -0,0 +1,232 @@
#include "loaders/LoaderDFF.h"
#include <iostream>
std::unique_ptr<Model> LoaderDFF::loadFromMemory(char *data)
{
auto model = std::unique_ptr<Model>(new Model);
RW::BinaryStreamSection root(data);
model->clump = root.readStructure<RW::BSClump>();
size_t dataI = 0;
while (root.hasMoreData(dataI)) {
auto sec = root.getNextChildSection(dataI);
switch (sec.header.id) {
case RW::SID_GeometryList: {
auto list = sec.readStructure<RW::BSGeometryList>();
size_t gdataI = 0;
while (sec.hasMoreData(gdataI)) {
Model::Geometry geometryStruct;
auto item = sec.getNextChildSection(gdataI);
if (item.header.id == RW::SID_Geometry) {
size_t dataI = 0, secI = 0;
auto geometry = item.readStructure<RW::BSGeometry>();
// std::cout << " verts(" << geometry.numverts << ") tris(" << geometry.numtris << ")" << std::endl;
item.getNextChildSection(secI);
char *data = item.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSGeometry);
if (item.header.versionid < 0x1003FFFF)
auto colors = readStructure<RW::BSGeometryColor>(data, dataI);
if ((geometry.flags & RW::BSGeometry::VertexColors) == RW::BSGeometry::VertexColors) {
for (size_t v = 0; v < geometry.numverts; ++v) {
readStructure<RW::BSColor>(data, dataI);
}
}
/** TEX COORDS **/
if ((geometry.flags & RW::BSGeometry::TexCoords1) == RW::BSGeometry::TexCoords1 ||
(geometry.flags & RW::BSGeometry::TexCoords2) == RW::BSGeometry::TexCoords1) {
for (size_t v = 0; v < geometry.numverts; ++v) {
geometryStruct.texcoords.push_back(readStructure<RW::BSGeometryUV>(data, dataI));
}
}
/** INDICIES **/
for (int j = 0; j < geometry.numtris; ++j) {
geometryStruct.triangles.push_back(readStructure<RW::BSGeometryTriangle>(data, dataI));
}
/** GEOMETRY BOUNDS **/
geometryStruct.geometryBounds = readStructure<RW::BSGeometryBounds>(data, dataI);
/** VERTICES **/
for (int v = 0; v < geometry.numverts; ++v) {
geometryStruct.vertices.push_back(readStructure<RW::BSTVector3>(data, dataI));
}
/** NORMALS **/
if ((geometry.flags & RW::BSGeometry::StoreNormals) == RW::BSGeometry::StoreNormals) {
for (int n = 0; n < geometry.numverts; ++n) {
geometryStruct.normals.push_back(readStructure<RW::BSTVector3>(data, dataI));
}
}
/** TEXTURES **/
auto materiallistsec = item.getNextChildSection(secI);
auto materialList = materiallistsec.readStructure<RW::BSMaterialList>();
// Skip over the per-material byte values that I don't know what do.
dataI += sizeof(uint32_t) * materialList.nummaterials;
size_t matI = 0;
materiallistsec.getNextChildSection(matI);
geometryStruct.materials.resize(materialList.nummaterials);
for (size_t m = 0; m < materialList.nummaterials; ++m) {
auto materialsec = materiallistsec.getNextChildSection(matI);
if (materialsec.header.id != RW::SID_Material)
continue;
auto material = materialsec.readStructure<RW::BSMaterial>();
geometryStruct.materials[m].textures.resize(material.numtextures);
size_t texI = 0;
materialsec.getNextChildSection(texI);
for (size_t t = 0; t < material.numtextures; ++t) {
auto texsec = materialsec.getNextChildSection(texI);
auto texture = texsec.readStructure<RW::BSTexture>();
std::string textureName, alphaName;
size_t yetAnotherI = 0;
texsec.getNextChildSection(yetAnotherI);
auto namesec = texsec.getNextChildSection(yetAnotherI);
auto alphasec = texsec.getNextChildSection(yetAnotherI);
// The data is null terminated anyway.
textureName = namesec.raw();
alphaName = alphasec.raw();
geometryStruct.materials[m].textures[t] = {textureName, alphaName};
}
}
if(item.hasMoreData(secI))
{
auto extensions = item.getNextChildSection(secI);
size_t extI = 0;
while(extensions.hasMoreData(extI))
{
auto extsec = extensions.getNextChildSection(extI);
if(extsec.header.id == RW::SID_BinMeshPLG)
{
auto meshplg = extsec.readSubStructure<RW::BSBinMeshPLG>(0);
geometryStruct.subgeom.resize(meshplg.numsplits);
size_t meshplgI = sizeof(RW::BSBinMeshPLG);
for(size_t i = 0; i < meshplg.numsplits; ++i)
{
auto plgHeader = extsec.readSubStructure<RW::BSMaterialSplit>(meshplgI);
meshplgI += sizeof(RW::BSMaterialSplit);
geometryStruct.subgeom[i].material = plgHeader.index;
geometryStruct.subgeom[i].indices.resize(plgHeader.numverts);
for (int j = 0; j < plgHeader.numverts; ++j) {
geometryStruct.subgeom[i].indices[j] = extsec.readSubStructure<uint32_t>(meshplgI);
meshplgI += sizeof(uint32_t);
}
}
}
}
}
// OpenGL buffer stuff
glGenBuffers(1, &geometryStruct.VBO);
glGenBuffers(1, &geometryStruct.EBO);
for(size_t i = 0; i < geometryStruct.subgeom.size(); ++i)
{
glGenBuffers(1, &(geometryStruct.subgeom[i].EBO));
}
size_t buffsize = (geometryStruct.vertices.size() * sizeof(float) * 3)
+ (geometryStruct.texcoords.size() * sizeof(float) * 2)
+ (geometryStruct.normals.size() * sizeof(float) * 3);
// Vertices
glBindBuffer(GL_ARRAY_BUFFER, geometryStruct.VBO);
glBufferData(GL_ARRAY_BUFFER, buffsize, NULL, GL_STATIC_DRAW);
glBufferSubData(
GL_ARRAY_BUFFER,
0,
(geometryStruct.vertices.size() * sizeof(float) * 3),
&geometryStruct.vertices[0]
);
if(geometryStruct.texcoords.size() > 0)
{
glBufferSubData(
GL_ARRAY_BUFFER,
(geometryStruct.vertices.size() * sizeof(float) * 3),
(geometryStruct.texcoords.size() * sizeof(float) * 2),
&geometryStruct.texcoords[0]
);
}
if(geometryStruct.normals.size() > 0 )
{
glBufferSubData(
GL_ARRAY_BUFFER,
(geometryStruct.vertices.size() * sizeof(float) * 3) + (geometryStruct.texcoords.size() * sizeof(float) * 2),
geometryStruct.normals.size() * 3 * sizeof(float),
&geometryStruct.normals[0]
);
}
// Elements
uint16_t indicies[geometryStruct.triangles.size() * 3];
size_t i = 0;
for (auto &tri : geometryStruct.triangles) {
indicies[i] = tri.first;
indicies[i + 1] = tri.second;
indicies[i + 2] = tri.third;
i += 3;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometryStruct.EBO);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(indicies),
indicies,
GL_STATIC_DRAW
);
for(size_t i = 0; i < geometryStruct.subgeom.size(); ++i)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometryStruct.subgeom[i].EBO);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(uint32_t) * geometryStruct.subgeom[i].indices.size(),
&(geometryStruct.subgeom[i].indices[0]),
GL_STATIC_DRAW
);
}
// Add it
model->geometries.push_back(geometryStruct);
}
}
}
}
}
return model;
}
template<class T> T LoaderDFF::readStructure(char *data, size_t &dataI)
{
size_t originalOffset = dataI;
dataI += sizeof(T);
return *reinterpret_cast<T*>(data + originalOffset);
}
RW::BSSectionHeader LoaderDFF::readHeader(char *data, size_t &dataI)
{
return readStructure<RW::BSSectionHeader>(data, dataI);
}

121
framework2/LoaderIMG.cpp Normal file
View File

@ -0,0 +1,121 @@
#include "loaders/LoaderIMG.h"
#include <cstring>
LoaderIMG::LoaderIMG()
: m_version(GTAIIIVC)
, m_assetCount(0)
{
}
bool LoaderIMG::load(const std::string& filename)
{
std::string dirName = filename;
dirName.append(".dir");
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_assets.resize(fileSize / 32);
m_assetCount = fileSize / 32;
fread(&m_assets[0], sizeof(LoaderIMGFile), fileSize / 32, fp);
fclose(fp);
m_archive = filename;
return true;
}
else
return false;
}
/// Get the information of a asset in the examining archive
LoaderIMGFile &LoaderIMG::getAssetInfo(const std::string& assetname)
{
for(size_t i = 0; i < m_assets.size(); ++i)
{
if(strcmp(m_assets[i].name, assetname.c_str()) == 0)
{
return m_assets[i];
}
}
}
char* LoaderIMG::loadToMemory(const std::string& assetname)
{
LoaderIMGFile assetInfo;
bool found = false;
for(size_t i = 0; i < m_assets.size(); ++i)
{
if(strcmp(m_assets[i].name, assetname.c_str()) == 0)
{
assetInfo = m_assets[i];
found = true;
}
}
if(!found)
{
std::cerr << "Asset '" << assetname << "' not found!" << std::endl;
return 0;
}
std::string dirName = m_archive;
dirName.append(".img");
FILE* fp = fopen(dirName.c_str(), "rb");
if(fp)
{
char* raw_data = new char[assetInfo.size * 2048];
fseek(fp, assetInfo.offset * 2048, SEEK_SET);
fread(raw_data, 2048, assetInfo.size, fp);
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;
FILE* dumpFile = fopen(filename.c_str(), "wb");
if(dumpFile)
{
fwrite(raw_data, getAssetInfo(assetname).size * 2048, 1, dumpFile);
fclose(dumpFile);
printf("=> IMG: Saved %s to disk with filename %s\n", assetname.c_str(), filename.c_str());
delete[] raw_data;
return true;
}
else
{
delete[] raw_data;
return false;
}
}
/// Get the information of an asset by its index
LoaderIMGFile &LoaderIMG::getAssetInfoByIndex(size_t index)
{
return m_assets[index];
}
uint32_t LoaderIMG::getAssetCount()
{
return m_assetCount;
}

117
framework2/LoaderIPL.cpp Normal file
View File

@ -0,0 +1,117 @@
#include "loaders/LoaderIPL.h"
#include <fstream>
#include <string>
#include <sstream>
#include <algorithm>
enum SectionTypes
{
INST,
PICK,
CULL,
ZONE,
NONE
};
/// Load the IPL data into memory
bool LoaderIPL::load(const std::string& filename)
{
std::ifstream str(filename);
if(!str.is_open())
return false;
SectionTypes section = NONE;
while(!str.eof())
{
std::string line;
getline(str, line);
line.erase(std::find_if(line.rbegin(), line.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), line.end());
if(!line.empty() && line[0] == '#')
{
// nothing, just a comment
}
else if(line == "end") // terminating a section
{
section = NONE;
}
else if(section == NONE) // starting a new section
{
if(line == "inst")
{
section = INST;
}
if(line == "pick")
{
section = PICK;
}
if(line == "cull")
{
section = CULL;
}
if(line == "zone")
{
section = ZONE;
}
}
else // regular entry
{
if(section == INST)
{
LoaderIPLInstance instance;
std::string id;
std::string model;
std::string posX, posY, posZ;
std::string scaleX, scaleY, scaleZ;
std::string rotX, rotY, rotZ, rotW;
std::stringstream strstream(line);
// read all the contents of the line
getline(strstream, id, ',');
getline(strstream, model, ',');
getline(strstream, posX, ',');
getline(strstream, posY, ',');
getline(strstream, posZ, ',');
getline(strstream, scaleX, ',');
getline(strstream, scaleY, ',');
getline(strstream, scaleZ, ',');
getline(strstream, rotX, ',');
getline(strstream, rotY, ',');
getline(strstream, rotZ, ',');
getline(strstream, rotW, ',');
// convert to our structure
instance.id = atoi(id.c_str());
instance.model = model.substr(1, model.size()-1);
instance.posX = atof(posX.c_str());
instance.posY = atof(posY.c_str());
instance.posZ = atof(posZ.c_str());
instance.scaleX = atof(scaleX.c_str());
instance.scaleY = atof(scaleY.c_str());
instance.scaleZ = atof(scaleZ.c_str());
instance.rotX = atof(rotX.c_str());
instance.rotY = atof(rotY.c_str());
instance.rotZ = atof(rotZ.c_str());
instance.rotW = atof(rotW.c_str());
centroid += glm::vec3(instance.posX, instance.posY, instance.posZ);
/*std::cout << "id: " << instance.id << std::endl;
std::cout << "model: " << instance.model << std::endl;
std::cout << "posX: " << instance.posX << std::endl;
std::cout << "posY: " << instance.posY << std::endl;
std::cout << "posZ: " << instance.posZ << std::endl;
std::cout << "rotW: " << instance.rotW << std::endl;*/
m_instances.push_back(instance);
}
}
}
return true;
}

View File

@ -0,0 +1,145 @@
#include "loaders/TextureLoader.h"
#include <fstream>
#include <iostream>
bool TextureLoader::loadFromFile(std::string filename)
{
std::ifstream dfile(filename);
if ( ! dfile.is_open()) {
std::cerr << "Error opening file " << filename << std::endl;
return false;
}
dfile.seekg(0, std::ios_base::end);
size_t length = dfile.tellg();
dfile.seekg(0);
char *data = new char[length];
dfile.read(data, length);
return loadFromMemory(data);
}
GLuint gErrorTextureData[] = { 0x00FF00FF, 0x00FFFFFF, 0x00FFFFFF, 0x00FF00FF };
bool TextureLoader::loadFromMemory(char *data)
{
RW::BinaryStreamSection root(data);
auto texDict = root.readStructure<RW::BSTextureDictionary>();
size_t rootI = 0;
while (root.hasMoreData(rootI)) {
auto rootSection = root.getNextChildSection(rootI);
if (rootSection.header.id != RW::SID_TextureNative)
continue;
auto texNative = rootSection.readStructure<RW::BSTextureNative>();
GLuint texture = 0;
if(texNative.platform != 8)
{
std::cerr << "Unsupported texture platform " << std::dec << texNative.platform << std::endl;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
2, 2, 0,
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, gErrorTextureData
);
}
else if((texNative.rasterformat & RW::BSTextureNative::FORMAT_EXT_PAL8) == RW::BSTextureNative::FORMAT_EXT_PAL8)
{
auto palette = rootSection.readSubStructure<RW::BSPaletteData>(sizeof(RW::BSSectionHeader)+sizeof(RW::BSTextureNative) - 4);
uint8_t* coldata = reinterpret_cast<uint8_t*>(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) + sizeof(RW::BSPaletteData) - 4);
uint8_t fullColor[texNative.width * texNative.height * 4];
bool hasAlpha = texNative.alpha == 1;
for(size_t j = 0; j < texNative.width * texNative.height; ++j)
{
size_t iTex = j * 4;
size_t iPal = coldata[j] * 4;
fullColor[iTex+0] = palette.palette[iPal+0];
fullColor[iTex+1] = palette.palette[iPal+1];
fullColor[iTex+2] = palette.palette[iPal+2];
fullColor[iTex+3] = hasAlpha ? palette.palette[iPal+3] : 255;
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
texNative.width, texNative.height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, fullColor
);
}
else if(
texNative.rasterformat == RW::BSTextureNative::FORMAT_1555 ||
texNative.rasterformat == RW::BSTextureNative::FORMAT_8888 ||
texNative.rasterformat == RW::BSTextureNative::FORMAT_888
)
{
auto coldata = rootSection.raw() + sizeof(RW::BSTextureNative);
uint32_t rastersize = *coldata;
coldata += sizeof(uint32_t);
GLenum type, format;
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;
break;
case RW::BSTextureNative::FORMAT_888:
format = GL_BGR;
type = GL_UNSIGNED_BYTE;
break;
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
texNative.width, texNative.height, 0,
format, type, coldata
);
}
else
{
std::cerr << "Unsuported raster format " << std::hex << texNative.rasterformat << std::endl;
}
if(texture != 0)
{
// todo: not completely ignore everything the TXD says.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
std::string name = std::string(texNative.diffuseName);
textures[name] = texture;
}
// std::cout << "Loaded texture '" << name << "'" << std::endl;
}
return true;
}
void TextureLoader::bindTexture(std::string texture)
{
if (textures.find(texture) == textures.end()) {
// std::cerr << "Could not find nor bind texture '" << texture << "'" << std::endl;
return;
}
glBindTexture(GL_TEXTURE_2D, textures[texture]);
}

View File

@ -0,0 +1,99 @@
#ifndef _GTADATA_H_
#define _GTADATA_H_
#include <string>
#include <map>
#include <memory>
#include <loaders/LoaderIMG.h>
#include <loaders/TextureLoader.h>
#include <loaders/LoaderDFF.h>
/**
* Handles loading and management of the Game's DAT
*/
class GTAData
{
private:
std::string datpath;
std::string splash;
public:
/**
* @struct GTAFile
* Stores information about a file the engine might want to load
*/
struct GTAFile
{
bool archived; /// Is the file inside an IMG or on the filesystem?
std::string path; /// Path to the file containing the file
};
/**
* ctor
* @param path Path to the root of the game data.
*/
GTAData(const std::string& path);
/**
* Returns the current platform
*/
std::string getPlatformString()
{
return "PC";
}
/**
* Loads the data contained in the given file
*/
void loadIDE(const std::string& name);
/**
* Handles the parsing of a COL file.
*/
void loadCOL(const size_t zone, const std::string& name);
/**
* Handles the loading of an IMG's data
*/
void loadIMG(const std::string& name);
void loadIPL(const std::string& name);
void load();
/**
* Returns a pointer to the named file if it is available, the memory must be freed.
* @param name the filename in the archive
* @return pointer to the data, NULL if it is not available
*/
char* loadFile(const std::string& name);
/**
* Maps the paths in GTA3.dat to the real paths
*/
std::map<std::string, std::string> iplLocations;
/**
* Maps file names to their locations
*/
std::map<std::string, GTAFile> fileLocations;
/**
* Map of loaded archives
*/
std::map<std::string, LoaderIMG> archives;
/**
* Texture Loader
*/
TextureLoader textureLoader;
/**
* Loaded models
*/
std::map<std::string, std::unique_ptr<Model>> models;
};
#endif

View File

@ -0,0 +1,45 @@
#ifndef _GTAENGINE_H_
#define _GTAENGINE_H_
#include "GTAData.h"
#include <loaders/LoaderIPL.h>
#include <vector>
#include <glm/glm.hpp>
/**
* @class GTAEngine
* Provides a simple interface to the framework's internals
*/
class GTAEngine
{
public:
GTAEngine(const std::string& gamepath);
/**
* Loads the game data
*/
bool load();
/**
* Loads an IPL into the game.
* @param name The name of the IPL as it appears in the games' gta.dat
*/
bool loadItems(const std::string& name);
/**
* Roughly the middle of everything
*/
glm::vec3 itemCentroid;
/**
* Game data
*/
GTAData gameData;
/**
* Until we have a real "object" class, just store a list of loaed instances.
*/
std::vector<LoaderIPLInstance> instances;
};
#endif

View File

@ -0,0 +1,121 @@
#ifndef _LOADERCOL_H_
#define _LOADERCOL_H_
#include <string>
#include <vector>
#include <glm/glm.hpp>
typedef glm::vec3 CollTVec3;
struct CollTBounds
{
CollTVec3 min, max;
CollTVec3 center;
float radius;
};
struct CollTBoundsV1
{
float radius;
CollTVec3 center;
CollTVec3 min, max;
};
struct CollTSurface
{
uint8_t material;
uint8_t flag;
uint8_t brightness;
uint8_t light;
};
struct CollTSphere
{
CollTVec3 center;
float radius;
CollTSurface surface;
};
struct CollTSphereV1
{
float radius;
CollTVec3 center;
CollTSurface surface;
};
struct CollTBox
{
CollTVec3 min, max;
CollTSurface surface;
};
struct CollTFaceGroup
{
CollTVec3 min, max;
uint16_t startface, endface;
};
typedef glm::vec3 CollTVertex;
struct CollTFace
{
uint16_t a, b, c;
uint8_t material;
uint8_t light;
};
struct CollTFaceV1
{
uint32_t a, b, c;
CollTSurface surface;
};
struct CollTHeader
{
char name[22];
uint16_t modelid;
CollTBounds bounds;
};
struct CollTHeaderV2
{
uint16_t numspheres;
uint16_t numboxes;
uint32_t numfaces;
uint32_t flags;
uint32_t offsetspheres;
uint32_t offsetboxes;
uint32_t offsetlines;
uint32_t offsetverts;
uint32_t offsetfaces;
};
struct CollTHeaderV3
{
uint32_t numshadowfaces;
uint32_t offsetverts;
uint32_t offsetfaces;
};
/**
* @class CollisionInstance
* Stores data about a collision proxy
*/
class CollisionInstance
{
};
/**
* @class LoaderCOL
* Loads collision data from COL files
*/
class LoaderCOL
{
public:
/// Load the COL data into memory
bool load(const std::string& file);
std::vector<CollisionInstance> instances;
};
#endif

View File

@ -0,0 +1,57 @@
#pragma once
#define GLEW_STATIC
#include <GL/glew.h>
#include "../../framework/rwbinarystream.h"
#include <vector>
#include <string>
#include <memory>
class Model
{
public:
RW::BSClump clump;
struct Texture {
std::string name;
std::string alphaName;
};
struct Material {
std::vector<Texture> textures;
};
struct SubGeometry {
GLuint EBO;
size_t material;
std::vector<uint32_t> indices;
};
struct Geometry {
GLuint VBO, EBO;
RW::BSGeometryBounds geometryBounds;
std::vector<RW::BSGeometryUV> texcoords;
std::vector<RW::BSGeometryTriangle> triangles;
std::vector<RW::BSTVector3> vertices;
std::vector<RW::BSTVector3> normals;
std::vector<Material> materials;
std::vector<SubGeometry> subgeom;
};
std::vector<Geometry> geometries;
};
class LoaderDFF
{
private:
template<class T> T readStructure(char *data, size_t &dataI);
RW::BSSectionHeader readHeader(char *data, size_t &dataI);
public:
std::unique_ptr<Model> loadFromMemory(char *data);
};

View File

@ -0,0 +1,65 @@
#ifndef LoaderIMG_h__
#define LoaderIMG_h__
#include <iostream>
#include <vector>
#include <cstdint>
/// \brief Points to one file within the archive
class LoaderIMGFile
{
public:
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
{
public:
/// Multiple versions of .IMG files
enum Versions
{
GTAIIIVC, ///< GTA III and GTA VC archives -- only this one is implemented
GTASA,
GTAIV
};
/// 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 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);
/// Get the information of an asset in the examining archive
LoaderIMGFile &getAssetInfo(const std::string& assetname);
/// Get the information of an asset by its index
LoaderIMGFile &getAssetInfoByIndex(size_t index);
/// Returns the number of asset files in the archive
uint32_t getAssetCount();
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)
std::vector<LoaderIMGFile> m_assets; ///< Asset info of the archive
};
#endif // LoaderIMG_h__

View File

@ -0,0 +1,39 @@
#ifndef LoaderIPL_h__
#define LoaderIPL_h__
#include <iostream>
#include <vector>
#include <glm/glm.hpp>
/**
\class LoaderIPLInstance
\brief One INST entry's data from a IPL file
*/
class LoaderIPLInstance
{
public:
int id; ///< ID of the asset in the main IMG archive
std::string model; ///< Name of the model for this instance, as seen in the IMG archive
float posX, posY, posZ; ///< 3D Position of the instance
float scaleX, scaleY, scaleZ; ///< Scale of the instance
float rotX, rotY, rotZ, rotW; ///< Rotation of the instance, in a Quaternion
};
/**
\class LoaderIPL
\brief Loads all data from a IPL file into memory
*/
class LoaderIPL
{
public:
/// Load the IPL data into memory
bool load(const std::string& filename);
/// The list of instances from the IPL file
std::vector<LoaderIPLInstance> m_instances;
/// The centroid of the instances
glm::vec3 centroid;
};
#endif // LoaderIPL_h__

View File

@ -0,0 +1,19 @@
#pragma once
#define GLEW_STATIC
#include <GL/glew.h>
#include "../../framework/rwbinarystream.h"
#include <string>
#include <map>
class TextureLoader
{
public:
bool loadFromFile(std::string filename);
bool loadFromMemory(char *data);
void bindTexture(std::string texture);
std::map<std::string, GLuint> textures;
};

View File

@ -1,5 +1,7 @@
add_executable(viewer main.cpp ../framework/LoaderIPL.cpp ../framework/LoaderIMG.cpp ../framework/LoaderDFF.cpp ../framework/TextureLoader.cpp)
add_executable(viewer main.cpp ../framework/LoaderDFF.cpp)
target_link_libraries( viewer sfml-graphics sfml-window sfml-system GL GLEW )
include_directories(../framework2/include)
target_link_libraries( viewer renderware sfml-graphics sfml-window sfml-system GL GLEW )
install(TARGETS viewer RUNTIME DESTINATION bin)

View File

@ -1,10 +1,8 @@
#define GLEW_STATIC
#include <GL/glew.h>
#include "../framework/LoaderIPL.h"
#include "../framework/LoaderIMG.h"
#include "../framework/LoaderDFF.h"
#include "../framework/TextureLoader.h"
#include <engine/GTAEngine.h>
#include <loaders/LoaderDFF.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
@ -47,11 +45,8 @@ GLuint uniModel, uniProj, uniView;
GLuint posAttrib, texAttrib;
LoaderDFF dffLoader;
TextureLoader textureLoader;
LoaderIPL iplLoader;
GTAEngine* gta = nullptr;
std::map<std::string, std::unique_ptr<Model>> models;
Model *selectedModel;
glm::vec3 selectedModelCenter;
glm::vec3 plyPos;
@ -116,63 +111,22 @@ void init(std::string gtapath)
glm::mat4 proj = glm::perspective(80.f, (float) WIDTH/HEIGHT, 0.1f, 5000.f);
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
LoaderIMG imgLoader;
if (imgLoader.load(gtapath +"/models/gta3")) {
for (int i = 0; i < imgLoader.getAssetCount(); i++) {
auto &asset = imgLoader.getAssetInfoByIndex(i);
std::string filename = asset.name;
if(asset.size == 0)
{
std::cerr << "Asset: " << filename << " has no size" << std::endl;
continue;
}
auto filetype = filename.substr(filename.size() - 3);
std::transform(filetype.begin(), filetype.end(), filetype.begin(), ::tolower);
if (filetype == "dff") {
std::string modelname = filename.substr(0, filename.size() - 4);
char *file = imgLoader.loadToMemory(filename);
if(file)
{
models[modelname] = std::move(dffLoader.loadFromMemory(file));
delete[] file;
}
} else if (filetype == "txd") {
char *file = imgLoader.loadToMemory(filename);
if(file)
{
textureLoader.loadFromMemory(file);
delete[] file;
}
}
}
}
if (iplLoader.load(gtapath +"/data/maps/industSW.ipl")) {
printf("IPL Loaded, size: %d\n", iplLoader.m_instances.size());
// Get the center of the model by averaging all the vertices! Hax!
for (int i = 0; i < iplLoader.m_instances.size(); i++) {
selectedModelCenter += glm::vec3{
iplLoader.m_instances[i].posX,
iplLoader.m_instances[i].posY,
iplLoader.m_instances[i].posZ
};
}
selectedModelCenter /= iplLoader.m_instances.size();
plyPos = selectedModelCenter;
} else {
printf("IPL failed to load.\n");
exit(1);
}
//textureLoader.loadFromFile("MISC.TXD");
selectedModel = models["Jetty"].get();
// GTA GET
gta = new GTAEngine(gtapath);
// This is harcoded in GTA III for some reason
gta->gameData.loadIMG("/models/gta3");
gta->load();
// Test out a known IPL.
gta->loadItems(gtapath + "/data/maps/industsw/industSW.ipl");
//gta->loadItems(gtapath + "/data/maps/industnw/industNW.ipl");
//gta->loadItems(gtapath + "/data/maps/industse/industSE.ipl");
//gta->loadItems(gtapath + "/data/maps/industne/industNE.ipl");
plyPos = gta->itemCentroid / (float) gta->instances.size();
}
void update()
@ -233,14 +187,21 @@ void update()
void render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auto& textureLoader = gta->gameData.textureLoader;
for (size_t i = 0; i < iplLoader.m_instances.size(); ++i) {
auto &obj = iplLoader.m_instances[i];
for (size_t i = 0; i < gta->instances.size(); ++i) {
auto &obj = gta->instances[i];
std::string modelname = obj.model;
if (modelname.substr(0, 3) == "LOD")
continue;
auto &model = models[modelname];
auto &model = gta->gameData.models[modelname];
// std::cout << "Rendering " << modelname << std::endl;
if(!model)
{
std::cout << "model " << modelname << " not there (" << gta->gameData.models.size() << " models loaded)" << std::endl;
}
for (size_t g = 0; g < model->geometries.size(); g++) {