openrw/framework2/TextureLoader.cpp

152 lines
4.5 KiB
C++
Raw Normal View History

#include <renderwure/loaders/TextureLoader.hpp>
2013-09-11 18:23:31 +00:00
#include <renderwure/engine/GTAData.hpp>
#include <renderwure/render/TextureAtlas.hpp>
2013-07-02 07:06:03 +01:00
#include <fstream>
#include <iostream>
2013-09-11 18:23:31 +00:00
bool TextureLoader::loadFromFile(std::string filename, GTAData* gameData)
2013-07-02 07:06:03 +01:00
{
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);
2013-09-11 18:23:31 +00:00
return loadFromMemory(data, gameData);
2013-07-02 07:06:03 +01:00
}
2013-09-14 02:46:14 +00:00
GLuint gErrorTextureData[] = { 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFF0000 };
2013-07-02 07:06:03 +01:00
2013-09-11 18:23:31 +00:00
bool TextureLoader::loadFromMemory(char *data, GTAData *gameData)
2013-07-02 07:06:03 +01:00
{
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;
2013-09-11 18:23:31 +00:00
RW::BSTextureNative texNative = rootSection.readStructure<RW::BSTextureNative>();
2013-09-11 11:10:42 +00:00
2013-09-11 18:23:31 +00:00
/// Short circuit for things we dont support.
if(texNative.platform != 8) {
2013-07-02 07:06:03 +01:00
std::cerr << "Unsupported texture platform " << std::dec << texNative.platform << std::endl;
2013-09-11 18:23:31 +00:00
continue;
}
2013-09-14 02:46:14 +00:00
bool isPal4 = (texNative.rasterformat & RW::BSTextureNative::FORMAT_EXT_PAL4) == RW::BSTextureNative::FORMAT_EXT_PAL4;
2013-09-11 18:23:31 +00:00
bool isPal8 = (texNative.rasterformat & RW::BSTextureNative::FORMAT_EXT_PAL8) == RW::BSTextureNative::FORMAT_EXT_PAL8;
bool isFulc = texNative.rasterformat == RW::BSTextureNative::FORMAT_1555 ||
texNative.rasterformat == RW::BSTextureNative::FORMAT_8888 ||
texNative.rasterformat == RW::BSTextureNative::FORMAT_888;
if(! (isPal8 || isFulc)) {
std::cerr << "Unsuported raster format " << std::dec << texNative.rasterformat << std::endl;
continue;
2013-07-02 07:06:03 +01:00
}
2013-09-11 18:23:31 +00:00
2013-09-14 02:46:14 +00:00
bool useAtlas = false;
GLuint textureName = 0;
TextureAtlas* atlas = nullptr;
glm::vec4 texRect(0.f, 0.f, 1.f, 1.f);
if(useAtlas) {
size_t ai = 0;
size_t texW = texNative.width, texH = texNative.height;
do {
atlas = gameData->getAtlas(ai++);
} while(! atlas->canPack(&texW, &texH, 1));
}
2013-09-11 18:23:31 +00:00
if(isPal8)
2013-07-02 07:06:03 +01:00
{
2013-09-11 18:23:31 +00:00
uint32_t fullColor[texNative.width * texNative.height];
2013-09-14 02:46:14 +00:00
size_t paletteSize = 1024;
2013-09-11 18:23:31 +00:00
uint8_t* coldata = reinterpret_cast<uint8_t*>(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) + paletteSize);
2013-09-14 02:46:14 +00:00
uint32_t* palette = reinterpret_cast<uint32_t*>(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) - 4);
2013-09-11 18:23:31 +00:00
2013-09-14 02:46:14 +00:00
for(size_t j = 0, iTex = 0; j < texNative.width * texNative.height; ++j)
{
iTex = j;
fullColor[iTex] = palette[coldata[j]];
}
2013-09-11 18:23:31 +00:00
2013-09-14 02:46:14 +00:00
if(atlas) {
atlas->packTextureFormat(
fullColor, GL_BGRA, GL_UNSIGNED_BYTE,
texNative.width, texNative.height,
texRect.x, texRect.y, texRect.z, texRect.w);
2013-07-02 07:06:03 +01:00
}
2013-09-11 18:23:31 +00:00
else {
2013-09-14 02:46:14 +00:00
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(
GL_TEXTURE_2D, 0, texNative.alpha ? GL_RGBA : GL_RGB,
texNative.width, texNative.height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, fullColor
);
2013-09-11 18:23:31 +00:00
}
2013-07-02 07:06:03 +01:00
}
2013-09-11 18:23:31 +00:00
else if(isFulc)
2013-07-02 07:06:03 +01:00
{
auto coldata = rootSection.raw() + sizeof(RW::BSTextureNative);
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:
2013-09-14 02:46:14 +00:00
format = GL_RGBA;
2013-07-02 07:06:03 +01:00
type = GL_UNSIGNED_INT_8_8_8_8_REV;
break;
case RW::BSTextureNative::FORMAT_888:
2013-09-14 02:46:14 +00:00
format = GL_BGRA;
2013-07-02 07:06:03 +01:00
type = GL_UNSIGNED_BYTE;
break;
}
2013-09-11 18:23:31 +00:00
2013-09-14 02:46:14 +00:00
if(atlas) {
atlas->packTextureFormat(
coldata, format, type,
texNative.width, texNative.height,
texRect.x, texRect.y, texRect.z, texRect.w);
}
else {
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(
GL_TEXTURE_2D, 0, texNative.alpha ? GL_RGBA : GL_RGB,
texNative.width, texNative.height, 0,
format, type, coldata
);
}
2013-07-02 07:06:03 +01:00
}
2013-09-14 02:46:14 +00:00
std::string name = std::string(texNative.diffuseName);
2013-07-02 07:06:03 +01:00
2013-09-14 02:46:14 +00:00
// todo: not completely ignore everything the TXD says.
if(!atlas) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2013-07-02 07:06:03 +01:00
2013-09-14 02:46:14 +00:00
glGenerateMipmap(GL_TEXTURE_2D);
}
2013-07-02 07:06:03 +01:00
2013-09-14 02:46:14 +00:00
gameData->textures.insert({name, {textureName, atlas, texRect}});
2013-07-02 07:06:03 +01:00
}
return true;
}