]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/Texture.cc
dispatch class not a singleton, engine is static
[chaz/yoink] / src / Moof / Texture.cc
index 44a0b423719d6dfbb10c1be2ae98630a97c6e05c..6769d8887644a1924d2fdc67974b1afa4df4083d 100644 (file)
 
 *******************************************************************************/
 
-#include <cstdlib>
+#include <cstdio>              // FILE
+#include <cstring>             // strncmp
 
 #include <boost/bind.hpp>
 
-#include <SDL/SDL.h>
-#include <SDL/SDL_image.h>
-
-#include "Dispatcher.hh"
-#include "Mippleton.hh"
+#include "Dispatch.hh"
+#include "Engine.hh"
+#include "Error.hh"
+#include "Image.hh"
+#include "Library.hh"
+#include "Log.hh"
 #include "OpenGL.hh"
 #include "Texture.hh"
 
@@ -47,11 +49,11 @@ namespace Mf {
  * which is worth having in memory.  The image data itself is not worth keeping
  * in memory if the texture has been loaded to GL, but the name of the resource
  * is retained so that it can be reloaded if necessary.  The implementation is a
- * mippleton so that multiple texture objects can share the same internal
- * objects and avoid having duplicate textures loaded to GL.
+ * library so that multiple texture objects can share the same internal objects
+ * and avoid having duplicate textures loaded to GL.
  */
 
-class Texture::TextureImpl : public Mippleton<TextureImpl>
+class Texture::Impl : public Library<Impl>
 {
 
        /**
@@ -60,22 +62,27 @@ class Texture::TextureImpl : public Mippleton<TextureImpl>
 
        void unloadFromGL()
        {
-               if (object_)
+               if (mObject)
                {
-                       glDeleteTextures(1, &object_);
-                       object_ = 0;
+                       if (mObject == gObject)
+                       {
+                               gObject = 0;
+                       }
+
+                       glDeleteTextures(1, &mObject);
+                       mObject = 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)
+       void contextRecreated()
        {
-               unloadFromGL();
+               mObject = gObject = 0;
                uploadToGL();
        }
 
@@ -101,29 +108,33 @@ public:
         * Construction is initialization.
         */
 
-       explicit TextureImpl(const std::string& name) :
-               Mippleton<TextureImpl>(name),
-               width_(0),
-               height_(0),
-               mode_(0),
-               minFilter_(GL_NEAREST),
-               maxFilter_(GL_NEAREST),
-               wrapU_(GL_CLAMP),
-               wrapV_(GL_CLAMP),
-               object_(0)
+       explicit Impl(const std::string& name) :
+               Library<Impl>(name),
+               //mContext(0),
+               mImage(Texture::getPath(getName())),
+               mWidth(0),
+               mHeight(0),
+               mMode(0),
+               mMinFilter(GL_NEAREST),
+               mMagFilter(GL_NEAREST),
+               mWrapS(GL_CLAMP),
+               mWrapT(GL_CLAMP),
+               mObject(0)
        {
-               uploadToGL();
+               // make sure we have a video
+               VideoP video = engine.getVideo();
+               ASSERT(video && "cannot load textures without a current video context");
 
                // we want to know when the GL context is recreated
-               Dispatcher::instance().addHandler("video.context_recreated",
-                               boost::bind(&TextureImpl::contextRecreated, this, _1), this);
+               mDispatchHandler = engine.addHandler("video.newcontext",
+                               boost::bind(&Impl::contextRecreated, this));
+
+               loadFromFile();
        }
 
-       ~TextureImpl()
+       ~Impl()
        {
                unloadFromGL();
-
-               Dispatcher::instance().removeHandler(this);
        }
 
 
@@ -134,15 +145,21 @@ public:
         * method makes them ready.
         */
 
+       /*
        static SDL_Surface* prepareImageForGL(SDL_Surface* surface)
        {
                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 +168,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,29 +204,9 @@ 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;
        }
+       */
 
        /**
         * Use SDL_image to load images from file.  A surface with the image data is
@@ -217,43 +214,19 @@ public:
         * @return Image data.
         */
 
-       SDL_Surface* loadImageData()
+       void loadFromFile()
        {
-               SDL_Surface* surface;
-
-               surface = IMG_Load(Texture::getPathToResource(getName()).c_str());
-
-               if (!surface)
+               if (!mImage.isValid())
                {
-                       throw Texture::Exception("loading failed");
+                       logWarning << "texture not found: " << getName() << std::endl;
+                       throw Error(Error::RESOURCE_NOT_FOUND, getName());
                }
 
-               SDL_Surface* temp = prepareImageForGL(surface);
-               SDL_FreeSurface(surface);
+               mImage.flip();
 
-               if (!temp)
-               {
-                       throw Texture::Exception("image couldn't be prepared for GL");
-               }
-
-               if (temp->format->BytesPerPixel == 3)
-               {
-                       mode_ = GL_RGB;
-               }
-               else if (temp->format->BytesPerPixel == 4)
-               {
-                       mode_ = GL_RGBA;
-               }
-               else
-               {
-                       SDL_FreeSurface(temp);
-                       throw Texture::Exception("image is not the required 24 or 32 bpp");
-               }
-
-               width_ = temp->w;
-               height_ = temp->h;
-
-               return temp;
+               mWidth = mImage.getWidth();
+               mHeight = mImage.getHeight();
+               mMode = mImage.getColorMode();
        }
 
 
@@ -264,33 +237,36 @@ public:
 
        void uploadToGL()
        {
-               if (object_)
+               if (mObject)
                {
-                       // Already loaded.
+                       // already loaded
                        return;
                }
 
-               SDL_Surface* imageData = loadImageData();
+               //if (!mContext) loadFromFile();
 
-               glGenTextures(1, &object_);
-               glBindTexture(GL_TEXTURE_2D, object_);
+               glGenTextures(1, &mObject);
+               glBindTexture(GL_TEXTURE_2D, mObject);
 
                glTexImage2D
+               //gluBuild2DMipmaps
                (
                        GL_TEXTURE_2D,
                        0,
-                       mode_,
-                       imageData->w,
-                       imageData->h,
+                       mMode,
+                       //3,
+                       mWidth,
+                       mHeight,
                        0,
-                       mode_,
+                       mMode,
                        GL_UNSIGNED_BYTE,
-                       imageData->pixels
+                       mImage.getPixels()
                );
 
                setProperties();
 
-               SDL_FreeSurface(imageData);
+               //SDL_FreeSurface(mContext);
+               //mContext = 0;
        }
 
 
@@ -301,38 +277,87 @@ 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_MIN_FILTER, mMinFilter);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mMagFilter);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mWrapS);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mWrapT);
        }
 
+       inline void setMinFilter(GLuint filter)
+       {
+               bind();
+               mMinFilter = filter;
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mMinFilter);
+       }
 
-       unsigned        width_;                 ///< Horizontal dimension of the image.
-       unsigned        height_;                ///< Vertical dimension.
+       inline void setMagFilter(GLuint filter)
+       {
+               bind();
+               mMagFilter = filter;
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mMagFilter);
+       }
+
+       inline void setWrapS(GLuint wrap)
+       {
+               bind();
+               mWrapS = wrap;
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mWrapS);
+       }
+
+       inline void setWrapT(GLuint wrap)
+       {
+               bind();
+               mWrapT = wrap;
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mWrapT);
+       }
+
+
+       inline void bind()
+       {
+               if (mObject == 0)
+               {
+                       uploadToGL();
+               }
+               if (mObject != gObject)
+               {
+                       glBindTexture(GL_TEXTURE_2D, mObject);
+                       gObject = mObject;
+               }
+       }
+
+
+       Image                           mImage;
+       unsigned                        mWidth;                 ///< Horizontal dimension of the image.
+       unsigned                        mHeight;                ///< Vertical dimension.
 
-       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.
+       GLuint                          mMode;                  ///< GL_RGB or GL_RGBA.
+       GLuint                          mMinFilter;             ///< Minifcation filter.
+       GLuint                          mMagFilter;             ///< Magnification filter.
+       GLuint                          mWrapS;                 ///< Wrapping behavior horizontally.
+       GLuint                          mWrapT;                 ///< Wrapping behavior vertically.
+
+       GLuint                          mObject;                ///< GL texture handle.
+       static GLuint           gObject;                ///< Global GL texture handle.
+
+       Dispatch::Handler       mDispatchHandler;
 };
 
+GLuint Texture::Impl::gObject = 0;
+
 
 Texture::Texture(const std::string& name) :
        // pass through
-       impl_(Texture::TextureImpl::retain(name), &Texture::TextureImpl::release)
-{}
+       mImpl(Texture::Impl::getInstance(name)) {}
 
 
 /**
  * Bind the GL texture for mapping, etc.
  */
 
-void Texture::bind()
+void Texture::bind() const
 {
-       glBindTexture(GL_TEXTURE_2D, getObject());
+       // pass through
+       mImpl->bind();
 }
 
 
@@ -340,59 +365,62 @@ void Texture::bind()
  * Get the texture object, for the curious.
  */
 
-GLuint Texture::getObject()
+GLuint Texture::getObject() const
 {
        // pass through
-       return impl_->object_;
+       return mImpl->mObject;
 }
 
 
-unsigned Texture::getWidth()
+void Texture::resetBind()
 {
-       // pass through
-       return impl_->width_;
+       glBindTexture(GL_TEXTURE_2D, 0);
+       Impl::gObject = 0;
 }
 
-unsigned Texture::getHeight()
+
+unsigned Texture::getWidth() const
 {
        // pass through
-       return impl_->height_;
+       return mImpl->mWidth;
 }
 
-
-void Texture::setMinFilter(GLuint filter)
+unsigned Texture::getHeight() const
 {
-       impl_->minFilter_ = filter;
+       // pass through
+       return mImpl->mHeight;
 }
 
-void Texture::setMaxFilter(GLuint filter)
+
+void Texture::setMinFilter(GLuint filter)
 {
-       impl_->maxFilter_ = filter;
+       // pass through
+       mImpl->setMinFilter(filter);
 }
 
-void Texture::setWrapU(GLuint wrap)
+void Texture::setMagFilter(GLuint filter)
 {
-       impl_->wrapU_ = wrap;
+       // pass through
+       mImpl->setMagFilter(filter);
 }
 
-void Texture::setWrapV(GLuint wrap)
+void Texture::setWrapS(GLuint wrap)
 {
-       impl_->wrapV_ = wrap;
+       // pass through
+       mImpl->setWrapS(wrap);
 }
 
-
-void Texture::applyChanges()
+void Texture::setWrapT(GLuint wrap)
 {
-       bind();
-       impl_->setProperties();
+       // pass through
+       mImpl->setWrapT(wrap);
 }
 
 
-std::string Texture::getPathToResource(const std::string& name)
+std::string Texture::getPath(const std::string& name)
 {
-       // TODO since this is a generic library class, more than PNG should be
-       // supported
-       return Resource::getPathToResource("textures/" + name + ".png");
+       std::string path = Resource::getPath("textures/" + name + ".png");
+       return path;
 }
 
 
This page took 0.031855 seconds and 4 git commands to generate.