diff --git a/CMakeLists.txt b/CMakeLists.txt index d2460b3bb..2fc809d50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -249,15 +249,13 @@ source_group("modules\\font\\freetype" FILES ${LOVE_SRC_MODULE_FONT_FREETYPE}) set(LOVE_SRC_MODULE_GRAPHICS_ROOT src/modules/graphics/Color.h - src/modules/graphics/Drawable.cpp src/modules/graphics/Drawable.h - src/modules/graphics/DrawQable.h src/modules/graphics/Graphics.cpp src/modules/graphics/Graphics.h - src/modules/graphics/Image.cpp - src/modules/graphics/Image.h src/modules/graphics/Quad.cpp src/modules/graphics/Quad.h + src/modules/graphics/Texture.cpp + src/modules/graphics/Texture.h src/modules/graphics/Volatile.cpp src/modules/graphics/Volatile.h ) @@ -285,6 +283,7 @@ set(LOVE_SRC_MODULE_GRAPHICS_OPENGL src/modules/graphics/opengl/Shader.h src/modules/graphics/opengl/SpriteBatch.cpp src/modules/graphics/opengl/SpriteBatch.h + src/modules/graphics/opengl/Texture.h src/modules/graphics/opengl/VertexBuffer.cpp src/modules/graphics/opengl/VertexBuffer.h src/modules/graphics/opengl/wrap_Canvas.cpp diff --git a/platform/macosx/love-framework.xcodeproj/project.pbxproj b/platform/macosx/love-framework.xcodeproj/project.pbxproj index b5da69f74..44cd5687e 100644 --- a/platform/macosx/love-framework.xcodeproj/project.pbxproj +++ b/platform/macosx/love-framework.xcodeproj/project.pbxproj @@ -109,9 +109,8 @@ FA08F61216C753E700F007B5 /* Rasterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1B1C4E4D288A1D2F29E57B1B /* Rasterizer.cpp */; }; FA08F61316C753E700F007B5 /* wrap_GlyphData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1B4E22F1388E2B2E76E3377B /* wrap_GlyphData.cpp */; }; FA08F61416C753E700F007B5 /* wrap_Rasterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11745DE315E859F71E881D76 /* wrap_Rasterizer.cpp */; }; - FA08F61516C753F600F007B5 /* Drawable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58BA2BB460AF3C591B22690E /* Drawable.cpp */; }; FA08F61716C753F600F007B5 /* Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03F17FF546D637744E263961 /* Graphics.cpp */; }; - FA08F61816C753F600F007B5 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58CC50E70A375FDF53EF01B6 /* Image.cpp */; }; + FA08F61816C753F600F007B5 /* Texture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58CC50E70A375FDF53EF01B6 /* Texture.cpp */; }; FA08F61A16C753F600F007B5 /* Volatile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B731754147B27AF73AC5358 /* Volatile.cpp */; }; FA08F61B16C7541400F007B5 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AD52074367950B735707CE1 /* Canvas.cpp */; }; FA08F61C16C7541400F007B5 /* Font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 583037E9238A6EF00DD20B1A /* Font.cpp */; }; @@ -267,6 +266,7 @@ FA7AA59317F6AC1F00704BE2 /* wrap_Mesh.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7AA59117F6AC1F00704BE2 /* wrap_Mesh.h */; }; FA7C937A16DCC6C2006F2BEE /* wrap_Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */; }; FA7C937B16DCC6C2006F2BEE /* wrap_Math.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7C937616DCC6C2006F2BEE /* wrap_Math.h */; }; + FA9B492A1875EFB900201DA9 /* Texture.h in Headers */ = {isa = PBXBuildFile; fileRef = FA9B49281875EFB900201DA9 /* Texture.h */; }; FA9B4A0816E1578300074F42 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA9B4A0716E1578300074F42 /* SDL2.framework */; }; FA9FC0B0173D6E3E005027FF /* wrap_Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA9FC0AE173D6E3E005027FF /* wrap_Window.cpp */; }; FA9FC0B1173D6E3E005027FF /* wrap_Window.h in Headers */ = {isa = PBXBuildFile; fileRef = FA9FC0AF173D6E3E005027FF /* wrap_Window.h */; }; @@ -285,7 +285,6 @@ FAC5710317402D1100D147E4 /* wrap_BezierCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC570FF17402D1100D147E4 /* wrap_BezierCurve.h */; }; FAC86E631724552C00EED715 /* wrap_Quad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E611724552C00EED715 /* wrap_Quad.cpp */; }; FAC86E641724552C00EED715 /* wrap_Quad.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E621724552C00EED715 /* wrap_Quad.h */; }; - FAC86E6A1724555D00EED715 /* DrawQable.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E661724555D00EED715 /* DrawQable.h */; }; FAC86E6B1724555D00EED715 /* Quad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E671724555D00EED715 /* Quad.cpp */; }; FAC86E6C1724555D00EED715 /* Quad.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E681724555D00EED715 /* Quad.h */; }; FAE010DB170DDE99006F29D0 /* ddsinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010D8170DDE99006F29D0 /* ddsinfo.h */; }; @@ -438,7 +437,7 @@ 1CAA69E00D0808BA2108238B /* wrap_ChainShape.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_ChainShape.cpp; sourceTree = ""; }; 1CD02D1975803957282F28AB /* auxiliar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = auxiliar.c; sourceTree = ""; }; 1CE84F1F19BC2AA412C638B1 /* timeout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = timeout.h; sourceTree = ""; }; - 1DA41DFF0869489411A71AFC /* Image.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = ""; }; + 1DA41DFF0869489411A71AFC /* Texture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Texture.h; sourceTree = ""; }; 1E22646A710E5EFC27FE3932 /* FrictionJoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FrictionJoint.cpp; sourceTree = ""; }; 1E27263847302FCA1F843B47 /* b2PrismaticJoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2PrismaticJoint.cpp; sourceTree = ""; }; 1E827AE8548C52493ED95629 /* wrap_Filesystem.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Filesystem.cpp; sourceTree = ""; }; @@ -629,8 +628,7 @@ 583037E9238A6EF00DD20B1A /* Font.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Font.cpp; sourceTree = ""; }; 584E16AE09E12536206C46FE /* Mouse.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Mouse.cpp; sourceTree = ""; }; 58792BC1126C2917432D706B /* b2CircleContact.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleContact.cpp; sourceTree = ""; }; - 58BA2BB460AF3C591B22690E /* Drawable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Drawable.cpp; sourceTree = ""; }; - 58CC50E70A375FDF53EF01B6 /* Image.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = ""; }; + 58CC50E70A375FDF53EF01B6 /* Texture.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Texture.cpp; sourceTree = ""; }; 58CD093F254501E37CA47CA8 /* types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = ""; }; 597478A255B82B56488B4717 /* wrap_FileData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_FileData.cpp; sourceTree = ""; }; 59BE634A2ACE722F14B86F89 /* b2Island.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2Island.cpp; sourceTree = ""; }; @@ -824,6 +822,7 @@ FA7AA59117F6AC1F00704BE2 /* wrap_Mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Mesh.h; sourceTree = ""; }; FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Math.cpp; sourceTree = ""; }; FA7C937616DCC6C2006F2BEE /* wrap_Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Math.h; sourceTree = ""; }; + FA9B49281875EFB900201DA9 /* Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Texture.h; sourceTree = ""; }; FA9B4A0716E1578300074F42 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = ""; }; FA9FC0AE173D6E3E005027FF /* wrap_Window.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Window.cpp; sourceTree = ""; }; FA9FC0AF173D6E3E005027FF /* wrap_Window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Window.h; sourceTree = ""; }; @@ -842,7 +841,6 @@ FAC570FF17402D1100D147E4 /* wrap_BezierCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_BezierCurve.h; sourceTree = ""; }; FAC86E611724552C00EED715 /* wrap_Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Quad.cpp; sourceTree = ""; }; FAC86E621724552C00EED715 /* wrap_Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Quad.h; sourceTree = ""; }; - FAC86E661724555D00EED715 /* DrawQable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawQable.h; sourceTree = ""; }; FAC86E671724555D00EED715 /* Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Quad.cpp; sourceTree = ""; }; FAC86E681724555D00EED715 /* Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Quad.h; sourceTree = ""; }; FAE010D8170DDE99006F29D0 /* ddsinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsinfo.h; sourceTree = ""; }; @@ -1476,16 +1474,14 @@ isa = PBXGroup; children = ( 4941079838020ECA049B5C21 /* Color.h */, - 58BA2BB460AF3C591B22690E /* Drawable.cpp */, 5D93601669875EE06721689E /* Drawable.h */, - FAC86E661724555D00EED715 /* DrawQable.h */, 03F17FF546D637744E263961 /* Graphics.cpp */, 777352284E262F48543E6E7F /* Graphics.h */, - 58CC50E70A375FDF53EF01B6 /* Image.cpp */, - 1DA41DFF0869489411A71AFC /* Image.h */, 75093EE94918576801F50993 /* opengl */, FAC86E671724555D00EED715 /* Quad.cpp */, FAC86E681724555D00EED715 /* Quad.h */, + 58CC50E70A375FDF53EF01B6 /* Texture.cpp */, + 1DA41DFF0869489411A71AFC /* Texture.h */, 4B731754147B27AF73AC5358 /* Volatile.cpp */, 0CFF64090F0F4F481BB80CF0 /* Volatile.h */, ); @@ -1683,6 +1679,7 @@ FA577A8616C71CF000860150 /* Shader.h */, 4D700D182EAA46273D1E2CC4 /* SpriteBatch.cpp */, 727D23FA1CC755B902471A45 /* SpriteBatch.h */, + FA9B49281875EFB900201DA9 /* Texture.h */, 426B1C4475DC54505B824B7F /* VertexBuffer.cpp */, 577B66502A5360AE60733B10 /* VertexBuffer.h */, 4E3251027026699A1D4D310D /* wrap_Canvas.cpp */, @@ -1979,7 +1976,6 @@ FA636D8B171B70920065623F /* RandomGenerator.h in Headers */, FA636D8F171B72A70065623F /* wrap_RandomGenerator.h in Headers */, FAC86E641724552C00EED715 /* wrap_Quad.h in Headers */, - FAC86E6A1724555D00EED715 /* DrawQable.h in Headers */, FAC86E6C1724555D00EED715 /* Quad.h in Headers */, FA03546D1731F3A700284828 /* simplexnoise1234.h in Headers */, FA3D9E0E16E68DE600CA6630 /* Cursor.h in Headers */, @@ -1990,6 +1986,7 @@ FAF6705218184FF800DBDEEA /* wuff_internal.h in Headers */, FAB007941740C28900A9664D /* Joystick.h in Headers */, FAB007981740C87D00A9664D /* wrap_Joystick.h in Headers */, + FA9B492A1875EFB900201DA9 /* Texture.h in Headers */, FAC5710117402D1100D147E4 /* BezierCurve.h in Headers */, FAC5710317402D1100D147E4 /* wrap_BezierCurve.h in Headers */, FA5FDC7E1788D548002F0ED2 /* callbacks.h in Headers */, @@ -2179,9 +2176,8 @@ FA08F61216C753E700F007B5 /* Rasterizer.cpp in Sources */, FA08F61316C753E700F007B5 /* wrap_GlyphData.cpp in Sources */, FA08F61416C753E700F007B5 /* wrap_Rasterizer.cpp in Sources */, - FA08F61516C753F600F007B5 /* Drawable.cpp in Sources */, FA08F61716C753F600F007B5 /* Graphics.cpp in Sources */, - FA08F61816C753F600F007B5 /* Image.cpp in Sources */, + FA08F61816C753F600F007B5 /* Texture.cpp in Sources */, FA08F61A16C753F600F007B5 /* Volatile.cpp in Sources */, FA08F61B16C7541400F007B5 /* Canvas.cpp in Sources */, FA08F61C16C7541400F007B5 /* Font.cpp in Sources */, diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 75558edd9..7dfbe9415 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -671,6 +671,7 @@ StringMap::Entry typeEntries[] = // Graphics {"Drawable", GRAPHICS_DRAWABLE_ID}, + {"Texture", GRAPHICS_TEXTURE_ID}, {"Image", GRAPHICS_IMAGE_ID}, {"Quad", GRAPHICS_QUAD_ID}, {"Font", GRAPHICS_FONT_ID}, diff --git a/src/common/types.h b/src/common/types.h index a161a80b3..4ead4dfe8 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -45,7 +45,7 @@ enum Type // Graphics GRAPHICS_DRAWABLE_ID, - GRAPHICS_DRAWQABLE_ID, + GRAPHICS_TEXTURE_ID, GRAPHICS_IMAGE_ID, GRAPHICS_QUAD_ID, GRAPHICS_FONT_ID, @@ -130,13 +130,13 @@ const bits FONT_RASTERIZER_T = (bits(1) << FONT_RASTERIZER_ID) | OBJECT_T; // Graphics. const bits GRAPHICS_DRAWABLE_T = (bits(1) << GRAPHICS_DRAWABLE_ID) | OBJECT_T; -const bits GRAPHICS_DRAWQABLE_T = (bits(1) << GRAPHICS_DRAWQABLE_ID) | GRAPHICS_DRAWABLE_T; -const bits GRAPHICS_IMAGE_T = (bits(1) << GRAPHICS_IMAGE_ID) | GRAPHICS_DRAWQABLE_T; +const bits GRAPHICS_TEXTURE_T = (bits(1) << GRAPHICS_TEXTURE_ID) | GRAPHICS_DRAWABLE_T; +const bits GRAPHICS_IMAGE_T = (bits(1) << GRAPHICS_IMAGE_ID) | GRAPHICS_TEXTURE_T; const bits GRAPHICS_QUAD_T = (bits(1) << GRAPHICS_QUAD_ID) | OBJECT_T; const bits GRAPHICS_FONT_T = (bits(1) << GRAPHICS_FONT_ID) | OBJECT_T; const bits GRAPHICS_PARTICLE_SYSTEM_T = (bits(1) << GRAPHICS_PARTICLE_SYSTEM_ID) | GRAPHICS_DRAWABLE_T; const bits GRAPHICS_SPRITE_BATCH_T = (bits(1) << GRAPHICS_SPRITE_BATCH_ID) | GRAPHICS_DRAWABLE_T; -const bits GRAPHICS_CANVAS_T = (bits(1) << GRAPHICS_CANVAS_ID) | GRAPHICS_DRAWQABLE_T; +const bits GRAPHICS_CANVAS_T = (bits(1) << GRAPHICS_CANVAS_ID) | GRAPHICS_TEXTURE_T; const bits GRAPHICS_SHADER_T = (bits(1) << GRAPHICS_SHADER_ID) | OBJECT_T; const bits GRAPHICS_MESH_T = (bits(1) << GRAPHICS_MESH_ID) | GRAPHICS_DRAWABLE_T; diff --git a/src/modules/graphics/DrawQable.h b/src/modules/graphics/DrawQable.h deleted file mode 100644 index 1c0d5230e..000000000 --- a/src/modules/graphics/DrawQable.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2006-2013 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_GRAPHICS_DRAWQABLE_H -#define LOVE_GRAPHICS_DRAWQABLE_H - -// LOVE -#include "Drawable.h" -#include "Quad.h" - -namespace love -{ -namespace graphics -{ - -/** - * A DrawQable is anything that be drawn in part with a Quad object. - **/ -class DrawQable : public Drawable -{ -public: - - /** - * Destructor. - **/ - virtual ~DrawQable() {} - - /** - * Draws the object with the specified transformation. - * - * @param quad The Quad object to use to draw the object. - * @param x The position of the object along the x-axis. - * @param y The position of the object along the y-axis. - * @param angle The angle of the object (in radians). - * @param sx The scale factor along the x-axis. - * @param sy The scale factor along the y-axis. - * @param ox The origin offset along the x-axis. - * @param oy The origin offset along the y-axis. - * @param kx Shear along the x-axis. - * @param ky Shear along the y-axis. - **/ - virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const = 0; -}; - -} // graphics -} // love - -#endif // LOVE_GRAPHICS_DRAWQABLE_H diff --git a/src/modules/graphics/Drawable.h b/src/modules/graphics/Drawable.h index d399a0855..9b7aa88aa 100644 --- a/src/modules/graphics/Drawable.h +++ b/src/modules/graphics/Drawable.h @@ -40,7 +40,7 @@ public: /** * Destructor. **/ - virtual ~Drawable(); + virtual ~Drawable() {} /** * Draws the object with the specified transformation. diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp deleted file mode 100644 index 3bdc06e0f..000000000 --- a/src/modules/graphics/Image.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2006-2013 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "Image.h" - -namespace love -{ -namespace graphics -{ - -Image::Filter Image::defaultFilter; - -Image::Filter::Filter() - : min(FILTER_LINEAR) - , mag(FILTER_LINEAR) - , mipmap(FILTER_NONE) - , anisotropy(1.0f) -{ -} - -Image::Wrap::Wrap() - : s(WRAP_CLAMP) - , t(WRAP_CLAMP) -{ -} - -Image::~Image() -{ -} - -void Image::setDefaultFilter(const Filter &f) -{ - defaultFilter = f; -} - -const Image::Filter &Image::getDefaultFilter() -{ - return defaultFilter; -} - -bool Image::getConstant(const char *in, FilterMode &out) -{ - return filterModes.find(in, out); -} - -bool Image::getConstant(FilterMode in, const char *&out) -{ - return filterModes.find(in, out); -} - -bool Image::getConstant(const char *in, WrapMode &out) -{ - return wrapModes.find(in, out); -} - -bool Image::getConstant(WrapMode in, const char *&out) -{ - return wrapModes.find(in, out); -} - -StringMap::Entry Image::filterModeEntries[] = -{ - { "linear", Image::FILTER_LINEAR }, - { "nearest", Image::FILTER_NEAREST }, -}; - -StringMap Image::filterModes(Image::filterModeEntries, sizeof(Image::filterModeEntries)); - -StringMap::Entry Image::wrapModeEntries[] = -{ - { "clamp", Image::WRAP_CLAMP }, - { "repeat", Image::WRAP_REPEAT }, -}; - -StringMap Image::wrapModes(Image::wrapModeEntries, sizeof(Image::wrapModeEntries)); - - -} // graphics -} // love diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp new file mode 100644 index 000000000..7a5daa01c --- /dev/null +++ b/src/modules/graphics/Texture.cpp @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "Texture.h" + +namespace love +{ +namespace graphics +{ + +Texture::Filter Texture::defaultFilter; + +Texture::Filter::Filter() + : min(FILTER_LINEAR) + , mag(FILTER_LINEAR) + , mipmap(FILTER_NONE) + , anisotropy(1.0f) +{ +} + +Texture::Wrap::Wrap() + : s(WRAP_CLAMP) + , t(WRAP_CLAMP) +{ +} + +Texture::Texture() + : width(0) + , height(0) + , filter(getDefaultFilter()) + , wrap() + , vertices() +{ +} + +Texture::~Texture() +{ +} + +int Texture::getWidth() const +{ + return width; +} + +int Texture::getHeight() const +{ + return height; +} + +const Texture::Filter &Texture::getFilter() const +{ + return filter; +} + +const Texture::Wrap &Texture::getWrap() const +{ + return wrap; +} + +const Vertex *Texture::getVertices() const +{ + return vertices; +} + +void Texture::setDefaultFilter(const Filter &f) +{ + defaultFilter = f; +} + +const Texture::Filter &Texture::getDefaultFilter() +{ + return defaultFilter; +} + +bool Texture::getConstant(const char *in, FilterMode &out) +{ + return filterModes.find(in, out); +} + +bool Texture::getConstant(FilterMode in, const char *&out) +{ + return filterModes.find(in, out); +} + +bool Texture::getConstant(const char *in, WrapMode &out) +{ + return wrapModes.find(in, out); +} + +bool Texture::getConstant(WrapMode in, const char *&out) +{ + return wrapModes.find(in, out); +} + +StringMap::Entry Texture::filterModeEntries[] = +{ + { "linear", Texture::FILTER_LINEAR }, + { "nearest", Texture::FILTER_NEAREST }, +}; + +StringMap Texture::filterModes(Texture::filterModeEntries, sizeof(Texture::filterModeEntries)); + +StringMap::Entry Texture::wrapModeEntries[] = +{ + { "clamp", Texture::WRAP_CLAMP }, + { "repeat", Texture::WRAP_REPEAT }, +}; + +StringMap Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries)); + + +} // graphics +} // love diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Texture.h similarity index 57% rename from src/modules/graphics/Image.h rename to src/modules/graphics/Texture.h index e2c49116d..e72e5cefe 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Texture.h @@ -18,35 +18,40 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_GRAPHICS_IMAGE_H -#define LOVE_GRAPHICS_IMAGE_H +#ifndef LOVE_GRAPHICS_TEXTURE_H +#define LOVE_GRAPHICS_TEXTURE_H // LOVE -#include "graphics/Volatile.h" -#include "graphics/DrawQable.h" #include "common/StringMap.h" +#include "common/math.h" +#include "Drawable.h" +#include "Quad.h" namespace love { namespace graphics { -class Image : public DrawQable, public Volatile +/** + * Base class for 2D textures. All textures can be drawn with Quads, have a + * width and height, and have filter and wrap modes. + **/ +class Texture : public Drawable { public: enum WrapMode { - WRAP_CLAMP = 1, + WRAP_CLAMP, WRAP_REPEAT, WRAP_MAX_ENUM }; enum FilterMode { - FILTER_LINEAR = 1, - FILTER_NEAREST, FILTER_NONE, + FILTER_LINEAR, + FILTER_NEAREST, FILTER_MAX_ENUM }; @@ -66,17 +71,56 @@ public: WrapMode t; }; - virtual ~Image(); - + Texture(); + virtual ~Texture(); + + /** + * Draws the texture using the specified transformation with a Quad applied. + * + * @param quad The Quad object to use to draw the object. + * @param x The position of the object along the x-axis. + * @param y The position of the object along the y-axis. + * @param angle The angle of the object (in radians). + * @param sx The scale factor along the x-axis. + * @param sy The scale factor along the y-axis. + * @param ox The origin offset along the x-axis. + * @param oy The origin offset along the y-axis. + * @param kx Shear along the x-axis. + * @param ky Shear along the y-axis. + **/ + virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const = 0; + + virtual int getWidth() const; + virtual int getHeight() const; + + virtual void setFilter(const Filter &f) = 0; + virtual const Filter &getFilter() const; + + virtual void setWrap(const Wrap &w) = 0; + virtual const Wrap &getWrap() const; + + virtual const Vertex *getVertices() const; + // The default filter. static void setDefaultFilter(const Filter &f); static const Filter &getDefaultFilter(); static bool getConstant(const char *in, FilterMode &out); static bool getConstant(FilterMode in, const char *&out); + static bool getConstant(const char *in, WrapMode &out); static bool getConstant(WrapMode in, const char *&out); +protected: + + int width; + int height; + + Filter filter; + Wrap wrap; + + Vertex vertices[4]; + private: // The default texture filter. @@ -84,12 +128,13 @@ private: static StringMap::Entry filterModeEntries[]; static StringMap filterModes; + static StringMap::Entry wrapModeEntries[]; static StringMap wrapModes; -}; // Image +}; // Texture } // graphics } // love -#endif // LOVE_GRAPHICS_IMAGE_H +#endif // LOVE_GRAPHICS_TEXTURE_H diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 324e39fdc..df41bd30f 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -115,7 +115,8 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glGenTextures(1, &img); gl.bindTexture(img); - gl.setTextureFilter(Image::getDefaultFilter()); + Texture::Filter filter = Texture::getDefaultFilter(); + gl.setTextureFilter(filter); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, format, NULL); @@ -183,7 +184,7 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy for (size_t i = 0; i < canvases.size(); i++) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 + i, - GL_TEXTURE_2D, canvases[i]->getTextureName(), 0); + GL_TEXTURE_2D, canvases[i]->getGLTexture(), 0); drawbuffers.push_back(GL_COLOR_ATTACHMENT1 + i); } @@ -224,7 +225,8 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy glGenTextures(1, &img); gl.bindTexture(img); - gl.setTextureFilter(Image::getDefaultFilter()); + Texture::Filter filter = Texture::getDefaultFilter(); + gl.setTextureFilter(filter); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, format, NULL); @@ -292,7 +294,7 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy for (size_t i = 0; i < canvases.size(); i++) { glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT + i, - GL_TEXTURE_2D, canvases[i]->getTextureName(), 0); + GL_TEXTURE_2D, canvases[i]->getGLTexture(), 0); drawbuffers.push_back(GL_COLOR_ATTACHMENT1_EXT + i); } @@ -364,37 +366,36 @@ static int maxFBOColorAttachments = 0; static int maxDrawBuffers = 0; Canvas::Canvas(int width, int height, TextureType texture_type) - : width(width) - , height(height) - , fbo(0) + : fbo(0) , depth_stencil(0) , img(0) , texture_type(texture_type) { + this->width = width; + this->height = height; + float w = static_cast(width); float h = static_cast(height); // world coordinates vertices[0].x = 0; - vertices[0].y = h; - vertices[1].x = w; + vertices[0].y = 0; + vertices[1].x = 0; vertices[1].y = h; vertices[2].x = w; - vertices[2].y = 0; - vertices[3].x = 0; + vertices[2].y = h; + vertices[3].x = w; vertices[3].y = 0; // texture coordinates vertices[0].s = 0; vertices[0].t = 0; - vertices[1].s = 1; - vertices[1].t = 0; + vertices[1].s = 0; + vertices[1].t = 1; vertices[2].s = 1; vertices[2].t = 1; - vertices[3].s = 0; - vertices[3].t = 1; - - settings.filter = Image::getDefaultFilter(); + vertices[3].s = 1; + vertices[3].t = 0; getStrategy(); @@ -410,36 +411,100 @@ Canvas::~Canvas() unloadVolatile(); } -bool Canvas::isSupported() +bool Canvas::loadVolatile() { - getStrategy(); - return (strategy != &strategyNone); -} + fbo = depth_stencil = img = 0; -bool Canvas::isHDRSupported() -{ - return GLEE_VERSION_3_0 || (isSupported() && GLEE_ARB_texture_float); -} - -bool Canvas::isMultiCanvasSupported() -{ - if (!(isSupported() && (GLEE_VERSION_2_0 || GLEE_ARB_draw_buffers))) - return false; - - if (maxFBOColorAttachments == 0 || maxDrawBuffers == 0) + // glTexImage2D is guaranteed to error in this case. + if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize()) { - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxFBOColorAttachments); - glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); + status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + return false; } - // system must support at least 4 simultanious active canvases - return maxFBOColorAttachments >= 4 && maxDrawBuffers >= 4; + status = strategy->createFBO(fbo, img, width, height, texture_type); + if (status != GL_FRAMEBUFFER_COMPLETE) + return false; + + setFilter(filter); + setWrap(wrap); + clear(Color(0, 0, 0, 0)); + return true; } -void Canvas::bindDefaultCanvas() +void Canvas::unloadVolatile() { - if (current != NULL) - current->stopGrab(); + strategy->deleteFBO(fbo, depth_stencil, img); + fbo = depth_stencil = img = 0; + + for (size_t i = 0; i < attachedCanvases.size(); i++) + attachedCanvases[i]->release(); + + attachedCanvases.clear(); +} + +void Canvas::drawv(const Matrix &t, const Vertex *v) const +{ + glPushMatrix(); + + glMultMatrixf((const GLfloat *)t.getElements()); + + gl.bindTexture(img); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].x); + glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].s); + + gl.prepareDraw(); + glDrawArrays(GL_QUADS, 0, 4); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + glPopMatrix(); +} + +void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const +{ + static Matrix t; + t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); + + drawv(t, vertices); +} + +void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const +{ + static Matrix t; + t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); + + const Vertex *v = quad->getVertices(); + drawv(t, v); +} + +void Canvas::setFilter(const Texture::Filter &f) +{ + filter = f; + gl.bindTexture(img); + gl.setTextureFilter(filter); +} + +void Canvas::setWrap(const Texture::Wrap &w) +{ + wrap = w; + gl.bindTexture(img); + gl.setTextureWrap(wrap); +} + +GLuint Canvas::getGLTexture() const +{ + return img; +} + +void Canvas::predraw() const +{ + gl.bindTexture(img); } void Canvas::setupGrab() @@ -463,7 +528,7 @@ void Canvas::setupGrab() glLoadIdentity(); // Set up orthographic view (no depth) - glOrtho(0.0, width, height, 0.0, -1.0, 1.0); + glOrtho(0.0, width, 0.0, height, -1.0, 1.0); // Switch back to modelview matrix glMatrixMode(GL_MODELVIEW); @@ -545,8 +610,10 @@ void Canvas::stopGrab() glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); + + current = nullptr; + gl.setViewport(systemViewport); - current = NULL; } void Canvas::clear(Color c) @@ -558,7 +625,7 @@ void Canvas::clear(Color c) if (current != this) { - if (current != NULL) + if (current != nullptr) previous = current->fbo; strategy->bindFBO(fbo); @@ -601,30 +668,6 @@ void Canvas::clear(Color c) strategy->bindFBO(previous); } -void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const -{ - static Matrix t; - t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); - - drawv(t, vertices); -} - -void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const -{ - static Matrix t; - t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); - - const Vertex *v = quad->getVertices(); - - // flip texture coordinates vertically. - Vertex w[4]; - memcpy(w, v, sizeof(Vertex) * 4); - for (size_t i = 0; i < 4; i++) - w[i].t = 1.0f - w[i].t; - - drawv(t, w); -} - bool Canvas::checkCreateStencil() { // Do nothing if we've already created the stencil buffer. @@ -649,7 +692,6 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image) int row = 4 * width; int size = row * height; GLubyte *pixels = new GLubyte[size]; - GLubyte *flipped = new GLubyte[size]; strategy->bindFBO(fbo); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); @@ -658,15 +700,8 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image) else strategy->bindFBO(0); - GLubyte *src = pixels, *dst = flipped + size - row; - for (int i = 0; i < height; ++i, dst -= row, src += row) - memcpy(dst, src, row); - - love::image::ImageData *img = image->newImageData(width, height, (void *)flipped, true); - - // The new ImageData now owns the flipped data, so we don't delete it here. - delete[] pixels; - + // The new ImageData now owns the pixel data, so we don't delete it here. + love::image::ImageData *img = image->newImageData(width, height, (void *)pixels, true); return img; } @@ -683,98 +718,36 @@ void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y) strategy->bindFBO(0); } -const std::vector &Canvas::getAttachedCanvases() const +bool Canvas::isSupported() { - return attachedCanvases; + getStrategy(); + return (strategy != &strategyNone); } -void Canvas::setFilter(const Image::Filter &f) +bool Canvas::isHDRSupported() { - settings.filter = f; - gl.bindTexture(img); - settings.filter.anisotropy = gl.setTextureFilter(f); + return GLEE_VERSION_3_0 || (isSupported() && GLEE_ARB_texture_float); } -Image::Filter Canvas::getFilter() const +bool Canvas::isMultiCanvasSupported() { - gl.bindTexture(img); - return gl.getTextureFilter(); -} - -void Canvas::setWrap(const Image::Wrap &w) -{ - settings.wrap = w; - gl.bindTexture(img); - gl.setTextureWrap(w); -} - -Image::Wrap Canvas::getWrap() const -{ - return settings.wrap; -} - -bool Canvas::loadVolatile() -{ - fbo = depth_stencil = img = 0; - - // glTexImage2D is guaranteed to error in this case. - if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize()) - { - status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + if (!(isSupported() && (GLEE_VERSION_2_0 || GLEE_ARB_draw_buffers))) return false; + + if (maxFBOColorAttachments == 0 || maxDrawBuffers == 0) + { + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxFBOColorAttachments); + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); } - status = strategy->createFBO(fbo, img, width, height, texture_type); - if (status != GL_FRAMEBUFFER_COMPLETE) - return false; - - setFilter(settings.filter); - setWrap(settings.wrap); - clear(Color(0, 0, 0, 0)); - return true; + // system must support at least 4 simultanious active canvases + return maxFBOColorAttachments >= 4 && maxDrawBuffers >= 4; } -void Canvas::unloadVolatile() +void Canvas::bindDefaultCanvas() { - strategy->deleteFBO(fbo, depth_stencil, img); - fbo = depth_stencil = img = 0; - - for (size_t i = 0; i < attachedCanvases.size(); i++) - attachedCanvases[i]->release(); - - attachedCanvases.clear(); -} - -int Canvas::getWidth() -{ - return width; -} - -int Canvas::getHeight() -{ - return height; -} - -void Canvas::drawv(const Matrix &t, const Vertex *v) const -{ - glPushMatrix(); - - glMultMatrixf((const GLfloat *)t.getElements()); - - gl.bindTexture(img); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].x); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].s); - - glDrawArrays(GL_QUADS, 0, 4); - - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - - glPopMatrix(); + if (current != nullptr) + current->stopGrab(); } bool Canvas::getConstant(const char *in, Canvas::TextureType &out) diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 7b7a7f12d..f9de4e546 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -21,14 +21,11 @@ #ifndef LOVE_GRAPHICS_OPENGL_CANVAS_H #define LOVE_GRAPHICS_OPENGL_CANVAS_H -#include "graphics/DrawQable.h" -#include "graphics/Volatile.h" -#include "graphics/Image.h" #include "graphics/Color.h" #include "image/Image.h" #include "image/ImageData.h" -#include "common/math.h" #include "common/Matrix.h" +#include "Texture.h" #include "OpenGL.h" namespace love @@ -38,7 +35,7 @@ namespace graphics namespace opengl { -class Canvas : public DrawQable, public Volatile +class Canvas : public Texture { public: @@ -52,6 +49,20 @@ public: Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL); virtual ~Canvas(); + // Implements Volatile. + virtual bool loadVolatile(); + virtual void unloadVolatile(); + + // Implements Drawable. + virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; + + // Implements Texture. + virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; + virtual void setFilter(const Texture::Filter &f); + virtual void setWrap(const Texture::Wrap &w); + virtual GLuint getGLTexture() const; + virtual void predraw() const; + /** * @param canvases A list of other canvases to temporarily attach to this one, * to allow drawing to multiple canvases at once. @@ -62,13 +73,6 @@ public: void clear(Color c); - virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; - - /** - * @copydoc DrawQable::drawq() - **/ - void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; - /** * Create and attach a stencil buffer to this Canvas' framebuffer, if necessary. **/ @@ -78,16 +82,10 @@ public: void getPixel(unsigned char* pixel_rgba, int x, int y); - const std::vector &getAttachedCanvases() const; - - void setFilter(const Image::Filter &f); - Image::Filter getFilter() const; - - void setWrap(const Image::Wrap &w); - Image::Wrap getWrap() const; - - int getWidth(); - int getHeight(); + inline const std::vector &getAttachedCanvases() const + { + return attachedCanvases; + } inline GLenum getStatus() const { @@ -99,9 +97,6 @@ public: return texture_type; } - bool loadVolatile(); - void unloadVolatile(); - static bool isSupported(); static bool isHDRSupported(); static bool isMultiCanvasSupported(); @@ -115,33 +110,16 @@ public: // The viewport dimensions of the system (default) framebuffer. static OpenGL::Viewport systemViewport; - GLuint getTextureName() const - { - return img; - } - private: - friend class Shader; - - GLsizei width; - GLsizei height; GLuint fbo; GLuint depth_stencil; GLuint img; TextureType texture_type; - Vertex vertices[4]; - GLenum status; - struct - { - Image::Filter filter; - Image::Wrap wrap; - } settings; - std::vector attachedCanvases; void setupGrab(); diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index eeb2b2c38..f978ec6d7 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -20,7 +20,6 @@ #include "common/config.h" #include "Font.h" #include "font/GlyphData.h" -#include "Image.h" #include "libraries/utf8/utf8.h" @@ -41,14 +40,14 @@ namespace opengl const int Font::TEXTURE_WIDTHS[] = {128, 256, 256, 512, 512, 1024, 1024}; const int Font::TEXTURE_HEIGHTS[] = {128, 128, 256, 256, 512, 512, 1024}; -Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) +Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter) : rasterizer(r) , height(r->getHeight()) , lineHeight(1) , mSpacing(1) , filter(filter) { - this->filter.mipmap = Image::FILTER_NONE; + this->filter.mipmap = Texture::FILTER_NONE; // Try to find the best texture size match for the font size. default to the // largest texture size if no rough match is found. @@ -350,6 +349,8 @@ void Font::print(const std::string &text, float x, float y, float extra_spacing, glVertexPointer(2, GL_FLOAT, sizeof(GlyphVertex), (GLvoid *)&glyphverts[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(GlyphVertex), (GLvoid *)&glyphverts[0].s); + gl.prepareDraw(); + // We need to draw a new vertex array for every section of the string which // uses a different texture than the previous section. std::vector::const_iterator it; @@ -494,18 +495,18 @@ float Font::getSpacing() const return mSpacing; } -void Font::setFilter(const Image::Filter &f) +void Font::setFilter(const Texture::Filter &f) { filter = f; for (auto it = textures.begin(); it != textures.end(); ++it) { gl.bindTexture(*it); - filter.anisotropy = gl.setTextureFilter(f); + gl.setTextureFilter(filter); } } -const Image::Filter &Font::getFilter() +const Texture::Filter &Font::getFilter() { return filter; } diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 5610c42ee..2679ff1fb 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -29,7 +29,8 @@ // LOVE #include "common/Object.h" #include "font/Rasterizer.h" -#include "graphics/Image.h" +#include "graphics/Texture.h" +#include "graphics/Volatile.h" #include "OpenGL.h" @@ -44,7 +45,7 @@ class Font : public Object, public Volatile { public: - Font(love::font::Rasterizer *r, const Image::Filter &filter = Image::getDefaultFilter()); + Font(love::font::Rasterizer *r, const Texture::Filter &filter = Texture::getDefaultFilter()); virtual ~Font(); @@ -122,8 +123,8 @@ public: **/ float getSpacing() const; - void setFilter(const Image::Filter &f); - const Image::Filter &getFilter(); + void setFilter(const Texture::Filter &f); + const Texture::Filter &getFilter(); // Implements Volatile. bool loadVolatile(); @@ -199,7 +200,7 @@ private: std::map glyphs; FontType type; - Image::Filter filter; + Texture::Filter filter; static const int NUM_TEXTURE_SIZES = 7; static const int TEXTURE_WIDTHS[NUM_TEXTURE_SIZES]; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 64854fb5b..651142c40 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -327,7 +327,11 @@ Image *Graphics::newImage(love::image::ImageData *data) { // Create the image. Image *image = new Image(data); - bool success; + + if (!isCreated()) + return image; + + bool success = false; try { success = image->load(); @@ -350,7 +354,11 @@ Image *Graphics::newImage(love::image::CompressedData *cdata) { // Create the image. Image *image = new Image(cdata); - bool success; + + if (!isCreated()) + return image; + + bool success = false; try { success = image->load(); @@ -374,19 +382,19 @@ Quad *Graphics::newQuad(Quad::Viewport v, float sw, float sh) return new Quad(v, sw, sh); } -Font *Graphics::newFont(love::font::Rasterizer *r, const Image::Filter &filter) +Font *Graphics::newFont(love::font::Rasterizer *r, const Texture::Filter &filter) { return new Font(r, filter); } -SpriteBatch *Graphics::newSpriteBatch(Image *image, int size, int usage) +SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, int usage) { - return new SpriteBatch(image, size, usage); + return new SpriteBatch(texture, size, usage); } -ParticleSystem *Graphics::newParticleSystem(Image *image, int size) +ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size) { - return new ParticleSystem(image, size); + return new ParticleSystem(texture, size); } Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type) @@ -629,23 +637,23 @@ Graphics::BlendMode Graphics::getBlendMode() const throw Exception("Unknown blend mode"); } -void Graphics::setDefaultFilter(const Image::Filter &f) +void Graphics::setDefaultFilter(const Texture::Filter &f) { - Image::setDefaultFilter(f); + Texture::setDefaultFilter(f); } -const Image::Filter &Graphics::getDefaultFilter() const +const Texture::Filter &Graphics::getDefaultFilter() const { - return Image::getDefaultFilter(); + return Texture::getDefaultFilter(); } -void Graphics::setDefaultMipmapFilter(Image::FilterMode filter, float sharpness) +void Graphics::setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness) { Image::setDefaultMipmapFilter(filter); Image::setDefaultMipmapSharpness(sharpness); } -void Graphics::getDefaultMipmapFilter(Image::FilterMode *filter, float *sharpness) const +void Graphics::getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const { *filter = Image::getDefaultMipmapFilter(); *sharpness = Image::getDefaultMipmapSharpness(); @@ -718,13 +726,13 @@ int Graphics::getMaxPointSize() const void Graphics::print(const std::string &str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky) { - if (currentFont != 0) + if (currentFont != nullptr) currentFont->print(str, x, y, 0.0, angle, sx, sy, ox, oy, kx, ky); } void Graphics::printf(const std::string &str, float x, float y, float wrap, AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { - if (currentFont == 0) + if (currentFont == nullptr) return; if (wrap < 0.0f) @@ -797,6 +805,7 @@ void Graphics::printf(const std::string &str, float x, float y, float wrap, Alig void Graphics::point(float x, float y) { + gl.prepareDraw(); gl.bindTexture(0); glBegin(GL_POINTS); glVertex2f(x, y); @@ -890,6 +899,7 @@ void Graphics::arc(DrawMode mode, float x, float y, float radius, float angle1, } else { + gl.prepareDraw(); gl.bindTexture(0); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *) coords); @@ -913,6 +923,7 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count) } else { + gl.prepareDraw(); gl.bindTexture(0); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *)coords); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index c3bb14383..d828ee302 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -203,11 +203,11 @@ public: /** * Creates a Font object. **/ - Font *newFont(love::font::Rasterizer *data, const Image::Filter &filter = Image::Filter()); + Font *newFont(love::font::Rasterizer *data, const Texture::Filter &filter = Texture::getDefaultFilter()); - SpriteBatch *newSpriteBatch(Image *image, int size, int usage); + SpriteBatch *newSpriteBatch(Texture *texture, int size, int usage); - ParticleSystem *newParticleSystem(Image *image, int size); + ParticleSystem *newParticleSystem(Texture *texture, int size); Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL); @@ -270,18 +270,18 @@ public: /** * Sets the default filter for images, canvases, and fonts. **/ - void setDefaultFilter(const Image::Filter &f); + void setDefaultFilter(const Texture::Filter &f); /** * Gets the default filter for images, canvases, and fonts. **/ - const Image::Filter &getDefaultFilter() const; + const Texture::Filter &getDefaultFilter() const; /** * Default Image mipmap filter mode and sharpness values. **/ - void setDefaultMipmapFilter(Image::FilterMode filter, float sharpness); - void getDefaultMipmapFilter(Image::FilterMode *filter, float *sharpness) const; + void setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness); + void getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const; /** * Sets the line width. diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 9ce6bf165..756d3ae34 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -33,14 +33,12 @@ namespace opengl float Image::maxMipmapSharpness = 0.0f; -Image::FilterMode Image::defaultMipmapFilter = Image::FILTER_NONE; +Texture::FilterMode Image::defaultMipmapFilter = Texture::FILTER_NONE; float Image::defaultMipmapSharpness = 0.0f; Image::Image(love::image::ImageData *data) : data(data) - , cdata(0) - , width(data->getWidth()) - , height(data->getHeight()) + , cdata(nullptr) , paddedWidth(width) , paddedHeight(height) , texture(0) @@ -49,15 +47,16 @@ Image::Image(love::image::ImageData *data) , compressed(false) , usingDefaultTexture(false) { + width = data->getWidth(); + height = data->getHeight(); + data->retain(); preload(); } Image::Image(love::image::CompressedData *cdata) - : data(0) + : data(nullptr) , cdata(cdata) - , width(cdata->getWidth(0)) - , height(cdata->getHeight(0)) , paddedWidth(width) , paddedHeight(height) , texture(0) @@ -66,34 +65,22 @@ Image::Image(love::image::CompressedData *cdata) , compressed(true) , usingDefaultTexture(false) { + width = cdata->getWidth(0); + height = cdata->getHeight(0); + cdata->retain(); preload(); } Image::~Image() { - if (data != 0) + if (data != nullptr) data->release(); - if (cdata != 0) + if (cdata != nullptr) cdata->release(); unload(); } -int Image::getWidth() const -{ - return width; -} - -int Image::getHeight() const -{ - return height; -} - -const Vertex *Image::getVertices() const -{ - return vertices; -} - love::image::ImageData *Image::getImageData() const { return data; @@ -144,6 +131,11 @@ void Image::postdraw() const } } +GLuint Image::getGLTexture() const +{ + return texture; +} + void Image::uploadCompressedMipmaps() { if (!isCompressed() || !cdata || !hasCompressedTextureSupport(cdata->getFormat())) @@ -246,7 +238,7 @@ void Image::checkMipmapsCreated() mipmapsCreated = true; } -void Image::setFilter(const Image::Filter &f) +void Image::setFilter(const Texture::Filter &f) { filter = f; @@ -258,16 +250,11 @@ void Image::setFilter(const Image::Filter &f) } bind(); - filter.anisotropy = gl.setTextureFilter(filter); + gl.setTextureFilter(filter); checkMipmapsCreated(); } -const Image::Filter &Image::getFilter() const -{ - return filter; -} - -void Image::setWrap(const Image::Wrap &w) +void Image::setWrap(const Texture::Wrap &w) { wrap = w; @@ -275,11 +262,6 @@ void Image::setWrap(const Image::Wrap &w) gl.setTextureWrap(w); } -const Image::Wrap &Image::getWrap() const -{ - return wrap; -} - void Image::setMipmapSharpness(float sharpness) { if (hasMipmapSharpnessSupport()) @@ -331,7 +313,6 @@ void Image::preload() vertices[3].s = 1; vertices[3].t = 0; - filter = getDefaultFilter(); filter.mipmap = defaultMipmapFilter; } @@ -544,6 +525,7 @@ void Image::drawv(const Matrix &t, const Vertex *v) const glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].s); + gl.prepareDraw(); glDrawArrays(GL_QUADS, 0, 4); glDisableClientState(GL_TEXTURE_COORD_ARRAY); @@ -564,12 +546,12 @@ float Image::getDefaultMipmapSharpness() return defaultMipmapSharpness; } -void Image::setDefaultMipmapFilter(Image::FilterMode f) +void Image::setDefaultMipmapFilter(Texture::FilterMode f) { defaultMipmapFilter = f; } -Image::FilterMode Image::getDefaultMipmapFilter() +Texture::FilterMode Image::getDefaultMipmapFilter() { return defaultMipmapFilter; } diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 7000df2ca..d9ea33ebf 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -28,7 +28,7 @@ #include "common/math.h" #include "image/ImageData.h" #include "image/CompressedData.h" -#include "graphics/Image.h" +#include "Texture.h" // OpenGL #include "OpenGL.h" @@ -46,7 +46,7 @@ namespace opengl * * @author Anders Ruud **/ -class Image : public love::graphics::Image +class Image : public Texture { public: @@ -70,11 +70,6 @@ public: **/ virtual ~Image(); - int getWidth() const; - int getHeight() const; - - const Vertex *getVertices() const; - love::image::ImageData *getImageData() const; love::image::CompressedData *getCompressedData() const; @@ -84,7 +79,7 @@ public: void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; /** - * @copydoc DrawQable::drawq() + * @copydoc Texture::drawq() **/ void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; @@ -93,20 +88,13 @@ public: * globally scales texture coordinates if the Image has NPOT dimensions and * NPOT isn't supported, etc. **/ - void predraw() const; - void postdraw() const; + virtual void predraw() const; + virtual void postdraw() const; - /** - * Sets the filter mode. - * @param f The filter mode. - **/ - void setFilter(const Image::Filter &f); + virtual GLuint getGLTexture() const; - const Image::Filter &getFilter() const; - - void setWrap(const Image::Wrap &w); - - const Image::Wrap &getWrap() const; + virtual void setFilter(const Texture::Filter &f); + virtual void setWrap(const Texture::Wrap &w); void setMipmapSharpness(float sharpness); float getMipmapSharpness() const; @@ -151,12 +139,6 @@ private: void drawv(const Matrix &t, const Vertex *v) const; - friend class Shader; - GLuint getTextureName() const - { - return texture; - } - // The ImageData from which the texture is created. May be null if // Compressed image data was used to create the texture. love::image::ImageData *data; @@ -165,18 +147,12 @@ private: // null if raw ImageData was used to create the texture. love::image::CompressedData *cdata; - // Width and height of the hardware texture. - int width, height; - // Real dimensions of the texture, if it was auto-padded to POT size. int paddedWidth, paddedHeight; // OpenGL texture identifier. GLuint texture; - // The source vertices of the image. - Vertex vertices[4]; - // Mipmap texture LOD bias (sharpness) value. float mipmapSharpness; @@ -190,12 +166,6 @@ private: // back to a default texture. bool usingDefaultTexture; - // The image's filter mode - Image::Filter filter; - - // The image's wrap mode - Image::Wrap wrap; - void preload(); void uploadTexturePadded(); diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index e0749a323..210e536e2 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -36,7 +36,7 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) , ibo(nullptr) , element_count(0) , draw_mode(mode) - , image(nullptr) + , texture(nullptr) , colors_enabled(false) , wireframe(false) { @@ -170,27 +170,27 @@ size_t Mesh::getVertexMapCount() const return element_count; } -void Mesh::setImage(Image *img) +void Mesh::setTexture(Texture *tex) { - img->retain(); + tex->retain(); - if (image) - image->release(); + if (texture) + texture->release(); - image = img; + texture = tex; } -void Mesh::setImage() +void Mesh::setTexture() { - if (image) - image->release(); + if (texture) + texture->release(); - image = nullptr; + texture = nullptr; } -Image *Mesh::getImage() const +Texture *Mesh::getTexture() const { - return image; + return texture; } void Mesh::setDrawMode(Mesh::DrawMode mode) @@ -232,8 +232,8 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo if (vertex_count == 0) return; - if (image) - image->predraw(); + if (texture) + texture->predraw(); else gl.bindTexture(0); @@ -266,6 +266,8 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo GLenum mode = getGLDrawMode(draw_mode); + gl.prepareDraw(); + if (ibo && element_count > 0) { VertexBuffer::Bind ibo_bind(*ibo); @@ -297,8 +299,8 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo glPopMatrix(); - if (image) - image->postdraw(); + if (texture) + texture->postdraw(); } GLenum Mesh::getGLDrawMode(Mesh::DrawMode mode) const diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 35cc21cbd..d20e42a31 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -26,7 +26,7 @@ #include "common/math.h" #include "common/StringMap.h" #include "graphics/Drawable.h" -#include "Image.h" +#include "Texture.h" #include "VertexBuffer.h" // C++ @@ -110,20 +110,20 @@ public: size_t getVertexMapCount() const; /** - * Sets the Image used when drawing the Mesh. + * Sets the texture used when drawing the Mesh. **/ - void setImage(Image *img); + void setTexture(Texture *texture); /** - * Disables any Image from being used when drawing the Mesh. + * Disables any texture from being used when drawing the Mesh. **/ - void setImage(); + void setTexture(); /** - * Gets the Image used when drawing the Mesh. May return null if no Image is - * set. + * Gets the texture used when drawing the Mesh. May return null if no + * texture is set. **/ - Image *getImage() const; + Texture *getTexture() const; /** * Sets the draw mode used when drawing the Mesh. @@ -167,7 +167,7 @@ private: DrawMode draw_mode; - Image *image; + Texture *texture; // Whether the per-vertex colors are used when drawing. bool colors_enabled; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index c1f5f2524..cbc5366b7 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -23,6 +23,7 @@ #include "OpenGL.h" #include "Shader.h" +#include "Canvas.h" #include "common/Exception.h" // C++ @@ -211,6 +212,14 @@ void OpenGL::createDefaultTexture() bindTexture(curtexture); } +void OpenGL::prepareDraw() +{ + // Make sure the active shader has the correct values for the built-in + // screen params uniform. + if (Shader::current) + Shader::current->checkSetScreenParams(); +} + void OpenGL::setColor(const Color &c) { glColor4ubv(&c.r); @@ -235,16 +244,13 @@ Color OpenGL::getClearColor() const void OpenGL::setViewport(const OpenGL::Viewport &v) { - Viewport oldViewport = state.viewport; - glViewport(v.x, v.y, v.w, v.h); state.viewport = v; // glScissor starts from the lower left, so we compensate when setting the // scissor. When the viewport is changed, we need to manually update the // scissor again. - if (v.h != oldViewport.h) - setScissor(state.scissor); + setScissor(state.scissor); } OpenGL::Viewport OpenGL::getViewport() const @@ -254,9 +260,15 @@ OpenGL::Viewport OpenGL::getViewport() const void OpenGL::setScissor(const OpenGL::Viewport &v) { - // We need to compensate for glScissor starting from the lower left of the - // viewport instead of the top left. - glScissor(v.x, state.viewport.h - (v.y + v.h), v.w, v.h); + if (Canvas::current) + glScissor(v.x, v.y, v.w, v.h); + else + { + // With no Canvas active, we need to compensate for glScissor starting + // from the lower left of the viewport instead of the top left. + glScissor(v.x, state.viewport.h - (v.y + v.h), v.w, v.h); + } + state.scissor = v; } @@ -275,7 +287,7 @@ void OpenGL::setTextureUnit(int textureunit) if (state.textureUnits.size() > 1) glActiveTexture(GL_TEXTURE0 + textureunit); else - throw love::Exception("Multitexturing not supported."); + throw love::Exception("Multitexturing is not supported."); } state.curTextureUnit = textureunit; @@ -322,26 +334,26 @@ void OpenGL::deleteTexture(GLuint texture) glDeleteTextures(1, &texture); } -float OpenGL::setTextureFilter(const graphics::Image::Filter &f) +float OpenGL::setTextureFilter(graphics::Texture::Filter &f) { GLint gmin, gmag; - if (f.mipmap == Image::FILTER_NONE) + if (f.mipmap == Texture::FILTER_NONE) { - if (f.min == Image::FILTER_NEAREST) + if (f.min == Texture::FILTER_NEAREST) gmin = GL_NEAREST; - else // f.min == Image::FILTER_LINEAR + else // f.min == Texture::FILTER_LINEAR gmin = GL_LINEAR; } else { - if (f.min == Image::FILTER_NEAREST && f.mipmap == Image::FILTER_NEAREST) + if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_NEAREST) gmin = GL_NEAREST_MIPMAP_NEAREST; - else if (f.min == Image::FILTER_NEAREST && f.mipmap == Image::FILTER_LINEAR) + else if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_LINEAR) gmin = GL_NEAREST_MIPMAP_LINEAR; - else if (f.min == Image::FILTER_LINEAR && f.mipmap == Image::FILTER_NEAREST) + else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_NEAREST) gmin = GL_LINEAR_MIPMAP_NEAREST; - else if (f.min == Image::FILTER_LINEAR && f.mipmap == Image::FILTER_LINEAR) + else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_LINEAR) gmin = GL_LINEAR_MIPMAP_LINEAR; else gmin = GL_LINEAR; @@ -350,10 +362,10 @@ float OpenGL::setTextureFilter(const graphics::Image::Filter &f) switch (f.mag) { - case Image::FILTER_NEAREST: + case Texture::FILTER_NEAREST: gmag = GL_NEAREST; break; - case Image::FILTER_LINEAR: + case Texture::FILTER_LINEAR: default: gmag = GL_LINEAR; break; @@ -362,60 +374,58 @@ float OpenGL::setTextureFilter(const graphics::Image::Filter &f) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag); - float anisotropy = 1.0f; - if (GLEE_EXT_texture_filter_anisotropic) { - anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); + f.anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, f.anisotropy); } - return anisotropy; + return f.anisotropy; } -graphics::Image::Filter OpenGL::getTextureFilter() +graphics::Texture::Filter OpenGL::getTextureFilter() { GLint gmin, gmag; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin); glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag); - Image::Filter f; + Texture::Filter f; switch (gmin) { case GL_NEAREST: - f.min = Image::FILTER_NEAREST; - f.mipmap = Image::FILTER_NONE; + f.min = Texture::FILTER_NEAREST; + f.mipmap = Texture::FILTER_NONE; break; case GL_NEAREST_MIPMAP_NEAREST: - f.min = f.mipmap = Image::FILTER_NEAREST; + f.min = f.mipmap = Texture::FILTER_NEAREST; break; case GL_NEAREST_MIPMAP_LINEAR: - f.min = Image::FILTER_NEAREST; - f.mipmap = Image::FILTER_LINEAR; + f.min = Texture::FILTER_NEAREST; + f.mipmap = Texture::FILTER_LINEAR; break; case GL_LINEAR_MIPMAP_NEAREST: - f.min = Image::FILTER_LINEAR; - f.mipmap = Image::FILTER_NEAREST; + f.min = Texture::FILTER_LINEAR; + f.mipmap = Texture::FILTER_NEAREST; break; case GL_LINEAR_MIPMAP_LINEAR: - f.min = f.mipmap = Image::FILTER_LINEAR; + f.min = f.mipmap = Texture::FILTER_LINEAR; break; case GL_LINEAR: default: - f.min = Image::FILTER_LINEAR; - f.mipmap = Image::FILTER_NONE; + f.min = Texture::FILTER_LINEAR; + f.mipmap = Texture::FILTER_NONE; break; } switch (gmag) { case GL_NEAREST: - f.mag = Image::FILTER_NEAREST; + f.mag = Texture::FILTER_NEAREST; break; case GL_LINEAR: default: - f.mag = Image::FILTER_LINEAR; + f.mag = Texture::FILTER_LINEAR; break; } @@ -425,16 +435,16 @@ graphics::Image::Filter OpenGL::getTextureFilter() return f; } -void OpenGL::setTextureWrap(const graphics::Image::Wrap &w) +void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w) { GLint gs, gt; switch (w.s) { - case Image::WRAP_CLAMP: + case Texture::WRAP_CLAMP: gs = GL_CLAMP_TO_EDGE; break; - case Image::WRAP_REPEAT: + case Texture::WRAP_REPEAT: default: gs = GL_REPEAT; break; @@ -442,10 +452,10 @@ void OpenGL::setTextureWrap(const graphics::Image::Wrap &w) switch (w.t) { - case Image::WRAP_CLAMP: + case Texture::WRAP_CLAMP: gt = GL_CLAMP_TO_EDGE; break; - case Image::WRAP_REPEAT: + case Texture::WRAP_REPEAT: default: gt = GL_REPEAT; break; @@ -455,34 +465,34 @@ void OpenGL::setTextureWrap(const graphics::Image::Wrap &w) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt); } -graphics::Image::Wrap OpenGL::getTextureWrap() +graphics::Texture::Wrap OpenGL::getTextureWrap() { GLint gs, gt; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs); glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, >); - Image::Wrap w; + Texture::Wrap w; switch (gs) { case GL_CLAMP_TO_EDGE: - w.s = Image::WRAP_CLAMP; + w.s = Texture::WRAP_CLAMP; break; case GL_REPEAT: default: - w.s = Image::WRAP_REPEAT; + w.s = Texture::WRAP_REPEAT; break; } switch (gt) { case GL_CLAMP_TO_EDGE: - w.t = Image::WRAP_CLAMP; + w.t = Texture::WRAP_CLAMP; break; case GL_REPEAT: default: - w.t = Image::WRAP_REPEAT; + w.t = Texture::WRAP_REPEAT; break; } diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 14033d1f8..d5e1dcad9 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -25,9 +25,9 @@ // LOVE #include "graphics/Color.h" -#include "graphics/Image.h" +#include "graphics/Texture.h" -// STL +// C++ #include // The last argument to AttribPointer takes a buffer offset casted to a pointer. @@ -93,6 +93,12 @@ public: **/ void deInitContext(); + /** + * Set up necessary state (LOVE-provided shader uniforms, etc.) for drawing. + * This *MUST* be called directly before OpenGL drawing functions. + **/ + void prepareDraw(); + /** * Sets the current constant color. **/ @@ -163,25 +169,25 @@ public: void deleteTexture(GLuint texture); /** - * Sets the image filter mode for the currently bound texture. + * Sets the texture filter mode for the currently bound texture. * Returns the actual amount of anisotropic filtering set. **/ - float setTextureFilter(const graphics::Image::Filter &f); + float setTextureFilter(graphics::Texture::Filter &f); /** - * Returns the image filter mode for the currently bound texture. + * Returns the texture filter mode for the currently bound texture. **/ - graphics::Image::Filter getTextureFilter(); + graphics::Texture::Filter getTextureFilter(); /** - * Sets the image wrap mode for the currently bound texture. + * Sets the texture wrap mode for the currently bound texture. **/ - void setTextureWrap(const graphics::Image::Wrap &w); + void setTextureWrap(const graphics::Texture::Wrap &w); /** - * Returns the image wrap mode for the currently bound texture. + * Returns the texture wrap mode for the currently bound texture. **/ - graphics::Image::Wrap getTextureWrap(); + graphics::Texture::Wrap getTextureWrap(); /** * Returns the maximum supported width or height of a texture. diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 5e3647edb..2df6d0913 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -58,13 +58,13 @@ float calculate_variation(float inner, float outer, float var) } // anonymous namespace -ParticleSystem::ParticleSystem(Image *image, uint32 size) +ParticleSystem::ParticleSystem(Texture *texture, uint32 size) : pMem(nullptr) , pFree(nullptr) , pHead(nullptr) , pTail(nullptr) , particleVerts(nullptr) - , image(image) + , texture(texture) , active(true) , insertMode(INSERT_MODE_TOP) , maxParticles(0) @@ -92,8 +92,8 @@ ParticleSystem::ParticleSystem(Image *image, uint32 size) , spinStart(0) , spinEnd(0) , spinVariation(0) - , offsetX(float(image->getWidth())*0.5f) - , offsetY(float(image->getHeight())*0.5f) + , offsetX(float(texture->getWidth())*0.5f) + , offsetY(float(texture->getHeight())*0.5f) { if (size == 0 || size > MAX_PARTICLES) throw love::Exception("Invalid ParticleSystem size."); @@ -101,7 +101,7 @@ ParticleSystem::ParticleSystem(Image *image, uint32 size) sizes.push_back(1.0f); colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); setBufferSize(size); - image->retain(); + texture->retain(); } ParticleSystem::ParticleSystem(const ParticleSystem &p) @@ -110,7 +110,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p) , pHead(nullptr) , pTail(nullptr) , particleVerts(nullptr) - , image(p.image) + , texture(p.texture) , active(p.active) , insertMode(p.insertMode) , maxParticles(p.maxParticles) @@ -147,14 +147,14 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p) { setBufferSize(maxParticles); - if (image != nullptr) - image->retain(); + if (texture != nullptr) + texture->retain(); } ParticleSystem::~ParticleSystem() { - if (image != nullptr) - image->release(); + if (texture != nullptr) + texture->release(); deleteBuffers(); } @@ -403,17 +403,19 @@ ParticleSystem::particle *ParticleSystem::removeParticle(particle *p) return pNext; } -void ParticleSystem::setImage(Image *image) +void ParticleSystem::setTexture(Texture *texture) { - Object::AutoRelease imagerelease(this->image); + Object::AutoRelease imagerelease(this->texture); - this->image = image; - this->image->retain(); + this->texture = texture; + + if (texture) + texture->retain(); } -Image *ParticleSystem::getImage() const +Texture *ParticleSystem::getTexture() const { - return image; + return texture; } void ParticleSystem::setInsertMode(InsertMode mode) @@ -777,7 +779,7 @@ bool ParticleSystem::isFull() const void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const { uint32 pCount = getCount(); - if (pCount == 0 || image == nullptr || pMem == nullptr || particleVerts == nullptr) + if (pCount == 0 || texture == nullptr || pMem == nullptr || particleVerts == nullptr) return; Color curcolor = gl.getColor(); @@ -788,7 +790,7 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); glMultMatrixf((const GLfloat *)t.getElements()); - const Vertex *imageVerts = image->getVertices(); + const Vertex *textureVerts = texture->getVertices(); Vertex *pVerts = particleVerts; particle *p = pHead; @@ -797,13 +799,13 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo { // particle vertices are image vertices transformed by particle information t.setTransformation(p->position[0], p->position[1], p->rotation, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f); - t.transform(pVerts, imageVerts, 4); + t.transform(pVerts, textureVerts, 4); // set the texture coordinate and color data for particle vertices for (int v = 0; v < 4; v++) { - pVerts[v].s = imageVerts[v].s; - pVerts[v].t = imageVerts[v].t; + pVerts[v].s = textureVerts[v].s; + pVerts[v].t = textureVerts[v].t; // particle colors are stored as floats (0-1) but vertex colors are stored as unsigned bytes (0-255) pVerts[v].r = (unsigned char) (p->color.r*255); @@ -816,7 +818,7 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo p = p->next; } - image->predraw(); + texture->predraw(); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); @@ -826,13 +828,14 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *) &particleVerts[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *) &particleVerts[0].s); + gl.prepareDraw(); glDrawArrays(GL_QUADS, 0, pCount * 4); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); - image->postdraw(); + texture->postdraw(); glPopMatrix(); diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 8e88a4a87..f8eadb7ad 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -27,7 +27,7 @@ #include "common/Vector.h" #include "graphics/Drawable.h" #include "graphics/Color.h" -#include "Image.h" +#include "Texture.h" // STL #include @@ -76,9 +76,9 @@ public: static const uint32 MAX_PARTICLES = LOVE_INT32_MAX / 4; /** - * Creates a particle system with the specified buffersize and image. + * Creates a particle system with the specified buffer size and texture. **/ - ParticleSystem(Image *image, uint32 buffer); + ParticleSystem(Texture *texture, uint32 buffer); ParticleSystem(const ParticleSystem &p); /** @@ -94,15 +94,15 @@ public: ParticleSystem *clone(); /** - * Sets the image used in the particle system. - * @param image The new image. + * Sets the texture used in the particle system. + * @param texture The new texture. **/ - void setImage(Image *image); + void setTexture(Texture *texture); /** - * Returns the image used when drawing the particle system. + * Returns the texture used when drawing the particle system. **/ - Image *getImage() const; + Texture *getTexture() const; /** * Clears the current buffer and allocates the appropriate amount of space for the buffer. @@ -531,8 +531,8 @@ protected: // array of transformed vertex data for all particles, for drawing Vertex *particleVerts; - // The image to be drawn. - Image *image; + // The texture to be drawn. + Texture *texture; // Whether the particle emitter is active. bool active; diff --git a/src/modules/graphics/opengl/Polyline.cpp b/src/modules/graphics/opengl/Polyline.cpp index a4b3ac934..9d6bb8265 100644 --- a/src/modules/graphics/opengl/Polyline.cpp +++ b/src/modules/graphics/opengl/Polyline.cpp @@ -327,6 +327,8 @@ Polyline::~Polyline() void Polyline::draw() { + gl.prepareDraw(); + // draw the core line gl.bindTexture(0); glEnableClientState(GL_VERTEX_ARRAY); diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index ccbd74420..3e65196c9 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -18,11 +18,13 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE #include "common/config.h" #include "Shader.h" -#include "Graphics.h" +#include "Canvas.h" +// C++ #include namespace love @@ -47,7 +49,7 @@ namespace ~TemporaryAttacher() { - if (prevShader != NULL) + if (prevShader != nullptr) prevShader->attach(); else curShader->detach(); @@ -59,28 +61,30 @@ namespace } // anonymous namespace -Shader *Shader::current = NULL; +Shader *Shader::current = nullptr; -GLint Shader::maxTextureUnits = 0; +GLint Shader::maxTexUnits = 0; std::vector Shader::textureCounters; Shader::Shader(const ShaderSources &sources) : shaderSources(sources) , program(0) + , builtinUniforms() + , lastCanvas((Canvas *) -1) { if (shaderSources.empty()) throw love::Exception("Cannot create shader: no source code!"); - if (maxTextureUnits <= 0) + if (maxTexUnits <= 0) { GLint maxtexunits; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtexunits); - maxTextureUnits = std::max(maxtexunits - 1, 0); + maxTexUnits = std::max(maxtexunits - 1, 0); } // initialize global texture id counters if needed - if (textureCounters.size() < (size_t) maxTextureUnits) - textureCounters.resize(maxTextureUnits, 0); + if (textureCounters.size() < (size_t) maxTexUnits) + textureCounters.resize(maxTexUnits, 0); // load shader source and create program object loadVolatile(); @@ -147,7 +151,7 @@ GLuint Shader::compileCode(ShaderType type, const std::string &code) glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen); GLchar *infolog = new GLchar[infologlen + 1]; - glGetShaderInfoLog(shaderid, infologlen, NULL, infolog); + glGetShaderInfoLog(shaderid, infologlen, nullptr, infolog); // Save any warnings for later querying. if (infologlen > 0) @@ -232,6 +236,11 @@ void Shader::mapActiveUniforms() u.name.erase(u.name.length() - 3); } + // If this is a built-in (LOVE-created) uniform, store the location. + BuiltinExtern builtin; + if (builtinNames.find(u.name.c_str(), builtin)) + builtinUniforms[int(builtin)] = u.location; + if (u.location != -1) uniforms[u.name] = u; } @@ -240,8 +249,12 @@ void Shader::mapActiveUniforms() bool Shader::loadVolatile() { // zero out active texture list - activeTextureUnits.clear(); - activeTextureUnits.insert(activeTextureUnits.begin(), maxTextureUnits, 0); + activeTexUnits.clear(); + activeTexUnits.insert(activeTexUnits.begin(), maxTexUnits, 0); + + // Built-in uniform locations default to -1 (nonexistant.) + for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++) + builtinUniforms[i] = -1; std::vector shaderids; @@ -263,7 +276,7 @@ bool Shader::loadVolatile() if (current == this) { // make sure glUseProgram gets called. - current = NULL; + current = nullptr; attach(); } @@ -282,19 +295,23 @@ void Shader::unloadVolatile() } // decrement global texture id counters for texture units which had textures bound from this shader - for (size_t i = 0; i < activeTextureUnits.size(); ++i) + for (size_t i = 0; i < activeTexUnits.size(); ++i) { - if (activeTextureUnits[i] > 0) + if (activeTexUnits[i] > 0) textureCounters[i] = std::max(textureCounters[i] - 1, 0); } // active texture list is probably invalid, clear it - activeTextureUnits.clear(); - activeTextureUnits.insert(activeTextureUnits.begin(), maxTextureUnits, 0); + activeTexUnits.clear(); + activeTexUnits.insert(activeTexUnits.begin(), maxTexUnits, 0); // same with uniform location list uniforms.clear(); + // And the locations of any built-in uniform variables. + for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++) + builtinUniforms[i] = -1; + shaderWarnings.clear(); } @@ -337,7 +354,7 @@ void Shader::attach(bool temporary) { if (current != this) { - if (current != NULL) + if (current != nullptr) current->release(); glUseProgram(program); @@ -350,10 +367,10 @@ void Shader::attach(bool temporary) { // make sure all sent textures are properly bound to their respective texture units // note: list potentially contains texture ids of deleted/invalid textures! - for (size_t i = 0; i < activeTextureUnits.size(); ++i) + for (size_t i = 0; i < activeTexUnits.size(); ++i) { - if (activeTextureUnits[i] > 0) - gl.bindTextureToUnit(activeTextureUnits[i], i + 1, false); + if (activeTexUnits[i] > 0) + gl.bindTextureToUnit(activeTexUnits[i], i + 1, false); } // We always want to use texture unit 0 for everyhing else. @@ -363,10 +380,10 @@ void Shader::attach(bool temporary) void Shader::detach() { - if (current != NULL) + if (current != nullptr) glUseProgram(0); - current = NULL; + current = nullptr; } const Shader::Uniform &Shader::getUniform(const std::string &name) const @@ -544,61 +561,53 @@ void Shader::sendMatrix(const std::string &name, int size, const GLfloat *m, int } } -void Shader::sendTexture(const std::string &name, GLuint texture) +void Shader::sendTexture(const std::string &name, Texture *texture) { + GLuint gltex = texture->getGLTexture(); + TemporaryAttacher attacher(this); - int textureunit = getTextureUnit(name); + int texunit = getTextureUnit(name); const Uniform &u = getUniform(name); checkSetUniformError(u, 1, 1, UNIFORM_SAMPLER); // bind texture to assigned texture unit and send uniform to shader program - gl.bindTextureToUnit(texture, textureunit, false); + gl.bindTextureToUnit(gltex, texunit, false); - glUniform1i(u.location, textureunit); + glUniform1i(u.location, texunit); // reset texture unit gl.setTextureUnit(0); // increment global shader texture id counter for this texture unit, if we haven't already - if (activeTextureUnits[textureunit-1] == 0) - ++textureCounters[textureunit-1]; + if (activeTexUnits[texunit-1] == 0) + ++textureCounters[texunit-1]; // store texture id so it can be re-bound to the proper texture unit later - activeTextureUnits[textureunit-1] = texture; + activeTexUnits[texunit-1] = gltex; + + retainObject(name, texture); } -void Shader::retainTexture(const std::string &name, Object *texture) +void Shader::retainObject(const std::string &name, Object *object) { auto it = boundRetainables.find(name); if (it != boundRetainables.end()) it->second->release(); - texture->retain(); - boundRetainables[name] = texture; -} - -void Shader::sendImage(const std::string &name, Image &image) -{ - sendTexture(name, image.getTextureName()); - retainTexture(name, &image); -} - -void Shader::sendCanvas(const std::string &name, Canvas &canvas) -{ - sendTexture(name, canvas.getTextureName()); - retainTexture(name, &canvas); + object->retain(); + boundRetainables[name] = object; } int Shader::getTextureUnit(const std::string &name) { - auto it = textureUnitPool.find(name); + auto it = texUnitPool.find(name); - if (it != textureUnitPool.end()) + if (it != texUnitPool.end()) return it->second; - int textureunit = 1; + int texunit = 1; // prefer texture units which are unused by all other shaders auto freeunit_it = std::find(textureCounters.begin(), textureCounters.end(), 0); @@ -606,33 +615,96 @@ int Shader::getTextureUnit(const std::string &name) if (freeunit_it != textureCounters.end()) { // we don't want to use unit 0 - textureunit = std::distance(textureCounters.begin(), freeunit_it) + 1; + texunit = std::distance(textureCounters.begin(), freeunit_it) + 1; } else { // no completely unused texture units exist, try to use next free slot in our own list - auto nextunit_it = std::find(activeTextureUnits.begin(), activeTextureUnits.end(), 0); + auto nextunit_it = std::find(activeTexUnits.begin(), activeTexUnits.end(), 0); - if (nextunit_it == activeTextureUnits.end()) + if (nextunit_it == activeTexUnits.end()) throw love::Exception("No more texture units available for shader."); // we don't want to use unit 0 - textureunit = std::distance(activeTextureUnits.begin(), nextunit_it) + 1; + texunit = std::distance(activeTexUnits.begin(), nextunit_it) + 1; } - textureUnitPool[name] = textureunit; - return textureunit; + texUnitPool[name] = texunit; + return texunit; +} + +bool Shader::hasBuiltinExtern(BuiltinExtern builtin) const +{ + return builtinUniforms[int(builtin)] != -1; +} + +bool Shader::sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *vec, int count) +{ + if (!hasBuiltinExtern(builtin)) + return false; + + GLint location = builtinUniforms[int(builtin)]; + + TemporaryAttacher attacher(this); + + switch (size) + { + case 1: + glUniform1fv(location, count, vec); + break; + case 2: + glUniform2fv(location, count, vec); + break; + case 3: + glUniform3fv(location, count, vec); + break; + case 4: + glUniform4fv(location, count, vec); + break; + default: + return false; + } + + return true; +} + +void Shader::checkSetScreenParams() +{ + if (lastCanvas == Canvas::current) + return; + + // In the shader, we do pixcoord.y = gl_FragCoord.y * params[0] + params[1]. + // This lets us flip pixcoord.y when needed, to be consistent (Canvases + // have flipped y-values for pixel coordinates.) + GLfloat params[] = {0.0f, 0.0f}; + + if (Canvas::current != nullptr) + { + // gl_FragCoord.y is flipped in Canvases, so we un-flip: + // pixcoord.y = gl_FragCoord.y * -1.0 + height. + params[0] = -1.0f; + params[1] = (float) Canvas::current->getHeight(); + } + else + { + // No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0. + params[0] = 1.0f; + params[1] = 0.0f; + } + + sendBuiltinFloat(BUILTIN_SCREEN_PARAMS, 2, params, 1); + lastCanvas = Canvas::current; } std::string Shader::getGLSLVersion() { - const char *tmp = 0; + const char *tmp = nullptr; // GL_SHADING_LANGUAGE_VERSION isn't available in OpenGL < 2.0. if (GLEE_VERSION_2_0 || GLEE_ARB_shading_language_100) tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); - if (tmp == 0) + if (tmp == nullptr) return "0.0"; // the version string always begins with a version number of the format @@ -658,6 +730,13 @@ StringMap::Entry Shader::typeNameEntr StringMap Shader::typeNames(Shader::typeNameEntries, sizeof(Shader::typeNameEntries)); +StringMap::Entry Shader::builtinNameEntries[] = +{ + {"love_ScreenParams", Shader::BUILTIN_SCREEN_PARAMS}, +}; + +StringMap Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries)); + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 3c93d5197..26b018d38 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -25,8 +25,7 @@ #include "common/Object.h" #include "common/StringMap.h" #include "OpenGL.h" -#include "Image.h" -#include "Canvas.h" +#include "Texture.h" // STL #include @@ -39,6 +38,9 @@ namespace graphics { namespace opengl { + +class Canvas; + // A GLSL shader class Shader : public Object, public Volatile { @@ -54,6 +56,13 @@ public: TYPE_MAX_ENUM }; + // Built-in extern (uniform) variables. + enum BuiltinExtern + { + BUILTIN_SCREEN_PARAMS, + BUILTIN_MAX_ENUM + }; + // Type for a list of shader source codes in the form of sources[shadertype] = code typedef std::map ShaderSources; @@ -120,18 +129,18 @@ public: void sendMatrix(const std::string &name, int size, const GLfloat *m, int count); /** - * Send an image to this Shader as a uniform. + * Send a texture to this Shader as a uniform. * * @param name The name of the uniform variable in the source code. **/ - void sendImage(const std::string &name, Image &image); + void sendTexture(const std::string &name, Texture *texture); /** - * Send a canvas to this Shader as a uniform. - * - * @param name The name of the uniform variable in the source code. + * Internal use only. **/ - void sendCanvas(const std::string &name, Canvas &canvas); + bool hasBuiltinExtern(BuiltinExtern builtin) const; + bool sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *m, int count); + void checkSetScreenParams(); static std::string getGLSLVersion(); static bool isSupported(); @@ -172,8 +181,7 @@ private: int getTextureUnit(const std::string &name); - void sendTexture(const std::string &name, GLuint texture); - void retainTexture(const std::string &name, Object *texture); + void retainObject(const std::string &name, Object *object); // Get any warnings or errors generated only by the shader program object. std::string getProgramWarnings() const; @@ -187,24 +195,34 @@ private: // volatile GLuint program; + // Location values for any built-in uniform variables. + GLint builtinUniforms[BUILTIN_MAX_ENUM]; + // Uniform location buffer map std::map uniforms; // Texture unit pool for setting images - std::map textureUnitPool; // textureUnitPool[name] = textureunit - std::vector activeTextureUnits; // activeTextureUnits[textureunit-1] = textureid + std::map texUnitPool; // texUnitPool[name] = textureunit + std::vector activeTexUnits; // activeTexUnits[textureunit-1] = textureid // Uniform name to retainable objects std::map boundRetainables; + // Pointer to the active Canvas when the screen params were last checked. + Canvas *lastCanvas; + // Max GPU texture units available for sent images - static GLint maxTextureUnits; + static GLint maxTexUnits; // Counts total number of textures bound to each texture unit in all shaders static std::vector textureCounters; static StringMap::Entry typeNameEntries[]; static StringMap typeNames; + + // Names for the built-in uniform variables. + static StringMap::Entry builtinNameEntries[]; + static StringMap builtinNames; }; } // opengl diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 0298cbbf0..34fae545a 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -25,8 +25,8 @@ #include "OpenGL.h" // LOVE -#include "Image.h" #include "VertexBuffer.h" +#include "Texture.h" // C++ #include @@ -41,8 +41,8 @@ namespace graphics namespace opengl { -SpriteBatch::SpriteBatch(Image *image, int size, int usage) - : image(image) +SpriteBatch::SpriteBatch(Texture *texture, int size, int usage) + : texture(texture) , size(size) , next(0) , color(0) @@ -87,12 +87,12 @@ SpriteBatch::SpriteBatch(Image *image, int size, int usage) throw love::Exception("Out of memory."); } - image->retain(); + texture->retain(); } SpriteBatch::~SpriteBatch() { - image->release(); + texture->release(); delete color; delete array_buf; @@ -106,7 +106,7 @@ int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, fl return -1; // Needed for colors. - memcpy(sprite, image->getVertices(), sizeof(Vertex)*4); + memcpy(sprite, texture->getVertices(), sizeof(Vertex) * 4); // Transform. static Matrix t; @@ -170,17 +170,17 @@ void SpriteBatch::unlock() array_buf->unmap(); } -void SpriteBatch::setImage(Image *newimage) +void SpriteBatch::setTexture(Texture *newtexture) { - Object::AutoRelease imagerelease(image); + Object::AutoRelease imagerelease(texture); - newimage->retain(); - image = newimage; + newtexture->retain(); + texture = newtexture; } -Image *SpriteBatch::getImage() +Texture *SpriteBatch::getTexture() { - return image; + return texture; } void SpriteBatch::setColor(const Color &color) @@ -279,7 +279,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); glMultMatrixf((const GLfloat *)t.getElements()); - image->predraw(); + texture->predraw(); VertexBuffer::Bind array_bind(*array_buf); VertexBuffer::Bind element_bind(*element_buf->getVertexBuffer()); @@ -299,6 +299,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), array_buf->getPointer(texel_offset)); + gl.prepareDraw(); glDrawElements(GL_TRIANGLES, element_buf->getIndexCount(next), element_buf->getType(), element_buf->getPointer(0)); glDisableClientState(GL_VERTEX_ARRAY); @@ -310,7 +311,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float gl.setColor(curcolor); } - image->postdraw(); + texture->postdraw(); glPopMatrix(); } diff --git a/src/modules/graphics/opengl/SpriteBatch.h b/src/modules/graphics/opengl/SpriteBatch.h index f3ac4fe5d..db72cef65 100644 --- a/src/modules/graphics/opengl/SpriteBatch.h +++ b/src/modules/graphics/opengl/SpriteBatch.h @@ -42,7 +42,7 @@ namespace opengl { // Forward declarations. -class Image; +class Texture; class VertexBuffer; class VertexIndex; @@ -58,7 +58,7 @@ public: USAGE_MAX_ENUM }; - SpriteBatch(Image *image, int size, int usage); + SpriteBatch(Texture *texture, int size, int usage); virtual ~SpriteBatch(); int add(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index = -1); @@ -68,8 +68,8 @@ public: void *lock(); void unlock(); - void setImage(Image *newimage); - Image *getImage(); + void setTexture(Texture *newtexture); + Texture *getTexture(); /** * Set the current color for this SpriteBatch. The sprites added @@ -127,7 +127,7 @@ private: */ void setColorv(Vertex *v, const Color &color); - Image *image; + Texture *texture; // Max number of sprites in the batch. int size; diff --git a/src/modules/graphics/Drawable.cpp b/src/modules/graphics/opengl/Texture.h similarity index 58% rename from src/modules/graphics/Drawable.cpp rename to src/modules/graphics/opengl/Texture.h index 843e031d9..37162da1f 100644 --- a/src/modules/graphics/Drawable.cpp +++ b/src/modules/graphics/opengl/Texture.h @@ -18,16 +18,48 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include "Drawable.h" +#ifndef LOVE_GRAPHICS_OPENGL_TEXTURE_H +#define LOVE_GRAPHICS_OPENGL_TEXTURE_H + +// LOVE +#include "graphics/Texture.h" +#include "graphics/Volatile.h" +#include "OpenGL.h" namespace love { namespace graphics { - -Drawable::~Drawable() +namespace opengl { -} +class Texture : public love::graphics::Texture, public Volatile +{ +public: + + virtual ~Texture() {} + + /** + * Gets the OpenGL id for this texture. + **/ + virtual GLuint getGLTexture() const = 0; + + /** + * Any setup the texture might need to do before drawing, e.g. binding + * the OpenGL texture for use. + **/ + virtual void predraw() const {} + + /** + * Any cleanup the texture might need to do directly after drawing. + **/ + virtual void postdraw() const {} + + +}; // Texture + +} // opengl } // graphics } // love + +#endif // LOVE_GRAPHICS_OPENGL_TEXTURE_H diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index a53574ea6..413d583a4 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -18,7 +18,6 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include "Graphics.h" #include "wrap_Canvas.h" namespace love @@ -84,14 +83,14 @@ int w_Canvas_setFilter(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - Image::Filter f; + Texture::Filter f; const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Image::getConstant(minstr, f.min)) + if (!Texture::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); - if (!Image::getConstant(magstr, f.mag)) + if (!Texture::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); @@ -105,12 +104,12 @@ int w_Canvas_setFilter(lua_State *L) int w_Canvas_getFilter(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - const Image::Filter f = canvas->getFilter(); + const Texture::Filter f = canvas->getFilter(); const char *minstr; const char *magstr; - Image::getConstant(f.min, minstr); - Image::getConstant(f.mag, magstr); + Texture::getConstant(f.min, minstr); + Texture::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); @@ -123,14 +122,14 @@ int w_Canvas_setWrap(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - Image::Wrap w; + Texture::Wrap w; const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); - if (!Image::getConstant(sstr, w.s)) + if (!Texture::getConstant(sstr, w.s)) return luaL_error(L, "Invalid wrap mode: %s", sstr); - if (!Image::getConstant(tstr, w.t)) + if (!Texture::getConstant(tstr, w.t)) return luaL_error(L, "Invalid wrap mode, %s", tstr); canvas->setWrap(w); @@ -141,12 +140,12 @@ int w_Canvas_setWrap(lua_State *L) int w_Canvas_getWrap(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - const Image::Wrap w = canvas->getWrap(); + const Texture::Wrap w = canvas->getWrap(); const char *wrap_s; const char *wrap_t; - Image::getConstant(w.s, wrap_s); - Image::getConstant(w.t, wrap_t); + Texture::getConstant(w.s, wrap_s); + Texture::getConstant(w.t, wrap_t); lua_pushstring(L, wrap_s); lua_pushstring(L, wrap_t); diff --git a/src/modules/graphics/opengl/wrap_Font.cpp b/src/modules/graphics/opengl/wrap_Font.cpp index cee0c0339..7b9392ea3 100644 --- a/src/modules/graphics/opengl/wrap_Font.cpp +++ b/src/modules/graphics/opengl/wrap_Font.cpp @@ -84,14 +84,14 @@ int w_Font_getLineHeight(lua_State *L) int w_Font_setFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - Image::Filter f = t->getFilter(); + Texture::Filter f = t->getFilter(); const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Image::getConstant(minstr, f.min)) + if (!Texture::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); - if (!Image::getConstant(magstr, f.mag)) + if (!Texture::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); @@ -103,11 +103,11 @@ int w_Font_setFilter(lua_State *L) int w_Font_getFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - const Image::Filter f = t->getFilter(); + const Texture::Filter f = t->getFilter(); const char *minstr; const char *magstr; - Image::getConstant(f.min, minstr); - Image::getConstant(f.mag, magstr); + Texture::getConstant(f.min, minstr); + Texture::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); lua_pushnumber(L, f.anisotropy); diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 59f7bbb22..b064ce119 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -20,7 +20,7 @@ #include "wrap_Graphics.h" #include "OpenGL.h" -#include "graphics/DrawQable.h" +#include "graphics/Texture.h" #include "image/ImageData.h" #include "font/Rasterizer.h" @@ -34,7 +34,7 @@ namespace graphics namespace opengl { -static Graphics *instance = 0; +static Graphics *instance = nullptr; int w_reset(lua_State *) { @@ -237,7 +237,7 @@ int w_newFont(lua_State *L) int w_newImageFont(lua_State *L) { // filter for glyphs - Image::Filter filter = instance->getDefaultFilter(); + Texture::Filter filter = instance->getDefaultFilter(); // Convert to ImageData if necessary. if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T)) @@ -277,7 +277,7 @@ int w_newImageFont(lua_State *L) int w_newSpriteBatch(lua_State *L) { - Image *image = luax_checkimage(L, 1); + Texture *texture = luax_checktype(L, 1, "Texture", GRAPHICS_TEXTURE_T); int size = luaL_optint(L, 2, 1000); SpriteBatch::UsageHint usage = SpriteBatch::USAGE_DYNAMIC; if (lua_gettop(L) > 2) @@ -287,8 +287,8 @@ int w_newSpriteBatch(lua_State *L) return luaL_error(L, "Invalid SpriteBatch usage hint: %s", usagestr); } - SpriteBatch *t = 0; - EXCEPT_GUARD(t = instance->newSpriteBatch(image, size, usage);) + SpriteBatch *t = nullptr; + EXCEPT_GUARD(t = instance->newSpriteBatch(texture, size, usage);) luax_pushtype(L, "SpriteBatch", GRAPHICS_SPRITE_BATCH_T, t); return 1; @@ -296,13 +296,13 @@ int w_newSpriteBatch(lua_State *L) int w_newParticleSystem(lua_State *L) { - Image *image = luax_checkimage(L, 1); + Texture *texture = luax_checktype(L, 1, "Texture", GRAPHICS_TEXTURE_T); lua_Number size = luaL_optnumber(L, 2, 1000); ParticleSystem *t = 0; if (size < 1.0 || size > ParticleSystem::MAX_PARTICLES) return luaL_error(L, "Invalid ParticleSystem size"); - EXCEPT_GUARD(t = instance->newParticleSystem(image, int(size));) + EXCEPT_GUARD(t = instance->newParticleSystem(texture, int(size));) luax_pushtype(L, "ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_T, t); return 1; @@ -434,10 +434,10 @@ int w_newMesh(lua_State *L) // Check first argument: mandatory table of vertices. luaL_checktype(L, 1, LUA_TTABLE); - // Second argument: optional image. - Image *img = 0; + // Second argument: optional texture. + Texture *tex = nullptr; if (!lua_isnoneornil(L, 2)) - img = luax_checkimage(L, 2); + tex = luax_checktype(L, 2, "Texture", GRAPHICS_TEXTURE_T); // Third argument: optional draw mode. const char *str = 0; @@ -485,11 +485,11 @@ int w_newMesh(lua_State *L) vertices.push_back(v); } - Mesh *t = 0; + Mesh *t = nullptr; EXCEPT_GUARD(t = instance->newMesh(vertices, mode);) - if (img) - t->setImage(img); + if (tex) + t->setTexture(tex); t->setVertexColors(use_colors); @@ -646,20 +646,20 @@ int w_getBlendMode(lua_State *L) int w_setDefaultFilter(lua_State *L) { - Image::FilterMode min; - Image::FilterMode mag; + Texture::FilterMode min; + Texture::FilterMode mag; const char *minstr = luaL_checkstring(L, 1); const char *magstr = luaL_optstring(L, 2, minstr); - if (!Image::getConstant(minstr, min)) + if (!Texture::getConstant(minstr, min)) return luaL_error(L, "Invalid filter mode: %s", minstr); - if (!Image::getConstant(magstr, mag)) + if (!Texture::getConstant(magstr, mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); float anisotropy = (float) luaL_optnumber(L, 3, 1.0); - Image::Filter f; + Texture::Filter f; f.min = min; f.mag = mag; f.anisotropy = anisotropy; @@ -671,12 +671,12 @@ int w_setDefaultFilter(lua_State *L) int w_getDefaultFilter(lua_State *L) { - const Image::Filter &f = instance->getDefaultFilter(); + const Texture::Filter &f = instance->getDefaultFilter(); const char *minstr; const char *magstr; - if (!Image::getConstant(f.min, minstr)) + if (!Texture::getConstant(f.min, minstr)) return luaL_error(L, "Unknown minification filter mode"); - if (!Image::getConstant(f.mag, magstr)) + if (!Texture::getConstant(f.mag, magstr)) return luaL_error(L, "Unknown magnification filter mode"); lua_pushstring(L, minstr); lua_pushstring(L, magstr); @@ -686,11 +686,11 @@ int w_getDefaultFilter(lua_State *L) int w_setDefaultMipmapFilter(lua_State *L) { - Image::FilterMode filter = Image::FILTER_NONE; + Texture::FilterMode filter = Texture::FILTER_NONE; if (!lua_isnoneornil(L, 1)) { const char *str = luaL_checkstring(L, 1); - if (!Image::getConstant(str, filter)) + if (!Texture::getConstant(str, filter)) return luaL_error(L, "Invalid filter mode: %s", str); } @@ -703,13 +703,13 @@ int w_setDefaultMipmapFilter(lua_State *L) int w_getDefaultMipmapFilter(lua_State *L) { - Image::FilterMode filter; + Texture::FilterMode filter; float sharpness; instance->getDefaultMipmapFilter(&filter, &sharpness); const char *str; - if (Image::getConstant(filter, str)) + if (Texture::getConstant(filter, str)) lua_pushstring(L, str); else lua_pushnil(L); @@ -1004,14 +1004,14 @@ int w_getRendererInfo(lua_State *L) int w_draw(lua_State *L) { - Drawable *drawable = 0; - DrawQable *drawqable = 0; - Quad *quad = 0; + Drawable *drawable = nullptr; + Texture *texture = nullptr; + Quad *quad = nullptr; int startidx = 2; if (luax_istype(L, 2, GRAPHICS_QUAD_T)) { - drawqable = luax_checktype(L, 1, "DrawQable", GRAPHICS_DRAWQABLE_T); + texture = luax_checktype(L, 1, "Texture", GRAPHICS_TEXTURE_T); quad = luax_totype(L, 2, "Quad", GRAPHICS_QUAD_T); startidx = 3; } @@ -1035,8 +1035,8 @@ int w_draw(lua_State *L) float kx = (float) luaL_optnumber(L, startidx + 7, 0.0); float ky = (float) luaL_optnumber(L, startidx + 8, 0.0); - if (drawqable && quad) - drawqable->drawq(quad, x, y, a, sx, sy, ox, oy, kx, ky); + if (texture && quad) + texture->drawq(quad, x, y, a, sx, sy, ox, oy, kx, ky); else if (drawable) drawable->draw(x, y, a, sx, sy, ox, oy, kx, ky); diff --git a/src/modules/graphics/opengl/wrap_Image.cpp b/src/modules/graphics/opengl/wrap_Image.cpp index 76f360e53..77943c91e 100644 --- a/src/modules/graphics/opengl/wrap_Image.cpp +++ b/src/modules/graphics/opengl/wrap_Image.cpp @@ -58,14 +58,14 @@ int w_Image_getDimensions(lua_State *L) int w_Image_setFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - Image::Filter f = t->getFilter(); + Texture::Filter f = t->getFilter(); const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Image::getConstant(minstr, f.min)) + if (!Texture::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); - if (!Image::getConstant(magstr, f.mag)) + if (!Texture::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); @@ -77,11 +77,11 @@ int w_Image_setFilter(lua_State *L) int w_Image_getFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - const Image::Filter f = t->getFilter(); + const Texture::Filter f = t->getFilter(); const char *minstr; const char *magstr; - Image::getConstant(f.min, minstr); - Image::getConstant(f.mag, magstr); + Texture::getConstant(f.min, minstr); + Texture::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); lua_pushnumber(L, f.anisotropy); @@ -91,14 +91,14 @@ int w_Image_getFilter(lua_State *L) int w_Image_setMipmapFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - Image::Filter f = t->getFilter(); + Texture::Filter f = t->getFilter(); if (lua_isnoneornil(L, 2)) - f.mipmap = Image::FILTER_NONE; // mipmapping is disabled if no argument is given + f.mipmap = Texture::FILTER_NONE; // mipmapping is disabled if no argument is given else { const char *mipmapstr = luaL_checkstring(L, 2); - if (!Image::getConstant(mipmapstr, f.mipmap)) + if (!Texture::getConstant(mipmapstr, f.mipmap)) return luaL_error(L, "Invalid filter mode: %s", mipmapstr); } @@ -114,10 +114,10 @@ int w_Image_getMipmapFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - const Image::Filter &f = t->getFilter(); + const Texture::Filter &f = t->getFilter(); const char *mipmapstr; - if (Image::getConstant(f.mipmap, mipmapstr)) + if (Texture::getConstant(f.mipmap, mipmapstr)) lua_pushstring(L, mipmapstr); else lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled @@ -130,29 +130,28 @@ int w_Image_setWrap(lua_State *L) { Image *i = luax_checkimage(L, 1); - Image::Wrap w; + Texture::Wrap w; const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); - if (!Image::getConstant(sstr, w.s)) + if (!Texture::getConstant(sstr, w.s)) return luaL_error(L, "Invalid wrap mode: %s", sstr); - if (!Image::getConstant(tstr, w.t)) + if (!Texture::getConstant(tstr, w.t)) return luaL_error(L, "Invalid wrap mode, %s", tstr); i->setWrap(w); - return 0; } int w_Image_getWrap(lua_State *L) { Image *i = luax_checkimage(L, 1); - const Image::Wrap w = i->getWrap(); + const Texture::Wrap w = i->getWrap(); const char *sstr; const char *tstr; - Image::getConstant(w.s, sstr); - Image::getConstant(w.t, tstr); + Texture::getConstant(w.s, sstr); + Texture::getConstant(w.t, tstr); lua_pushstring(L, sstr); lua_pushstring(L, tstr); return 2; diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index c4399eb24..a20b4f489 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -20,7 +20,11 @@ // LOVE #include "wrap_Mesh.h" -#include "wrap_Image.h" +#include "Image.h" +#include "Canvas.h" + +// C++ +#include namespace love { @@ -231,31 +235,42 @@ int w_Mesh_getVertexMap(lua_State *L) return 1; } -int w_Mesh_setImage(lua_State *L) +int w_Mesh_setTexture(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); if (lua_isnoneornil(L, 2)) - t->setImage(); + t->setTexture(); else { - Image *img = luax_checkimage(L, 2); - t->setImage(img); + Texture *tex = luax_checktype(L, 2, "Texture", GRAPHICS_TEXTURE_T); + t->setTexture(tex); } return 0; } -int w_Mesh_getImage(lua_State *L) +int w_Mesh_getTexture(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); - Image *img = t->getImage(); + Texture *tex = t->getTexture(); - if (img == NULL) + if (tex == nullptr) return 0; - img->retain(); - luax_pushtype(L, "Image", GRAPHICS_IMAGE_T, img); + tex->retain(); + + // FIXME: big hack right here. + if (typeid(*tex) == typeid(Image)) + luax_pushtype(L, "Image", GRAPHICS_IMAGE_T, tex); + else if (typeid(*tex) == typeid(Canvas)) + luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, tex); + else + { + tex->release(); + return luaL_error(L, "Unable to determine texture type."); + } + return 1; } @@ -322,14 +337,19 @@ static const luaL_Reg functions[] = { "getVertexCount", w_Mesh_getVertexCount }, { "setVertexMap", w_Mesh_setVertexMap }, { "getVertexMap", w_Mesh_getVertexMap }, - { "setImage", w_Mesh_setImage }, - { "getImage", w_Mesh_getImage }, + { "setTexture", w_Mesh_setTexture }, + { "getTexture", w_Mesh_getTexture }, { "setDrawMode", w_Mesh_setDrawMode }, { "getDrawMode", w_Mesh_getDrawMode }, { "setVertexColors", w_Mesh_setVertexColors }, { "hasVertexColors", w_Mesh_hasVertexColors }, { "setWireframe", w_Mesh_setWireframe }, { "isWireframe", w_Mesh_isWireframe }, + + // Deprecated since 0.9.1. + { "setImage", w_Mesh_setTexture }, + { "getImage", w_Mesh_getTexture }, + { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Mesh.h b/src/modules/graphics/opengl/wrap_Mesh.h index e3d52ebc8..0433738d1 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.h +++ b/src/modules/graphics/opengl/wrap_Mesh.h @@ -41,8 +41,8 @@ int w_Mesh_getVertices(lua_State *L); int w_Mesh_getVertexCount(lua_State *L); int w_Mesh_setVertexMap(lua_State *L); int w_Mesh_getVertexMap(lua_State *L); -int w_Mesh_setImage(lua_State *L); -int w_Mesh_getImage(lua_State *L); +int w_Mesh_setTexture(lua_State *L); +int w_Mesh_getTexture(lua_State *L); int w_Mesh_setDrawMode(lua_State *L); int w_Mesh_getDrawMode(lua_State *L); int w_Mesh_setVertexColors(lua_State *L); diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 97c2e29cd..727e2deea 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -18,12 +18,19 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE #include "wrap_ParticleSystem.h" - #include "common/Vector.h" +#include "Image.h" +#include "Canvas.h" + +// C #include +// C++ +#include + namespace love { namespace graphics @@ -47,20 +54,31 @@ int w_ParticleSystem_clone(lua_State *L) return 1; } -int w_ParticleSystem_setImage(lua_State *L) +int w_ParticleSystem_setTexture(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); - Image *i = luax_checkimage(L, 2); - t->setImage(i); + Texture *tex = luax_checktype(L, 2, "Texture", GRAPHICS_TEXTURE_T); + t->setTexture(tex); return 0; } -int w_ParticleSystem_getImage(lua_State *L) +int w_ParticleSystem_getTexture(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); - Image *i = t->getImage(); - i->retain(); - luax_pushtype(L, "Image", GRAPHICS_IMAGE_T, i); + Texture *tex = t->getTexture(); + tex->retain(); + + // FIXME: big hack right here. + if (typeid(*tex) == typeid(Image)) + luax_pushtype(L, "Image", GRAPHICS_IMAGE_T, tex); + else if (typeid(*tex) == typeid(Canvas)) + luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, tex); + else + { + tex->release(); + return luaL_error(L, "Unable to determine texture type."); + } + return 1; } @@ -616,8 +634,8 @@ int w_ParticleSystem_update(lua_State *L) static const luaL_Reg functions[] = { { "clone", w_ParticleSystem_clone }, - { "setImage", w_ParticleSystem_setImage }, - { "getImage", w_ParticleSystem_getImage }, + { "setTexture", w_ParticleSystem_setTexture }, + { "getTexture", w_ParticleSystem_getTexture }, { "setBufferSize", w_ParticleSystem_setBufferSize }, { "getBufferSize", w_ParticleSystem_getBufferSize }, { "setInsertMode", w_ParticleSystem_setInsertMode }, @@ -668,6 +686,11 @@ static const luaL_Reg functions[] = { "isPaused", w_ParticleSystem_isPaused }, { "isStopped", w_ParticleSystem_isStopped }, { "update", w_ParticleSystem_update }, + + // Deprecated since 0.9.1. + { "setImage", w_ParticleSystem_setTexture }, + { "getImage", w_ParticleSystem_getTexture }, + { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.h b/src/modules/graphics/opengl/wrap_ParticleSystem.h index d81586689..277799080 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.h +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.h @@ -23,7 +23,6 @@ // LOVE #include "common/runtime.h" -#include "wrap_Image.h" #include "ParticleSystem.h" namespace love @@ -35,8 +34,8 @@ namespace opengl ParticleSystem *luax_checkparticlesystem(lua_State *L, int idx); int w_ParticleSystem_clone(lua_State *L); -int w_ParticleSystem_setImage(lua_State *L); -int w_ParticleSystem_getImage(lua_State *L); +int w_ParticleSystem_setTexture(lua_State *L); +int w_ParticleSystem_getTexture(lua_State *L); int w_ParticleSystem_setBufferSize(lua_State *L); int w_ParticleSystem_getBufferSize(lua_State *L); int w_ParticleSystem_setInsertMode(lua_State *L); diff --git a/src/modules/graphics/opengl/wrap_Shader.cpp b/src/modules/graphics/opengl/wrap_Shader.cpp index a2cb1eb45..491146ffd 100644 --- a/src/modules/graphics/opengl/wrap_Shader.cpp +++ b/src/modules/graphics/opengl/wrap_Shader.cpp @@ -253,23 +253,13 @@ int w_Shader_sendMatrix(lua_State *L) return 0; } -int w_Shader_sendImage(lua_State *L) +int w_Shader_sendTexture(lua_State *L) { Shader *shader = luax_checkshader(L, 1); const char *name = luaL_checkstring(L, 2); - Image *img = luax_checkimage(L, 3); + Texture *texture = luax_checktype(L, 3, "Texture", GRAPHICS_TEXTURE_T); - EXCEPT_GUARD(shader->sendImage(name, *img);) - return 0; -} - -int w_Shader_sendCanvas(lua_State *L) -{ - Shader *shader = luax_checkshader(L, 1); - const char *name = luaL_checkstring(L, 2); - Canvas *canvas = luax_checkcanvas(L, 3); - - EXCEPT_GUARD(shader->sendCanvas(name, *canvas);) + EXCEPT_GUARD(shader->sendTexture(name, texture);) return 0; } @@ -318,7 +308,7 @@ static void w_convertMatrices(lua_State *L, int idx) int w_Shader_send(lua_State *L) { int ttype = lua_type(L, 3); - Proxy *p = 0; + Proxy *p = nullptr; switch (ttype) { @@ -328,13 +318,11 @@ int w_Shader_send(lua_State *L) return w_Shader_sendFloat(L); break; case LUA_TUSERDATA: - // Image or Canvas. + // Texture (Image or Canvas). p = (Proxy *) lua_touserdata(L, 3); - if (p->flags[GRAPHICS_IMAGE_ID]) - return w_Shader_sendImage(L); - else if (p->flags[GRAPHICS_CANVAS_ID]) - return w_Shader_sendCanvas(L); + if (p->flags[GRAPHICS_TEXTURE_ID]) + return w_Shader_sendTexture(L); break; case LUA_TTABLE: @@ -366,9 +354,13 @@ static const luaL_Reg functions[] = { "sendBoolean", w_Shader_sendInt }, { "sendFloat", w_Shader_sendFloat }, { "sendMatrix", w_Shader_sendMatrix }, - { "sendImage", w_Shader_sendImage }, - { "sendCanvas", w_Shader_sendCanvas }, + { "sendTexture", w_Shader_sendTexture }, { "send", w_Shader_send }, + + // Deprecated since 0.9.1. + { "sendImage", w_Shader_sendTexture }, + { "sendCanvas", w_Shader_sendTexture }, + { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Shader.h b/src/modules/graphics/opengl/wrap_Shader.h index af092c61b..055fadbf8 100644 --- a/src/modules/graphics/opengl/wrap_Shader.h +++ b/src/modules/graphics/opengl/wrap_Shader.h @@ -36,8 +36,7 @@ int w_Shader_getWarnings(lua_State *L); int w_Shader_sendInt(lua_State *L); int w_Shader_sendFloat(lua_State *L); int w_Shader_sendMatrix(lua_State *L); -int w_Shader_sendImage(lua_State *L); -int w_Shader_sendCanvas(lua_State *L); +int w_Shader_sendTexture(lua_State *L); int w_Shader_send(lua_State *L); extern "C" int luaopen_shader(lua_State *L); diff --git a/src/modules/graphics/opengl/wrap_SpriteBatch.cpp b/src/modules/graphics/opengl/wrap_SpriteBatch.cpp index 65e2ff099..f712db9b3 100644 --- a/src/modules/graphics/opengl/wrap_SpriteBatch.cpp +++ b/src/modules/graphics/opengl/wrap_SpriteBatch.cpp @@ -18,8 +18,13 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include "Image.h" +// LOVE #include "wrap_SpriteBatch.h" +#include "Image.h" +#include "Canvas.h" + +// C++ +#include namespace love { @@ -36,7 +41,7 @@ SpriteBatch *luax_checkspritebatch(lua_State *L, int idx) int w_SpriteBatch_add(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); - Quad *quad = 0; + Quad *quad = nullptr; int startidx = 2; if (luax_istype(L, 2, GRAPHICS_QUAD_T)) @@ -74,7 +79,7 @@ int w_SpriteBatch_set(lua_State *L) SpriteBatch *t = luax_checkspritebatch(L, 1); int id = luaL_checkinteger(L, 2); - Quad *quad = 0; + Quad *quad = nullptr; int startidx = 3; if (luax_istype(L, 3, GRAPHICS_QUAD_T)) @@ -126,20 +131,31 @@ int w_SpriteBatch_unbind(lua_State *L) return 0; } -int w_SpriteBatch_setImage(lua_State *L) +int w_SpriteBatch_setTexture(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); - Image *image = luax_checktype(L, 2, "Image", GRAPHICS_IMAGE_T); - t->setImage(image); + Texture *tex = luax_checktype(L, 2, "Texture", GRAPHICS_TEXTURE_T); + t->setTexture(tex); return 0; } -int w_SpriteBatch_getImage(lua_State *L) +int w_SpriteBatch_getTexture(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); - Image *image = t->getImage(); - image->retain(); - luax_pushtype(L, "Image", GRAPHICS_IMAGE_T, image); + Texture *tex = t->getTexture(); + tex->retain(); + + // FIXME: big hack right here. + if (typeid(*tex) == typeid(Image)) + luax_pushtype(L, "Image", GRAPHICS_IMAGE_T, tex); + else if (typeid(*tex) == typeid(Canvas)) + luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, tex); + else + { + tex->release(); + return luaL_error(L, "Unable to determine texture type."); + } + return 1; } @@ -224,13 +240,17 @@ static const luaL_Reg functions[] = { "clear", w_SpriteBatch_clear }, { "bind", w_SpriteBatch_bind }, { "unbind", w_SpriteBatch_unbind }, - { "setImage", w_SpriteBatch_setImage }, - { "getImage", w_SpriteBatch_getImage }, + { "setTexture", w_SpriteBatch_setTexture }, + { "getTexture", w_SpriteBatch_getTexture }, { "setColor", w_SpriteBatch_setColor }, { "getColor", w_SpriteBatch_getColor }, { "getCount", w_SpriteBatch_getCount }, { "setBufferSize", w_SpriteBatch_setBufferSize }, { "getBufferSize", w_SpriteBatch_getBufferSize }, + + // Deprecated since 0.9.1. + { "setImage", w_SpriteBatch_setTexture }, + { "getImage", w_SpriteBatch_getTexture }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_SpriteBatch.h b/src/modules/graphics/opengl/wrap_SpriteBatch.h index 10e4384f3..acc56ff62 100644 --- a/src/modules/graphics/opengl/wrap_SpriteBatch.h +++ b/src/modules/graphics/opengl/wrap_SpriteBatch.h @@ -39,8 +39,8 @@ int w_SpriteBatch_setg(lua_State *L); int w_SpriteBatch_clear(lua_State *L); int w_SpriteBatch_bind(lua_State *L); int w_SpriteBatch_unbind(lua_State *L); -int w_SpriteBatch_setImage(lua_State *L); -int w_SpriteBatch_getImage(lua_State *L); +int w_SpriteBatch_setTexture(lua_State *L); +int w_SpriteBatch_getTexture(lua_State *L); int w_SpriteBatch_setColor(lua_State *L); int w_SpriteBatch_getColor(lua_State *L); int w_SpriteBatch_getCount(lua_State *L); diff --git a/src/scripts/graphics.lua b/src/scripts/graphics.lua index 5defc641f..f0fb6eaa1 100644 --- a/src/scripts/graphics.lua +++ b/src/scripts/graphics.lua @@ -1303,7 +1303,8 @@ do #define ProjectionMatrix gl_ProjectionMatrix #define TransformProjectionMatrix gl_ModelViewProjectionMatrix #define NormalMatrix gl_NormalMatrix -uniform sampler2D _tex0_;]] +uniform sampler2D _tex0_; +uniform vec2 love_ScreenParams;]] local GLSL_VERTEX = { HEADER = [[ @@ -1335,14 +1336,22 @@ void main() { void main() { // fix crashing issue in OSX when _tex0_ is unused within effect() float dummy = texture2D(_tex0_, vec2(.5)).r; - gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, gl_FragCoord.xy); + + // See Shader::checkSetScreenParams in Shader.cpp. + vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenParams[0]) + love_ScreenParams[1]); + + gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord); }]], FOOTER_MULTI_CANVAS = [[ void main() { // fix crashing issue in OSX when _tex0_ is unused within effect() float dummy = texture2D(_tex0_, vec2(.5)).r; - effects(VaryingColor, _tex0_, VaryingTexCoord.st, gl_FragCoord.xy); + + // See Shader::checkSetScreenParams in Shader.cpp. + vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenParams[0]) + love_ScreenParams[1]); + + effects(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord); }]], } diff --git a/src/scripts/graphics.lua.h b/src/scripts/graphics.lua.h index e47b50c71..6596a0b84 100644 --- a/src/scripts/graphics.lua.h +++ b/src/scripts/graphics.lua.h @@ -6294,7 +6294,9 @@ const unsigned char graphics_lua[] = 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x67, 0x6c, 0x5f, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, - 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x5d, 0x5d, 0x0a, + 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x0a, + 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, + 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3b, 0x5d, 0x5d, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, @@ -6342,11 +6344,20 @@ const unsigned char graphics_lua[] = 0x09, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x28, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x2e, 0x35, 0x29, 0x29, 0x2e, 0x72, 0x3b, 0x0a, + 0x09, 0x2f, 0x2f, 0x20, 0x53, 0x65, 0x65, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x3a, 0x3a, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x53, 0x65, 0x74, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x20, 0x69, 0x6e, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x63, 0x70, 0x70, 0x2e, 0x0a, + 0x09, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, + 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, + 0x2e, 0x78, 0x2c, 0x20, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, + 0x79, 0x20, 0x2a, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x5b, 0x30, 0x5d, 0x29, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, + 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5b, 0x31, 0x5d, 0x29, 0x3b, 0x0a, 0x09, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, - 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x73, 0x74, 0x2c, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, - 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x78, 0x79, 0x29, 0x3b, 0x0a, + 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x73, 0x74, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, + 0x6f, 0x72, 0x64, 0x29, 0x3b, 0x0a, 0x7d, 0x5d, 0x5d, 0x2c, 0x0a, 0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x43, 0x41, 0x4e, 0x56, 0x41, 0x53, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, @@ -6358,10 +6369,19 @@ const unsigned char graphics_lua[] = 0x09, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x28, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x2e, 0x35, 0x29, 0x29, 0x2e, 0x72, 0x3b, 0x0a, + 0x09, 0x2f, 0x2f, 0x20, 0x53, 0x65, 0x65, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x3a, 0x3a, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x53, 0x65, 0x74, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x20, 0x69, 0x6e, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x63, 0x70, 0x70, 0x2e, 0x0a, + 0x09, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, + 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, + 0x2e, 0x78, 0x2c, 0x20, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, + 0x79, 0x20, 0x2a, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x5b, 0x30, 0x5d, 0x29, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, + 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5b, 0x31, 0x5d, 0x29, 0x3b, 0x0a, 0x09, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x28, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, - 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x73, 0x74, 0x2c, 0x20, 0x67, 0x6c, 0x5f, - 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x78, 0x79, 0x29, 0x3b, 0x0a, + 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x73, 0x74, 0x2c, 0x20, 0x70, 0x69, 0x78, + 0x65, 0x6c, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x29, 0x3b, 0x0a, 0x7d, 0x5d, 0x5d, 0x2c, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x72,