// Texture object. // #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; } Texture::~Texture() { } ///////////////////////////////////////////////////////////////////////////// // Texture attributes void Texture::AddRef(bool bFilter) { if (m_nRef == 0) Load(bFilter); m_nRef++; } void Texture::DeRef() { m_nRef--; if (m_nRef == 0) Unload(); } ///////////////////////////////////////////////////////////////////////////// // Load methods 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_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; } // Load from textures.bin file void Texture::Load(bool bFilter) { 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) { 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; }