]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/Texture.cc
fixed up video and texture handling
[chaz/yoink] / src / Moof / Texture.cc
index 44a0b423719d6dfbb10c1be2ae98630a97c6e05c..8bd3c4a3ae00a16657d670fe55620f48b0c99af0 100644 (file)
@@ -26,7 +26,7 @@
 
 *******************************************************************************/
 
-#include <cstdlib>
+#include <cstring>             // memcpy
 
 #include <boost/bind.hpp>
 
@@ -62,20 +62,25 @@ class Texture::TextureImpl : public Mippleton<TextureImpl>
        {
                if (object_)
                {
+                       if (object_ == globalObject_)
+                       {
+                               globalObject_ = 0;
+                       }
+
                        glDeleteTextures(1, &object_);
                        object_ = 0;
                }
        }
 
        /**
-        * If the GL context was recreated, we probably need to reload the texture.
-        * This may involve reading it from disk again, but hopefully the OS was
-        * smart enough to cache it if the client has plenty of RAM.
+        * If the GL context was recreated, we need to reload the texture.  This may
+        * involve reading it from disk again, but hopefully the OS was smart enough
+        * to cache it if the client has plenty of RAM.
         */
 
        void contextRecreated(const Notification& note)
        {
-               unloadFromGL();
+               object_ = globalObject_ = 0;
                uploadToGL();
        }
 
@@ -95,6 +100,29 @@ class Texture::TextureImpl : public Mippleton<TextureImpl>
                return value;
        }
 
+
+       static void flipSurface(SDL_Surface* image)
+       {
+               unsigned char*  pixels = (Uint8*)(image->pixels);
+
+               unsigned                pitch = image->pitch;
+               unsigned char   line[pitch];
+
+               int             yBegin = 0;
+               int             yEnd = image->h - 1;
+
+               if (SDL_MUSTLOCK(image)) SDL_LockSurface(image);
+               while (yBegin < yEnd)
+               {
+                       memcpy(line,                    pixels + pitch * yBegin, pitch);
+                       memcpy(pixels + pitch * yBegin, pixels + pitch * yEnd,   pitch);
+                       memcpy(pixels + pitch * yEnd,   line,                    pitch);
+                       yBegin++;
+                       yEnd--;
+               }
+               if (SDL_MUSTLOCK(image)) SDL_UnlockSurface(image);
+       }
+
 public:
 
        /**
@@ -103,16 +131,17 @@ public:
 
        explicit TextureImpl(const std::string& name) :
                Mippleton<TextureImpl>(name),
+               surface_(0),
                width_(0),
                height_(0),
                mode_(0),
                minFilter_(GL_NEAREST),
-               maxFilter_(GL_NEAREST),
-               wrapU_(GL_CLAMP),
-               wrapV_(GL_CLAMP),
+               magFilter_(GL_NEAREST),
+               wrapS_(GL_CLAMP),
+               wrapT_(GL_CLAMP),
                object_(0)
        {
-               uploadToGL();
+               loadFromFile();
 
                // we want to know when the GL context is recreated
                Dispatcher::instance().addHandler("video.context_recreated",
@@ -121,6 +150,11 @@ public:
 
        ~TextureImpl()
        {
+               if (surface_)
+               {
+                       SDL_FreeSurface(surface_);
+               }
+
                unloadFromGL();
 
                Dispatcher::instance().removeHandler(this);
@@ -139,10 +173,15 @@ public:
                int w = powerOfTwo(surface->w);
                int h = powerOfTwo(surface->h);
 
+               // 2. OpenGL textures make more sense within the coordinate system when
+               // they are "upside down," so let's flip it.
+
+               flipSurface(surface);
+
                // 1. OpenGL images must (generally) have dimensions of a power-of-two.
                // If this one doesn't, we can at least be more friendly by expanding
                // the dimensions so that they are, though there will be some empty
-               // space within the range of normal texture coordinates.  It's better of
+               // space within the range of normal texture coordinates.  It's better if
                // textures are the right size to begin with.
 
                SDL_Surface* image = SDL_CreateRGBSurface
@@ -151,14 +190,14 @@ public:
                        w, h,
                        32,
 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
-                       0x000000FF, 
-                       0x0000FF00, 
-                       0x00FF0000, 
+                       0x000000FF,
+                       0x0000FF00,
+                       0x00FF0000,
                        0xFF000000
 #else
                        0xFF000000,
-                       0x00FF0000, 
-                       0x0000FF00, 
+                       0x00FF0000,
+                       0x0000FF00,
                        0x000000FF
 #endif
                );
@@ -187,27 +226,6 @@ public:
                        SDL_SetAlpha(surface, savedFlags, savedAlpha);
                }
 
-               // 2. OpenGL textures make more sense within the coordinate system when
-               // they are "upside down," so let's flip it.
-
-               Uint8 line[image->pitch];
-
-               Uint8 *pixels = static_cast<Uint8*>(image->pixels);
-               Uint16 pitch = image->pitch;
-               int ybegin = 0;
-               int yend = image->h - 1;
-
-               if (SDL_MUSTLOCK(image)) SDL_LockSurface(image);
-               while (ybegin < yend)
-               {
-                       memcpy(line, pixels + pitch * ybegin, pitch);
-                       memcpy(pixels + pitch * ybegin, pixels + pitch * yend, pitch);
-                       memcpy(pixels + pitch * yend, line, pitch);
-                       ybegin++;
-                       yend--;
-               }
-               if (SDL_MUSTLOCK(image)) SDL_UnlockSurface(image);
-
                return image;
        }
 
@@ -217,7 +235,7 @@ public:
         * @return Image data.
         */
 
-       SDL_Surface* loadImageData()
+       void loadFromFile()
        {
                SDL_Surface* surface;
 
@@ -225,7 +243,7 @@ public:
 
                if (!surface)
                {
-                       throw Texture::Exception("loading failed");
+                       throw Texture::Exception("loading from file failed");
                }
 
                SDL_Surface* temp = prepareImageForGL(surface);
@@ -233,7 +251,7 @@ public:
 
                if (!temp)
                {
-                       throw Texture::Exception("image couldn't be prepared for GL");
+                       throw Texture::Exception("uploading to opengl failed");
                }
 
                if (temp->format->BytesPerPixel == 3)
@@ -247,13 +265,13 @@ public:
                else
                {
                        SDL_FreeSurface(temp);
-                       throw Texture::Exception("image is not the required 24 or 32 bpp");
+                       throw Texture::Exception("incompatible color mode");
                }
 
                width_ = temp->w;
                height_ = temp->h;
 
-               return temp;
+               surface_ = temp;
        }
 
 
@@ -266,11 +284,11 @@ public:
        {
                if (object_)
                {
-                       // Already loaded.
+                       // already loaded
                        return;
                }
 
-               SDL_Surface* imageData = loadImageData();
+               if (!surface_) loadFromFile();
 
                glGenTextures(1, &object_);
                glBindTexture(GL_TEXTURE_2D, object_);
@@ -280,17 +298,18 @@ public:
                        GL_TEXTURE_2D,
                        0,
                        mode_,
-                       imageData->w,
-                       imageData->h,
+                       surface_->w,
+                       surface_->h,
                        0,
                        mode_,
                        GL_UNSIGNED_BYTE,
-                       imageData->pixels
+                       surface_->pixels
                );
 
                setProperties();
 
-               SDL_FreeSurface(imageData);
+               SDL_FreeSurface(surface_);
+               surface_ = 0;
        }
 
 
@@ -302,23 +321,70 @@ public:
        void setProperties()
        {
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter_);
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, maxFilter_);
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapU_);
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapV_);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter_);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS_);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT_);
        }
 
+       inline void setMinFilter(GLuint filter)
+       {
+               bind();
+               minFilter_ = filter;
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter_);
+       }
+
+       inline void setMagFilter(GLuint filter)
+       {
+               bind();
+               magFilter_ = filter;
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter_);
+       }
+
+       inline void setWrapS(GLuint wrap)
+       {
+               bind();
+               wrapS_ = wrap;
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS_);
+       }
 
-       unsigned        width_;                 ///< Horizontal dimension of the image.
-       unsigned        height_;                ///< Vertical dimension.
+       inline void setWrapT(GLuint wrap)
+       {
+               bind();
+               wrapT_ = wrap;
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT_);
+       }
 
-       GLuint          mode_;                  ///< Depth of the image, GL_RGB or GL_RGBA.
-       GLuint          minFilter_;             ///< Filter.
-       GLuint          maxFilter_;             ///< Filter.
-       GLuint          wrapU_;                 ///< Wrapping behavior horizontally.
-       GLuint          wrapV_;                 ///< Wrapping behavior vertically.
-       GLuint          object_;                ///< GL texture handle.
+
+       inline void bind()
+       {
+               if (object_ == 0)
+               {
+                       uploadToGL();
+               }
+               if (object_ != globalObject_)
+               {
+                       glBindTexture(GL_TEXTURE_2D, object_);
+                       globalObject_ = object_;
+               }
+       }
+
+
+       SDL_Surface*    surface_;
+       unsigned                width_;                 ///< Horizontal dimension of the image.
+       unsigned                height_;                ///< Vertical dimension.
+
+       GLuint                  mode_;                  ///< Depth of the image, GL_RGB or GL_RGBA.
+       GLuint                  minFilter_;             ///< Minifcation filter.
+       GLuint                  magFilter_;             ///< Magnification filter.
+       GLuint                  wrapS_;                 ///< Wrapping behavior horizontally.
+       GLuint                  wrapT_;                 ///< Wrapping behavior vertically.
+
+       GLuint                  object_;                ///< GL texture handle.
+       static GLuint   globalObject_;  ///< Global GL texture handle.
 };
 
+GLuint Texture::TextureImpl::globalObject_ = 0;
+
 
 Texture::Texture(const std::string& name) :
        // pass through
@@ -332,7 +398,8 @@ Texture::Texture(const std::string& name) :
 
 void Texture::bind()
 {
-       glBindTexture(GL_TEXTURE_2D, getObject());
+       // pass through
+       impl_->bind();
 }
 
 
@@ -362,36 +429,32 @@ unsigned Texture::getHeight()
 
 void Texture::setMinFilter(GLuint filter)
 {
-       impl_->minFilter_ = filter;
-}
-
-void Texture::setMaxFilter(GLuint filter)
-{
-       impl_->maxFilter_ = filter;
+       // pass through
+       impl_->setMinFilter(filter);
 }
 
-void Texture::setWrapU(GLuint wrap)
+void Texture::setMagFilter(GLuint filter)
 {
-       impl_->wrapU_ = wrap;
+       // pass through
+       impl_->setMagFilter(filter);
 }
 
-void Texture::setWrapV(GLuint wrap)
+void Texture::setWrapS(GLuint wrap)
 {
-       impl_->wrapV_ = wrap;
+       // pass through
+       impl_->setWrapS(wrap);
 }
 
-
-void Texture::applyChanges()
+void Texture::setWrapT(GLuint wrap)
 {
-       bind();
-       impl_->setProperties();
+       // pass through
+       impl_->setWrapT(wrap);
 }
 
 
 std::string Texture::getPathToResource(const std::string& name)
 {
-       // TODO since this is a generic library class, more than PNG should be
-       // supported
+       // TODO named resources must be png for now
        return Resource::getPathToResource("textures/" + name + ".png");
 }
 
This page took 0.029334 seconds and 4 git commands to generate.