diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 69ef21bf3..dd254743a 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -89,6 +89,16 @@ bool Graphics::getConstant(PointStyle in, const char *&out) return pointStyles.find(in, out); } +bool Graphics::getConstant(const char *in, AlphaTestMode &out) +{ + return alphaTests.find(in, out); +} + +bool Graphics::getConstant(AlphaTestMode in, const char *&out) +{ + return alphaTests.find(in, out); +} + bool Graphics::getConstant(const char *in, Support &out) { return support.find(in, out); @@ -154,6 +164,18 @@ StringMap::Entry Graphics::point StringMap Graphics::pointStyles(Graphics::pointStyleEntries, sizeof(Graphics::pointStyleEntries)); +StringMap::Entry Graphics::alphaTestEntries[] = +{ + { "<", Graphics::ALPHATEST_LESS }, + { "<=", Graphics::ALPHATEST_LEQUAL }, + { "==", Graphics::ALPHATEST_EQUAL }, + { "~=", Graphics::ALPHATEST_NOTEQUAL }, + { ">=", Graphics::ALPHATEST_GEQUAL }, + { ">", Graphics::ALPHATEST_GREATER }, +}; + +StringMap Graphics::alphaTests(Graphics::alphaTestEntries, sizeof(Graphics::alphaTestEntries)); + StringMap::Entry Graphics::supportEntries[] = { { "canvas", Graphics::SUPPORT_CANVAS }, diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 435a014f2..78c06db73 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -83,6 +83,17 @@ public: POINT_MAX_ENUM }; + enum AlphaTestMode + { + ALPHATEST_LESS = 1, + ALPHATEST_LEQUAL, + ALPHATEST_EQUAL, + ALPHATEST_NOTEQUAL, + ALPHATEST_GEQUAL, + ALPHATEST_GREATER, + ALPHATEST_MAX_ENUM + }; + enum Support { SUPPORT_CANVAS = 1, @@ -118,6 +129,9 @@ public: static bool getConstant(const char *in, PointStyle &out); static bool getConstant(PointStyle in, const char *&out); + static bool getConstant(const char *in, AlphaTestMode &out); + static bool getConstant(AlphaTestMode in, const char *&out); + static bool getConstant(const char *in, Support &out); static bool getConstant(Support in, const char *&out); @@ -141,6 +155,9 @@ private: static StringMap::Entry pointStyleEntries[]; static StringMap pointStyles; + static StringMap::Entry alphaTestEntries[]; + static StringMap alphaTests; + static StringMap::Entry supportEntries[]; static StringMap support; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 9242e95b9..3804c7432 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -81,6 +81,14 @@ DisplayState Graphics::saveState() glGetFloatv(GL_POINT_SIZE, &s.pointSize); //get point style s.pointStyle = (glIsEnabled(GL_POINT_SMOOTH) == GL_TRUE) ? Graphics::POINT_SMOOTH : Graphics::POINT_ROUGH; + // get alpha test status + s.alphaTest = isAlphaTestEnabled(); + if (s.alphaTest) + { + // if alpha testing is enabled, store mode and reference alpha + s.alphaTestMode = getAlphaTestMode(); + s.alphaTestRef = getAlphaTestRef(); + } //get scissor status s.scissor = (glIsEnabled(GL_SCISSOR_TEST) == GL_TRUE); //do we have scissor, if so, store the box @@ -100,6 +108,10 @@ void Graphics::restoreState(const DisplayState &s) setBlendMode(s.blendMode); setLine(lineWidth, s.lineStyle); setPoint(s.pointSize, s.pointStyle); + if (s.alphaTest) + setAlphaTest(s.alphaTestMode, s.alphaTestRef); + else + setAlphaTest(); if (s.scissor) setScissor(s.scissorBox[0], s.scissorBox[1], s.scissorBox[2], s.scissorBox[3]); else @@ -152,6 +164,10 @@ bool Graphics::setMode(int width, int height, WindowFlags *flags) if (GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap) glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); + // Set default alpha test mode and value + glAlphaFunc(GL_GREATER, 0.0f); + setAlphaTest(); + // Enable textures glEnable(GL_TEXTURE_2D); setActiveTextureUnit(0); @@ -356,6 +372,80 @@ void Graphics::discardStencil() glDisable(GL_STENCIL_TEST); } +void Graphics::setAlphaTest(Graphics::AlphaTestMode mode, unsigned char refalpha) +{ + GLclampf ref = refalpha / 255.0f; + + glEnable(GL_ALPHA_TEST); + + switch (mode) + { + case ALPHATEST_LESS: + glAlphaFunc(GL_LESS, ref); + break; + case ALPHATEST_LEQUAL: + glAlphaFunc(GL_LEQUAL, ref); + break; + case ALPHATEST_EQUAL: + glAlphaFunc(GL_EQUAL, ref); + break; + case ALPHATEST_NOTEQUAL: + glAlphaFunc(GL_NOTEQUAL, ref); + break; + case ALPHATEST_GEQUAL: + glAlphaFunc(GL_GEQUAL, ref); + break; + case ALPHATEST_GREATER: + glAlphaFunc(GL_GREATER, ref); + break; + default: + glDisable(GL_ALPHA_TEST); + break; + } +} + +void Graphics::setAlphaTest() +{ + glDisable(GL_ALPHA_TEST); +} + +bool Graphics::isAlphaTestEnabled() +{ + return glIsEnabled(GL_ALPHA_TEST) == GL_TRUE; +} + +Graphics::AlphaTestMode Graphics::getAlphaTestMode() +{ + GLint func; + glGetIntegerv(GL_ALPHA_TEST_FUNC, &func); + + switch (func) + { + case GL_LESS: + return ALPHATEST_LESS; + case GL_LEQUAL: + return ALPHATEST_LEQUAL; + case GL_EQUAL: + return ALPHATEST_EQUAL; + case GL_NOTEQUAL: + return ALPHATEST_NOTEQUAL; + case GL_GEQUAL: + return ALPHATEST_GEQUAL; + case GL_GREATER: + return ALPHATEST_GREATER; + default: + return ALPHATEST_MAX_ENUM; + } +} + +unsigned char Graphics::getAlphaTestRef() +{ + GLfloat ref; + glGetFloatv(GL_ALPHA_TEST_REF, &ref); + + return ref * 255; +} + Image *Graphics::newImage(love::image::ImageData *data) { // Create the image. diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 5890e1761..7bfc08f77 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -73,6 +73,10 @@ struct DisplayState float pointSize; Graphics::PointStyle pointStyle; + bool alphaTest; + Graphics::AlphaTestMode alphaTestMode; + unsigned char alphaTestRef; + // Scissor. bool scissor; GLint scissorBox[4]; @@ -96,6 +100,7 @@ struct DisplayState lineStyle = Graphics::LINE_SMOOTH; pointSize = 1.0f; pointStyle = Graphics::POINT_SMOOTH; + alphaTest = false; scissor = false; colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = true; caption = ""; @@ -248,6 +253,33 @@ public: */ void discardStencil(); + /** + * Enables alpha testing for all following draw calls + * @param mode The alpha comparison mode used when performing the alpha test + * @param refalpha The reference alpha value used when perfoming the alpha test + */ + void setAlphaTest(Graphics::AlphaTestMode mode, unsigned char refalpha); + + /** + * Disables alpha testing + */ + void setAlphaTest(); + + /** + * True if alpha testing is enabled + */ + bool isAlphaTestEnabled(); + + /** + * Gets the current alpha test comparison mode + */ + Graphics::AlphaTestMode getAlphaTestMode(); + + /** + * Gets the current alpha test reference alpha value (0-255) + */ + unsigned char getAlphaTestRef(); + /** * Creates an Image object with padding and/or optimization. **/ diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index e1fbba89b..b6eff71d9 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -274,6 +274,47 @@ int w_setInvertedStencil(lua_State *L) return setStencil(L, true); } +int w_setAlphaTest(lua_State *L) +{ + // disable alpha testing if no arguments are given + if (lua_gettop(L) == 0) + { + instance->setAlphaTest(); + return 0; + } + + const char *modestr = luaL_checkstring(L, 1); + unsigned char refalpha = (unsigned char) luaL_checkinteger(L, 2); + + Graphics::AlphaTestMode mode; + if (!Graphics::getConstant(modestr, mode)) + return luaL_error(L, "Invalid alpha test mode: %s", modestr); + + instance->setAlphaTest(mode, refalpha); + + return 0; +} + +int w_getAlphaTest(lua_State *L) +{ + // return nil if not enabled + if (!instance->isAlphaTestEnabled()) + return 0; + + Graphics::AlphaTestMode mode = instance->getAlphaTestMode(); + + const char *modestr; + if (!Graphics::getConstant(mode, modestr)) + return 0; // also return nil if alpha test mode isn't valid + + unsigned char refalpha = instance->getAlphaTestRef(); + + lua_pushstring(L, modestr); + lua_pushnumber(L, refalpha); + + return 2; +} + int w_newImage(lua_State *L) { love::image::ImageData *data = 0; @@ -1589,6 +1630,9 @@ static const luaL_Reg functions[] = { "setStencil", w_setStencil }, { "setInvertedStencil", w_setInvertedStencil }, + { "setAlphaTest", w_setAlphaTest }, + { "getAlphaTest", w_getAlphaTest }, + { "point", w_point }, { "line", w_line }, { "rectangle", w_rectangle }, diff --git a/src/modules/graphics/opengl/wrap_Graphics.h b/src/modules/graphics/opengl/wrap_Graphics.h index b67d0e2e5..9be30a723 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.h +++ b/src/modules/graphics/opengl/wrap_Graphics.h @@ -56,6 +56,8 @@ int w_setScissor(lua_State *L); int w_getScissor(lua_State *L); int w_defineMask(lua_State *L); int w_setMask(lua_State *L); +int w_setAlphaTest(lua_State *L); +int w_getAlphaTest(lua_State *L); int w_newImage(lua_State *L); int w_newQuad(lua_State *L); int w_newQuad(lua_State *L);