diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 37c94f384..451d8070c 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -45,8 +45,6 @@ Graphics::Graphics() , userMatrices(0) { currentWindow = love::window::sdl::Window::getSingleton(); - - resetBoundTexture(); } Graphics::~Graphics() @@ -116,6 +114,8 @@ bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int f // Unload all volatile objects. These must be reloaded after // the display mode change. Volatile::unloadAll(); + + uninitializeContext(); bool success = currentWindow->setWindow(width, height, fullscreen, vsync, fsaa); // Regardless of failure, we'll have to set up OpenGL once again. @@ -124,6 +124,8 @@ bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int f height = currentWindow->getHeight(); // Okay, setup OpenGL. + + initializeContext(); // Enable blending glEnable(GL_BLEND); @@ -138,6 +140,7 @@ bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int f // Enable textures glEnable(GL_TEXTURE_2D); + setActiveTextureUnit(GL_TEXTURE0); // Set the viewport to top-left corner glViewport(0, 0, width, height); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index edcdf59fa..44234fa4e 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -18,7 +18,9 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +#include #include "OpenGL.h" +#include "common/Exception.h" namespace love { @@ -27,27 +29,95 @@ namespace graphics namespace opengl { -static GLuint boundTexture = 0; +static bool contextInitialized = false; -void resetBoundTexture() +static int curTextureUnitIndex = 0; +static std::vector textureUnits; + +void initializeContext() { - // OpenGL might not be initialized yet, so we can't do a real reset - boundTexture = 0; + if (contextInitialized) + return; + + contextInitialized = true; + + if (GLEE_ARB_multitexture || GLEE_VERSION_1_3) + { + GLint maxtextureunits; + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxtextureunits); + + if (GLEE_VERSION_2_0 || GLEE_ARB_vertex_shader) + { + GLint maxtextureimageunits; + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureimageunits); + + if (maxtextureimageunits > maxtextureunits) + maxtextureunits = maxtextureimageunits; + } + + textureUnits.resize(maxtextureunits, 0); + + GLenum activeTextureUnit; + glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *)&activeTextureUnit); + + curTextureUnitIndex = activeTextureUnit - GL_TEXTURE0; + } + else + { + // multitexturing not supported so we only have 1 texture unit + textureUnits.resize(1, 0); + curTextureUnitIndex = 0; + } } -void bindTexture(GLuint texture, bool override) +void uninitializeContext() { - if (texture != boundTexture || texture == 0 || override) + contextInitialized = false; +} + +void setActiveTextureUnit(GLenum textureunit) +{ + initializeContext(); + + int textureunitindex = textureunit - GL_TEXTURE0; + + if (textureunitindex < 0 || (size_t) textureunitindex >= textureUnits.size()) + throw love::Exception("Invalid texture unit index."); + + if (textureunitindex != curTextureUnitIndex) { - boundTexture = texture; + if (GLEE_VERSION_1_3) + glActiveTexture(textureunit); + else if (GLEE_ARB_multitexture) + glActiveTextureARB(textureunit); + else + throw love::Exception("Multitexturing not supported."); + } + + curTextureUnitIndex = textureunitindex; +} + +void bindTexture(GLuint texture) +{ + initializeContext(); + + if (texture != textureUnits[curTextureUnitIndex] || texture == 0) + { + textureUnits[curTextureUnitIndex] = texture; glBindTexture(GL_TEXTURE_2D, texture); } } void deleteTexture(GLuint texture) { - if (texture == boundTexture) - boundTexture = 0; + initializeContext(); + + std::vector::iterator it; + for (it = textureUnits.begin(); it != textureUnits.end(); ++it) + { + if (*it == texture) + *it = 0; + } glDeleteTextures(1, &texture); } diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 93d32d47d..a0c0b265b 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -30,16 +30,22 @@ namespace graphics namespace opengl { -// resets the stored bound texture id -void resetBoundTexture(); +void initializeContext(); + +void uninitializeContext(); + +/** + * Helper for setting the active texture unit + * @param textureunit The GL texture unit to set + **/ +void setActiveTextureUnit(GLenum textureunit); /** * Helper for binding an OpenGL texture. * Makes sure we aren't redundantly binding textures. * @param texture The texture to bind. - * @param override Overrides the checks to guarantee texture bind **/ -void bindTexture(GLuint texture, bool override = false); +void bindTexture(GLuint texture); /** * Helper for deleting an OpenGL texture. diff --git a/src/modules/graphics/opengl/ShaderEffect.cpp b/src/modules/graphics/opengl/ShaderEffect.cpp index 2a5725712..4cdb8f17c 100644 --- a/src/modules/graphics/opengl/ShaderEffect.cpp +++ b/src/modules/graphics/opengl/ShaderEffect.cpp @@ -332,12 +332,12 @@ void ShaderEffect::sendTexture(const std::string &name, GLuint texture) GLint texture_unit = getTextureUnit(name); - glActiveTexture(GL_TEXTURE0 + texture_unit); - bindTexture(texture, true); // guarantee it gets bound + setActiveTextureUnit(GL_TEXTURE0 + texture_unit); + bindTexture(texture); glUniform1i(location, texture_unit); // reset texture unit - glActiveTexture(GL_TEXTURE0); + setActiveTextureUnit(GL_TEXTURE0); // throw error if needed checkSetUniformError(); diff --git a/src/modules/graphics/opengl/ShaderEffect.h b/src/modules/graphics/opengl/ShaderEffect.h index 88e706dfe..ce3f0b2e8 100644 --- a/src/modules/graphics/opengl/ShaderEffect.h +++ b/src/modules/graphics/opengl/ShaderEffect.h @@ -48,6 +48,7 @@ public: void attach(); static void detach(); + static std::string getGLSLVersion(); static bool isSupported();