Back to index

extremetuxracer  0.5beta
textures.cpp
Go to the documentation of this file.
00001 /* 
00002  * PPRacer 
00003  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00004  *
00005  * Copyright (C) 1999-2001 Jasmin F. Patry
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program 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
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020  */
00021 
00022 #include "textures.h"
00023 #include "game_config.h"
00024 #include <string>
00025 #include <list>
00026 #include <map>
00027 #include <GL/glext.h>
00028 
00029 #include "ppgltk/images/image.h"
00030 
00031 static std::map<std::string,texture_node_t> textureTable;
00032 static std::map<std::string,texture_node_t> bindingTable;
00033 
00034 
00035 bool get_texture_binding( const char *binding, GLuint *texid )
00036 {
00037     std::map<std::string,texture_node_t>::iterator texnode;
00038     if ( (texnode = bindingTable.find(binding))!=bindingTable.end() ){
00039               *texid = texnode->second.texture_id;
00040               return true;
00041     }
00042     return false;  
00043 }
00044 
00045 bool load_and_bind_texture( const char *binding, const char *filename )
00046 {
00047     return (bool) ( load_texture( binding, filename, 1 ) &&
00048                     bind_texture( binding, binding ) );
00049 }
00050 
00051 void init_textures() 
00052 {
00053 } 
00054 
00055 int get_min_filter()
00056 {
00057     switch( getparam_mipmap_type() ) {
00058     case 0: 
00059        return GL_NEAREST;
00060     case 1:
00061        return GL_LINEAR;
00062     case 2: 
00063        return GL_NEAREST_MIPMAP_NEAREST;
00064     case 3: 
00065        return GL_LINEAR_MIPMAP_NEAREST;
00066     case 4: 
00067        return GL_NEAREST_MIPMAP_LINEAR;
00068     case 5: 
00069        return GL_LINEAR_MIPMAP_LINEAR;
00070     default:
00071        return GL_LINEAR_MIPMAP_NEAREST;
00072     }
00073 }
00074 
00075 bool load_texture( const char *texname, const char *filename, int repeatable )
00076 {
00077        pp::Image *texImage = pp::Image::readFile(filename);
00078        
00079     texture_node_t *tex;
00080     int max_texture_size;
00081 
00082 
00083     print_debug(DEBUG_TEXTURE, "Loading texture %s from file: %s", 
00084               texname, filename);
00085 
00086     if ( texImage == NULL ) {
00087        print_warning( IMPORTANT_WARNING, 
00088                      "couldn't load image %s", filename );
00089        return false;
00090     }
00091 
00092        std::map<std::string,texture_node_t>::iterator it;
00093     if ( (it = textureTable.find(texname))!=textureTable.end() ){
00094               tex = &it->second;
00095               print_debug(DEBUG_TEXTURE, "Found texture %s with id: %d", 
00096                   texname, it->second.texture_id);
00097         glDeleteTextures( 1, &(tex->texture_id) );
00098        }else{
00099               tex = &textureTable[texname];
00100               tex->ref_count = 0;
00101        }
00102     
00103     tex->repeatable = repeatable;
00104     glGenTextures( 1, &(tex->texture_id) );
00105     glBindTexture( GL_TEXTURE_2D, tex->texture_id );
00106 
00107     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
00108 
00109 
00110     if ( repeatable ) {
00111               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
00112               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
00113     } else {
00114               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
00115               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
00116     }
00117     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00118     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
00119                      get_min_filter() );
00120               
00121     /* Check if we need to scale image */
00122     glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*) &max_texture_size );
00123     if ( texImage->width > max_texture_size ||
00124         texImage->height > max_texture_size ) 
00125     {
00126        char *newdata = (char*)malloc( texImage->depth *
00127                                    max_texture_size *
00128                                    max_texture_size );
00129 
00130        check_assertion( newdata != NULL, "out of memory" );
00131 
00132        print_debug( DEBUG_TEXTURE, "Texture `%s' too large -- scaling to "
00133                    "maximum allowed size",
00134                    filename );
00135 
00136        /* In the case of large- or small-aspect ratio textures, this
00137            could end up using *more* space... oh well. */
00138        gluScaleImage( texImage->depth == 3 ? GL_RGB : GL_RGBA,
00139                      texImage->width, texImage->height, 
00140                      GL_UNSIGNED_BYTE,
00141                      texImage->data,
00142                      max_texture_size, max_texture_size, 
00143                      GL_UNSIGNED_BYTE,
00144                      newdata );
00145 
00146        free( texImage->data );
00147        texImage->data = (unsigned char*) newdata;
00148        texImage->width = max_texture_size;
00149        texImage->height = max_texture_size;
00150     }
00151 
00152     gluBuild2DMipmaps( GL_TEXTURE_2D, texImage->depth, texImage->width,
00153                      texImage->height, texImage->depth == 3 ? GL_RGB : GL_RGBA, 
00154                      GL_UNSIGNED_BYTE, texImage->data );
00155 
00156        delete texImage;
00157 
00158     return true;
00159 } 
00160 
00161 
00162 texture_node_t*
00163 get_texture( const char *texname)
00164 {
00165        std::map<std::string,texture_node_t>::iterator it;
00166        
00167        if ( (it = textureTable.find(texname))!=textureTable.end() ){
00168               return &(it->second);
00169        }else{
00170               return NULL;
00171        }
00172 }
00173 
00174 
00175 bool
00176 del_texture( const char *texname )
00177 {
00178     
00179        print_debug( DEBUG_TEXTURE, "Deleting texture %s", texname );
00180 
00181        std::map<std::string,texture_node_t>::iterator it;
00182        if ( (it = textureTable.find(texname))!= textureTable.end() ){
00183               check_assertion( it->second.ref_count == 0,
00184                       "Trying to delete texture with non-zero reference "
00185                             "count" );
00186               glDeleteTextures( 1, &(it->second.texture_id) );
00187               textureTable.erase(it);
00188               return true;
00189     }
00190        return false;
00191 }
00192 
00193 
00194 bool bind_texture( const char *binding, const char *texname )
00195 {
00196     
00197        texture_node_t *tex;
00198        
00199        print_debug(DEBUG_TEXTURE, "Binding %s to texture name: %s", 
00200               binding, texname);
00201        
00202        tex = get_texture( texname );
00203        
00204        if (tex == NULL){
00205               print_warning( IMPORTANT_WARNING, 
00206                      "Attempt to bind to Texture unloaded texture: `%s'\n", texname );
00207               return false;
00208        }
00209 
00210        std::map<std::string,texture_node_t>::iterator oldtex;
00211     if ( (oldtex = bindingTable.find(binding))!=bindingTable.end() ){
00212               oldtex->second.ref_count--;
00213               bindingTable.erase(oldtex);
00214     }
00215 
00216        bindingTable[binding] = *tex;
00217        tex->ref_count++;
00218 
00219     return true;
00220 }
00221 
00222 bool unbind_texture( const char *binding )
00223 {
00224        std::map<std::string,texture_node_t>::iterator tex;
00225        if ( (tex = bindingTable.find(binding))!=bindingTable.end() ){
00226               tex->second.ref_count--;
00227               bindingTable.erase(tex);
00228               return true;
00229        }
00230        return false;
00231 }
00232 
00233 void get_current_texture_dimensions( int *width, int *height )
00234 {
00235     glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, (GLint*) width );
00236     glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, (GLint*) height );
00237 }
00238 
00239 bool flush_textures(void)
00240 {
00241        bool result;
00242        std::map<std::string,texture_node_t>::iterator mapit;
00243        for(mapit=textureTable.begin();mapit!=textureTable.end(); mapit++){
00244               if (mapit->second.ref_count == 0) {
00245                      result = del_texture( (*mapit).first.c_str() );
00246                      check_assertion(result, "Attempt to flush non-existant texture");     
00247                   // RK: reset pointer to start of table since mapit got deleted
00248             mapit = textureTable.begin();
00249               }
00250        }
00251        return true;
00252 }
00253 
00254 static int load_texture_cb ( ClientData cd, Tcl_Interp *ip, int argc, 
00255                           CONST84 char *argv[]) 
00256 {
00257     int repeatable = 1;
00258 
00259     if ( ( argc != 3 ) && (argc != 4) ) {
00260        Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n", 
00261                       "Usage: ", argv[0], "<texture name> <image file>",
00262                       " [repeatable]", (char *)0 );
00263        return TCL_ERROR;
00264     } 
00265 
00266     if ( ( argc == 4 ) && ( Tcl_GetInt( ip, argv[3], &repeatable ) != TCL_OK ) ) {
00267         Tcl_AppendResult(ip, argv[0], ": invalid repeatable flag",
00268                       (char *)0 );
00269         return TCL_ERROR;
00270     } 
00271     
00272     if (!load_texture(argv[1], argv[2], repeatable)) {
00273        Tcl_AppendResult(ip, argv[0], ": Could not load texture ", 
00274                       argv[2], (char*)0);
00275        return TCL_ERROR;
00276     }
00277 
00278     return TCL_OK;
00279 }
00280 
00281 static int bind_texture_cb ( ClientData cd, Tcl_Interp *ip, int argc, 
00282                           CONST84 char *argv[])
00283 {
00284     if ( argc != 3 ) {
00285        Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n", 
00286                       "Usage: ", argv[0], "<object name> <texture name>",
00287                       (char *)0 );
00288        return TCL_ERROR;
00289     } 
00290 
00291     if (!bind_texture(argv[1], argv[2])) {
00292        Tcl_AppendResult(ip, argv[0], ": Could not bind texture ", 
00293                       argv[2], (char*)0);
00294        return TCL_ERROR;
00295     }
00296 
00297     return TCL_OK;
00298 }
00299 
00300 
00301 void register_texture_callbacks( Tcl_Interp *ip )
00302 {
00303     Tcl_CreateCommand (ip, "tux_load_texture",   load_texture_cb,   0,0);
00304     Tcl_CreateCommand (ip, "tux_bind_texture",   bind_texture_cb,   0,0);
00305 }