2013-07-02 08:40:43 +02:00
|
|
|
#include <renderwure/loaders/TextureLoader.hpp>
|
2013-09-11 20:23:31 +02:00
|
|
|
#include <renderwure/engine/GTAData.hpp>
|
|
|
|
#include <renderwure/render/TextureAtlas.hpp>
|
2013-07-02 08:06:03 +02:00
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
|
2013-09-11 20:23:31 +02:00
|
|
|
bool TextureLoader::loadFromFile(std::string filename, GTAData* gameData)
|
2013-07-02 08:06:03 +02: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 20:23:31 +02:00
|
|
|
return loadFromMemory(data, gameData);
|
2013-07-02 08:06:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
GLuint gErrorTextureData[] = { 0x00FF00FF, 0x00FFFFFF, 0x00FFFFFF, 0x00FF00FF };
|
|
|
|
|
2013-09-11 20:23:31 +02:00
|
|
|
bool TextureLoader::loadFromMemory(char *data, GTAData *gameData)
|
2013-07-02 08:06:03 +02: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 20:23:31 +02:00
|
|
|
RW::BSTextureNative texNative = rootSection.readStructure<RW::BSTextureNative>();
|
2013-09-11 13:10:42 +02:00
|
|
|
|
2013-09-11 20:23:31 +02:00
|
|
|
/// Short circuit for things we dont support.
|
|
|
|
if(texNative.platform != 8) {
|
2013-07-02 08:06:03 +02:00
|
|
|
std::cerr << "Unsupported texture platform " << std::dec << texNative.platform << std::endl;
|
2013-09-11 20:23:31 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
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 08:06:03 +02:00
|
|
|
}
|
2013-09-11 20:23:31 +02:00
|
|
|
|
|
|
|
TextureAtlas* atlas;
|
|
|
|
glm::vec4 texRect;
|
|
|
|
size_t ai = 0;
|
|
|
|
size_t texW = texNative.width, texH = texNative.height;
|
|
|
|
do {
|
|
|
|
atlas = gameData->getAtlas(ai++);
|
|
|
|
} while(! atlas->canPack(&texW, &texH, 1));
|
|
|
|
|
|
|
|
if(isPal8)
|
2013-07-02 08:06:03 +02:00
|
|
|
{
|
2013-09-11 20:23:31 +02:00
|
|
|
uint32_t fullColor[texNative.width * texNative.height];
|
|
|
|
size_t paletteSize = sizeof(uint32_t) * 256;
|
2013-08-18 21:31:37 +02:00
|
|
|
|
2013-09-11 20:23:31 +02:00
|
|
|
uint8_t* coldata = reinterpret_cast<uint8_t*>(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) + paletteSize);
|
|
|
|
|
|
|
|
if((texNative.rasterformat & RW::BSTextureNative::FORMAT_8888) == RW::BSTextureNative::FORMAT_8888) {
|
|
|
|
uint32_t* palette = reinterpret_cast<uint32_t*>(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) - 4);
|
|
|
|
|
|
|
|
for(size_t j = 0, iTex = 0, iPal = 0; j < texNative.width * texNative.height; ++j)
|
|
|
|
{
|
|
|
|
iTex = j;
|
|
|
|
iPal = coldata[j];
|
|
|
|
fullColor[iTex] = palette[iPal];
|
|
|
|
}
|
2013-07-02 08:06:03 +02:00
|
|
|
}
|
2013-09-11 20:23:31 +02:00
|
|
|
else {
|
|
|
|
uint32_t* palette = reinterpret_cast<uint32_t*>(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) - 4);
|
|
|
|
|
|
|
|
for(size_t j = 0, iTex = 0, iPal = 0; j < texNative.width * texNative.height; ++j)
|
|
|
|
{
|
|
|
|
iTex = j;
|
|
|
|
iPal = coldata[j];
|
|
|
|
fullColor[iTex] = 0xFF000000 | palette[iPal];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
atlas->packTextureFormat(
|
|
|
|
fullColor, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
|
texNative.width, texNative.height,
|
|
|
|
texRect.x, texRect.y, texRect.z, texRect.w);
|
2013-07-02 08:06:03 +02:00
|
|
|
}
|
2013-09-11 20:23:31 +02:00
|
|
|
else if(isFulc)
|
2013-07-02 08:06:03 +02: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:
|
|
|
|
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;
|
|
|
|
}
|
2013-09-11 20:23:31 +02:00
|
|
|
|
|
|
|
atlas->packTextureFormat(
|
|
|
|
coldata, format, type,
|
|
|
|
texNative.width, texNative.height,
|
|
|
|
texRect.x, texRect.y, texRect.z, texRect.w);
|
2013-07-02 08:06:03 +02:00
|
|
|
}
|
|
|
|
|
2013-09-11 20:23:31 +02:00
|
|
|
// 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);
|
2013-07-02 08:06:03 +02:00
|
|
|
|
2013-09-11 20:23:31 +02:00
|
|
|
glGenerateMipmap(GL_TEXTURE_2D);*/
|
2013-07-02 08:06:03 +02:00
|
|
|
|
2013-09-11 20:23:31 +02:00
|
|
|
std::string name = std::string(texNative.diffuseName);
|
2013-07-02 08:06:03 +02:00
|
|
|
|
2013-09-11 20:23:31 +02:00
|
|
|
gameData->textures.insert({name, {atlas, texRect}});
|
2013-07-02 08:06:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|