summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorleo2000-05-25 15:19:53 +0000
committerleo2000-05-25 15:19:53 +0000
commit06edf761241eee2323d5e263f2b0e153169a76d9 (patch)
treef3e6248636fd8c7ebf9175161721eb77bfa8edc6
parentdaaff783a77e2fa5a35678091663c3a6fa850e25 (diff)
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
-rw-r--r--common/texture.cpp335
-rw-r--r--common/texture.h63
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 <string.h>
#include <stdlib.h>
+#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 <GL/gl.h>
-#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;
};