From 06edf761241eee2323d5e263f2b0e153169a76d9 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 25 May 2000 15:19:53 +0000 Subject: Better texture loading code, Replaced calls to gluBuild2DMipmaps with a custom mipmap function. git-svn-id: http://svn.leocad.org/trunk@67 c7d43263-9d01-0410-8a33-9dba5d9f93d6 --- common/texture.cpp | 335 +++++++++++++++++++++++++++++++++-------------------- common/texture.h | 63 +++++----- 2 files changed, 239 insertions(+), 159 deletions(-) diff --git a/common/texture.cpp b/common/texture.cpp index 066fa6a..00ad097 100644 --- a/common/texture.cpp +++ b/common/texture.cpp @@ -1,26 +1,62 @@ // Texture object. // -#ifdef LC_WINDOWS -#include "stdafx.h" -#endif -#include "GL/glu.h" #include #include +#include "opengl.h" #include "file.h" #include "texture.h" #include "project.h" #include "globals.h" #include "image.h" +// ============================================================================= +// Static functions + +static void* ResizeImage (GLubyte* old_image, int components, int srcw, int srch, int destw, int desth) +{ + int i, j, k; + float sx, sy; + GLubyte* new_image; + + new_image = (GLubyte*)malloc (destw*desth*components*sizeof(GLubyte)); + if (new_image == NULL) + return NULL; + + if (destw > 1) + sx = (GLfloat) (srcw-1) / (GLfloat) (destw-1); + else + sx = (GLfloat) (srcw-1); + if (desth > 1) + sy = (GLfloat) (srch-1) / (GLfloat) (desth-1); + else + sy = (GLfloat) (srch-1); + + for (i = 0; i < desth; i++) + { + GLint ii = (GLint)(i * sy); + for (j = 0; j < destw; j++) + { + GLint jj = (GLint)(j * sx); + GLubyte *src = old_image + (ii * srcw + jj) * components; + GLubyte *dst = new_image + (i * destw + j) * components; + + for (k = 0; k < components; k++) + *dst++ = *src++; + } + } + + return new_image; +} + ///////////////////////////////////////////////////////////////////////////// // Texture construction/destruction // Only called for the background image, use LoadIndex() Texture::Texture() { - m_nRef = 1; - m_nID = 0; + m_nRef = 1; + m_nID = 0; } Texture::~Texture() @@ -32,17 +68,17 @@ Texture::~Texture() void Texture::AddRef(bool bFilter) { - if (m_nRef == 0) - Load(bFilter); + if (m_nRef == 0) + Load(bFilter); - m_nRef++; + m_nRef++; } void Texture::DeRef() { - m_nRef--; - if (m_nRef == 0) - Unload(); + m_nRef--; + if (m_nRef == 0) + Unload(); } ///////////////////////////////////////////////////////////////////////////// @@ -50,132 +86,177 @@ void Texture::DeRef() void Texture::LoadIndex(File* idx) { - unsigned char bt; - - // TODO: don't change ref. if reloading - m_nRef = 0; - m_nID = 0; - - idx->Read(m_strName, 8); - idx->ReadShort(&m_nWidth, 1); - idx->ReadShort(&m_nHeight, 1); - idx->ReadByte(&bt, 1); - - switch (bt) - { - case LC_INTENSITY: m_nType = GL_LUMINANCE; break; - case LC_RGB: m_nType = GL_RGB; break; - case LC_RGBA: m_nType = GL_RGBA; break; - } - - idx->ReadLong(&m_nOffset, 1); + unsigned char bt; + + // TODO: don't change ref. if reloading + m_nRef = 0; + m_nID = 0; + + idx->Read(m_strName, 8); + idx->ReadShort(&m_nWidth, 1); + idx->ReadShort(&m_nHeight, 1); + idx->ReadByte(&bt, 1); + + switch (bt) + { + case LC_INTENSITY: + m_nFormat = GL_LUMINANCE; + m_nFileSize = m_nWidth*m_nHeight; + break; + case LC_RGB: + m_nFormat = GL_RGB; + m_nFileSize = m_nWidth*m_nHeight*3; + break; + case LC_RGBA: + m_nFormat = GL_RGBA; + m_nFileSize = m_nWidth*m_nHeight*4; + break; + } + + idx->ReadLong(&m_nOffset, 1); } void Texture::Unload() { - if (m_nID != 0) - glDeleteTextures(1, &m_nID); - m_nID = 0; + if (m_nID != 0) + glDeleteTextures(1, &m_nID); + m_nID = 0; } // Load from textures.bin file void Texture::Load(bool bFilter) { - unsigned char* bits; - char filename[LC_MAXPATH]; - FileDisk bin; - int size; - - strcpy(filename, project->GetLibraryPath()); - strcat(filename, "textures.bin"); - if (!bin.Open(filename, "rb")) - return; - - size = m_nWidth*m_nHeight; - if (m_nType == GL_RGB) - size *= 3; - if (m_nType == GL_RGBA) - size *= 4; - bits = (unsigned char*)malloc(size); - - bin.Seek(m_nOffset, SEEK_SET); - bin.Read(bits, size); - bin.Close(); - - if (m_nID == 0) - glGenTextures(1, &m_nID); - - glBindTexture(GL_TEXTURE_2D, m_nID); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); -// glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - if (m_nType == GL_LUMINANCE) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY4, m_nWidth, m_nHeight, - 0, m_nType, GL_UNSIGNED_BYTE, bits); - } - else - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bFilter ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bFilter ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, m_nWidth, m_nHeight, - 0, m_nType, GL_UNSIGNED_BYTE, bits); - - if (bFilter) - gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB5_A1, - m_nWidth, m_nHeight, m_nType, GL_UNSIGNED_BYTE, bits); - } - - free(bits); + char filename[LC_MAXPATH]; + FileDisk bin; + void* bits; + + strcpy(filename, project->GetLibraryPath()); + strcat(filename, "textures.bin"); + if (!bin.Open(filename, "rb")) + return; + + bits = malloc(m_nFileSize); + + bin.Seek(m_nOffset, SEEK_SET); + bin.Read(bits, m_nFileSize); + bin.Close(); + + FinishLoadImage (bFilter, bits); + + free(bits); } bool Texture::LoadFromFile(char* strFilename, bool bFilter) { - LC_IMAGE* image = OpenImage(strFilename); - - if (image == NULL) - { - if (m_nID != 0) - { - glDeleteTextures(1, &m_nID); - m_nID = 0; - } - m_nWidth = 0; - m_nHeight = 0; - - return false; - } - - m_nWidth = image->width; - m_nHeight = image->height; - m_nType = GL_RGB; - - if (m_nID == 0) - glGenTextures(1, &m_nID); - - glBindTexture(GL_TEXTURE_2D, m_nID); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bFilter ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bFilter ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, 3, m_nWidth, m_nHeight, - 0, m_nType, GL_UNSIGNED_BYTE, image->bits); - - if (bFilter) - gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, - m_nWidth, m_nHeight, m_nType, GL_UNSIGNED_BYTE, image->bits); - - free(image); - - return true; + LC_IMAGE* image = OpenImage(strFilename); + + if (image != NULL) + { + m_nWidth = image->width; + m_nHeight = image->height; + m_nFileSize = m_nWidth*m_nHeight*3; + m_nFormat = GL_RGB; + + if (FinishLoadImage (bFilter, image->bits) == true) + { + free (image); + return true; + } + free(image); + } + + if (m_nID != 0) + { + glDeleteTextures(1, &m_nID); + m_nID = 0; + } + m_nWidth = 0; + m_nHeight = 0; + m_nFileSize = 0; + + return false; +} + +bool Texture::FinishLoadImage (bool bFilter, void *data) +{ + GLint w, h, level, maxsize; + GLint i, j, k, pow2; + GLint components; + + if (data == NULL || m_nWidth < 1 || m_nHeight < 1) + return false; + + if (m_nID == 0) + glGenTextures(1, &m_nID); + + glBindTexture(GL_TEXTURE_2D, m_nID); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bFilter ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bFilter ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + switch (m_nFormat) + { + case GL_LUMINANCE: components = 1; break; + case GL_RGB: components = 3; break; + case GL_RGBA: components = 4; break; + default: return false; + } + + glGetIntegerv (GL_MAX_TEXTURE_SIZE, &maxsize); + + for (pow2 = 1; pow2 < m_nWidth; pow2 = pow2 << 1); + w = (pow2 == m_nWidth) ? m_nWidth : (pow2 << 1); + + for (pow2 = 1; pow2 < m_nHeight; pow2 = pow2 << 1); + h = (pow2 == m_nHeight) ? m_nHeight : (pow2 << 1); + + if (w > maxsize) w = maxsize; + if (h > maxsize) h = maxsize; + + if (w != m_nWidth || h != m_nHeight) + { + data = ResizeImage ((GLubyte*)data, components, m_nWidth, m_nHeight, w, h); + m_nWidth = w; + m_nHeight = h; + if (data == NULL) + return false; + } + else + { + void *tmp = malloc (w*h*components); + memcpy (tmp, data, w*h*components); + data = tmp; + } + + if (m_nFormat == GL_LUMINANCE) + glTexImage2D (GL_TEXTURE_2D, 0, GL_INTENSITY4, w, h, 0, m_nFormat, GL_UNSIGNED_BYTE, data); + else + glTexImage2D (GL_TEXTURE_2D, 0, components, w, h, 0, m_nFormat, GL_UNSIGNED_BYTE, data); + + if (bFilter) + for (level = 1; ((w != 1) && (h != 1)); level++) + { + GLubyte *out, *in; + int row; + + row = w * components; + if (w != 1) w >>= 1; + if (h != 1) h >>= 1; + in = out = (GLubyte*)data; + + for (i = 0; i < h; i++, in+=row) + for (j = 0; j < w; j++, out+=components, in+=2*components) + for (k = 0; k < components; k++) + out[k] = (in[k] + in[k+components] + in[row] + in[row+k+components])>>2; + + glTexImage2D (GL_TEXTURE_2D, level, components, w, h, 0, m_nFormat, GL_UNSIGNED_BYTE, data); + } + + free (data); + return true; } diff --git a/common/texture.h b/common/texture.h index 546c7c8..52c223b 100644 --- a/common/texture.h +++ b/common/texture.h @@ -5,46 +5,45 @@ #ifndef _TEXTURE_H #define _TEXTURE_H -#ifndef GLuint -#include -#endif - class File; typedef enum { LC_INTENSITY, LC_RGB, LC_RGBA } LC_TEXTURE_TYPES; class Texture { -public: - Texture(); - ~Texture(); - - void MakeCurrent() - { - if (m_nID != 0) - { glBindTexture(GL_TEXTURE_2D, m_nID); } - } - - bool IsLoaded() - { return glIsTexture(m_nID) == GL_TRUE; } - void Load(bool bFilter); - bool LoadFromFile(char* strFilename, bool bFilter); - void Unload(); - - void LoadIndex(File* idx); - void AddRef(bool bFilter); - void DeRef(); - - // Read-only - char m_strName[9]; - unsigned short m_nWidth; - unsigned short m_nHeight; + public: + Texture(); + ~Texture(); + + void MakeCurrent() + { + if (m_nID != 0) + glBindTexture(GL_TEXTURE_2D, m_nID); + } + + bool IsLoaded() + { return ((m_nID != 0) && (glIsTexture(m_nID) == GL_TRUE)); } + void Load(bool bFilter); + bool LoadFromFile(char* strFilename, bool bFilter); + void Unload(); + + void LoadIndex(File* idx); + void AddRef(bool bFilter); + void DeRef(); + + // Read-only + char m_strName[9]; + unsigned short m_nWidth; + unsigned short m_nHeight; protected: - int m_nRef; - GLuint m_nID; - GLenum m_nType; - unsigned long m_nOffset; + bool FinishLoadImage (bool bFilter, void *data); + + int m_nRef; + GLuint m_nID; + GLenum m_nFormat; + unsigned long m_nOffset; + unsigned long m_nFileSize; }; -- cgit v1.2.3