+++ /dev/null
-
-/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
-**] All rights reserved.
-*
-* vi:ts=4 sw=4 tw=75
-*
-* Distributable under the terms and conditions of the 2-clause BSD license;
-* see the file COPYING for a complete text of the license.
-*
-**************************************************************************/
-
-#include <cstdio> // FILE
-#include <cstring> // strncmp
-#include <stdexcept>
-
-#include <boost/algorithm/string.hpp>
-#include <boost/bind.hpp>
-
-#include "dispatcher.hh"
-#include "manager.hh"
-#include "log.hh"
-#include "opengl.hh"
-#include "script.hh"
-#include "texture.hh"
-#include "video.hh"
-
-
-namespace moof {
-
-
-/**
- * The texture implementation just contains all the information about the
- * image 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 manager so that multiple texture
- * objects can share the same internal objects and avoid having duplicate
- * textures loaded to GL.
- */
-
-class texture::impl : public manager<impl>
-{
-
- /**
- * Delete the texture (if it is loaded) from GL.
- */
-
- void unload_from_gl()
- {
- if (mObject)
- {
- if (mObject == gObject)
- {
- gObject = 0;
- }
-
- glDeleteTextures(1, &mObject);
- mObject = 0;
- }
- }
-
- /**
- * 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 context_recreated()
- {
- mObject = gObject = 0;
- upload_to_gl();
- }
-
- /**
- * This is a helper method used by some of the texture loading code.
- * It returns the first power of two which is greater than the input
- * value.
- */
-
- static int power_of_two(int input)
- {
- int value = 1;
-
- while (value < input)
- {
- value <<= 1;
- }
- return value;
- }
-
-
- static void bind_script_constants(script& script)
- {
- script::slot g = script.globals();
-
- g.set_field("CLAMP", GL_CLAMP);
- g.set_field("REPEAT", GL_REPEAT);
- g.set_field("LINEAR", GL_LINEAR);
- g.set_field("NEAREST", GL_NEAREST);
- g.set_field("LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR);
- g.set_field("LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST);
- g.set_field("NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR);
- g.set_field("NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST);
- }
-
-public:
-
- /*
- * Construction is initialization.
- */
- impl() :
- mMinFilter(GL_NEAREST),
- mMagFilter(GL_NEAREST),
- mWrapS(GL_CLAMP),
- mWrapT(GL_CLAMP),
- mTilesS(1),
- mTilesT(1),
- mObject(0)
- {
- // make sure we have a video context
- video* video = video::current();
- ASSERT(video && "should have a video context set");
-
- // we want to know when the GL context is recreated
- dispatcher& dispatcher = dispatcher::global();
- mNewContextDispatch = dispatcher.add_target("video.newcontext",
- boost::bind(&impl::context_recreated, this));
- }
-
- ~impl()
- {
- unload_from_gl();
- }
-
-
- void init(const std::string& name)
- {
- std::string path(name);
-
- resource::find(path);
-
- mImage = image::alloc(path);
- if (!mImage->is_valid())
- {
- throw std::runtime_error("texture not found: " + name);
- }
-
- mImage->flip();
-
- script script;
-
- bind_script_constants(script);
- log::import(script);
-
- if (script.do_string(mImage->comment()) != script::success)
- {
- std::string str;
- script[-1].get(str);
- log_warning(str);
- }
- else
- {
- log_info("loading tiles from texture", path);
-
- script::slot globals = script.globals();
- globals.get(mTilesS, "tiles_s");
- globals.get(mTilesT, "tiles_t");
- globals.get(mMinFilter, "min_filter");
- globals.get(mMagFilter, "mag_filter");
- globals.get(mWrapS, "wrap_s");
- globals.get(mWrapT, "wrap_t");
- }
- }
-
-
- /*
- * Upload the image to GL so that it will be accessible by a much more
- * manageable handle and hopefully reside in video memory.
- */
- void upload_to_gl()
- {
- if (mObject)
- {
- // already loaded
- return;
- }
-
- glGenTextures(1, &mObject);
- glBindTexture(GL_TEXTURE_2D, mObject);
-
- glTexImage2D
- //gluBuild2DMipmaps
- (
- GL_TEXTURE_2D,
- 0,
- mImage->mode(),
- //3,
- mImage->width(),
- mImage->height(),
- 0,
- mImage->mode(),
- GL_UNSIGNED_BYTE,
- mImage->pixels()
- );
-
- set_properties();
- }
-
-
- /*
- * Sets some texture properties such as the filters and external
- * coordinate behavior.
- */
- void set_properties()
- {
- 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);
- }
-
- void min_filter(GLuint filter)
- {
- bind();
- mMinFilter = filter;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mMinFilter);
- }
-
- void mag_filter(GLuint filter)
- {
- bind();
- mMagFilter = filter;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mMagFilter);
- }
-
- void wrap_s(GLuint wrap)
- {
- bind();
- mWrapS = wrap;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mWrapS);
- }
-
- void wrap_t(GLuint wrap)
- {
- bind();
- mWrapT = wrap;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mWrapT);
- }
-
-
- void bind()
- {
- if (mObject == 0)
- {
- upload_to_gl();
- }
- if (mObject != gObject)
- {
- glBindTexture(GL_TEXTURE_2D, mObject);
- gObject = mObject;
- }
- }
-
-
- bool tile_coordinates(int index, scalar coords[8]) const
- {
- // make sure the index represents a real tile
- if (index < 0 && 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;
- }
-
- image_ptr mImage;
-
- GLuint mMinFilter; ///< Minification filter.
- GLuint mMagFilter; ///< Magnification filter.
- GLuint mWrapS; ///< Wrapping behavior horizontally.
- GLuint mWrapT; ///< Wrapping behavior vertically.
- int mTilesS;
- int mTilesT;
-
- GLuint mObject; ///< GL texture handle.
- static GLuint gObject; ///< Global GL texture handle.
-
- dispatcher::handle mNewContextDispatch;
-};
-
-GLuint texture::impl::gObject = 0;
-
-
-texture::texture(const std::string& name) : // FIXME: this is really weird
- image(name),
- // pass through
- impl_(texture::impl::instance(name)) {}
-
-
-/**
- * Bind the GL texture for mapping, etc.
- */
-
-void texture::bind() const
-{
- // pass through
- impl_->bind();
-}
-
-
-/**
- * Get the texture object, for the curious.
- */
-
-GLuint texture::object() const
-{
- // pass through
- return impl_->mObject;
-}
-
-
-void texture::reset_binding()
-{
- glBindTexture(GL_TEXTURE_2D, 0);
- impl::gObject = 0;
-}
-
-
-void texture::min_filter(GLuint filter)
-{
- // pass through
- impl_->min_filter(filter);
-}
-
-void texture::mag_filter(GLuint filter)
-{
- // pass through
- impl_->mag_filter(filter);
-}
-
-void texture::wrap_s(GLuint wrap)
-{
- // pass through
- impl_->wrap_s(wrap);
-}
-
-void texture::wrap_t(GLuint wrap)
-{
- // pass through
- impl_->wrap_t(wrap);
-}
-
-
-bool texture::tile_coordinates(int index, scalar coords[8]) const
-{
- // pass through
- return impl_->tile_coordinates(index, coords);
-}
-
-bool texture::tile_coordinates(int index, scalar coords[8],
- orientation orientation) const
-{
- if (tile_coordinates(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;
-}
-
-
-} // namespace moof
-