123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- /*!
- * \file src/Texture.cpp
- * \brief Texture registry
- *
- * \author Mongoose
- * \author xythobuz
- */
-
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
-
- #ifdef __APPLE__
- #include <OpenGL/gl.h>
- #include <OpenGL/glu.h>
- #else
- #include <GL/gl.h>
- #include <GL/glu.h>
- #endif
-
- #include "utils/tga.h"
- #include "Texture.h"
-
- Texture::Texture() {
- mTextureIds = NULL;
- mFlags = 0;
- mTextureId = -1;
- mTextureId2 = -1;
- mTextureCount = 0;
- mTextureLimit = 0;
- }
-
- Texture::~Texture() {
- reset();
- }
-
- unsigned char *Texture::generateColorTexture(unsigned char rgba[4],
- unsigned int width, unsigned int height) {
- unsigned char *image;
- unsigned int i, size;
-
- image = new unsigned char[height*width*4];
-
- for (i = 0, size = width*height; i < size; ++i) {
- /* RBGA */
- image[i*4] = rgba[0];
- image[i*4+1] = rgba[1];
- image[i*4+2] = rgba[2];
- image[i*4+3] = rgba[3];
- }
-
- return image;
- }
-
- int Texture::loadColorTexture(unsigned char rgba[4],
- unsigned int width, unsigned int height) {
- unsigned char *image;
- int id;
-
- image = generateColorTexture(rgba, width, height);
- id = loadBuffer(image, width, height, RGBA, 32);
- delete [] image;
-
- return id;
- }
-
- void Texture::setFlag(TextureFlag flag) {
- mFlags |= flag;
- }
-
- void Texture::clearFlag(TextureFlag flag) {
- mFlags |= flag;
- mFlags ^= flag;
- }
-
- void Texture::reset() {
- if (mTextureIds) {
- glDeleteTextures(mTextureLimit, mTextureIds);
- delete [] mTextureIds;
- }
-
- mTextureIds = 0x0;
- mTextureCount = 0;
- mTextureLimit = 0;
- }
-
- void Texture::disableMultiTexture() {
- mFlags ^= fUseMultiTexture;
- mTextureId = -1;
- mTextureId2 = -1;
-
- glDisable(GL_TEXTURE_2D);
- glActiveTextureARB(GL_TEXTURE0_ARB);
- }
-
- void Texture::useMultiTexture(float aU, float aV, float bU, float bV) {
- if (!(mFlags & fUseMultiTexture))
- return;
-
- glMultiTexCoord2fARB(GL_TEXTURE0_ARB, aU, aV);
- glMultiTexCoord2fARB(GL_TEXTURE1_ARB, bU, bV);
- }
-
- void Texture::useMultiTexture(float u, float v) {
- if (!(mFlags & fUseMultiTexture))
- return;
-
- glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
- glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
- }
-
- void Texture::bindMultiTexture(int texture0, int texture1) {
- if (//(int)a == mTextureId && (int)b == mTextureId2 ||
- !mTextureIds ||
- texture0 < 0 || texture0 > (int)mTextureCount ||
- texture1 < 0 || texture1 > (int)mTextureCount) {
- return;
- }
-
- mFlags |= fUseMultiTexture;
- mTextureId = texture0;
- mTextureId2 = texture1;
-
- glActiveTextureARB(GL_TEXTURE0_ARB);
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, mTextureIds[texture0]);
-
- glActiveTextureARB(GL_TEXTURE1_ARB);
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, mTextureIds[texture1]);
- }
-
- void Texture::setMaxTextureCount(unsigned int n) {
- mTextureLimit = n;
-
- mTextureIds = new unsigned int[n];
-
- glGenTextures(n, mTextureIds);
- }
-
- int Texture::getTextureCount() {
- return (mTextureCount-1);
- }
-
- int Texture::loadBuffer(unsigned char *image,
- unsigned int width, unsigned int height,
- ColorMode mode, unsigned int bpp) {
- int id;
-
- id = loadBufferSlot(image, width, height, mode, bpp, mTextureCount++);
-
- if (id < 0)
- return id;
-
- return ++id;
- }
-
- void convertARGB32bppToRGBA32bpp(unsigned char *image,
- unsigned int w, unsigned int h) {
- unsigned int i, size = w*h;
- unsigned char swap;
-
- for (i = 0; i < size; ++i)
- {
- /* 32-bit ARGB to RGBA */
- swap = image[i*4+3];
- image[i*4] = image[i*4+1];
- image[i*4+1] = image[i*4+2];
- image[i*4+2] = image[i*4+3];
- image[i*4+3] = swap;
- }
- }
-
- // http://mmmovania.blogspot.de/2011/01/opengl-30-and-above-deprecated-func-and.html
- // http://www.g-truc.net/post-0256.html
- GLint deprecated_gluBuild2DMipmaps(GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data) {
- glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
- glTexImage2D(target, 0, internalFormat, width, height, 0, format, type, data);
- return 0;
- }
-
- int Texture::loadBufferSlot(unsigned char *image,
- unsigned int width, unsigned int height,
- ColorMode mode, unsigned int bpp,
- unsigned int slot) {
- unsigned char bytes;
- unsigned int glcMode;
-
-
- if (!mTextureIds || slot >= mTextureLimit) {
- printf("Texture::Load> ERROR Not initialized or out of free slots\n");
- return -1000;
- }
-
- if (!width || !height || !image) {
- printf("Texture::Load> ERROR Assertion 'image is valid' failed\n");
- return -1;
- }
-
- switch (mode) {
- case GREYSCALE:
- if (bpp != 8) {
- printf("Texture::Load> ERROR Unsupported GREYSCALE, %i bpp\n", bpp);
- return -2;
- }
- bytes = 1;
- glcMode = GL_LUMINANCE;
- break;
- case RGB:
- if (bpp != 24) {
- printf("Texture::Load> ERROR Unsupported RGB, %i bpp\n", bpp);
- return -2;
- }
- bytes = 3;
- glcMode = GL_RGB;
- break;
- case ARGB:
- if (bpp == 32) {
- convertARGB32bppToRGBA32bpp(image, width, height);
- } else {
- printf("Texture::Load> ERROR Unsupported ARGB, %i bpp\n", bpp);
- return -2;
- }
- bytes = 4;
- glcMode = GL_RGBA;
- break;
- case RGBA:
- if (bpp != 32) {
- printf("Texture::Load> ERROR Unsupported RGBA, %i bpp\n", bpp);
- return -2;
- }
- bytes = 4;
- glcMode = GL_RGBA;
- break;
- }
-
- glClearColor(0.0, 0.0, 0.0, 0.0);
- glEnable(GL_DEPTH_TEST);
- glShadeModel(GL_SMOOTH);
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- glBindTexture(GL_TEXTURE_2D, mTextureIds[slot]);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
- if (mFlags & fUseMipmaps) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_NEAREST_MIPMAP_LINEAR);
- //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_LINEAR_MIPMAP_LINEAR);
-
- //gluBuild2DMipmaps(GL_TEXTURE_2D, bytes, width, height, glcMode, GL_UNSIGNED_BYTE, image);
- // gluBuild2DMipmaps is deprecated. Replacement by xythobuz
- deprecated_gluBuild2DMipmaps(GL_TEXTURE_2D, bytes, width, height, glcMode, GL_UNSIGNED_BYTE, image);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
- glTexImage2D(GL_TEXTURE_2D, 0, glcMode, width, height, 0,
- glcMode, GL_UNSIGNED_BYTE, image);
- }
-
- //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
- return slot;
- }
-
- void Texture::bindTextureId(unsigned int n) {
- if ((int)n == mTextureId || !mTextureIds || n > mTextureCount) {
- return;
- }
-
- mTextureId = n;
-
- glEnable(GL_TEXTURE_2D);
- //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
- glBindTexture(GL_TEXTURE_2D, mTextureIds[n]);
- }
-
- void Texture::glScreenShot(char *base, unsigned int width, unsigned int height) {
- FILE *f;
- int sz = width * height;
- unsigned char *image = new unsigned char[sz * 3];
- char filename[1024];
- static int count = 0;
- bool done = false;
-
- if (!image || !width || !height) {
- if (image)
- delete [] image;
-
- printf("glScreenShot> ERROR: Couldn't allocate image!\n");
- return;
- }
-
- // Don't overwrite files
- while (!done) {
- snprintf(filename, 1024, "%s-%04i.tga", base, count++);
-
- f = fopen(filename, "rb");
-
- if (f)
- fclose(f);
- else
- done = true;
- }
-
- // Capture frame buffer
- glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, image);
-
- tgaSaveFilename(image, width, height, 0, "%s", filename);
- printf("Took screenshot '%s'.\n", filename);
-
- delete [] image;
- }
-
- int Texture::loadTGA(const char *filename) {
- FILE *f;
- unsigned char *image = NULL;
- unsigned char *image2 = NULL;
- unsigned int w, h;
- char type;
- int id = -1;
-
- f = fopen(filename, "rb");
-
- if (!f) {
- perror("Couldn't load file");
- } else if (!tgaCheck(f)) {
- tgaLoad(f, &image, &w, &h, &type);
-
- type += 2;
-
- image2 = scaleBuffer(image, w, h, (type == 4) ? 4 : 3);
-
- if (image2) {
- image = image2;
- w = h = 256;
- }
-
- if (image) {
- id = loadBuffer(image, w, h,
- (type == 4) ? RGBA : RGB,
- (type == 4) ? 32 : 24);
-
- delete [] image;
- }
-
- fclose(f);
- }
-
- if (id == -1) {
- printf("Texture::loadTGA> ERROR: Failed to load '%s'\n", filename);
- }
-
- return id;
- }
-
- int Texture::nextPower(int seed) {
- int i;
- for (i = 1; i < seed; i *= 2);
- return i;
- }
-
- /* This code based off on gluScaleImage() */
- unsigned char *Texture::scaleBuffer(unsigned char *image,
- int width, int height, int components) {
- int i, j, k;
- float* tempin;
- float* tempout;
- float sx, sy;
- //int components = 3;
- unsigned char *timage;
- int original_height = height;
- int original_width = width;
-
- if (!image || !width || !height)
- return NULL;
-
- height = nextPower(height);
- width = nextPower(width);
-
- if (height > 256)
- height = 256;
-
- if (width > 256)
- width = 256;
-
- // Check to see if scaling is needed
- if (height == original_height && width == original_width)
- return NULL;
-
- //printf("%i\n", components);
-
- timage = new unsigned char[height * width * components];
- tempin = new float[original_width * original_height * components * sizeof(float)];
- tempout = new float[width * height * components * sizeof(float)];
-
- // Copy user data to float format.
- for (i = 0; i < original_height * original_width * components; ++i) {
- tempin[i] = (float)image[i];
- }
-
- // Determine which filter to use by checking ratios.
- if (width > 1) {
- sx = (float)(original_width - 1) / (float)(width - 1);
- } else {
- sx = (float)(original_width - 1);
- }
-
- if (height > 1) {
- sy = (float)(original_height - 1) / (float) (height - 1);
- } else {
- sy = (float)(original_height - 1);
- }
-
- if (sx < 1.0 && sy < 1.0) {
- /* Magnify both width and height: use weighted sample of 4 pixels */
- int i0, i1, j0, j1;
- float alpha, beta;
- float* src00;
- float* src01;
- float* src10;
- float* src11;
- float s1, s2;
- float* dst;
-
- for (i = 0; i < height; ++i) {
- i0 = (int)(i * sy);
- i1 = i0 + 1;
-
- if (i1 >= original_height) {
- i1 = original_height - 1;
- }
-
- alpha = i * sy - i0;
-
- for (j = 0; j < width; ++j) {
- j0 = (int) (j * sx);
- j1 = j0 + 1;
-
- if (j1 >= original_width) {
- j1 = original_width - 1;
- }
-
- beta = j * sx - j0;
-
- /* Compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
- src00 = tempin + (i0 * original_width + j0) * components;
- src01 = tempin + (i0 * original_width + j1) * components;
- src10 = tempin + (i1 * original_width + j0) * components;
- src11 = tempin + (i1 * original_width + j1) * components;
-
- dst = tempout + (i * width + j) * components;
-
- for (k = 0; k < components; ++k) {
- s1 = *src00++ * (1.0f - beta) + *src01++ * beta;
- s2 = *src10++ * (1.0f - beta) + *src11++ * beta;
- *dst++ = s1 * (1.0f - alpha) + s2 * alpha;
- }
- }
- }
- } else {
- /* Shrink width and/or height: use an unweighted box filter */
- int i0, i1;
- int j0, j1;
- int ii, jj;
- float sum;
- float* dst;
-
- for (i = 0; i < height; ++i) {
- i0 = (int) (i * sy);
- i1 = i0 + 1;
-
- if (i1 >= original_height) {
- i1 = original_height - 1;
- }
-
- for (j = 0; j < width; ++j) {
- j0 = (int) (j * sx);
- j1 = j0 + 1;
-
- if (j1 >= original_width) {
- j1 = original_width - 1;
- }
-
- dst = tempout + (i * width + j) * components;
-
- /* Compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
- for (k = 0; k < components; ++k) {
- sum = 0.0;
-
- for (ii = i0; ii <= i1; ++ii) {
- for (jj = j0; jj <= j1; ++jj) {
- sum += *(tempin + (ii * original_width + jj)
- * components + k);
- }
- }
-
- sum /= ( j1 - j0 + 1 ) * ( i1 - i0 + 1 );
- *dst++ = sum;
- }
- }
- }
- }
-
- // Copy to our results.
- for( i = 0; i < height * width * components; ++i) {
- timage[i] = (unsigned char)tempout[i];
- }
-
- // Delete our temp buffers.
- delete[] tempin;
- delete[] tempout;
- delete[] image;
-
- return timage;
- }
|