mirror of
https://github.com/rwengine/openrw.git
synced 2025-01-31 20:11:37 +01:00
Initial engine framework
This commit is contained in:
parent
92c8f6a10c
commit
c214f07c2b
@ -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)
|
include_directories(include)
|
||||||
|
150
framework2/GTAData.cpp
Normal file
150
framework2/GTAData.cpp
Normal 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
46
framework2/GTAEngine.cpp
Normal 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
84
framework2/LoaderCOL.cpp
Normal 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
232
framework2/LoaderDFF.cpp
Normal 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
121
framework2/LoaderIMG.cpp
Normal 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
117
framework2/LoaderIPL.cpp
Normal 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;
|
||||||
|
}
|
145
framework2/TextureLoader.cpp
Normal file
145
framework2/TextureLoader.cpp
Normal 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]);
|
||||||
|
}
|
99
framework2/include/engine/GTAData.h
Normal file
99
framework2/include/engine/GTAData.h
Normal 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
|
45
framework2/include/engine/GTAEngine.h
Normal file
45
framework2/include/engine/GTAEngine.h
Normal 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
|
121
framework2/include/loaders/LoaderCOL.h
Normal file
121
framework2/include/loaders/LoaderCOL.h
Normal 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
|
57
framework2/include/loaders/LoaderDFF.h
Normal file
57
framework2/include/loaders/LoaderDFF.h
Normal 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);
|
||||||
|
};
|
65
framework2/include/loaders/LoaderIMG.h
Normal file
65
framework2/include/loaders/LoaderIMG.h
Normal 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__
|
39
framework2/include/loaders/LoaderIPL.h
Normal file
39
framework2/include/loaders/LoaderIPL.h
Normal 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__
|
19
framework2/include/loaders/TextureLoader.h
Normal file
19
framework2/include/loaders/TextureLoader.h
Normal 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;
|
||||||
|
};
|
@ -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)
|
install(TARGETS viewer RUNTIME DESTINATION bin)
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
#define GLEW_STATIC
|
#define GLEW_STATIC
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
#include "../framework/LoaderIPL.h"
|
#include <engine/GTAEngine.h>
|
||||||
#include "../framework/LoaderIMG.h"
|
#include <loaders/LoaderDFF.h>
|
||||||
#include "../framework/LoaderDFF.h"
|
|
||||||
#include "../framework/TextureLoader.h"
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
@ -47,11 +45,8 @@ GLuint uniModel, uniProj, uniView;
|
|||||||
GLuint posAttrib, texAttrib;
|
GLuint posAttrib, texAttrib;
|
||||||
|
|
||||||
LoaderDFF dffLoader;
|
LoaderDFF dffLoader;
|
||||||
TextureLoader textureLoader;
|
GTAEngine* gta = nullptr;
|
||||||
LoaderIPL iplLoader;
|
|
||||||
|
|
||||||
std::map<std::string, std::unique_ptr<Model>> models;
|
|
||||||
Model *selectedModel;
|
|
||||||
glm::vec3 selectedModelCenter;
|
glm::vec3 selectedModelCenter;
|
||||||
|
|
||||||
glm::vec3 plyPos;
|
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);
|
glm::mat4 proj = glm::perspective(80.f, (float) WIDTH/HEIGHT, 0.1f, 5000.f);
|
||||||
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
|
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
|
||||||
|
|
||||||
LoaderIMG imgLoader;
|
// GTA GET
|
||||||
|
gta = new GTAEngine(gtapath);
|
||||||
if (imgLoader.load(gtapath +"/models/gta3")) {
|
|
||||||
for (int i = 0; i < imgLoader.getAssetCount(); i++) {
|
// This is harcoded in GTA III for some reason
|
||||||
auto &asset = imgLoader.getAssetInfoByIndex(i);
|
gta->gameData.loadIMG("/models/gta3");
|
||||||
|
|
||||||
std::string filename = asset.name;
|
gta->load();
|
||||||
|
|
||||||
if(asset.size == 0)
|
// Test out a known IPL.
|
||||||
{
|
gta->loadItems(gtapath + "/data/maps/industsw/industSW.ipl");
|
||||||
std::cerr << "Asset: " << filename << " has no size" << std::endl;
|
//gta->loadItems(gtapath + "/data/maps/industnw/industNW.ipl");
|
||||||
continue;
|
//gta->loadItems(gtapath + "/data/maps/industse/industSE.ipl");
|
||||||
}
|
//gta->loadItems(gtapath + "/data/maps/industne/industNE.ipl");
|
||||||
|
|
||||||
auto filetype = filename.substr(filename.size() - 3);
|
plyPos = gta->itemCentroid / (float) gta->instances.size();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void update()
|
void update()
|
||||||
@ -233,14 +187,21 @@ void update()
|
|||||||
void render()
|
void render()
|
||||||
{
|
{
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
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) {
|
for (size_t i = 0; i < gta->instances.size(); ++i) {
|
||||||
auto &obj = iplLoader.m_instances[i];
|
auto &obj = gta->instances[i];
|
||||||
std::string modelname = obj.model;
|
std::string modelname = obj.model;
|
||||||
if (modelname.substr(0, 3) == "LOD")
|
if (modelname.substr(0, 3) == "LOD")
|
||||||
continue;
|
continue;
|
||||||
auto &model = models[modelname];
|
auto &model = gta->gameData.models[modelname];
|
||||||
// std::cout << "Rendering " << modelname << std::endl;
|
// 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++) {
|
for (size_t g = 0; g < model->geometries.size(); g++) {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user