Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GlTextures.cpp

00001 // Sh: A GPU metaprogramming language.
00002 //
00003 // Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory
00004 // Project administrator: Michael D. McCool
00005 // Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa,
00006 //          Michael D. McCool
00007 // 
00008 // This software is provided 'as-is', without any express or implied
00009 // warranty. In no event will the authors be held liable for any damages
00010 // arising from the use of this software.
00011 // 
00012 // Permission is granted to anyone to use this software for any purpose,
00013 // including commercial applications, and to alter it and redistribute it
00014 // freely, subject to the following restrictions:
00015 // 
00016 // 1. The origin of this software must not be misrepresented; you must
00017 // not claim that you wrote the original software. If you use this
00018 // software in a product, an acknowledgment in the product documentation
00019 // would be appreciated but is not required.
00020 // 
00021 // 2. Altered source versions must be plainly marked as such, and must
00022 // not be misrepresented as being the original software.
00023 // 
00024 // 3. This notice may not be removed or altered from any source
00025 // distribution.
00027 #include "ShContext.hpp"
00028 #include "GlTextures.hpp"
00029 #include <sstream>
00030 #include "GlTextureName.hpp"
00031 #include "GlTextureStorage.hpp"
00032 
00033 namespace shgl {
00034 
00035 using namespace SH;
00036 
00037 const unsigned int shGlTargets[] = {
00038   GL_TEXTURE_1D,
00039   GL_TEXTURE_2D,
00040   GL_TEXTURE_RECTANGLE_NV,
00041   GL_TEXTURE_3D,
00042   GL_TEXTURE_CUBE_MAP,
00043 };
00044 
00045 const unsigned int shGlCubeMapTargets[] = {
00046   GL_TEXTURE_CUBE_MAP_POSITIVE_X,
00047   GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
00048   GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
00049   GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
00050   GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
00051   GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
00052 };
00053 
00054 ShCubeDirection glToShCubeDir(GLuint target)
00055 {
00056   switch (target) {
00057   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
00058     return SH_CUBE_POS_X;
00059   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
00060     return SH_CUBE_NEG_X;
00061   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
00062     return SH_CUBE_POS_Y;
00063   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
00064     return SH_CUBE_NEG_Y;
00065   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
00066     return SH_CUBE_POS_Z;
00067   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
00068     return SH_CUBE_NEG_Z;
00069   }
00070   return SH_CUBE_POS_X;
00071 }
00072 
00073 GLenum shGlInternalFormat(const ShTextureNodePtr& node)
00074 {
00075   GLenum byteformats[4] = {GL_LUMINANCE8, GL_LUMINANCE8_ALPHA8, GL_RGB8, GL_RGBA8}; 
00076   GLenum shortformats[4] = {GL_LUMINANCE16, GL_LUMINANCE16_ALPHA16, GL_RGB16, GL_RGBA16}; 
00077 
00078   GLenum halfformats_nv[4] = {GL_FLOAT_R16_NV, GL_FLOAT_RGBA16_NV, GL_FLOAT_RGB16_NV, GL_FLOAT_RGBA16_NV};
00079   GLenum fpformats_nv[4] = {GL_FLOAT_R32_NV, GL_FLOAT_RGBA32_NV, GL_FLOAT_RGB32_NV, GL_FLOAT_RGBA32_NV};
00080 
00081   GLenum halfformats_ati[4] = {GL_LUMINANCE_FLOAT16_ATI,
00082                              GL_LUMINANCE_ALPHA_FLOAT16_ATI,
00083                              GL_RGB_FLOAT16_ATI,
00084                              GL_RGBA_FLOAT16_ATI};
00085 
00086   GLenum fpformats_ati[4] = {GL_LUMINANCE_FLOAT32_ATI,
00087                              GL_LUMINANCE_ALPHA_FLOAT32_ATI,
00088                              GL_RGB_FLOAT32_ATI,
00089                              GL_RGBA_FLOAT32_ATI};
00090   GLenum* formats = 0;
00091   bool clamped = (node->traits().clamping() == SH::ShTextureTraits::SH_CLAMPED);
00092   // @todo type - assume that !clamped means unclamped for now...
00093   // may have other clamping modes later on?
00094   
00095   std::string exts(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
00096   bool float_nv = (exts.find("NV_float_buffer") != std::string::npos);
00097   bool float_ati = (exts.find("ATI_texture_float") != std::string::npos);
00098 
00099   // @todo type respect CLAMPED flag 
00100   if (node->size() < 0 || node->size() > 4) return 0;
00101 
00102 
00103 
00104   // @todo type
00105   // handle fractional types
00106   // right now all available formats - double, float, signed ints, unsigned ints should
00107   // be stored internally as float if possible
00108 
00109   if(clamped) {
00110     switch(node->valueType()) {
00111       case SH_DOUBLE:
00112       case SH_FLOAT:        
00113       case SH_HALF:
00114       case SH_FINT:
00115       case SH_FSHORT:
00116       case SH_FUINT:
00117       case SH_FUSHORT:
00118         formats = shortformats;
00119         break;
00120 
00121      case SH_FBYTE:
00122      case SH_FUBYTE:
00123         formats = byteformats;
00124         break;
00125 
00126       case SH_INT: 
00127       case SH_UINT:
00128       case SH_SHORT: 
00129       case SH_USHORT:
00130       case SH_BYTE:
00131       case SH_UBYTE:
00132         SH_DEBUG_WARN("Using integer data type for a [0,1] clamped texture format is not advised.");
00133         formats = byteformats;
00134         break;
00135 
00136      default:
00137         SH_DEBUG_ERROR("Could not find appropriate clamped texture format \n"
00138                        "Using default instead!");
00139         return node->size();
00140         break;
00141     }
00142   } else {
00143     switch(node->valueType()) {
00144       case SH_DOUBLE:
00145       case SH_FLOAT:        
00146       case SH_INT: 
00147       case SH_UINT:
00148         if (float_nv) formats = fpformats_nv;
00149         else if (float_ati) formats = fpformats_ati;
00150         break;
00151 
00152       case SH_HALF:
00153       case SH_SHORT: 
00154       case SH_BYTE:
00155       case SH_USHORT:
00156       case SH_UBYTE:
00157         if (float_nv) formats = halfformats_nv;
00158         else if (float_ati) formats = halfformats_ati;
00159         break;
00160 
00161       case SH_FINT:
00162       case SH_FSHORT:
00163       case SH_FUINT:
00164       case SH_FUSHORT:
00165         formats = shortformats;
00166         break;
00167 
00168      case SH_FBYTE:
00169      case SH_FUBYTE:
00170         formats = byteformats;
00171         break;
00172      default:
00173         SH_DEBUG_ERROR("Could not find appropriate unclamped texture format \n"
00174                        "Using default instead!");
00175         return node->size();
00176         break;
00177     }
00178   }
00179   
00180   return formats[node->size() - 1];
00181 }
00182 
00183 GLenum shGlFormat(const ShTextureNodePtr& node)
00184 {
00185   switch (node->size()) {
00186   case 1:
00187     return GL_LUMINANCE;
00188   case 2:
00189     return GL_LUMINANCE_ALPHA;
00190   case 3:
00191     return GL_RGB;
00192   case 4:
00193     return GL_RGBA;
00194   default:
00195     break;
00196   }
00197   // TODO: Warn or something
00198   return 0;
00199 }
00200 
00201 /* Returns glReadPixels/glTexImage type for a given value type 
00202  * and returns a value type for the temporary buffer
00203  * (or SH_VALUETYPE_END if we can read pixels directly into
00204  * the original buffer)*/
00205 GLenum shGlType(ShValueType valueType, ShValueType &convertedType) {
00206   convertedType = SH_VALUETYPE_END;
00207   GLenum result = GL_NONE;
00208   switch(valueType) {
00209     case SH_I_DOUBLE:
00210     case SH_I_FLOAT:
00211       SH_DEBUG_ERROR("Interval types not supported in memory");
00212       result = GL_FLOAT;
00213       break;
00214 
00215     case SH_DOUBLE:
00216     case SH_HALF:
00217     case SH_INT: 
00218     case SH_SHORT: 
00219     case SH_BYTE:
00220     case SH_UINT:
00221     case SH_USHORT:
00222     case SH_UBYTE:
00223       convertedType = SH_FLOAT;
00224     case SH_FLOAT:        result = GL_FLOAT; break;
00225 
00226 
00227     case SH_FINT:     result = GL_INT; break;
00228     case SH_FSHORT:   result = GL_SHORT; break;
00229     case SH_FBYTE:    result = GL_BYTE; break;
00230     case SH_FUINT:    result = GL_UNSIGNED_INT; break;
00231     case SH_FUSHORT:  result = GL_UNSIGNED_SHORT; break;
00232     case SH_FUBYTE:   result = GL_UNSIGNED_BYTE; break;
00233 
00234     default:
00235       SH_DEBUG_ERROR("Unsupported value type to glReadPixel type conversion"); 
00236       break;
00237   }
00238 
00239   std::string exts(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
00240   if(valueType == SH_HALF) { 
00241         if((exts.find("NV_half_float") != std::string::npos)) {
00242           convertedType = SH_VALUETYPE_END; 
00243           result = GL_HALF_FLOAT_NV; 
00244         } else if(exts.find("APPLE_float_pixels") != std::string::npos) {
00245           convertedType = SH_VALUETYPE_END; 
00246           //result = HALF_APPLE; 
00247         }
00248   }
00249   SH_DEBUG_ASSERT(result != GL_NONE);
00250   return result;
00251 }
00252 
00253 struct StorageFinder {
00254   StorageFinder(const ShTextureNodePtr& node, bool ignoreTarget = false)
00255     : node(node), ignoreTarget(ignoreTarget)
00256   {
00257   }
00258   
00259   bool operator()(const ShStoragePtr& storage) const
00260   {
00261     GlTextureStoragePtr t = shref_dynamic_cast<GlTextureStorage>(storage);
00262     if (!t) {
00263       return false;
00264     }
00265     if (!ignoreTarget) {
00266       if (t->texName()->params() != node->traits()) return false;
00267       if (t->target() != shGlTargets[node->dims()]) return false;
00268     }
00269     if (t->width() != node->width()) return false;
00270     if (t->height() != node->height()) return false;
00271     if (t->depth() != node->depth()) return false;
00272     return true;
00273   }
00274   
00275   const ShTextureNodePtr& node;
00276   bool ignoreTarget;
00277 };
00278 
00279 GlTextures::GlTextures(void)
00280 {
00281 }
00282 
00283 TextureStrategy* GlTextures::create(void)
00284 {
00285   return new GlTextures;
00286 }
00287 
00288 
00289 void GlTextures::bindTexture(const ShTextureNodePtr& node,
00290                              GLenum target)
00291 {
00292   if (!node) return;
00293 
00294   // TODO: Check for memories that are 0
00295   
00296   if (!node->meta("opengl:preset").empty()) {
00297     SH_GL_CHECK_ERROR(glActiveTextureARB(target));
00298     GLuint name;
00299     std::istringstream is(node->meta("opengl:preset"));
00300     is >> name; // TODO: Check for errors
00301     SH_GL_CHECK_ERROR(glBindTexture(shGlTargets[node->dims()], name));
00302     node->meta("opengl:texid", node->meta("opengl:preset"));
00303     return;
00304   } 
00305   
00306   if (node->dims() == SH_TEXTURE_CUBE) {
00307     
00308     // Look for a cubemap that happens to have just the right storages
00309     
00310     GlTextureName::NameList::const_iterator I;
00311     for (I = GlTextureName::beginNames(); I != GlTextureName::endNames(); ++I) {
00312       const GlTextureName* name = *I;
00313       if (name->target() != GL_TEXTURE_CUBE_MAP) continue;
00314       if (name->params() != node->traits()) continue;
00315       
00316       GlTextureName::StorageList::const_iterator S;
00317       for (S = name->beginStorages(); S != name->endStorages(); ++S) {
00318         GlTextureStorage* s = dynamic_cast<GlTextureStorage*>(*S);
00319         if (!s) continue;
00320         ShCubeDirection dir = glToShCubeDir(s->target());
00321         if (s->memory() != node->memory(dir).object() || !StorageFinder(node, true)(s))
00322           break;
00323       }
00324       // If we got through the whole list, we've found a matching list.
00325       if (S == name->endStorages()) break;
00326     }
00327     
00328     if (I == GlTextureName::endNames()) {
00329       // Need to allocate new storages
00330       GlTextureNamePtr texname = new GlTextureName(GL_TEXTURE_CUBE_MAP);
00331       texname->params(node->traits());
00332       for (int i = 0; i < 6; i++) {
00333         ShCubeDirection dir = static_cast<ShCubeDirection>(i);
00334         GlTextureStoragePtr storage = new GlTextureStorage(node->memory(dir).object(),
00335                                                            shGlCubeMapTargets[i],
00336                                                            shGlFormat(node),
00337                                                            shGlInternalFormat(node),
00338                                                            node->valueType(),
00339                                                            node->width(), node->height(),
00340                                                            node->depth(), node->size(),
00341                                                            node->count(), texname);
00342         storage->sync();
00343       }
00344       SH_GL_CHECK_ERROR(glActiveTextureARB(target));
00345       SH_GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_CUBE_MAP, texname->value()));
00346       std::ostringstream os;
00347       os << texname->value();
00348       node->meta("opengl:texid", os.str());
00349     } else {
00350       // Just synchronize the storages
00351       GlTextureName::StorageList::const_iterator S;
00352       for (S = (*I)->beginStorages(); S != (*I)->endStorages(); ++S) {
00353         GlTextureStorage* s = dynamic_cast<GlTextureStorage*>(*S);
00354         if (!s) continue;
00355         s->sync();
00356       }
00357       SH_GL_CHECK_ERROR(glActiveTextureARB(target));
00358       SH_GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_CUBE_MAP, (*I)->value()));
00359       std::ostringstream os;
00360       os << (*I)->value();
00361       node->meta("opengl:texid", os.str());
00362     }
00363   } else {
00364 
00365     StorageFinder finder(node);
00366     GlTextureStoragePtr storage =
00367       shref_dynamic_cast<GlTextureStorage>(node->memory()->findStorage("opengl:texture", finder));
00368     if (!storage) {
00369       GlTextureNamePtr name = new GlTextureName(shGlTargets[node->dims()]);
00370       storage = new GlTextureStorage(node->memory().object(),
00371                                      shGlTargets[node->dims()],
00372                                      shGlFormat(node),
00373                                      shGlInternalFormat(node),
00374                                      node->valueType(),
00375                                      node->width(), node->height(), 
00376                                      node->depth(), node->size(),
00377                                      node->count(), name);
00378       name->params(node->traits());
00379     }
00380 
00381     SH_GL_CHECK_ERROR(glActiveTextureARB(target));
00382     storage->sync();
00383     SH_GL_CHECK_ERROR(glBindTexture(shGlTargets[node->dims()], storage->name()));
00384 
00385     std::ostringstream os;
00386     os << storage->name();
00387     node->meta("opengl:texid", os.str());
00388   }
00389 }
00390 
00391 
00392 }

Generated on Mon Jan 24 18:36:29 2005 for Sh by  doxygen 1.4.1