X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FTexture.cc;h=128d54f3d7c8750b2087859a22b81aa6c5f18dc6;hp=44a0b423719d6dfbb10c1be2ae98630a97c6e05c;hb=29e3d45f7bbbf31eadf793c41ff2b3d9c47b7539;hpb=c2321281bf12a7efaedde930422c7ddbc92080d4 diff --git a/src/Moof/Texture.cc b/src/Moof/Texture.cc index 44a0b42..128d54f 100644 --- a/src/Moof/Texture.cc +++ b/src/Moof/Texture.cc @@ -26,7 +26,7 @@ *******************************************************************************/ -#include +#include // memcpy #include @@ -62,20 +62,25 @@ class Texture::TextureImpl : public Mippleton { 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 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(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(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 @@ -330,9 +396,10 @@ Texture::Texture(const std::string& name) : * Bind the GL texture for mapping, etc. */ -void Texture::bind() +void Texture::bind() const { - glBindTexture(GL_TEXTURE_2D, getObject()); + // pass through + impl_->bind(); } @@ -340,20 +407,20 @@ void Texture::bind() * Get the texture object, for the curious. */ -GLuint Texture::getObject() +GLuint Texture::getObject() const { // pass through return impl_->object_; } -unsigned Texture::getWidth() +unsigned Texture::getWidth() const { // pass through return impl_->width_; } -unsigned Texture::getHeight() +unsigned Texture::getHeight() const { // pass through return impl_->height_; @@ -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"); }