mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-07 11:22:45 +01:00
Merge pull request #254 from danhedron/texture-slots
Load textures into separate groups
This commit is contained in:
commit
04e79a5117
@ -5,7 +5,6 @@
|
||||
#include <engine/GameState.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <loaders/LoaderCOL.hpp>
|
||||
#include <loaders/LoaderDFF.hpp>
|
||||
#include <loaders/LoaderIDE.hpp>
|
||||
#include <loaders/LoaderIPL.hpp>
|
||||
#include <script/SCMFile.hpp>
|
||||
@ -23,6 +22,10 @@
|
||||
|
||||
GameData::GameData(Logger* log, const std::string& path)
|
||||
: datpath(path), logger(log), engine(nullptr) {
|
||||
dffLoader.setTextureLookupCallback(
|
||||
[&](const std::string& texture, const std::string&) {
|
||||
return findSlotTexture(currenttextureslot, texture);
|
||||
});
|
||||
}
|
||||
|
||||
GameData::~GameData() {
|
||||
@ -37,13 +40,13 @@ void GameData::load() {
|
||||
/// @todo cuts.img files should be loaded differently to gta3.img
|
||||
loadIMG("anim/cuts.img");
|
||||
|
||||
loadLevelFile("data/default.dat");
|
||||
loadLevelFile("data/gta3.dat");
|
||||
|
||||
loadTXD("particle.txd");
|
||||
loadTXD("icons.txd");
|
||||
loadTXD("hud.txd");
|
||||
loadTXD("fonts.txd");
|
||||
textureslots["particle"] = loadTextureArchive("particle.txd");
|
||||
textureslots["icons"] = loadTextureArchive("icons.txd");
|
||||
textureslots["hud"] = loadTextureArchive("hud.txd");
|
||||
textureslots["fonts"] = loadTextureArchive("fonts.txd");
|
||||
textureslots["generic"] = loadTextureArchive("generic.txd");
|
||||
auto misc = loadTextureArchive("misc.txd");
|
||||
textureslots["generic"].insert(misc.begin(), misc.end());
|
||||
|
||||
loadCarcols("data/carcols.dat");
|
||||
loadWeather("data/timecyc.dat");
|
||||
@ -52,6 +55,9 @@ void GameData::load() {
|
||||
loadWeaponDAT("data/weapon.dat");
|
||||
|
||||
loadIFP("ped.ifp");
|
||||
|
||||
loadLevelFile("data/default.dat");
|
||||
loadLevelFile("data/gta3.dat");
|
||||
}
|
||||
|
||||
void GameData::loadLevelFile(const std::string& path) {
|
||||
@ -63,6 +69,9 @@ void GameData::loadLevelFile(const std::string& path) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset texture slot
|
||||
currenttextureslot = "generic";
|
||||
|
||||
for (std::string line, cmd; std::getline(datfile, line);) {
|
||||
if (line.size() == 0 || line[0] == '#') continue;
|
||||
#ifndef RW_WINDOWS
|
||||
@ -296,23 +305,41 @@ void GameData::loadWater(const std::string& path) {
|
||||
}
|
||||
|
||||
void GameData::loadTXD(const std::string& name) {
|
||||
if (loadedFiles.find(name) != loadedFiles.end()) {
|
||||
auto slot = name;
|
||||
auto ext = name.find(".txd");
|
||||
if (ext != std::string::npos) {
|
||||
slot = name.substr(0, ext);
|
||||
}
|
||||
|
||||
// Set the current texture slot
|
||||
currenttextureslot = slot;
|
||||
|
||||
// Check if this texture slot is loaded already
|
||||
auto slotit = textureslots.find(slot);
|
||||
if (slotit != textureslots.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadedFiles[name] = true;
|
||||
textureslots[slot] = std::move(loadTextureArchive(name));
|
||||
}
|
||||
|
||||
TextureArchive GameData::loadTextureArchive(const std::string& name) {
|
||||
/// @todo refactor loadTXD to use correct file locations
|
||||
auto file = index.openFile(name);
|
||||
if (!file) {
|
||||
logger->error("Data", "Failed to open txd: " + name);
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
TextureArchive textures;
|
||||
|
||||
TextureLoader l;
|
||||
if (!l.loadFromMemory(file, textures)) {
|
||||
logger->error("Data", "Error loading txd: " + name);
|
||||
return {};
|
||||
}
|
||||
|
||||
return textures;
|
||||
}
|
||||
|
||||
void GameData::getNameAndLod(std::string& name, int& lod) {
|
||||
@ -329,8 +356,7 @@ Model* GameData::loadClump(const std::string& name) {
|
||||
logger->error("Data", "Failed to load model " + name);
|
||||
return nullptr;
|
||||
}
|
||||
LoaderDFF l;
|
||||
auto m = l.loadFromMemory(file);
|
||||
auto m = dffLoader.loadFromMemory(file);
|
||||
if (!m) {
|
||||
logger->error("Data", "Error loading model file " + name);
|
||||
return nullptr;
|
||||
@ -344,8 +370,7 @@ void GameData::loadModelFile(const std::string& name) {
|
||||
logger->log("Data", Logger::Error, "Failed to load model file " + name);
|
||||
return;
|
||||
}
|
||||
LoaderDFF l;
|
||||
auto m = l.loadFromMemory(file);
|
||||
auto m = dffLoader.loadFromMemory(file);
|
||||
if (!m) {
|
||||
logger->log("Data", Logger::Error, "Error loading model file " + name);
|
||||
return;
|
||||
@ -374,14 +399,14 @@ void GameData::loadModel(ModelID model) {
|
||||
auto info = modelinfo[model].get();
|
||||
/// @todo replace openFile with API for loading from CDIMAGE archives
|
||||
auto name = info->name;
|
||||
auto slotname = info->textureslot;
|
||||
|
||||
// Re-direct special models
|
||||
switch (info->type()) {
|
||||
case ModelDataType::ClumpInfo:
|
||||
// Re-direct the hier objects to the special object ids
|
||||
name = engine->state->specialModels[info->id()];
|
||||
/// @todo remove this from here
|
||||
loadTXD(name + ".txd");
|
||||
slotname = name;
|
||||
break;
|
||||
case ModelDataType::PedInfo:
|
||||
static const std::string specialPrefix("special");
|
||||
@ -389,8 +414,7 @@ void GameData::loadModel(ModelID model) {
|
||||
auto sid = name.substr(specialPrefix.size());
|
||||
unsigned short specialID = std::atoi(sid.c_str());
|
||||
name = engine->state->specialCharacters[specialID];
|
||||
/// @todo remove this from here
|
||||
loadTXD(name + ".txd");
|
||||
slotname = name;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -398,14 +422,19 @@ void GameData::loadModel(ModelID model) {
|
||||
}
|
||||
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
std::transform(slotname.begin(), slotname.end(), slotname.begin(),
|
||||
::tolower);
|
||||
|
||||
/// @todo remove this from here
|
||||
loadTXD(slotname + ".txd");
|
||||
|
||||
auto file = index.openFile(name + ".dff");
|
||||
if (!file) {
|
||||
logger->error("Data", "Failed to load model for " +
|
||||
std::to_string(model) + " [" + name + "]");
|
||||
return;
|
||||
}
|
||||
LoaderDFF l;
|
||||
auto m = l.loadFromMemory(file);
|
||||
auto m = dffLoader.loadFromMemory(file);
|
||||
if (!m) {
|
||||
logger->error("Data",
|
||||
"Error loading model file for " + std::to_string(model));
|
||||
|
@ -39,8 +39,10 @@ class GameData {
|
||||
private:
|
||||
std::string datpath;
|
||||
std::string splash;
|
||||
std::string currenttextureslot;
|
||||
|
||||
Logger* logger;
|
||||
LoaderDFF dffLoader;
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
@ -111,10 +113,16 @@ public:
|
||||
void loadLevelFile(const std::string& path);
|
||||
|
||||
/**
|
||||
* Attempts to load a TXD, or does nothing if it has already been loaded
|
||||
* Loads the txt slot if it is not already loaded and sets
|
||||
* the current TXD slot
|
||||
*/
|
||||
void loadTXD(const std::string& name);
|
||||
|
||||
/**
|
||||
* Loads a named texture archive from the game data
|
||||
*/
|
||||
TextureArchive loadTextureArchive(const std::string& name);
|
||||
|
||||
/**
|
||||
* Converts combined {name}_l{LOD} into name and lod.
|
||||
*/
|
||||
@ -155,9 +163,17 @@ public:
|
||||
|
||||
void loadSplash(const std::string& name);
|
||||
|
||||
TextureData::Handle findTexture(const std::string& name,
|
||||
const std::string& alpha = "") {
|
||||
return textures[{name, alpha}];
|
||||
TextureData::Handle findSlotTexture(const std::string& slot,
|
||||
const std::string& texture) const {
|
||||
auto slotit = textureslots.find(slot);
|
||||
if (slotit == textureslots.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto textureit = slotit->second.find(texture);
|
||||
if (textureit == slotit->second.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return textureit->second;
|
||||
}
|
||||
|
||||
FileIndex index;
|
||||
@ -222,9 +238,9 @@ public:
|
||||
WeatherLoader weatherLoader;
|
||||
|
||||
/**
|
||||
* Loaded textures (Textures are ID by name and alpha pairs)
|
||||
* Texture slots, containing loaded textures.
|
||||
*/
|
||||
std::map<std::pair<std::string, std::string>, TextureData::Handle> textures;
|
||||
std::map<std::string, TextureArchive> textureslots;
|
||||
|
||||
/**
|
||||
* Texture atlases.
|
||||
|
@ -158,18 +158,6 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
|
||||
data->loadModel(oi->id());
|
||||
}
|
||||
|
||||
std::string modelname = oi->name;
|
||||
std::string texturename = oi->textureslot;
|
||||
|
||||
std::transform(std::begin(modelname), std::end(modelname),
|
||||
std::begin(modelname), tolower);
|
||||
std::transform(std::begin(texturename), std::end(texturename),
|
||||
std::begin(texturename), tolower);
|
||||
|
||||
if (!texturename.empty()) {
|
||||
data->loadTXD(texturename + ".txd");
|
||||
}
|
||||
|
||||
// Check for dynamic data.
|
||||
auto dyit = data->dynamicObjectData.find(oi->name);
|
||||
std::shared_ptr<DynamicObjectData> dydata;
|
||||
@ -177,7 +165,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
|
||||
dydata = dyit->second;
|
||||
}
|
||||
|
||||
if (modelname.empty()) {
|
||||
if (oi->name.empty()) {
|
||||
logger->warning(
|
||||
"World", "Instance with missing model: " + std::to_string(id));
|
||||
}
|
||||
@ -243,15 +231,12 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
||||
}
|
||||
|
||||
auto clumpmodel = static_cast<ClumpModelInfo*>(modelinfo);
|
||||
std::string texturename;
|
||||
|
||||
if (!clumpmodel->isLoaded()) {
|
||||
data->loadModel(id);
|
||||
}
|
||||
auto model = clumpmodel->getModel();
|
||||
|
||||
texturename = modelinfo->textureslot;
|
||||
|
||||
if (id == 0) {
|
||||
auto playerobj = pedestrianPool.find(state->playerObject);
|
||||
if (playerobj) {
|
||||
@ -259,10 +244,6 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
||||
}
|
||||
}
|
||||
|
||||
if (!texturename.empty()) {
|
||||
data->loadTXD(texturename + ".txd");
|
||||
}
|
||||
|
||||
auto instance = new CutsceneObject(this, pos, rot, model, modelinfo);
|
||||
|
||||
cutscenePool.insert(instance);
|
||||
@ -285,10 +266,6 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
|
||||
data->loadModel(id);
|
||||
}
|
||||
|
||||
if (!vti->textureslot.empty()) {
|
||||
data->loadTXD(vti->textureslot + ".txd");
|
||||
}
|
||||
|
||||
glm::u8vec3 prim(255), sec(128);
|
||||
auto palit = data->vehiclePalettes.find(
|
||||
vti->name); // modelname is conveniently lowercase (usually)
|
||||
@ -361,12 +338,6 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id,
|
||||
data->loadModel(id);
|
||||
}
|
||||
|
||||
std::string texturename = pt->textureslot;
|
||||
|
||||
if (!texturename.empty()) {
|
||||
data->loadTXD(texturename + ".txd");
|
||||
}
|
||||
|
||||
auto ped = new CharacterObject(this, pos, rot, pt);
|
||||
ped->setGameObjectID(gid);
|
||||
new DefaultAIController(ped);
|
||||
@ -388,13 +359,12 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos,
|
||||
std::string modelname = "player";
|
||||
std::string texturename = "player";
|
||||
|
||||
data->loadTXD(texturename + ".txd");
|
||||
if (!pt->isLoaded()) {
|
||||
auto model = data->loadClump(modelname + ".dff");
|
||||
pt->setModel(model);
|
||||
}
|
||||
|
||||
data->loadTXD(texturename + ".txd");
|
||||
|
||||
auto ped = new CharacterObject(this, pos, rot, pt);
|
||||
ped->setGameObjectID(gid);
|
||||
ped->setLifetime(GameObject::PlayerLifetime);
|
||||
@ -416,8 +386,6 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
||||
data->loadModel(id);
|
||||
}
|
||||
|
||||
data->loadTXD(modelInfo->textureslot + ".txd");
|
||||
|
||||
PickupObject* pickup = nullptr;
|
||||
auto pickuptype = (PickupObject::PickupType)type;
|
||||
|
||||
|
@ -83,7 +83,7 @@ PickupObject::PickupObject(GameWorld* world, const glm::vec3& position,
|
||||
m_corona->particle.direction = glm::vec3(0.f, 0.f, 1.f);
|
||||
m_corona->particle.orientation = VisualFX::ParticleData::Camera;
|
||||
m_corona->particle.colour = glm::vec4(1.0f, 0.3f, 0.3f, 0.3f);
|
||||
m_corona->particle.texture = engine->data->findTexture("coronacircle");
|
||||
m_corona->particle.texture = engine->data->findSlotTexture("particle", "coronacircle");
|
||||
|
||||
auto flags = behaviourFlags(m_type);
|
||||
RW_UNUSED(flags);
|
||||
|
@ -71,7 +71,7 @@ void ProjectileObject::explode() {
|
||||
0.f});
|
||||
}
|
||||
|
||||
auto tex = engine->data->findTexture("explo02");
|
||||
auto tex = engine->data->findSlotTexture("particle", "explo02");
|
||||
|
||||
auto explosion = engine->createEffect(VisualFX::Particle);
|
||||
explosion->particle.size = glm::vec2(exp_size);
|
||||
|
@ -404,7 +404,7 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera,
|
||||
GLuint splashTexName = 0;
|
||||
auto fc = world->state->fadeColour;
|
||||
if ((fc.r + fc.g + fc.b) == 0 && world->state->currentSplash.size() > 0) {
|
||||
auto splash = world->data->findTexture(world->state->currentSplash);
|
||||
auto splash = world->data->findSlotTexture("generic", world->state->currentSplash);
|
||||
if (splash) {
|
||||
splashTexName = splash->getName();
|
||||
}
|
||||
@ -494,16 +494,6 @@ void GameRenderer::renderGeometry(Model* model, size_t g,
|
||||
|
||||
if (mat.textures.size() > 0) {
|
||||
auto tex = mat.textures[0].texture;
|
||||
if (!tex) {
|
||||
auto& tC = mat.textures[0].name;
|
||||
auto& tA = mat.textures[0].alphaName;
|
||||
tex = data->findTexture(tC, tA);
|
||||
if (!tex) {
|
||||
// logger->warning("Renderer", "Missing texture: " + tC
|
||||
// + " " + tA);
|
||||
}
|
||||
mat.textures[0].texture = tex;
|
||||
}
|
||||
if (tex) {
|
||||
dp.textures = {tex->getName()};
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ void MapRenderer::draw(GameWorld* world, const MapInfo& mi) {
|
||||
for (int m = 0; m < MAP_BLOCK_SIZE; ++m) {
|
||||
std::string num = (m < 10 ? "0" : "");
|
||||
std::string name = "radar" + num + std::to_string(m);
|
||||
auto texture = world->data->textures[{name, ""}];
|
||||
auto texture = world->data->findSlotTexture(name, name);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getName());
|
||||
|
||||
@ -140,7 +140,8 @@ void MapRenderer::draw(GameWorld* world, const MapInfo& mi) {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
// We only need the outer ring if we're clipping.
|
||||
glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
TextureData::Handle radarDisc = data->findTexture("radardisc");
|
||||
TextureData::Handle radarDisc =
|
||||
data->findSlotTexture("hud", "radardisc");
|
||||
|
||||
glm::mat4 model;
|
||||
model = glm::translate(model, glm::vec3(mi.screenPosition, 0.0f));
|
||||
@ -257,7 +258,7 @@ void MapRenderer::prepareBlip(const glm::vec2& coord, const glm::mat4& view,
|
||||
|
||||
GLuint tex = 0;
|
||||
if (!texture.empty()) {
|
||||
auto sprite = data->findTexture(texture);
|
||||
auto sprite = data->findSlotTexture("hud", texture);
|
||||
tex = sprite->getName();
|
||||
}
|
||||
renderer->setUniform(rectProg, "colour", colour);
|
||||
|
@ -61,17 +61,6 @@ void ObjectRenderer::renderGeometry(Model* model, size_t g,
|
||||
|
||||
if (mat.textures.size() > 0) {
|
||||
auto tex = mat.textures[0].texture;
|
||||
if (!tex) {
|
||||
auto& tC = mat.textures[0].name;
|
||||
auto& tA = mat.textures[0].alphaName;
|
||||
tex = m_world->data->findTexture(tC, tA);
|
||||
if (!tex) {
|
||||
// logger->warning("Renderer", "Missing texture: " + tC
|
||||
// + " " + tA);
|
||||
dp.textures = {m_errorTexture};
|
||||
}
|
||||
mat.textures[0].texture = tex;
|
||||
}
|
||||
if (tex) {
|
||||
if (tex->isTransparent()) {
|
||||
isTransparent = true;
|
||||
|
@ -284,7 +284,7 @@ void TextRenderer::renderText(const TextRenderer::TextInfo& ti,
|
||||
Renderer::DrawParameters dp;
|
||||
dp.start = 0;
|
||||
dp.count = gb.getCount();
|
||||
auto ftexture = renderer->getData()->findTexture(fonts[ti.font]);
|
||||
auto ftexture = renderer->getData()->findSlotTexture("fonts", fonts[ti.font]);
|
||||
dp.textures = {ftexture->getName()};
|
||||
dp.depthWrite = false;
|
||||
|
||||
|
@ -98,7 +98,7 @@ void WaterRenderer::setDataTexture(GLuint fbBinding, GLuint dataTex) {
|
||||
void WaterRenderer::render(GameRenderer* renderer, GameWorld* world) {
|
||||
auto r = renderer->getRenderer();
|
||||
|
||||
auto waterTex = world->data->findTexture("water_old");
|
||||
auto waterTex = world->data->findSlotTexture("particle", "water_old");
|
||||
RW_CHECK(waterTex != nullptr, "Water texture is null");
|
||||
if (waterTex == nullptr) {
|
||||
// Can't render water if we don't have a texture.
|
||||
|
@ -168,7 +168,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
|
||||
}
|
||||
|
||||
TextureData::Handle itemTexture =
|
||||
render->getData()->findTexture(itemTextureName);
|
||||
render->getData()->findSlotTexture("hud", itemTextureName);
|
||||
RW_CHECK(itemTexture != nullptr, "Item has 0 texture");
|
||||
if (itemTexture != nullptr) {
|
||||
RW_CHECK(itemTexture->getName() != 0, "Item has 0 texture");
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <gl/gl_core_3_3.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <map>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -37,3 +38,4 @@ private:
|
||||
glm::ivec2 size;
|
||||
bool hasAlpha;
|
||||
};
|
||||
using TextureArchive = std::map<std::string, TextureData::Handle>;
|
||||
|
@ -341,8 +341,10 @@ void LoaderDFF::readTexture(Model *model, const RWBStream &stream) {
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
std::transform(alpha.begin(), alpha.end(), alpha.begin(), ::tolower);
|
||||
|
||||
TextureData::Handle textureinst =
|
||||
texturelookup ? texturelookup(name, alpha) : nullptr;
|
||||
model->geometries.back()->materials.back().textures.push_back(
|
||||
{name, alpha, nullptr});
|
||||
{name, alpha, textureinst});
|
||||
}
|
||||
|
||||
void LoaderDFF::readGeometryExtension(Model *model, const RWBStream &stream) {
|
||||
|
@ -2,14 +2,14 @@
|
||||
#ifndef _LOADERDFF_HPP_
|
||||
#define _LOADERDFF_HPP_
|
||||
|
||||
#include <gl/TextureData.hpp>
|
||||
#include <loaders/RWBinaryStream.hpp>
|
||||
|
||||
#include <platform/FileHandle.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Model;
|
||||
class GameData;
|
||||
|
||||
class DFFLoaderException {
|
||||
std::string _message;
|
||||
@ -48,7 +48,16 @@ class LoaderDFF {
|
||||
void readAtomic(Model* model, const RWBStream& stream);
|
||||
|
||||
public:
|
||||
using TextureLookupCallback = std::function<TextureData::Handle(
|
||||
const std::string&, const std::string&)>;
|
||||
|
||||
Model* loadFromMemory(FileHandle file);
|
||||
|
||||
void setTextureLookupCallback(TextureLookupCallback tlc) {
|
||||
texturelookup = tlc;
|
||||
}
|
||||
private:
|
||||
TextureLookupCallback texturelookup;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -182,11 +182,7 @@ bool TextureLoader::loadFromMemory(FileHandle file,
|
||||
|
||||
auto texture = createTexture(texNative, rootSection);
|
||||
|
||||
inTextures[{name, alpha}] = texture;
|
||||
|
||||
if (!alpha.empty()) {
|
||||
inTextures[{name, ""}] = texture;
|
||||
}
|
||||
inTextures[name] = texture;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -11,8 +11,6 @@
|
||||
|
||||
// This might suffice
|
||||
#include <gl/TextureData.hpp>
|
||||
typedef std::map<std::pair<std::string, std::string>, TextureData::Handle>
|
||||
TextureArchive;
|
||||
|
||||
class FileIndex;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user