mirror of
https://github.com/rwengine/openrw.git
synced 2025-01-31 12:01:38 +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)
|
||||
|
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)
|
||||
|
@ -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++) {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user