250 lines
7.4 KiB
C++
250 lines
7.4 KiB
C++
#include "../System/Debug.h"
|
|
#include "Texture.h"
|
|
#include <iostream>
|
|
using namespace std;
|
|
|
|
static GLuint boundTexture = 0;
|
|
|
|
static bool IsBGR(SDL_Surface* surf) {
|
|
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
|
|
return (surf->format->Rmask & 0x00FF0000) &&
|
|
(surf->format->Bmask & 0x000000FF);
|
|
#else
|
|
return (surf->format->Bmask & 0xFF000000) &&
|
|
(surf->format->Rmask & 0x0000FF00);
|
|
#endif
|
|
}
|
|
|
|
int BuildTexture(const char* filename, GLuint* texID, GLint param, bool genMips) {
|
|
// Create a storage space for the texture.
|
|
SDL_Surface* textureImage;
|
|
// Format to pass to texture generation method.
|
|
GLint format;
|
|
GLint internalFormat;
|
|
|
|
// Load the image, check for errors, if it isn't found, quit.
|
|
textureImage = IMG_Load(filename);
|
|
|
|
if(!textureImage) {
|
|
Debug::logger->message("Warning: could not load %s", filename);
|
|
return false;
|
|
}
|
|
|
|
switch(textureImage->format->BitsPerPixel) {
|
|
case 8:
|
|
internalFormat = format = GL_ALPHA;
|
|
break;
|
|
case 16:
|
|
internalFormat = format = GL_LUMINANCE_ALPHA;
|
|
break;
|
|
case 24:
|
|
internalFormat = GL_RGB;
|
|
if (IsBGR(textureImage))
|
|
format = GL_BGR_EXT;
|
|
else
|
|
format = GL_RGB;
|
|
break;
|
|
case 32:
|
|
internalFormat = GL_RGBA;
|
|
if (IsBGR(textureImage))
|
|
format = GL_BGR_EXT;
|
|
else
|
|
format = GL_RGBA;
|
|
break;
|
|
default:
|
|
format = internalFormat = GL_NONE;
|
|
}
|
|
|
|
if(internalFormat == GL_NONE || format == GL_NONE) {
|
|
Debug::logger->message("Warning: invalid texture format for %s", filename);
|
|
SDL_FreeSurface(textureImage);
|
|
return false;
|
|
}
|
|
|
|
// Create the texture.
|
|
glGenTextures(1, texID);
|
|
|
|
// Typical texture generation using data from the bitmap.
|
|
BindTexture(*texID);
|
|
|
|
// Setup filtering.
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, param);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, param);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
if(genMips) {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
// Generate the textures and mipmaps.
|
|
gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, textureImage->w,
|
|
textureImage->h, format, GL_UNSIGNED_BYTE,
|
|
textureImage->pixels);
|
|
} else {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, textureImage->w,
|
|
textureImage->h, 0, format, GL_UNSIGNED_BYTE,
|
|
textureImage->pixels);
|
|
}
|
|
// Free up the memory we used.
|
|
SDL_FreeSurface(textureImage);
|
|
return true;
|
|
}
|
|
|
|
int LoadTGAFile(const char* filename, TGAFILE* tgaFile) {
|
|
FILE* filePtr; // Pointer to our texture.
|
|
unsigned char ucharBad; // Garbage unsigned char data.
|
|
short int sintBad; // Garbage short int data.
|
|
long imageSize; // size of the TGA image.
|
|
int colorMode; // 4 for RGBA or 3 for RGB.
|
|
long imgIndex; // counter variable.
|
|
unsigned char colorSwap; // Swap variable.
|
|
|
|
// Open the TGA file.
|
|
filePtr = fopen(filename, "rb");
|
|
if(!filePtr)
|
|
return 0;
|
|
|
|
// Read the first two bytes of garbage.
|
|
fread(&ucharBad, sizeof(unsigned char), 1, filePtr);
|
|
fread(&ucharBad, sizeof(unsigned char), 1, filePtr);
|
|
|
|
// Read in the image type.
|
|
fread(&tgaFile->textureTypeCode, sizeof(unsigned char), 1, filePtr);
|
|
|
|
// The texture type should be either 2(color) or 3(greyscale).
|
|
if((tgaFile->textureTypeCode != 2) && (tgaFile->textureTypeCode != 3)) {
|
|
fclose(filePtr);
|
|
return 0;
|
|
}
|
|
|
|
// Read 13 bytes of garbage data.
|
|
fread(&sintBad, sizeof(short int), 1, filePtr);
|
|
fread(&sintBad, sizeof(short int), 1, filePtr);
|
|
fread(&ucharBad, sizeof(unsigned char), 1, filePtr);
|
|
fread(&sintBad, sizeof(short int), 1, filePtr);
|
|
fread(&sintBad, sizeof(short int), 1, filePtr);
|
|
|
|
// Read image dimensions.
|
|
fread(&tgaFile->textureWidth, sizeof(short int), 1, filePtr);
|
|
fread(&tgaFile->textureHeight, sizeof(short int), 1, filePtr);
|
|
|
|
// Read image bit depth.
|
|
fread(&tgaFile->bitCount, sizeof(unsigned char), 1, filePtr);
|
|
|
|
// Read 1 byte of garbage data.
|
|
fread(&ucharBad, sizeof(unsigned char), 1, filePtr);
|
|
|
|
// colorMode -> 3 = BGR, 4 = BGRA
|
|
colorMode = tgaFile->bitCount / 8;
|
|
imageSize = tgaFile->textureWidth * tgaFile->textureHeight * colorMode;
|
|
|
|
// Allocate memory for image data.
|
|
tgaFile->textureData = (unsigned char*)malloc(sizeof(unsigned char)*imageSize);
|
|
|
|
// Read in the image data.
|
|
fread(tgaFile->textureData, sizeof(unsigned char), imageSize, filePtr);
|
|
|
|
// Change BGR to RGB so OpenGL can read the data.
|
|
for(imgIndex = 0; imgIndex < imageSize; imgIndex += colorMode) {
|
|
colorSwap = tgaFile->textureData[imgIndex];
|
|
tgaFile->textureData[imgIndex] = tgaFile->textureData[imgIndex + 2];
|
|
tgaFile->textureData[imgIndex + 2] = colorSwap;
|
|
}
|
|
// Close the file.
|
|
fclose(filePtr);
|
|
return 1;
|
|
}
|
|
|
|
int WriteTGAFile(const char* filename, short int width, short int height, unsigned char* imageData) {
|
|
unsigned char byteSkip; // Use to fill in the data fields that we don't care about.
|
|
short int shortSkip;
|
|
unsigned char imageType; // Image type that we are writing to file.
|
|
int colorMode;
|
|
unsigned char colorSwap;
|
|
int imgIndex;
|
|
unsigned char bitDepth;
|
|
long imageSize;
|
|
FILE* filePtr;
|
|
|
|
// Create a file for writing to binary mode.
|
|
filePtr = fopen(filename, "wb");
|
|
if(!filePtr) {
|
|
fclose(filePtr);
|
|
return 0;
|
|
}
|
|
|
|
imageType = 2; // RGB, uncompressed.
|
|
bitDepth = 24; // 24-bitdepth.
|
|
colorMode = 3; // RGB color mode.
|
|
|
|
byteSkip = 0;
|
|
shortSkip = 0;
|
|
|
|
// Write 2 bytes of data.
|
|
fwrite(&byteSkip, sizeof(unsigned char), 1, filePtr);
|
|
fwrite(&byteSkip, sizeof(unsigned char), 1, filePtr);
|
|
|
|
// Write image type.
|
|
fwrite(&imageType, sizeof(unsigned char), 1, filePtr);
|
|
|
|
fwrite(&shortSkip, sizeof(short int), 1, filePtr);
|
|
fwrite(&shortSkip, sizeof(short int), 1, filePtr);
|
|
fwrite(&byteSkip, sizeof(unsigned char), 1, filePtr);
|
|
fwrite(&shortSkip, sizeof(short int), 1, filePtr);
|
|
fwrite(&shortSkip, sizeof(short int), 1, filePtr);
|
|
|
|
// Write image dimensions.
|
|
fwrite(&width, sizeof(short int), 1, filePtr);
|
|
fwrite(&height, sizeof(short int), 1, filePtr);
|
|
fwrite(&bitDepth, sizeof(unsigned char), 1, filePtr);
|
|
|
|
// Write 1 byte of data
|
|
fwrite(&byteSkip, sizeof(unsigned char), 1, filePtr);
|
|
|
|
// Calculate the image size.
|
|
imageSize = width * height * colorMode;
|
|
|
|
// Change the image data from RGB to BGR
|
|
for(imgIndex = 0; imgIndex < imageSize; imgIndex += colorMode) {
|
|
colorSwap = imageData[imgIndex];
|
|
imageData[imgIndex] = imageData[imgIndex + 2];
|
|
imageData[imgIndex + 2] = colorSwap;
|
|
}
|
|
|
|
// Write the image data.
|
|
fwrite(imageData, sizeof(unsigned char), imageSize, filePtr);
|
|
|
|
// Close the file.
|
|
fclose(filePtr);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void BindTexture(GLuint texID) {
|
|
if(boundTexture != texID){
|
|
glBindTexture(GL_TEXTURE_2D, texID);
|
|
boundTexture = texID;
|
|
}
|
|
}
|
|
|
|
Texture::Texture() {
|
|
texID = 0;
|
|
width = 0;
|
|
height = 0;
|
|
}
|
|
|
|
Texture::~Texture() {
|
|
if(texID != 0) {
|
|
glDeleteTextures(1, &texID);
|
|
texID = 0;
|
|
}
|
|
}
|
|
|
|
bool Texture::Load(const char* filename) {
|
|
if(BuildTexture(filename, &texID, GL_CLAMP, false)) {
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|