X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FTexture.cc;h=801acbae227f89d7a58970a1e97ed836a008391a;hp=78dc0c8148b478c092f0375ac46c3ecff2d7f707;hb=e973a129b5b83b628ba3f09e8c95682fc74080cd;hpb=bffc879fc8ee8167bb123310d39fad4e2f426ffd diff --git a/src/Moof/Texture.cc b/src/Moof/Texture.cc index 78dc0c8..801acba 100644 --- a/src/Moof/Texture.cc +++ b/src/Moof/Texture.cc @@ -26,18 +26,20 @@ *******************************************************************************/ -#include // memcpy +#include // FILE +#include // strncmp +#include #include -#include -#include - -#include "Dispatcher.hh" -#include "Library.hh" +#include "Dispatch.hh" +#include "Error.hh" +#include "Manager.hh" #include "Log.hh" #include "OpenGL.hh" +#include "Script.hh" #include "Texture.hh" +#include "Video.hh" namespace Mf { @@ -48,11 +50,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. + * manager so that multiple texture objects can share the same internal objects + * and avoid having duplicate textures loaded to GL. */ -class Texture::Impl : public Library +class Texture::Impl : public Manager { /** @@ -63,9 +65,9 @@ class Texture::Impl : public Library { if (mObject) { - if (mObject == globalObject_) + if (mObject == gObject) { - globalObject_ = 0; + gObject = 0; } glDeleteTextures(1, &mObject); @@ -79,9 +81,9 @@ class Texture::Impl : public Library * to cache it if the client has plenty of RAM. */ - void contextRecreated(const Notification* note) + void contextRecreated() { - mObject = globalObject_ = 0; + mObject = gObject = 0; uploadToGL(); } @@ -102,26 +104,16 @@ class Texture::Impl : public Library } - static void flipSurface(SDL_Surface* image) + static void bindScriptConstants(Mf::Script& script) { - 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); + script.push(GL_CLAMP); script.set("CLAMP"); + script.push(GL_REPEAT); script.set("REPEAT"); + script.push(GL_LINEAR); script.set("LINEAR"); + script.push(GL_NEAREST); script.set("NEAREST"); + script.push(GL_LINEAR_MIPMAP_LINEAR); script.set("LINEAR_MIPMAP_LINEAR"); + script.push(GL_LINEAR_MIPMAP_NEAREST); script.set("LINEAR_MIPMAP_NEAREST"); + script.push(GL_NEAREST_MIPMAP_LINEAR); script.set("NEAREST_MIPMAP_LINEAR"); + script.push(GL_NEAREST_MIPMAP_NEAREST); script.set("NEAREST_MIPMAP_NEAREST"); } public: @@ -130,35 +122,26 @@ public: * Construction is initialization. */ - explicit Impl(const std::string& name) : - Library(name), - mContext(0), - mWidth(0), - mHeight(0), - mMode(0), + Impl() : mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST), mWrapS(GL_CLAMP), mWrapT(GL_CLAMP), + mTilesS(1), + mTilesT(1), mObject(0) { - loadFromFile(); + // make sure we have a video context + ASSERT(video && "cannot load textures without a current video context"); // we want to know when the GL context is recreated - Dispatcher::getInstance().addHandler("video.context_recreated", - boost::bind(&Impl::contextRecreated, this, _1), this); + mDispatchHandler = core.addHandler("video.newcontext", + boost::bind(&Impl::contextRecreated, this)); } ~Impl() { - if (mContext) - { - SDL_FreeSurface(mContext); - } - unloadFromGL(); - - Dispatcher::getInstance().removeHandler(this); } @@ -169,6 +152,7 @@ public: * method makes them ready. */ + /* static SDL_Surface* prepareImageForGL(SDL_Surface* surface) { int w = powerOfTwo(surface->w); @@ -229,6 +213,7 @@ public: return image; } + */ /** * Use SDL_image to load images from file. A surface with the image data is @@ -236,44 +221,55 @@ public: * @return Image data. */ - void loadFromFile() + void init(const std::string& name) { - SDL_Surface* surface; + std::string path = Texture::getPath(name); - surface = IMG_Load(Texture::getPath(getName()).c_str()); - - if (!surface) + mImage = Image::alloc(path); + if (!mImage->isValid()) { - logWarning("texture not found: %s", getName().c_str()); - throw Exception(Exception::FILE_NOT_FOUND); + logWarning << "texture not found: " << path << std::endl; + Error(Error::RESOURCE_NOT_FOUND, path).raise(); } - SDL_Surface* temp = prepareImageForGL(surface); - SDL_FreeSurface(surface); + mImage->flip(); - if (!temp) - { - throw Exception(Exception::OPENGL_ERROR); - } + Mf::Script script; - if (temp->format->BytesPerPixel == 3) - { - mMode = GL_RGB; - } - else if (temp->format->BytesPerPixel == 4) + importLogFunctions(script); + bindScriptConstants(script); + + if (script.doString(mImage->getComment()) != Mf::Script::SUCCESS) { - mMode = GL_RGBA; + std::string str; + script[-1].get(str); + Mf::logWarning(str); } else { - SDL_FreeSurface(temp); - throw Exception(Exception::BAD_IMAGE_FORMAT); - } + Mf::logInfo << "loading tiles from texture " << path << std::endl; + + Mf::Script::Slot globals = script.getGlobalTable(); + Mf::Script::Slot top = script[-1]; + + globals.pushField("tiles_s"); + top.get(mTilesS); + + globals.pushField("tiles_t"); + top.get(mTilesT); + + globals.pushField("min_filter"); + top.get(mMinFilter); + + globals.pushField("mag_filter"); + top.get(mMagFilter); - mWidth = temp->w; - mHeight = temp->h; + globals.pushField("wrap_s"); + top.get(mWrapS); - mContext = temp; + globals.pushField("wrap_t"); + top.get(mWrapT); + } } @@ -290,8 +286,6 @@ public: return; } - if (!mContext) loadFromFile(); - glGenTextures(1, &mObject); glBindTexture(GL_TEXTURE_2D, mObject); @@ -300,20 +294,17 @@ public: ( GL_TEXTURE_2D, 0, - mMode, + mImage->getMode(), //3, - mContext->w, - mContext->h, + mImage->getWidth(), + mImage->getHeight(), 0, - mMode, + mImage->getMode(), GL_UNSIGNED_BYTE, - mContext->pixels + mImage->getPixels() ); setProperties(); - - SDL_FreeSurface(mContext); - mContext = 0; } @@ -365,32 +356,55 @@ public: { uploadToGL(); } - if (mObject != globalObject_) + if (mObject != gObject) { glBindTexture(GL_TEXTURE_2D, mObject); - globalObject_ = mObject; + gObject = mObject; } } - SDL_Surface* mContext; - unsigned mWidth; ///< Horizontal dimension of the image. - unsigned mHeight; ///< Vertical dimension. + bool getTileCoords(Texture::TileIndex index, Scalar coords[8]) const + { + // make sure the index represents a real tile + if (index >= mTilesS * mTilesT) return false; + + Scalar w = 1.0 / Scalar(mTilesS); + Scalar h = 1.0 / Scalar(mTilesT); + + coords[0] = Scalar(index % mTilesS) * w; + coords[1] = (Scalar(mTilesT - 1) - + Scalar(index / mTilesS)) * h; + coords[2] = coords[0] + w; + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = coords[1] + h; + coords[6] = coords[0]; + coords[7] = coords[5]; + + return true; + } + + ImageP mImage; + + GLuint mMinFilter; ///< Minification filter. + GLuint mMagFilter; ///< Magnification filter. + GLuint mWrapS; ///< Wrapping behavior horizontally. + GLuint mWrapT; ///< Wrapping behavior vertically. + unsigned mTilesS; + unsigned mTilesT; - GLuint mMode; ///< Depth of the image, 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. - GLuint mObject; ///< GL texture handle. - static GLuint globalObject_; ///< Global GL texture handle. + Dispatch::Handler mDispatchHandler; }; -GLuint Texture::Impl::globalObject_ = 0; +GLuint Texture::Impl::gObject = 0; Texture::Texture(const std::string& name) : + Image(Texture::getPath(name)), // pass through mImpl(Texture::Impl::getInstance(name)) {} @@ -420,20 +434,7 @@ GLuint Texture::getObject() const void Texture::resetBind() { glBindTexture(GL_TEXTURE_2D, 0); - Impl::globalObject_ = 0; -} - - -unsigned Texture::getWidth() const -{ - // pass through - return mImpl->mWidth; -} - -unsigned Texture::getHeight() const -{ - // pass through - return mImpl->mHeight; + Impl::gObject = 0; } @@ -462,10 +463,54 @@ void Texture::setWrapT(GLuint wrap) } +bool Texture::getTileCoords(TileIndex index, Scalar coords[8]) const +{ + // pass through + return mImpl->getTileCoords(index, coords); +} + +bool Texture::getTileCoords(TileIndex index, Scalar coords[8], + Orientation orientation) const +{ + if (getTileCoords(index, coords)) + { + if (orientation & FLIP) + { + // this looks kinda weird, but it's just swapping in a way that + // doesn't require an intermediate variable + coords[1] = coords[5]; + coords[5] = coords[3]; + coords[3] = coords[7]; + coords[7] = coords[5]; + } + if (orientation & REVERSE) + { + coords[0] = coords[2]; + coords[2] = coords[6]; + coords[4] = coords[6]; + coords[6] = coords[0]; + } + + return true; + } + + return false; +} + + std::string Texture::getPath(const std::string& name) { - std::string path = Resource::getPath("textures/" + name + ".png"); - return path; + if (boost::find_last(name, ".png")) + { + return Resource::getPath(name); + } + else + { + std::string path("textures/"); + path += name; + path += ".png"; + return Resource::getPath(path); + } }