Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

Texture.cpp

Go to the documentation of this file.
00001 
00002 /*
00003     TEDDY - General graphics application library
00004     Copyright (C) 1999-2002  Timo Suoranta
00005     tksuoran@cc.helsinki.fi
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2.1 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 
00021     $Id: Texture.cpp,v 1.5 2002/01/11 14:34:59 tksuoran Exp $
00022 */
00023 
00024 
00025 #include "Teddy/TeddyConfig.h"
00026 #include "Teddy/Graphics/Texture.h"
00027 #include "Teddy/Graphics/View.h"
00028 #include "Teddy/Graphics/glu_mipmap.h"
00029 #include "Teddy/SysSupport/Messages.h"
00030 #include <cstdlib>
00031 using namespace Teddy::Maths;
00032 using namespace Teddy::SysSupport;
00033 
00034 
00035 namespace Teddy    {
00036 namespace Graphics {
00037 
00038 
00039 /*static*/ const unsigned long Texture::TX_RESERVED         = (1ul<<0ul);
00040 /*static*/ const unsigned long Texture::TX_BLIT_NO_SCALE    = (1ul<<1ul);
00041 /*static*/ const unsigned long Texture::TX_GENERATE_ALPHA   = (1ul<<2ul);
00042 /*static*/ const unsigned long Texture::TX_ALPHA_ONLY       = (1ul<<3ul);
00043 /*static*/ const unsigned long Texture::TX_NO_ALPHA         = (1ul<<4ul);
00044 
00045 /*static*/ const unsigned long Texture::WRAP_REPEAT         =     1     ;
00046 /*static*/ const unsigned long Texture::WRAP_CLAMP          =     2     ;
00047 
00048 /*static*/ const unsigned long Texture::ENV_BLEND              =  1;
00049 /*static*/ const unsigned long Texture::ENV_REPLACE            =  2;
00050 /*static*/ const unsigned long Texture::ENV_DECAL              =  3;
00051 /*static*/ const unsigned long Texture::ENV_MODULATE           =  4;
00052 
00053 /*static*/ const unsigned long Texture::FORMAT_INTENSITY       =  1;
00054 /*static*/ const unsigned long Texture::FORMAT_LUMINANCE       =  2;
00055 /*static*/ const unsigned long Texture::FORMAT_LUMINANCE_ALPHA =  3;
00056 /*static*/ const unsigned long Texture::FORMAT_ALPHA           =  4;
00057 /*static*/ const unsigned long Texture::FORMAT_RGB             =  5;
00058 /*static*/ const unsigned long Texture::FORMAT_RGBA            =  6;
00059 
00060 /*static*/ const unsigned long Texture::FILTER_NEAREST         =  1;
00061 /*static*/ const unsigned long Texture::FILTER_LINEAR          =  2;
00062 
00063 
00069 static int minPow( GLuint value ){
00070     GLuint i = 2;
00071 
00072     while( i<value ) i *= 2;
00073     return i;
00074 }
00075 
00076 
00081 Texture::Texture( const std::string &name )
00082 :
00083 Named( name )
00084 {
00085     this->is_good                = false;
00086     this->work_data              = NULL;
00087     this->work_data_pixel_format = 0;
00088     this->work_data_allocated    = false;
00089     this->gl_internal_format     = 0;
00090     this->env_function           = ENV_MODULATE;
00091     this->env_color              = Color(0,0,0,0);
00092     this->filter_mode            = FILTER_NEAREST;
00093     this->wrap_s                 = WRAP_REPEAT;
00094     this->wrap_t                 = WRAP_REPEAT;
00095     this->options                = 0;
00096     this->modify                 = 0;
00097 
00098 #   if defined( USE_TINY_GL )
00099     this->env_function       = ENV_DECAL;
00100 #   endif
00101 
00102     glGenTextures( 1, &gl_texture_id );
00103 }
00104 
00105 
00107 /*virtual*/ Texture::~Texture(){
00108     glDeleteTextures( 1, &gl_texture_id );
00109     setWorkData( NULL );
00110 }
00111 
00112 
00114 void Texture::apply(){
00115     if( is_good ){
00116         glBindTexture( GL_TEXTURE_2D, gl_texture_id );
00117     }else{
00118         emsg( M_MAT, "Texture::apply() texture is not good" );
00119     }
00120 
00121 }
00122 
00123 
00128 bool Texture::isGood(){
00129     return is_good;
00130 }
00131 
00132 
00138 void Texture::setWrap( int wrap_s, int wrap_t ){
00139     this->wrap_s = wrap_s;
00140     this->wrap_t = wrap_t;
00141 }
00142 
00143 
00148 void Texture::setEnv( int env_function ){
00149     this->env_function = env_function;
00150 }
00151 
00152 
00158 void Texture::setEnv( int env_function, const Color &env_color ){
00159 #   if !defined( USE_TINY_GL )
00160     this->env_function = env_function;
00161     this->env_color    = env_color;
00162 #   endif
00163 }
00164 
00165 
00170 void Texture::setFilter( int filter_mode ){
00171     this->filter_mode = filter_mode;
00172 }
00173 
00174 
00179 const IntVector2 &Texture::getSize(){
00180     return size;
00181 }
00182 
00183 
00192 void Texture::putData( unsigned char *data, const IntVector2 &size, int format, unsigned long modify ){
00193     switch( format ){
00194         case FORMAT_INTENSITY      : work_data_pixel_format = GL_INTENSITY;       break;
00195         case FORMAT_LUMINANCE      : work_data_pixel_format = GL_LUMINANCE;       break;
00196         case FORMAT_LUMINANCE_ALPHA: work_data_pixel_format = GL_LUMINANCE_ALPHA; break;
00197         case FORMAT_ALPHA          : work_data_pixel_format = GL_ALPHA;           break;
00198         case FORMAT_RGB            : work_data_pixel_format = GL_RGB;             break;
00199         case FORMAT_RGBA           : work_data_pixel_format = GL_RGBA;            break;
00200         default:
00201             emsg( M_MAT, "Texture::putData() unknown format" );
00202             break;
00203     }
00204     this->size   = size;
00205     this->modify = modify;
00206 
00207     gl_internal_format = work_data_pixel_format;
00208 
00209     setWorkData( data, false );
00210     doFormat();
00211     doSize();
00212 }
00213 
00214 
00224 void Texture::setWorkData( void *vdata, bool alloc ){
00225     unsigned char *data = (unsigned char *)vdata;
00226     if( work_data_allocated == true ){
00227         delete[] work_data;
00228     }
00229     work_data = data;
00230     if( alloc == true ){
00231         if( data != NULL ){
00232             work_data_allocated = true;
00233         }else{
00234             work_data_allocated;
00235         }
00236     }
00237 }
00238 
00239 
00241 bool Texture::doFormat(){
00242 
00243 #   if defined( USE_TINY_GL )
00244 
00245     convert_to_rgb();
00246 
00247 #   else
00248 
00249     //  Generate, add and remove alpha channel
00250     if( modify.isEnabled(TX_NO_ALPHA) ){
00251         switch( work_data_pixel_format ){
00252         case GL_INTENSITY      : gl_internal_format = GL_INTENSITY; break;
00253         case GL_LUMINANCE      : gl_internal_format = GL_LUMINANCE; break;
00254 //      case GL_LUMINANCE_ALPHA: gl_internal_format = GL_LUMINANCE;
00255         case GL_ALPHA          : gl_internal_format     = GL_LUMINANCE;
00256                                  work_data_pixel_format = GL_LUMINANCE; break;
00257         case GL_RGB            : gl_internal_format = GL_RGB; break;
00258         case GL_RGBA           : gl_internal_format = GL_RGB; break;
00259         default:
00260             emsg( M_MAT, "Texture::doFormat() problem" );
00261             return false;
00262         }
00263     }else if( modify.isEnabled(TX_GENERATE_ALPHA) ){
00264         if( modify.isEnabled(TX_ALPHA_ONLY) ){
00265             convert_to_a();
00266         }
00267     }
00268 
00269 #   endif
00270 
00271     return true;
00272 }
00273 
00274 
00276 bool Texture::doSize(){
00277 
00278 #   if defined( USE_TINY_GL )
00279     gl_internal_format = GL_RGB;
00280 #   endif
00281 
00282     //  Scale if needed
00283     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
00284     View::check();
00285     bool scale      = false;
00286     IntVector2 new_size = size;
00287 
00288     //  Scaling process should make sure that all
00289     //  texture sizes are ok to the OpenGL driver,
00290     //  which may be different on any machine.
00291     if( new_size[0] != minPow(new_size[0]) ){
00292         new_size[0] = minPow( new_size[0] );
00293         scale     = true;
00294     }
00295     if( new_size[1] != minPow(new_size[1]) ){
00296         new_size[1]  = minPow( new_size[1] );
00297         scale      = true;
00298     }
00299 
00300     //  See if texture size is ok for OpenGL driver
00301     //  Does not seem to work :/
00302 
00303 #   if defined( USE_TINY_GL )
00304 
00305     if( new_size[0] > 256 ){
00306         new_size[0] = 256;
00307         scale = true;
00308     }
00309     if( new_size[1] > 256 ){
00310         new_size[1] = 256;
00311         scale = true;
00312     }
00313 
00314 #   else
00315 
00316     if( new_size[0] > 1024 ){
00317         new_size[0] = 1024;
00318         scale = true;
00319     }
00320     if( new_size[1] > 512 ){
00321         new_size[1] = 512;
00322         scale = true;
00323     }
00324 
00325     GLint format = 0;
00326     int   x      = 0;
00327     int   tries  = 0;
00328 
00329     for( tries=0; tries<1000; tries++ ){
00330         glTexImage2D( GL_PROXY_TEXTURE_2D, 0, gl_internal_format, new_size[0], new_size[1], 0, work_data_pixel_format, GL_UNSIGNED_BYTE, NULL );
00331         glGetTexLevelParameteriv( GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format );
00332         View::check();
00333 
00334         if( format == 0 ){  //  if not, go down in size
00335             x     = 1 - x;
00336             scale = true;
00337             if( x==0 ){
00338                 new_size[1] = new_size[1] / 2;  //  halve height
00339             }else{
00340                 new_size[0] = new_size[0] / 2;   //  halve width
00341             }
00342         }else{
00343             if( format == gl_internal_format ){
00344                 break;  //  ok size!
00345             }else{
00346                 emsg( M_MAT, "format?! 0x%x\n", format );
00347                 break;
00348             }
00349         }
00350         if( new_size[0]==0 || new_size[1]==0 ){
00351             emsg( M_MAT, "Can not find memory for texture - Giving up!" );
00352             return false;
00353         }
00354     }
00355 
00356     if( tries==1000 ){
00357         emsg( M_MAT, "Can not find memory for texture after 1000 tries - Giving up!" );
00358         return false;
00359     }
00360 
00361 #   endif
00362 
00363     if( scale ){
00364         //debug_msg( "Doing scale from %d x %d to %d x %d", width, height, new_width, new_height );
00365         void *new_data = NULL;//new unsigned char[ new_width * new_height * gl_components];
00366         glu_ScaleImage(
00367             work_data_pixel_format,
00368             size[0],     size[1],     GL_UNSIGNED_BYTE,  work_data,
00369             new_size[0], new_size[1], GL_UNSIGNED_BYTE, &new_data
00370         );
00371         View::check();
00372 
00373         setWorkData( new_data );
00374         this->size = new_size;
00375     }
00376     //debug_msg( "Texture size %d x %d", width, height );
00377 
00378     return true;
00379 }
00380 
00381 
00383 bool Texture::doBind(){
00384     glBindTexture( GL_TEXTURE_2D,       gl_texture_id );
00385     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
00386     View::check();
00387 
00388     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
00389     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
00390     View::check();
00391 
00392     switch( filter_mode ){
00393     default:
00394         emsg( M_MAT, "Unknown texture filter mode" );
00395     case FILTER_NEAREST:
00396         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
00397         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
00398         break;
00399 
00400     case FILTER_LINEAR:
00401         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00402         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
00403         break;
00404     }
00405     View::check();
00406 
00407     switch( wrap_s ){
00408     default:
00409         emsg( M_MAT, "Unknown texture wrap mode" );
00410     case WRAP_REPEAT:
00411         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
00412         break;
00413     case WRAP_CLAMP:
00414         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
00415         break;
00416     }
00417     View::check();
00418 
00419     switch( wrap_t ){
00420     default:
00421         emsg( M_MAT, "Unknown texture wrap mode" );
00422     case WRAP_REPEAT:
00423         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
00424         break;
00425     case WRAP_CLAMP:
00426         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
00427         break;
00428     }
00429     View::check();
00430 
00431 #   if !defined( USE_TINY_GL )
00432     switch( env_function ){
00433     default: 
00434         emsg( M_MAT, "Unknown texture function" );
00435     case ENV_BLEND   : 
00436         glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,  GL_BLEND       );
00437         glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env_color.rgba ); 
00438         break;
00439     case ENV_REPLACE:
00440         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE  );
00441         break;
00442     case ENV_DECAL:
00443         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL    );
00444         break;
00445     case ENV_MODULATE:
00446         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
00447         break;
00448     }
00449     View::check();
00450 
00451     if( modify.isEnabled(TX_BLIT_NO_SCALE) == true ){
00452         glTexImage2D(
00453             GL_TEXTURE_2D, 
00454             0, 
00455             gl_internal_format, 
00456             size[0], size[1],
00457             0, 
00458             work_data_pixel_format, 
00459             GL_UNSIGNED_BYTE, 
00460             work_data
00461         );
00462     View::check();
00463     }else{
00464         int error = glu_Build2DMipmaps(
00465             GL_TEXTURE_2D,
00466             gl_internal_format, 
00467             size[0], size[1],
00468             work_data_pixel_format, 
00469             GL_UNSIGNED_BYTE, 
00470             work_data 
00471         );
00472 
00473         if( error != 0 ){
00474             emsg( M_MAT, "glu_Build2DMipmaps() failed" );
00475             return false;
00476         } 
00477     };
00478 
00479 #   else
00480     glTexImage2D( GL_TEXTURE_2D, 0, 3, size[0], size[1], 0, work_data_pixel_format, GL_UNSIGNED_BYTE, work_data );
00481 #   endif
00482     View::check();
00483     is_good = true;
00484     return true;
00485 }
00486 
00487 
00488 };  //  namespace Graphics
00489 };  //  namespace Teddy
00490 
00491 
00492 /*
00493 
00494 Useful extensions:
00495 
00496 GL_IBM_texture_mirrored_repeat
00497 GL_EXT_texture_filter_anisotropic (GL_TEXTURE_MAX_ANISOTROPY_EXT)
00498 GL_ARB_texture_compression
00499 GL_EXT_texture_compression_s3tc
00500 
00501 Texture formats:
00502 
00503 GL_INTENSITY
00504 GL_LUMINANCE
00505 GL_ALPHA
00506 GL_LUMINANCE_ALPHA
00507 GL_RGB
00508 GL_RGBA
00509 
00510 GL_ARB_texture_compression:
00511 
00512 GL_COMPRESSED_ALPHA_ARB
00513 GL_COMPRESSED_LUMINANCE_ARB
00514 GL_COMPRESSED_INTENSITY_ARB
00515 GL_COMPRESSED_LUMINANCE_ALPHA_ARB
00516 GL_COMPRESSED_RGB_ARB
00517 GL_COMPRESSED_RGBA_ARB
00518 
00519 GL_EXT_texture_compression_s3tc:
00520 
00521 GL_COMPRESSED_RGB_S3TC_DXT1_EXT
00522 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
00523 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
00524 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
00525 
00526 */
00527 
00528