From 7f77c2d0b30ce0d26f0564216b75f22bcbb3696a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 15 Jan 2014 14:56:28 -0400 Subject: [PATCH 01/56] Canvas:renderTo now restores the previously active Canvas when done, instead of erroring if another Canvas is already active --- src/modules/graphics/opengl/wrap_Canvas.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 4d5ab1282..9a4669563 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -34,22 +34,21 @@ Canvas *luax_checkcanvas(lua_State *L, int idx) int w_Canvas_renderTo(lua_State *L) { - // As startGrab() clears the framebuffer, better not allow - // grabbing inside another grabbing - if (Canvas::current != NULL) - { - Canvas::bindDefaultCanvas(); - return luaL_error(L, "Current render target not the default canvas!"); - } - Canvas *canvas = luax_checkcanvas(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); + // Save the current Canvas so we can restore it when we're done. + Canvas *oldcanvas = Canvas::current; + EXCEPT_GUARD(canvas->startGrab();) lua_settop(L, 2); // make sure the function is on top of the stack lua_call(L, 0, 0); - canvas->stopGrab(); + + if (oldcanvas != nullptr) + oldcanvas->startGrab(oldcanvas->getAttachedCanvases()); + else + Canvas::bindDefaultCanvas(); return 0; } From 9b9671f5ee1261ff594f3b800b93811528de4f4b Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 15 Jan 2014 23:03:39 -0400 Subject: [PATCH 02/56] Fixed a potential memory leak when a Font object errors --- src/modules/graphics/opengl/Font.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 2b4bf8750..1e5aab95c 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -186,7 +186,15 @@ Font::Glyph *Font::addGlyph(uint32 glyph) if (textureY + h + TEXTURE_PADDING > textureHeight) { // totally out of space - new texture! - createTexture(); + try + { + createTexture(); + } + catch (love::Exception &) + { + gd->release(); + throw; + } } Glyph *g = new Glyph; From dc35db1c7b908744a164986781074ef50d2b4b7b Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 15 Jan 2014 23:38:39 -0400 Subject: [PATCH 03/56] =?UTF-8?q?Fixed=20tab=20characters=20(=E2=80=98\t?= =?UTF-8?q?=E2=80=99)=20in=20text=20to=20be=20drawn=20properly=20with=20lo?= =?UTF-8?q?ve.graphics.print.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/font/GlyphData.h | 1 - src/modules/graphics/opengl/Font.cpp | 29 +++++++++++++++++++++++++--- src/modules/graphics/opengl/Font.h | 9 +++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/modules/font/GlyphData.h b/src/modules/font/GlyphData.h index 59aa1200b..6144dcb9b 100644 --- a/src/modules/font/GlyphData.h +++ b/src/modules/font/GlyphData.h @@ -46,7 +46,6 @@ struct GlyphMetrics int advance; int bearingX; int bearingY; - int spacing; }; /** diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 1e5aab95c..5cb062cb3 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -46,6 +46,7 @@ Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter) , lineHeight(1) , mSpacing(1) , filter(filter) + , useSpacesAsTab(false) { this->filter.mipmap = Texture::FILTER_NONE; @@ -67,13 +68,16 @@ Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter) textureWidth = TEXTURE_WIDTHS[textureSizeIndex]; textureHeight = TEXTURE_HEIGHTS[textureSizeIndex]; - love::font::GlyphData *gd = 0; + love::font::GlyphData *gd = nullptr; try { - gd = r->getGlyphData(32); + gd = r->getGlyphData(32); // Space character. type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA) ? FONT_TRUETYPE : FONT_IMAGE; + if (!r->hasGlyph(9)) // No tab character in the Rasterizer. + useSpacesAsTab = true; + loadVolatile(); } catch (love::Exception &) @@ -172,7 +176,26 @@ void Font::createTexture() Font::Glyph *Font::addGlyph(uint32 glyph) { - love::font::GlyphData *gd = rasterizer->getGlyphData(glyph); + love::font::GlyphData *gd = nullptr; + + // Use spaces for the tab 'glyph'. + if (glyph == 9 && useSpacesAsTab) + { + love::font::GlyphData *spacegd = rasterizer->getGlyphData(32); + + love::font::GlyphMetrics gm = {}; + gm.advance = spacegd->getAdvance() * SPACES_PER_TAB; + gm.bearingX = spacegd->getBearingX(); + gm.bearingY = spacegd->getBearingY(); + love::font::GlyphData::Format f = spacegd->getFormat(); + + spacegd->release(); + + gd = new love::font::GlyphData(glyph, gm, f); + } + else + gd = rasterizer->getGlyphData(glyph); + int w = gd->getWidth(); int h = gd->getHeight(); diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 1d92bac63..791eee6f7 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -202,14 +202,19 @@ private: FontType type; Texture::Filter filter; + int textureX, textureY; + int rowHeight; + + bool useSpacesAsTab; + static const int NUM_TEXTURE_SIZES = 7; static const int TEXTURE_WIDTHS[NUM_TEXTURE_SIZES]; static const int TEXTURE_HEIGHTS[NUM_TEXTURE_SIZES]; static const int TEXTURE_PADDING = 1; - int textureX, textureY; - int rowHeight; + // This will be used if the Rasterizer doesn't have a tab character itself. + static const int SPACES_PER_TAB = 4; }; // Font From 29f47d9a1023086a84b69b9a0082327c2152c4e9 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 16 Jan 2014 16:20:30 -0400 Subject: [PATCH 04/56] Changed particle spawning behaviour in ParticleSystems to spawn at an interpolated position between the location at the previous update and the current one. This results in much smoother behaviour when moving a ParticleSystem constantly via ParticleSystem:setPosition. Also fixed particle spawning to better fill up the buffer. --- .../graphics/opengl/ParticleSystem.cpp | 59 +++++++++++-------- src/modules/graphics/opengl/ParticleSystem.h | 5 +- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index dbc26eb2e..3f176a00b 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -118,6 +118,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p) , emissionRate(p.emissionRate) , emitCounter(0.0f) , position(p.position) + , prevPosition(p.prevPosition) , areaSpreadDistribution(p.areaSpreadDistribution) , areaSpread(p.areaSpread) , lifetime(p.lifetime) @@ -205,14 +206,14 @@ uint32 ParticleSystem::getBufferSize() const return maxParticles; } -void ParticleSystem::addParticle() +void ParticleSystem::addParticle(float t) { if (isFull()) return; // Gets a free particle and updates the allocation pointer. particle *p = pFree++; - initParticle(p); + initParticle(p, t); switch (insertMode) { @@ -231,10 +232,13 @@ void ParticleSystem::addParticle() activeParticles++; } -void ParticleSystem::initParticle(particle *p) +void ParticleSystem::initParticle(particle *p, float t) { float min,max; + // Linearly interpolate between the previous and current emitter position. + love::Vector pos = prevPosition + (position - prevPosition) * t; + min = particleLifeMin; max = particleLifeMax; if (min == max) @@ -243,8 +247,8 @@ void ParticleSystem::initParticle(particle *p) p->life = (float) rng.random(min, max); p->lifetime = p->life; - p->position[0] = position.getX(); - p->position[1] = position.getY(); + p->position[0] = pos.x; + p->position[1] = pos.y; switch (areaSpreadDistribution) { @@ -265,7 +269,7 @@ void ParticleSystem::initParticle(particle *p) max = direction + spread/2.0f; p->direction = (float) rng.random(min, max); - p->origin = position; + p->origin = pos; min = speedMin; max = speedMax; @@ -748,7 +752,7 @@ void ParticleSystem::emit(uint32 num) num = std::min(num, maxParticles - activeParticles); while(num--) - addParticle(); + addParticle(1.0f); } bool ParticleSystem::isActive() const @@ -847,25 +851,6 @@ void ParticleSystem::update(float dt) if (pMem == nullptr || dt == 0.0f) return; - // Make some more particles. - if (active) - { - float rate = 1.0f / emissionRate; // the amount of time between each particle emit - emitCounter += dt; - while (emitCounter > rate) - { - addParticle(); - emitCounter -= rate; - } - /*int particles = (int)(emissionRate * dt); - for (int i = 0; i != particles; i++) - add();*/ - - life -= dt; - if (lifetime != -1 && life < 0) - stop(); - } - // Traverse all particles and update. particle *p = pHead; @@ -940,6 +925,28 @@ void ParticleSystem::update(float dt) p = p->next; } } + + // Make some more particles. + if (active) + { + float rate = 1.0f / emissionRate; // the amount of time between each particle emit + emitCounter += dt; + float total = emitCounter - rate; + while (emitCounter > rate) + { + addParticle(1.0f - (emitCounter - rate) / total); + emitCounter -= rate; + } + /*int particles = (int)(emissionRate * dt); + for (int i = 0; i != particles; i++) + add();*/ + + life -= dt; + if (lifetime != -1 && life < 0) + stop(); + } + + prevPosition = position; } bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out) diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 08f692cb5..14b37a1c4 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -554,6 +554,7 @@ protected: // The relative position of the particle emitter. love::Vector position; + love::Vector prevPosition; // Emission area spread. AreaSpreadDistribution areaSpreadDistribution; @@ -610,11 +611,11 @@ protected: void createBuffers(size_t size); void deleteBuffers(); - void addParticle(); + void addParticle(float t); particle *removeParticle(particle *p); // Called by addParticle. - void initParticle(particle *p); + void initParticle(particle *p, float t); void insertTop(particle *p); void insertBottom(particle *p); void insertRandom(particle *p); From 309193895a333ed3ea8daedfacee6d57343d5ead Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 17 Jan 2014 21:11:20 -0400 Subject: [PATCH 05/56] Added opt-in support for high-dpi mode in OS X when on a retina display (resolves issue #761). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a ‘highdpi’ boolean flag to t.window/love.window.setMode (defaults to false.) When the window is actually in high-dpi mode on a supported display, the graphics width and height and the mouse position are in pixels, rather than ‘window coordinates’. Added love.window.getPixelScale. Returns the scale factor of the window from user-space points to pixels (e.g. it will be 1 normally, and 2 on a retina display in OS X with high-dpi mode enabled.) --- src/modules/event/sdl/Event.cpp | 54 ++++++++++-- src/modules/mouse/sdl/Mouse.cpp | 51 ++++++++++- src/modules/window/Window.cpp | 40 +++++---- src/modules/window/Window.h | 52 ++++++----- src/modules/window/sdl/Window.cpp | 135 ++++++++++++++++++++--------- src/modules/window/sdl/Window.h | 12 +-- src/modules/window/wrap_Window.cpp | 106 ++++++++++++---------- src/modules/window/wrap_Window.h | 1 + src/scripts/boot.lua | 1 + src/scripts/boot.lua.h | 4 +- 10 files changed, 308 insertions(+), 148 deletions(-) diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index ece1f7bfd..e50ce357d 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -37,6 +37,24 @@ namespace event namespace sdl { +// SDL reports mouse coordinates in the window coordinate system in OS X, but +// we want them in pixel coordinates (may be different with high-DPI enabled.) +static void windowToPixelCoords(int *x, int *y) +{ + double scale = 1.0; + + window::Window *window = (window::Window *) Module::findInstance("love.window."); + if (window != nullptr) + scale = window->getPixelScale(); + + if (x != nullptr) + *x = int(double(*x) * scale); + + if (y != nullptr) + *y = int(double(*x) * scale); +} + + const char *Event::getName() const { return "love.event.sdl"; @@ -162,8 +180,11 @@ Message *Event::convert(const SDL_Event &e) const case SDL_MOUSEBUTTONUP: if (buttons.find(e.button.button, button) && mouse::Mouse::getConstant(button, txt)) { - arg1 = new Variant((double) e.button.x); - arg2 = new Variant((double) e.button.y); + int x = e.button.x; + int y = e.button.y; + windowToPixelCoords(&x, &y); + arg1 = new Variant((double) x); + arg2 = new Variant((double) y); arg3 = new Variant(txt, strlen(txt)); msg = new Message((e.type == SDL_MOUSEBUTTONDOWN) ? "mousepressed" : "mousereleased", @@ -182,6 +203,7 @@ Message *Event::convert(const SDL_Event &e) const int mx, my; SDL_GetMouseState(&mx, &my); + windowToPixelCoords(&mx, &my); arg1 = new Variant((double) mx); arg2 = new Variant((double) my); @@ -366,7 +388,7 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const Message *Event::convertWindowEvent(const SDL_Event &e) const { Message *msg = 0; - Variant *arg1, *arg2; + Variant *arg1, *arg2, *arg3, *arg4; window::Window *win = 0; if (e.type != SDL_WINDOWEVENT) @@ -402,17 +424,31 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const win = (window::Window *) Module::findInstance("love.window."); if (win) { + int px_w = e.window.data1; + int px_h = e.window.data2; + +#if SDL_VERSION_ATLEAST(2,0,1) + SDL_Window *sdlwin = SDL_GetWindowFromID(e.window.windowID); + if (sdlwin) + SDL_GL_GetDrawableSize(sdlwin, &px_w, &px_h); +#endif + win->onWindowResize(e.window.data1, e.window.data2); graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics."); if (gfx) - gfx->setViewportSize(e.window.data1, e.window.data2); + gfx->setViewportSize(px_w, px_h); + + arg1 = new Variant((double) px_w); + arg2 = new Variant((double) px_h); + arg3 = new Variant((double) e.window.data1); + arg4 = new Variant((double) e.window.data2); + msg = new Message("resize", arg1, arg2, arg3, arg4); + arg1->release(); + arg2->release(); + arg3->release(); + arg4->release(); } - arg1 = new Variant((double) e.window.data1); - arg2 = new Variant((double) e.window.data2); - msg = new Message("resize", arg1, arg2); - arg1->release(); - arg2->release(); break; } diff --git a/src/modules/mouse/sdl/Mouse.cpp b/src/modules/mouse/sdl/Mouse.cpp index 94b187a7a..200e3e203 100644 --- a/src/modules/mouse/sdl/Mouse.cpp +++ b/src/modules/mouse/sdl/Mouse.cpp @@ -32,6 +32,39 @@ namespace mouse namespace sdl { +// SDL reports mouse coordinates in the window coordinate system in OS X, but +// we want them in pixel coordinates (may be different with high-DPI enabled.) +static void windowToPixelCoords(int *x, int *y) +{ + double scale = 1.0; + + love::window::Window *window = love::window::sdl::Window::getSingleton(); + if (window != nullptr) + scale = window->getPixelScale(); + + if (x != nullptr) + *x = int(double(*x) * scale); + + if (y != nullptr) + *y = int(double(*x) * scale); +} + +// And vice versa for setting mouse coordinates. +static void pixelToWindowCoords(int *x, int *y) +{ + double scale = 1.0; + + love::window::Window *window = love::window::sdl::Window::getSingleton(); + if (window != nullptr) + scale = window->getPixelScale(); + + if (x != nullptr) + *x = int(double(*x) / scale); + + if (y != nullptr) + *y = int(double(*x) / scale); +} + const char *Mouse::getName() const { return "love.mouse.sdl"; @@ -98,30 +131,40 @@ love::mouse::Cursor *Mouse::getCursor() const int Mouse::getX() const { int x; - SDL_GetMouseState(&x, 0); + SDL_GetMouseState(&x, nullptr); + windowToPixelCoords(&x, nullptr); + return x; } int Mouse::getY() const { int y; - SDL_GetMouseState(0, &y); + SDL_GetMouseState(nullptr, &y); + windowToPixelCoords(nullptr, &y); + return y; } void Mouse::getPosition(int &x, int &y) const { - SDL_GetMouseState(&x, &y); + int mx, my; + SDL_GetMouseState(&mx, &my); + windowToPixelCoords(&mx, &my); + + x = mx; + y = my; } void Mouse::setPosition(int x, int y) { love::window::Window *window = love::window::sdl::Window::getSingleton(); - SDL_Window *handle = NULL; + SDL_Window *handle = nullptr; if (window) handle = (SDL_Window *) window->getHandle(); + pixelToWindowCoords(&x, &y); SDL_WarpMouseInWindow(handle, x, y); } diff --git a/src/modules/window/Window.cpp b/src/modules/window/Window.cpp index ac9c45a4e..6243830aa 100644 --- a/src/modules/window/Window.cpp +++ b/src/modules/window/Window.cpp @@ -26,19 +26,19 @@ namespace love namespace window { -Window *Window::singleton = NULL; +Window *Window::singleton = nullptr; Window::~Window() { if (singleton == this) - singleton = NULL; + singleton = nullptr; } void Window::swapBuffers() { } -WindowAttributes::WindowAttributes() +WindowSettings::WindowSettings() : fullscreen(false) , fstype(Window::FULLSCREEN_TYPE_NORMAL) , vsync(true) @@ -49,6 +49,7 @@ WindowAttributes::WindowAttributes() , borderless(false) , centered(true) , display(0) + , highdpi(false) { } @@ -62,31 +63,32 @@ bool Window::getConstant(Window::FullscreenType in, const char *&out) return fullscreenTypes.find(in, out); } -bool Window::getConstant(const char *in, Window::Attribute &out) +bool Window::getConstant(const char *in, Window::Setting &out) { - return attributes.find(in, out); + return settings.find(in, out); } -bool Window::getConstant(Window::Attribute in, const char *&out) +bool Window::getConstant(Window::Setting in, const char *&out) { - return attributes.find(in, out); + return settings.find(in, out); } -StringMap::Entry Window::attributeEntries[] = +StringMap::Entry Window::settingEntries[] = { - {"fullscreen", ATTRIB_FULLSCREEN}, - {"fullscreentype", ATTRIB_FULLSCREEN_TYPE}, - {"vsync", ATTRIB_VSYNC}, - {"fsaa", ATTRIB_FSAA}, - {"resizable", ATTRIB_RESIZABLE}, - {"minwidth", ATTRIB_MIN_WIDTH}, - {"minheight", ATTRIB_MIN_HEIGHT}, - {"borderless", ATTRIB_BORDERLESS}, - {"centered", ATTRIB_CENTERED}, - {"display", ATTRIB_DISPLAY} + {"fullscreen", SETTING_FULLSCREEN}, + {"fullscreentype", SETTING_FULLSCREEN_TYPE}, + {"vsync", SETTING_VSYNC}, + {"fsaa", SETTING_FSAA}, + {"resizable", SETTING_RESIZABLE}, + {"minwidth", SETTING_MIN_WIDTH}, + {"minheight", SETTING_MIN_HEIGHT}, + {"borderless", SETTING_BORDERLESS}, + {"centered", SETTING_CENTERED}, + {"display", SETTING_DISPLAY}, + {"highdpi", SETTING_HIGHDPI}, }; -StringMap Window::attributes(Window::attributeEntries, sizeof(Window::attributeEntries)); +StringMap Window::settings(Window::settingEntries, sizeof(Window::settingEntries)); StringMap::Entry Window::fullscreenTypeEntries[] = { diff --git a/src/modules/window/Window.h b/src/modules/window/Window.h index 0f84c7c51..ad247fd0b 100644 --- a/src/modules/window/Window.h +++ b/src/modules/window/Window.h @@ -37,26 +37,27 @@ namespace window // Forward-declared so it can be used in the class methods. We can't define the // whole thing here because it uses the Window::Type enum. -struct WindowAttributes; +struct WindowSettings; class Window : public Module { public: - // Types of window attributes. - enum Attribute + // Different window settings. + enum Setting { - ATTRIB_FULLSCREEN, - ATTRIB_FULLSCREEN_TYPE, - ATTRIB_VSYNC, - ATTRIB_FSAA, - ATTRIB_RESIZABLE, - ATTRIB_MIN_WIDTH, - ATTRIB_MIN_HEIGHT, - ATTRIB_BORDERLESS, - ATTRIB_CENTERED, - ATTRIB_DISPLAY, - ATTRIB_MAX_ENUM + SETTING_FULLSCREEN, + SETTING_FULLSCREEN_TYPE, + SETTING_VSYNC, + SETTING_FSAA, + SETTING_RESIZABLE, + SETTING_MIN_WIDTH, + SETTING_MIN_HEIGHT, + SETTING_BORDERLESS, + SETTING_CENTERED, + SETTING_DISPLAY, + SETTING_HIGHDPI, + SETTING_MAX_ENUM }; enum FullscreenType @@ -74,8 +75,8 @@ public: virtual ~Window(); - virtual bool setWindow(int width = 800, int height = 600, WindowAttributes *attribs = 0) = 0; - virtual void getWindow(int &width, int &height, WindowAttributes &attribs) = 0; + virtual bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr) = 0; + virtual void getWindow(int &width, int &height, WindowSettings &settings) = 0; virtual bool setFullscreen(bool fullscreen, FullscreenType fstype) = 0; virtual bool setFullscreen(bool fullscreen) = 0; @@ -113,14 +114,16 @@ public: virtual void setMouseGrab(bool grab) = 0; virtual bool isMouseGrabbed() const = 0; + virtual double getPixelScale() const = 0; + virtual const void *getHandle() const = 0; //virtual static Window *createSingleton() = 0; //virtual static Window *getSingleton() = 0; // No virtual statics, of course, but you are supposed to implement these statics. - static bool getConstant(const char *in, Attribute &out); - static bool getConstant(Attribute in, const char *&out); + static bool getConstant(const char *in, Setting &out); + static bool getConstant(Setting in, const char *&out); static bool getConstant(const char *in, FullscreenType &out); static bool getConstant(FullscreenType in, const char *&out); @@ -131,17 +134,18 @@ protected: private: - static StringMap::Entry attributeEntries[]; - static StringMap attributes; + static StringMap::Entry settingEntries[]; + static StringMap settings; static StringMap::Entry fullscreenTypeEntries[]; static StringMap fullscreenTypes; }; // Window -struct WindowAttributes +struct WindowSettings { - WindowAttributes(); + WindowSettings(); + bool fullscreen; // = false Window::FullscreenType fstype; // = FULLSCREEN_TYPE_NORMAL bool vsync; // = true @@ -152,7 +156,9 @@ struct WindowAttributes bool borderless; // = false bool centered; // = true int display; // = 0 -}; // WindowFlags + bool highdpi; // false + +}; // WindowSettings } // window } // love diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 400706687..0c94c8624 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -63,21 +63,21 @@ Window::~Window() Window::_currentMode::_currentMode() : width(800) , height(600) - , attribs() + , settings() , icon(0) { } -bool Window::setWindow(int width, int height, WindowAttributes *attribs) +bool Window::setWindow(int width, int height, WindowSettings *settings) { graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics."); - if (gfx) + if (gfx != nullptr) gfx->unSetMode(); - WindowAttributes f; + WindowSettings f; - if (attribs) - f = *attribs; + if (settings) + f = *settings; f.minwidth = std::max(f.minwidth, 1); f.minheight = std::max(f.minheight, 1); @@ -116,15 +116,28 @@ bool Window::setWindow(int width, int height, WindowAttributes *attribs) if (f.borderless) sdlflags |= SDL_WINDOW_BORDERLESS; +#if SDL_VERSION_ATLEAST(2,0,1) + if (f.highdpi) + sdlflags |= SDL_WINDOW_ALLOW_HIGHDPI; +#endif + // Destroy and recreate the window if the dimensions or flags have changed. if (window) { int curdisplay = SDL_GetWindowDisplayIndex(window); Uint32 wflags = SDL_GetWindowFlags(window); - wflags &= (SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS); + + Uint32 testflags = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP + | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS; + +#if SDL_VERSION_ATLEAST(2,0,1) + testflags |= SDL_WINDOW_ALLOW_HIGHDPI; +#endif + + wflags &= testflags; if (sdlflags != wflags || width != curMode.width || height != curMode.height - || f.display != curdisplay || f.fsaa != curMode.attribs.fsaa) + || f.display != curdisplay || f.fsaa != curMode.settings.fsaa) { SDL_DestroyWindow(window); window = 0; @@ -182,10 +195,19 @@ bool Window::setWindow(int width, int height, WindowAttributes *attribs) created = true; - updateAttributes(f); + updateSettings(f); - if (gfx) - gfx->setMode(curMode.width, curMode.height); + if (gfx != nullptr) + { + int width = curMode.width; + int height = curMode.height; + +#if SDL_VERSION_ATLEAST(2,0,1) + SDL_GL_GetDrawableSize(window, &width, &height); +#endif + + gfx->setMode(width, height); + } // Make sure the mouse keeps its previous grab setting. setMouseGrab(mouseGrabbed); @@ -250,8 +272,8 @@ bool Window::setContext(int fsaa, bool vsync) fsaa = (buffers > 0) ? samples : 0; } - curMode.attribs.fsaa = fsaa; - curMode.attribs.vsync = SDL_GL_GetSwapInterval() != 0; + curMode.settings.fsaa = fsaa; + curMode.settings.vsync = SDL_GL_GetSwapInterval() != 0; return true; } @@ -271,7 +293,7 @@ void Window::setWindowGLAttributes(int fsaa) const SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); } -void Window::updateAttributes(const WindowAttributes &newattribs) +void Window::updateSettings(const WindowSettings &newsettings) { Uint32 wflags = SDL_GetWindowFlags(window); @@ -280,54 +302,60 @@ void Window::updateAttributes(const WindowAttributes &newattribs) if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { - curMode.attribs.fullscreen = true; - curMode.attribs.fstype = FULLSCREEN_TYPE_DESKTOP; + curMode.settings.fullscreen = true; + curMode.settings.fstype = FULLSCREEN_TYPE_DESKTOP; } else if ((wflags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN) { - curMode.attribs.fullscreen = true; - curMode.attribs.fstype = FULLSCREEN_TYPE_NORMAL; + curMode.settings.fullscreen = true; + curMode.settings.fstype = FULLSCREEN_TYPE_NORMAL; } else { - curMode.attribs.fullscreen = false; - curMode.attribs.fstype = newattribs.fstype; + curMode.settings.fullscreen = false; + curMode.settings.fstype = newsettings.fstype; } // The min width/height is set to 0 internally in SDL when in fullscreen. - if (curMode.attribs.fullscreen) + if (curMode.settings.fullscreen) { - curMode.attribs.minwidth = newattribs.minwidth; - curMode.attribs.minheight = newattribs.minheight; + curMode.settings.minwidth = newsettings.minwidth; + curMode.settings.minheight = newsettings.minheight; } else - SDL_GetWindowMinimumSize(window, &curMode.attribs.minwidth, &curMode.attribs.minheight); + SDL_GetWindowMinimumSize(window, &curMode.settings.minwidth, &curMode.settings.minheight); - curMode.attribs.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0; - curMode.attribs.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0; - curMode.attribs.centered = newattribs.centered; - curMode.attribs.display = std::max(SDL_GetWindowDisplayIndex(window), 0); + curMode.settings.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0; + curMode.settings.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0; + curMode.settings.centered = newsettings.centered; + curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0); + +#if SDL_VERSION_ATLEAST(2,0,1) + curMode.settings.highdpi = (wflags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; +#else + curMode.settings.highdpi = false; +#endif // Only minimize on focus loss if the window is in exclusive-fullscreen // mode (mimics behaviour of SDL 2.0.2+). // In OS X we always disable this to prevent dock minimization weirdness. #ifndef LOVE_MACOSX - if (curMode.attribs.fullscreen && curMode.attribs.fstype == FULLSCREEN_TYPE_NORMAL) + if (curMode.settings.fullscreen && curMode.settings.fstype == FULLSCREEN_TYPE_NORMAL) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1"); else #endif SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); } -void Window::getWindow(int &width, int &height, WindowAttributes &attribs) +void Window::getWindow(int &width, int &height, WindowSettings &settings) { // Window position may be different from creation - update display index. if (window) - curMode.attribs.display = std::max(SDL_GetWindowDisplayIndex(window), 0); + curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0); width = curMode.width; height = curMode.height; - attribs = curMode.attribs; + settings = curMode.settings; } bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) @@ -335,9 +363,9 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) if (!window) return false; - WindowAttributes newattribs = curMode.attribs; - newattribs.fullscreen = fullscreen; - newattribs.fstype = fstype; + WindowSettings newsettings = curMode.settings; + newsettings.fullscreen = fullscreen; + newsettings.fstype = fstype; Uint32 sdlflags = 0; @@ -361,12 +389,21 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) if (SDL_SetWindowFullscreen(window, sdlflags) == 0) { SDL_GL_MakeCurrent(window, context); - updateAttributes(newattribs); + updateSettings(newsettings); // Update the viewport size now instead of waiting for event polling. graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics."); - if (gfx) - gfx->setViewportSize(curMode.width, curMode.height); + if (gfx != nullptr) + { + int width = curMode.width; + int height = curMode.height; + +#if SDL_VERSION_ATLEAST(2,0,1) + SDL_GL_GetDrawableSize(window, &width, &height); +#endif + + gfx->setViewportSize(width, height); + } return true; } @@ -376,7 +413,7 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) bool Window::setFullscreen(bool fullscreen) { - return setFullscreen(fullscreen, curMode.attribs.fstype); + return setFullscreen(fullscreen, curMode.settings.fstype); } int Window::getDisplayCount() const @@ -559,6 +596,26 @@ bool Window::isMouseGrabbed() const return mouseGrabbed; } +double Window::getPixelScale() const +{ + double scale = 1.0; + +#if SDL_VERSION_ATLEAST(2,0,1) + if (window) + { + int wheight; + SDL_GetWindowSize(window, nullptr, &wheight); + + int dheight = wheight; + SDL_GL_GetDrawableSize(window, nullptr, &dheight); + + scale = (double) dheight / wheight; + } +#endif + + return scale; +} + const void *Window::getHandle() const { return window; diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index b6e7ca953..81796663a 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -41,8 +41,8 @@ public: Window(); ~Window(); - bool setWindow(int width = 800, int height = 600, WindowAttributes *attribs = 0); - void getWindow(int &width, int &height, WindowAttributes &attribs); + bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr); + void getWindow(int &width, int &height, WindowSettings &settings); bool setFullscreen(bool fullscreen, FullscreenType fstype); bool setFullscreen(bool fullscreen); @@ -79,6 +79,8 @@ public: void setMouseGrab(bool grab); bool isMouseGrabbed() const; + double getPixelScale() const; + const void *getHandle() const; static love::window::Window *createSingleton(); @@ -91,8 +93,8 @@ private: bool setContext(int fsaa, bool vsync); void setWindowGLAttributes(int fsaa) const; - // Update the saved window attribs based on the window's actual state. - void updateAttributes(const WindowAttributes &newattribs); + // Update the saved window settings based on the window's actual state. + void updateSettings(const WindowSettings &newsettings); std::string windowTitle; @@ -102,7 +104,7 @@ private: int width; int height; - WindowAttributes attribs; + WindowSettings settings; love::image::ImageData *icon; } curMode; diff --git a/src/modules/window/wrap_Window.cpp b/src/modules/window/wrap_Window.cpp index 799c5e93d..395875111 100644 --- a/src/modules/window/wrap_Window.cpp +++ b/src/modules/window/wrap_Window.cpp @@ -26,7 +26,7 @@ namespace love namespace window { -static Window *instance = 0; +static Window *instance = nullptr; int w_getDisplayCount(lua_State *L) { @@ -34,10 +34,10 @@ int w_getDisplayCount(lua_State *L) return 1; } -static const char *attribName(Window::Attribute attrib) +static const char *settingName(Window::Setting setting) { const char *name = nullptr; - Window::getConstant(attrib, name); + Window::getConstant(setting, name); return name; } @@ -62,91 +62,94 @@ int w_setMode(lua_State *L) return luax_typerror(L, -2, "string"); const char *key = luaL_checkstring(L, -2); - Window::Attribute attrib; + Window::Setting setting; - if (!Window::getConstant(key, attrib)) - return luaL_error(L, "Invalid window attribute: %s", key); + if (!Window::getConstant(key, setting)) + return luaL_error(L, "Invalid window setting: %s", key); lua_pop(L, 1); } - WindowAttributes attribs; + WindowSettings settings; - lua_getfield(L, 3, attribName(Window::ATTRIB_FULLSCREEN_TYPE)); + lua_getfield(L, 3, settingName(Window::SETTING_FULLSCREEN_TYPE)); if (!lua_isnoneornil(L, -1)) { const char *typestr = luaL_checkstring(L, -1); - - if (!Window::getConstant(typestr, attribs.fstype)) + if (!Window::getConstant(typestr, settings.fstype)) return luaL_error(L, "Invalid fullscreen type: %s", typestr); } else { // Default to "normal" fullscreen. - attribs.fstype = Window::FULLSCREEN_TYPE_NORMAL; + settings.fstype = Window::FULLSCREEN_TYPE_NORMAL; } lua_pop(L, 1); - attribs.fullscreen = luax_boolflag(L, 3, attribName(Window::ATTRIB_FULLSCREEN), false); - attribs.vsync = luax_boolflag(L, 3, attribName(Window::ATTRIB_VSYNC), true); - attribs.fsaa = luax_intflag(L, 3, attribName(Window::ATTRIB_FSAA), 0); - attribs.resizable = luax_boolflag(L, 3, attribName(Window::ATTRIB_RESIZABLE), false); - attribs.minwidth = luax_intflag(L, 3, attribName(Window::ATTRIB_MIN_WIDTH), 1); - attribs.minheight = luax_intflag(L, 3, attribName(Window::ATTRIB_MIN_HEIGHT), 1); - attribs.borderless = luax_boolflag(L, 3, attribName(Window::ATTRIB_BORDERLESS), false); - attribs.centered = luax_boolflag(L, 3, attribName(Window::ATTRIB_CENTERED), true); - attribs.display = luax_intflag(L, 3, attribName(Window::ATTRIB_DISPLAY), 1); + settings.fullscreen = luax_boolflag(L, 3, settingName(Window::SETTING_FULLSCREEN), false); + settings.vsync = luax_boolflag(L, 3, settingName(Window::SETTING_VSYNC), true); + settings.fsaa = luax_intflag(L, 3, settingName(Window::SETTING_FSAA), 0); + settings.resizable = luax_boolflag(L, 3, settingName(Window::SETTING_RESIZABLE), false); + settings.minwidth = luax_intflag(L, 3, settingName(Window::SETTING_MIN_WIDTH), 1); + settings.minheight = luax_intflag(L, 3, settingName(Window::SETTING_MIN_HEIGHT), 1); + settings.borderless = luax_boolflag(L, 3, settingName(Window::SETTING_BORDERLESS), false); + settings.centered = luax_boolflag(L, 3, settingName(Window::SETTING_CENTERED), true); + settings.display = luax_intflag(L, 3, settingName(Window::SETTING_DISPLAY), 1); + settings.highdpi = luax_boolflag(L, 3, settingName(Window::SETTING_HIGHDPI), false); // Display index is 1-based in Lua and 0-based internally. - attribs.display--; + settings.display--; - EXCEPT_GUARD(luax_pushboolean(L, instance->setWindow(w, h, &attribs));) + EXCEPT_GUARD(luax_pushboolean(L, instance->setWindow(w, h, &settings));) return 1; } int w_getMode(lua_State *L) { int w, h; - WindowAttributes attribs; - instance->getWindow(w, h, attribs); + WindowSettings settings; + instance->getWindow(w, h, settings); lua_pushnumber(L, w); lua_pushnumber(L, h); lua_newtable(L); const char *fstypestr = "normal"; - Window::getConstant(attribs.fstype, fstypestr); + Window::getConstant(settings.fstype, fstypestr); lua_pushstring(L, fstypestr); - lua_setfield(L, -2, attribName(Window::ATTRIB_FULLSCREEN_TYPE)); + lua_setfield(L, -2, settingName(Window::SETTING_FULLSCREEN_TYPE)); - luax_pushboolean(L, attribs.fullscreen); - lua_setfield(L, -2, attribName(Window::ATTRIB_FULLSCREEN)); + luax_pushboolean(L, settings.fullscreen); + lua_setfield(L, -2, settingName(Window::SETTING_FULLSCREEN)); - luax_pushboolean(L, attribs.vsync); - lua_setfield(L, -2, attribName(Window::ATTRIB_VSYNC)); + luax_pushboolean(L, settings.vsync); + lua_setfield(L, -2, settingName(Window::SETTING_VSYNC)); - lua_pushinteger(L, attribs.fsaa); - lua_setfield(L, -2, attribName(Window::ATTRIB_FSAA)); + lua_pushinteger(L, settings.fsaa); + lua_setfield(L, -2, settingName(Window::SETTING_FSAA)); - luax_pushboolean(L, attribs.resizable); - lua_setfield(L, -2, attribName(Window::ATTRIB_RESIZABLE)); + luax_pushboolean(L, settings.resizable); + lua_setfield(L, -2, settingName(Window::SETTING_RESIZABLE)); - lua_pushinteger(L, attribs.minwidth); - lua_setfield(L, -2, attribName(Window::ATTRIB_MIN_WIDTH)); + lua_pushinteger(L, settings.minwidth); + lua_setfield(L, -2, settingName(Window::SETTING_MIN_WIDTH)); - lua_pushinteger(L, attribs.minheight); - lua_setfield(L, -2, attribName(Window::ATTRIB_MIN_HEIGHT)); + lua_pushinteger(L, settings.minheight); + lua_setfield(L, -2, settingName(Window::SETTING_MIN_HEIGHT)); - luax_pushboolean(L, attribs.borderless); - lua_setfield(L, -2, attribName(Window::ATTRIB_BORDERLESS)); + luax_pushboolean(L, settings.borderless); + lua_setfield(L, -2, settingName(Window::SETTING_BORDERLESS)); - luax_pushboolean(L, attribs.centered); - lua_setfield(L, -2, attribName(Window::ATTRIB_CENTERED)); + luax_pushboolean(L, settings.centered); + lua_setfield(L, -2, settingName(Window::SETTING_CENTERED)); // Display index is 0-based internally and 1-based in Lua. - lua_pushinteger(L, attribs.display + 1); - lua_setfield(L, -2, attribName(Window::ATTRIB_DISPLAY)); + lua_pushinteger(L, settings.display + 1); + lua_setfield(L, -2, settingName(Window::SETTING_DISPLAY)); + + luax_pushboolean(L, settings.highdpi); + lua_setfield(L, -2, settingName(Window::SETTING_HIGHDPI)); return 3; } @@ -202,14 +205,14 @@ int w_setFullscreen(lua_State *L) int w_getFullscreen(lua_State *L) { int w, h; - WindowAttributes attribs; - instance->getWindow(w, h, attribs); + WindowSettings settings; + instance->getWindow(w, h, settings); const char *typestr; - if (!Window::getConstant(attribs.fstype, typestr)) + if (!Window::getConstant(settings.fstype, typestr)) luaL_error(L, "Unknown fullscreen type."); - luax_pushboolean(L, attribs.fullscreen); + luax_pushboolean(L, settings.fullscreen); lua_pushstring(L, typestr); return 2; } @@ -300,6 +303,12 @@ int w_isVisible(lua_State *L) return 1; } +int w_getPixelScale(lua_State *L) +{ + lua_pushnumber(L, instance->getPixelScale()); + return 1; +} + static const luaL_Reg functions[] = { { "getDisplayCount", w_getDisplayCount }, @@ -320,6 +329,7 @@ static const luaL_Reg functions[] = { "hasFocus", w_hasFocus }, { "hasMouseFocus", w_hasMouseFocus }, { "isVisible", w_isVisible }, + { "getPixelScale", w_getPixelScale }, { 0, 0 } }; diff --git a/src/modules/window/wrap_Window.h b/src/modules/window/wrap_Window.h index 6bba9a574..760374c14 100644 --- a/src/modules/window/wrap_Window.h +++ b/src/modules/window/wrap_Window.h @@ -47,6 +47,7 @@ int w_getTitle(lua_State *L); int w_hasFocus(lua_State *L); int w_hasMouseFocus(lua_State *L); int w_isVisible(lua_State *L); +int w_getPixelScale(lua_State *L); extern "C" LOVE_EXPORT int luaopen_love_window(lua_State *L); } // window diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index a02e698b8..bf8766dca 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -300,6 +300,7 @@ function love.init() borderless = false, resizable = false, centered = true, + highdpi = false, }, modules = { event = true, diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 24349aacc..f9b9d7f84 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -27,7 +27,7 @@ const unsigned char boot_lua[] = 0x2d, 0x2d, 0x5b, 0x5b, 0x0a, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, - 0x2d, 0x32, 0x30, 0x31, 0x33, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x27, 0x61, 0x73, 0x2d, 0x69, 0x73, 0x27, 0x2c, 0x20, 0x77, @@ -537,6 +537,8 @@ const unsigned char boot_lua[] = 0x73, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x2c, 0x0a, 0x09, 0x09, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, From 0d52ac6d520fc0f79991ef98d12d5f6bc5d84b18 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 17 Jan 2014 21:12:30 -0400 Subject: [PATCH 06/56] Fixed dumb typo --- src/modules/event/sdl/Event.cpp | 2 +- src/modules/mouse/sdl/Mouse.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index e50ce357d..c6ecdc6f7 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -51,7 +51,7 @@ static void windowToPixelCoords(int *x, int *y) *x = int(double(*x) * scale); if (y != nullptr) - *y = int(double(*x) * scale); + *y = int(double(*y) * scale); } diff --git a/src/modules/mouse/sdl/Mouse.cpp b/src/modules/mouse/sdl/Mouse.cpp index 200e3e203..59a6e056e 100644 --- a/src/modules/mouse/sdl/Mouse.cpp +++ b/src/modules/mouse/sdl/Mouse.cpp @@ -46,7 +46,7 @@ static void windowToPixelCoords(int *x, int *y) *x = int(double(*x) * scale); if (y != nullptr) - *y = int(double(*x) * scale); + *y = int(double(*y) * scale); } // And vice versa for setting mouse coordinates. From 50b7bdcea978afe600bace23292545f695f88686 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 17 Jan 2014 21:17:11 -0400 Subject: [PATCH 07/56] =?UTF-8?q?And=20another=20typo=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/mouse/sdl/Mouse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/mouse/sdl/Mouse.cpp b/src/modules/mouse/sdl/Mouse.cpp index 59a6e056e..74e86291e 100644 --- a/src/modules/mouse/sdl/Mouse.cpp +++ b/src/modules/mouse/sdl/Mouse.cpp @@ -62,7 +62,7 @@ static void pixelToWindowCoords(int *x, int *y) *x = int(double(*x) / scale); if (y != nullptr) - *y = int(double(*x) / scale); + *y = int(double(*y) / scale); } const char *Mouse::getName() const From ad65b577be0782484e9439145e35cd1a236a0339 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 17 Jan 2014 22:00:50 -0400 Subject: [PATCH 08/56] Updated changelog --- changes.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/changes.txt b/changes.txt index 569cb7ef4..8449db034 100644 --- a/changes.txt +++ b/changes.txt @@ -8,8 +8,10 @@ LOVE 0.9.1 [Baby Inspector] * Added Mesh:setWireframe and Mesh:isWireframe for debugging. * Added CircleShape:getPoint and CircleShape:setPoint. * Added Mesh/SpriteBatch/ParticleSystem:setTexture, accepts Canvases and Images. + * Added high-dpi window support for Retina displays in OS X, via the 'highdpi' window flag. + * Added love.window.getPixelScale. - * Deprecated Mesh/SpriteBatch/ParticleSystem:setImage. + * Deprecated Mesh/SpriteBatch/ParticleSystem:setImage and love.graphics.getMaxImageSize. * Fixed love.graphics.scale with negative values causing incorrect line widths. * Fixed Joystick:isDown using 0-based button index arguments. @@ -17,11 +19,16 @@ LOVE 0.9.1 [Baby Inspector] * Fixed love.graphics.setCanvas() to restore the proper viewport and scissor rectangles. * Fixed TrueType font glyphs which request a monochrome bitmap pixel mode. * Fixed love.graphics.reset causing crashes when called in between love.graphics.push/pop. + * Fixed tab characters ("\t") to display properly with love.graphics.print. + + * Renamed love.graphics.getMaxImageSize to love.graphics.getMaxTextureSize (old function still exists.) * Updated the error text for love.filesystem’s module searchers when require fails. * Updated the love.filesystem module searchers to be tried after package.preload instead of before. * Updated love.graphics.newParticleSystem, newSpriteBatch, and newMesh to accept Canvases. * Updated Canvas drawing code, texture coordinates are no longer flipped vertically. + * Updated Canvas:renderTo to work properly if a Canvas is currently active. + * Updated particle spawning behaviour in ParticleSystems to be smoother when moving the emitter. LOVE 0.9.0 [Baby Inspector] --------------------------- From 0e13975c116d058ce2a89489a14a38c22b2a3f2a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 17 Jan 2014 22:28:06 -0400 Subject: [PATCH 09/56] Improved some error message text --- src/common/runtime.cpp | 2 +- src/common/runtime.h | 2 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 5 +++-- src/modules/physics/box2d/Physics.cpp | 5 +++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 55c216adb..e4da8991a 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -464,7 +464,7 @@ void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *dat bool luax_istype(lua_State *L, int idx, love::bits type) { - if (lua_isuserdata(L, idx) == 0) + if (lua_type(L, idx) != LUA_TUSERDATA) return false; return ((((Proxy *)lua_touserdata(L, idx))->flags & type) == type); diff --git a/src/common/runtime.h b/src/common/runtime.h index 8f99f259f..de9c6fbde 100644 --- a/src/common/runtime.h +++ b/src/common/runtime.h @@ -401,7 +401,7 @@ extern "C" { // Also called from luasocket template T *luax_checktype(lua_State *L, int idx, const char *name, love::bits type) { - if (lua_isuserdata(L, idx) == 0) + if (lua_type(L, idx) != LUA_TUSERDATA) luax_typerror(L, idx, name); Proxy *u = (Proxy *)lua_touserdata(L, idx); diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 4ceda2c31..00387e194 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -1122,8 +1122,9 @@ int w_line(lua_State *L) args = lua_objlen(L, 1); is_table = true; } + if (args % 2 != 0) - return luaL_error(L, "Number of vertices must be a multiple of two"); + return luaL_error(L, "Number of vertex components must be a multiple of two"); else if (args < 4) return luaL_error(L, "Need at least two vertices to draw a line"); @@ -1224,7 +1225,7 @@ int w_polygon(lua_State *L) } if (args % 2 != 0) - return luaL_error(L, "Number of vertices must be a multiple of two"); + return luaL_error(L, "Number of vertex components must be a multiple of two"); else if (args < 6) return luaL_error(L, "Need at least three vertices to draw a polygon"); diff --git a/src/modules/physics/box2d/Physics.cpp b/src/modules/physics/box2d/Physics.cpp index e5c6a03a3..a76aca20f 100644 --- a/src/modules/physics/box2d/Physics.cpp +++ b/src/modules/physics/box2d/Physics.cpp @@ -93,8 +93,9 @@ EdgeShape *Physics::newEdgeShape(float x1, float y1, float x2, float y2) int Physics::newPolygonShape(lua_State *L) { int argc = lua_gettop(L); - if (argc%2 != 0) - return luaL_error(L, "Number of vertices must be a multiple of two."); + if (argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + // 3 to 8 (b2_maxPolygonVertices) vertices int vcount = argc / 2; if (vcount < 3) From 81d9810ed8333499def8bb1b4cdf35c52c8eb8bd Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 18 Jan 2014 00:41:02 -0400 Subject: [PATCH 10/56] Fixed t.window.highdpi in love.conf, updated the nogame screen to look slightly better on retina displays --- src/scripts/boot.lua | 17 +++++++++++++---- src/scripts/boot.lua.h | 35 +++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index bf8766dca..27297734f 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -389,6 +389,7 @@ function love.init() borderless = c.window.borderless, centered = c.window.centered, display = c.window.display, + highdpi = c.window.highdpi, }), "Could not set window mode") love.window.setTitle(c.window.title or c.title) if c.window.icon then @@ -1374,8 +1375,9 @@ function love.nogame() local ox = rain.ox local oy = rain.oy - local batch_w = 2 * math.ceil(love.graphics.getWidth() / sx) + 2 - local batch_h = 2 * math.ceil(love.graphics.getHeight() / sy) + 2 + local m = 1 / love.window.getPixelScale() + local batch_w = 2 * math.ceil(m * love.graphics.getWidth() / sx) + 2 + local batch_h = 2 * math.ceil(m * love.graphics.getHeight() / sy) + 2 batch:clear() @@ -1410,8 +1412,9 @@ function love.nogame() g_time = g_time + dt / 2 local int, frac = math.modf(g_time) update_rain(frac) - inspector.x = love.graphics.getWidth() * 0.45 - inspector.y = love.graphics.getHeight() * 0.55 + local scale = love.window.getPixelScale() + inspector.x = love.graphics.getWidth() * 0.45 / scale + inspector.y = love.graphics.getHeight() * 0.55 / scale end local function draw_grid() @@ -1482,8 +1485,13 @@ function love.nogame() function love.draw() love.graphics.setColor(255, 255, 255) + love.graphics.push() + love.graphics.scale(love.window.getPixelScale()) + draw_grid() draw_inspector() + + love.graphics.pop() end function love.keyreleased(key) @@ -1499,6 +1507,7 @@ function love.nogame() t.modules.physics = false t.modules.joystick = false t.window.resizable = true + t.window.highdpi = true end end diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index f9b9d7f84..b90a473a6 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -670,6 +670,8 @@ const unsigned char boot_lua[] = 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x2e, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x65, 0x74, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x54, @@ -4926,14 +4928,17 @@ const unsigned char boot_lua[] = 0x6f, 0x78, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x79, 0x20, 0x3d, 0x20, 0x72, 0x61, 0x69, 0x6e, 0x2e, 0x6f, 0x79, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, 0x31, 0x20, 0x2f, 0x20, 0x6c, 0x6f, + 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x67, 0x65, 0x74, 0x50, 0x69, 0x78, 0x65, 0x6c, + 0x53, 0x63, 0x61, 0x6c, 0x65, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x77, 0x20, 0x3d, 0x20, - 0x32, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, - 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, - 0x28, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x78, 0x29, 0x20, 0x2b, 0x20, 0x32, 0x0a, + 0x32, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6d, 0x20, 0x2a, 0x20, + 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x57, + 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x78, 0x29, 0x20, 0x2b, 0x20, 0x32, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x68, 0x20, 0x3d, 0x20, - 0x32, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, - 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x28, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x79, 0x29, 0x20, 0x2b, 0x20, 0x32, 0x0a, + 0x32, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6d, 0x20, 0x2a, 0x20, + 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x48, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x79, 0x29, 0x20, 0x2b, 0x20, 0x32, 0x0a, 0x09, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x67, 0x65, 0x74, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x29, 0x20, 0x3c, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x77, @@ -4979,12 +4984,17 @@ const unsigned char boot_lua[] = 0x29, 0x0a, 0x09, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x61, 0x69, 0x6e, 0x28, 0x66, 0x72, 0x61, 0x63, 0x29, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, + 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x67, 0x65, 0x74, 0x50, 0x69, 0x78, 0x65, 0x6c, + 0x53, 0x63, 0x61, 0x6c, 0x65, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x78, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, - 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x34, 0x35, 0x0a, + 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x34, 0x35, 0x20, 0x2f, 0x20, 0x73, 0x63, 0x61, 0x6c, + 0x65, 0x0a, 0x09, 0x09, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x48, 0x65, 0x69, - 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x35, 0x35, 0x0a, + 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x35, 0x35, 0x20, 0x2f, 0x20, 0x73, 0x63, 0x61, + 0x6c, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x67, 0x72, 0x69, 0x64, 0x28, 0x29, 0x0a, @@ -5128,8 +5138,15 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x29, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x75, + 0x73, 0x68, 0x28, 0x29, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x63, + 0x61, 0x6c, 0x65, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x67, 0x65, + 0x74, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x28, 0x29, 0x29, 0x0a, 0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x67, 0x72, 0x69, 0x64, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x28, 0x29, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x6f, + 0x70, 0x28, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, @@ -5157,6 +5174,8 @@ const unsigned char boot_lua[] = 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x09, 0x74, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, + 0x09, 0x09, 0x74, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, + 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, From 73f1ce0d40c0883666004bc93233e5c1b2eb895b Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 21 Jan 2014 06:01:50 -0400 Subject: [PATCH 11/56] Added instancing support to Meshes via Mesh:setInstanceCount. Added a new built-in variable to vertex shaders: int love_InstanceID. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit love.graphics.draw(mesh) will draw the mesh instancecount times, using hardware instancing when available. The only way to draw individual instances differently from each other is to use the love_InstanceID variable in a vertex shader. Added love.graphics.isSupported(“instancing”). Hardware instancing is supported if true, otherwise a (slower) pseudo-instancing fallback is used internally when drawing instanced meshes. --- src/modules/graphics/Graphics.cpp | 1 + src/modules/graphics/Graphics.h | 1 + src/modules/graphics/opengl/Mesh.cpp | 33 +++++++-- src/modules/graphics/opengl/Mesh.h | 11 +++ src/modules/graphics/opengl/OpenGL.cpp | 69 +++++++++++++++++-- src/modules/graphics/opengl/OpenGL.h | 24 +++++++ src/modules/graphics/opengl/Shader.cpp | 30 ++++++++ src/modules/graphics/opengl/Shader.h | 8 +++ src/modules/graphics/opengl/wrap_Graphics.cpp | 4 ++ src/modules/graphics/opengl/wrap_Mesh.cpp | 16 +++++ src/modules/graphics/opengl/wrap_Mesh.h | 2 + src/scripts/graphics.lua | 10 ++- src/scripts/graphics.lua.h | 21 +++++- 13 files changed, 217 insertions(+), 13 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 93a13bef7..9d3e20a0a 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -175,6 +175,7 @@ StringMap::Entry Graphics::suppor { "mipmap", Graphics::SUPPORT_MIPMAP }, { "dxt", Graphics::SUPPORT_DXT }, { "bc5", Graphics::SUPPORT_BC5 }, + { "instancing", Graphics::SUPPORT_INSTANCING }, }; StringMap Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries)); diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 994e2bed3..90b87cac3 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -94,6 +94,7 @@ public: SUPPORT_MIPMAP, SUPPORT_DXT, SUPPORT_BC5, + SUPPORT_INSTANCING, SUPPORT_MAX_ENUM }; diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index f73ff7dca..12fa91d91 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -35,6 +35,7 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) , vertex_count(0) , ibo(nullptr) , element_count(0) + , instance_count(1) , draw_mode(mode) , texture(nullptr) , colors_enabled(false) @@ -51,8 +52,8 @@ Mesh::~Mesh() void Mesh::setVertices(const std::vector &verts) { - if (verts.size() < 3) - throw love::Exception("At least 3 vertices are required."); + if (verts.size() == 0) + throw love::Exception("At least one vertex is required."); size_t size = sizeof(Vertex) * verts.size(); @@ -170,6 +171,19 @@ size_t Mesh::getVertexMapCount() const return element_count; } +void Mesh::setInstanceCount(int count) +{ + if (count < 1) + count = 1; + + instance_count = count; +} + +int Mesh::getInstanceCount() const +{ + return instance_count; +} + void Mesh::setTexture(Texture *tex) { tex->retain(); @@ -270,18 +284,27 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo if (ibo && element_count > 0) { + // Use the custom vertex map (index buffer) to draw the vertices. VertexBuffer::Bind ibo_bind(*ibo); // Make sure the index buffer isn't mapped (sends data to GPU if needed.) ibo->unmap(); - // Use the custom vertex map to draw the vertices. - glDrawElements(mode, element_count, GL_UNSIGNED_INT, ibo->getPointer(0)); + const void *indices = ibo->getPointer(0); + const GLenum type = GL_UNSIGNED_INT; + + if (instance_count > 1) + gl.drawElementsInstanced(mode, element_count, type, indices, instance_count); + else + glDrawElements(mode, element_count, type, indices); } else { // Normal non-indexed drawing (no custom vertex map.) - glDrawArrays(mode, 0, vertex_count); + if (instance_count > 1) + gl.drawArraysInstanced(mode, 0, vertex_count, instance_count); + else + glDrawArrays(mode, 0, vertex_count); } if (wireframe) diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 498e501ed..ab2c02967 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -109,6 +109,15 @@ public: **/ size_t getVertexMapCount() const; + /** + * Sets the number of instances of this Mesh to draw (uses hardware + * instancing when possible.) + * A custom vertex shader is necessary in order to introduce differences + * in each instance. + **/ + void setInstanceCount(int count); + int getInstanceCount() const; + /** * Sets the texture used when drawing the Mesh. **/ @@ -165,6 +174,8 @@ private: VertexBuffer *ibo; size_t element_count; + int instance_count; + DrawMode draw_mode; Texture *texture; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 18301f223..cae8c88b9 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -113,6 +113,8 @@ void OpenGL::initContext() initMaxValues(); createDefaultTexture(); + state.lastPseudoInstanceID = -1; + contextInitialized = true; } @@ -214,10 +216,69 @@ void OpenGL::createDefaultTexture() 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(); + Shader *shader = Shader::current; + if (shader != nullptr) + { + // Make sure the active shader has the correct values for its + // love-provided uniforms. + shader->checkSetScreenParams(); + + // Make sure the Instance ID variable is up-to-date when + // pseudo-instancing is used. + if (state.lastPseudoInstanceID != 0 && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID)) + { + glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, 0.0f); + state.lastPseudoInstanceID = 0; + } + } +} + +void OpenGL::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + Shader *shader = Shader::current; + + if (GLEE_ARB_draw_instanced) + glDrawArraysInstancedARB(mode, first, count, primcount); + else + { + bool shaderHasID = shader && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID); + + // Pseudo-instancing fallback. + for (int i = 0; i < primcount; i++) + { + if (shaderHasID) + glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, (GLfloat) i); + + glDrawArrays(mode, first, count); + } + + if (shaderHasID) + state.lastPseudoInstanceID = primcount - 1; + } +} + +void OpenGL::drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) +{ + Shader *shader = Shader::current; + + if (GLEE_ARB_draw_instanced) + glDrawElementsInstancedARB(mode, count, type, indices, primcount); + else + { + bool shaderHasID = shader && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID); + + // Pseudo-instancing fallback. + for (int i = 0; i < primcount; i++) + { + if (shaderHasID) + glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, (GLfloat) i); + + glDrawElements(mode, count, type, indices); + } + + if (shaderHasID) + state.lastPseudoInstanceID = primcount - 1; + } } void OpenGL::setColor(const Color &c) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 29bdcf835..6a27fb6f2 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -63,6 +63,17 @@ public: VENDOR_UNKNOWN }; + // Vertex attributes used in shaders by LOVE. The values map to OpenGL + // generic vertex attribute indices, when applicable. + // LOVE uses the old hard-coded attribute APIs for positions, colors, etc. + // (for now.) + enum VertexAttrib + { + // Instance ID when pseudo-instancing is used. + ATTRIB_PSEUDO_INSTANCE_ID = 1, + ATTRIB_MAX_ENUM + }; + // A rectangle representing an OpenGL viewport or a scissor box. struct Viewport { @@ -99,6 +110,16 @@ public: **/ void prepareDraw(); + /** + * glDrawArraysInstanced with a pseudo-instancing fallback. + **/ + void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount); + + /** + * glDrawElementsInstanced with a pseudo-instancing fallback. + **/ + void drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); + /** * Sets the current constant color. **/ @@ -230,6 +251,9 @@ private: Viewport viewport; Viewport scissor; + // The last ID value used for pseudo-instancing. + int lastPseudoInstanceID; + } state; }; // OpenGL diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 88ebbdac3..b14ea7a74 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -70,6 +70,7 @@ Shader::Shader(const ShaderSources &sources) : shaderSources(sources) , program(0) , builtinUniforms() + , vertexAttributes() , lastCanvas((Canvas *) -1) { if (shaderSources.empty()) @@ -181,6 +182,14 @@ void Shader::createProgram(const std::vector &shaderids) for (it = shaderids.begin(); it != shaderids.end(); ++it) glAttachShader(program, *it); + // Bind generic vertex attribute indices to names in the shader. + for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++) + { + const char *name = nullptr; + if (attribNames.find((OpenGL::VertexAttrib) i, name)) + glBindAttribLocation(program, i, (const GLchar *) name); + } + glLinkProgram(program); // flag shaders for auto-deletion when the program object is deleted. @@ -273,6 +282,15 @@ bool Shader::loadVolatile() // Retreive all active uniform variables in this shader from OpenGL. mapActiveUniforms(); + for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++) + { + const char *name = nullptr; + if (attribNames.find(OpenGL::VertexAttrib(i), name)) + vertexAttributes[i] = glGetAttribLocation(program, name); + else + vertexAttributes[i] = -1; + } + if (current == this) { // make sure glUseProgram gets called. @@ -633,6 +651,11 @@ int Shader::getTextureUnit(const std::string &name) return texunit; } +bool Shader::hasVertexAttrib(OpenGL::VertexAttrib attrib) const +{ + return vertexAttributes[int(attrib)] != -1; +} + bool Shader::hasBuiltinExtern(BuiltinExtern builtin) const { return builtinUniforms[int(builtin)] != -1; @@ -730,6 +753,13 @@ StringMap::Entry Shader::typeNameEntr StringMap Shader::typeNames(Shader::typeNameEntries, sizeof(Shader::typeNameEntries)); +StringMap::Entry Shader::attribNameEntries[] = +{ + {"love_PseudoInstanceID", OpenGL::ATTRIB_PSEUDO_INSTANCE_ID}, +}; + +StringMap Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries)); + StringMap::Entry Shader::builtinNameEntries[] = { {"love_ScreenParams", Shader::BUILTIN_SCREEN_PARAMS}, diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 97fcafc43..ab32bffd7 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -138,6 +138,7 @@ public: /** * Internal use only. **/ + bool hasVertexAttrib(OpenGL::VertexAttrib attrib) const; bool hasBuiltinExtern(BuiltinExtern builtin) const; bool sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *m, int count); void checkSetScreenParams(); @@ -198,6 +199,9 @@ private: // Location values for any built-in uniform variables. GLint builtinUniforms[BUILTIN_MAX_ENUM]; + // Location values for any generic vertex attribute variables. + GLint vertexAttributes[OpenGL::ATTRIB_MAX_ENUM]; + // Uniform location buffer map std::map uniforms; @@ -220,6 +224,10 @@ private: static StringMap::Entry typeNameEntries[]; static StringMap typeNames; + // Names for the generic vertex attributes used by love. + static StringMap::Entry attribNameEntries[]; + static StringMap attribNames; + // Names for the built-in uniform variables. static StringMap::Entry builtinNameEntries[]; static StringMap builtinNames; diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 00387e194..0fcf827b9 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -984,6 +984,10 @@ int w_isSupported(lua_State *L) if (!Image::hasCompressedTextureSupport(image::CompressedData::FORMAT_BC5)) supported = false; break; + case Graphics::SUPPORT_INSTANCING: + if (!GLEE_ARB_draw_instanced) + supported = false; + break; default: supported = false; } diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index 1ea57e755..84c5cfedd 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -236,6 +236,20 @@ int w_Mesh_getVertexMap(lua_State *L) return 1; } +int w_Mesh_setInstanceCount(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + t->setInstanceCount(luaL_checkint(L, 2)); + return 0; +} + +int w_Mesh_getInstanceCount(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + lua_pushinteger(L, t->getInstanceCount()); + return 1; +} + int w_Mesh_setTexture(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); @@ -338,6 +352,8 @@ static const luaL_Reg functions[] = { "getVertexCount", w_Mesh_getVertexCount }, { "setVertexMap", w_Mesh_setVertexMap }, { "getVertexMap", w_Mesh_getVertexMap }, + { "setInstanceCount", w_Mesh_setInstanceCount }, + { "getInstanceCount", w_Mesh_getInstanceCount }, { "setTexture", w_Mesh_setTexture }, { "getTexture", w_Mesh_getTexture }, { "setDrawMode", w_Mesh_setDrawMode }, diff --git a/src/modules/graphics/opengl/wrap_Mesh.h b/src/modules/graphics/opengl/wrap_Mesh.h index efae413dc..2e3a381f2 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.h +++ b/src/modules/graphics/opengl/wrap_Mesh.h @@ -41,6 +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_setInstanceCount(lua_State *L); +int w_Mesh_getInstanceCount(lua_State *L); int w_Mesh_setTexture(lua_State *L); int w_Mesh_getTexture(lua_State *L); int w_Mesh_setDrawMode(lua_State *L); diff --git a/src/scripts/graphics.lua b/src/scripts/graphics.lua index 2af520bcb..0d6ce715e 100644 --- a/src/scripts/graphics.lua +++ b/src/scripts/graphics.lua @@ -1315,7 +1315,15 @@ uniform vec2 love_ScreenParams;]] #define VertexColor gl_Color #define VaryingTexCoord gl_TexCoord[0] -#define VaryingColor gl_FrontColor]], +#define VaryingColor gl_FrontColor + +#if defined(GL_ARB_draw_instanced) + #extension GL_ARB_draw_instanced : enable + #define love_InstanceID gl_InstanceIDARB +#else + attribute float love_PseudoInstanceID; + int love_InstanceID = int(love_PseudoInstanceID); +#endif]], FOOTER = [[ void main() { diff --git a/src/scripts/graphics.lua.h b/src/scripts/graphics.lua.h index c08ac6326..280c4c83c 100644 --- a/src/scripts/graphics.lua.h +++ b/src/scripts/graphics.lua.h @@ -27,7 +27,7 @@ const unsigned char graphics_lua[] = 0x2d, 0x2d, 0x5b, 0x5b, 0x0a, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, - 0x2d, 0x32, 0x30, 0x31, 0x33, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x27, 0x61, 0x73, 0x2d, 0x69, 0x73, 0x27, 0x2c, 0x20, 0x77, @@ -6312,8 +6312,23 @@ const unsigned char graphics_lua[] = 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x67, 0x6c, 0x5f, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x5b, 0x30, 0x5d, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, - 0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x5d, 0x5d, - 0x2c, 0x0a, + 0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x0a, + 0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, + 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x29, 0x0a, + 0x09, 0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, + 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x3a, 0x20, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x0a, + 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x20, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x41, 0x52, 0x42, 0x0a, + 0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a, + 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6c, + 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x3b, 0x0a, + 0x09, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, + 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x29, 0x3b, 0x0a, + 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x5d, 0x5d, 0x2c, 0x0a, 0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, From ba7e69d776a71f0589e61a2ae34cc0e6f1ba8184 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 21 Jan 2014 06:16:47 -0400 Subject: [PATCH 12/56] Added Mesh:setDrawRange(min, max) and Mesh:getDrawRange(). If no vertex map is set, this restricts the drawn vertices to those whose indices in the vertex array are between [min, max] inclusive. If a vertex map is set, this restricts the values used in the vertex map to those whose indices in the vertex map array are between [min, max] inclusive. Added Mesh constructor variant: love.graphics.newMesh(vertexcount, texture, drawmode). Creates a Mesh with a certain number of vertices with x,y,u,v,r,g,b,a values of (0,0,0,0,255,255,255,255). --- src/modules/graphics/opengl/Graphics.cpp | 5 + src/modules/graphics/opengl/Graphics.h | 1 + src/modules/graphics/opengl/Mesh.cpp | 89 ++++++++++++++--- src/modules/graphics/opengl/Mesh.h | 18 ++++ src/modules/graphics/opengl/wrap_Graphics.cpp | 96 ++++++++++--------- src/modules/graphics/opengl/wrap_Mesh.cpp | 34 +++++++ src/modules/graphics/opengl/wrap_Mesh.h | 2 + 7 files changed, 191 insertions(+), 54 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 075887c4a..e6469a512 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -460,6 +460,11 @@ Mesh *Graphics::newMesh(const std::vector &vertices, Mesh::DrawMode mode return new Mesh(vertices, mode); } +Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode mode) +{ + return new Mesh(vertexcount, mode); +} + void Graphics::setColor(const Color &c) { gl.setColor(c); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 1dc2c5c82..54e90e9e7 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -213,6 +213,7 @@ public: Shader *newShader(const Shader::ShaderSources &sources); Mesh *newMesh(const std::vector &vertices, Mesh::DrawMode mode = Mesh::DRAW_MODE_FAN); + Mesh *newMesh(int vertexcount, Mesh::DrawMode mode = Mesh::DRAW_MODE_FAN); /** * Sets the foreground color. diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 12fa91d91..becae3596 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -23,6 +23,9 @@ #include "common/Matrix.h" #include "common/Exception.h" +// C++ +#include + namespace love { namespace graphics @@ -37,6 +40,8 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) , element_count(0) , instance_count(1) , draw_mode(mode) + , range_min(-1) + , range_max(-1) , texture(nullptr) , colors_enabled(false) , wireframe(false) @@ -44,6 +49,35 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) setVertices(verts); } +Mesh::Mesh(int vertexcount, Mesh::DrawMode mode) + : vbo(nullptr) + , vertex_count(0) + , ibo(nullptr) + , element_count(0) + , draw_mode(mode) + , range_min(-1) + , range_max(-1) + , texture(nullptr) + , colors_enabled(false) + , wireframe(false) +{ + if (vertexcount < 1) + throw love::Exception("Invalid number of vertices."); + + std::vector verts(vertexcount); + + // Default-initialized vertices should have a white opaque color. + for (size_t i = 0; i < verts.size(); i++) + { + verts[i].r = 255; + verts[i].g = 255; + verts[i].b = 255; + verts[i].a = 255; + } + + setVertices(verts); +} + Mesh::~Mesh() { delete vbo; @@ -163,7 +197,7 @@ const uint32 *Mesh::getVertexMap() const return (uint32 *) ibo->map(); } - return 0; + return nullptr; } size_t Mesh::getVertexMapCount() const @@ -173,10 +207,7 @@ size_t Mesh::getVertexMapCount() const void Mesh::setInstanceCount(int count) { - if (count < 1) - count = 1; - - instance_count = count; + instance_count = std::max(count, 1); } int Mesh::getInstanceCount() const @@ -217,6 +248,26 @@ Mesh::DrawMode Mesh::getDrawMode() const return draw_mode; } +void Mesh::setDrawRange(int min, int max) +{ + if (min < 0 || max < 0 || min > max) + throw love::Exception("Invalid draw range."); + + range_min = min; + range_max = max; +} + +void Mesh::setDrawRange() +{ + range_min = range_max = -1; +} + +void Mesh::getDrawRange(int &min, int &max) const +{ + min = range_min; + max = range_max; +} + void Mesh::setVertexColors(bool enable) { colors_enabled = enable; @@ -290,21 +341,37 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo // Make sure the index buffer isn't mapped (sends data to GPU if needed.) ibo->unmap(); - const void *indices = ibo->getPointer(0); - const GLenum type = GL_UNSIGNED_INT; + int max = element_count - 1; + if (range_max >= 0) + max = std::min(std::max(range_max, 0), (int) element_count - 1); + + int min = 0; + if (range_min >= 0) + min = std::min(std::max(range_min, 0), max); + + const void *indices = ibo->getPointer(min * sizeof(uint32)); + GLenum type = GL_UNSIGNED_INT; if (instance_count > 1) - gl.drawElementsInstanced(mode, element_count, type, indices, instance_count); + gl.drawElementsInstanced(mode, max - min + 1, type, indices, instance_count); else - glDrawElements(mode, element_count, type, indices); + glDrawElements(mode, max - min + 1, type, indices); } else { + int max = vertex_count - 1; + if (range_max >= 0) + max = std::min(std::max(range_max, 0), (int) vertex_count - 1); + + int min = 0; + if (range_min >= 0) + min = std::min(std::max(range_min, 0), max); + // Normal non-indexed drawing (no custom vertex map.) if (instance_count > 1) - gl.drawArraysInstanced(mode, 0, vertex_count, instance_count); + gl.drawArraysInstanced(mode, min, max - min + 1, instance_count); else - glDrawArrays(mode, 0, vertex_count); + glDrawArrays(mode, min, max - min + 1); } if (wireframe) diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index ab2c02967..7719c1c58 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -22,6 +22,7 @@ #define LOVE_GRAPHICS_OPENGL_MESH_H // LOVE +#include "common/config.h" #include "common/int.h" #include "common/math.h" #include "common/StringMap.h" @@ -64,6 +65,16 @@ public: * @param mode The draw mode to use when drawing the Mesh. **/ Mesh(const std::vector &verts, DrawMode mode = DRAW_MODE_FAN); + + /** + * Constructor. + * Creates a Mesh with a certain number of default-initialized (hidden) + * vertices. + * @param vertexcount The number of vertices to use in the Mesh. + * @param mode The draw mode to use when drawing the Mesh. + **/ + Mesh(int vertexcount, DrawMode mode = DRAW_MODE_FAN); + virtual ~Mesh(); /** @@ -140,6 +151,10 @@ public: void setDrawMode(DrawMode mode); DrawMode getDrawMode() const; + void setDrawRange(int min, int max); + void setDrawRange(); + void getDrawRange(int &min, int &max) const; + /** * Sets whether per-vertex colors are enabled. If this is disabled, the * global color (love.graphics.setColor) will be used for the entire Mesh. @@ -178,6 +193,9 @@ private: DrawMode draw_mode; + int range_min; + int range_max; + Texture *texture; // Whether the per-vertex colors are used when drawing. diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 0fcf827b9..da0aac721 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -440,8 +440,10 @@ int w_newShader(lua_State *L) int w_newMesh(lua_State *L) { - // Check first argument: mandatory table of vertices. - luaL_checktype(L, 1, LUA_TTABLE); + // Check first argument: table of vertices or number of vertices. + int ttype = lua_type(L, 1); + if (ttype != LUA_TTABLE && ttype != LUA_TNUMBER) + luaL_argerror(L, 1, "table or number expected"); // Second argument: optional texture. Texture *tex = nullptr; @@ -456,52 +458,60 @@ int w_newMesh(lua_State *L) if (str && !Mesh::getConstant(str, mode)) return luaL_error(L, "Invalid mesh draw mode: %s", str); - size_t vertex_count = lua_objlen(L, 1); - std::vector vertices; - vertices.reserve(vertex_count); - - bool use_colors = false; - - // Get the vertices from the table. - for (size_t i = 1; i <= vertex_count; i++) - { - lua_rawgeti(L, 1, i); - - if (lua_type(L, -1) != LUA_TTABLE) - return luax_typerror(L, 1, "table of tables"); - - for (int j = 1; j <= 8; j++) - lua_rawgeti(L, -j, j); - - Vertex v; - - v.x = (float) luaL_checknumber(L, -8); - v.y = (float) luaL_checknumber(L, -7); - - v.s = (float) luaL_checknumber(L, -6); - v.t = (float) luaL_checknumber(L, -5); - - v.r = (unsigned char) luaL_optinteger(L, -4, 255); - v.g = (unsigned char) luaL_optinteger(L, -3, 255); - v.b = (unsigned char) luaL_optinteger(L, -2, 255); - v.a = (unsigned char) luaL_optinteger(L, -1, 255); - - // Enable per-vertex coloring if any color is not the default. - if (!use_colors && (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255)) - use_colors = true; - - lua_pop(L, 9); - vertices.push_back(v); - } - Mesh *t = nullptr; - EXCEPT_GUARD(t = instance->newMesh(vertices, mode);) + + if (ttype == LUA_TTABLE) + { + size_t vertex_count = lua_objlen(L, 1); + std::vector vertices; + vertices.reserve(vertex_count); + + bool use_colors = false; + + // Get the vertices from the table. + for (size_t i = 1; i <= vertex_count; i++) + { + lua_rawgeti(L, 1, i); + + if (lua_type(L, -1) != LUA_TTABLE) + return luax_typerror(L, 1, "table of tables"); + + for (int j = 1; j <= 8; j++) + lua_rawgeti(L, -j, j); + + Vertex v; + + v.x = (float) luaL_checknumber(L, -8); + v.y = (float) luaL_checknumber(L, -7); + + v.s = (float) luaL_checknumber(L, -6); + v.t = (float) luaL_checknumber(L, -5); + + v.r = (unsigned char) luaL_optinteger(L, -4, 255); + v.g = (unsigned char) luaL_optinteger(L, -3, 255); + v.b = (unsigned char) luaL_optinteger(L, -2, 255); + v.a = (unsigned char) luaL_optinteger(L, -1, 255); + + // Enable per-vertex coloring if any color is not the default. + if (!use_colors && (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255)) + use_colors = true; + + lua_pop(L, 9); + vertices.push_back(v); + } + + EXCEPT_GUARD(t = instance->newMesh(vertices, mode);) + t->setVertexColors(use_colors); + } + else + { + int count = luaL_checkint(L, 1); + EXCEPT_GUARD(t = instance->newMesh(count, mode);) + } if (tex) t->setTexture(tex); - t->setVertexColors(use_colors); - luax_pushtype(L, "Mesh", GRAPHICS_MESH_T, t); return 1; } diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index 84c5cfedd..4548030a1 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -315,6 +315,38 @@ int w_Mesh_getDrawMode(lua_State *L) return 1; } +int w_Mesh_setDrawRange(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + + if (lua_isnoneornil(L, 2)) + t->setDrawRange(); + else + { + int rangemin = luaL_checkint(L, 2) - 1; + int rangemax = luaL_checkint(L, 3) - 1; + EXCEPT_GUARD(t->setDrawRange(rangemin, rangemax);) + } + + return 0; +} + +int w_Mesh_getDrawRange(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + + int rangemin = -1; + int rangemax = -1; + t->getDrawRange(rangemin, rangemax); + + if (rangemin < 0 || rangemax < 0) + return 0; + + lua_pushinteger(L, rangemin + 1); + lua_pushinteger(L, rangemax + 1); + return 2; +} + int w_Mesh_setVertexColors(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); @@ -358,6 +390,8 @@ static const luaL_Reg functions[] = { "getTexture", w_Mesh_getTexture }, { "setDrawMode", w_Mesh_setDrawMode }, { "getDrawMode", w_Mesh_getDrawMode }, + { "setDrawRange", w_Mesh_setDrawRange }, + { "getDrawRange", w_Mesh_getDrawRange }, { "setVertexColors", w_Mesh_setVertexColors }, { "hasVertexColors", w_Mesh_hasVertexColors }, { "setWireframe", w_Mesh_setWireframe }, diff --git a/src/modules/graphics/opengl/wrap_Mesh.h b/src/modules/graphics/opengl/wrap_Mesh.h index 2e3a381f2..9b4cdc77a 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.h +++ b/src/modules/graphics/opengl/wrap_Mesh.h @@ -47,6 +47,8 @@ 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_setDrawRange(lua_State *L); +int w_Mesh_getDrawRange(lua_State *L); int w_Mesh_setVertexColors(lua_State *L); int w_Mesh_hasVertexColors(lua_State *L); int w_Mesh_setWireframe(lua_State *L); From 10f1e23931e2b43631b4d79ac1bc0f2ac477eed1 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 22 Jan 2014 18:26:10 -0400 Subject: [PATCH 13/56] Increased version to 0.9.1 --- platform/macosx/Info-Framework.plist | 4 ++-- platform/macosx/love-Info.plist | 2 +- src/common/version.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/macosx/Info-Framework.plist b/platform/macosx/Info-Framework.plist index 2bdfccf99..9ac7b9f46 100644 --- a/platform/macosx/Info-Framework.plist +++ b/platform/macosx/Info-Framework.plist @@ -17,11 +17,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.9.0 + 0.9.1 CFBundleSignature LoVe CFBundleVersion - 0.9.0 + 0.9.1 NSPrincipalClass diff --git a/platform/macosx/love-Info.plist b/platform/macosx/love-Info.plist index b14f6022a..c7585e930 100644 --- a/platform/macosx/love-Info.plist +++ b/platform/macosx/love-Info.plist @@ -46,7 +46,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.9.0 + 0.9.1 CFBundleSignature LoVe LSApplicationCategoryType diff --git a/src/common/version.h b/src/common/version.h index d8798f9dc..9a07b4572 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -27,8 +27,8 @@ namespace love // Version stuff. const int VERSION_MAJOR = 0; const int VERSION_MINOR = 9; -const int VERSION_REV = 0; -const char *VERSION = "0.9.0"; +const int VERSION_REV = 1; +const char *VERSION = "0.9.1"; const char *VERSION_COMPATIBILITY[] = { VERSION, 0 }; const char *VERSION_CODENAME = "Baby Inspector"; From 7556fde5e691d98be06f73050d5a99ce231156ba Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 01:31:41 -0400 Subject: [PATCH 14/56] Added antialiasing (MSAA) support to Canvases via a new optional parameter. Added Canvas:getFSAA. --- src/modules/graphics/Drawable.h | 2 +- src/modules/graphics/Texture.h | 2 +- src/modules/graphics/opengl/Canvas.cpp | 269 ++++++++++++++++-- src/modules/graphics/opengl/Canvas.h | 25 +- src/modules/graphics/opengl/Graphics.cpp | 4 +- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/opengl/Image.cpp | 10 +- src/modules/graphics/opengl/Image.h | 10 +- src/modules/graphics/opengl/Mesh.cpp | 2 +- src/modules/graphics/opengl/Mesh.h | 2 +- src/modules/graphics/opengl/OpenGL.cpp | 12 + .../graphics/opengl/ParticleSystem.cpp | 2 +- src/modules/graphics/opengl/ParticleSystem.h | 2 +- src/modules/graphics/opengl/Shader.cpp | 5 + src/modules/graphics/opengl/Shader.h | 2 + src/modules/graphics/opengl/SpriteBatch.cpp | 2 +- src/modules/graphics/opengl/SpriteBatch.h | 2 +- src/modules/graphics/opengl/Texture.h | 4 +- src/modules/graphics/opengl/wrap_Canvas.cpp | 8 + src/modules/graphics/opengl/wrap_Canvas.h | 1 + src/modules/graphics/opengl/wrap_Graphics.cpp | 7 +- 21 files changed, 321 insertions(+), 54 deletions(-) diff --git a/src/modules/graphics/Drawable.h b/src/modules/graphics/Drawable.h index aea03b340..a4cd7e2ff 100644 --- a/src/modules/graphics/Drawable.h +++ b/src/modules/graphics/Drawable.h @@ -55,7 +55,7 @@ public: * @param kx Shear along the x-axis. * @param ky Shear along the y-axis. **/ - virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const = 0; + virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) = 0; }; } // graphics diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index e87c432f4..7b5a525a4 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -88,7 +88,7 @@ public: * @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 void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) = 0; virtual int getWidth() const; virtual int getHeight() const; diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 855830dd1..334f16103 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -63,12 +63,26 @@ struct FramebufferStrategy return false; } + /// Create a MSAA renderbuffer and attach it to the active FBO. + /** + * @param[in] width Width of the MSAA buffer + * @param[in] height Height of the MSAA buffer + * @param[inout] samples Number of samples to use + * @param[in] internalformat The internal format to use for the buffer + * @param[out] buffer Name for the MSAA buffer + * @return Whether the MSAA buffer was successfully created and attached + **/ + virtual bool createMSAABuffer(int, int, int &, GLenum, GLuint &) + { + return false; + } + /// remove objects /** * @param[in] framebuffer Framebuffer name * @param[in] depth_stencil Name for packed depth and stencil buffer */ - virtual void deleteFBO(GLuint, GLuint) {} + virtual void deleteFBO(GLuint, GLuint, GLuint) {} virtual void bindFBO(GLuint) {} /// attach additional canvases to the active framebuffer for rendering @@ -93,8 +107,11 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, texture, 0); + if (texture != 0) + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture, 0); + } // check status GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -118,13 +135,44 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glBindRenderbuffer(GL_RENDERBUFFER, 0); // check status - return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE; + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + glDeleteRenderbuffers(1, &stencil); + stencil = 0; + return false; + } + + return true; } - virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil) + virtual bool createMSAABuffer(int width, int height, int &samples, GLenum internalformat, GLuint &buffer) + { + glGenRenderbuffers(1, &buffer); + glBindRenderbuffer(GL_RENDERBUFFER, buffer); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat, + width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, buffer); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples); + + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + glDeleteRenderbuffers(1, &buffer); + buffer = 0; + return false; + } + + return true; + } + + virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint msaa_buffer) { if (depth_stencil != 0) glDeleteRenderbuffers(1, &depth_stencil); + if (msaa_buffer != 0) + glDeleteRenderbuffers(1, &msaa_buffer); if (framebuffer != 0) glDeleteFramebuffers(1, &framebuffer); } @@ -192,7 +240,7 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy virtual bool createStencil(int width, int height, GLuint &stencil) { // create combined depth/stencil buffer - glDeleteRenderbuffers(1, &stencil); + glDeleteRenderbuffersEXT(1, &stencil); glGenRenderbuffersEXT(1, &stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, @@ -203,13 +251,47 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); // check status - return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT; + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + glDeleteRenderbuffersEXT(1, &stencil); + stencil = 0; + return false; + } + + return true; } - virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil) + virtual bool createMSAABuffer(int width, int height, int &samples, GLenum internalformat, GLuint &buffer) + { + if (!GLEE_EXT_framebuffer_multisample) + return false; + + glGenRenderbuffersEXT(1, &buffer); + glBindRenderbufferEXT(GL_RENDERBUFFER, buffer); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, + internalformat, width, height); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, buffer); + glGetRenderbufferParameterivEXT(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples); + + glBindRenderbufferEXT(GL_RENDERBUFFER, 0); + + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + glDeleteRenderbuffersEXT(1, &buffer); + buffer = 0; + return false; + } + + return true; + } + + virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint msaa_buffer) { if (depth_stencil != 0) glDeleteRenderbuffersEXT(1, &depth_stencil); + if (msaa_buffer != 0) + glDeleteRenderbuffersEXT(1, &msaa_buffer); if (framebuffer != 0) glDeleteFramebuffersEXT(1, &framebuffer); } @@ -257,7 +339,7 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT virtual bool createStencil(int width, int height, GLuint &stencil) { // create stencil buffer - glDeleteRenderbuffers(1, &stencil); + glDeleteRenderbuffersEXT(1, &stencil); glGenRenderbuffersEXT(1, &stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, @@ -268,14 +350,21 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); // check status - return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT; + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + glDeleteRenderbuffersEXT(1, &stencil); + stencil = 0; + return false; + } + + return true; } bool isSupported() { GLuint fb = 0, stencil = 0; GLenum status = createFBO(fb, 0); - deleteFBO(fb, stencil); + deleteFBO(fb, stencil, 0); return status == GL_FRAMEBUFFER_COMPLETE; } }; @@ -311,11 +400,15 @@ static void getStrategy() static int maxFBOColorAttachments = 0; static int maxDrawBuffers = 0; -Canvas::Canvas(int width, int height, TextureType texture_type) +Canvas::Canvas(int width, int height, TextureType texture_type, int fsaa) : fbo(0) + , resolve_fbo(0) , texture(0) + , fsaa_buffer(0) , depth_stencil(0) , texture_type(texture_type) + , fsaa_samples(fsaa) + , fsaa_dirty(false) { this->width = width; this->height = height; @@ -357,9 +450,50 @@ Canvas::~Canvas() unloadVolatile(); } +bool Canvas::createFSAAFBO(GLenum internalformat) +{ + // Create our FBO without a texture. + status = strategy->createFBO(fbo, 0); + + GLuint previous = 0; + if (current != this) + { + if (current != nullptr) + previous = current->fbo; + + strategy->bindFBO(fbo); + } + + // Create and attach the MSAA buffer for our FBO. + if (strategy->createMSAABuffer(width, height, fsaa_samples, internalformat, fsaa_buffer)) + status = GL_FRAMEBUFFER_COMPLETE; + else + status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + + // Create the FBO used for the MSAA resolve, and attach the texture. + if (status == GL_FRAMEBUFFER_COMPLETE) + status = strategy->createFBO(resolve_fbo, texture); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + // Clean up. + strategy->deleteFBO(fbo, 0, fsaa_buffer); + strategy->deleteFBO(resolve_fbo, 0, 0); + fbo = fsaa_buffer = resolve_fbo = 0; + fsaa_samples = 0; + } + + if (current != this) + strategy->bindFBO(previous); + + return status == GL_FRAMEBUFFER_COMPLETE; +} + bool Canvas::loadVolatile() { fbo = depth_stencil = texture = 0; + resolve_fbo = fsaa_buffer = 0; + status = GL_FRAMEBUFFER_COMPLETE; // glTexImage2D is guaranteed to error in this case. if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize()) @@ -406,7 +540,25 @@ bool Canvas::loadVolatile() return false; } - status = strategy->createFBO(fbo, texture); + int max_samples = 0; + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object + || GLEE_EXT_framebuffer_multisample) + { + glGetIntegerv(GL_MAX_SAMPLES, &max_samples); + } + + if (fsaa_samples > max_samples) + fsaa_samples = max_samples; + + // Try to create a FSAA FBO if requested. + bool fsaasuccess = false; + if (fsaa_samples > 1) + fsaasuccess = createFSAAFBO(internalformat); + + // On failure (or no requested FSAA), fall back to a regular FBO. + if (!fsaasuccess) + status = strategy->createFBO(fbo, texture); + if (status != GL_FRAMEBUFFER_COMPLETE) return false; @@ -416,11 +568,13 @@ bool Canvas::loadVolatile() void Canvas::unloadVolatile() { - strategy->deleteFBO(fbo, depth_stencil); + strategy->deleteFBO(fbo, depth_stencil, fsaa_buffer); + strategy->deleteFBO(resolve_fbo, 0, 0); gl.deleteTexture(texture); fbo = depth_stencil = texture = 0; + resolve_fbo = fsaa_buffer = 0; for (size_t i = 0; i < attachedCanvases.size(); i++) attachedCanvases[i]->release(); @@ -428,13 +582,12 @@ void Canvas::unloadVolatile() attachedCanvases.clear(); } -void Canvas::drawv(const Matrix &t, const Vertex *v) const +void Canvas::drawv(const Matrix &t, const Vertex *v) { glPushMatrix(); - glMultMatrixf((const GLfloat *)t.getElements()); - gl.bindTexture(texture); + predraw(); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -447,11 +600,13 @@ void Canvas::drawv(const Matrix &t, const Vertex *v) const glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); + + postdraw(); glPopMatrix(); } -void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const +void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { static Matrix t; t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); @@ -459,7 +614,7 @@ void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, f 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 +void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { static Matrix t; t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); @@ -487,8 +642,12 @@ GLuint Canvas::getGLTexture() const return texture; } -void Canvas::predraw() const +void Canvas::predraw() { + // We need to make sure the texture is up-to-date by resolving the MSAA + // buffer (which we render to when the canvas is active) to it. + resolveMSAA(); + gl.bindTexture(texture); } @@ -520,6 +679,9 @@ void Canvas::setupGrab() // indicate we are using this fbo current = this; + + if (fsaa_buffer != 0) + fsaa_dirty = true; } void Canvas::startGrab(const std::vector &canvases) @@ -535,6 +697,9 @@ void Canvas::startGrab(const std::vector &canvases) if (canvases.size()+1 > size_t(maxDrawBuffers) || canvases.size()+1 > size_t(maxFBOColorAttachments)) throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1); + + if (fsaa_samples != 0) + throw love::Exception("Multi-canvas rendering is not supported with FSAA."); } for (size_t i = 0; i < canvases.size(); i++) @@ -545,6 +710,9 @@ void Canvas::startGrab(const std::vector &canvases) if (canvases[i]->getTextureType() != texture_type) throw love::Exception("All canvas arguments must have the same texture type."); + if (canvases[i]->getFSAA() != 0) + throw love::Exception("Multi-canvas rendering is not supported with FSAA."); + if (!canvaseschanged && canvases[i] != attachedCanvases[i]) canvaseschanged = true; } @@ -674,12 +842,22 @@ bool Canvas::checkCreateStencil() love::image::ImageData *Canvas::getImageData(love::image::Image *image) { + resolveMSAA(); + int row = 4 * width; int size = row * height; GLubyte *pixels = new GLubyte[size]; - strategy->bindFBO(fbo); + // Our texture is attached to 'resolve_fbo' when we use MSAA. + if (fsaa_samples > 1 && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)) + glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo); + else if (fsaa_samples > 1 && GLEE_EXT_framebuffer_multisample) + glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo); + else + strategy->bindFBO(fbo); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + if (current) strategy->bindFBO(current->fbo); else @@ -692,10 +870,17 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image) void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y) { - if (current != this) + resolveMSAA(); + + // Our texture is attached to 'resolve_fbo' when we use MSAA. + if (fsaa_samples > 1 && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)) + glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo); + else if (fsaa_samples > 1 && GLEE_EXT_framebuffer_multisample) + glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo); + else if (current != this) strategy->bindFBO(fbo); - glReadPixels(x, height - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_rgba); + glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_rgba); if (current && current != this) strategy->bindFBO(current->fbo); @@ -703,6 +888,44 @@ void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y) strategy->bindFBO(0); } +bool Canvas::resolveMSAA() +{ + if (resolve_fbo == 0 || fsaa_buffer == 0) + return false; + + if (!fsaa_dirty) + return true; + + GLuint previous = 0; + if (current != nullptr) + previous = current->fbo; + + // Do the MSAA resolve by blitting the MSAA renderbuffer to the texture. + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object) + { + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo); + glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + else if (GLEE_EXT_framebuffer_multisample && GLEE_EXT_framebuffer_blit) + { + glBindFramebufferEXT(GL_READ_FRAMEBUFFER, fbo); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, resolve_fbo); + glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + else + return false; + + strategy->bindFBO(previous); + + if (current != this) + fsaa_dirty = false; + + return true; +} + bool Canvas::isSupported() { getStrategy(); diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index e9e9f7ca0..f643294fc 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -46,7 +46,7 @@ public: TYPE_MAX_ENUM }; - Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL); + Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL, int fsaa = 0); virtual ~Canvas(); // Implements Volatile. @@ -54,14 +54,14 @@ public: 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; + virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); // 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 drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); virtual void setFilter(const Texture::Filter &f); virtual void setWrap(const Texture::Wrap &w); virtual GLuint getGLTexture() const; - virtual void predraw() const; + virtual void predraw(); /** * @param canvases A list of other canvases to temporarily attach to this one, @@ -97,6 +97,13 @@ public: return texture_type; } + inline int getFSAA() const + { + return fsaa_samples; + } + + bool resolveMSAA(); + static bool isSupported(); static bool isHDRSupported(); static bool isMultiCanvasSupported(); @@ -112,8 +119,13 @@ public: private: + bool createFSAAFBO(GLenum internalformat); + GLuint fbo; + GLuint resolve_fbo; + GLuint texture; + GLuint fsaa_buffer; GLuint depth_stencil; TextureType texture_type; @@ -122,8 +134,11 @@ private: std::vector attachedCanvases; + int fsaa_samples; + bool fsaa_dirty; + void setupGrab(); - void drawv(const Matrix &t, const Vertex *v) const; + void drawv(const Matrix &t, const Vertex *v); static StringMap::Entry textureTypeEntries[]; static StringMap textureTypes; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index e6469a512..a8144c15c 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -392,7 +392,7 @@ ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size) return new ParticleSystem(texture, size); } -Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type) +Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type, int fsaa) { if (texture_type == Canvas::TYPE_HDR && !Canvas::isHDRSupported()) throw Exception("HDR Canvases are not supported by your OpenGL implementation"); @@ -405,7 +405,7 @@ Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_t while (GL_NO_ERROR != glGetError()) /* clear opengl error flag */; - Canvas *canvas = new Canvas(width, height, texture_type); + Canvas *canvas = new Canvas(width, height, texture_type, fsaa); GLenum err = canvas->getStatus(); // everything ok, return canvas (early out) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 54e90e9e7..b63ae801a 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -208,7 +208,7 @@ public: ParticleSystem *newParticleSystem(Texture *texture, int size); - Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL); + Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL, int fsaa = 0); Shader *newShader(const Shader::ShaderSources &sources); diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 2d7719656..e3ef771dd 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -91,7 +91,7 @@ love::image::CompressedData *Image::getCompressedData() const return cdata; } -void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const +void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { Matrix t; t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); @@ -99,7 +99,7 @@ void Image::draw(float x, float y, float angle, float sx, float sy, float ox, fl drawv(t, vertices); } -void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const +void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { Matrix t; t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); @@ -107,7 +107,7 @@ void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, drawv(t, quad->getVertices()); } -void Image::predraw() const +void Image::predraw() { bind(); @@ -121,7 +121,7 @@ void Image::predraw() const } } -void Image::postdraw() const +void Image::postdraw() { if (width != paddedWidth || height != paddedHeight) { @@ -511,7 +511,7 @@ void Image::uploadDefaultTexture() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, px); } -void Image::drawv(const Matrix &t, const Vertex *v) const +void Image::drawv(const Matrix &t, const Vertex *v) { predraw(); diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 0622fb8dc..865c5f3bd 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -76,20 +76,20 @@ public: /** * @copydoc Drawable::draw() **/ - void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; + void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); /** * @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; + void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); /** * Call before using this Image's texture to draw. Binds the texture, * globally scales texture coordinates if the Image has NPOT dimensions and * NPOT isn't supported, etc. **/ - virtual void predraw() const; - virtual void postdraw() const; + virtual void predraw(); + virtual void postdraw(); virtual GLuint getGLTexture() const; @@ -137,7 +137,7 @@ private: void uploadDefaultTexture(); - void drawv(const Matrix &t, const Vertex *v) const; + void drawv(const Matrix &t, const Vertex *v); // The ImageData from which the texture is created. May be null if // Compressed image data was used to create the texture. diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index becae3596..d440bc786 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -288,7 +288,7 @@ bool Mesh::isWireframe() const return wireframe; } -void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const +void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { const size_t pos_offset = offsetof(Vertex, x); const size_t tex_offset = offsetof(Vertex, s); diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 7719c1c58..3a5029a4d 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -172,7 +172,7 @@ public: bool isWireframe() const; // Implements Drawable. - void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; + void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); static bool getConstant(const char *in, DrawMode &out); static bool getConstant(DrawMode in, const char *&out); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index cae8c88b9..6b3ca1d5f 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -230,6 +230,18 @@ void OpenGL::prepareDraw() glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, 0.0f); state.lastPseudoInstanceID = 0; } + + // We need to make sure antialiased Canvases are properly resolved + // before sampling from their textures in a shader. + // This is kind of a big hack. :( + const std::map &r = shader->getBoundRetainables(); + for (auto it = r.begin(); it != r.end(); ++it) + { + // Even bigger hack! D: + Canvas *canvas = dynamic_cast(it->second); + if (canvas != nullptr) + canvas->resolveMSAA(); + } } } diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 3f176a00b..04bdbee87 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -780,7 +780,7 @@ bool ParticleSystem::isFull() const return activeParticles == maxParticles; } -void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const +void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { uint32 pCount = getCount(); if (pCount == 0 || texture == nullptr || pMem == nullptr || particleVerts == nullptr) diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 14b37a1c4..1314578a9 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -470,7 +470,7 @@ public: * @param x The x-coordinate. * @param y The y-coordinate. **/ - virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; + virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); /** * Updates the particle system. diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index b14ea7a74..365a52569 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -719,6 +719,11 @@ void Shader::checkSetScreenParams() lastCanvas = Canvas::current; } +const std::map &Shader::getBoundRetainables() const +{ + return boundRetainables; +} + std::string Shader::getGLSLVersion() { const char *tmp = nullptr; diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index ab32bffd7..937d79308 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -143,6 +143,8 @@ public: bool sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *m, int count); void checkSetScreenParams(); + const std::map &getBoundRetainables() const; + static std::string getGLSLVersion(); static bool isSupported(); diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 7b583c4b8..032e8769e 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -263,7 +263,7 @@ int SpriteBatch::getBufferSize() const return size; } -void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const +void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { const size_t vertex_offset = offsetof(Vertex, x); const size_t texel_offset = offsetof(Vertex, s); diff --git a/src/modules/graphics/opengl/SpriteBatch.h b/src/modules/graphics/opengl/SpriteBatch.h index de14bf099..ae79db8d6 100644 --- a/src/modules/graphics/opengl/SpriteBatch.h +++ b/src/modules/graphics/opengl/SpriteBatch.h @@ -109,7 +109,7 @@ public: int getBufferSize() const; // Implements Drawable. - void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; + void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); static bool getConstant(const char *in, UsageHint &out); static bool getConstant(UsageHint in, const char *&out); diff --git a/src/modules/graphics/opengl/Texture.h b/src/modules/graphics/opengl/Texture.h index 6dee55350..3a02decbd 100644 --- a/src/modules/graphics/opengl/Texture.h +++ b/src/modules/graphics/opengl/Texture.h @@ -48,12 +48,12 @@ public: * Any setup the texture might need to do before drawing, e.g. binding * the OpenGL texture for use. **/ - virtual void predraw() const {} + virtual void predraw() {} /** * Any cleanup the texture might need to do directly after drawing. **/ - virtual void postdraw() const {} + virtual void postdraw() {} }; // Texture diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 9a4669563..cbc9b6ed9 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -120,6 +120,13 @@ int w_Canvas_getType(lua_State *L) return 1; } +int w_Canvas_getFSAA(lua_State *L) +{ + Canvas *canvas = luax_checkcanvas(L, 1); + lua_pushinteger(L, canvas->getFSAA()); + return 1; +} + static const luaL_Reg functions[] = { // From wrap_Texture. @@ -136,6 +143,7 @@ static const luaL_Reg functions[] = { "getPixel", w_Canvas_getPixel }, { "clear", w_Canvas_clear }, { "getType", w_Canvas_getType }, + { "getFSAA", w_Canvas_getFSAA }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Canvas.h b/src/modules/graphics/opengl/wrap_Canvas.h index 4a6bea87b..89c7952f2 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.h +++ b/src/modules/graphics/opengl/wrap_Canvas.h @@ -40,6 +40,7 @@ int w_Canvas_getImageData(lua_State *L); int w_Canvas_getPixel(lua_State * L); int w_Canvas_clear(lua_State *L); int w_Canvas_getType(lua_State *L); +int w_Canvas_getFSAA(lua_State *L); extern "C" int luaopen_canvas(lua_State *L); } // opengl diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index da0aac721..3118fb5e2 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -323,15 +323,16 @@ int w_newCanvas(lua_State *L) int width = luaL_optint(L, 1, instance->getWidth()); int height = luaL_optint(L, 2, instance->getHeight()); const char *str = luaL_optstring(L, 3, "normal"); + int fsaa = luaL_optint(L, 4, 0); Canvas::TextureType texture_type; if (!Canvas::getConstant(str, texture_type)) return luaL_error(L, "Invalid canvas type: %s", str); - Canvas *canvas = 0; - EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type);) + Canvas *canvas = nullptr; + EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type, fsaa);) - if (canvas == 0) + if (canvas == nullptr) return luaL_error(L, "Canvas not created, but no error thrown. I don't even..."); luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, canvas); From 988404e4ca5091f64464dcc89fab3f2a4313cd53 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 02:19:30 -0400 Subject: [PATCH 15/56] Added love.graphics.getSystemLimit (resolves issue #840). Deprecated love.graphics.getMaxPointSize. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit love.graphics.getSystemLimit currently accepts these enum strings: “pointsize”, “texturesize”, “multicanvas”, and “canvasfsaa”. --- src/modules/graphics/Graphics.cpp | 20 ++++++++ src/modules/graphics/Graphics.h | 15 ++++++ src/modules/graphics/opengl/Canvas.cpp | 13 +---- src/modules/graphics/opengl/Graphics.cpp | 47 ++++++++++++++----- src/modules/graphics/opengl/Graphics.h | 16 ++----- src/modules/graphics/opengl/OpenGL.cpp | 19 ++++++++ src/modules/graphics/opengl/OpenGL.h | 6 +++ src/modules/graphics/opengl/wrap_Graphics.cpp | 20 ++++++-- src/modules/graphics/opengl/wrap_Graphics.h | 1 + 9 files changed, 119 insertions(+), 38 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 9d3e20a0a..f29ae4a47 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -109,6 +109,16 @@ bool Graphics::getConstant(RendererInfo in, const char *&out) return rendererInfo.find(in, out); } +bool Graphics::getConstant(const char *in, SystemLimit &out) +{ + return systemLimits.find(in, out); +} + +bool Graphics::getConstant(SystemLimit in, const char *&out) +{ + return systemLimits.find(in, out); +} + StringMap::Entry Graphics::drawModeEntries[] = { { "line", Graphics::DRAW_LINE }, @@ -190,5 +200,15 @@ StringMap::Entry Graph StringMap Graphics::rendererInfo(Graphics::rendererInfoEntries, sizeof(Graphics::rendererInfoEntries)); +StringMap::Entry Graphics::systemLimitEntries[] = +{ + {"pointsize", Graphics::LIMIT_POINT_SIZE}, + {"texturesize", Graphics::LIMIT_TEXTURE_SIZE}, + {"multicanvas", Graphics::LIMIT_MULTI_CANVAS}, + {"canvasfsaa", Graphics::LIMIT_CANVAS_FSAA}, +}; + +StringMap Graphics::systemLimits(Graphics::systemLimitEntries, sizeof(Graphics::systemLimitEntries)); + } // graphics } // love diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 90b87cac3..25fc45c50 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -107,6 +107,15 @@ public: RENDERER_INFO_MAX_ENUM }; + enum SystemLimit + { + LIMIT_POINT_SIZE, + LIMIT_TEXTURE_SIZE, + LIMIT_MULTI_CANVAS, + LIMIT_CANVAS_FSAA, + LIMIT_MAX_ENUM + }; + virtual ~Graphics(); /** @@ -151,6 +160,9 @@ public: static bool getConstant(const char *in, RendererInfo &out); static bool getConstant(RendererInfo in, const char *&out); + static bool getConstant(const char *in, SystemLimit &out); + static bool getConstant(SystemLimit in, const char *&out); + private: static StringMap::Entry drawModeEntries[]; @@ -177,6 +189,9 @@ private: static StringMap::Entry rendererInfoEntries[]; static StringMap rendererInfo; + static StringMap::Entry systemLimitEntries[]; + static StringMap systemLimits; + }; // Graphics } // graphics diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 334f16103..afadd448a 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -939,17 +939,8 @@ bool Canvas::isHDRSupported() bool Canvas::isMultiCanvasSupported() { - 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); - } - - // system must support at least 4 simultanious active canvases - return maxFBOColorAttachments >= 4 && maxDrawBuffers >= 4; + // system must support at least 4 simultanious active canvases. + return gl.getMaxRenderTargets() >= 4; } void Canvas::bindDefaultCanvas() diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index a8144c15c..51f849f96 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -313,11 +313,6 @@ void Graphics::discardStencil() glDisable(GL_STENCIL_TEST); } -int Graphics::getMaxTextureSize() const -{ - return gl.getMaxTextureSize(); -} - Image *Graphics::newImage(love::image::ImageData *data) { // Create the image. @@ -717,13 +712,6 @@ Graphics::PointStyle Graphics::getPointStyle() const return POINT_ROUGH; } -int Graphics::getMaxPointSize() const -{ - GLint max; - glGetIntegerv(GL_POINT_SIZE_MAX, &max); - return (int)max; -} - 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 != nullptr) @@ -1031,6 +1019,41 @@ std::string Graphics::getRendererInfo(Graphics::RendererInfo infotype) const return std::string(infostr); } +double Graphics::getSystemLimit(SystemLimit limittype) const +{ + double limit = 0.0; + + switch (limittype) + { + case Graphics::LIMIT_POINT_SIZE: + { + GLfloat limits[2]; + glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, limits); + limit = limits[1]; + } + break; + case Graphics::LIMIT_TEXTURE_SIZE: + limit = (double) gl.getMaxTextureSize(); + break; + case Graphics::LIMIT_MULTI_CANVAS: + limit = (double) gl.getMaxRenderTargets(); + break; + case Graphics::LIMIT_CANVAS_FSAA: + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object + || GLEE_EXT_framebuffer_multisample) + { + GLint intlimit = 0; + glGetIntegerv(GL_MAX_SAMPLES, &intlimit); + limit = (double) intlimit; + } + break; + default: + break; + } + + return limit; +} + void Graphics::push() { if (userMatrices == matrixLimit) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index b63ae801a..070794941 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -186,11 +186,6 @@ public: */ void discardStencil(); - /** - * Gets the maximum supported width or height of Textures on this system. - **/ - int getMaxTextureSize() const; - /** * Creates an Image object with padding and/or optimization. **/ @@ -337,12 +332,6 @@ public: **/ PointStyle getPointStyle() const; - /** - * Gets the maximum point size supported. - * This may vary from computer to computer. - **/ - int getMaxPointSize() const; - /** * Draws text at the specified coordinates, with rotation and * scaling along both axes. @@ -444,6 +433,11 @@ public: **/ std::string getRendererInfo(Graphics::RendererInfo infotype) const; + /** + * Gets the system-dependent numeric limit for the specified parameter. + **/ + double getSystemLimit(SystemLimit limittype) const; + void push(); void pop(); void rotate(float r); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 6b3ca1d5f..f07120f65 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -43,6 +43,7 @@ OpenGL::OpenGL() : contextInitialized(false) , maxAnisotropy(1.0f) , maxTextureSize(0) + , maxRenderTargets(0) , vendor(VENDOR_UNKNOWN) , state() { @@ -190,6 +191,19 @@ void OpenGL::initMaxValues() maxAnisotropy = 1.0f; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + + if (Canvas::isSupported() && (GLEE_VERSION_2_0 || GLEE_ARB_draw_buffers)) + { + int maxattachments = 0; + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxattachments); + + int maxdrawbuffers = 0; + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers); + + maxRenderTargets = std::min(maxattachments, maxdrawbuffers); + } + else + maxRenderTargets = 0; } void OpenGL::createDefaultTexture() @@ -577,6 +591,11 @@ int OpenGL::getMaxTextureSize() const return maxTextureSize; } +int OpenGL::getMaxRenderTargets() const +{ + return maxRenderTargets; +} + OpenGL::Vendor OpenGL::getVendor() const { return vendor; diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 6a27fb6f2..602770164 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -215,6 +215,11 @@ public: **/ int getMaxTextureSize() const; + /** + * Returns the maximum supported number of simultaneous render targets. + **/ + int getMaxRenderTargets() const; + /** * Get the GPU vendor of this OpenGL context. **/ @@ -231,6 +236,7 @@ private: float maxAnisotropy; int maxTextureSize; + int maxRenderTargets; Vendor vendor; diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 3118fb5e2..4026de632 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -146,7 +146,7 @@ int w_setInvertedStencil(lua_State *L) int w_getMaxTextureSize(lua_State *L) { - lua_pushinteger(L, instance->getMaxTextureSize()); + lua_pushinteger(L, instance->getSystemLimit(Graphics::LIMIT_TEXTURE_SIZE)); return 1; } @@ -831,7 +831,7 @@ int w_getPointStyle(lua_State *L) int w_getMaxPointSize(lua_State *L) { - lua_pushnumber(L, instance->getMaxPointSize()); + lua_pushnumber(L, instance->getSystemLimit(Graphics::LIMIT_POINT_SIZE)); return 1; } @@ -1026,6 +1026,18 @@ int w_getRendererInfo(lua_State *L) return 4; } +int w_getSystemLimit(lua_State *L) +{ + const char *limitstr = luaL_checkstring(L, 1); + Graphics::SystemLimit limittype; + + if (!Graphics::getConstant(limitstr, limittype)) + return luaL_error(L, "Invalid system limit type: %s", limitstr); + + lua_pushnumber(L, instance->getSystemLimit(limittype)); + return 1; +} + int w_draw(lua_State *L) { Drawable *drawable = nullptr; @@ -1363,8 +1375,6 @@ static const luaL_Reg functions[] = { "setPointStyle", w_setPointStyle }, { "getPointSize", w_getPointSize }, { "getPointStyle", w_getPointStyle }, - { "getMaxPointSize", w_getMaxPointSize }, - { "getMaxTextureSize", w_getMaxTextureSize }, { "newScreenshot", w_newScreenshot }, { "setCanvas", w_setCanvas }, { "getCanvas", w_getCanvas }, @@ -1374,6 +1384,7 @@ static const luaL_Reg functions[] = { "isSupported", w_isSupported }, { "getRendererInfo", w_getRendererInfo }, + { "getSystemLimit", w_getSystemLimit }, { "draw", w_draw }, @@ -1409,6 +1420,7 @@ static const luaL_Reg functions[] = // Deprecated since 0.9.1. { "getMaxImageSize", w_getMaxTextureSize }, + { "getMaxPointSize", w_getMaxPointSize }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Graphics.h b/src/modules/graphics/opengl/wrap_Graphics.h index 4514bb68b..60c525121 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.h +++ b/src/modules/graphics/opengl/wrap_Graphics.h @@ -92,6 +92,7 @@ int w_setShader(lua_State *L); int w_getShader(lua_State *L); int w_isSupported(lua_State *L); int w_getRendererInfo(lua_State *L); +int w_getSystemLimit(lua_State *L); int w_draw(lua_State *L); int w_print(lua_State *L); int w_printf(lua_State *L); From 3a24e73891cef3294fe9430bb7f6f7906f7ef01d Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 02:28:38 -0400 Subject: [PATCH 16/56] =?UTF-8?q?0.9.1=E2=80=99s=20API=20is=20designed=20t?= =?UTF-8?q?o=20be=20backwards-compatible=20with=200.9.0=20games=20(resolve?= =?UTF-8?q?s=20issue=20#839)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/version.h b/src/common/version.h index 9a07b4572..5e3e15f72 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -29,7 +29,7 @@ const int VERSION_MAJOR = 0; const int VERSION_MINOR = 9; const int VERSION_REV = 1; const char *VERSION = "0.9.1"; -const char *VERSION_COMPATIBILITY[] = { VERSION, 0 }; +const char *VERSION_COMPATIBILITY[] = { VERSION, "0.9.0", 0 }; const char *VERSION_CODENAME = "Baby Inspector"; } // love From c5c788e976b838a54ac30941db2d250549c613d2 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 02:58:34 -0400 Subject: [PATCH 17/56] =?UTF-8?q?Added=20a=20built-in=20variable=20readabl?= =?UTF-8?q?e=20in=20shaders:=20=E2=80=98love=5FScreenSize=E2=80=99.=20Its?= =?UTF-8?q?=20x=20and=20y=20components=20contain=20the=20width=20and=20hei?= =?UTF-8?q?ght=20of=20the=20current=20viewport.=20Resolves=20issue=20#841.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/graphics/opengl/OpenGL.h | 5 +++++ src/modules/graphics/opengl/Shader.cpp | 26 +++++++++++++++++--------- src/modules/graphics/opengl/Shader.h | 3 ++- src/scripts/graphics.lua | 6 +++--- src/scripts/graphics.lua.h | 16 ++++++++-------- 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 602770164..8e61c012e 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -87,6 +87,11 @@ public: Viewport(int _x, int _y, int _w, int _h) : x(_x), y(_y), w(_w), h(_h) {} + + bool operator == (const Viewport &rhs) const + { + return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h; + } }; OpenGL(); diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 365a52569..7b94e805c 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -72,6 +72,7 @@ Shader::Shader(const ShaderSources &sources) , builtinUniforms() , vertexAttributes() , lastCanvas((Canvas *) -1) + , lastViewport() { if (shaderSources.empty()) throw love::Exception("Cannot create shader: no source code!"); @@ -693,30 +694,37 @@ bool Shader::sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *ve void Shader::checkSetScreenParams() { - if (lastCanvas == Canvas::current) + OpenGL::Viewport view = gl.getViewport(); + + if (view == lastViewport && lastCanvas == Canvas::current) return; - // In the shader, we do pixcoord.y = gl_FragCoord.y * params[0] + params[1]. + // In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w. // 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}; + GLfloat params[] = { + (GLfloat) view.w, (GLfloat) view.h, + 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(); + params[2] = -1.0f; + params[3] = (GLfloat) view.h; } else { // No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0. - params[0] = 1.0f; - params[1] = 0.0f; + params[2] = 1.0f; + params[3] = 0.0f; } - sendBuiltinFloat(BUILTIN_SCREEN_PARAMS, 2, params, 1); + sendBuiltinFloat(BUILTIN_SCREEN_SIZE, 4, params, 1); + lastCanvas = Canvas::current; + lastViewport = view; } const std::map &Shader::getBoundRetainables() const @@ -767,7 +775,7 @@ StringMap Shader::attribNames(Sha StringMap::Entry Shader::builtinNameEntries[] = { - {"love_ScreenParams", Shader::BUILTIN_SCREEN_PARAMS}, + {"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE}, }; StringMap Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries)); diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 937d79308..db116cc47 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -59,7 +59,7 @@ public: // Built-in extern (uniform) variables. enum BuiltinExtern { - BUILTIN_SCREEN_PARAMS, + BUILTIN_SCREEN_SIZE, BUILTIN_MAX_ENUM }; @@ -216,6 +216,7 @@ private: // Pointer to the active Canvas when the screen params were last checked. Canvas *lastCanvas; + OpenGL::Viewport lastViewport; // Max GPU texture units available for sent images static GLint maxTexUnits; diff --git a/src/scripts/graphics.lua b/src/scripts/graphics.lua index 0d6ce715e..4b2b9b814 100644 --- a/src/scripts/graphics.lua +++ b/src/scripts/graphics.lua @@ -1304,7 +1304,7 @@ do #define TransformProjectionMatrix gl_ModelViewProjectionMatrix #define NormalMatrix gl_NormalMatrix uniform sampler2D _tex0_; -uniform vec2 love_ScreenParams;]] +uniform vec4 love_ScreenSize;]] local GLSL_VERTEX = { HEADER = [[ @@ -1346,7 +1346,7 @@ void main() { float dummy = texture2D(_tex0_, vec2(.5)).r; // See Shader::checkSetScreenParams in Shader.cpp. - vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenParams[0]) + love_ScreenParams[1]); + vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w); gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord); }]], @@ -1357,7 +1357,7 @@ void main() { float dummy = texture2D(_tex0_, vec2(.5)).r; // See Shader::checkSetScreenParams in Shader.cpp. - vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenParams[0]) + love_ScreenParams[1]); + vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w); effects(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord); }]], diff --git a/src/scripts/graphics.lua.h b/src/scripts/graphics.lua.h index 280c4c83c..b89461c99 100644 --- a/src/scripts/graphics.lua.h +++ b/src/scripts/graphics.lua.h @@ -6295,8 +6295,8 @@ const unsigned char graphics_lua[] = 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, 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, + 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, + 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a, 0x65, 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, @@ -6365,9 +6365,9 @@ const unsigned char graphics_lua[] = 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, + 0x79, 0x20, 0x2a, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a, + 0x65, 0x2e, 0x7a, 0x29, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, + 0x53, 0x69, 0x7a, 0x65, 0x2e, 0x77, 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, @@ -6390,9 +6390,9 @@ const unsigned char graphics_lua[] = 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, + 0x79, 0x20, 0x2a, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a, + 0x65, 0x2e, 0x7a, 0x29, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, + 0x53, 0x69, 0x7a, 0x65, 0x2e, 0x77, 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, 0x70, 0x69, 0x78, From 0da21a430a180e99204016c7388c580e2d711509 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 18:44:00 -0400 Subject: [PATCH 18/56] Mac: enabled link-time optimization for Release builds of love --- platform/macosx/love-framework.xcodeproj/project.pbxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/macosx/love-framework.xcodeproj/project.pbxproj b/platform/macosx/love-framework.xcodeproj/project.pbxproj index dedef2bf8..71a3c9e75 100644 --- a/platform/macosx/love-framework.xcodeproj/project.pbxproj +++ b/platform/macosx/love-framework.xcodeproj/project.pbxproj @@ -2364,6 +2364,7 @@ ); LD_RUNPATH_SEARCH_PATHS = "@rpath"; LIBRARY_SEARCH_PATHS = ""; + LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = NO; USE_HEADERMAP = NO; From 0f9bf64cf8de4682f6eb0a3152a1852b2f968622 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 19:04:12 -0400 Subject: [PATCH 19/56] =?UTF-8?q?Xcode=20project:=20added=20new=20build=20?= =?UTF-8?q?scheme=20=E2=80=98Distribution=E2=80=99,=20moved=20LTO=20from?= =?UTF-8?q?=20=E2=80=98Release=E2=80=99=20to=20=E2=80=98Distribution?= =?UTF-8?q?=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../love-framework.xcodeproj/project.pbxproj | 63 +++++++++++++++- .../macosx/love.xcodeproj/project.pbxproj | 75 +++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/platform/macosx/love-framework.xcodeproj/project.pbxproj b/platform/macosx/love-framework.xcodeproj/project.pbxproj index 71a3c9e75..3f245a0f0 100644 --- a/platform/macosx/love-framework.xcodeproj/project.pbxproj +++ b/platform/macosx/love-framework.xcodeproj/project.pbxproj @@ -2364,7 +2364,6 @@ ); LD_RUNPATH_SEARCH_PATHS = "@rpath"; LIBRARY_SEARCH_PATHS = ""; - LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = NO; USE_HEADERMAP = NO; @@ -2408,6 +2407,66 @@ }; name = Debug; }; + FA5326C4189719C700F7BBF4 /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_ENABLE_MODULES = YES; + DEAD_CODE_STRIPPING = YES; + FRAMEWORK_SEARCH_PATHS = /Library/Frameworks; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = LOVE_MACOSX_USE_FRAMEWORKS; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../../src\"", + "\"$(SRCROOT)/../../src/libraries\"", + "\"$(SRCROOT)/../../src/modules\"", + "\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"", + /Library/Frameworks/FreeType.framework/Headers, + /Library/Frameworks/Lua.framework/Headers, + /Library/Frameworks/SDL2.framework/Headers, + ); + LD_RUNPATH_SEARCH_PATHS = "@rpath"; + LIBRARY_SEARCH_PATHS = ""; + LLVM_LTO = YES; + MACOSX_DEPLOYMENT_TARGET = 10.6; + ONLY_ACTIVE_ARCH = NO; + USE_HEADERMAP = NO; + WARNING_CFLAGS = "-Wall"; + }; + name = Distribution; + }; + FA5326C5189719C700F7BBF4 /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = NO; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_COMPATIBILITY_VERSION = 9.0; + DYLIB_CURRENT_VERSION = 9.0; + FRAMEWORK_VERSION = A; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + INFOPLIST_FILE = "Info-Framework.plist"; + LD_DYLIB_INSTALL_NAME = "@rpath/$(EXECUTABLE_PATH)"; + OTHER_LDFLAGS = ( + "-undefined", + dynamic_lookup, + ); + PRODUCT_NAME = love; + SKIP_INSTALL = YES; + WRAPPER_EXTENSION = framework; + }; + name = Distribution; + }; FA577AC016C7507900860150 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2465,6 +2524,7 @@ buildConfigurations = ( 64274E785071353E1A1D0D4B /* Debug */, 10D5479E63C26BB35EB5482E /* Release */, + FA5326C4189719C700F7BBF4 /* Distribution */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; @@ -2474,6 +2534,7 @@ buildConfigurations = ( FA577AC016C7507900860150 /* Debug */, FA577AC116C7507900860150 /* Release */, + FA5326C5189719C700F7BBF4 /* Distribution */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; diff --git a/platform/macosx/love.xcodeproj/project.pbxproj b/platform/macosx/love.xcodeproj/project.pbxproj index 9c4739788..e6081aeff 100644 --- a/platform/macosx/love.xcodeproj/project.pbxproj +++ b/platform/macosx/love.xcodeproj/project.pbxproj @@ -402,6 +402,79 @@ }; name = Release; }; + FA5326C618971A0900F7BBF4 /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_ENABLE_MODULES = YES; + DEPLOYMENT_POSTPROCESSING = NO; + FRAMEWORK_SEARCH_PATHS = /Library/Frameworks; + GCC_INPUT_FILETYPE = automatic; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = LOVE_MACOSX_USE_FRAMEWORKS; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO; + GCC_WARN_ABOUT_MISSING_NEWLINE = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = NO; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = NO; + GCC_WARN_MISSING_PARENTHESES = NO; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO; + GCC_WARN_PEDANTIC = NO; + GCC_WARN_SHADOW = NO; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO; + GCC_WARN_UNUSED_PARAMETER = NO; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../../src\"", + "\"$(SRCROOT)/../../src/libraries\"", + "\"$(SRCROOT)/../../src/modules\"", + /Library/Frameworks/Lua.framework/Headers, + /Library/Frameworks/SDL2.framework/Headers, + ); + INFOPLIST_FILE = "love-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; + LLVM_LTO = YES; + MACOSX_DEPLOYMENT_TARGET = 10.6; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ""; + "OTHER_LDFLAGS[arch=x86_64]" = ( + "-pagezero_size", + 10000, + "-image_base", + 100000000, + ); + PRODUCT_NAME = love; + SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; + WARNING_CFLAGS = ( + "-Wall", + "-W", + ); + }; + name = Distribution; + }; + FA5326C718971A0900F7BBF4 /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/build/Release\"", + "\"$(SRCROOT)/build/Debug\"", + ); + INSTALL_PATH = /Applications; + PRODUCT_NAME = love; + }; + name = Distribution; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -410,6 +483,7 @@ buildConfigurations = ( C01FCF4B08A954540054247B /* Debug */, C01FCF4C08A954540054247B /* Release */, + FA5326C718971A0900F7BBF4 /* Distribution */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -419,6 +493,7 @@ buildConfigurations = ( C01FCF4F08A954540054247B /* Debug */, C01FCF5008A954540054247B /* Release */, + FA5326C618971A0900F7BBF4 /* Distribution */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; From a2a8b14cfd53529bcc13b146598b45f4f8f07c45 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 19:24:14 -0400 Subject: [PATCH 20/56] Added love.getVersion (resolves issue #809). Syntax is: major, minor, revision, codename = love.getVersion(). --- src/modules/love/love.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 77fe5b208..7bb700b76 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -170,6 +170,15 @@ const char *love_codename() return love::VERSION_CODENAME; } +static int w_love_getVersion(lua_State *L) +{ + lua_pushinteger(L, love::VERSION_MAJOR); + lua_pushinteger(L, love::VERSION_MINOR); + lua_pushinteger(L, love::VERSION_REV); + lua_pushstring(L, love::VERSION_CODENAME); + return 4; +} + int luaopen_love(lua_State * L) { love::luax_insistglobal(L, "love"); @@ -203,6 +212,9 @@ int luaopen_love(lua_State * L) lua_setfield(L, -2, "_version_compat"); + lua_pushcfunction(L, w_love_getVersion); + lua_setfield(L, -2, "getVersion"); + #ifdef LOVE_WINDOWS lua_pushstring(L, "Windows"); #elif defined(LOVE_MACOSX) From d70023e3505ab0d459e1bbc82aa8aa8bf88ebaf1 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 23:30:16 -0400 Subject: [PATCH 21/56] =?UTF-8?q?Enable=20OpenGL=E2=80=99s=20debug=20outpu?= =?UTF-8?q?t=20when=20the=20LOVE=5FGRAPHICS=5FDEBUG=20environment=20variab?= =?UTF-8?q?le=20is=20=E2=80=981=E2=80=99.=20Resolves=20issue=20#607.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/graphics/opengl/Graphics.cpp | 64 ++++++++++++++++++++++++ src/modules/graphics/opengl/Graphics.h | 2 + src/modules/graphics/opengl/OpenGL.cpp | 61 ++++++++++++++++++++++ src/modules/graphics/opengl/OpenGL.h | 5 ++ src/modules/window/sdl/Window.cpp | 25 +++++++++ 5 files changed, 157 insertions(+) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 51f849f96..42e67b2d1 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -210,6 +210,18 @@ bool Graphics::setMode(int width, int height) glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &matrixLimit); matrixLimit -= 5; + bool enabledebug = false; + + if (GLEE_VERSION_3_0) + { + // Enable OpenGL's debug output if a debug context has been created. + GLint flags = 0; + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + enabledebug = (flags & GL_CONTEXT_FLAG_DEBUG_BIT) != 0; + } + + setDebug(enabledebug); + return true; } @@ -226,6 +238,58 @@ void Graphics::unSetMode() gl.deInitContext(); } +static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, GLvoid* /*usr*/) +{ + // Human-readable strings for the debug info. + const char *sourceStr = OpenGL::debugSourceString(source); + const char *typeStr = OpenGL::debugTypeString(type); + const char *severityStr = OpenGL::debugSeverityString(severity); + + const char *fmt = "OpenGL: %s [source=%s, type=%s, severity=%s, id=%d]\n"; + printf(fmt, msg, sourceStr, typeStr, severityStr, id); +} + +void Graphics::setDebug(bool enable) +{ + // Make sure debug output is supported. The AMD ext. is a bit different + // so we don't make use of it, since AMD drivers now support KHR_debug. + if (!(GLEE_VERSION_4_3 || GLEE_KHR_debug || GLEE_ARB_debug_output)) + return; + + // Ugly hack to reduce code duplication. + if (GLEE_ARB_debug_output && !(GLEE_VERSION_4_3 || GLEE_KHR_debug)) + { + glDebugMessageCallback = (GLEEPFNGLDEBUGMESSAGECALLBACKPROC) glDebugMessageCallbackARB; + glDebugMessageControl = (GLEEPFNGLDEBUGMESSAGECONTROLPROC) glDebugMessageControlARB; + } + + if (!enable) + { + // Disable the debug callback function. + glDebugMessageCallback(nullptr, nullptr); + + // We can disable debug output entirely with KHR_debug. + if (GLEE_VERSION_4_3 || GLEE_KHR_debug) + glDisable(GL_DEBUG_OUTPUT); + + return; + } + + // We don't want asynchronous debug output. + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + + glDebugMessageCallback(debugCB, nullptr); + + // Initially, enable everything. + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); + + // Disable messages about deprecated OpenGL functionality. + glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); + glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); + + ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)"); +} + void Graphics::reset() { DisplayState s; diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 070794941..ecba2806e 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -115,6 +115,8 @@ public: virtual bool setMode(int width, int height); virtual void unSetMode(); + void setDebug(bool enable); + /** * Resets the current color, background color, * line style, and so forth. (This will be called diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index f07120f65..ee501cc33 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -601,6 +601,67 @@ OpenGL::Vendor OpenGL::getVendor() const return vendor; } +const char *OpenGL::debugSeverityString(GLenum severity) +{ + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH: + return "high"; + case GL_DEBUG_SEVERITY_MEDIUM: + return "medium"; + case GL_DEBUG_SEVERITY_LOW: + return "low"; + default: + break; + } + return "unknown"; +} + +const char *OpenGL::debugSourceString(GLenum source) +{ + switch (source) + { + case GL_DEBUG_SOURCE_API: + return "API"; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + return "window"; + case GL_DEBUG_SOURCE_SHADER_COMPILER: + return "shader"; + case GL_DEBUG_SOURCE_THIRD_PARTY: + return "external"; + case GL_DEBUG_SOURCE_APPLICATION: + return "LOVE"; + case GL_DEBUG_SOURCE_OTHER: + return "other"; + default: + break; + } + return "unknown"; +} + +const char *OpenGL::debugTypeString(GLenum type) +{ + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + return "error"; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + return "deprecated behavior"; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + return "undefined behavior"; + case GL_DEBUG_TYPE_PERFORMANCE: + return "performance"; + case GL_DEBUG_TYPE_PORTABILITY: + return "portability"; + case GL_DEBUG_TYPE_OTHER: + return "other"; + default: + break; + } + return "unknown"; +} + + // OpenGL class instance singleton. OpenGL gl; diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 8e61c012e..2fd253381 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -230,6 +230,11 @@ public: **/ Vendor getVendor() const; + // Get human-readable strings for debug info. + static const char *debugSeverityString(GLenum severity); + static const char *debugSourceString(GLenum source); + static const char *debugTypeString(GLenum type); + private: void initVendor(); diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 0c94c8624..6f5f0f6e1 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -250,6 +250,18 @@ bool Window::setContext(int fsaa, bool vsync) context = SDL_GL_CreateContext(window); } + if (!context) + { + int flags = 0; + SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &flags); + if (flags & SDL_GL_CONTEXT_DEBUG_FLAG) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); + context = SDL_GL_CreateContext(window); + } + } + if (!context) { std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl; @@ -291,6 +303,19 @@ void Window::setWindowGLAttributes(int fsaa) const // FSAA. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); + + // Do we want a debug context? + const char *debugenv = SDL_GetHint("LOVE_GRAPHICS_DEBUG"); + if (debugenv && *debugenv == '1') + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + } + else + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); + } } void Window::updateSettings(const WindowSettings &newsettings) From 6b538b5827a32fc73e90ff959aa2fd3a1f0ded8f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 27 Jan 2014 23:42:26 -0400 Subject: [PATCH 22/56] The emission rate for ParticleSystems is no longer restricted to integer numbers. --- src/modules/graphics/opengl/ParticleSystem.cpp | 6 +++--- src/modules/graphics/opengl/ParticleSystem.h | 6 +++--- src/modules/graphics/opengl/wrap_ParticleSystem.cpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 04bdbee87..cf613da04 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -432,14 +432,14 @@ ParticleSystem::InsertMode ParticleSystem::getInsertMode() const return insertMode; } -void ParticleSystem::setEmissionRate(int rate) +void ParticleSystem::setEmissionRate(float rate) { - if (rate < 0) + if (rate < 0.0f) throw love::Exception("Invalid emission rate"); emissionRate = rate; } -int ParticleSystem::getEmissionRate() const +float ParticleSystem::getEmissionRate() const { return emissionRate; } diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 1314578a9..8180f52df 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -131,12 +131,12 @@ public: * Sets the emission rate. * @param rate The amount of particles per second. **/ - void setEmissionRate(int rate); + void setEmissionRate(float rate); /** * Returns the number of particles created per second. **/ - int getEmissionRate() const; + float getEmissionRate() const; /** * Sets the lifetime of the particle emitter (-1 means eternal) @@ -547,7 +547,7 @@ protected: uint32 activeParticles; // The emission rate (particles/sec). - int emissionRate; + float emissionRate; // Used to determine when a particle should be emitted. float emitCounter; diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 91517d60c..8f38aa70d 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -127,7 +127,7 @@ int w_ParticleSystem_getInsertMode(lua_State *L) int w_ParticleSystem_setEmissionRate(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); - int arg1 = luaL_checkint(L, 2); + float arg1 = (float) luaL_checknumber(L, 2); EXCEPT_GUARD(t->setEmissionRate(arg1);) return 0; } @@ -135,7 +135,7 @@ int w_ParticleSystem_setEmissionRate(lua_State *L) int w_ParticleSystem_getEmissionRate(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); - lua_pushinteger(L, t->getEmissionRate()); + lua_pushnumber(L, t->getEmissionRate()); return 1; } From a7ed5812046b72bb6f8d2002781571c05eb8b4a4 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 28 Jan 2014 03:20:08 -0400 Subject: [PATCH 23/56] =?UTF-8?q?Reverted=20ParticleSystem:setPosition?= =?UTF-8?q?=E2=80=99s=20functionality=20to=200.9.0=E2=80=99s=20beheaviour,?= =?UTF-8?q?=20added=20ParticleSystem:moveTo=20which=20has=20the=20new=20be?= =?UTF-8?q?haviour=20(new=20particles=20spawn=20in=20a=20line=20between=20?= =?UTF-8?q?the=20old=20position=20and=20where=20the=20emitter=20was=20move?= =?UTF-8?q?d=20to.)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/graphics/opengl/ParticleSystem.cpp | 6 ++++++ src/modules/graphics/opengl/ParticleSystem.h | 9 +++++++++ src/modules/graphics/opengl/wrap_ParticleSystem.cpp | 10 ++++++++++ src/modules/graphics/opengl/wrap_ParticleSystem.h | 1 + 4 files changed, 26 insertions(+) diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index cf613da04..d5d52da2b 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -474,6 +474,7 @@ void ParticleSystem::getParticleLifetime(float *min, float *max) const void ParticleSystem::setPosition(float x, float y) { position = love::Vector(x, y); + prevPosition = position; } const love::Vector &ParticleSystem::getPosition() const @@ -481,6 +482,11 @@ const love::Vector &ParticleSystem::getPosition() const return position; } +void ParticleSystem::moveTo(float x, float y) +{ + position = love::Vector(x, y); +} + void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y) { areaSpread = love::Vector(x, y); diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 8180f52df..8ebdf1d8e 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -176,6 +176,15 @@ public: **/ const love::Vector &getPosition() const; + /** + * Moves the position of the center of the emitter. + * When update is called, newly spawned particles will appear in a line + * between the old emitter position and where the emitter was moved to, + * resulting in a smoother-feeling particle system if moveTo is called + * repeatedly. + **/ + void moveTo(float x, float y); + /** * Sets the emission area spread parameters and distribution type. The interpretation of * the parameters depends on the distribution type: diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 8f38aa70d..6e875b645 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -191,6 +191,15 @@ int w_ParticleSystem_getPosition(lua_State *L) return 2; } +int w_ParticleSystem_moveTo(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + float arg2 = (float)luaL_checknumber(L, 3); + t->moveTo(arg1, arg2); + return 0; +} + int w_ParticleSystem_setAreaSpread(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); @@ -649,6 +658,7 @@ static const luaL_Reg functions[] = { "getParticleLifetime", w_ParticleSystem_getParticleLifetime }, { "setPosition", w_ParticleSystem_setPosition }, { "getPosition", w_ParticleSystem_getPosition }, + { "moveTo", w_ParticleSystem_moveTo }, { "setAreaSpread", w_ParticleSystem_setAreaSpread }, { "getAreaSpread", w_ParticleSystem_getAreaSpread }, { "setDirection", w_ParticleSystem_setDirection }, diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.h b/src/modules/graphics/opengl/wrap_ParticleSystem.h index 849374745..08948c386 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.h +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.h @@ -48,6 +48,7 @@ int w_ParticleSystem_setParticleLifetime(lua_State *L); int w_ParticleSystem_getParticleLifetime(lua_State *L); int w_ParticleSystem_setPosition(lua_State *L); int w_ParticleSystem_getPosition(lua_State *L); +int w_ParticleSystem_moveTo(lua_State *L); int w_ParticleSystem_setAreaSpread(lua_State *L); int w_ParticleSystem_getAreaSpread(lua_State *L); int w_ParticleSystem_setDirection(lua_State *L); From 7ef0a6b576a921d7cd1e2be40380c038d26b0130 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 28 Jan 2014 03:27:42 -0400 Subject: [PATCH 24/56] Updated changelog --- changes.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/changes.txt b/changes.txt index 8449db034..ee38d261e 100644 --- a/changes.txt +++ b/changes.txt @@ -6,12 +6,21 @@ LOVE 0.9.1 [Baby Inspector] * Added Source:clone. * Added ParticleSystem:clone. * Added Mesh:setWireframe and Mesh:isWireframe for debugging. + * Added Mesh:setDrawRange and Mesh:getDrawRange. + * Added instancing support to Meshes with Mesh:setInstanceCount. * Added CircleShape:getPoint and CircleShape:setPoint. * Added Mesh/SpriteBatch/ParticleSystem:setTexture, accepts Canvases and Images. * Added high-dpi window support for Retina displays in OS X, via the 'highdpi' window flag. * Added love.window.getPixelScale. + * Added love.graphics.getSystemLimit. + * Added ParticleSystem:moveTo, has smoother emitter movement compared to setPosition. + * Added antialiasing support to Canvases. + * Added Canvas:getFSAA. + * Added 'love_ScreenSize' built-in variable in shaders. + * Added love.getVersion. - * Deprecated Mesh/SpriteBatch/ParticleSystem:setImage and love.graphics.getMaxImageSize. + * Deprecated Mesh/SpriteBatch/ParticleSystem:setImage. + * Deprecated love.graphics.getMaxImageSize and love.graphics.getMaxPointSize. * Fixed love.graphics.scale with negative values causing incorrect line widths. * Fixed Joystick:isDown using 0-based button index arguments. @@ -28,7 +37,7 @@ LOVE 0.9.1 [Baby Inspector] * Updated love.graphics.newParticleSystem, newSpriteBatch, and newMesh to accept Canvases. * Updated Canvas drawing code, texture coordinates are no longer flipped vertically. * Updated Canvas:renderTo to work properly if a Canvas is currently active. - * Updated particle spawning behaviour in ParticleSystems to be smoother when moving the emitter. + * Updated ParticleSystem:setEmissionRate to accept non-integer numbers. LOVE 0.9.0 [Baby Inspector] --------------------------- From a49c2a88c1158a32aa7b5a078e782b57aa902aaf Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 29 Jan 2014 05:24:47 -0400 Subject: [PATCH 25/56] Increased robustness of audio module initialization (see issue #646.) Also changed Source:play to return a boolean indicating success. --- src/modules/audio/Audio.h | 2 +- src/modules/audio/Source.h | 2 +- src/modules/audio/null/Audio.cpp | 7 ++--- src/modules/audio/null/Audio.h | 3 +-- src/modules/audio/null/Source.cpp | 3 ++- src/modules/audio/null/Source.h | 2 +- src/modules/audio/openal/Audio.cpp | 42 +++++++++++++++++++---------- src/modules/audio/openal/Audio.h | 3 +-- src/modules/audio/openal/Pool.cpp | 40 ++++++++++++++++++++------- src/modules/audio/openal/Pool.h | 11 +++++--- src/modules/audio/openal/Source.cpp | 5 ++-- src/modules/audio/openal/Source.h | 2 +- src/modules/audio/wrap_Audio.cpp | 4 +-- src/modules/audio/wrap_Source.cpp | 4 +-- 14 files changed, 83 insertions(+), 47 deletions(-) diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index b7c192577..b43391dbe 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -88,7 +88,7 @@ public: * Play the specified Source. * @param source The Source to play. **/ - virtual void play(Source *source) = 0; + virtual bool play(Source *source) = 0; /** * Stops playback on the specified source. diff --git a/src/modules/audio/Source.h b/src/modules/audio/Source.h index b7a17d02d..43c5fafca 100644 --- a/src/modules/audio/Source.h +++ b/src/modules/audio/Source.h @@ -53,7 +53,7 @@ public: virtual Source *clone() = 0; - virtual void play() = 0; + virtual bool play() = 0; virtual void stop() = 0; virtual void pause() = 0; virtual void resume() = 0; diff --git a/src/modules/audio/null/Audio.cpp b/src/modules/audio/null/Audio.cpp index 2e5031ae1..6b6fd3f93 100644 --- a/src/modules/audio/null/Audio.cpp +++ b/src/modules/audio/null/Audio.cpp @@ -61,12 +61,9 @@ int Audio::getMaxSources() const return 0; } -void Audio::play(love::audio::Source *) -{ -} - -void Audio::play() +bool Audio::play(love::audio::Source *) { + return false; } void Audio::stop(love::audio::Source *) diff --git a/src/modules/audio/null/Audio.h b/src/modules/audio/null/Audio.h index 3f571da67..372f756c5 100644 --- a/src/modules/audio/null/Audio.h +++ b/src/modules/audio/null/Audio.h @@ -48,8 +48,7 @@ public: love::audio::Source *newSource(love::sound::SoundData *soundData); int getSourceCount() const; int getMaxSources() const; - void play(love::audio::Source *source); - void play(); + bool play(love::audio::Source *source); void stop(love::audio::Source *source); void stop(); void pause(love::audio::Source *source); diff --git a/src/modules/audio/null/Source.cpp b/src/modules/audio/null/Source.cpp index d343587f8..0fc043cc3 100644 --- a/src/modules/audio/null/Source.cpp +++ b/src/modules/audio/null/Source.cpp @@ -42,8 +42,9 @@ love::audio::Source *Source::clone() return this; } -void Source::play() +bool Source::play() { + return false; } void Source::stop() diff --git a/src/modules/audio/null/Source.h b/src/modules/audio/null/Source.h index 887b3ef56..326ff23d5 100644 --- a/src/modules/audio/null/Source.h +++ b/src/modules/audio/null/Source.h @@ -39,7 +39,7 @@ public: virtual ~Source(); virtual love::audio::Source *clone(); - virtual void play(); + virtual bool play(); virtual void stop(); virtual void pause(); virtual void resume(); diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index 07ce2959d..c6af9be19 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -69,22 +69,25 @@ void Audio::PoolThread::setFinish() } Audio::Audio() - : distanceModel(DISTANCE_INVERSE_CLAMPED) + : device(nullptr) + , capture(nullptr) + , context(nullptr) + , pool(nullptr) + , poolThread(nullptr) + , distanceModel(DISTANCE_INVERSE_CLAMPED) { - // Passing zero for default device. - device = alcOpenDevice(0); + // Passing null for default device. + device = alcOpenDevice(nullptr); - if (device == 0) + if (device == nullptr) throw love::Exception("Could not open device."); - context = alcCreateContext(device, 0); + context = alcCreateContext(device, nullptr); - if (context == 0) + if (context == nullptr) throw love::Exception("Could not create context."); - alcMakeContextCurrent(context); - - if (alcGetError(device) != ALC_NO_ERROR) + if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR) throw love::Exception("Could not make context current."); /*std::string captureName(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); @@ -108,7 +111,18 @@ Audio::Audio() }*/ // pool must be allocated after AL context. - pool = new Pool(); + try + { + pool = new Pool(); + } + catch (love::Exception &) + { + alcMakeContextCurrent(nullptr); + alcDestroyContext(context); + //if (capture) alcCaptureCloseDevice(capture); + alcCloseDevice(device); + throw; + } poolThread = new PoolThread(pool); poolThread->start(); @@ -122,7 +136,7 @@ Audio::~Audio() delete poolThread; delete pool; - alcMakeContextCurrent(0); + alcMakeContextCurrent(nullptr); alcDestroyContext(context); //if (capture) alcCaptureCloseDevice(capture); alcCloseDevice(device); @@ -154,9 +168,9 @@ int Audio::getMaxSources() const return pool->getMaxSources(); } -void Audio::play(love::audio::Source *source) +bool Audio::play(love::audio::Source *source) { - source->play(); + return source->play(); } void Audio::stop(love::audio::Source *source) @@ -281,7 +295,7 @@ bool Audio::canRecord() Audio::DistanceModel Audio::getDistanceModel() const { - return this->distanceModel; + return distanceModel; } void Audio::setDistanceModel(DistanceModel distanceModel) diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index a40494b2a..6e5f50696 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -67,8 +67,7 @@ public: love::audio::Source *newSource(love::sound::SoundData *soundData); int getSourceCount() const; int getMaxSources() const; - void play(love::audio::Source *source); - void play(); + bool play(love::audio::Source *source); void stop(love::audio::Source *source); void stop(); void pause(love::audio::Source *source); diff --git a/src/modules/audio/openal/Pool.cpp b/src/modules/audio/openal/Pool.cpp index f3d74a91a..8fde3785b 100644 --- a/src/modules/audio/openal/Pool.cpp +++ b/src/modules/audio/openal/Pool.cpp @@ -30,23 +30,43 @@ namespace openal { Pool::Pool() + : sources() + , totalSources(0) + , mutex(nullptr) { + // Clear errors. + alGetError(); + // Generate sources. - alGenSources(NUM_SOURCES, sources); + for (int i = 0; i < MAX_SOURCES; i++) + { + alGenSources(1, &sources[i]); + + // We might hit an implementation-dependent limit on the total number + // of sources before reaching MAX_SOURCES. + if (alGetError() != AL_NO_ERROR) + break; + + totalSources++; + } + + if (totalSources < 4) + throw love::Exception("Could not generate sources."); // Create the mutex. mutex = thread::newMutex(); - if (alGetError() != AL_NO_ERROR) - throw love::Exception("Could not generate sources."); + ALboolean hasext = alIsExtensionPresent("AL_SOFT_direct_channels"); // Make all sources available initially. - for (int i = 0; i < NUM_SOURCES; i++) + for (int i = 0; i < totalSources; i++) { -#ifdef AL_DIRECT_CHANNELS_SOFT - // Bypassing virtualization of speakers for multi-channel sources in OpenAL Soft. - alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE); -#endif + if (hasext) + { + // Bypass virtualization of speakers for multi-channel sources in OpenAL Soft. + alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE); + } + available.push(sources[i]); } } @@ -58,7 +78,7 @@ Pool::~Pool() delete mutex; // Free all sources. - alDeleteSources(NUM_SOURCES, sources); + alDeleteSources(totalSources, sources); } bool Pool::isAvailable() const @@ -113,7 +133,7 @@ int Pool::getSourceCount() const int Pool::getMaxSources() const { - return NUM_SOURCES; + return totalSources; } bool Pool::play(Source *source, ALuint &out) diff --git a/src/modules/audio/openal/Pool.h b/src/modules/audio/openal/Pool.h index 46353e759..f0896ea97 100644 --- a/src/modules/audio/openal/Pool.h +++ b/src/modules/audio/openal/Pool.h @@ -36,6 +36,7 @@ #ifdef LOVE_MACOSX_USE_FRAMEWORKS #include #include +#include #else #include #include @@ -99,11 +100,15 @@ private: bool findSource(Source *source, ALuint &out); bool removeSource(Source *source); - // Number of OpenAL sources. - static const int NUM_SOURCES = 64; + + // Maximum possible number of OpenAL sources the pool attempts to generate. + static const int MAX_SOURCES = 64; // OpenAL sources - ALuint sources[NUM_SOURCES]; + ALuint sources[MAX_SOURCES]; + + // Total number of created sources in the pool. + int totalSources; // A queue of available sources. std::queue available; diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index 332eb336e..1ea4243aa 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -165,15 +165,16 @@ love::audio::Source *Source::clone() return new Source(*this); } -void Source::play() +bool Source::play() { if (valid && paused) { pool->resume(this); - return; + return true; } valid = pool->play(this, source); + return valid; } void Source::stop() diff --git a/src/modules/audio/openal/Source.h b/src/modules/audio/openal/Source.h index 9a1182d74..911b57978 100644 --- a/src/modules/audio/openal/Source.h +++ b/src/modules/audio/openal/Source.h @@ -76,7 +76,7 @@ public: virtual ~Source(); virtual love::audio::Source *clone(); - virtual void play(); + virtual bool play(); virtual void stop(); virtual void pause(); virtual void resume(); diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 4b8e39969..217c4f98e 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -75,8 +75,8 @@ int w_newSource(lua_State *L) int w_play(lua_State *L) { Source *s = luax_checksource(L, 1); - instance->play(s); - return 0; + luax_pushboolean(L, instance->play(s)); + return 1; } int w_stop(lua_State *L) diff --git a/src/modules/audio/wrap_Source.cpp b/src/modules/audio/wrap_Source.cpp index d1f3e61a1..b6b152b2b 100644 --- a/src/modules/audio/wrap_Source.cpp +++ b/src/modules/audio/wrap_Source.cpp @@ -44,8 +44,8 @@ int w_Source_clone(lua_State *L) int w_Source_play(lua_State *L) { Source *t = luax_checksource(L, 1); - t->play(); - return 0; + luax_pushboolean(L, t->play()); + return 1; } int w_Source_stop(lua_State *L) From 007d0d5216f3bf18b557f8d6cb07b2ca2260ca4a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 29 Jan 2014 16:20:05 -0400 Subject: [PATCH 26/56] Windows: create the console before modules are loaded (allows information printed during module initialization to be displayed.) --- src/scripts/boot.lua | 10 +++++----- src/scripts/boot.lua.h | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 27297734f..df1f8cd3b 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -343,6 +343,11 @@ function love.init() c.console = true end + -- Console hack + if c.console and love._openConsole then + love._openConsole() + end + -- Gets desired modules. for k,v in ipairs{ "thread", @@ -370,11 +375,6 @@ function love.init() love.createhandlers() end - -- Console hack - if c.console and love._openConsole then - love._openConsole() - end - -- Setup window here. if c.window and c.modules.window then assert(love.window.setMode(c.window.width, c.window.height, diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index b90a473a6..892d7dc88 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -601,6 +601,13 @@ const unsigned char boot_lua[] = 0x6e, 0x0a, 0x09, 0x09, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x68, 0x61, 0x63, 0x6b, 0x0a, + 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, + 0x65, 0x28, 0x29, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x73, 0x20, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, @@ -632,13 +639,6 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x28, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x68, 0x61, 0x63, 0x6b, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, - 0x65, 0x28, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x53, 0x65, 0x74, 0x75, 0x70, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2e, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, From 33f12a60914e980208b3427dc28ac739345fe3f7 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 29 Jan 2014 17:04:03 -0400 Subject: [PATCH 27/56] Source:play now returns false if alSourcePlay failed --- src/modules/audio/openal/Pool.cpp | 4 +--- src/modules/audio/openal/Source.cpp | 11 ++++++++++- src/modules/audio/openal/Source.h | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/modules/audio/openal/Pool.cpp b/src/modules/audio/openal/Pool.cpp index 8fde3785b..f8e613394 100644 --- a/src/modules/audio/openal/Pool.cpp +++ b/src/modules/audio/openal/Pool.cpp @@ -161,9 +161,7 @@ bool Pool::play(Source *source, ALuint &out) source->retain(); - source->playAtomic(); - - ok = true; + ok = source->playAtomic(); } else { diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index 1ea4243aa..237cf02b1 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -513,7 +513,7 @@ bool Source::isLooping() const return looping; } -void Source::playAtomic() +bool Source::playAtomic() { if (type == TYPE_STATIC) { @@ -540,10 +540,19 @@ void Source::playAtomic() // of the new one. reset(); + // Clear errors. + alGetError(); + alSourcePlay(source); + // alSourcePlay may fail if the system has reached its limit of simultaneous + // playing sources. + bool success = alGetError() == AL_NO_ERROR; + valid = true; //if it fails it will be set to false again //but this prevents a horrible, horrible bug + + return success; } void Source::stopAtomic() diff --git a/src/modules/audio/openal/Source.h b/src/modules/audio/openal/Source.h index 911b57978..5591c6b85 100644 --- a/src/modules/audio/openal/Source.h +++ b/src/modules/audio/openal/Source.h @@ -118,7 +118,7 @@ public: virtual float getMaxDistance() const; virtual int getChannels() const; - void playAtomic(); + bool playAtomic(); void stopAtomic(); void pauseAtomic(); void resumeAtomic(); From 2a4d47e6143bf9e2aff662cbdfed1c7609b644da Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 29 Jan 2014 23:10:57 -0400 Subject: [PATCH 28/56] Added a missing newline to a print statement --- src/modules/graphics/opengl/Graphics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 42e67b2d1..4cc6ae171 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -287,7 +287,7 @@ void Graphics::setDebug(bool enable) glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); - ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)"); + ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n"); } void Graphics::reset() From 40242689b19c7058fe3ceb3112d53b9f4dcd3a31 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 30 Jan 2014 21:09:13 -0400 Subject: [PATCH 29/56] Fixed rendering to multiple canvases, removed some redundant OpenGL calls when switching between canvases --- src/modules/graphics/opengl/Canvas.cpp | 37 +++++++++++---------- src/modules/graphics/opengl/Canvas.h | 2 +- src/modules/graphics/opengl/SpriteBatch.cpp | 4 +++ src/modules/graphics/opengl/SpriteBatch.h | 2 -- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index afadd448a..090aeb028 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -397,9 +397,6 @@ static void getStrategy() } } -static int maxFBOColorAttachments = 0; -static int maxDrawBuffers = 0; - Canvas::Canvas(int width, int height, TextureType texture_type, int fsaa) : fbo(0) , resolve_fbo(0) @@ -657,12 +654,19 @@ void Canvas::setupGrab() if (current == this) return; - // cleanup after previous fbo - if (current != NULL) - current->stopGrab(); + // cleanup after previous Canvas + if (current != nullptr) + { + systemViewport = current->systemViewport; + current->stopGrab(true); + } + else + systemViewport = gl.getViewport(); + + // indicate we are using this Canvas. + current = this; // bind the framebuffer object. - systemViewport = gl.getViewport(); strategy->bindFBO(fbo); gl.setViewport(OpenGL::Viewport(0, 0, width, height)); @@ -677,9 +681,6 @@ void Canvas::setupGrab() // Switch back to modelview matrix glMatrixMode(GL_MODELVIEW); - // indicate we are using this fbo - current = this; - if (fsaa_buffer != 0) fsaa_dirty = true; } @@ -695,7 +696,7 @@ void Canvas::startGrab(const std::vector &canvases) if (!isMultiCanvasSupported()) throw love::Exception("Multi-canvas rendering is not supported on this system."); - if (canvases.size()+1 > size_t(maxDrawBuffers) || canvases.size()+1 > size_t(maxFBOColorAttachments)) + if ((int) canvases.size() + 1 > gl.getMaxRenderTargets()) throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1); if (fsaa_samples != 0) @@ -752,21 +753,23 @@ void Canvas::startGrab() attachedCanvases.clear(); } -void Canvas::stopGrab() +void Canvas::stopGrab(bool switchingToOtherCanvas) { // i am not grabbing. leave me alone if (current != this) return; - // bind default - strategy->bindFBO(0); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - current = nullptr; - - gl.setViewport(systemViewport); + // bind default + if (!switchingToOtherCanvas) + { + strategy->bindFBO(0); + current = nullptr; + gl.setViewport(systemViewport); + } } void Canvas::clear(Color c) diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index f643294fc..86db8f0f9 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -69,7 +69,7 @@ public: **/ void startGrab(const std::vector &canvases); void startGrab(); - void stopGrab(); + void stopGrab(bool switchingToOtherCanvas = false); void clear(Color c); diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 032e8769e..bd2e52f99 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -105,6 +105,8 @@ int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, fl if ((index == -1 && next >= size) || index < -1 || index >= size) return -1; + Vertex sprite[4]; + // Needed for colors. memcpy(sprite, texture->getVertices(), sizeof(Vertex) * 4); @@ -131,6 +133,8 @@ int SpriteBatch::addq(Quad *quad, float x, float y, float a, float sx, float sy, if ((index == -1 && next >= size) || index < -1 || index >= next) return -1; + Vertex sprite[4]; + // Needed for colors. memcpy(sprite, quad->getVertices(), sizeof(Vertex) * 4); diff --git a/src/modules/graphics/opengl/SpriteBatch.h b/src/modules/graphics/opengl/SpriteBatch.h index ae79db8d6..7339c7c77 100644 --- a/src/modules/graphics/opengl/SpriteBatch.h +++ b/src/modules/graphics/opengl/SpriteBatch.h @@ -135,8 +135,6 @@ private: // The next free element. int next; - Vertex sprite[4]; - // Current color. This color, if present, will be applied to the next // added sprite. Color *color; From 9e746c56fada7754fcb8575d7720c0004a85e40b Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 30 Jan 2014 21:51:17 -0400 Subject: [PATCH 30/56] love.graphics.getBlendMode no longer does several glGetInteger function calls --- src/modules/graphics/opengl/Graphics.cpp | 105 ++++++----------------- src/modules/graphics/opengl/OpenGL.cpp | 36 ++++++++ src/modules/graphics/opengl/OpenGL.h | 20 +++++ 3 files changed, 83 insertions(+), 78 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 4cc6ae171..8539c140b 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -169,9 +169,6 @@ bool Graphics::setMode(int width, int height) // Enable blending glEnable(GL_BLEND); - // "Normal" blending - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // Enable all color component writes. setColorMask(true, true, true, true); @@ -576,22 +573,16 @@ const bool *Graphics::getColorMask() const void Graphics::setBlendMode(Graphics::BlendMode mode) { - const int gl_1_4 = GLEE_VERSION_1_4; - - GLenum func = GL_FUNC_ADD; - GLenum src_rgb = GL_ONE; - GLenum src_a = GL_ONE; - GLenum dst_rgb = GL_ZERO; - GLenum dst_a = GL_ZERO; + OpenGL::BlendState state = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD}; switch (mode) { case BLEND_ALPHA: - if (gl_1_4 || GLEE_EXT_blend_func_separate) + if (GLEE_VERSION_1_4 || GLEE_EXT_blend_func_separate) { - src_rgb = GL_SRC_ALPHA; - src_a = GL_ONE; - dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA; + state.srcRGB = GL_SRC_ALPHA; + state.srcA = GL_ONE; + state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA; } else { @@ -599,98 +590,56 @@ void Graphics::setBlendMode(Graphics::BlendMode mode) // This will most likely only be used for the Microsoft software renderer and // since it's still stuck with OpenGL 1.1, the only expected difference is a // different alpha value when reading back the default framebuffer (newScreenshot). - src_rgb = src_a = GL_SRC_ALPHA; - dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA; + state.srcRGB = state.srcA = GL_SRC_ALPHA; + state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA; } break; case BLEND_MULTIPLICATIVE: - src_rgb = src_a = GL_DST_COLOR; - dst_rgb = dst_a = GL_ZERO; + state.srcRGB = state.srcA = GL_DST_COLOR; + state.dstRGB = state.dstA = GL_ZERO; break; case BLEND_PREMULTIPLIED: - src_rgb = src_a = GL_ONE; - dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA; + state.srcRGB = state.srcA = GL_ONE; + state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA; break; case BLEND_SUBTRACTIVE: - func = GL_FUNC_REVERSE_SUBTRACT; + state.func = GL_FUNC_REVERSE_SUBTRACT; case BLEND_ADDITIVE: - src_rgb = src_a = GL_SRC_ALPHA; - dst_rgb = dst_a = GL_ONE; + state.srcRGB = state.srcA = GL_SRC_ALPHA; + state.dstRGB = state.dstA = GL_ONE; break; case BLEND_REPLACE: default: - src_rgb = src_a = GL_ONE; - dst_rgb = dst_a = GL_ZERO; + state.srcRGB = state.srcA = GL_ONE; + state.dstRGB = state.dstA = GL_ZERO; break; } - if (gl_1_4 || GLEE_ARB_imaging) - glBlendEquation(func); - else if (GLEE_EXT_blend_minmax && GLEE_EXT_blend_subtract) - glBlendEquationEXT(func); - else - { - if (func == GL_FUNC_REVERSE_SUBTRACT) - throw Exception("This graphics card does not support the subtractive blend mode!"); - // GL_FUNC_ADD is the default even without access to glBlendEquation, so that'll still work. - } - - if (src_rgb == src_a && dst_rgb == dst_a) - glBlendFunc(src_rgb, dst_rgb); - else - { - if (gl_1_4) - glBlendFuncSeparate(src_rgb, dst_rgb, src_a, dst_a); - else if (GLEE_EXT_blend_func_separate) - glBlendFuncSeparateEXT(src_rgb, dst_rgb, src_a, dst_a); - else - throw Exception("This graphics card does not support separated rgb and alpha blend functions!"); - } + gl.setBlendState(state); } Graphics::BlendMode Graphics::getBlendMode() const { - const int gl_1_4 = GLEE_VERSION_1_4; + OpenGL::BlendState state = gl.getBlendState(); - GLint src_rgb, src_a, dst_rgb, dst_a; - GLint equation = GL_FUNC_ADD; - - if (gl_1_4 || GLEE_EXT_blend_func_separate) - { - glGetIntegerv(GL_BLEND_SRC_RGB, &src_rgb); - glGetIntegerv(GL_BLEND_SRC_ALPHA, &src_a); - glGetIntegerv(GL_BLEND_DST_RGB, &dst_rgb); - glGetIntegerv(GL_BLEND_DST_ALPHA, &dst_a); - } - else - { - glGetIntegerv(GL_BLEND_SRC, &src_rgb); - glGetIntegerv(GL_BLEND_DST, &dst_rgb); - src_a = src_rgb; - dst_a = dst_rgb; - } - - if (gl_1_4 || GLEE_ARB_imaging || (GLEE_EXT_blend_minmax && GLEE_EXT_blend_subtract)) - glGetIntegerv(GL_BLEND_EQUATION, &equation); - - if (equation == GL_FUNC_REVERSE_SUBTRACT) // && src == GL_SRC_ALPHA && dst == GL_ONE + if (state.func == GL_FUNC_REVERSE_SUBTRACT) // && src == GL_SRC_ALPHA && dst == GL_ONE return BLEND_SUBTRACTIVE; // Everything else has equation == GL_FUNC_ADD. - else if (src_rgb == src_a && dst_rgb == dst_a) + else if (state.srcRGB == state.srcA && state.dstRGB == state.dstA) { - if (src_rgb == GL_SRC_ALPHA && dst_rgb == GL_ONE) + if (state.srcRGB == GL_SRC_ALPHA && state.dstRGB == GL_ONE) return BLEND_ADDITIVE; - else if (src_rgb == GL_SRC_ALPHA && dst_rgb == GL_ONE_MINUS_SRC_ALPHA) + else if (state.srcRGB == GL_SRC_ALPHA && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA) return BLEND_ALPHA; // alpha blend mode fallback for very old OpenGL versions. - else if (src_rgb == GL_DST_COLOR && dst_rgb == GL_ZERO) + else if (state.srcRGB == GL_DST_COLOR && state.dstRGB == GL_ZERO) return BLEND_MULTIPLICATIVE; - else if (src_rgb == GL_ONE && dst_rgb == GL_ONE_MINUS_SRC_ALPHA) + else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA) return BLEND_PREMULTIPLIED; - else if (src_rgb == GL_ONE && dst_rgb == GL_ZERO) + else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ZERO) return BLEND_REPLACE; } - else if (src_rgb == GL_SRC_ALPHA && src_a == GL_ONE && - dst_rgb == GL_ONE_MINUS_SRC_ALPHA && dst_a == GL_ONE_MINUS_SRC_ALPHA) + else if (state.srcRGB == GL_SRC_ALPHA && state.srcA == GL_ONE && + state.dstRGB == GL_ONE_MINUS_SRC_ALPHA && state.dstA == GL_ONE_MINUS_SRC_ALPHA) return BLEND_ALPHA; throw Exception("Unknown blend mode"); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index ee501cc33..fea9ca877 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -111,6 +111,9 @@ void OpenGL::initContext() glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &state.textureUnits[0]); } + BlendState blend = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD}; + setBlendState(blend); + initMaxValues(); createDefaultTexture(); @@ -364,6 +367,39 @@ OpenGL::Viewport OpenGL::getScissor() const return state.scissor; } +void OpenGL::setBlendState(const BlendState &blend) +{ + if (GLEE_VERSION_1_4 || GLEE_ARB_imaging) + glBlendEquation(blend.func); + else if (GLEE_EXT_blend_minmax && GLEE_EXT_blend_subtract) + glBlendEquationEXT(blend.func); + else + { + if (blend.func == GL_FUNC_REVERSE_SUBTRACT) + throw love::Exception("This graphics card does not support the subtractive blend mode!"); + // GL_FUNC_ADD is the default even without access to glBlendEquation, so that'll still work. + } + + if (blend.srcRGB == blend.srcA && blend.dstRGB == blend.dstA) + glBlendFunc(blend.srcRGB, blend.dstRGB); + else + { + if (GLEE_VERSION_1_4) + glBlendFuncSeparate(blend.srcRGB, blend.dstRGB, blend.srcA, blend.dstA); + else if (GLEE_EXT_blend_func_separate) + glBlendFuncSeparateEXT(blend.srcRGB, blend.dstRGB, blend.srcA, blend.dstA); + else + throw love::Exception("This graphics card does not support separated rgb and alpha blend functions!"); + } + + state.blend = blend; +} + +OpenGL::BlendState OpenGL::getBlendState() const +{ + return state.blend; +} + void OpenGL::setTextureUnit(int textureunit) { if (textureunit < 0 || (size_t) textureunit >= state.textureUnits.size()) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 2fd253381..b912d4aac 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -94,6 +94,13 @@ public: } }; + struct BlendState + { + GLenum srcRGB, srcA; + GLenum dstRGB, dstA; + GLenum func; + }; + OpenGL(); /** @@ -167,6 +174,17 @@ public: **/ Viewport getScissor() const; + /** + * Sets blending functionality. + * Note: This does not globally enable or disable blending. + **/ + void setBlendState(const BlendState &blend); + + /** + * Gets the currently set blending functionality. + **/ + BlendState getBlendState() const; + /** * Helper for setting the active texture unit. * @@ -267,6 +285,8 @@ private: Viewport viewport; Viewport scissor; + BlendState blend; + // The last ID value used for pseudo-instancing. int lastPseudoInstanceID; From ce4fdf4ac9dbf958c2529e3a6586536a41babd83 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 2 Feb 2014 18:31:41 -0400 Subject: [PATCH 31/56] Added sRGB (gamma-correct) support for Images, Canvases, and the main screen. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit love.graphics.newImage(path, “srgb”) creates a new Image whose texels are treated as being in the sRGB color space, so they are linearized when drawing/sampling from the image. love.graphics.newCanvas(w, h, “srgb”) creates a new Canvas whose texels are treated as being in the sRGB color space, so drawing to the Canvas does a linear->sRGB conversion (but blends linearly), and sampling from it (drawing it or using it in a shader) converts from sRGB to linear space. The "srgb" window flag does the same as Canvases for the main screen. --- src/modules/graphics/Graphics.cpp | 1 + src/modules/graphics/Graphics.h | 3 +- src/modules/graphics/Texture.cpp | 19 +++++ src/modules/graphics/Texture.h | 14 ++++ src/modules/graphics/opengl/Canvas.cpp | 72 +++++++++++-------- src/modules/graphics/opengl/Canvas.h | 26 +++---- src/modules/graphics/opengl/Graphics.cpp | 42 ++++++++--- src/modules/graphics/opengl/Graphics.h | 8 +-- src/modules/graphics/opengl/Image.cpp | 51 ++++++++++--- src/modules/graphics/opengl/Image.h | 13 +++- src/modules/graphics/opengl/wrap_Canvas.cpp | 13 ++-- src/modules/graphics/opengl/wrap_Canvas.h | 2 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 33 ++++++--- src/modules/window/Window.cpp | 2 + src/modules/window/Window.h | 2 + src/modules/window/sdl/Window.cpp | 18 +++-- src/modules/window/sdl/Window.h | 4 +- src/modules/window/wrap_Window.cpp | 4 ++ src/scripts/boot.lua | 2 + src/scripts/boot.lua.h | 3 + 20 files changed, 237 insertions(+), 95 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index f29ae4a47..10f8cf8e1 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -186,6 +186,7 @@ StringMap::Entry Graphics::suppor { "dxt", Graphics::SUPPORT_DXT }, { "bc5", Graphics::SUPPORT_BC5 }, { "instancing", Graphics::SUPPORT_INSTANCING }, + { "srgb", Graphics::SUPPORT_SRGB }, }; StringMap Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries)); diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 25fc45c50..e91d96e8f 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -95,6 +95,7 @@ public: SUPPORT_DXT, SUPPORT_BC5, SUPPORT_INSTANCING, + SUPPORT_SRGB, SUPPORT_MAX_ENUM }; @@ -128,7 +129,7 @@ public: * @param width The viewport width. * @param height The viewport height. **/ - virtual bool setMode(int width, int height) = 0; + virtual bool setMode(int width, int height, bool &sRGB) = 0; /** * Un-sets the current graphics display mode (uninitializing objects if diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 25034a3d0..0a8d85541 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -109,6 +109,16 @@ bool Texture::getConstant(WrapMode in, const char *&out) return wrapModes.find(in, out); } +bool Texture::getConstant(const char *in, Format &out) +{ + return formats.find(in, out); +} + +bool Texture::getConstant(Format in, const char *&out) +{ + return formats.find(in, out); +} + StringMap::Entry Texture::filterModeEntries[] = { { "linear", Texture::FILTER_LINEAR }, @@ -125,6 +135,15 @@ StringMap::Entry Texture::wrapModeEnt StringMap Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries)); +StringMap::Entry Texture::formatEntries[] = +{ + {"normal", Texture::FORMAT_NORMAL}, + {"hdr", Texture::FORMAT_HDR}, + {"srgb", Texture::FORMAT_SRGB}, +}; + +StringMap Texture::formats(Texture::formatEntries, sizeof(Texture::formatEntries)); + } // graphics } // love diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 7b5a525a4..d9c83171e 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -55,6 +55,14 @@ public: FILTER_MAX_ENUM }; + enum Format + { + FORMAT_NORMAL, + FORMAT_HDR, + FORMAT_SRGB, + FORMAT_MAX_ENUM + }; + struct Filter { Filter(); @@ -111,6 +119,9 @@ public: static bool getConstant(const char *in, WrapMode &out); static bool getConstant(WrapMode in, const char *&out); + static bool getConstant(const char *in, Format &out); + static bool getConstant(Format in, const char *&out); + protected: int width; @@ -132,6 +143,9 @@ private: static StringMap::Entry wrapModeEntries[]; static StringMap wrapModes; + static StringMap::Entry formatEntries[]; + static StringMap formats; + }; // Texture } // graphics diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 090aeb028..ed9ff6113 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -369,7 +369,7 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT } }; -FramebufferStrategy *strategy = NULL; +FramebufferStrategy *strategy = nullptr; FramebufferStrategy strategyNone; @@ -379,8 +379,9 @@ FramebufferStrategyPackedEXT strategyPackedEXT; FramebufferStrategyEXT strategyEXT; -Canvas *Canvas::current = NULL; +Canvas *Canvas::current = nullptr; OpenGL::Viewport Canvas::systemViewport = OpenGL::Viewport(); +bool Canvas::screenHasSRGB = false; static void getStrategy() { @@ -397,13 +398,13 @@ static void getStrategy() } } -Canvas::Canvas(int width, int height, TextureType texture_type, int fsaa) +Canvas::Canvas(int width, int height, Texture::Format format, int fsaa) : fbo(0) , resolve_fbo(0) , texture(0) , fsaa_buffer(0) , depth_stencil(0) - , texture_type(texture_type) + , format(format) , fsaa_samples(fsaa) , fsaa_dirty(false) { @@ -507,13 +508,17 @@ bool Canvas::loadVolatile() GLint internalformat; GLenum textype; - switch (texture_type) + switch (format) { - case TYPE_HDR: + case Texture::FORMAT_HDR: internalformat = GL_RGBA16F; textype = GL_FLOAT; break; - case TYPE_NORMAL: + case Texture::FORMAT_SRGB: + internalformat = GL_SRGB8_ALPHA8; + textype = GL_UNSIGNED_BYTE; + break; + case Texture::FORMAT_NORMAL: default: internalformat = GL_RGBA8; textype = GL_UNSIGNED_BYTE; @@ -681,6 +686,12 @@ void Canvas::setupGrab() // Switch back to modelview matrix glMatrixMode(GL_MODELVIEW); + // Make sure the correct sRGB setting is used when drawing to the canvas. + if (format == FORMAT_SRGB) + glEnable(GL_FRAMEBUFFER_SRGB); + else if (screenHasSRGB) + glDisable(GL_FRAMEBUFFER_SRGB); + if (fsaa_buffer != 0) fsaa_dirty = true; } @@ -708,8 +719,8 @@ void Canvas::startGrab(const std::vector &canvases) if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height) throw love::Exception("All canvas arguments must have the same dimensions."); - if (canvases[i]->getTextureType() != texture_type) - throw love::Exception("All canvas arguments must have the same texture type."); + if (canvases[i]->getTextureFormat() != format) + throw love::Exception("All canvas arguments must have the same texture format."); if (canvases[i]->getFSAA() != 0) throw love::Exception("Multi-canvas rendering is not supported with FSAA."); @@ -763,12 +774,22 @@ void Canvas::stopGrab(bool switchingToOtherCanvas) glPopMatrix(); glMatrixMode(GL_MODELVIEW); - // bind default - if (!switchingToOtherCanvas) + if (switchingToOtherCanvas) { + if (format == FORMAT_SRGB) + glDisable(GL_FRAMEBUFFER_SRGB); + } + else + { + // bind system framebuffer. strategy->bindFBO(0); current = nullptr; gl.setViewport(systemViewport); + + if (format == FORMAT_SRGB && !screenHasSRGB) + glDisable(GL_FRAMEBUFFER_SRGB); + else if (format != FORMAT_SRGB && screenHasSRGB) + glEnable(GL_FRAMEBUFFER_SRGB); } } @@ -940,6 +961,18 @@ bool Canvas::isHDRSupported() return GLEE_VERSION_3_0 || (isSupported() && GLEE_ARB_texture_float); } +bool Canvas::isSRGBSupported() +{ + if (GLEE_VERSION_3_0) + return true; + + if (!isSupported()) + return false; + + return (GLEE_ARB_framebuffer_sRGB || GLEE_EXT_framebuffer_sRGB) + && GLEE_EXT_texture_sRGB; +} + bool Canvas::isMultiCanvasSupported() { // system must support at least 4 simultanious active canvases. @@ -952,23 +985,6 @@ void Canvas::bindDefaultCanvas() current->stopGrab(); } -bool Canvas::getConstant(const char *in, Canvas::TextureType &out) -{ - return textureTypes.find(in, out); -} - -bool Canvas::getConstant(Canvas::TextureType in, const char *&out) -{ - return textureTypes.find(in, out); -} - -StringMap::Entry Canvas::textureTypeEntries[] = -{ - {"normal", Canvas::TYPE_NORMAL}, - {"hdr", Canvas::TYPE_HDR}, -}; -StringMap Canvas::textureTypes(Canvas::textureTypeEntries, sizeof(Canvas::textureTypeEntries)); - } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 86db8f0f9..2d87b0bbc 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -39,14 +39,7 @@ class Canvas : public Texture { public: - enum TextureType - { - TYPE_NORMAL, - TYPE_HDR, - TYPE_MAX_ENUM - }; - - Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL, int fsaa = 0); + Canvas(int width, int height, Texture::Format format = Texture::FORMAT_NORMAL, int fsaa = 0); virtual ~Canvas(); // Implements Volatile. @@ -92,9 +85,9 @@ public: return status; } - inline TextureType getTextureType() const + inline Texture::Format getTextureFormat() const { - return texture_type; + return format; } inline int getFSAA() const @@ -106,17 +99,18 @@ public: static bool isSupported(); static bool isHDRSupported(); + static bool isSRGBSupported(); static bool isMultiCanvasSupported(); - static bool getConstant(const char *in, TextureType &out); - static bool getConstant(TextureType in, const char *&out); - static Canvas *current; static void bindDefaultCanvas(); // The viewport dimensions of the system (default) framebuffer. static OpenGL::Viewport systemViewport; + // Whether the main screen should have linear -> sRGB conversions enabled. + static bool screenHasSRGB; + private: bool createFSAAFBO(GLenum internalformat); @@ -128,7 +122,7 @@ private: GLuint fsaa_buffer; GLuint depth_stencil; - TextureType texture_type; + Format format; GLenum status; @@ -140,9 +134,7 @@ private: void setupGrab(); void drawv(const Matrix &t, const Vertex *v); - static StringMap::Entry textureTypeEntries[]; - static StringMap textureTypes; -}; +}; // Canvas } // opengl } // graphics diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 8539c140b..64298dc51 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -57,8 +57,13 @@ Graphics::Graphics() { currentWindow = love::window::sdl::Window::createSingleton(); + int w, h; + love::window::WindowSettings wsettings; + + currentWindow->getWindow(w, h, wsettings); + if (currentWindow->isCreated()) - setMode(currentWindow->getWidth(), currentWindow->getHeight()); + setMode(w, h, wsettings.sRGB); } Graphics::~Graphics() @@ -150,7 +155,7 @@ void Graphics::setViewportSize(int width, int height) c->startGrab(c->getAttachedCanvases()); } -bool Graphics::setMode(int width, int height) +bool Graphics::setMode(int width, int height, bool &sRGB) { this->width = width; this->height = height; @@ -207,6 +212,19 @@ bool Graphics::setMode(int width, int height) glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &matrixLimit); matrixLimit -= 5; + // Set whether drawing converts input from linear -> sRGB colorspace. + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_sRGB || GLEE_EXT_framebuffer_sRGB) + { + if (sRGB) + glEnable(GL_FRAMEBUFFER_SRGB); + else + glDisable(GL_FRAMEBUFFER_SRGB); + } + else + sRGB = false; + + Canvas::screenHasSRGB = sRGB; + bool enabledebug = false; if (GLEE_VERSION_3_0) @@ -284,6 +302,9 @@ void Graphics::setDebug(bool enable) glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); + if (GLEE_VERSION_4_3 || GLEE_KHR_debug) + glEnable(GL_DEBUG_OUTPUT); + ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n"); } @@ -374,10 +395,10 @@ void Graphics::discardStencil() glDisable(GL_STENCIL_TEST); } -Image *Graphics::newImage(love::image::ImageData *data) +Image *Graphics::newImage(love::image::ImageData *data, Texture::Format format) { // Create the image. - Image *image = new Image(data); + Image *image = new Image(data, format); if (!isCreated()) return image; @@ -401,10 +422,10 @@ Image *Graphics::newImage(love::image::ImageData *data) return image; } -Image *Graphics::newImage(love::image::CompressedData *cdata) +Image *Graphics::newImage(love::image::CompressedData *cdata, Texture::Format format) { // Create the image. - Image *image = new Image(cdata); + Image *image = new Image(cdata, format); if (!isCreated()) return image; @@ -448,11 +469,14 @@ ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size) return new ParticleSystem(texture, size); } -Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type, int fsaa) +Canvas *Graphics::newCanvas(int width, int height, Texture::Format format, int fsaa) { - if (texture_type == Canvas::TYPE_HDR && !Canvas::isHDRSupported()) + if (format == Texture::FORMAT_HDR && !Canvas::isHDRSupported()) throw Exception("HDR Canvases are not supported by your OpenGL implementation"); + if (format == Texture::FORMAT_SRGB && !Canvas::isSRGBSupported()) + throw Exception("sRGB Canvases are not supported by your OpenGL implementation"); + if (width > gl.getMaxTextureSize()) throw Exception("Cannot create canvas: width of %d pixels is too large for this system.", width); else if (height > gl.getMaxTextureSize()) @@ -461,7 +485,7 @@ Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_t while (GL_NO_ERROR != glGetError()) /* clear opengl error flag */; - Canvas *canvas = new Canvas(width, height, texture_type, fsaa); + Canvas *canvas = new Canvas(width, height, format, fsaa); GLenum err = canvas->getStatus(); // everything ok, return canvas (early out) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index ecba2806e..276b06378 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -112,7 +112,7 @@ public: void restoreState(const DisplayState &s); virtual void setViewportSize(int width, int height); - virtual bool setMode(int width, int height); + virtual bool setMode(int width, int height, bool &sRGB); virtual void unSetMode(); void setDebug(bool enable); @@ -191,8 +191,8 @@ public: /** * Creates an Image object with padding and/or optimization. **/ - Image *newImage(love::image::ImageData *data); - Image *newImage(love::image::CompressedData *cdata); + Image *newImage(love::image::ImageData *data, Texture::Format format = Texture::FORMAT_NORMAL); + Image *newImage(love::image::CompressedData *cdata, Texture::Format format = Texture::FORMAT_NORMAL); Quad *newQuad(Quad::Viewport v, float sw, float sh); @@ -205,7 +205,7 @@ public: ParticleSystem *newParticleSystem(Texture *texture, int size); - Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL, int fsaa = 0); + Canvas *newCanvas(int width, int height, Texture::Format format = Texture::FORMAT_NORMAL, int fsaa = 0); Shader *newShader(const Shader::ShaderSources &sources); diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index e3ef771dd..2166fd4a5 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -36,7 +36,7 @@ float Image::maxMipmapSharpness = 0.0f; Texture::FilterMode Image::defaultMipmapFilter = Texture::FILTER_NONE; float Image::defaultMipmapSharpness = 0.0f; -Image::Image(love::image::ImageData *data) +Image::Image(love::image::ImageData *data, Texture::Format format) : data(data) , cdata(nullptr) , paddedWidth(width) @@ -45,6 +45,7 @@ Image::Image(love::image::ImageData *data) , mipmapSharpness(defaultMipmapSharpness) , mipmapsCreated(false) , compressed(false) + , format(format) , usingDefaultTexture(false) { width = data->getWidth(); @@ -54,7 +55,7 @@ Image::Image(love::image::ImageData *data) preload(); } -Image::Image(love::image::CompressedData *cdata) +Image::Image(love::image::CompressedData *cdata, Texture::Format format) : data(nullptr) , cdata(cdata) , paddedWidth(width) @@ -63,6 +64,7 @@ Image::Image(love::image::CompressedData *cdata) , mipmapSharpness(defaultMipmapSharpness) , mipmapsCreated(false) , compressed(true) + , format(format) , usingDefaultTexture(false) { width = cdata->getWidth(0); @@ -328,6 +330,9 @@ void Image::unload() bool Image::loadVolatile() { + if (format == FORMAT_SRGB && !hasSRGBSupport()) + throw love::Exception("sRGB images are not supported on this system."); + if (isCompressed() && cdata && !hasCompressedTextureSupport(cdata->getFormat())) { const char *str; @@ -400,9 +405,10 @@ void Image::uploadTexturePadded() } else if (data) { + GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB8_ALPHA8 : GL_RGBA8; glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA8, + iformat, (GLsizei)paddedWidth, (GLsizei)paddedHeight, 0, @@ -437,9 +443,10 @@ void Image::uploadTexture() } else if (data) { + GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB8_ALPHA8 : GL_RGBA8; glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA8, + iformat, (GLsizei)width, (GLsizei)height, 0, @@ -497,6 +504,11 @@ bool Image::refresh() return true; } +Texture::Format Image::getFormat() const +{ + return format; +} + void Image::uploadDefaultTexture() { usingDefaultTexture = true; @@ -561,16 +573,27 @@ bool Image::isCompressed() const return compressed; } -GLenum Image::getCompressedFormat(image::CompressedData::Format format) const +GLenum Image::getCompressedFormat(image::CompressedData::Format cformat) const { - switch (format) + bool srgb = format == FORMAT_SRGB; + + switch (cformat) { case image::CompressedData::FORMAT_DXT1: - return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + if (srgb) + return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + else + return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; case image::CompressedData::FORMAT_DXT3: - return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + if (srgb) + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + else + return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; case image::CompressedData::FORMAT_DXT5: - return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + if (srgb) + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + else + return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; case image::CompressedData::FORMAT_BC4: return GL_COMPRESSED_RED_RGTC1; case image::CompressedData::FORMAT_BC4s: @@ -580,7 +603,10 @@ GLenum Image::getCompressedFormat(image::CompressedData::Format format) const case image::CompressedData::FORMAT_BC5s: return GL_COMPRESSED_SIGNED_RG_RGTC2; default: - return GL_RGBA8; + if (srgb) + return GL_SRGB8_ALPHA8; + else + return GL_RGBA8; } } @@ -632,6 +658,11 @@ bool Image::hasCompressedTextureSupport(image::CompressedData::Format format) return false; } +bool Image::hasSRGBSupport() +{ + return GLEE_VERSION_2_1 || GLEE_EXT_texture_sRGB; +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 865c5f3bd..d23f385ec 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -56,14 +56,14 @@ public: * * @param data The data from which to load the image. **/ - Image(love::image::ImageData *data); + Image(love::image::ImageData *data, Texture::Format format = Texture::FORMAT_NORMAL); /** * Creates a new Image with compressed image data. * * @param cdata The compressed data from which to load the image. **/ - Image(love::image::CompressedData *cdata); + Image(love::image::CompressedData *cdata, Texture::Format format = Texture::FORMAT_NORMAL); /** * Destructor. Deletes the hardware texture and other resources. @@ -120,6 +120,8 @@ public: **/ bool refresh(); + Texture::Format getFormat() const; + static void setDefaultMipmapSharpness(float sharpness); static float getDefaultMipmapSharpness(); static void setDefaultMipmapFilter(FilterMode f); @@ -133,6 +135,8 @@ public: static bool hasCompressedTextureSupport(); static bool hasCompressedTextureSupport(image::CompressedData::Format format); + static bool hasSRGBSupport(); + private: void uploadDefaultTexture(); @@ -162,6 +166,9 @@ private: // Whether this Image is using a compressed texture. bool compressed; + // The format to interpret the texture's data as. + Texture::Format format; + // True if the image wasn't able to be properly created and it had to fall // back to a default texture. bool usingDefaultTexture; @@ -180,7 +187,7 @@ private: static FilterMode defaultMipmapFilter; static float defaultMipmapSharpness; - GLenum getCompressedFormat(image::CompressedData::Format format) const; + GLenum getCompressedFormat(image::CompressedData::Format cformat) const; }; // Image diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index cbc9b6ed9..a3c31b7f9 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -110,12 +110,14 @@ int w_Canvas_clear(lua_State *L) return 0; } -int w_Canvas_getType(lua_State *L) +int w_Canvas_getFormat(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - Canvas::TextureType type = canvas->getTextureType(); + Texture::Format format = canvas->getTextureFormat(); const char *str; - Canvas::getConstant(type, str); + if (!Texture::getConstant(format, str)) + return luaL_error(L, "Unknown texture format."); + lua_pushstring(L, str); return 1; } @@ -142,8 +144,11 @@ static const luaL_Reg functions[] = { "getImageData", w_Canvas_getImageData }, { "getPixel", w_Canvas_getPixel }, { "clear", w_Canvas_clear }, - { "getType", w_Canvas_getType }, + { "getFormat", w_Canvas_getFormat }, { "getFSAA", w_Canvas_getFSAA }, + + // Deprecated since 0.9.1. + { "getType", w_Canvas_getFormat }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Canvas.h b/src/modules/graphics/opengl/wrap_Canvas.h index 89c7952f2..4e48ffe03 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.h +++ b/src/modules/graphics/opengl/wrap_Canvas.h @@ -39,7 +39,7 @@ int w_Canvas_renderTo(lua_State *L); int w_Canvas_getImageData(lua_State *L); int w_Canvas_getPixel(lua_State * L); int w_Canvas_clear(lua_State *L); -int w_Canvas_getType(lua_State *L); +int w_Canvas_getFormat(lua_State *L); int w_Canvas_getFSAA(lua_State *L); extern "C" int luaopen_canvas(lua_State *L); diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 4026de632..7cd02c52f 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -152,8 +152,17 @@ int w_getMaxTextureSize(lua_State *L) int w_newImage(lua_State *L) { - love::image::ImageData *data = 0; - love::image::CompressedData *cdata = 0; + love::image::ImageData *data = nullptr; + love::image::CompressedData *cdata = nullptr; + + Texture::Format format = Texture::FORMAT_NORMAL; + const char *fstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2); + + if (fstr != nullptr && !Texture::getConstant(fstr, format)) + return luaL_error(L, "Invalid texture format: %s", fstr); + + if (format == Texture::FORMAT_HDR) // For now... + return luaL_error(L, "HDR images are not supported."); // Convert to FileData, if necessary. if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T)) @@ -185,15 +194,15 @@ int w_newImage(lua_State *L) return luaL_error(L, "Error creating image."); // Create the image. - Image *image = 0; + Image *image = nullptr; EXCEPT_GUARD( if (cdata) - image = instance->newImage(cdata); + image = instance->newImage(cdata, format); else if (data) - image = instance->newImage(data); + image = instance->newImage(data, format); ) - if (image == 0) + if (image == nullptr) return luaL_error(L, "Could not load image."); // Push the type. @@ -325,12 +334,12 @@ int w_newCanvas(lua_State *L) const char *str = luaL_optstring(L, 3, "normal"); int fsaa = luaL_optint(L, 4, 0); - Canvas::TextureType texture_type; - if (!Canvas::getConstant(str, texture_type)) - return luaL_error(L, "Invalid canvas type: %s", str); + Texture::Format format; + if (!Texture::getConstant(str, format)) + return luaL_error(L, "Invalid texture format: %s", str); Canvas *canvas = nullptr; - EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type, fsaa);) + EXCEPT_GUARD(canvas = instance->newCanvas(width, height, format, fsaa);) if (canvas == nullptr) return luaL_error(L, "Canvas not created, but no error thrown. I don't even..."); @@ -999,6 +1008,10 @@ int w_isSupported(lua_State *L) if (!GLEE_ARB_draw_instanced) supported = false; break; + case Graphics::SUPPORT_SRGB: + if (!Canvas::isSRGBSupported()) + supported = false; + break; default: supported = false; } diff --git a/src/modules/window/Window.cpp b/src/modules/window/Window.cpp index 6243830aa..1e3216c8a 100644 --- a/src/modules/window/Window.cpp +++ b/src/modules/window/Window.cpp @@ -50,6 +50,7 @@ WindowSettings::WindowSettings() , centered(true) , display(0) , highdpi(false) + , sRGB(false) { } @@ -86,6 +87,7 @@ StringMap::Entry Window::settingEntri {"centered", SETTING_CENTERED}, {"display", SETTING_DISPLAY}, {"highdpi", SETTING_HIGHDPI}, + {"srgb", SETTING_SRGB}, }; StringMap Window::settings(Window::settingEntries, sizeof(Window::settingEntries)); diff --git a/src/modules/window/Window.h b/src/modules/window/Window.h index ad247fd0b..b52900c66 100644 --- a/src/modules/window/Window.h +++ b/src/modules/window/Window.h @@ -57,6 +57,7 @@ public: SETTING_CENTERED, SETTING_DISPLAY, SETTING_HIGHDPI, + SETTING_SRGB, SETTING_MAX_ENUM }; @@ -157,6 +158,7 @@ struct WindowSettings bool centered; // = true int display; // = 0 bool highdpi; // false + bool sRGB; // false }; // WindowSettings diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 6f5f0f6e1..a5b0d1326 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -154,7 +154,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) if (!window) { // In Windows and Linux, some GL attributes are set on window creation. - setWindowGLAttributes(f.fsaa); + setWindowGLAttributes(f.fsaa, f.sRGB); const char *title = windowTitle.c_str(); int pos = f.centered ? centeredpos : uncenteredpos; @@ -190,7 +190,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) SDL_RaiseWindow(window); - if (!setContext(f.fsaa, f.vsync)) + if (!setContext(f.fsaa, f.vsync, f.sRGB)) return false; created = true; @@ -206,7 +206,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) SDL_GL_GetDrawableSize(window, &width, &height); #endif - gfx->setMode(width, height); + gfx->setMode(width, height, curMode.settings.sRGB); } // Make sure the mouse keeps its previous grab setting. @@ -226,7 +226,7 @@ bool Window::onWindowResize(int width, int height) return true; } -bool Window::setContext(int fsaa, bool vsync) +bool Window::setContext(int fsaa, bool vsync, bool sRGB) { // We would normally only need to recreate the context if FSAA changes or // SDL_GL_MakeCurrent is unsuccessful, but in Windows MakeCurrent can @@ -238,7 +238,7 @@ bool Window::setContext(int fsaa, bool vsync) } // Make sure the proper attributes are set. - setWindowGLAttributes(fsaa); + setWindowGLAttributes(fsaa, sRGB); context = SDL_GL_CreateContext(window); @@ -290,7 +290,7 @@ bool Window::setContext(int fsaa, bool vsync) return true; } -void Window::setWindowGLAttributes(int fsaa) const +void Window::setWindowGLAttributes(int fsaa, bool sRGB) const { // Set GL window attributes. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); @@ -304,6 +304,10 @@ void Window::setWindowGLAttributes(int fsaa) const SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); +#if SDL_VERSION_ATLEAST(2,0,1) + SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0); +#endif + // Do we want a debug context? const char *debugenv = SDL_GetHint("LOVE_GRAPHICS_DEBUG"); if (debugenv && *debugenv == '1') @@ -370,6 +374,8 @@ void Window::updateSettings(const WindowSettings &newsettings) else #endif SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); + + curMode.settings.sRGB = newsettings.sRGB; } void Window::getWindow(int &width, int &height, WindowSettings &settings) diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index 81796663a..3af5d46c5 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -90,8 +90,8 @@ public: private: - bool setContext(int fsaa, bool vsync); - void setWindowGLAttributes(int fsaa) const; + bool setContext(int fsaa, bool vsync, bool sRGB); + void setWindowGLAttributes(int fsaa, bool sRGB) const; // Update the saved window settings based on the window's actual state. void updateSettings(const WindowSettings &newsettings); diff --git a/src/modules/window/wrap_Window.cpp b/src/modules/window/wrap_Window.cpp index 395875111..42c14fa74 100644 --- a/src/modules/window/wrap_Window.cpp +++ b/src/modules/window/wrap_Window.cpp @@ -96,6 +96,7 @@ int w_setMode(lua_State *L) settings.centered = luax_boolflag(L, 3, settingName(Window::SETTING_CENTERED), true); settings.display = luax_intflag(L, 3, settingName(Window::SETTING_DISPLAY), 1); settings.highdpi = luax_boolflag(L, 3, settingName(Window::SETTING_HIGHDPI), false); + settings.sRGB = luax_boolflag(L, 3, settingName(Window::SETTING_SRGB), false); // Display index is 1-based in Lua and 0-based internally. settings.display--; @@ -151,6 +152,9 @@ int w_getMode(lua_State *L) luax_pushboolean(L, settings.highdpi); lua_setfield(L, -2, settingName(Window::SETTING_HIGHDPI)); + luax_pushboolean(L, settings.sRGB); + lua_setfield(L, -2, settingName(Window::SETTING_SRGB)); + return 3; } diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index df1f8cd3b..d5cc212fd 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -301,6 +301,7 @@ function love.init() resizable = false, centered = true, highdpi = false, + srgb = false, }, modules = { event = true, @@ -390,6 +391,7 @@ function love.init() centered = c.window.centered, display = c.window.display, highdpi = c.window.highdpi, + srgb = c.window.srgb, }), "Could not set window mode") love.window.setTitle(c.window.title or c.title) if c.window.icon then diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 892d7dc88..aeb746199 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -539,6 +539,7 @@ const unsigned char boot_lua[] = 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x73, 0x72, 0x67, 0x62, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x2c, 0x0a, 0x09, 0x09, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, @@ -672,6 +673,8 @@ const unsigned char boot_lua[] = 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x73, 0x72, 0x67, 0x62, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, + 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x65, 0x74, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x54, From b625bb6624ae07f7019c3d3fb45ff6e93e4fb8df Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 3 Feb 2014 04:59:58 -0400 Subject: [PATCH 32/56] moved Mesh:setWireframe to love.graphics.setWireframe (affects all draws until it's disabled.) Wireframe mode should only be used for debugging: the wireframe lines behave differently than regular lines, their widths aren't affected by the graphics scale, and the mode isn't available on OpenGL ES. --- src/modules/graphics/opengl/Graphics.cpp | 14 ++++++++++++++ src/modules/graphics/opengl/Graphics.h | 17 +++++++++++++++++ src/modules/graphics/opengl/Mesh.cpp | 18 ------------------ src/modules/graphics/opengl/Mesh.h | 11 ----------- src/modules/graphics/opengl/wrap_Graphics.cpp | 14 ++++++++++++++ src/modules/graphics/opengl/wrap_Graphics.h | 2 ++ src/modules/graphics/opengl/wrap_Mesh.cpp | 16 ---------------- src/modules/graphics/opengl/wrap_Mesh.h | 2 -- 8 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 64298dc51..5df3d4d0a 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -102,6 +102,8 @@ DisplayState Graphics::saveState() for (int i = 0; i < 4; i++) s.colorMask[i] = colorMask[i]; + wireframe = isWireframe(); + return s; } @@ -119,6 +121,7 @@ void Graphics::restoreState(const DisplayState &s) else setScissor(); setColorMask(s.colorMask[0], s.colorMask[1], s.colorMask[2], s.colorMask[3]); + setWireframe(s.wireframe); } void Graphics::setViewportSize(int width, int height) @@ -749,6 +752,17 @@ Graphics::PointStyle Graphics::getPointStyle() const return POINT_ROUGH; } +void Graphics::setWireframe(bool enable) +{ + wireframe = enable; + glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL); +} + +bool Graphics::isWireframe() const +{ + return wireframe; +} + 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 != nullptr) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 276b06378..b68755d08 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -81,6 +81,8 @@ struct DisplayState // Color mask. bool colorMask[4]; + bool wireframe; + // Default values. DisplayState() { @@ -93,6 +95,7 @@ struct DisplayState pointStyle = Graphics::POINT_SMOOTH; scissor = false; colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = true; + wireframe = false; } }; @@ -334,6 +337,19 @@ public: **/ PointStyle getPointStyle() const; + /** + * Sets whether graphics will be drawn as wireframe lines instead of filled + * triangles (has no effect for drawn points.) + * This should only be used as a debugging tool. The wireframe lines do not + * behave the same as regular love.graphics lines. + **/ + void setWireframe(bool enable); + + /** + * Gets whether wireframe drawing mode is enabled. + **/ + bool isWireframe() const; + /** * Draws text at the specified coordinates, with rotation and * scaling along both axes. @@ -460,6 +476,7 @@ private: GLint matrixLimit; GLint userMatrices; bool colorMask[4]; + bool wireframe; int width; int height; diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index d440bc786..62b8275c3 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -44,7 +44,6 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) , range_max(-1) , texture(nullptr) , colors_enabled(false) - , wireframe(false) { setVertices(verts); } @@ -59,7 +58,6 @@ Mesh::Mesh(int vertexcount, Mesh::DrawMode mode) , range_max(-1) , texture(nullptr) , colors_enabled(false) - , wireframe(false) { if (vertexcount < 1) throw love::Exception("Invalid number of vertices."); @@ -278,16 +276,6 @@ bool Mesh::hasVertexColors() const return colors_enabled; } -void Mesh::setWireframe(bool enable) -{ - wireframe = enable; -} - -bool Mesh::isWireframe() const -{ - return wireframe; -} - void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { const size_t pos_offset = offsetof(Vertex, x); @@ -326,9 +314,6 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), vbo->getPointer(color_offset)); } - if (wireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - GLenum mode = getGLDrawMode(draw_mode); gl.prepareDraw(); @@ -374,9 +359,6 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo glDrawArrays(mode, min, max - min + 1); } - if (wireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 3a5029a4d..5e6e974fe 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -162,15 +162,6 @@ public: void setVertexColors(bool enable); bool hasVertexColors() const; - /** - * Sets whether the Mesh will be drawn as wireframe lines instead of filled - * triangles (has no effect for DRAW_MODE_POINTS.) - * This should only be used as a debugging tool. The wireframe lines do not - * behave the same as regular love.graphics lines. - **/ - void setWireframe(bool enable); - bool isWireframe() const; - // Implements Drawable. void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); @@ -201,8 +192,6 @@ private: // Whether the per-vertex colors are used when drawing. bool colors_enabled; - bool wireframe; - static StringMap::Entry drawModeEntries[]; static StringMap drawModes; diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 7cd02c52f..e7d6a6d74 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -844,6 +844,18 @@ int w_getMaxPointSize(lua_State *L) return 1; } +int w_setWireframe(lua_State *L) +{ + instance->setWireframe(luax_toboolean(L, 1)); + return 0; +} + +int w_isWireframe(lua_State *L) +{ + luax_pushboolean(L, instance->isWireframe()); + return 1; +} + int w_newScreenshot(lua_State *L) { love::image::Image *image = luax_getmodule(L, "image", MODULE_IMAGE_T); @@ -1388,6 +1400,8 @@ static const luaL_Reg functions[] = { "setPointStyle", w_setPointStyle }, { "getPointSize", w_getPointSize }, { "getPointStyle", w_getPointStyle }, + { "setWireframe", w_setWireframe }, + { "isWireframe", w_isWireframe }, { "newScreenshot", w_newScreenshot }, { "setCanvas", w_setCanvas }, { "getCanvas", w_getCanvas }, diff --git a/src/modules/graphics/opengl/wrap_Graphics.h b/src/modules/graphics/opengl/wrap_Graphics.h index 60c525121..85977cca6 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.h +++ b/src/modules/graphics/opengl/wrap_Graphics.h @@ -85,6 +85,8 @@ int w_setPointStyle(lua_State *L); int w_getPointSize(lua_State *L); int w_getPointStyle(lua_State *L); int w_getMaxPointSize(lua_State *L); +int w_setWireframe(lua_State *L); +int w_isWireframe(lua_State *L); int w_newScreenshot(lua_State *L); int w_setCanvas(lua_State *L); int w_getCanvas(lua_State *L); diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index 4548030a1..e3e8800b9 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -361,20 +361,6 @@ int w_Mesh_hasVertexColors(lua_State *L) return 1; } -int w_Mesh_setWireframe(lua_State *L) -{ - Mesh *t = luax_checkmesh(L, 1); - t->setWireframe(luax_toboolean(L, 2)); - return 0; -} - -int w_Mesh_isWireframe(lua_State *L) -{ - Mesh *t = luax_checkmesh(L, 1); - luax_pushboolean(L, t->isWireframe()); - return 1; -} - static const luaL_Reg functions[] = { { "setVertex", w_Mesh_setVertex }, @@ -394,8 +380,6 @@ static const luaL_Reg functions[] = { "getDrawRange", w_Mesh_getDrawRange }, { "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 }, diff --git a/src/modules/graphics/opengl/wrap_Mesh.h b/src/modules/graphics/opengl/wrap_Mesh.h index 9b4cdc77a..aa7c0f08b 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.h +++ b/src/modules/graphics/opengl/wrap_Mesh.h @@ -51,8 +51,6 @@ int w_Mesh_setDrawRange(lua_State *L); int w_Mesh_getDrawRange(lua_State *L); int w_Mesh_setVertexColors(lua_State *L); int w_Mesh_hasVertexColors(lua_State *L); -int w_Mesh_setWireframe(lua_State *L); -int w_Mesh_isWireframe(lua_State *L); extern "C" int luaopen_mesh(lua_State *L); From 823b1babc89e4a8f6ca6ef38fea3b8d9a409685e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2014 02:02:54 -0400 Subject: [PATCH 33/56] Specifying the srgb window flag should now cause it to fall back to srgb=false in all situations if an srgb-capable system framebuffer isn't supported, instead of failing to create the window --- src/modules/window/sdl/Window.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index a5b0d1326..44662e728 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -82,7 +82,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) f.minwidth = std::max(f.minwidth, 1); f.minheight = std::max(f.minheight, 1); - f.display = std::min(std::max(f.display, 0), getDisplayCount()); + f.display = std::min(std::max(f.display, 0), getDisplayCount() - 1); // Use the desktop resolution if a width or height of 0 is specified. if (width == 0 || height == 0) @@ -290,7 +290,7 @@ bool Window::setContext(int fsaa, bool vsync, bool sRGB) return true; } -void Window::setWindowGLAttributes(int fsaa, bool sRGB) const +void Window::setWindowGLAttributes(int fsaa, bool /* sRGB */) const { // Set GL window attributes. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); @@ -304,9 +304,14 @@ void Window::setWindowGLAttributes(int fsaa, bool sRGB) const SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); + /* FIXME: Enable this code but make sure to try to re-create the window and + * context with this disabled, if creation fails with it enabled. + * We can leave this out for now because in practice the framebuffer will + * already be sRGB-capable (on desktops at least.) #if SDL_VERSION_ATLEAST(2,0,1) SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0); #endif + */ // Do we want a debug context? const char *debugenv = SDL_GetHint("LOVE_GRAPHICS_DEBUG"); From e54d771be403d8d1eab3911f2be73223ced169cb Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Feb 2014 19:45:50 -0400 Subject: [PATCH 34/56] Added love.math.gammaToLinear and love.math.linearToGamma for converting RGB color values from the sRGB color-space to linear and vice-versa. --- src/modules/math/MathModule.cpp | 30 +++++++++++++++ src/modules/math/MathModule.h | 10 +++++ src/modules/math/wrap_Math.cpp | 66 +++++++++++++++++++++++++++++++++ src/modules/math/wrap_Math.h | 2 + 4 files changed, 108 insertions(+) diff --git a/src/modules/math/MathModule.cpp b/src/modules/math/MathModule.cpp index 9ffefe839..ed096ebd7 100644 --- a/src/modules/math/MathModule.cpp +++ b/src/modules/math/MathModule.cpp @@ -193,5 +193,35 @@ bool Math::isConvex(const std::vector &polygon) return true; } +/** + * http://en.wikipedia.org/wiki/SRGB#The_reverse_transformation + **/ +float Math::gammaToLinear(float c) const +{ + if (c > 1.0) + return 1.0; + else if (c < 0.0) + return 0.0; + else if (c <= 0.04045) + return c / 12.92; + else + return powf((c + 0.055) / 1.055, 2.4); +} + +/** + * http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29 + **/ +float Math::linearToGamma(float c) const +{ + if (c > 1.0) + return 1.0; + else if (c < 0.0) + return 0.0; + else if (c < 0.0031308) + return c * 12.92; + else + return 1.055 * powf(c, 0.41666) - 0.055; +} + } // math } // love diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index 70f420515..0765a0e9c 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -136,6 +136,16 @@ public: **/ bool isConvex(const std::vector &polygon); + /** + * Converts a value from the sRGB (gamma) colorspace to linear RGB. + **/ + float gammaToLinear(float c) const; + + /** + * Converts a value from linear RGB to the sRGB (gamma) colorspace. + **/ + float linearToGamma(float c) const; + /** * Calculate Simplex noise for the specified coordinate(s). * diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index 95cf37940..773ecf040 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -238,6 +238,70 @@ int w_isConvex(lua_State *L) return 1; } +static int getGammaArgs(lua_State *L, float color[4]) +{ + int numcomponents = 0; + + if (lua_istable(L, 1)) + { + int n = lua_objlen(L, 1); + for (int i = 1; i <= n && i <= 4; i++) + { + lua_rawgeti(L, 1, i); + color[i - 1] = (float) luaL_checknumber(L, -1) / 255.0; + numcomponents++; + } + + lua_pop(L, numcomponents); + } + else + { + int n = lua_gettop(L); + for (int i = 1; i <= n && i <= 4; i++) + { + color[i - 1] = (float) luaL_checknumber(L, i) / 255.0; + numcomponents++; + } + } + + if (numcomponents == 0) + luaL_checknumber(L, 1); + + return numcomponents; +} + +int w_gammaToLinear(lua_State *L) +{ + float color[4]; + int numcomponents = getGammaArgs(L, color); + + for (int i = 0; i < numcomponents; i++) + { + // Alpha should always be linear. + if (i < 3) + color[i] = Math::instance.gammaToLinear(color[i]); + lua_pushnumber(L, color[i] * 255); + } + + return numcomponents; +} + +int w_linearToGamma(lua_State *L) +{ + float color[4]; + int numcomponents = getGammaArgs(L, color); + + for (int i = 0; i < numcomponents; i++) + { + // Alpha should always be linear. + if (i < 3) + color[i] = Math::instance.linearToGamma(color[i]); + lua_pushnumber(L, color[i] * 255); + } + + return numcomponents; +} + int w_noise(lua_State *L) { float w, x, y, z; @@ -285,6 +349,8 @@ static const luaL_Reg functions[] = { "newBezierCurve", w_newBezierCurve }, { "triangulate", w_triangulate }, { "isConvex", w_isConvex }, + { "gammaToLinear", w_gammaToLinear }, + { "linearToGamma", w_linearToGamma }, { "noise", w_noise }, { 0, 0 } }; diff --git a/src/modules/math/wrap_Math.h b/src/modules/math/wrap_Math.h index 8693535dc..f4c73fcbb 100644 --- a/src/modules/math/wrap_Math.h +++ b/src/modules/math/wrap_Math.h @@ -38,6 +38,8 @@ int w_newRandomGenerator(lua_State *L); int w_newBezierCurve(lua_State *L); int w_triangulate(lua_State *L); int w_isConvex(lua_State *L); +int w_gammaToLinear(lua_State *L); +int w_linearToGamma(lua_State *L); int w_noise(lua_State *L); extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L); From 4edebe1789a3e36df36fc3ee803f9cf078794e2c Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 5 Feb 2014 02:21:16 -0400 Subject: [PATCH 35/56] Updated changelog --- changes.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/changes.txt b/changes.txt index ee38d261e..003c6b347 100644 --- a/changes.txt +++ b/changes.txt @@ -5,7 +5,7 @@ LOVE 0.9.1 [Baby Inspector] * Added Source:clone. * Added ParticleSystem:clone. - * Added Mesh:setWireframe and Mesh:isWireframe for debugging. + * Added love.graphics.setWireframe for debugging. * Added Mesh:setDrawRange and Mesh:getDrawRange. * Added instancing support to Meshes with Mesh:setInstanceCount. * Added CircleShape:getPoint and CircleShape:setPoint. @@ -18,6 +18,9 @@ LOVE 0.9.1 [Baby Inspector] * Added Canvas:getFSAA. * Added 'love_ScreenSize' built-in variable in shaders. * Added love.getVersion. + * Added support for gamma-correct rendering. + * Added love.graphics.isSupported("srgb"). + * Added love.math.gammaToLinear and love.math.linearToGamma. * Deprecated Mesh/SpriteBatch/ParticleSystem:setImage. * Deprecated love.graphics.getMaxImageSize and love.graphics.getMaxPointSize. @@ -38,6 +41,8 @@ LOVE 0.9.1 [Baby Inspector] * Updated Canvas drawing code, texture coordinates are no longer flipped vertically. * Updated Canvas:renderTo to work properly if a Canvas is currently active. * Updated ParticleSystem:setEmissionRate to accept non-integer numbers. + * Updated Source:play to return a boolean indicating success. + * Updated t.console in conf.lua to create the console before modules are loaded in Windows. LOVE 0.9.0 [Baby Inspector] --------------------------- From 615492540debaae6b7e65307572d120902b5f751 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 6 Feb 2014 05:46:47 -0400 Subject: [PATCH 36/56] Added ParticleSystem:setRelativeRotation. If enabled, particle rotations and angles will be relative to their current velocities. --- .../graphics/opengl/ParticleSystem.cpp | 51 +++++++++++++------ src/modules/graphics/opengl/ParticleSystem.h | 36 ++++++++----- .../graphics/opengl/wrap_ParticleSystem.cpp | 16 ++++++ .../graphics/opengl/wrap_ParticleSystem.h | 2 + 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index d5d52da2b..e47525005 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -94,6 +94,7 @@ ParticleSystem::ParticleSystem(Texture *texture, uint32 size) , spinVariation(0) , offsetX(float(texture->getWidth())*0.5f) , offsetY(float(texture->getHeight())*0.5f) + , relativeRotation(false) { if (size == 0 || size > MAX_PARTICLES) throw love::Exception("Invalid ParticleSystem size."); @@ -145,6 +146,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p) , offsetX(p.offsetX) , offsetY(p.offsetY) , colors(p.colors) + , relativeRotation(p.relativeRotation) { setBufferSize(maxParticles); @@ -169,7 +171,7 @@ void ParticleSystem::createBuffers(size_t size) { try { - pFree = pMem = new particle[size]; + pFree = pMem = new Particle[size]; particleVerts = new love::Vertex[size * 4]; maxParticles = (uint32) size; } @@ -212,7 +214,7 @@ void ParticleSystem::addParticle(float t) return; // Gets a free particle and updates the allocation pointer. - particle *p = pFree++; + Particle *p = pFree++; initParticle(p, t); switch (insertMode) @@ -232,7 +234,7 @@ void ParticleSystem::addParticle(float t) activeParticles++; } -void ParticleSystem::initParticle(particle *p, float t) +void ParticleSystem::initParticle(Particle *p, float t) { float min,max; @@ -298,10 +300,14 @@ void ParticleSystem::initParticle(particle *p, float t) p->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation); p->rotation = (float) rng.random(min, max); + p->angle = p->rotation; + if (relativeRotation) + p->angle += atan2f(p->speed.y, p->speed.x); + p->color = colors[0]; } -void ParticleSystem::insertTop(particle *p) +void ParticleSystem::insertTop(Particle *p) { if (pHead == nullptr) { @@ -317,7 +323,7 @@ void ParticleSystem::insertTop(particle *p) pTail = p; } -void ParticleSystem::insertBottom(particle *p) +void ParticleSystem::insertBottom(Particle *p) { if (pTail == nullptr) { @@ -333,7 +339,7 @@ void ParticleSystem::insertBottom(particle *p) pHead = p; } -void ParticleSystem::insertRandom(particle *p) +void ParticleSystem::insertRandom(Particle *p) { // Nonuniform, but 64-bit is so large nobody will notice. Hopefully. uint64 pos = rng.rand() % ((int64) activeParticles + 1); @@ -341,7 +347,7 @@ void ParticleSystem::insertRandom(particle *p) // Special case where the particle gets inserted before the head. if (pos == activeParticles) { - particle *pA = pHead; + Particle *pA = pHead; if (pA) pA->prev = p; p->prev = nullptr; @@ -351,8 +357,8 @@ void ParticleSystem::insertRandom(particle *p) } // Inserts the particle after the randomly selected particle. - particle *pA = pMem + pos; - particle *pB = pA->next; + Particle *pA = pMem + pos; + Particle *pB = pA->next; pA->next = p; if (pB) pB->prev = p; @@ -362,12 +368,12 @@ void ParticleSystem::insertRandom(particle *p) p->next = pB; } -ParticleSystem::particle *ParticleSystem::removeParticle(particle *p) +ParticleSystem::Particle *ParticleSystem::removeParticle(Particle *p) { // The linked list is updated in this function and old pointers may be // invalidated. The returned pointer will inform the caller of the new // pointer to the next particle. - particle *pNext = nullptr; + Particle *pNext = nullptr; // Removes the particle from the linked list. if (p->prev) @@ -715,6 +721,16 @@ std::vector ParticleSystem::getColor() const return ncolors; } +void ParticleSystem::setRelativeRotation(bool enable) +{ + relativeRotation = enable; +} + +bool ParticleSystem::hasRelativeRotation() const +{ + return relativeRotation; +} + uint32 ParticleSystem::getCount() const { return activeParticles; @@ -802,13 +818,13 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo const Vertex *textureVerts = texture->getVertices(); Vertex *pVerts = particleVerts; - particle *p = pHead; + Particle *p = pHead; // set the vertex data for each particle (transformation, texcoords, color) while (p) { // 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.setTransformation(p->position[0], p->position[1], p->angle, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f); t.transform(pVerts, textureVerts, 4); // set the texture coordinate and color data for particle vertices @@ -858,7 +874,7 @@ void ParticleSystem::update(float dt) return; // Traverse all particles and update. - particle *p = pHead; + Particle *p = pHead; while (p) { @@ -903,7 +919,12 @@ void ParticleSystem::update(float dt) const float t = 1.0f - p->life / p->lifetime; // Rotate. - p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t)*dt; + p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t) * dt; + + p->angle = p->rotation; + + if (relativeRotation) + p->angle += atan2f(p->speed.y, p->speed.x); // Change size according to given intervals: // i = 0 1 2 3 n-1 diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 8ebdf1d8e..8b27192d6 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -421,6 +421,12 @@ public: **/ std::vector getColor() const; + /** + * sets whether particle angles & rotations are relative to their velocities. + **/ + void setRelativeRotation(bool enable); + bool hasRelativeRotation() const; + /** * Returns the amount of particles that are currently active in the system. **/ @@ -494,11 +500,12 @@ public: static bool getConstant(InsertMode in, const char *&out); protected: + // Represents a single particle. - struct particle + struct Particle { - particle *prev; - particle *next; + Particle *prev; + Particle *next; float lifetime; float life; @@ -518,7 +525,8 @@ protected: float sizeOffset; float sizeIntervalSize; - float rotation; + float rotation; // Amount of rotation applied to the final angle. + float angle; float spinStart; float spinEnd; @@ -526,16 +534,16 @@ protected: }; // Pointer to the beginning of the allocated memory. - particle *pMem; + Particle *pMem; // Pointer to a free particle. - particle *pFree; + Particle *pFree; // Pointer to the start of the linked list. - particle *pHead; + Particle *pHead; // Pointer to the end of the linked list. - particle *pTail; + Particle *pTail; // array of transformed vertex data for all particles, for drawing Vertex *particleVerts; @@ -617,17 +625,19 @@ protected: // Color. std::vector colors; + bool relativeRotation; + void createBuffers(size_t size); void deleteBuffers(); void addParticle(float t); - particle *removeParticle(particle *p); + Particle *removeParticle(Particle *p); // Called by addParticle. - void initParticle(particle *p, float t); - void insertTop(particle *p); - void insertBottom(particle *p); - void insertRandom(particle *p); + void initParticle(Particle *p, float t); + void insertTop(Particle *p); + void insertBottom(Particle *p); + void insertRandom(Particle *p); static StringMap::Entry distributionsEntries[]; static StringMap distributions; diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 6e875b645..6cb3c0416 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -569,6 +569,20 @@ int w_ParticleSystem_getColors(lua_State *L) return colors.size(); } +int w_ParticleSystem_setRelativeRotation(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + t->setRelativeRotation(luax_toboolean(L, 2)); + return 0; +} + +int w_ParticleSystem_hasRelativeRotation(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + luax_pushboolean(L, t->hasRelativeRotation()); + return 1; +} + int w_ParticleSystem_getCount(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); @@ -687,6 +701,8 @@ static const luaL_Reg functions[] = { "getColors", w_ParticleSystem_getColors }, { "setOffset", w_ParticleSystem_setOffset }, { "getOffset", w_ParticleSystem_getOffset }, + { "setRelativeRotation", w_ParticleSystem_setRelativeRotation }, + { "hasRelativeRotation", w_ParticleSystem_hasRelativeRotation }, { "getCount", w_ParticleSystem_getCount }, { "start", w_ParticleSystem_start }, { "stop", w_ParticleSystem_stop }, diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.h b/src/modules/graphics/opengl/wrap_ParticleSystem.h index 08948c386..b3c96a54f 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.h +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.h @@ -77,6 +77,8 @@ int w_ParticleSystem_setColors(lua_State *L); int w_ParticleSystem_getColors(lua_State *L); int w_ParticleSystem_setOffset(lua_State *L); int w_ParticleSystem_getOffset(lua_State *L); +int w_ParticleSystem_setRelativeRotation(lua_State *L); +int w_ParticleSystem_hasRelativeRotation(lua_State *L); int w_ParticleSystem_getCount(lua_State *L); int w_ParticleSystem_start(lua_State *L); int w_ParticleSystem_stop(lua_State *L); From de1f105e40cc2d1da67a5d6a054a1d41138e0ff5 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 8 Feb 2014 02:43:13 -0400 Subject: [PATCH 37/56] the AL_SOFT_direct_channels OpenAL extension shouldn't be required for compilation --- src/modules/audio/openal/Pool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/audio/openal/Pool.cpp b/src/modules/audio/openal/Pool.cpp index f8e613394..8d239f4d7 100644 --- a/src/modules/audio/openal/Pool.cpp +++ b/src/modules/audio/openal/Pool.cpp @@ -61,11 +61,13 @@ Pool::Pool() // Make all sources available initially. for (int i = 0; i < totalSources; i++) { +#ifdef AL_SOFT_direct_channels if (hasext) { // Bypass virtualization of speakers for multi-channel sources in OpenAL Soft. alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE); } +#endif available.push(sources[i]); } From d07e31370da173ab0e3920ac41d9142f6622dcac Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 8 Feb 2014 20:28:41 -0400 Subject: [PATCH 38/56] Added RandomGenerator:getState and RandomGenerator:setState (resolves issue #831.) getState returns an implementation-dependent string representing the current state of the RandomGenerator's PRNG. setState sets the PRNG's state to an implementation-dependent string. --- src/modules/math/MathModule.h | 40 +++++----- src/modules/math/RandomGenerator.cpp | 96 ++++++++++++++++++----- src/modules/math/RandomGenerator.h | 74 ++++++++--------- src/modules/math/wrap_Math.cpp | 47 +++++++---- src/modules/math/wrap_Math.h | 6 +- src/modules/math/wrap_RandomGenerator.cpp | 67 ++++++++-------- src/modules/math/wrap_RandomGenerator.h | 6 +- 7 files changed, 201 insertions(+), 135 deletions(-) diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index 0765a0e9c..e9df716ac 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -53,26 +53,6 @@ public: virtual ~Math() {} - inline void setRandomSeed(RandomGenerator::Seed seed) - { - rng.setSeed(seed); - } - - inline void setRandomSeed(uint32 low, uint32 high) - { - rng.setSeed(low, high); - } - - inline RandomGenerator::Seed getRandomSeed() const - { - return rng.getSeed(); - } - - inline void getRandomSeed(uint32 &low, uint32 &high) const - { - rng.getSeed(low, high); - } - /** * @copydoc RandomGenerator::random() **/ @@ -105,6 +85,26 @@ public: return rng.randomNormal(stddev); } + inline void setRandomSeed(RandomGenerator::Seed seed) + { + rng.setSeed(seed); + } + + inline RandomGenerator::Seed getRandomSeed() const + { + return rng.getSeed(); + } + + inline void setRandomState(const std::string &statestr) + { + rng.setState(statestr); + } + + inline std::string getRandomState() const + { + return rng.getState(); + } + /** * Create a new random number generator. **/ diff --git a/src/modules/math/RandomGenerator.cpp b/src/modules/math/RandomGenerator.cpp index 1f7b58a47..0e26d3e8d 100644 --- a/src/modules/math/RandomGenerator.cpp +++ b/src/modules/math/RandomGenerator.cpp @@ -20,8 +20,13 @@ #include "RandomGenerator.h" -// STL +// C++ #include +#include +#include + +// C +#include namespace love { @@ -36,25 +41,10 @@ RandomGenerator::RandomGenerator() { // because it is too big for some compilers to handle ... if you know what // i mean -#ifdef LOVE_BIG_ENDIAN - seed.b32.a = 0x0139408D; - seed.b32.b = 0xCBBF7A44; -#else - seed.b32.b = 0x0139408D; - seed.b32.a = 0xCBBF7A44; -#endif - - rng_state = seed; -} - -void RandomGenerator::setSeed(RandomGenerator::Seed newseed) -{ - // 0 xor 0 is still 0, so Xorshift can't generate new numbers. - if (newseed.b64 == 0) - throw love::Exception("Invalid random seed."); - - seed = newseed; - rng_state = seed; + Seed newseed; + newseed.b32.low = 0xCBBF7A44; + newseed.b32.high = 0x0139408D; + setSeed(newseed); } uint64 RandomGenerator::rand() @@ -83,5 +73,71 @@ double RandomGenerator::randomNormal(double stddev) return r * sin(phi) * stddev; } +void RandomGenerator::setSeed(RandomGenerator::Seed newseed) +{ + // 0 xor 0 is still 0, so Xorshift can't generate new numbers. + if (newseed.b64 == 0) + throw love::Exception("Invalid random seed."); + + seed = newseed; + rng_state = seed; +} + +RandomGenerator::Seed RandomGenerator::getSeed() const +{ + return seed; +} + +void RandomGenerator::setState(const std::string &statestr) +{ + // For this implementation we'll accept a hex string representing the + // 64-bit state integer xorshift uses. + + Seed state = {}; + + // Hex string must start with 0x. + if (statestr.find("0x") != 0 || statestr.size() < 3) + throw love::Exception("Invalid random state."); + + // standardized strtoull (or 64 bit integer support for stringstream) + // requires C++11's standard library, which we can't use yet. + // I use strtol like this not because it's the best solution, but because + // it's "good enough". + + // Convert the hex string to the state integer character-by-character. + for (size_t i = 2; i < statestr.size(); i++) + { + char hex[2] = {statestr[i], 0}; + char *end = nullptr; + + // Convert the current hex character to a number. + int nibble = strtol(hex, &end, 16); + + // Check if strtol failed to convert it. + if (end != nullptr && *end != 0) + throw love::Exception("Invalid random state."); + + state.b64 = (state.b64 << 4) + nibble; + } + + rng_state = state; +} + +std::string RandomGenerator::getState() const +{ + // For this implementation we'll return a hex string representing the 64-bit + // state integer xorshift uses. + + std::stringstream ss; + + ss << "0x"; + + // Again with the stringstream not dealing with 64 bit integers... + ss << std::setfill('0') << std::setw(8) << std::hex << rng_state.b32.high; + ss << std::setfill('0') << std::setw(8) << std::hex << rng_state.b32.low; + + return ss.str(); +} + } // math } // love diff --git a/src/modules/math/RandomGenerator.h b/src/modules/math/RandomGenerator.h index 830a9506c..aab0f9277 100644 --- a/src/modules/math/RandomGenerator.h +++ b/src/modules/math/RandomGenerator.h @@ -28,8 +28,9 @@ #include "common/int.h" #include "common/Object.h" -// STL +// C++ #include +#include namespace love { @@ -45,54 +46,19 @@ public: uint64 b64; struct { - uint32 a; - uint32 b; +#ifdef LOVE_BIG_ENDIAN + uint32 high; + uint32 low; +#else + uint32 low; + uint32 high; +#endif } b32; }; RandomGenerator(); virtual ~RandomGenerator() {} - /** - * Set pseudo-random seed. - * It's up to the implementation how to use this. - **/ - void setSeed(Seed seed); - - /** - * Separately set the low and high bits of the pseudo-random seed. - **/ - inline void setSeed(uint32 low, uint32 high) - { - Seed newseed; - -#ifdef LOVE_BIG_ENDIAN - newseed.b32.a = high; - newseed.b32.b = low; -#else - newseed.b32.b = high; - newseed.b32.a = low; -#endif - - setSeed(newseed); - } - - inline Seed getSeed() const - { - return seed; - } - - inline void getSeed(uint32 &low, uint32 &high) const - { -#ifdef LOVE_BIG_ENDIAN - high = seed.b32.a; - low = seed.b32.b; -#else - high = seed.b32.b; - low = seed.b32.a; -#endif - } - /** * Return uniformly distributed pseudo random integer. * @@ -138,6 +104,28 @@ public: **/ double randomNormal(double stddev); + /** + * Set pseudo-random seed. + * It's up to the implementation how to use this. + **/ + void setSeed(Seed seed); + + /** + * Get the previously set pseudo-random seed. + **/ + Seed getSeed() const; + + /** + * Set the internal implementation-dependent state value based on a string. + **/ + void setState(const std::string &statestr); + + /** + * Get a string representation of the implementation-dependent internal + * state value. + **/ + std::string getState() const; + private: Seed seed; diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index 773ecf040..50b78f956 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -32,21 +32,6 @@ namespace love namespace math { -int w_setRandomSeed(lua_State *L) -{ - EXCEPT_GUARD(Math::instance.setRandomSeed(luax_checkrandomseed(L, 1));) - return 0; -} - -int w_getRandomSeed(lua_State *L) -{ - uint32 low = 0, high = 0; - Math::instance.getRandomSeed(low, high); - lua_pushnumber(L, (lua_Number) low); - lua_pushnumber(L, (lua_Number) high); - return 2; -} - int w_random(lua_State *L) { return luax_getrandom(L, 1, Math::instance.random()); @@ -62,6 +47,32 @@ int w_randomNormal(lua_State *L) return 1; } +int w_setRandomSeed(lua_State *L) +{ + EXCEPT_GUARD(Math::instance.setRandomSeed(luax_checkrandomseed(L, 1));) + return 0; +} + +int w_getRandomSeed(lua_State *L) +{ + RandomGenerator::Seed s = Math::instance.getRandomSeed(); + lua_pushnumber(L, (lua_Number) s.b32.low); + lua_pushnumber(L, (lua_Number) s.b32.high); + return 2; +} + +int w_setRandomState(lua_State *L) +{ + EXCEPT_GUARD(Math::instance.setRandomState(luax_checkstring(L, 1));) + return 0; +} + +int w_getRandomState(lua_State *L) +{ + luax_pushstring(L, Math::instance.getRandomState()); + return 1; +} + int w_newRandomGenerator(lua_State *L) { RandomGenerator::Seed s; @@ -341,10 +352,12 @@ int w_noise(lua_State *L) // List of functions to wrap. static const luaL_Reg functions[] = { - { "setRandomSeed", w_setRandomSeed }, - { "getRandomSeed", w_getRandomSeed }, { "random", w_random }, { "randomNormal", w_randomNormal }, + { "setRandomSeed", w_setRandomSeed }, + { "getRandomSeed", w_getRandomSeed }, + { "setRandomState", w_setRandomState }, + { "getRandomState", w_getRandomState }, { "newRandomGenerator", w_newRandomGenerator }, { "newBezierCurve", w_newBezierCurve }, { "triangulate", w_triangulate }, diff --git a/src/modules/math/wrap_Math.h b/src/modules/math/wrap_Math.h index f4c73fcbb..d75afe4ae 100644 --- a/src/modules/math/wrap_Math.h +++ b/src/modules/math/wrap_Math.h @@ -30,10 +30,12 @@ namespace love namespace math { -int w_setRandomSeed(lua_State *L); -int w_getRandomSeed(lua_State *L); int w_random(lua_State *L); int w_randomNormal(lua_State *L); +int w_setRandomSeed(lua_State *L); +int w_getRandomSeed(lua_State *L); +int w_setRandomState(lua_State *L); +int w_getRandomState(lua_State *L); int w_newRandomGenerator(lua_State *L); int w_newBezierCurve(lua_State *L); int w_triangulate(lua_State *L); diff --git a/src/modules/math/wrap_RandomGenerator.cpp b/src/modules/math/wrap_RandomGenerator.cpp index 78cf53a04..ea029df2a 100644 --- a/src/modules/math/wrap_RandomGenerator.cpp +++ b/src/modules/math/wrap_RandomGenerator.cpp @@ -47,16 +47,8 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx) if (!lua_isnoneornil(L, idx + 1)) { - uint32 low = checkrandomseed_part(L, idx); - uint32 high = checkrandomseed_part(L, idx + 1); - -#ifdef LOVE_BIG_ENDIAN - s.b32.a = high; - s.b32.b = low; -#else - s.b32.b = high; - s.b32.a = low; -#endif + s.b32.low = checkrandomseed_part(L, idx); + s.b32.high = checkrandomseed_part(L, idx + 1); } else s.b64 = checkrandomseed_part(L, idx); @@ -95,25 +87,6 @@ RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx) return luax_checktype(L, idx, "RandomGenerator", MATH_RANDOM_GENERATOR_T); } -int w_RandomGenerator_setSeed(lua_State *L) -{ - RandomGenerator *rng = luax_checkrandomgenerator(L, 1); - EXCEPT_GUARD(rng->setSeed(luax_checkrandomseed(L, 2));) - return 0; -} - -int w_RandomGenerator_getSeed(lua_State *L) -{ - RandomGenerator *rng = luax_checkrandomgenerator(L, 1); - - uint32 low = 0, high = 0; - rng->getSeed(low, high); - - lua_pushnumber(L, (lua_Number) low); - lua_pushnumber(L, (lua_Number) high); - return 2; -} - int w_RandomGenerator_random(lua_State *L) { RandomGenerator *rng = luax_checkrandomgenerator(L, 1); @@ -132,12 +105,44 @@ int w_RandomGenerator_randomNormal(lua_State *L) return 1; } +int w_RandomGenerator_setSeed(lua_State *L) +{ + RandomGenerator *rng = luax_checkrandomgenerator(L, 1); + EXCEPT_GUARD(rng->setSeed(luax_checkrandomseed(L, 2));) + return 0; +} + +int w_RandomGenerator_getSeed(lua_State *L) +{ + RandomGenerator *rng = luax_checkrandomgenerator(L, 1); + RandomGenerator::Seed s = rng->getSeed(); + lua_pushnumber(L, (lua_Number) s.b32.low); + lua_pushnumber(L, (lua_Number) s.b32.high); + return 2; +} + +int w_RandomGenerator_setState(lua_State *L) +{ + RandomGenerator *rng = luax_checkrandomgenerator(L, 1); + EXCEPT_GUARD(rng->setState(luax_checkstring(L, 2));) + return 0; +} + +int w_RandomGenerator_getState(lua_State *L) +{ + RandomGenerator *rng = luax_checkrandomgenerator(L, 1); + luax_pushstring(L, rng->getState()); + return 1; +} + static const luaL_Reg functions[] = { - { "setSeed", w_RandomGenerator_setSeed }, - { "getSeed", w_RandomGenerator_getSeed }, { "random", w_RandomGenerator_random }, { "randomNormal", w_RandomGenerator_randomNormal }, + { "setSeed", w_RandomGenerator_setSeed }, + { "getSeed", w_RandomGenerator_getSeed }, + { "setState", w_RandomGenerator_setState }, + { "getState", w_RandomGenerator_getState }, { 0, 0 } }; diff --git a/src/modules/math/wrap_RandomGenerator.h b/src/modules/math/wrap_RandomGenerator.h index 07e82894e..ad5201d17 100644 --- a/src/modules/math/wrap_RandomGenerator.h +++ b/src/modules/math/wrap_RandomGenerator.h @@ -36,10 +36,12 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx); int luax_getrandom(lua_State *L, int startidx, double r); RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx); -int w_RandomGenerator_setSeed(lua_State *L); -int w_RandomGenerator_getSeed(lua_State *L); int w_RandomGenerator_random(lua_State *L); int w_RandomGenerator_randomNormal(lua_State *L); +int w_RandomGenerator_setSeed(lua_State *L); +int w_RandomGenerator_getSeed(lua_State *L); +int w_RandomGenerator_setState(lua_State *L); +int w_RandomGenerator_getState(lua_State *L); extern "C" int luaopen_randomgenerator(lua_State *L); } // math From 0e28a9d01b5ec2cba93aad782ee4d22c541194be Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 10 Feb 2014 02:32:24 -0400 Subject: [PATCH 39/56] Added a header guard for luasocket's lua.h wrapper --- src/libraries/luasocket/libluasocket/lua.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libraries/luasocket/libluasocket/lua.h b/src/libraries/luasocket/libluasocket/lua.h index e97bc2ac2..a280df842 100644 --- a/src/libraries/luasocket/libluasocket/lua.h +++ b/src/libraries/luasocket/libluasocket/lua.h @@ -1,3 +1,6 @@ +#ifndef LUA_WRAP_H +#define LUA_WRAP_H + #define LUA_COMPAT_ALL #include #include @@ -10,3 +13,5 @@ extern int luax_typerror(lua_State *L, int narg, const char *type); #endif + +#endif // LUA_WRAP_H From c17cada9e071144e21a081827735ddefec053534 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 10 Feb 2014 14:01:59 -0400 Subject: [PATCH 40/56] Fixed World:getBodyList, World:getJointList, and World:getContactList causing hard crashes instead of Lua errors --- src/modules/physics/box2d/wrap_World.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index b4739f24c..fb45ead88 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -143,21 +143,27 @@ int w_World_getBodyList(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); - return t->getBodyList(L); + int ret = 0; + EXCEPT_GUARD(ret = t->getBodyList(L);) + return ret; } int w_World_getJointList(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); - return t->getJointList(L); + int ret = 0; + EXCEPT_GUARD(ret = t->getJointList(L);) + return ret; } int w_World_getContactList(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); - return t->getContactList(L); + int ret = 0; + EXCEPT_GUARD(ret = t->getContactList(L);) + return ret; } int w_World_queryBoundingBox(lua_State *L) From 6259e38d846f53380ae4f38900fe10665f9fcbec Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 12 Feb 2014 02:22:57 -0400 Subject: [PATCH 41/56] Meshes will now use the smallest integer data type possible for index buffer (vertex map) values, instead of always using 32-bit integer numbers. --- src/modules/graphics/opengl/Graphics.cpp | 7 ++ src/modules/graphics/opengl/Graphics.h | 2 + src/modules/graphics/opengl/Mesh.cpp | 124 ++++++++++++++++++---- src/modules/graphics/opengl/Mesh.h | 9 +- src/modules/graphics/opengl/wrap_Mesh.cpp | 11 +- 5 files changed, 122 insertions(+), 31 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 5df3d4d0a..3630e3216 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -53,6 +53,7 @@ Graphics::Graphics() , width(0) , height(0) , created(false) + , activeStencil(false) , savedState() { currentWindow = love::window::sdl::Window::createSingleton(); @@ -383,6 +384,8 @@ void Graphics::defineStencil() glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + activeStencil = true; } void Graphics::useStencil(bool invert) @@ -394,8 +397,12 @@ void Graphics::useStencil(bool invert) void Graphics::discardStencil() { + if (!activeStencil) + return; + setColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); glDisable(GL_STENCIL_TEST); + activeStencil = false; } Image *Graphics::newImage(love::image::ImageData *data, Texture::Format format) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index b68755d08..7ab7560cd 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -482,6 +482,8 @@ private: int height; bool created; + bool activeStencil; + DisplayState savedState; }; // Graphics diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 62b8275c3..10597568f 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -38,6 +38,7 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) , vertex_count(0) , ibo(nullptr) , element_count(0) + , element_data_type(getGLDataTypeFromMax(verts.size())) , instance_count(1) , draw_mode(mode) , range_min(-1) @@ -53,6 +54,7 @@ Mesh::Mesh(int vertexcount, Mesh::DrawMode mode) , vertex_count(0) , ibo(nullptr) , element_count(0) + , element_data_type(getGLDataTypeFromMax(vertexcount)) , draw_mode(mode) , range_min(-1) , range_max(-1) @@ -151,15 +153,42 @@ size_t Mesh::getVertexCount() const return vertex_count; } +/** + * Copies index data from a vector to a mapped index buffer. + **/ +template +static void copyToIndexBuffer(const std::vector &indices, VertexBuffer::Mapper &buffermap, size_t maxval) +{ + T *elems = (T *) buffermap.get(); + + for (size_t i = 0; i < indices.size(); i++) + { + if (indices[i] >= maxval) + throw love::Exception("Invalid vertex map value: %d", indices[i] + 1); + + elems[i] = (T) indices[i]; + } +} + void Mesh::setVertexMap(const std::vector &map) { - for (size_t i = 0; i < map.size(); i++) - { - if (map[i] >= vertex_count) - throw love::Exception("Invalid vertex map value: %d", map[i] + 1); - } + GLenum datatype = getGLDataTypeFromMax(vertex_count); - size_t size = sizeof(uint32) * map.size(); + // Calculate the size in bytes of the index buffer data. + size_t size = map.size(); + switch (datatype) + { + case GL_UNSIGNED_BYTE: + size *= sizeof(uint8); + break; + case GL_UNSIGNED_SHORT: + size *= sizeof(uint16); + break; + case GL_UNSIGNED_INT: + default: + size *= sizeof(uint32); + break; + } if (ibo && size > ibo->getSize()) { @@ -175,27 +204,68 @@ void Mesh::setVertexMap(const std::vector &map) element_count = map.size(); - if (ibo && element_count > 0) - { - VertexBuffer::Bind ibo_bind(*ibo); - VertexBuffer::Mapper ibo_map(*ibo); + if (!ibo || element_count == 0) + return; - // Fill the buffer. - memcpy(ibo_map.get(), &map[0], size); + VertexBuffer::Bind ibo_bind(*ibo); + VertexBuffer::Mapper ibo_map(*ibo); + + // Fill the buffer with the index values from the vector. + switch (datatype) + { + case GL_UNSIGNED_BYTE: + copyToIndexBuffer(map, ibo_map, vertex_count); + break; + case GL_UNSIGNED_SHORT: + copyToIndexBuffer(map, ibo_map, vertex_count); + break; + case GL_UNSIGNED_INT: + default: + copyToIndexBuffer(map, ibo_map, vertex_count); + break; } + + element_data_type = datatype; } -const uint32 *Mesh::getVertexMap() const +/** + * Copies index data from a mapped buffer to a vector. + **/ +template +static void copyFromIndexBuffer(void *buffer, std::vector &indices, size_t maxval) { - if (ibo && element_count > 0) + T *elems = (T *) buffer; + for (size_t i = 0; i < maxval; i++) + indices.push_back((uint32) elems[i]); +} + +void Mesh::getVertexMap(std::vector &map) const +{ + if (!ibo || element_count == 0) + return; + + map.clear(); + map.reserve(element_count); + + VertexBuffer::Bind ibo_bind(*ibo); + + // We unmap the buffer in Mesh::draw and Mesh::setVertexMap. + void *buffer = ibo->map(); + + // Fill the vector from the buffer. + switch (element_data_type) { - VertexBuffer::Bind ibo_bind(*ibo); - - // We unmap the buffer in Mesh::draw and Mesh::setVertexMap. - return (uint32 *) ibo->map(); + case GL_UNSIGNED_BYTE: + copyFromIndexBuffer(buffer, map, vertex_count); + break; + case GL_UNSIGNED_SHORT: + copyFromIndexBuffer(buffer, map, vertex_count); + break; + case GL_UNSIGNED_INT: + default: + copyFromIndexBuffer(buffer, map, vertex_count); + break; } - - return nullptr; } size_t Mesh::getVertexMapCount() const @@ -335,7 +405,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo min = std::min(std::max(range_min, 0), max); const void *indices = ibo->getPointer(min * sizeof(uint32)); - GLenum type = GL_UNSIGNED_INT; + GLenum type = element_data_type; if (instance_count > 1) gl.drawElementsInstanced(mode, max - min + 1, type, indices, instance_count); @@ -375,7 +445,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo texture->postdraw(); } -GLenum Mesh::getGLDrawMode(Mesh::DrawMode mode) const +GLenum Mesh::getGLDrawMode(DrawMode mode) const { switch (mode) { @@ -394,6 +464,16 @@ GLenum Mesh::getGLDrawMode(Mesh::DrawMode mode) const return GL_TRIANGLES; } +GLenum Mesh::getGLDataTypeFromMax(size_t maxvalue) const +{ + if (maxvalue > LOVE_UINT16_MAX) + return GL_UNSIGNED_INT; + else if (maxvalue > LOVE_UINT8_MAX) + return GL_UNSIGNED_SHORT; + else + return GL_UNSIGNED_BYTE; +} + bool Mesh::getConstant(const char *in, Mesh::DrawMode &out) { return drawModes.find(in, out); diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 5e6e974fe..da73af438 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -109,11 +109,10 @@ public: void setVertexMap(const std::vector &map); /** - * Gets a pointer to the vertex map array. The pointer is only valid until - * the next function call in the graphics module. - * May return null if the vertex map is empty. + * Fills the uint32 vector passed into the method with the previously set + * vertex map (index buffer) values. **/ - const uint32 *getVertexMap() const; + void getVertexMap(std::vector &map) const; /** * Gets the total number of elements in the vertex map array. @@ -171,6 +170,7 @@ public: private: GLenum getGLDrawMode(DrawMode mode) const; + GLenum getGLDataTypeFromMax(size_t maxvalue) const; // Vertex buffer. VertexBuffer *vbo; @@ -179,6 +179,7 @@ private: // Element (vertex index) buffer, for the vertex map. VertexBuffer *ibo; size_t element_count; + GLenum element_data_type; int instance_count; diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index e3e8800b9..92a0371cf 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -220,14 +220,15 @@ int w_Mesh_setVertexMap(lua_State *L) int w_Mesh_getVertexMap(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); - const uint32 *vertex_map = 0; - EXCEPT_GUARD(vertex_map = t->getVertexMap();) - size_t elements = t->getVertexMapCount(); + std::vector vertex_map; + EXCEPT_GUARD(t->getVertexMap(vertex_map);) - lua_createtable(L, elements, 0); + size_t element_count = vertex_map.size(); - for (size_t i = 0; i < elements; i++) + lua_createtable(L, element_count, 0); + + for (size_t i = 0; i < element_count; i++) { lua_pushinteger(L, lua_Integer(vertex_map[i]) + 1); lua_rawseti(L, -2, i + 1); From 31134ada131aedc0a904114b431446855bbca163 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 13 Feb 2014 19:59:35 -0400 Subject: [PATCH 42/56] Updated changelog --- changes.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/changes.txt b/changes.txt index 003c6b347..1401af364 100644 --- a/changes.txt +++ b/changes.txt @@ -5,6 +5,8 @@ LOVE 0.9.1 [Baby Inspector] * Added Source:clone. * Added ParticleSystem:clone. + * Added ParticleSystem:moveTo, has smoother emitter movement compared to setPosition. + * Added ParticleSystem:setRelativeRotation. * Added love.graphics.setWireframe for debugging. * Added Mesh:setDrawRange and Mesh:getDrawRange. * Added instancing support to Meshes with Mesh:setInstanceCount. @@ -13,7 +15,6 @@ LOVE 0.9.1 [Baby Inspector] * Added high-dpi window support for Retina displays in OS X, via the 'highdpi' window flag. * Added love.window.getPixelScale. * Added love.graphics.getSystemLimit. - * Added ParticleSystem:moveTo, has smoother emitter movement compared to setPosition. * Added antialiasing support to Canvases. * Added Canvas:getFSAA. * Added 'love_ScreenSize' built-in variable in shaders. @@ -21,6 +22,7 @@ LOVE 0.9.1 [Baby Inspector] * Added support for gamma-correct rendering. * Added love.graphics.isSupported("srgb"). * Added love.math.gammaToLinear and love.math.linearToGamma. + * Added RandomGenerator:getState and RandomGenerator:setState. * Deprecated Mesh/SpriteBatch/ParticleSystem:setImage. * Deprecated love.graphics.getMaxImageSize and love.graphics.getMaxPointSize. @@ -32,6 +34,7 @@ LOVE 0.9.1 [Baby Inspector] * Fixed TrueType font glyphs which request a monochrome bitmap pixel mode. * Fixed love.graphics.reset causing crashes when called in between love.graphics.push/pop. * Fixed tab characters ("\t") to display properly with love.graphics.print. + * Fixed World:getBodyList and World:getJointList causing hard crashes. * Renamed love.graphics.getMaxImageSize to love.graphics.getMaxTextureSize (old function still exists.) @@ -43,6 +46,7 @@ LOVE 0.9.1 [Baby Inspector] * Updated ParticleSystem:setEmissionRate to accept non-integer numbers. * Updated Source:play to return a boolean indicating success. * Updated t.console in conf.lua to create the console before modules are loaded in Windows. + * Updated Mesh vertex maps (index buffers) to use less space in VRAM. LOVE 0.9.0 [Baby Inspector] --------------------------- From 2a19a4444ef505a4cb725c9a18902ecc55555ebe Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 15 Feb 2014 20:59:57 -0400 Subject: [PATCH 43/56] Allow Fixture:setUserData and Fixture:getUserData to be called in coroutines (resolves issue #850.) Bad things will still happen if you call them from a love Thread which didn't create the World and the Fixture object. Don't do it! --- src/common/Reference.cpp | 22 ++++++++++++++------ src/common/Reference.h | 18 +++++++++++++++- src/modules/physics/box2d/Fixture.cpp | 30 +++++++++++++-------------- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/common/Reference.cpp b/src/common/Reference.cpp index 38e28e099..127023974 100644 --- a/src/common/Reference.cpp +++ b/src/common/Reference.cpp @@ -64,21 +64,31 @@ void Reference::unref() } } -void Reference::push() +void Reference::push(lua_State *newL) { if (idx != LUA_REFNIL) { - luax_insist(L, LUA_REGISTRYINDEX, REFERENCE_TABLE_NAME); - lua_rawgeti(L, -1, idx); - lua_remove(L, -2); + luax_insist(newL, LUA_REGISTRYINDEX, REFERENCE_TABLE_NAME); + lua_rawgeti(newL, -1, idx); + lua_remove(newL, -2); } else - lua_pushnil(L); + lua_pushnil(newL); } -lua_State *Reference::getL() +void Reference::push() +{ + push(L); +} + +lua_State *Reference::getL() const { return L; } +void Reference::setL(lua_State *newL) +{ + L = newL; +} + } // love diff --git a/src/common/Reference.h b/src/common/Reference.h index 5d7341b20..eb8e8b288 100644 --- a/src/common/Reference.h +++ b/src/common/Reference.h @@ -63,6 +63,14 @@ public: **/ void unref(); + /** + * Pushes the referred value onto the stack of a different coroutine + * in the same main Lua state. + * THIS SHOULD NOT BE USED FOR DIFFERENT LUA STATES (created with + * luaL_newstate)! Only with different coroutines! + **/ + void push(lua_State *newL); + /** * Pushes the referred value onto the stack. **/ @@ -72,7 +80,15 @@ public: * Gets the Lua state associated with this * reference. **/ - lua_State *getL(); + lua_State *getL() const; + + /** + * Associates a new Lua state with this reference. + * THIS IS DANGEROUS! It is only designed to be + * used with different coroutines from the same + * main Lua state! + **/ + void setL(lua_State *newL); private: diff --git a/src/modules/physics/box2d/Fixture.cpp b/src/modules/physics/box2d/Fixture.cpp index f133bac62..9b80ef222 100644 --- a/src/modules/physics/box2d/Fixture.cpp +++ b/src/modules/physics/box2d/Fixture.cpp @@ -39,10 +39,10 @@ namespace box2d Fixture::Fixture(Body *body, Shape *shape, float density) : body(body) - , fixture(NULL) + , fixture(nullptr) { data = new fixtureudata(); - data->ref = 0; + data->ref = nullptr; b2FixtureDef def; def.shape = shape->shape; def.userData = (void *)data; @@ -65,13 +65,10 @@ Fixture::Fixture(b2Fixture *f) Fixture::~Fixture() { - if (data->ref != 0) + if (data != nullptr) delete data->ref; delete data; - data = NULL; - - fixture = NULL; } Shape::Type Fixture::getType() const @@ -127,14 +124,14 @@ Body *Fixture::getBody() const Shape *Fixture::getShape() const { if (!fixture->GetShape()) - return NULL; + return nullptr; return new Shape(fixture->GetShape(), false); } bool Fixture::isValid() const { - return fixture != 0; + return fixture != nullptr; } void Fixture::setFilterData(int *v) @@ -230,21 +227,24 @@ int Fixture::setUserData(lua_State *L) { love::luax_assert_argc(L, 1, 1); - if (data->ref != 0) + if (data->ref != nullptr) { + // We set the Reference's lua_State to this one before deleting it, so + // it unrefs using the current lua_State's stack. This is necessary + // if setUserData is called in a coroutine. + data->ref->setL(L); delete data->ref; - data->ref = 0; } data->ref = new Reference(L); + return 0; } int Fixture::getUserData(lua_State *L) { - love::luax_assert_argc(L, 0, 0); - if (data->ref != 0) - data->ref->push(); + if (data->ref != nullptr) + data->ref->push(L); else lua_pushnil(L); @@ -311,10 +311,10 @@ void Fixture::destroy(bool implicit) return; } - if (!implicit && fixture != 0) + if (!implicit && fixture != nullptr) body->body->DestroyFixture(fixture); Memoizer::remove(fixture); - fixture = NULL; + fixture = nullptr; // Box2D fixture destroyed. Release its reference to the love Fixture. this->release(); From c2971f9568f01fc89e7f8f9cebd3f0ce81f2e2dd Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Sun, 16 Feb 2014 09:59:27 +0100 Subject: [PATCH 44/56] Distribute associations, icons and manpages in the deb package --- platform/unix/debian/love.install | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/platform/unix/debian/love.install b/platform/unix/debian/love.install index 487155e20..ac4c7a440 100644 --- a/platform/unix/debian/love.install +++ b/platform/unix/debian/love.install @@ -1 +1,6 @@ usr/bin/love +usr/share/man/man1/love.1 +usr/share/pixmaps/love.svg +usr/share/mime/packages/love.xml +usr/share/icons/hicolor/scalable/mimetypes/application-x-love-game.svg +usr/share/applications/love.desktop From e92be92900de081f3aae3d9822396ee907b46601 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Sun, 16 Feb 2014 13:19:59 +0100 Subject: [PATCH 45/56] Add fused and version flags to love manpage --- platform/unix/love.1 | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/platform/unix/love.1 b/platform/unix/love.1 index 0abaa5577..539cf9a9c 100644 --- a/platform/unix/love.1 +++ b/platform/unix/love.1 @@ -1,4 +1,5 @@ .\" (c) 2008-2011 Miriam Ruiz +.\" (c) 2013 Bart van Strien .\" .\" This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damagesarising from the use of this software. .\" @@ -11,16 +12,25 @@ .\" 3. This notice may not be removed or altered from any source distribution. .\" .\" Modifications: -.\" - Update version to 0.9 and remove reference to doc dir - Bart van Strien, 2013 +.\" - Update version to 0.9 and remove reference to doc dir +.\" - Add fused and version flags + .TH "LÖVE" "1" "0.9" "" "" .SH "NAME" love \- 2D game development framework + .SH "SYNOPSIS" .B love -<\fIgame.love\fR> +[--fused] <\fIgame.love\fR> +.PP +.B love +--version +.PP + .SH "DESCRIPTION" LÖVE was created to be a user\-friendly engine in which simple (or complicated) games could be made without having extensive knowledge of system or graphics functions and without having to dedicate time towards developing the same engine features time and time again. .P Developed with cross\-platform implementation in mind, it utilizes the latest open source libraries to deliver a similar game experience, independent of operating system. By relying on the Lua scripting language for game\-specific programming, it allows even the novice game creator to quickly and efficiently develop an idea into a fully working game. + .SH "SEE ALSO" You can find more information at \fIhttp://love2d.org/\fR From 94aa39116e851cb98feefe9d840526fc8db42d37 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 16 Feb 2014 14:54:33 -0400 Subject: [PATCH 46/56] Fixed stencils used when an antialiased Canvas is active --- src/modules/graphics/opengl/Canvas.cpp | 47 ++++++++++++++++++++------ 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index ed9ff6113..daf32429c 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -55,10 +55,11 @@ struct FramebufferStrategy /** * @param[in] width Width of the stencil buffer * @param[in] height Height of the stencil buffer + * @param[in] samples Number of samples to use * @param[out] stencil Name for stencil buffer * @return Whether the stencil buffer was successfully created **/ - virtual bool createStencil(int, int, GLuint &) + virtual bool createStencil(int, int, int, GLuint &) { return false; } @@ -121,16 +122,20 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy return status; } - virtual bool createStencil(int width, int height, GLuint &stencil) + virtual bool createStencil(int width, int height, int samples, GLuint &stencil) { // create combined depth/stencil buffer glDeleteRenderbuffers(1, &stencil); glGenRenderbuffers(1, &stencil); glBindRenderbuffer(GL_RENDERBUFFER, stencil); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height); + + if (samples > 0) + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH_STENCIL, width, height); + else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, stencil); + GL_RENDERBUFFER, stencil); glBindRenderbuffer(GL_RENDERBUFFER, 0); @@ -237,14 +242,24 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy return status; } - virtual bool createStencil(int width, int height, GLuint &stencil) + virtual bool createStencil(int width, int height, int samples, GLuint &stencil) { // create combined depth/stencil buffer glDeleteRenderbuffersEXT(1, &stencil); glGenRenderbuffersEXT(1, &stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, - width, height); + + if (samples > 0) + { + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, + GL_DEPTH_STENCIL, width, height); + } + else + { + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, + width, height); + } + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, stencil); @@ -336,14 +351,24 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT { - virtual bool createStencil(int width, int height, GLuint &stencil) + virtual bool createStencil(int width, int height, int samples, GLuint &stencil) { // create stencil buffer glDeleteRenderbuffersEXT(1, &stencil); glGenRenderbuffersEXT(1, &stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, - width, height); + + if (samples > 0) + { + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, + GL_STENCIL_INDEX, width, height); + } + else + { + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, + width, height); + } + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, stencil); @@ -854,7 +879,7 @@ bool Canvas::checkCreateStencil() if (current != this) strategy->bindFBO(fbo); - bool success = strategy->createStencil(width, height, depth_stencil); + bool success = strategy->createStencil(width, height, fsaa_samples, depth_stencil); if (current && current != this) strategy->bindFBO(current->fbo); From fe5e7c17e79de8c251964f2612d58d08b9240609 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 26 Feb 2014 20:47:05 -0400 Subject: [PATCH 47/56] Added Body:setUserData and Body:getUserData (resolves issue #853_ --- src/common/Reference.cpp | 2 +- src/modules/graphics/opengl/Canvas.cpp | 6 ++-- src/modules/physics/box2d/Body.cpp | 44 ++++++++++++++++++++++++- src/modules/physics/box2d/Body.h | 27 ++++++++++++++- src/modules/physics/box2d/Fixture.h | 3 -- src/modules/physics/box2d/wrap_Body.cpp | 16 +++++++++ src/modules/physics/box2d/wrap_Body.h | 2 ++ 7 files changed, 91 insertions(+), 9 deletions(-) diff --git a/src/common/Reference.cpp b/src/common/Reference.cpp index 127023974..d2ea05774 100644 --- a/src/common/Reference.cpp +++ b/src/common/Reference.cpp @@ -26,7 +26,7 @@ namespace love const char REFERENCE_TABLE_NAME[] = "love-references"; Reference::Reference() - : L(0) + : L(nullptr) , idx(LUA_REFNIL) { } diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index daf32429c..d534ac910 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -129,7 +129,7 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glGenRenderbuffers(1, &stencil); glBindRenderbuffer(GL_RENDERBUFFER, stencil); - if (samples > 0) + if (samples > 1) glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH_STENCIL, width, height); else glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height); @@ -249,7 +249,7 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy glGenRenderbuffersEXT(1, &stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); - if (samples > 0) + if (samples > 1) { glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_DEPTH_STENCIL, width, height); @@ -358,7 +358,7 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT glGenRenderbuffersEXT(1, &stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); - if (samples > 0) + if (samples > 1) { glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_STENCIL_INDEX, width, height); diff --git a/src/modules/physics/box2d/Body.cpp b/src/modules/physics/box2d/Body.cpp index 72565658c..d43830d97 100644 --- a/src/modules/physics/box2d/Body.cpp +++ b/src/modules/physics/box2d/Body.cpp @@ -37,10 +37,14 @@ namespace box2d Body::Body(World *world, b2Vec2 p, Body::Type type) : world(world) + , udata(nullptr) { + udata = new bodyudata(); + udata->ref = nullptr; world->retain(); b2BodyDef def; def.position = Physics::scaleDown(p); + def.userData = (void *) udata; body = world->world->CreateBody(&def); // Box2D body holds a reference to the love Body. this->retain(); @@ -50,7 +54,9 @@ Body::Body(World *world, b2Vec2 p, Body::Type type) Body::Body(b2Body *b) : body(b) + , udata(nullptr) { + udata = (bodyudata *) b->GetUserData(); world = (World *)Memoizer::find(b->GetWorld()); world->retain(); // Box2D body holds a reference to the love Body. @@ -60,8 +66,10 @@ Body::Body(b2Body *b) Body::~Body() { + if (udata != nullptr) + delete udata->ref; + delete udata; world->release(); - body = 0; } float Body::getX() @@ -469,6 +477,40 @@ void Body::destroy() this->release(); } +int Body::setUserData(lua_State *L) +{ + love::luax_assert_argc(L, 1, 1); + + if (udata == nullptr) + { + udata = new bodyudata(); + body->SetUserData((void *) udata); + } + + if (udata->ref != nullptr) + { + // We set the Reference's lua_State to this one before deleting it, so + // it unrefs using the current lua_State's stack. This is necessary + // if setUserData is called in a coroutine. + udata->ref->setL(L); + delete udata->ref; + } + + udata->ref = new Reference(L); + + return 0; +} + +int Body::getUserData(lua_State *L) +{ + if (udata != nullptr && udata->ref != nullptr) + udata->ref->push(L); + else + lua_pushnil(L); + + return 1; +} + } // box2d } // physics } // love diff --git a/src/modules/physics/box2d/Body.h b/src/modules/physics/box2d/Body.h index 30cd1229b..cd4faf11b 100644 --- a/src/modules/physics/box2d/Body.h +++ b/src/modules/physics/box2d/Body.h @@ -41,6 +41,16 @@ class World; class Shape; class Fixture; +/** + * This struct is stored in a void pointer in the Box2D Body class. For now, all + * we need is a Lua reference to arbitrary data, but we might need more later. + **/ +struct bodyudata +{ + // Reference to arbitrary data. + Reference *ref; +}; + /** * A Body is an entity which has position and orientation * in world space. A Body does have collision geometry @@ -388,6 +398,18 @@ public: **/ void destroy(); + /** + * This function stores an in-C reference to + * arbitrary Lua data in the Box2D Body object. + **/ + int setUserData(lua_State *L); + + /** + * Gets the data set with setData. If no + * data is set, nil is returned. + **/ + int getUserData(lua_State *L); + private: /** @@ -408,7 +430,10 @@ private: // This ensures that a World only can be destroyed // once all bodies have been destroyed too. World *world; -}; + + bodyudata *udata; + +}; // Body } // box2d } // physics diff --git a/src/modules/physics/box2d/Fixture.h b/src/modules/physics/box2d/Fixture.h index e7f18f942..5564406d4 100644 --- a/src/modules/physics/box2d/Fixture.h +++ b/src/modules/physics/box2d/Fixture.h @@ -123,9 +123,6 @@ public: /** * This function stores an in-C reference to * arbitrary Lua data in the Box2D Fixture object. - * - * The data set here will be passed to the collision - * handler when collisions occur. **/ int setUserData(lua_State *L); diff --git a/src/modules/physics/box2d/wrap_Body.cpp b/src/modules/physics/box2d/wrap_Body.cpp index 419d1fb29..61eb7529d 100644 --- a/src/modules/physics/box2d/wrap_Body.cpp +++ b/src/modules/physics/box2d/wrap_Body.cpp @@ -538,6 +538,20 @@ int w_Body_destroy(lua_State *L) return 0; } +int w_Body_setUserData(lua_State *L) +{ + Body *t = luax_checkbody(L, 1); + lua_remove(L, 1); + return t->setUserData(L); +} + +int w_Body_getUserData(lua_State *L) +{ + Body *t = luax_checkbody(L, 1); + lua_remove(L, 1); + return t->getUserData(L); +} + static const luaL_Reg functions[] = { { "getX", w_Body_getX }, @@ -592,6 +606,8 @@ static const luaL_Reg functions[] = { "isFixedRotation", w_Body_isFixedRotation }, { "getFixtureList", w_Body_getFixtureList }, { "destroy", w_Body_destroy }, + { "setUserData", w_Body_setUserData }, + { "getUserData", w_Body_getUserData }, { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_Body.h b/src/modules/physics/box2d/wrap_Body.h index f06348809..2a41556f0 100644 --- a/src/modules/physics/box2d/wrap_Body.h +++ b/src/modules/physics/box2d/wrap_Body.h @@ -85,6 +85,8 @@ int w_Body_setFixedRotation(lua_State *L); int w_Body_isFixedRotation(lua_State *L); int w_Body_getFixtureList(lua_State *L); int w_Body_destroy(lua_State *L); +int w_Body_setUserData(lua_State *L); +int w_Body_getUserData(lua_State *L); extern "C" int luaopen_body(lua_State *L); } // box2d From ecf37320a96fd271d46d6b2b909efda843e665e2 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 27 Feb 2014 05:38:46 -0400 Subject: [PATCH 48/56] Changed love.graphics.newMesh, Mesh:setVertex, and Mesh:setVertices to default the u,v arguments to 0,0 instead of requiring them --- src/common/Memoizer.cpp | 8 ++++++-- src/modules/graphics/opengl/wrap_Graphics.cpp | 4 ++-- src/modules/graphics/opengl/wrap_Mesh.cpp | 12 ++++++------ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/common/Memoizer.cpp b/src/common/Memoizer.cpp index dcc8e5df2..8d6ec7d4f 100644 --- a/src/common/Memoizer.cpp +++ b/src/common/Memoizer.cpp @@ -38,8 +38,12 @@ void Memoizer::remove(void *key) void *Memoizer::find(void *key) { - if (objectMap.count(key)) return objectMap[key]; - return NULL; + auto it = objectMap.find(key); + + if (it != objectMap.end()) + return it->second; + else + return nullptr; } } // love diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index e7d6a6d74..243c9e908 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -494,8 +494,8 @@ int w_newMesh(lua_State *L) v.x = (float) luaL_checknumber(L, -8); v.y = (float) luaL_checknumber(L, -7); - v.s = (float) luaL_checknumber(L, -6); - v.t = (float) luaL_checknumber(L, -5); + v.s = (float) luaL_optnumber(L, -6, 0.0); + v.t = (float) luaL_optnumber(L, -5, 0.0); v.r = (unsigned char) luaL_optinteger(L, -4, 255); v.g = (unsigned char) luaL_optinteger(L, -3, 255); diff --git a/src/modules/graphics/opengl/wrap_Mesh.cpp b/src/modules/graphics/opengl/wrap_Mesh.cpp index 92a0371cf..83e21afd3 100644 --- a/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -53,8 +53,8 @@ int w_Mesh_setVertex(lua_State *L) v.x = luaL_checknumber(L, -8); v.y = luaL_checknumber(L, -7); - v.s = luaL_checknumber(L, -6); - v.t = luaL_checknumber(L, -5); + v.s = luaL_optnumber(L, -6, 0.0); + v.t = luaL_optnumber(L, -5, 0.0); v.r = luaL_optinteger(L, -4, 255); v.g = luaL_optinteger(L, -3, 255); v.b = luaL_optinteger(L, -2, 255); @@ -66,8 +66,8 @@ int w_Mesh_setVertex(lua_State *L) { v.x = luaL_checknumber(L, 3); v.y = luaL_checknumber(L, 4); - v.s = luaL_checknumber(L, 5); - v.t = luaL_checknumber(L, 6); + v.s = luaL_optnumber(L, 5, 0.0); + v.t = luaL_optnumber(L, 6, 0.0); v.r = luaL_optinteger(L, 7, 255); v.g = luaL_optinteger(L, 8, 255); v.b = luaL_optinteger(L, 9, 255); @@ -122,8 +122,8 @@ int w_Mesh_setVertices(lua_State *L) v.x = (float) luaL_checknumber(L, -8); v.y = (float) luaL_checknumber(L, -7); - v.s = (float) luaL_checknumber(L, -6); - v.t = (float) luaL_checknumber(L, -5); + v.s = (float) luaL_optnumber(L, -6, 0.0); + v.t = (float) luaL_optnumber(L, -5, 0.0); v.r = (unsigned char) luaL_optinteger(L, -4, 255); v.g = (unsigned char) luaL_optinteger(L, -3, 255); From ec0f428c4f9795b5a45d0e87cb2b1acb4544908d Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 1 Mar 2014 20:23:04 -0400 Subject: [PATCH 49/56] Cleaned up the code for initializing love.filesystem and the source and save directories a bit --- src/modules/sound/SoundData.cpp | 20 ++++----- src/modules/sound/SoundData.h | 5 ++- src/scripts/boot.lua | 33 +++++++++------ src/scripts/boot.lua.h | 75 +++++++++++++++++++++------------ 4 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/modules/sound/SoundData.cpp b/src/modules/sound/SoundData.cpp index edc9720a6..cbb9383c1 100644 --- a/src/modules/sound/SoundData.cpp +++ b/src/modules/sound/SoundData.cpp @@ -52,7 +52,7 @@ SoundData::SoundData(Decoder *decoder) { while (bufferSize < (size_t) size + decoded) bufferSize <<= 1; - data = (char *)realloc(data, bufferSize); + data = (int8 *) realloc(data, bufferSize); } if (!data) @@ -76,7 +76,7 @@ SoundData::SoundData(Decoder *decoder) // Shrink buffer if necessary. if (data && bufferSize > (size_t) size) - data = (char *) realloc(data, size); + data = (int8 *) realloc(data, size); channels = decoder->getChannels(); bitDepth = decoder->getBitDepth(); @@ -139,7 +139,7 @@ void SoundData::load(int samples, int sampleRate, int bitDepth, int channels, vo if (realsize > INT_MAX) throw love::Exception("Data is too big!"); - data = (char *)malloc(size); + data = (int8 *) malloc(size); if (!data) throw love::Exception("Not enough memory."); @@ -190,14 +190,12 @@ void SoundData::setSample(int i, float sample) if (bitDepth == 16) { - short *s = (short *)data; - s[i] = (short)(sample*(float)SHRT_MAX); - return; + int16 *s = (int16 *) data; + s[i] = (int16) (sample * (float) LOVE_INT16_MAX); } else { - data[i] = (char)(sample*(float)CHAR_MAX); - return; + data[i] = (int8) (sample * (float) LOVE_INT8_MAX); } } @@ -209,12 +207,12 @@ float SoundData::getSample(int i) const if (bitDepth == 16) { - short *s = (short *)data; - return (float)s[i]/(float)SHRT_MAX; + int16 *s = (int16 *) data; + return (float) s[i] / (float) LOVE_INT16_MAX; } else { - return (float)data[i]/(float)CHAR_MAX; + return (float) data[i] / (float) LOVE_INT8_MAX; } } diff --git a/src/modules/sound/SoundData.h b/src/modules/sound/SoundData.h index d6b7528db..e12e55ba0 100644 --- a/src/modules/sound/SoundData.h +++ b/src/modules/sound/SoundData.h @@ -23,7 +23,7 @@ // LOVE #include "filesystem/File.h" - +#include "common/int.h" #include "Decoder.h" namespace love @@ -59,12 +59,13 @@ private: void load(int samples, int sampleRate, int bitDepth, int channels, void *newData = 0); - char *data; + int8 *data; int size; int sampleRate; int bitDepth; int channels; + }; // SoundData } // sound diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index d5cc212fd..183b1725f 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -223,15 +223,14 @@ function love.createhandlers() end -local is_fused_game = false -local no_game_code = false - local function uridecode(s) return s:gsub("%%%x%x", function(str) return string.char(tonumber(str:sub(2), 16)) end) end +local no_game_code = false + -- This can't be overriden. function love.boot() @@ -248,35 +247,45 @@ function love.boot() -- Is this one of those fancy "fused" games? local can_has_game = pcall(love.filesystem.setSource, arg0) - is_fused_game = can_has_game + local is_fused_game = can_has_game if love.arg.options.fused.set then is_fused_game = true end + love.filesystem.setFused(is_fused_game) + + local identity = "" if not can_has_game and o.game.set and o.game.arg[1] then local nouri = o.game.arg[1] if nouri:sub(1, 7) == "file://" then nouri = uridecode(nouri:sub(8)) end local full_source = love.path.getfull(nouri) - local leaf = love.path.leaf(full_source) - leaf = leaf:gsub("^([%.]+)", "") -- strip leading "."'s - leaf = leaf:gsub("%.([^%.]+)$", "") -- strip extension - leaf = leaf:gsub("%.", "_") -- replace remaining "."'s with "_" - love.filesystem.setIdentity(leaf) can_has_game = pcall(love.filesystem.setSource, full_source) + + -- Use the name of the source .love as the identity for now. + identity = love.path.leaf(full_source) + else + -- Use the name of the exe as the identity for now. + identity = love.path.leaf(arg0) end + identity = identity:gsub("^([%.]+)", "") -- strip leading "."'s + identity = identity:gsub("%.([^%.]+)$", "") -- strip extension + identity = identity:gsub("%.", "_") -- replace remaining "."'s with "_" + identity = #identity > 0 and identity or "lovegame" + + -- When conf.lua is initially loaded, the main source should be checked + -- before the save directory (the identity should be appended.) + pcall(love.filesystem.setIdentity, identity, true) + if can_has_game and not (love.filesystem.exists("main.lua") or love.filesystem.exists("conf.lua")) then no_game_code = true end - love.filesystem.setFused(is_fused_game) - if not can_has_game then love.nogame() end - end function love.init() diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index aeb746199..5e6f539ad 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -404,10 +404,6 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x09, 0x7d, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x6d, - 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, - 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, 0x72, 0x69, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x73, 0x29, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x25, @@ -418,6 +414,8 @@ const unsigned char boot_lua[] = 0x62, 0x28, 0x32, 0x29, 0x2c, 0x20, 0x31, 0x36, 0x29, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, + 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x6e, 0x2e, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x62, 0x6f, 0x6f, 0x74, @@ -442,13 +440,18 @@ const unsigned char boot_lua[] = 0x65, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x30, 0x29, 0x0a, - 0x09, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x63, - 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, + 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x75, 0x73, 0x65, 0x64, 0x2e, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, + 0x65, 0x74, 0x46, 0x75, 0x73, 0x65, 0x64, 0x28, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, + 0x61, 0x6d, 0x65, 0x29, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, + 0x22, 0x22, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x5b, 0x31, 0x5d, 0x20, @@ -464,28 +467,51 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x67, 0x65, 0x74, 0x66, 0x75, 0x6c, 0x6c, 0x28, 0x6e, 0x6f, 0x75, 0x72, 0x69, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, - 0x65, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x3d, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x3a, 0x67, 0x73, 0x75, 0x62, - 0x28, 0x22, 0x5e, 0x28, 0x5b, 0x25, 0x2e, 0x5d, 0x2b, 0x29, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x20, 0x2d, - 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x6c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, - 0x22, 0x27, 0x73, 0x0a, - 0x09, 0x09, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x3d, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x3a, 0x67, 0x73, 0x75, 0x62, - 0x28, 0x22, 0x25, 0x2e, 0x28, 0x5b, 0x5e, 0x25, 0x2e, 0x5d, 0x2b, 0x29, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, - 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, - 0x6f, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x3d, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x3a, 0x67, 0x73, 0x75, 0x62, - 0x28, 0x22, 0x25, 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x5f, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x70, - 0x6c, 0x61, 0x63, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x22, - 0x27, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x22, 0x5f, 0x22, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, - 0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, 0x6c, 0x65, 0x61, 0x66, 0x29, 0x0a, 0x09, 0x09, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x0a, + 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x2e, 0x6c, 0x6f, 0x76, + 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x2e, 0x0a, + 0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, + 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x29, 0x0a, + 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, + 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x2e, 0x0a, + 0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, + 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x61, 0x66, 0x28, 0x61, 0x72, 0x67, 0x30, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5e, 0x28, 0x5b, 0x25, 0x2e, 0x5d, 0x2b, 0x29, 0x22, + 0x2c, 0x20, 0x22, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, 0x6c, 0x65, 0x61, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x22, 0x27, 0x73, 0x0a, + 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x2e, 0x28, 0x5b, 0x5e, 0x25, 0x2e, 0x5d, 0x2b, + 0x29, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x70, 0x20, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x0a, + 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x5f, 0x22, 0x29, + 0x20, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, + 0x69, 0x6e, 0x67, 0x20, 0x22, 0x2e, 0x22, 0x27, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x22, 0x5f, 0x22, 0x0a, + 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x23, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x20, 0x3e, 0x20, 0x30, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x6c, 0x6f, 0x76, 0x65, 0x67, 0x61, 0x6d, 0x65, 0x22, 0x0a, + 0x09, 0x2d, 0x2d, 0x20, 0x57, 0x68, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x20, + 0x69, 0x73, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, + 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x0a, + 0x09, 0x2d, 0x2d, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x76, + 0x65, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x28, 0x74, 0x68, 0x65, 0x20, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, + 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x2e, 0x29, 0x0a, + 0x09, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2c, 0x20, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e, @@ -495,9 +521,6 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, - 0x65, 0x74, 0x46, 0x75, 0x73, 0x65, 0x64, 0x28, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, - 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6e, 0x6f, 0x67, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0a, From 55514720a66f4881174dbcd2b36216ec6182363c Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 1 Mar 2014 21:16:01 -0400 Subject: [PATCH 50/56] Fixed some minor compiler warnings --- src/common/Data.h | 2 +- src/common/Vector.cpp | 2 +- src/common/b64.h | 2 +- src/common/utf8.h | 2 +- src/libraries/ddsparse/ddsparse.h | 2 +- src/modules/audio/Audio.h | 2 +- src/modules/font/Font.h | 2 +- src/modules/font/ImageRasterizer.h | 2 +- src/modules/font/Rasterizer.cpp | 2 +- src/modules/font/Rasterizer.h | 2 +- src/modules/font/freetype/TrueTypeRasterizer.cpp | 2 +- src/modules/graphics/opengl/Font.h | 2 +- src/modules/graphics/opengl/ParticleSystem.h | 2 +- src/modules/image/Image.h | 4 ++-- src/modules/mouse/Mouse.h | 2 +- src/modules/mouse/wrap_Cursor.cpp | 4 ++-- src/modules/physics/box2d/wrap_MotorJoint.cpp | 2 +- src/modules/sound/Decoder.h | 2 +- src/modules/sound/lullaby/FLACDecoder.cpp | 2 +- src/modules/sound/lullaby/GmeDecoder.cpp | 2 +- src/modules/system/wrap_System.cpp | 2 +- 21 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/common/Data.h b/src/common/Data.h index ea31e69e7..ffea71cf9 100644 --- a/src/common/Data.h +++ b/src/common/Data.h @@ -38,7 +38,7 @@ public: /** * Destructor. **/ - virtual ~Data() {}; + virtual ~Data() {} /** * Gets a pointer to the data. This pointer will obviously not diff --git a/src/common/Vector.cpp b/src/common/Vector.cpp index 8e0ae515b..c2d37869d 100644 --- a/src/common/Vector.cpp +++ b/src/common/Vector.cpp @@ -23,4 +23,4 @@ namespace love { // Implementation in header. -} \ No newline at end of file +} diff --git a/src/common/b64.h b/src/common/b64.h index 99685cdac..55fe47dea 100644 --- a/src/common/b64.h +++ b/src/common/b64.h @@ -38,4 +38,4 @@ char *b64_decode(const char *src, int slen, int &size); } // love -#endif // LOVE_B64_H \ No newline at end of file +#endif // LOVE_B64_H diff --git a/src/common/utf8.h b/src/common/utf8.h index 6f0d78ef1..9a2c51e9b 100644 --- a/src/common/utf8.h +++ b/src/common/utf8.h @@ -45,4 +45,4 @@ void replace_char(std::string &str, char find, char replace); } // love -#endif // LOVE_WINDOWS \ No newline at end of file +#endif // LOVE_WINDOWS diff --git a/src/libraries/ddsparse/ddsparse.h b/src/libraries/ddsparse/ddsparse.h index 82c2c41cc..6ab659347 100644 --- a/src/libraries/ddsparse/ddsparse.h +++ b/src/libraries/ddsparse/ddsparse.h @@ -60,7 +60,7 @@ struct Image const uint8_t *data; Image() : width(0), height(0), dataSize(0), data(0) - {}; + {} }; /** diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index b43391dbe..9a8ca863c 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -67,7 +67,7 @@ public: /** * Destructor. **/ - virtual ~Audio() {}; + virtual ~Audio() {} virtual Source *newSource(love::sound::Decoder *decoder) = 0; virtual Source *newSource(love::sound::SoundData *soundData) = 0; diff --git a/src/modules/font/Font.h b/src/modules/font/Font.h index dacde0348..a92b88efc 100644 --- a/src/modules/font/Font.h +++ b/src/modules/font/Font.h @@ -54,4 +54,4 @@ public: } // font } // love -#endif // LOVE_FONT_FONT_H \ No newline at end of file +#endif // LOVE_FONT_FONT_H diff --git a/src/modules/font/ImageRasterizer.h b/src/modules/font/ImageRasterizer.h index 5c7e9e8f6..482d442c6 100644 --- a/src/modules/font/ImageRasterizer.h +++ b/src/modules/font/ImageRasterizer.h @@ -79,4 +79,4 @@ private: } // font } // love -#endif // LOVE_FONT_IMAGE_RASTERIZER_H \ No newline at end of file +#endif // LOVE_FONT_IMAGE_RASTERIZER_H diff --git a/src/modules/font/Rasterizer.cpp b/src/modules/font/Rasterizer.cpp index 1454f2557..cec9f0bef 100644 --- a/src/modules/font/Rasterizer.cpp +++ b/src/modules/font/Rasterizer.cpp @@ -96,4 +96,4 @@ bool Rasterizer::hasGlyphs(const std::string &text) const } } // font -} // love \ No newline at end of file +} // love diff --git a/src/modules/font/Rasterizer.h b/src/modules/font/Rasterizer.h index a4cd6e5c9..ff1cd22e5 100644 --- a/src/modules/font/Rasterizer.h +++ b/src/modules/font/Rasterizer.h @@ -114,4 +114,4 @@ protected: } // font } // love -#endif // LOVE_FONT_RASTERIZER_H \ No newline at end of file +#endif // LOVE_FONT_RASTERIZER_H diff --git a/src/modules/font/freetype/TrueTypeRasterizer.cpp b/src/modules/font/freetype/TrueTypeRasterizer.cpp index 847793687..e09328f70 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.cpp +++ b/src/modules/font/freetype/TrueTypeRasterizer.cpp @@ -146,4 +146,4 @@ bool TrueTypeRasterizer::hasGlyph(uint32 glyph) const } // freetype } // font -} // love \ No newline at end of file +} // love diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 791eee6f7..fee277452 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -175,7 +175,7 @@ private: return texture < other.texture; else return startvertex < other.startvertex; - }; + } }; bool initializeTexture(GLenum format); diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 8b27192d6..272ab8303 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -65,7 +65,7 @@ public: INSERT_MODE_TOP, INSERT_MODE_BOTTOM, INSERT_MODE_RANDOM, - INSERT_MODE_MAX_ENUM, + INSERT_MODE_MAX_ENUM }; /** diff --git a/src/modules/image/Image.h b/src/modules/image/Image.h index b95024475..9a5d50794 100644 --- a/src/modules/image/Image.h +++ b/src/modules/image/Image.h @@ -47,7 +47,7 @@ public: /** * Destructor. **/ - virtual ~Image() {}; + virtual ~Image() {} /** * Creates new ImageData from FileData. @@ -93,4 +93,4 @@ public: } // image } // love -#endif // LOVE_IMAGE_IMAGE_H \ No newline at end of file +#endif // LOVE_IMAGE_IMAGE_H diff --git a/src/modules/mouse/Mouse.h b/src/modules/mouse/Mouse.h index 3a178fd4d..90d73d727 100644 --- a/src/modules/mouse/Mouse.h +++ b/src/modules/mouse/Mouse.h @@ -49,7 +49,7 @@ public: BUTTON_MAX_ENUM }; - virtual ~Mouse() {}; + virtual ~Mouse() {} virtual Cursor *newCursor(love::image::ImageData *data, int hotx, int hoty) = 0; virtual Cursor *getSystemCursor(Cursor::SystemCursor cursortype) = 0; diff --git a/src/modules/mouse/wrap_Cursor.cpp b/src/modules/mouse/wrap_Cursor.cpp index 9e0702937..bb245cfba 100644 --- a/src/modules/mouse/wrap_Cursor.cpp +++ b/src/modules/mouse/wrap_Cursor.cpp @@ -51,7 +51,7 @@ int w_Cursor_getType(lua_State *L) lua_pushstring(L, typestr); return 1; -}; +} static const luaL_Reg functions[] = { @@ -65,4 +65,4 @@ extern "C" int luaopen_cursor(lua_State *L) } } // mouse -} // love \ No newline at end of file +} // love diff --git a/src/modules/physics/box2d/wrap_MotorJoint.cpp b/src/modules/physics/box2d/wrap_MotorJoint.cpp index 7286d3504..b264e17a9 100644 --- a/src/modules/physics/box2d/wrap_MotorJoint.cpp +++ b/src/modules/physics/box2d/wrap_MotorJoint.cpp @@ -140,4 +140,4 @@ extern "C" int luaopen_motorjoint(lua_State *L) } // box2d } // phyics -} // love \ No newline at end of file +} // love diff --git a/src/modules/sound/Decoder.h b/src/modules/sound/Decoder.h index 3701c1e8f..50c522c1b 100644 --- a/src/modules/sound/Decoder.h +++ b/src/modules/sound/Decoder.h @@ -67,7 +67,7 @@ public: /** * Destructor. Should free internal buffer. **/ - virtual ~Decoder() {}; + virtual ~Decoder() {} /** * Decodes the next chunk of the music stream, this will usually be diff --git a/src/modules/sound/lullaby/FLACDecoder.cpp b/src/modules/sound/lullaby/FLACDecoder.cpp index 1fcd8245a..6762d9f7b 100644 --- a/src/modules/sound/lullaby/FLACDecoder.cpp +++ b/src/modules/sound/lullaby/FLACDecoder.cpp @@ -183,4 +183,4 @@ void FLACDecoder::error_callback(FLAC__StreamDecoderErrorStatus status) } // sound } // love -#endif // 0 \ No newline at end of file +#endif // 0 diff --git a/src/modules/sound/lullaby/GmeDecoder.cpp b/src/modules/sound/lullaby/GmeDecoder.cpp index aa48fc283..98d364829 100644 --- a/src/modules/sound/lullaby/GmeDecoder.cpp +++ b/src/modules/sound/lullaby/GmeDecoder.cpp @@ -146,4 +146,4 @@ int GmeDecoder::getBitDepth() const } // sound } // love -#endif // LOVE_SUPPORT_GME \ No newline at end of file +#endif // LOVE_SUPPORT_GME diff --git a/src/modules/system/wrap_System.cpp b/src/modules/system/wrap_System.cpp index c4df69f07..c17c29c3c 100644 --- a/src/modules/system/wrap_System.cpp +++ b/src/modules/system/wrap_System.cpp @@ -109,4 +109,4 @@ extern "C" int luaopen_love_system(lua_State *L) } } // system -} // love \ No newline at end of file +} // love From a3afb1a9ca765b6e5e19654827129a556f4c260f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 2 Mar 2014 03:17:47 -0400 Subject: [PATCH 51/56] Refactored the ImageData decoding/encoding backends a bit --- CMakeLists.txt | 1 + .../love-framework.xcodeproj/project.pbxproj | 4 ++ src/modules/image/magpie/DevilHandler.cpp | 32 +++++----- src/modules/image/magpie/DevilHandler.h | 19 +++--- src/modules/image/magpie/FormatHandler.cpp | 62 +++++++++++++++++++ src/modules/image/magpie/FormatHandler.h | 28 ++++++--- src/modules/image/magpie/Image.cpp | 13 ++-- src/modules/image/magpie/Image.h | 9 +++ src/modules/image/magpie/ImageData.cpp | 55 +++++++++++----- src/modules/image/magpie/ImageData.h | 13 +++- 10 files changed, 179 insertions(+), 57 deletions(-) create mode 100644 src/modules/image/magpie/FormatHandler.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c8af83674..f5b00344e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -341,6 +341,7 @@ set(LOVE_SRC_MODULE_IMAGE_MAGPIE src/modules/image/magpie/ddsHandler.h src/modules/image/magpie/DevilHandler.cpp src/modules/image/magpie/DevilHandler.h + src/modules/image/magpie/FormatHandler.cpp src/modules/image/magpie/FormatHandler.h src/modules/image/magpie/Image.cpp src/modules/image/magpie/Image.h diff --git a/platform/macosx/love-framework.xcodeproj/project.pbxproj b/platform/macosx/love-framework.xcodeproj/project.pbxproj index 3f245a0f0..839b1a9ce 100644 --- a/platform/macosx/love-framework.xcodeproj/project.pbxproj +++ b/platform/macosx/love-framework.xcodeproj/project.pbxproj @@ -289,6 +289,7 @@ FAC86E641724552C00EED715 /* wrap_Quad.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E621724552C00EED715 /* wrap_Quad.h */; }; FAC86E6B1724555D00EED715 /* Quad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E671724555D00EED715 /* Quad.cpp */; }; FAC86E6C1724555D00EED715 /* Quad.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E681724555D00EED715 /* Quad.h */; }; + FADD58DD18C30367005FC3BF /* FormatHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADD58DC18C30367005FC3BF /* FormatHandler.cpp */; }; FAE010DB170DDE99006F29D0 /* ddsinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010D8170DDE99006F29D0 /* ddsinfo.h */; }; FAE010DC170DDE99006F29D0 /* ddsparse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE010D9170DDE99006F29D0 /* ddsparse.cpp */; }; FAE010DD170DDE99006F29D0 /* ddsparse.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010DA170DDE99006F29D0 /* ddsparse.h */; }; @@ -847,6 +848,7 @@ FAC86E621724552C00EED715 /* wrap_Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Quad.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 = ""; }; + FADD58DC18C30367005FC3BF /* FormatHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormatHandler.cpp; sourceTree = ""; }; FAE010D8170DDE99006F29D0 /* ddsinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsinfo.h; sourceTree = ""; }; FAE010D9170DDE99006F29D0 /* ddsparse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ddsparse.cpp; sourceTree = ""; }; FAE010DA170DDE99006F29D0 /* ddsparse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsparse.h; sourceTree = ""; }; @@ -1088,6 +1090,7 @@ FAE010DF170DE25E006F29D0 /* ddsHandler.h */, 1AA7781A230065F346E2313A /* DevilHandler.cpp */, 283342E174613897621A43F1 /* DevilHandler.h */, + FADD58DC18C30367005FC3BF /* FormatHandler.cpp */, FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */, 505F23A73BFE250833D650E4 /* Image.cpp */, 68616BD516DB124312B47EB3 /* Image.h */, @@ -2267,6 +2270,7 @@ FA08F66816C7548200F007B5 /* wrap_WheelJoint.cpp in Sources */, FA08F66916C7548200F007B5 /* wrap_World.cpp in Sources */, FA08F66A16C7549200F007B5 /* Sound.cpp in Sources */, + FADD58DD18C30367005FC3BF /* FormatHandler.cpp in Sources */, FA08F66B16C7549200F007B5 /* SoundData.cpp in Sources */, FA08F66C16C7549200F007B5 /* wrap_Decoder.cpp in Sources */, FA08F66D16C7549200F007B5 /* wrap_Sound.cpp in Sources */, diff --git a/src/modules/image/magpie/DevilHandler.cpp b/src/modules/image/magpie/DevilHandler.cpp index dede18fdc..74abd813b 100644 --- a/src/modules/image/magpie/DevilHandler.cpp +++ b/src/modules/image/magpie/DevilHandler.cpp @@ -23,15 +23,10 @@ // LOVE #include "common/Exception.h" #include "common/math.h" -#include "thread/threads.h" // DevIL #include -using love::thread::Lock; - -static Mutex *devilMutex = 0; - namespace love { namespace image @@ -44,21 +39,22 @@ static inline void ilxClearErrors() while (ilGetError() != IL_NO_ERROR); } -void DevilHandler::init() +DevilHandler::DevilHandler() + : mutex(nullptr) { + // There should only ever be one DevilHandler object (owned by the Image + // module), so we can use the global initialization function here. ilInit(); ilEnable(IL_ORIGIN_SET); ilOriginFunc(IL_ORIGIN_UPPER_LEFT); } -void DevilHandler::quit() +DevilHandler::~DevilHandler() { ilShutDown(); - if (devilMutex) - { - delete devilMutex; - devilMutex = 0; - } + + if (mutex) + delete mutex; } bool DevilHandler::canDecode(love::filesystem::FileData * /*data*/) @@ -85,10 +81,10 @@ bool DevilHandler::canEncode(ImageData::Format format) DevilHandler::DecodedImage DevilHandler::decode(love::filesystem::FileData *data) { - if (!devilMutex) - devilMutex = thread::newMutex(); + if (!mutex) + mutex = love::thread::newMutex(); - Lock lock(devilMutex); + love::thread::Lock lock(mutex); ILuint image = ilGenImage(); ilBindImage(image); @@ -140,10 +136,10 @@ DevilHandler::DecodedImage DevilHandler::decode(love::filesystem::FileData *data DevilHandler::EncodedImage DevilHandler::encode(const DecodedImage &img, ImageData::Format format) { - if (!devilMutex) - devilMutex = thread::newMutex(); + if (!mutex) + mutex = love::thread::newMutex(); - Lock lock(devilMutex); + love::thread::Lock lock(mutex); ILuint tempimage = ilGenImage(); ilBindImage(tempimage); diff --git a/src/modules/image/magpie/DevilHandler.h b/src/modules/image/magpie/DevilHandler.h index 5d1e85019..d1f833abc 100644 --- a/src/modules/image/magpie/DevilHandler.h +++ b/src/modules/image/magpie/DevilHandler.h @@ -24,6 +24,7 @@ // LOVE #include "filesystem/FileData.h" #include "FormatHandler.h" +#include "thread/threads.h" namespace love { @@ -39,16 +40,20 @@ class DevilHandler : public FormatHandler { public: - static void init(); - static void quit(); - // Implements FormatHandler. - static bool canDecode(love::filesystem::FileData *data); - static bool canEncode(ImageData::Format format); + DevilHandler(); + virtual ~DevilHandler(); - static DecodedImage decode(love::filesystem::FileData *data); - static EncodedImage encode(const DecodedImage &img, ImageData::Format format); + virtual bool canDecode(love::filesystem::FileData *data); + virtual bool canEncode(ImageData::Format format); + + virtual DecodedImage decode(love::filesystem::FileData *data); + virtual EncodedImage encode(const DecodedImage &img, ImageData::Format format); + +private: + + Mutex *mutex; }; // DevilHandler diff --git a/src/modules/image/magpie/FormatHandler.cpp b/src/modules/image/magpie/FormatHandler.cpp new file mode 100644 index 000000000..d50e24008 --- /dev/null +++ b/src/modules/image/magpie/FormatHandler.cpp @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2006-2014 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. + **/ + +// LOVE +#include "FormatHandler.h" +#include "common/Exception.h" + +namespace love +{ +namespace image +{ +namespace magpie +{ + +FormatHandler::FormatHandler() +{ +} + +FormatHandler::~FormatHandler() +{ +} + +bool FormatHandler::canDecode(love::filesystem::FileData* /*data*/) +{ + return false; +} + +bool FormatHandler::canEncode(ImageData::Format /*format*/) +{ + return false; +} + +FormatHandler::DecodedImage FormatHandler::decode(love::filesystem::FileData* /*data*/) +{ + throw love::Exception("Image decoding is not implemented for this format backend."); +} + +FormatHandler::EncodedImage FormatHandler::encode(const DecodedImage& /*img*/, ImageData::Format /*format*/) +{ + throw love::Exception("Image encoding is not implemented for this format backend."); +} + +} // magpie +} // image +} // love diff --git a/src/modules/image/magpie/FormatHandler.h b/src/modules/image/magpie/FormatHandler.h index f953e97e3..f115fced6 100644 --- a/src/modules/image/magpie/FormatHandler.h +++ b/src/modules/image/magpie/FormatHandler.h @@ -24,6 +24,7 @@ // LOVE #include "image/ImageData.h" #include "filesystem/FileData.h" +#include "common/Object.h" namespace love { @@ -34,8 +35,9 @@ namespace magpie /** * Base class for all ImageData encoder/decoder library interfaces. + * We inherit from love::Object to take advantage of reference counting... **/ -class FormatHandler +class FormatHandler : public love::Object { public: @@ -56,26 +58,32 @@ public: EncodedImage() : size(0), data(0) {} }; - // Lets pretend we have virtual static methods... + /** + * The default constructor is called when the Image module is initialized. + **/ + FormatHandler(); /** - * Determines whether a particular FileData can be decoded by this handler. - * @param data The data to decode. + * The destructor is called when the Image module is uninitialized. **/ - // virtual static bool canDecode(love::filesystem::FileData *data) = 0; + virtual ~FormatHandler(); /** - * Determines whether this handler can encode to a particular format. - * @param format The format to encode to. + * Whether this format handler can decode a particular FileData. **/ - // virtual static bool canEncode(ImageData::Format format) = 0; + virtual bool canDecode(love::filesystem::FileData *data); + + /** + * Whether this format handler can encode to a particular format. + **/ + virtual bool canEncode(ImageData::Format format); /** * Decodes an image from its encoded form into raw pixel data. * @param data The encoded data to decode. * @return The decoded pixel data. **/ - // virtual static DecodedImage decode(love::filesystem::FileData *data) = 0; + virtual DecodedImage decode(love::filesystem::FileData *data); /** * Encodes an image from raw pixel data into a particular format. @@ -83,7 +91,7 @@ public: * @param format The format to encode to. * @return The encoded image data. **/ - // virtual static EncodedImage encode(const DecodedImage &img, ImageData::Format format) = 0; + virtual EncodedImage encode(const DecodedImage &img, ImageData::Format format); }; // FormatHandler diff --git a/src/modules/image/magpie/Image.cpp b/src/modules/image/magpie/Image.cpp index 7eb8d2519..3953aefdd 100644 --- a/src/modules/image/magpie/Image.cpp +++ b/src/modules/image/magpie/Image.cpp @@ -34,12 +34,15 @@ namespace magpie Image::Image() { - DevilHandler::init(); + formatHandlers.push_back(new DevilHandler); } Image::~Image() { - DevilHandler::quit(); + // ImageData objects reference the FormatHandlers in our list, so we should + // release them instead of deleting them completely here. + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->release(); } const char *Image::getName() const @@ -49,17 +52,17 @@ const char *Image::getName() const love::image::ImageData *Image::newImageData(love::filesystem::FileData *data) { - return new ImageData(data); + return new ImageData(formatHandlers, data); } love::image::ImageData *Image::newImageData(int width, int height) { - return new ImageData(width, height); + return new ImageData(formatHandlers, width, height); } love::image::ImageData *Image::newImageData(int width, int height, void *data, bool own) { - return new ImageData(width, height, data, own); + return new ImageData(formatHandlers, width, height, data, own); } love::image::CompressedData *Image::newCompressedData(love::filesystem::FileData *data) diff --git a/src/modules/image/magpie/Image.h b/src/modules/image/magpie/Image.h index 4385e6635..75adfc479 100644 --- a/src/modules/image/magpie/Image.h +++ b/src/modules/image/magpie/Image.h @@ -23,6 +23,10 @@ // LOVE #include "image/Image.h" +#include "FormatHandler.h" + +// C++ +#include namespace love { @@ -54,6 +58,11 @@ public: bool isCompressed(love::filesystem::FileData *data); +private: + + // Image format handlers we can use for decoding and encoding ImageData. + std::list formatHandlers; + }; // Image } // magpie diff --git a/src/modules/image/magpie/ImageData.cpp b/src/modules/image/magpie/ImageData.cpp index db614abbb..7864b55e9 100644 --- a/src/modules/image/magpie/ImageData.cpp +++ b/src/modules/image/magpie/ImageData.cpp @@ -18,11 +18,9 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE #include "ImageData.h" -#include "FormatHandler.h" -#include "DevilHandler.h" - namespace love { namespace image @@ -30,23 +28,36 @@ namespace image namespace magpie { -ImageData::ImageData(love::filesystem::FileData *data) +ImageData::ImageData(std::list formats, love::filesystem::FileData *data) + : formatHandlers(formats) { + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->retain(); + decode(data); } -ImageData::ImageData(int width, int height) +ImageData::ImageData(std::list formats, int width, int height) + : formatHandlers(formats) { + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->retain(); + this->width = width; this->height = height; + create(width, height); // Set to black/transparency. memset(data, 0, width*height*sizeof(pixel)); } -ImageData::ImageData(int width, int height, void *data, bool own) +ImageData::ImageData(std::list formats, int width, int height, void *data, bool own) + : formatHandlers(formats) { + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->retain(); + this->width = width; this->height = height; @@ -59,6 +70,9 @@ ImageData::ImageData(int width, int height, void *data, bool own) ImageData::~ImageData() { delete[] data; + + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->release(); } void ImageData::create(int width, int height, void *data) @@ -80,16 +94,23 @@ void ImageData::decode(love::filesystem::FileData *data) { FormatHandler::DecodedImage decodedimage; - if (DevilHandler::canDecode(data)) - decodedimage = DevilHandler::decode(data); - else + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + { + if ((*it)->canDecode(data)) + { + decodedimage = (*it)->decode(data); + break; + } + } + + if (decodedimage.data == nullptr) throw love::Exception("Could not decode image: unrecognized format."); // The decoder *must* output a 32 bits-per-pixel image. if (decodedimage.size != decodedimage.width*decodedimage.height*sizeof(pixel)) { delete[] decodedimage.data; - throw love::Exception("Coult not convert image!"); + throw love::Exception("Could not convert image!"); } if (this->data) @@ -114,15 +135,21 @@ void ImageData::encode(love::filesystem::File *f, ImageData::Format format) rawimage.size = width*height*sizeof(pixel); rawimage.data = data; - if (DevilHandler::canEncode(format)) - encodedimage = DevilHandler::encode(rawimage, format); - else + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + { + if ((*it)->canEncode(format)) + { + encodedimage = (*it)->encode(rawimage, format); + break; + } + } + + if (encodedimage.data == nullptr) throw love::Exception("Image format has no suitable encoder."); } try { - f->open(love::filesystem::File::WRITE); f->write(encodedimage.data, encodedimage.size); f->close(); diff --git a/src/modules/image/magpie/ImageData.h b/src/modules/image/magpie/ImageData.h index b7ccbf346..298e82423 100644 --- a/src/modules/image/magpie/ImageData.h +++ b/src/modules/image/magpie/ImageData.h @@ -22,9 +22,13 @@ #define LOVE_IMAGE_MAGPIE_IMAGE_DATA_H // LOVE +#include "FormatHandler.h" #include "filesystem/File.h" #include "image/ImageData.h" +// C++ +#include + namespace love { namespace image @@ -36,9 +40,9 @@ class ImageData : public love::image::ImageData { public: - ImageData(love::filesystem::FileData *data); - ImageData(int width, int height); - ImageData(int width, int height, void *data, bool own); + ImageData(std::list formats, love::filesystem::FileData *data); + ImageData(std::list formats, int width, int height); + ImageData(std::list formats, int width, int height, void *data, bool own); virtual ~ImageData(); // Implements image::ImageData. @@ -52,6 +56,9 @@ private: // Decode and load an encoded format. void decode(love::filesystem::FileData *data); + // Image format handlers we can use for decoding and encoding. + std::list formatHandlers; + }; // ImageData } // magpie From d5096840ba20d9cfda63221ff952ecb11bc70908 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 2 Mar 2014 15:49:29 -0400 Subject: [PATCH 52/56] Fixed Canvas:clear not working properly with antialiased Canvases --- src/modules/graphics/opengl/Canvas.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index d534ac910..58ee616c4 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -590,6 +590,9 @@ bool Canvas::loadVolatile() return false; clear(Color(0, 0, 0, 0)); + + fsaa_dirty = (fsaa_buffer != 0); + return true; } @@ -868,6 +871,9 @@ void Canvas::clear(Color c) if (current != this) strategy->bindFBO(previous); + + if (fsaa_buffer != 0) + fsaa_dirty = true; } bool Canvas::checkCreateStencil() From f7c0fc1888786002d82634f3422eba9ade53fcd8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 3 Mar 2014 03:36:17 -0400 Subject: [PATCH 53/56] Make sure love.window.getMode returns up-to-date information about the window, remove some Mac-specific windowing code now unnecessary with SDL 2.0.2. --- src/modules/window/sdl/Window.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 44662e728..af8a0940e 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -371,13 +371,10 @@ void Window::updateSettings(const WindowSettings &newsettings) #endif // Only minimize on focus loss if the window is in exclusive-fullscreen - // mode (mimics behaviour of SDL 2.0.2+). - // In OS X we always disable this to prevent dock minimization weirdness. -#ifndef LOVE_MACOSX + // mode. if (curMode.settings.fullscreen && curMode.settings.fstype == FULLSCREEN_TYPE_NORMAL) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1"); else -#endif SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); curMode.settings.sRGB = newsettings.sRGB; @@ -385,9 +382,9 @@ void Window::updateSettings(const WindowSettings &newsettings) void Window::getWindow(int &width, int &height, WindowSettings &settings) { - // Window position may be different from creation - update display index. + // The window might have been modified (moved, resized, etc.) by the user. if (window) - curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0); + updateSettings(curMode.settings); width = curMode.width; height = curMode.height; From 07aba4c14727127af63c95c78d927a6fe9076974 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Mar 2014 00:52:16 -0400 Subject: [PATCH 54/56] Added some missing obscure key constants --- src/modules/event/sdl/Event.cpp | 10 ++++++++++ src/modules/keyboard/Keyboard.cpp | 10 ++++++++++ src/modules/keyboard/Keyboard.h | 10 ++++++++++ src/modules/keyboard/sdl/Keyboard.cpp | 10 ++++++++++ 4 files changed, 40 insertions(+) diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index c6ecdc6f7..b2e8288e4 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -644,6 +644,16 @@ std::map Event::createKeyMap() k[SDLK_AUDIOPLAY] = Keyboard::KEY_AUDIOPLAY; k[SDLK_AUDIOMUTE] = Keyboard::KEY_AUDIOMUTE; k[SDLK_MEDIASELECT] = Keyboard::KEY_MEDIASELECT; + k[SDLK_WWW] = Keyboard::KEY_WWW; + k[SDLK_MAIL] = Keyboard::KEY_MAIL; + k[SDLK_CALCULATOR] = Keyboard::KEY_CALCULATOR; + k[SDLK_COMPUTER] = Keyboard::KEY_COMPUTER; + k[SDLK_AC_SEARCH] = Keyboard::KEY_APP_SEARCH; + k[SDLK_AC_HOME] = Keyboard::KEY_APP_HOME; + k[SDLK_AC_BACK] = Keyboard::KEY_APP_BACK; + k[SDLK_AC_FORWARD] = Keyboard::KEY_APP_FORWARD; + k[SDLK_AC_REFRESH] = Keyboard::KEY_APP_REFRESH; + k[SDLK_AC_BOOKMARKS] = Keyboard::KEY_APP_BOOKMARKS; k[SDLK_BRIGHTNESSDOWN] = Keyboard::KEY_BRIGHTNESSDOWN; k[SDLK_BRIGHTNESSUP] = Keyboard::KEY_BRIGHTNESSUP; diff --git a/src/modules/keyboard/Keyboard.cpp b/src/modules/keyboard/Keyboard.cpp index 6270c108f..10622b097 100644 --- a/src/modules/keyboard/Keyboard.cpp +++ b/src/modules/keyboard/Keyboard.cpp @@ -220,6 +220,16 @@ StringMap::Entry Keyboard::keyEntries[] = {"audioplay", Keyboard::KEY_AUDIOPLAY}, {"audiomute", Keyboard::KEY_AUDIOMUTE}, {"mediaselect", Keyboard::KEY_MEDIASELECT}, + {"www", Keyboard::KEY_WWW}, + {"mail", Keyboard::KEY_MAIL}, + {"calculator", Keyboard::KEY_CALCULATOR}, + {"computer", Keyboard::KEY_COMPUTER}, + {"appsearch", Keyboard::KEY_APP_SEARCH}, + {"apphome", Keyboard::KEY_APP_HOME}, + {"appback", Keyboard::KEY_APP_BACK}, + {"appforward", Keyboard::KEY_APP_FORWARD}, + {"apprefresh", Keyboard::KEY_APP_REFRESH}, + {"appbookmarks", Keyboard::KEY_APP_BOOKMARKS}, {"brightnessdown", Keyboard::KEY_BRIGHTNESSDOWN}, {"brightnessup", Keyboard::KEY_BRIGHTNESSUP}, diff --git a/src/modules/keyboard/Keyboard.h b/src/modules/keyboard/Keyboard.h index 5e2e325a0..f53071197 100644 --- a/src/modules/keyboard/Keyboard.h +++ b/src/modules/keyboard/Keyboard.h @@ -220,6 +220,16 @@ public: KEY_AUDIOPLAY, KEY_AUDIOMUTE, KEY_MEDIASELECT, + KEY_WWW, + KEY_MAIL, + KEY_CALCULATOR, + KEY_COMPUTER, + KEY_APP_SEARCH, + KEY_APP_HOME, + KEY_APP_BACK, + KEY_APP_FORWARD, + KEY_APP_REFRESH, + KEY_APP_BOOKMARKS, KEY_BRIGHTNESSDOWN, KEY_BRIGHTNESSUP, diff --git a/src/modules/keyboard/sdl/Keyboard.cpp b/src/modules/keyboard/sdl/Keyboard.cpp index 4c70ea94a..3c9bd6468 100644 --- a/src/modules/keyboard/sdl/Keyboard.cpp +++ b/src/modules/keyboard/sdl/Keyboard.cpp @@ -264,6 +264,16 @@ std::map Keyboard::createKeyMap() k[Keyboard::KEY_AUDIOPLAY] = SDLK_AUDIOPLAY; k[Keyboard::KEY_AUDIOMUTE] = SDLK_AUDIOMUTE; k[Keyboard::KEY_MEDIASELECT] = SDLK_MEDIASELECT; + k[Keyboard::KEY_WWW] = SDLK_WWW; + k[Keyboard::KEY_MAIL] = SDLK_MAIL; + k[Keyboard::KEY_CALCULATOR] = SDLK_CALCULATOR; + k[Keyboard::KEY_COMPUTER] = SDLK_COMPUTER; + k[Keyboard::KEY_APP_SEARCH] = SDLK_AC_SEARCH; + k[Keyboard::KEY_APP_HOME] = SDLK_AC_HOME; + k[Keyboard::KEY_APP_BACK] = SDLK_AC_BACK; + k[Keyboard::KEY_APP_FORWARD] = SDLK_AC_FORWARD; + k[Keyboard::KEY_APP_REFRESH] = SDLK_AC_REFRESH; + k[Keyboard::KEY_APP_BOOKMARKS] = SDLK_AC_BOOKMARKS; k[Keyboard::KEY_BRIGHTNESSDOWN] = SDLK_BRIGHTNESSDOWN; k[Keyboard::KEY_BRIGHTNESSUP] = SDLK_BRIGHTNESSUP; From b9fd3f355465cf990c5168ad9fa0f81c98073cbc Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 4 Mar 2014 01:09:48 -0400 Subject: [PATCH 55/56] Missed one --- src/modules/event/sdl/Event.cpp | 1 + src/modules/keyboard/Keyboard.cpp | 1 + src/modules/keyboard/Keyboard.h | 1 + src/modules/keyboard/sdl/Keyboard.cpp | 1 + 4 files changed, 4 insertions(+) diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index b2e8288e4..425da01fa 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -652,6 +652,7 @@ std::map Event::createKeyMap() k[SDLK_AC_HOME] = Keyboard::KEY_APP_HOME; k[SDLK_AC_BACK] = Keyboard::KEY_APP_BACK; k[SDLK_AC_FORWARD] = Keyboard::KEY_APP_FORWARD; + k[SDLK_AC_STOP] = Keyboard::KEY_APP_STOP; k[SDLK_AC_REFRESH] = Keyboard::KEY_APP_REFRESH; k[SDLK_AC_BOOKMARKS] = Keyboard::KEY_APP_BOOKMARKS; diff --git a/src/modules/keyboard/Keyboard.cpp b/src/modules/keyboard/Keyboard.cpp index 10622b097..16e93005f 100644 --- a/src/modules/keyboard/Keyboard.cpp +++ b/src/modules/keyboard/Keyboard.cpp @@ -228,6 +228,7 @@ StringMap::Entry Keyboard::keyEntries[] = {"apphome", Keyboard::KEY_APP_HOME}, {"appback", Keyboard::KEY_APP_BACK}, {"appforward", Keyboard::KEY_APP_FORWARD}, + {"appstop", Keyboard::KEY_APP_STOP}, {"apprefresh", Keyboard::KEY_APP_REFRESH}, {"appbookmarks", Keyboard::KEY_APP_BOOKMARKS}, diff --git a/src/modules/keyboard/Keyboard.h b/src/modules/keyboard/Keyboard.h index f53071197..1b7c80bd1 100644 --- a/src/modules/keyboard/Keyboard.h +++ b/src/modules/keyboard/Keyboard.h @@ -228,6 +228,7 @@ public: KEY_APP_HOME, KEY_APP_BACK, KEY_APP_FORWARD, + KEY_APP_STOP, KEY_APP_REFRESH, KEY_APP_BOOKMARKS, diff --git a/src/modules/keyboard/sdl/Keyboard.cpp b/src/modules/keyboard/sdl/Keyboard.cpp index 3c9bd6468..488632d6a 100644 --- a/src/modules/keyboard/sdl/Keyboard.cpp +++ b/src/modules/keyboard/sdl/Keyboard.cpp @@ -272,6 +272,7 @@ std::map Keyboard::createKeyMap() k[Keyboard::KEY_APP_HOME] = SDLK_AC_HOME; k[Keyboard::KEY_APP_BACK] = SDLK_AC_BACK; k[Keyboard::KEY_APP_FORWARD] = SDLK_AC_FORWARD; + k[Keyboard::KEY_APP_STOP] = SDLK_AC_STOP; k[Keyboard::KEY_APP_REFRESH] = SDLK_AC_REFRESH; k[Keyboard::KEY_APP_BOOKMARKS] = SDLK_AC_BOOKMARKS; From 314a528996420c7a058d3fa618b1a9fa71ad26bd Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 10 Mar 2014 21:36:14 -0300 Subject: [PATCH 56/56] Fixed loading BC4 compressed textures --- .../love-framework.xcodeproj/project.pbxproj | 2 +- .../macosx/love.xcodeproj/project.pbxproj | 2 +- src/libraries/ddsparse/ddsparse.cpp | 31 ++++++++++--------- src/libraries/enet/enet.cpp | 4 --- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/platform/macosx/love-framework.xcodeproj/project.pbxproj b/platform/macosx/love-framework.xcodeproj/project.pbxproj index 839b1a9ce..84e5457de 100644 --- a/platform/macosx/love-framework.xcodeproj/project.pbxproj +++ b/platform/macosx/love-framework.xcodeproj/project.pbxproj @@ -2048,7 +2048,7 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0510; }; buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "love-framework" */; compatibilityVersion = "Xcode 3.2"; diff --git a/platform/macosx/love.xcodeproj/project.pbxproj b/platform/macosx/love.xcodeproj/project.pbxproj index e6081aeff..ab34a46bf 100644 --- a/platform/macosx/love.xcodeproj/project.pbxproj +++ b/platform/macosx/love.xcodeproj/project.pbxproj @@ -198,7 +198,7 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0510; }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "love" */; compatibilityVersion = "Xcode 3.2"; diff --git a/src/libraries/ddsparse/ddsparse.cpp b/src/libraries/ddsparse/ddsparse.cpp index 590d665ce..f6fe62bcc 100644 --- a/src/libraries/ddsparse/ddsparse.cpp +++ b/src/libraries/ddsparse/ddsparse.cpp @@ -237,36 +237,37 @@ size_t Parser::getMipmapCount() const size_t Parser::parseImageSize(Format fmt, int width, int height) const { - size_t size = 0; + size_t numBlocksWide = 0; + size_t numBlocksHigh = 0; + size_t numBytesPerBlock = 0; switch (fmt) { case FORMAT_DXT1: + case FORMAT_BC4: + case FORMAT_BC4s: + numBytesPerBlock = 8; + break; case FORMAT_DXT3: case FORMAT_DXT5: case FORMAT_BC5s: case FORMAT_BC5: + case FORMAT_BC6H: case FORMAT_BC7: case FORMAT_BC7srgb: - { - int numBlocksWide = 0; - if (width > 0) - numBlocksWide = std::max(1, (width + 3) / 4); - - int numBlocksHigh = 0; - if (height > 0) - numBlocksHigh = std::max(1, (height + 3) / 4); - - int numBytesPerBlock = (fmt == FORMAT_DXT1 ? 8 : 16); - - size = numBlocksWide * numBytesPerBlock * numBlocksHigh; - } + numBytesPerBlock = 16; break; default: break; } - return size; + if (width > 0) + numBlocksWide = std::max(1, (width + 3) / 4); + + if (height > 0) + numBlocksHigh = std::max(1, (height + 3) / 4); + + return numBlocksWide * numBytesPerBlock * numBlocksHigh; } bool Parser::parseTexData(const uint8_t *data, size_t dataSize, Format fmt, int w, int h, int mips) diff --git a/src/libraries/enet/enet.cpp b/src/libraries/enet/enet.cpp index 836c166c6..34e215c78 100644 --- a/src/libraries/enet/enet.cpp +++ b/src/libraries/enet/enet.cpp @@ -716,10 +716,6 @@ static const struct luaL_Reg enet_peer_funcs [] = { {NULL, NULL} }; -static const struct luaL_Reg enet_event_funcs [] = { - {NULL, NULL} -}; - int luaopen_enet(lua_State *l) { enet_initialize(); atexit(enet_deinitialize);