1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-07 19:32:49 +01:00
openrw/rwengine/src/loaders/TextureLoader.cpp

238 lines
6.3 KiB
C++
Raw Normal View History

#include <loaders/TextureLoader.hpp>
2013-12-20 17:02:46 +01:00
#include <engine/GameData.hpp>
#include <render/TextureAtlas.hpp>
#include <render/TextureData.hpp>
2013-07-02 08:06:03 +02:00
#include <fstream>
#include <iostream>
2013-12-20 16:45:41 +01:00
#include <algorithm>
2013-07-02 08:06:03 +02:00
2013-12-20 16:45:41 +01:00
GLuint gErrorTextureData[] = { 0xFFFF00FF, 0xFF000000, 0xFF000000, 0xFFFF00FF };
GLuint gDebugTextureData[] = {0xFF0000FF, 0xFF00FF00};
2013-12-20 16:45:41 +01:00
GLuint gTextureRed[] = {0xFF0000FF};
GLuint gTextureGreen[] = {0xFF00FF00};
GLuint gTextureBlue[] = {0xFFFF0000};
2013-07-02 08:06:03 +02:00
TextureData::Handle getErrorTexture()
2013-07-02 08:06:03 +02:00
{
2013-09-14 06:29:28 +02:00
static GLuint errTexName = 0;
static TextureData::Handle tex;
2013-09-14 06:29:28 +02:00
if(errTexName == 0)
{
glGenTextures(1, &errTexName);
glBindTexture(GL_TEXTURE_2D, errTexName);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
2, 2, 0,
GL_RGBA, GL_UNSIGNED_BYTE, gErrorTextureData
);
2013-12-20 16:45:41 +01:00
glGenerateMipmap(GL_TEXTURE_2D);
tex = TextureData::create(errTexName, {2, 2}, false);
2013-09-14 06:29:28 +02:00
}
return tex;
2013-09-14 06:29:28 +02:00
}
2013-07-02 08:06:03 +02:00
2013-09-15 04:39:07 +02:00
const size_t paletteSize = 1024;
void processPalette(uint32_t* fullColor, RW::BSTextureNative& texNative, RW::BinaryStreamSection& rootSection)
{
uint8_t* dataBase = reinterpret_cast<uint8_t*>(rootSection.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSTextureNative) - 4);
uint8_t* coldata = (dataBase + paletteSize + sizeof(uint32_t));
uint32_t raster_size = *reinterpret_cast<uint32_t*>(dataBase + paletteSize);
uint32_t* palette = reinterpret_cast<uint32_t*>(dataBase);
for(size_t j = 0; j < raster_size; ++j)
{
fullColor[j] = palette[coldata[j]];
}
}
TextureData::Handle createTexture(RW::BSTextureNative& texNative, RW::BinaryStreamSection& rootSection)
2013-09-14 06:29:28 +02:00
{
// TODO: Exception handling.
if(texNative.platform != 8) {
std::cerr << "Unsupported texture platform " << std::dec << texNative.platform << std::endl;
return getErrorTexture();
}
2013-07-02 08:06:03 +02:00
2013-09-14 06:29:28 +02: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;
// Export this value
bool transparent = !((texNative.rasterformat&RW::BSTextureNative::FORMAT_888) == RW::BSTextureNative::FORMAT_888);
2013-09-14 06:29:28 +02:00
if(! (isPal8 || isFulc)) {
std::cerr << "Unsuported raster format " << std::dec << texNative.rasterformat << std::endl;
return getErrorTexture();
}
2013-07-02 08:06:03 +02:00
2013-09-14 06:29:28 +02:00
GLuint textureName = 0;
#if ENABLE_ABHORENT_DEBUGGING
if(true)
{
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)(gDebugTextureData) + (*transparent ? 0 : 4)
);
}
else
#endif
2013-09-14 06:29:28 +02:00
if(isPal8)
{
uint32_t fullColor[texNative.width * texNative.height];
2013-09-11 20:23:31 +02:00
2013-09-15 04:39:07 +02:00
processPalette(fullColor, texNative, rootSection);
2013-09-14 06:29:28 +02:00
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
texNative.width, texNative.height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, fullColor
);
}
else if(isFulc)
{
auto coldata = rootSection.raw() + sizeof(RW::BSTextureNative);
coldata += sizeof(uint32_t);
GLenum type = GL_UNSIGNED_BYTE, format = GL_RGBA;
2013-09-14 06:29:28 +02:00
switch(texNative.rasterformat)
2013-07-02 08:06:03 +02:00
{
2013-09-14 06:29:28 +02:00
case RW::BSTextureNative::FORMAT_1555:
format = GL_RGBA;
type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
break;
case RW::BSTextureNative::FORMAT_8888:
2013-12-20 16:45:41 +01:00
format = GL_BGRA;
//type = GL_UNSIGNED_INT_8_8_8_8_REV;
coldata += 8;
2013-12-20 16:45:41 +01:00
type = GL_UNSIGNED_BYTE;
2013-09-14 06:29:28 +02:00
break;
case RW::BSTextureNative::FORMAT_888:
format = GL_BGRA;
type = GL_UNSIGNED_BYTE;
break;
default:
break;
2013-07-02 08:06:03 +02:00
}
2013-09-14 06:29:28 +02:00
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(
2013-09-15 04:39:07 +02:00
GL_TEXTURE_2D, 0, GL_RGBA,
2013-09-14 06:29:28 +02:00
texNative.width, texNative.height, 0,
format, type, coldata
);
}
2013-12-20 16:45:41 +01:00
else {
return getErrorTexture();
}
2013-07-02 08:06:03 +02:00
2013-09-14 06:29:28 +02:00
GLenum texFilter = GL_LINEAR;
switch(texNative.filterflags & 0xFF) {
default:
case RW::BSTextureNative::FILTER_LINEAR:
texFilter = GL_LINEAR;
break;
case RW::BSTextureNative::FILTER_NEAREST:
texFilter = GL_NEAREST;
break;
}
2013-07-02 08:06:03 +02:00
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
2013-09-14 06:29:28 +02:00
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texFilter);
GLenum texwrap = GL_REPEAT;
switch(texNative.wrapU) {
default:
case RW::BSTextureNative::WRAP_WRAP:
texwrap = GL_REPEAT;
break;
case RW::BSTextureNative::WRAP_CLAMP:
texwrap = GL_CLAMP_TO_EDGE;
break;
case RW::BSTextureNative::WRAP_MIRROR:
texwrap = GL_MIRRORED_REPEAT;
break;
}
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texwrap );
switch(texNative.wrapV) {
default:
case RW::BSTextureNative::WRAP_WRAP:
texwrap = GL_REPEAT;
break;
case RW::BSTextureNative::WRAP_CLAMP:
texwrap = GL_CLAMP_TO_EDGE;
break;
case RW::BSTextureNative::WRAP_MIRROR:
texwrap = GL_MIRRORED_REPEAT;
break;
}
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texwrap );
glGenerateMipmap(GL_TEXTURE_2D);
return TextureData::create( textureName, { texNative.width, texNative.height }, transparent );
2013-09-14 06:29:28 +02:00
}
bool TextureLoader::loadFromMemory(FileHandle file, GameData *gameData)
2013-09-14 06:29:28 +02:00
{
auto data = file->data;
2013-09-14 06:29:28 +02:00
RW::BinaryStreamSection root(data);
/*auto texDict =*/ root.readStructure<RW::BSTextureDictionary>();
2013-09-14 06:29:28 +02:00
size_t rootI = 0;
while (root.hasMoreData(rootI)) {
auto rootSection = root.getNextChildSection(rootI);
if (rootSection.header.id != RW::SID_TextureNative)
continue;
RW::BSTextureNative texNative = rootSection.readStructure<RW::BSTextureNative>();
std::string name = std::string(texNative.diffuseName);
std::string alpha = std::string(texNative.alphaName);
2013-12-20 16:45:41 +01:00
std::transform(name.begin(), name.end(), name.begin(), ::tolower );
std::transform(alpha.begin(), alpha.end(), alpha.begin(), ::tolower );
auto texture = createTexture(texNative, rootSection);
2013-07-02 08:06:03 +02:00
gameData->textures[{name, alpha}] = texture;
if( !alpha.empty() ) {
gameData->textures[{name, ""}] = texture;
}
2013-07-02 08:06:03 +02:00
}
return true;
}
2014-06-06 13:18:32 +02:00
LoadTextureArchiveJob::LoadTextureArchiveJob(WorkContext *context, GameData *gd, const std::string &file)
: WorkJob(context), _gameData(gd), _file(file)
2014-06-06 13:18:32 +02:00
{
}
void LoadTextureArchiveJob::work()
{
data = _gameData->openFile(_file);
2014-06-06 13:18:32 +02:00
}
void LoadTextureArchiveJob::complete()
{
// TODO error status
if(data) {
2014-06-06 13:18:32 +02:00
TextureLoader loader;
loader.loadFromMemory(data, _gameData);
2014-06-06 13:18:32 +02:00
}
}