/*************************************************************************** texture.cpp - A texture class ------------------- begin : Tue Jun 18 2002 copyright : (C) 2002 by CJP email : cornware-cjp@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "texture.h" #include "image.h" #include "datafile.h" #include #include #include #include CTexture::CTexture(CDataManager *manager) : CDataObject(manager, CDataObject::eMaterial) { m_Color = CVector(0,0,0); m_TextureSmooth = true; //default m_Texture = 0; m_Sizex = m_Sizey = 256; } CTexture::~CTexture() { unload(); } bool CTexture::load(const CString &filename, const CParamList &list) { CDataObject::load(filename, list); m_Sizex = m_ParamList.getValue("sizex", "256").toInt(); m_Sizey = m_ParamList.getValue("sizey", "256").toInt(); m_TextureSmooth = m_ParamList.getValue("smooth", "true") == "true"; CDataFile f(m_Filename); RGBImageRec *in_image = loadImage(f.useExtern()); in_image = loadFromImage(in_image, m_Sizex, m_Sizey); freeImage(in_image); return true; } void CTexture::unload() { if(!isLoaded()) return; glDeleteTextures(1, &m_Texture); m_Texture = 0; CDataObject::unload(); } RGBImageRec *CTexture::loadImage(CString filename) { return GenericImageLoad(filename.c_str()); } /* free's in_image returns either a malloc'ed image, or NULL Sometimes in_image is returned, and nothing is malloc'ed or free'd */ RGBImageRec *CTexture::loadFromImage(RGBImageRec *in_image, int xs, int ys) { RGBImageRec *image; image = scaleImage(in_image, xs, ys); if(image==NULL) { image = in_image; //in_image is not freed because we use it } else { freeImage(in_image); //no longer used because we have image } glGenTextures(1, &m_Texture); glBindTexture(GL_TEXTURE_2D, m_Texture); if(image->format == 1) //RGBA {glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, image->sizeX, image->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->data);} else //Assume RGB {glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, image->sizeX, image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data);} glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); if(m_TextureSmooth) { glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); } else { glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); } m_Sizex = image->sizeX; m_Sizey = image->sizeY; //determine color RGBImageRec *image2 = scaleImage(image, 1,1); if(image2==NULL) { m_Color.x = (float)*(image->data ) / 255; m_Color.y = (float)*(image->data+1) / 255; m_Color.z = (float)*(image->data+2) / 255; } else { m_Color.x = (float)*(image2->data ) / 255; m_Color.y = (float)*(image2->data+1) / 255; m_Color.z = (float)*(image2->data+2) / 255; freeImage(image2); } return image; } void CTexture::freeImage(RGBImageRec *image) { if(image != NULL) { if(image->data != NULL) free(image->data); free(image); } } void CTexture::draw() const { if (getSizeX() <= 4 || getSizeY() <= 4) {printf(" Error: trying to draw a too small texture:\n" " x=%d, y=%d\n", getSizeX(), getSizeY()); return;} glBindTexture(GL_TEXTURE_2D, m_Texture ); } int CTexture::getSizeX() const { return m_Sizex; } int CTexture::getSizeY() const { return m_Sizey; } CVector CTexture::getColor() const { //printf("Returning texture color: %f,%f,%f\n", m_Color.x, m_Color.y, m_Color.z); return m_Color; } /* returns NULL when in already has the right size */ RGBImageRec *CTexture::scaleImage(RGBImageRec *in, int xs, int ys) { int sizex,sizey; unsigned char *bitmapdata; RGBImageRec *out; if(xs < 1) xs = 1; if(ys < 1) ys = 1; sizex = (in->sizeX>xs)? xs : in->sizeX; sizey = (in->sizeY>ys)? ys : in->sizeY; if(sizex==in->sizeX && sizey==in->sizeY) return NULL; //don't scale; use the same texture bitmapdata = (unsigned char *)malloc(4*sizex*sizey*sizeof(unsigned char)); out = (RGBImageRec *)malloc(sizeof(RGBImageRec)); out->data = bitmapdata; out->sizeX = sizex; out->sizeY = sizey; out->format = in->format; #undef USE_GLUSCALE //I guess gluscaleImage is faster than my own algoritm, //But it gives poor textures at low-res. #ifdef USE_GLUSCALE if(sizex >= 4 && sizey >= 4) { if(in->format == 1) //RGBA { gluScaleImage(GL_RGBA, in->sizeX, in->sizeY, GL_UNSIGNED_BYTE, in->data, out->sizeX, out->sizeY, GL_UNSIGNED_BYTE, out->data ); } else //assume RGB { gluScaleImage(GL_RGB, in->sizeX, in->sizeY, GL_UNSIGNED_BYTE, in->data, out->sizeX, out->sizeY, GL_UNSIGNED_BYTE, out->data ); } } else //still need my own algoritm for very small sizes { #endif int bsx; int bsy; int opp=1; int i, j, x, y; int r, g, b, a; int pixsize = 3; //RGB if(in->format == 1) pixsize = 4; //RGBA bsx = in->sizeX / xs; bsy = in->sizeY / ys; if(bsx<1) {bsx=1;} if(bsy<1) {bsy=1;} opp = bsx*bsy; //printf("Oorspronkelijke resolutie: %dx%d\n",in->sizeX, in->sizeY); //printf("Resizing with blocksize %dx%d...\n",bsx,bsy); for(x=0; xdata + pixsize*(bsx*x+i+in->sizeX*(bsy*y+j)) ); g += *(in->data + pixsize*(bsx*x+i+in->sizeX*(bsy*y+j)) +1); b += *(in->data + pixsize*(bsx*x+i+in->sizeX*(bsy*y+j)) +2); if(in->format == 1) a += *(in->data + pixsize*(bsx*x+i+in->sizeX*(bsy*y+j)) +3); } *(bitmapdata + pixsize*(x+sizex*y) ) = r/opp; *(bitmapdata + pixsize*(x+sizex*y) +1) = g/opp; *(bitmapdata + pixsize*(x+sizex*y) +2) = b/opp; if(in->format == 1) *(bitmapdata + pixsize*(x+sizex*y) +3) = a/opp; } #ifdef USE_GLUSCALE } #endif return out; }