00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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 const unsigned long Texture::TX_RESERVED = (1ul<<0ul);
00040 const unsigned long Texture::TX_BLIT_NO_SCALE = (1ul<<1ul);
00041 const unsigned long Texture::TX_GENERATE_ALPHA = (1ul<<2ul);
00042 const unsigned long Texture::TX_ALPHA_ONLY = (1ul<<3ul);
00043 const unsigned long Texture::TX_NO_ALPHA = (1ul<<4ul);
00044
00045 const unsigned long Texture::WRAP_REPEAT = 1 ;
00046 const unsigned long Texture::WRAP_CLAMP = 2 ;
00047
00048 const unsigned long Texture::ENV_BLEND = 1;
00049 const unsigned long Texture::ENV_REPLACE = 2;
00050 const unsigned long Texture::ENV_DECAL = 3;
00051 const unsigned long Texture::ENV_MODULATE = 4;
00052
00053 const unsigned long Texture::FORMAT_INTENSITY = 1;
00054 const unsigned long Texture::FORMAT_LUMINANCE = 2;
00055 const unsigned long Texture::FORMAT_LUMINANCE_ALPHA = 3;
00056 const unsigned long Texture::FORMAT_ALPHA = 4;
00057 const unsigned long Texture::FORMAT_RGB = 5;
00058 const unsigned long Texture::FORMAT_RGBA = 6;
00059
00060 const unsigned long Texture::FILTER_NEAREST = 1;
00061 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 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
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
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
00283 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
00284 View::check();
00285 bool scale = false;
00286 IntVector2 new_size = size;
00287
00288
00289
00290
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
00301
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 ){
00335 x = 1 - x;
00336 scale = true;
00337 if( x==0 ){
00338 new_size[1] = new_size[1] / 2;
00339 }else{
00340 new_size[0] = new_size[0] / 2;
00341 }
00342 }else{
00343 if( format == gl_internal_format ){
00344 break;
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
00365 void *new_data = NULL;
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
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 };
00489 };
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528