mirror of
https://github.com/leozide/leocad
synced 2024-11-17 07:47:55 +01:00
271 lines
5.9 KiB
C++
271 lines
5.9 KiB
C++
// Texture object.
|
|
//
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "opengl.h"
|
|
#include "file.h"
|
|
#include "texture.h"
|
|
#include "project.h"
|
|
#include "globals.h"
|
|
#include "image.h"
|
|
#include "library.h"
|
|
#include "lc_application.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_ALPHA;
|
|
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, lcGetPiecesLibrary()->GetLibraryPath());
|
|
strcat(filename, "textures.bin");
|
|
if (!bin.Open(filename, "rb"))
|
|
return;
|
|
|
|
if (m_nFormat == GL_LUMINANCE_ALPHA)
|
|
bits = malloc (m_nFileSize*2);
|
|
else
|
|
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)
|
|
{
|
|
Image image;
|
|
|
|
if (image.FileLoad (strFilename))
|
|
{
|
|
image.ResizePow2 ();
|
|
|
|
m_nWidth = image.Width ();
|
|
m_nHeight = image.Height ();
|
|
|
|
if (image.Alpha ())
|
|
m_nFormat = GL_RGBA;
|
|
else
|
|
m_nFormat = GL_RGB;
|
|
|
|
if (FinishLoadImage (bFilter, image.GetData ()) == true)
|
|
return true;
|
|
}
|
|
|
|
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_ALPHA: components = 2; break;
|
|
case GL_RGB: components = 3; break;
|
|
case GL_RGBA: components = 4; break;
|
|
default: return false;
|
|
}
|
|
|
|
// create an alpha channel for the texture
|
|
if (m_nFormat == GL_LUMINANCE_ALPHA)
|
|
for (i = m_nWidth*m_nHeight-1; i >= 0; i--)
|
|
((GLubyte*)data)[i*2+1] = ((GLubyte*)data)[i*2] = ((GLubyte*)data)[i];
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|