mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
Merge in default, update changelog
--HG-- branch : minor
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -158,7 +158,8 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
|
||||
{
|
||||
{ "canvas", Graphics::SUPPORT_CANVAS },
|
||||
{ "hdrcanvas", Graphics::SUPPORT_HDR_CANVAS },
|
||||
{ "pixeleffect", Graphics::SUPPORT_PIXELEFFECT },
|
||||
{ "shader", Graphics::SUPPORT_SHADER },
|
||||
{ "pixeleffect", Graphics::SUPPORT_SHADER }, // for compatibility
|
||||
{ "npot", Graphics::SUPPORT_NPOT },
|
||||
{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },
|
||||
{ "mipmap", Graphics::SUPPORT_MIPMAP },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
{
|
||||
SUPPORT_CANVAS = 1,
|
||||
SUPPORT_HDR_CANVAS,
|
||||
SUPPORT_PIXELEFFECT,
|
||||
SUPPORT_SHADER,
|
||||
SUPPORT_NPOT,
|
||||
SUPPORT_SUBTRACTIVE,
|
||||
SUPPORT_MIPMAP,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -458,6 +458,18 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image)
|
||||
return img;
|
||||
}
|
||||
|
||||
void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y)
|
||||
{
|
||||
strategy->bindFBO( fbo );
|
||||
|
||||
glReadPixels(x, height - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_rgba);
|
||||
|
||||
if (current)
|
||||
strategy->bindFBO( current->fbo );
|
||||
else
|
||||
strategy->bindFBO( 0 );
|
||||
}
|
||||
|
||||
void Canvas::setFilter(const Image::Filter &f)
|
||||
{
|
||||
bindTexture(img);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "common/math.h"
|
||||
#include "common/Matrix.h"
|
||||
#include "OpenGL.h"
|
||||
#include "GLee.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -65,6 +64,8 @@ public:
|
||||
|
||||
love::image::ImageData *getImageData(love::image::Image *image);
|
||||
|
||||
void getPixel(unsigned char* pixel_rgba, int x, int y);
|
||||
|
||||
void setFilter(const Image::Filter &f);
|
||||
Image::Filter getFilter() const;
|
||||
|
||||
@@ -96,7 +97,7 @@ public:
|
||||
static void bindDefaultCanvas();
|
||||
|
||||
private:
|
||||
friend class PixelEffect;
|
||||
friend class Shader;
|
||||
GLuint getTextureName() const
|
||||
{
|
||||
return img;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -48,12 +48,7 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
|
||||
, lineHeight(1)
|
||||
, mSpacing(1)
|
||||
, filter(filter)
|
||||
, mipmapsharpness(0.0f)
|
||||
{
|
||||
love::font::GlyphData *gd = r->getGlyphData(32);
|
||||
type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE);
|
||||
delete gd;
|
||||
|
||||
// try to find the best texture size match for the font size
|
||||
// default to the largest texture size if no rough match is found
|
||||
texture_size_index = NUM_TEXTURE_SIZES - 1;
|
||||
@@ -71,9 +66,23 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
|
||||
texture_width = TEXTURE_WIDTHS[texture_size_index];
|
||||
texture_height = TEXTURE_HEIGHTS[texture_size_index];
|
||||
|
||||
loadVolatile();
|
||||
love::font::GlyphData *gd = 0;
|
||||
|
||||
r->retain();
|
||||
try
|
||||
{
|
||||
gd = r->getGlyphData(32);
|
||||
loadVolatile();
|
||||
}
|
||||
catch (love::Exception &)
|
||||
{
|
||||
delete gd;
|
||||
throw;
|
||||
}
|
||||
|
||||
type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA) ? FONT_TRUETYPE : FONT_IMAGE;
|
||||
delete gd;
|
||||
|
||||
rasterizer->retain();
|
||||
}
|
||||
|
||||
Font::~Font()
|
||||
@@ -115,8 +124,8 @@ void Font::createTexture()
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLint format = (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA);
|
||||
|
||||
@@ -157,10 +166,9 @@ void Font::createTexture()
|
||||
&emptyData[0]);
|
||||
|
||||
setFilter(filter);
|
||||
setMipmapSharpness(mipmapsharpness);
|
||||
}
|
||||
|
||||
Font::Glyph *Font::addGlyph(const int glyph)
|
||||
Font::Glyph *Font::addGlyph(unsigned int glyph)
|
||||
{
|
||||
love::font::GlyphData *gd = rasterizer->getGlyphData(glyph);
|
||||
int w = gd->getWidth();
|
||||
@@ -233,7 +241,7 @@ Font::Glyph *Font::addGlyph(const int glyph)
|
||||
return g;
|
||||
}
|
||||
|
||||
Font::Glyph *Font::findGlyph(const int glyph)
|
||||
Font::Glyph *Font::findGlyph(unsigned int glyph)
|
||||
{
|
||||
Glyph *g = glyphs[glyph];
|
||||
if (!g)
|
||||
@@ -273,7 +281,7 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
int g = *i++;
|
||||
unsigned int g = *i++;
|
||||
|
||||
if (g == '\n')
|
||||
{
|
||||
@@ -380,7 +388,7 @@ int Font::getWidth(const std::string &str)
|
||||
utf8::iterator<std::string::const_iterator> end(line.end(), line.begin(), line.end());
|
||||
while (i != end)
|
||||
{
|
||||
int c = *i++;
|
||||
unsigned int c = *i++;
|
||||
g = findGlyph(c);
|
||||
width += static_cast<int>(g->spacing * mSpacing);
|
||||
}
|
||||
@@ -402,7 +410,7 @@ int Font::getWidth(const char *str)
|
||||
return this->getWidth(std::string(str));
|
||||
}
|
||||
|
||||
int Font::getWidth(const char character)
|
||||
int Font::getWidth(unsigned int character)
|
||||
{
|
||||
Glyph *g = findGlyph(character);
|
||||
return g->spacing;
|
||||
@@ -488,41 +496,6 @@ float Font::getSpacing() const
|
||||
return mSpacing;
|
||||
}
|
||||
|
||||
void Font::checkMipmapsCreated() const
|
||||
{
|
||||
if (filter.mipmap != Image::FILTER_NEAREST && filter.mipmap != Image::FILTER_LINEAR)
|
||||
return;
|
||||
|
||||
if (!Image::hasMipmapSupport())
|
||||
throw love::Exception("Mipmap filtering is not supported on this system!");
|
||||
|
||||
GLboolean mipmapscreated;
|
||||
glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&mipmapscreated);
|
||||
|
||||
// generate mipmaps for this image if we haven't already
|
||||
if (!mipmapscreated)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||
|
||||
if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
else if (GLEE_EXT_framebuffer_object)
|
||||
glGenerateMipmapEXT(GL_TEXTURE_2D);
|
||||
else
|
||||
{
|
||||
// modify single texel to trigger mipmap chain generation
|
||||
std::vector<GLubyte> emptydata(type == FONT_TRUETYPE ? 2 : 4);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
0, 0,
|
||||
1, 1,
|
||||
type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
&emptydata[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Font::setFilter(const Image::Filter &f)
|
||||
{
|
||||
filter = f;
|
||||
@@ -531,7 +504,6 @@ void Font::setFilter(const Image::Filter &f)
|
||||
for (it = textures.begin(); it != textures.end(); ++it)
|
||||
{
|
||||
bindTexture(*it);
|
||||
checkMipmapsCreated();
|
||||
setTextureFilter(f);
|
||||
}
|
||||
}
|
||||
@@ -541,32 +513,8 @@ const Image::Filter &Font::getFilter()
|
||||
return filter;
|
||||
}
|
||||
|
||||
void Font::setMipmapSharpness(float sharpness)
|
||||
{
|
||||
if (!Image::hasMipmapSharpnessSupport())
|
||||
return;
|
||||
|
||||
// LOD bias has the range (-maxbias, maxbias)
|
||||
mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f);
|
||||
|
||||
std::vector<GLuint>::const_iterator it;
|
||||
for (it = textures.begin(); it != textures.end(); ++it)
|
||||
{
|
||||
bindTexture(*it);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper
|
||||
}
|
||||
}
|
||||
|
||||
float Font::getMipmapSharpness() const
|
||||
{
|
||||
return mipmapsharpness;
|
||||
}
|
||||
|
||||
bool Font::loadVolatile()
|
||||
{
|
||||
if (Image::hasMipmapSharpnessSupport())
|
||||
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness);
|
||||
|
||||
createTexture();
|
||||
return true;
|
||||
}
|
||||
@@ -574,7 +522,7 @@ bool Font::loadVolatile()
|
||||
void Font::unloadVolatile()
|
||||
{
|
||||
// nuke everything from orbit
|
||||
std::map<int, Glyph *>::iterator it = glyphs.begin();
|
||||
std::map<unsigned int, Glyph *>::iterator it = glyphs.begin();
|
||||
Glyph *g;
|
||||
while (it != glyphs.end())
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -78,17 +78,17 @@ public:
|
||||
/**
|
||||
* Returns the width of the passed string.
|
||||
*
|
||||
* @param line A line of text.
|
||||
* @param str A string of text.
|
||||
**/
|
||||
int getWidth(const std::string &line);
|
||||
int getWidth(const char *line);
|
||||
int getWidth(const std::string &str);
|
||||
int getWidth(const char *str);
|
||||
|
||||
/**
|
||||
* Returns the width of the passed character.
|
||||
*
|
||||
* @param character A character.
|
||||
**/
|
||||
int getWidth(const char character);
|
||||
int getWidth(unsigned int character);
|
||||
|
||||
/**
|
||||
* Returns the maximal width of a wrapped string
|
||||
@@ -129,9 +129,6 @@ public:
|
||||
void setFilter(const Image::Filter &f);
|
||||
const Image::Filter &getFilter();
|
||||
|
||||
void setMipmapSharpness(float sharpness);
|
||||
float getMipmapSharpness() const;
|
||||
|
||||
// Implements Volatile.
|
||||
bool loadVolatile();
|
||||
void unloadVolatile();
|
||||
@@ -191,7 +188,7 @@ private:
|
||||
int texture_height;
|
||||
|
||||
std::vector<GLuint> textures; // vector of packed textures
|
||||
std::map<int, Glyph *> glyphs; // maps glyphs to quad information
|
||||
std::map<unsigned int, Glyph *> glyphs; // maps glyphs to quad information
|
||||
FontType type;
|
||||
Image::Filter filter;
|
||||
|
||||
@@ -204,18 +201,10 @@ private:
|
||||
int texture_x, texture_y;
|
||||
int rowHeight;
|
||||
|
||||
// Mipmap texture LOD bias value
|
||||
float mipmapsharpness;
|
||||
|
||||
// Implementation-dependent maximum/minimum mipmap sharpness values
|
||||
float maxmipmapsharpness;
|
||||
|
||||
void checkMipmapsCreated() const;
|
||||
|
||||
bool initializeTexture(GLint format);
|
||||
void createTexture();
|
||||
Glyph *addGlyph(const int glyph);
|
||||
Glyph *findGlyph (const int glyph);
|
||||
Glyph *addGlyph(unsigned int glyph);
|
||||
Glyph *findGlyph(unsigned int glyph);
|
||||
}; // Font
|
||||
|
||||
} // opengl
|
||||
|
||||
+23090
-12981
File diff suppressed because it is too large
Load Diff
+22267
-12454
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -47,8 +47,6 @@ Graphics::Graphics()
|
||||
, userMatrices(0)
|
||||
{
|
||||
currentWindow = love::window::sdl::Window::getSingleton();
|
||||
|
||||
resetBoundTexture();
|
||||
}
|
||||
|
||||
Graphics::~Graphics()
|
||||
@@ -64,7 +62,7 @@ const char *Graphics::getName() const
|
||||
return "love.graphics.opengl";
|
||||
}
|
||||
|
||||
bool Graphics::checkMode(int width, int height, bool fullscreen)
|
||||
bool Graphics::checkMode(int width, int height, bool fullscreen) const
|
||||
{
|
||||
return currentWindow->checkWindowSize(width, height, fullscreen);
|
||||
}
|
||||
@@ -119,13 +117,19 @@ bool Graphics::setMode(int width, int height, WindowFlags *flags)
|
||||
// the display mode change.
|
||||
Volatile::unloadAll();
|
||||
|
||||
bool success = currentWindow->setWindow(width, height, flags);
|
||||
// Regardless of failure, we'll have to set up OpenGL once again.
|
||||
uninitializeContext();
|
||||
|
||||
bool success = currentWindow->setWindow(width, height, flags);
|
||||
|
||||
// Regardless of failure, we'll have to set up OpenGL once again.
|
||||
width = currentWindow->getWidth();
|
||||
height = currentWindow->getHeight();
|
||||
|
||||
// Okay, setup OpenGL.
|
||||
initializeContext();
|
||||
|
||||
// Make sure antialiasing works when set elsewhere
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
// Enable blending
|
||||
glEnable(GL_BLEND);
|
||||
@@ -138,8 +142,13 @@ bool Graphics::setMode(int width, int height, WindowFlags *flags)
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
|
||||
|
||||
// Auto-generated mipmaps should be the best quality possible
|
||||
if (GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap)
|
||||
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
||||
|
||||
// Enable textures
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
setActiveTextureUnit(0);
|
||||
|
||||
// Set the viewport to top-left corner
|
||||
glViewport(0, 0, width, height);
|
||||
@@ -173,7 +182,7 @@ bool Graphics::setMode(int width, int height, WindowFlags *flags)
|
||||
return success;
|
||||
}
|
||||
|
||||
void Graphics::getMode(int &width, int &height, WindowFlags &flags)
|
||||
void Graphics::getMode(int &width, int &height, WindowFlags &flags) const
|
||||
{
|
||||
currentWindow->getWindow(width, height, flags);
|
||||
}
|
||||
@@ -193,7 +202,7 @@ void Graphics::reset()
|
||||
DisplayState s;
|
||||
discardStencil();
|
||||
Canvas::bindDefaultCanvas();
|
||||
PixelEffect::detach();
|
||||
Shader::detach();
|
||||
restoreState(s);
|
||||
}
|
||||
|
||||
@@ -219,36 +228,36 @@ void Graphics::setCaption(const char *caption)
|
||||
currentWindow->setWindowTitle(title);
|
||||
}
|
||||
|
||||
int Graphics::getCaption(lua_State *L)
|
||||
int Graphics::getCaption(lua_State *L) const
|
||||
{
|
||||
std::string title = currentWindow->getWindowTitle();
|
||||
lua_pushstring(L, title.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Graphics::getWidth()
|
||||
int Graphics::getWidth() const
|
||||
{
|
||||
return currentWindow->getWidth();
|
||||
}
|
||||
|
||||
int Graphics::getHeight()
|
||||
int Graphics::getHeight() const
|
||||
{
|
||||
return currentWindow->getHeight();
|
||||
}
|
||||
|
||||
int Graphics::getRenderHeight()
|
||||
int Graphics::getRenderHeight() const
|
||||
{
|
||||
if (Canvas::current)
|
||||
return Canvas::current->getHeight();
|
||||
return getHeight();
|
||||
}
|
||||
|
||||
bool Graphics::isCreated()
|
||||
bool Graphics::isCreated() const
|
||||
{
|
||||
return currentWindow->isCreated();
|
||||
}
|
||||
|
||||
int Graphics::getModes(lua_State *L)
|
||||
int Graphics::getModes(lua_State *L) const
|
||||
{
|
||||
int n;
|
||||
love::window::Window::WindowSize **modes = currentWindow->getFullscreenSizes(n);
|
||||
@@ -295,7 +304,7 @@ void Graphics::setScissor()
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
int Graphics::getScissor(lua_State *L)
|
||||
int Graphics::getScissor(lua_State *L) const
|
||||
{
|
||||
if (glIsEnabled(GL_SCISSOR_TEST) == GL_FALSE)
|
||||
return 0;
|
||||
@@ -368,31 +377,12 @@ Quad *Graphics::newQuad(float x, float y, float w, float h, float sw, float sh)
|
||||
|
||||
Font *Graphics::newFont(love::font::Rasterizer *r, const Image::Filter &filter)
|
||||
{
|
||||
Font *font = new Font(r, filter);
|
||||
|
||||
// Load it and check for errors.
|
||||
if (!font)
|
||||
{
|
||||
delete font;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return font;
|
||||
return new Font(r, filter);
|
||||
}
|
||||
|
||||
SpriteBatch *Graphics::newSpriteBatch(Image *image, int size, int usage)
|
||||
{
|
||||
SpriteBatch *t = NULL;
|
||||
try
|
||||
{
|
||||
t = new SpriteBatch(image, size, usage);
|
||||
}
|
||||
catch(love::Exception &e)
|
||||
{
|
||||
if (t) delete t;
|
||||
throw e;
|
||||
}
|
||||
return t;
|
||||
return new SpriteBatch(image, size, usage);
|
||||
}
|
||||
|
||||
ParticleSystem *Graphics::newParticleSystem(Image *image, int size)
|
||||
@@ -453,20 +443,9 @@ Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_t
|
||||
return NULL; // never reached
|
||||
}
|
||||
|
||||
PixelEffect *Graphics::newPixelEffect(const std::string &code)
|
||||
Shader *Graphics::newShader(const Shader::ShaderSources &sources)
|
||||
{
|
||||
PixelEffect *effect = NULL;
|
||||
try
|
||||
{
|
||||
effect = new PixelEffect(code);
|
||||
}
|
||||
catch(love::Exception &e)
|
||||
{
|
||||
if (effect)
|
||||
delete effect;
|
||||
throw(e);
|
||||
}
|
||||
return effect;
|
||||
return new Shader(sources);
|
||||
}
|
||||
|
||||
void Graphics::setColor(const Color &c)
|
||||
@@ -474,7 +453,7 @@ void Graphics::setColor(const Color &c)
|
||||
glColor4ubv(&c.r);
|
||||
}
|
||||
|
||||
Color Graphics::getColor()
|
||||
Color Graphics::getColor() const
|
||||
{
|
||||
float c[4];
|
||||
glGetFloatv(GL_CURRENT_COLOR, c);
|
||||
@@ -493,7 +472,7 @@ void Graphics::setBackgroundColor(const Color &c)
|
||||
glClearColor((float)c.r/255.0f, (float)c.g/255.0f, (float)c.b/255.0f, (float)c.a/255.0f);
|
||||
}
|
||||
|
||||
Color Graphics::getBackgroundColor()
|
||||
Color Graphics::getBackgroundColor() const
|
||||
{
|
||||
float c[4];
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, c);
|
||||
@@ -518,44 +497,83 @@ void Graphics::setFont(Font *font)
|
||||
currentFont->retain();
|
||||
}
|
||||
|
||||
Font *Graphics::getFont()
|
||||
Font *Graphics::getFont() const
|
||||
{
|
||||
return currentFont;
|
||||
}
|
||||
|
||||
void Graphics::setBlendMode(Graphics::BlendMode mode)
|
||||
{
|
||||
if (GLEE_VERSION_1_4 || GLEE_ARB_imaging)
|
||||
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;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
if (mode == BLEND_SUBTRACTIVE)
|
||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||
case BLEND_ALPHA:
|
||||
if (gl_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;
|
||||
}
|
||||
else
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
{
|
||||
// Fallback for OpenGL implementations without support for separate blend functions.
|
||||
// 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;
|
||||
}
|
||||
break;
|
||||
case BLEND_MULTIPLICATIVE:
|
||||
src_rgb = src_a = GL_DST_COLOR;
|
||||
dst_rgb = dst_a = GL_ZERO;
|
||||
break;
|
||||
case BLEND_PREMULTIPLIED:
|
||||
src_rgb = src_a = GL_ONE;
|
||||
dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
case BLEND_SUBTRACTIVE:
|
||||
func = GL_FUNC_REVERSE_SUBTRACT;
|
||||
case BLEND_ADDITIVE:
|
||||
src_rgb = src_a = GL_SRC_ALPHA;
|
||||
dst_rgb = dst_a = GL_ONE;
|
||||
break;
|
||||
case BLEND_NONE:
|
||||
default:
|
||||
src_rgb = src_a = GL_ONE;
|
||||
dst_rgb = dst_a = GL_ZERO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gl_1_4 || GLEE_ARB_imaging)
|
||||
glBlendEquation(func);
|
||||
else if (GLEE_EXT_blend_minmax && GLEE_EXT_blend_subtract)
|
||||
{
|
||||
if (mode == BLEND_SUBTRACTIVE)
|
||||
glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
|
||||
else
|
||||
glBlendEquationEXT(GL_FUNC_ADD_EXT);
|
||||
}
|
||||
glBlendEquationEXT(func);
|
||||
else
|
||||
{
|
||||
if (mode == BLEND_SUBTRACTIVE)
|
||||
throw Exception("This graphics card does not support the subtract blend mode!");
|
||||
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 (mode == BLEND_ALPHA)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else if (mode == BLEND_MULTIPLICATIVE)
|
||||
glBlendFunc(GL_DST_COLOR, GL_ZERO);
|
||||
else if (mode == BLEND_PREMULTIPLIED)
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else if (mode == BLEND_NONE)
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
else // mode == BLEND_ADDITIVE || mode == BLEND_SUBTRACTIVE
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::setColorMode(Graphics::ColorMode mode)
|
||||
@@ -572,30 +590,55 @@ void Graphics::setColorMode(Graphics::ColorMode mode)
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
}
|
||||
|
||||
Graphics::BlendMode Graphics::getBlendMode()
|
||||
Graphics::BlendMode Graphics::getBlendMode() const
|
||||
{
|
||||
GLint dst, src, equation;
|
||||
glGetIntegerv(GL_BLEND_DST, &dst);
|
||||
glGetIntegerv(GL_BLEND_SRC, &src);
|
||||
glGetIntegerv(GL_BLEND_EQUATION, &equation);
|
||||
const int gl_1_4 = GLEE_VERSION_1_4;
|
||||
|
||||
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
|
||||
return BLEND_SUBTRACTIVE;
|
||||
else if (src == GL_SRC_ALPHA && dst == GL_ONE) // && equation == GL_FUNC_ADD
|
||||
return BLEND_ADDITIVE;
|
||||
else if (src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) // && equation == GL_FUNC_ADD
|
||||
// Everything else has equation == GL_FUNC_ADD.
|
||||
else if (src_rgb == src_a && dst_rgb == dst_a)
|
||||
{
|
||||
if (src_rgb == GL_SRC_ALPHA && dst_rgb == GL_ONE)
|
||||
return BLEND_ADDITIVE;
|
||||
else if (src_rgb == GL_SRC_ALPHA && dst_rgb == 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)
|
||||
return BLEND_MULTIPLICATIVE;
|
||||
else if (src_rgb == GL_ONE && dst_rgb == GL_ONE_MINUS_SRC_ALPHA)
|
||||
return BLEND_PREMULTIPLIED;
|
||||
else if (src_rgb == GL_ONE && dst_rgb == GL_ZERO)
|
||||
return BLEND_NONE;
|
||||
}
|
||||
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)
|
||||
return BLEND_ALPHA;
|
||||
else if (src == GL_DST_COLOR && dst == GL_ZERO) // && equation == GL_FUNC_ADD
|
||||
return BLEND_MULTIPLICATIVE;
|
||||
else if (src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) // && equation == GL_FUNC_ADD
|
||||
return BLEND_PREMULTIPLIED;
|
||||
else if (src == GL_ONE && dst == GL_ZERO)
|
||||
return BLEND_NONE;
|
||||
|
||||
return BLEND_MAX_ENUM; // Should never be reached.
|
||||
throw Exception("Unknown blend mode");
|
||||
}
|
||||
|
||||
Graphics::ColorMode Graphics::getColorMode()
|
||||
Graphics::ColorMode Graphics::getColorMode() const
|
||||
{
|
||||
GLint mode;
|
||||
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &mode);
|
||||
@@ -637,12 +680,12 @@ void Graphics::setLine(float width, Graphics::LineStyle style)
|
||||
setLineStyle(style);
|
||||
}
|
||||
|
||||
float Graphics::getLineWidth()
|
||||
float Graphics::getLineWidth() const
|
||||
{
|
||||
return lineWidth;
|
||||
}
|
||||
|
||||
Graphics::LineStyle Graphics::getLineStyle()
|
||||
Graphics::LineStyle Graphics::getLineStyle() const
|
||||
{
|
||||
return lineStyle;
|
||||
}
|
||||
@@ -670,14 +713,14 @@ void Graphics::setPoint(float size, Graphics::PointStyle style)
|
||||
glPointSize((GLfloat)size);
|
||||
}
|
||||
|
||||
float Graphics::getPointSize()
|
||||
float Graphics::getPointSize() const
|
||||
{
|
||||
GLfloat size;
|
||||
glGetFloatv(GL_POINT_SIZE, &size);
|
||||
return (float)size;
|
||||
}
|
||||
|
||||
Graphics::PointStyle Graphics::getPointStyle()
|
||||
Graphics::PointStyle Graphics::getPointStyle() const
|
||||
{
|
||||
if (glIsEnabled(GL_POINT_SMOOTH) == GL_TRUE)
|
||||
return POINT_SMOOTH;
|
||||
@@ -685,7 +728,7 @@ Graphics::PointStyle Graphics::getPointStyle()
|
||||
return POINT_ROUGH;
|
||||
}
|
||||
|
||||
int Graphics::getMaxPointSize()
|
||||
int Graphics::getMaxPointSize() const
|
||||
{
|
||||
GLint max;
|
||||
glGetIntegerv(GL_POINT_SIZE_MAX, &max);
|
||||
@@ -746,11 +789,10 @@ void Graphics::printf(const char *str, float x, float y, float wrap, AlignMode a
|
||||
|
||||
void Graphics::point(float x, float y)
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
bindTexture(0);
|
||||
glBegin(GL_POINTS);
|
||||
glVertex2f(x, y);
|
||||
glEnd();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
// Calculate line boundary points u1 and u2. Sketch:
|
||||
@@ -944,7 +986,7 @@ void Graphics::polyline(const float *coords, size_t count)
|
||||
// end get line vertex boundaries
|
||||
|
||||
// draw the core line
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
bindTexture(0);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *)vertices);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
|
||||
@@ -954,7 +996,6 @@ void Graphics::polyline(const float *coords, size_t count)
|
||||
draw_overdraw(overdraw, count, pixel_size, looping);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
// cleanup
|
||||
delete[] vertices;
|
||||
@@ -1038,12 +1079,11 @@ void Graphics::arc(DrawMode mode, float x, float y, float radius, float angle1,
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
bindTexture(0);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *) coords);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, points + 2);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
delete[] coords;
|
||||
@@ -1062,12 +1102,11 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count)
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
bindTexture(0);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *)coords);
|
||||
glDrawArrays(GL_POLYGON, 0, count/2-1); // opengl will close the polygon for us
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1140,32 +1179,7 @@ void Graphics::shear(float kx, float ky)
|
||||
glMultMatrixf((const GLfloat *)t.getElements());
|
||||
}
|
||||
|
||||
void Graphics::drawTest(Image *image, float x, float y, float a, float sx, float sy, float ox, float oy)
|
||||
{
|
||||
image->bind();
|
||||
|
||||
// Buffer for transforming the image.
|
||||
vertex buf[4];
|
||||
|
||||
Matrix t;
|
||||
t.translate(x, y);
|
||||
t.rotate(a);
|
||||
t.scale(sx, sy);
|
||||
t.translate(ox, oy);
|
||||
t.transform(buf, image->getVertices(), 4);
|
||||
|
||||
const vertex *vertices = image->getVertices();
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&buf[0].x);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&vertices[0].s);
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
bool Graphics::hasFocus()
|
||||
bool Graphics::hasFocus() const
|
||||
{
|
||||
return currentWindow->hasFocus();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <cmath>
|
||||
|
||||
// OpenGL
|
||||
#include "GLee.h"
|
||||
#include "OpenGL.h"
|
||||
|
||||
// LOVE
|
||||
#include "graphics/Graphics.h"
|
||||
@@ -37,14 +37,13 @@
|
||||
|
||||
#include "window/Window.h"
|
||||
|
||||
#include "OpenGL.h"
|
||||
#include "Font.h"
|
||||
#include "Image.h"
|
||||
#include "Quad.h"
|
||||
#include "SpriteBatch.h"
|
||||
#include "ParticleSystem.h"
|
||||
#include "Canvas.h"
|
||||
#include "PixelEffect.h"
|
||||
#include "Shader.h"
|
||||
|
||||
using love::window::WindowFlags;
|
||||
|
||||
@@ -120,7 +119,7 @@ public:
|
||||
* @param width The window width.
|
||||
* @param height The window height.
|
||||
**/
|
||||
bool checkMode(int width, int height, bool fullscreen);
|
||||
bool checkMode(int width, int height, bool fullscreen) const;
|
||||
|
||||
DisplayState saveState();
|
||||
|
||||
@@ -140,7 +139,7 @@ public:
|
||||
* @param height Pointer to an integer for the window height.
|
||||
* @param flags A WindowFlags structure.
|
||||
**/
|
||||
void getMode(int &width, int &height, WindowFlags &flags);
|
||||
void getMode(int &width, int &height, WindowFlags &flags) const;
|
||||
|
||||
/**
|
||||
* Toggles fullscreen. Note that this also needs to reload the
|
||||
@@ -176,22 +175,22 @@ public:
|
||||
**/
|
||||
void setCaption(const char *caption);
|
||||
|
||||
int getCaption(lua_State *L);
|
||||
int getCaption(lua_State *L) const;
|
||||
|
||||
/**
|
||||
* Gets the width of the current display mode.
|
||||
**/
|
||||
int getWidth();
|
||||
int getWidth() const;
|
||||
|
||||
/**
|
||||
* Gets the height of the current display mode.
|
||||
**/
|
||||
int getHeight();
|
||||
int getHeight() const;
|
||||
|
||||
/**
|
||||
* True if some display mode is set.
|
||||
**/
|
||||
bool isCreated();
|
||||
bool isCreated() const;
|
||||
|
||||
/**
|
||||
* This native Lua function gets available modes
|
||||
@@ -206,7 +205,7 @@ public:
|
||||
* Only fullscreen modes are returned here, as all
|
||||
* window sizes are supported (normally).
|
||||
**/
|
||||
int getModes(lua_State *L);
|
||||
int getModes(lua_State *L) const;
|
||||
|
||||
/**
|
||||
* Scissor defines a box such that everything outside that box is discarded and not drawn.
|
||||
@@ -227,7 +226,7 @@ public:
|
||||
* This native Lua function gets the current scissor box in the order of:
|
||||
* x, y, width, height
|
||||
**/
|
||||
int getScissor(lua_State *L);
|
||||
int getScissor(lua_State *L) const;
|
||||
|
||||
/**
|
||||
* Enables the stencil buffer and set stencil function to fill it
|
||||
@@ -269,7 +268,7 @@ public:
|
||||
|
||||
Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL);
|
||||
|
||||
PixelEffect *newPixelEffect(const std::string &code);
|
||||
Shader *newShader(const Shader::ShaderSources &sources);
|
||||
|
||||
/**
|
||||
* Sets the foreground color.
|
||||
@@ -280,7 +279,7 @@ public:
|
||||
/**
|
||||
* Gets current color.
|
||||
**/
|
||||
Color getColor();
|
||||
Color getColor() const;
|
||||
|
||||
/**
|
||||
* Sets the background Color.
|
||||
@@ -290,7 +289,7 @@ public:
|
||||
/**
|
||||
* Gets the current background color.
|
||||
**/
|
||||
Color getBackgroundColor();
|
||||
Color getBackgroundColor() const;
|
||||
|
||||
/**
|
||||
* Sets the current font.
|
||||
@@ -300,7 +299,7 @@ public:
|
||||
/**
|
||||
* Gets the current Font, or nil if none.
|
||||
**/
|
||||
Font *getFont();
|
||||
Font *getFont() const;
|
||||
|
||||
/**
|
||||
* Sets the current blend mode.
|
||||
@@ -320,12 +319,12 @@ public:
|
||||
/**
|
||||
* Gets the current blend mode.
|
||||
**/
|
||||
BlendMode getBlendMode();
|
||||
BlendMode getBlendMode() const;
|
||||
|
||||
/**
|
||||
* Gets the current color mode.
|
||||
**/
|
||||
ColorMode getColorMode();
|
||||
ColorMode getColorMode() const;
|
||||
|
||||
/**
|
||||
* Gets the current image filter.
|
||||
@@ -353,12 +352,12 @@ public:
|
||||
/**
|
||||
* Gets the line width.
|
||||
**/
|
||||
float getLineWidth();
|
||||
float getLineWidth() const;
|
||||
|
||||
/**
|
||||
* Gets the line style.
|
||||
**/
|
||||
LineStyle getLineStyle();
|
||||
LineStyle getLineStyle() const;
|
||||
|
||||
/**
|
||||
* Sets the size of points.
|
||||
@@ -379,18 +378,18 @@ public:
|
||||
/**
|
||||
* Gets the point size.
|
||||
**/
|
||||
float getPointSize();
|
||||
float getPointSize() const;
|
||||
|
||||
/**
|
||||
* Gets the point style.
|
||||
**/
|
||||
PointStyle getPointStyle();
|
||||
PointStyle getPointStyle() const;
|
||||
|
||||
/**
|
||||
* Gets the maximum point size supported.
|
||||
* This may vary from computer to computer.
|
||||
**/
|
||||
int getMaxPointSize();
|
||||
int getMaxPointSize() const;
|
||||
|
||||
/**
|
||||
* Draws text at the specified coordinates, with rotation and
|
||||
@@ -510,9 +509,7 @@ public:
|
||||
void translate(float x, float y);
|
||||
void shear(float kx, float ky);
|
||||
|
||||
void drawTest(Image *image, float x, float y, float a, float sx, float sy, float ox, float oy);
|
||||
|
||||
bool hasFocus();
|
||||
bool hasFocus() const;
|
||||
private:
|
||||
|
||||
Font *currentFont;
|
||||
@@ -523,7 +520,7 @@ private:
|
||||
GLint matrixLimit;
|
||||
GLint userMatrices;
|
||||
|
||||
int getRenderHeight();
|
||||
int getRenderHeight() const;
|
||||
}; // Graphics
|
||||
|
||||
} // opengl
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -37,7 +37,8 @@ Image::Image(love::image::ImageData *data)
|
||||
: width((float)(data->getWidth()))
|
||||
, height((float)(data->getHeight()))
|
||||
, texture(0)
|
||||
, mipmapsharpness(0.0f)
|
||||
, mipmapSharpness(0.0f)
|
||||
, mipmapsCreated(false)
|
||||
{
|
||||
data->retain();
|
||||
this->data = data;
|
||||
@@ -143,38 +144,55 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo
|
||||
drawv(t, v);
|
||||
}
|
||||
|
||||
void Image::checkMipmapsCreated() const
|
||||
void Image::checkMipmapsCreated()
|
||||
{
|
||||
if (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR)
|
||||
if (mipmapsCreated || (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR))
|
||||
return;
|
||||
|
||||
if (!hasMipmapSupport())
|
||||
throw love::Exception("Mipmap filtering is not supported on this system!");
|
||||
throw love::Exception("Mipmap filtering is not supported on this system.");
|
||||
|
||||
// some old GPUs/systems claim support for NPOT textures, but fail when generating mipmaps
|
||||
// we can't detect which systems will do this, so we fail gracefully for all NPOT images
|
||||
// Some old drivers claim support for NPOT textures, but fail when creating mipmaps.
|
||||
// we can't detect which systems will do this, so we fail gracefully for all NPOT images.
|
||||
int w = int(width), h = int(height);
|
||||
if (w != next_p2(w) || h != next_p2(h))
|
||||
throw love::Exception("Could not generate mipmaps: image does not have power of two dimensions!");
|
||||
throw love::Exception("Cannot create mipmaps: image does not have power of two dimensions.");
|
||||
|
||||
bind();
|
||||
|
||||
GLboolean mipmapscreated;
|
||||
glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&mipmapscreated);
|
||||
if (hasNpot() && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object))
|
||||
{
|
||||
// AMD/ATI drivers have several bugs when generating mipmaps,
|
||||
// re-uploading the entire base image seems to be required.
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA8,
|
||||
(GLsizei)width,
|
||||
(GLsizei)height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data->getData());
|
||||
|
||||
// generate mipmaps for this image if we haven't already
|
||||
if (!mipmapscreated)
|
||||
// More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||
|
||||
if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
else if (GLEE_EXT_framebuffer_object)
|
||||
glGenerateMipmapEXT(GL_TEXTURE_2D);
|
||||
else
|
||||
// modify single texel to trigger mipmap chain generation
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data->getData());
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(GLsizei)width,
|
||||
(GLsizei)height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data->getData());
|
||||
}
|
||||
|
||||
mipmapsCreated = true;
|
||||
}
|
||||
|
||||
void Image::setFilter(const Image::Filter &f)
|
||||
@@ -182,8 +200,8 @@ void Image::setFilter(const Image::Filter &f)
|
||||
filter = f;
|
||||
|
||||
bind();
|
||||
checkMipmapsCreated();
|
||||
setTextureFilter(f);
|
||||
checkMipmapsCreated();
|
||||
}
|
||||
|
||||
const Image::Filter &Image::getFilter() const
|
||||
@@ -210,15 +228,15 @@ void Image::setMipmapSharpness(float sharpness)
|
||||
return;
|
||||
|
||||
// LOD bias has the range (-maxbias, maxbias)
|
||||
mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f);
|
||||
mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f);
|
||||
|
||||
bind();
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); // negative bias is sharper
|
||||
}
|
||||
|
||||
float Image::getMipmapSharpness() const
|
||||
{
|
||||
return mipmapsharpness;
|
||||
return mipmapSharpness;
|
||||
}
|
||||
|
||||
void Image::bind() const
|
||||
@@ -242,7 +260,7 @@ void Image::unload()
|
||||
bool Image::loadVolatile()
|
||||
{
|
||||
if (hasMipmapSharpnessSupport())
|
||||
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness);
|
||||
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
|
||||
|
||||
if (hasNpot())
|
||||
return loadVolatileNPOT();
|
||||
@@ -255,11 +273,8 @@ bool Image::loadVolatilePOT()
|
||||
glGenTextures(1,(GLuint *)&texture);
|
||||
bindTexture(texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
setTextureFilter(filter);
|
||||
setTextureWrap(wrap);
|
||||
|
||||
float p2width = next_p2(width);
|
||||
float p2height = next_p2(height);
|
||||
@@ -271,29 +286,34 @@ bool Image::loadVolatilePOT()
|
||||
vertices[2].s = s;
|
||||
vertices[3].s = s;
|
||||
|
||||
while (glGetError() != GL_NO_ERROR); // clear errors
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA8,
|
||||
(GLsizei)p2width,
|
||||
(GLsizei)p2height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
0);
|
||||
0,
|
||||
GL_RGBA8,
|
||||
(GLsizei)p2width,
|
||||
(GLsizei)p2height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
0);
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(GLsizei)width,
|
||||
(GLsizei)height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data->getData());
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(GLsizei)width,
|
||||
(GLsizei)height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data->getData());
|
||||
|
||||
setMipmapSharpness(mipmapsharpness);
|
||||
setFilter(filter);
|
||||
setWrap(wrap);
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
throw love::Exception("Cannot create image: size may be too large for this system.");
|
||||
|
||||
mipmapsCreated = false;
|
||||
checkMipmapsCreated();
|
||||
setMipmapSharpness(mipmapSharpness);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -303,25 +323,27 @@ bool Image::loadVolatileNPOT()
|
||||
glGenTextures(1,(GLuint *)&texture);
|
||||
bindTexture(texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
setTextureFilter(filter);
|
||||
setTextureWrap(wrap);
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
while (glGetError() != GL_NO_ERROR); // clear errors
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA8,
|
||||
(GLsizei)width,
|
||||
(GLsizei)height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data->getData());
|
||||
0,
|
||||
GL_RGBA8,
|
||||
(GLsizei)width,
|
||||
(GLsizei)height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data->getData());
|
||||
|
||||
setMipmapSharpness(mipmapsharpness);
|
||||
setFilter(filter);
|
||||
setWrap(wrap);
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
throw love::Exception("Cannot create image: size may be too large for this system.");
|
||||
|
||||
mipmapsCreated = false;
|
||||
checkMipmapsCreated();
|
||||
setMipmapSharpness(mipmapSharpness);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -362,12 +384,12 @@ bool Image::hasNpot()
|
||||
|
||||
bool Image::hasMipmapSupport()
|
||||
{
|
||||
return (GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap) != 0;
|
||||
return GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap;
|
||||
}
|
||||
|
||||
bool Image::hasMipmapSharpnessSupport()
|
||||
{
|
||||
return (GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias) != 0;
|
||||
return GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias;
|
||||
}
|
||||
|
||||
} // opengl
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -28,10 +28,8 @@
|
||||
#include "image/ImageData.h"
|
||||
#include "graphics/Image.h"
|
||||
|
||||
#include "OpenGL.h"
|
||||
|
||||
// OpenGL
|
||||
#include "GLee.h"
|
||||
#include "OpenGL.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -127,7 +125,7 @@ private:
|
||||
|
||||
void drawv(const Matrix &t, const vertex *v) const;
|
||||
|
||||
friend class PixelEffect;
|
||||
friend class Shader;
|
||||
GLuint getTextureName() const
|
||||
{
|
||||
return texture;
|
||||
@@ -144,11 +142,14 @@ private:
|
||||
// The source vertices of the image.
|
||||
vertex vertices[4];
|
||||
|
||||
// Mipmap texture LOD bias value
|
||||
float mipmapsharpness;
|
||||
// Mipmap texture LOD bias (sharpness) value.
|
||||
float mipmapSharpness;
|
||||
|
||||
// Implementation-dependent maximum/minimum mipmap sharpness values
|
||||
float maxmipmapsharpness;
|
||||
// Implementation-dependent min/max mipmap sharpness values.
|
||||
float maxMipmapSharpness;
|
||||
|
||||
// True if mipmaps have been created for this Image.
|
||||
bool mipmapsCreated;
|
||||
|
||||
// The image's filter mode
|
||||
Image::Filter filter;
|
||||
@@ -159,7 +160,7 @@ private:
|
||||
bool loadVolatilePOT();
|
||||
bool loadVolatileNPOT();
|
||||
|
||||
void checkMipmapsCreated() const;
|
||||
void checkMipmapsCreated();
|
||||
|
||||
}; // Image
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,7 +18,14 @@
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/Exception.h"
|
||||
|
||||
#include "OpenGL.h"
|
||||
#include "Shader.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -27,27 +34,143 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
static GLuint boundTexture = 0;
|
||||
static bool contextInitialized = false;
|
||||
|
||||
void resetBoundTexture()
|
||||
static int curTextureUnit = 0;
|
||||
static std::vector<GLuint> textureUnits;
|
||||
|
||||
void initializeContext()
|
||||
{
|
||||
// OpenGL might not be initialized yet, so we can't do a real reset
|
||||
boundTexture = 0;
|
||||
if (contextInitialized)
|
||||
return;
|
||||
|
||||
contextInitialized = true;
|
||||
|
||||
// initialize multiple texture unit support for shaders, if available
|
||||
textureUnits.clear();
|
||||
if (Shader::isSupported())
|
||||
{
|
||||
GLint maxtextureunits;
|
||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureunits);
|
||||
|
||||
textureUnits.resize(maxtextureunits, 0);
|
||||
|
||||
GLenum curgltextureunit;
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &curgltextureunit);
|
||||
|
||||
curTextureUnit = curgltextureunit - GL_TEXTURE0;
|
||||
|
||||
// Retrieve currently bound textures for each texture unit
|
||||
for (size_t i = 0; i < textureUnits.size(); i++)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &textureUnits[i]);
|
||||
}
|
||||
|
||||
glActiveTexture(curgltextureunit);
|
||||
}
|
||||
else
|
||||
{
|
||||
// multitexturing not supported, so we only have 1 texture unit
|
||||
textureUnits.resize(1, 0);
|
||||
curTextureUnit = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &textureUnits[0]);
|
||||
}
|
||||
|
||||
// The functionality of the core and ARB VBOs are identical, so we can
|
||||
// assign the pointers of the core functions to the names of the ARB
|
||||
// functions, if the latter isn't supported but the former is.
|
||||
if (GLEE_VERSION_1_5 && !GLEE_ARB_vertex_buffer_object)
|
||||
{
|
||||
glBindBufferARB = (GLEEPFNGLBINDBUFFERARBPROC) glBindBuffer;
|
||||
glBufferDataARB = (GLEEPFNGLBUFFERDATAARBPROC) glBufferData;
|
||||
glBufferSubDataARB = (GLEEPFNGLBUFFERSUBDATAARBPROC) glBufferSubData;
|
||||
glDeleteBuffersARB = (GLEEPFNGLDELETEBUFFERSARBPROC) glDeleteBuffers;
|
||||
glGenBuffersARB = (GLEEPFNGLGENBUFFERSARBPROC) glGenBuffers;
|
||||
glGetBufferParameterivARB = (GLEEPFNGLGETBUFFERPARAMETERIVARBPROC) glGetBufferParameteriv;
|
||||
glGetBufferPointervARB = (GLEEPFNGLGETBUFFERPOINTERVARBPROC) glGetBufferPointerv;
|
||||
glGetBufferSubDataARB = (GLEEPFNGLGETBUFFERSUBDATAARBPROC) glGetBufferSubData;
|
||||
glIsBufferARB = (GLEEPFNGLISBUFFERARBPROC) glIsBuffer;
|
||||
glMapBufferARB = (GLEEPFNGLMAPBUFFERARBPROC) glMapBuffer;
|
||||
glUnmapBufferARB = (GLEEPFNGLUNMAPBUFFERARBPROC) glUnmapBuffer;
|
||||
}
|
||||
|
||||
// Set the 'default' texture (id 0) as a repeating white pixel.
|
||||
// Otherwise, texture2D inside a shader would return black when drawing graphics primitives,
|
||||
// which would create the need to use different "passthrough" shaders for untextured primitives vs images.
|
||||
|
||||
GLuint curtexture = textureUnits[curTextureUnit];
|
||||
bindTexture(0);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
GLubyte pixel = 255;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE8, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pixel);
|
||||
|
||||
bindTexture(curtexture);
|
||||
}
|
||||
|
||||
void bindTexture(GLuint texture, bool override)
|
||||
void uninitializeContext()
|
||||
{
|
||||
if (texture != boundTexture || texture == 0 || override)
|
||||
contextInitialized = false;
|
||||
}
|
||||
|
||||
void setActiveTextureUnit(int textureunit)
|
||||
{
|
||||
if (textureunit < 0 || (size_t) textureunit >= textureUnits.size())
|
||||
throw love::Exception("Invalid texture unit index (%d).", textureunit);
|
||||
|
||||
if (textureunit != curTextureUnit)
|
||||
{
|
||||
boundTexture = texture;
|
||||
if (textureUnits.size() > 1)
|
||||
glActiveTexture(GL_TEXTURE0 + textureunit);
|
||||
else
|
||||
throw love::Exception("Multitexturing not supported.");
|
||||
}
|
||||
|
||||
curTextureUnit = textureunit;
|
||||
}
|
||||
|
||||
void bindTexture(GLuint texture)
|
||||
{
|
||||
if (texture != textureUnits[curTextureUnit])
|
||||
{
|
||||
textureUnits[curTextureUnit] = texture;
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
}
|
||||
}
|
||||
|
||||
void bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev)
|
||||
{
|
||||
if (textureunit < 0 || (size_t) textureunit >= textureUnits.size())
|
||||
throw love::Exception("Invalid texture unit index.");
|
||||
|
||||
if (texture != textureUnits[textureunit])
|
||||
{
|
||||
int oldtextureunit = curTextureUnit;
|
||||
setActiveTextureUnit(textureunit);
|
||||
|
||||
textureUnits[textureunit] = texture;
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
if (restoreprev)
|
||||
setActiveTextureUnit(oldtextureunit);
|
||||
}
|
||||
}
|
||||
|
||||
void deleteTexture(GLuint texture)
|
||||
{
|
||||
if (texture == boundTexture)
|
||||
boundTexture = 0;
|
||||
// glDeleteTextures binds texture 0 to all texture units the deleted texture was bound to
|
||||
std::vector<GLuint>::iterator it;
|
||||
for (it = textureUnits.begin(); it != textureUnits.end(); ++it)
|
||||
{
|
||||
if (*it == texture)
|
||||
*it = 0;
|
||||
}
|
||||
|
||||
glDeleteTextures(1, &texture);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,8 +18,8 @@
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_COMMON_OPENGL_H
|
||||
#define LOVE_COMMON_OPENGL_H
|
||||
#ifndef LOVE_GRAPHICS_OPENGL_OPENGL_H
|
||||
#define LOVE_GRAPHICS_OPENGL_OPENGL_H
|
||||
|
||||
#include "GLee.h"
|
||||
#include "graphics/Image.h"
|
||||
@@ -31,43 +31,61 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
// resets the stored bound texture id
|
||||
void resetBoundTexture();
|
||||
/**
|
||||
* Initializes some required context state,
|
||||
* based on current and default OpenGL state.
|
||||
**/
|
||||
void initializeContext();
|
||||
|
||||
/**
|
||||
* Marks current context state as invalid.
|
||||
**/
|
||||
void uninitializeContext();
|
||||
|
||||
/**
|
||||
* Helper for setting the active texture unit.
|
||||
*
|
||||
* @param textureunit Index in the range of [0, maxtextureunits-1]
|
||||
**/
|
||||
void setActiveTextureUnit(int textureunit);
|
||||
|
||||
/**
|
||||
* Helper for binding an OpenGL texture.
|
||||
* Makes sure we aren't redundantly binding textures.
|
||||
* @param texture The texture to bind.
|
||||
* @param override Overrides the checks to guarantee texture bind
|
||||
**/
|
||||
void bindTexture(GLuint texture, bool override = false);
|
||||
void bindTexture(GLuint texture);
|
||||
|
||||
/**
|
||||
* Helper for binding a texture to a specific texture unit.
|
||||
*
|
||||
* @param textureunit Index in the range of [0, maxtextureunits-1]
|
||||
* @param resoreprev Restore previously bound texture unit when done.
|
||||
**/
|
||||
void bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev);
|
||||
|
||||
/**
|
||||
* Helper for deleting an OpenGL texture.
|
||||
* Cleans up if the texture is currently bound.
|
||||
* @param texture The texture to delete.
|
||||
**/
|
||||
void deleteTexture(GLuint texture);
|
||||
|
||||
/**
|
||||
* Sets the image filter mode for the currently bound texture
|
||||
* @param f The image filter to set
|
||||
* Sets the image filter mode for the currently bound texture.
|
||||
*/
|
||||
void setTextureFilter(const graphics::Image::Filter &f);
|
||||
|
||||
/**
|
||||
* Returns the image filter mode for the currently bound texture
|
||||
* Returns the image filter mode for the currently bound texture.
|
||||
*/
|
||||
graphics::Image::Filter getTextureFilter();
|
||||
|
||||
/**
|
||||
* Sets the image wrap mode for the currently bound texture
|
||||
* @param w The wrap mode to set
|
||||
* Sets the image wrap mode for the currently bound texture.
|
||||
*/
|
||||
void setTextureWrap(const graphics::Image::Wrap &w);
|
||||
|
||||
/**
|
||||
* Returns the image wrap mode for the currently bound texture
|
||||
* Returns the image wrap mode for the currently bound texture.
|
||||
*/
|
||||
graphics::Image::Wrap getTextureWrap();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "common/math.h"
|
||||
|
||||
#include "GLee.h"
|
||||
#include "OpenGL.h"
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -63,6 +63,7 @@ ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer)
|
||||
, pLast(0)
|
||||
, pEnd(0)
|
||||
, particleVerts(0)
|
||||
, sprite(sprite)
|
||||
, active(true)
|
||||
, emissionRate(0)
|
||||
, emitCounter(0)
|
||||
@@ -91,11 +92,10 @@ ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer)
|
||||
, offsetX(sprite->getWidth()*0.5f)
|
||||
, offsetY(sprite->getHeight()*0.5f)
|
||||
{
|
||||
this->sprite = sprite;
|
||||
sprite->retain();
|
||||
sizes.push_back(1.0f);
|
||||
colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
setBufferSize(buffer);
|
||||
sprite->retain();
|
||||
}
|
||||
|
||||
ParticleSystem::~ParticleSystem()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#include "PixelEffect.h"
|
||||
#include "GLee.h"
|
||||
#include "Graphics.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// temporarily attaches a shader program (for setting uniforms, etc)
|
||||
// reattaches the originally active program when destroyed
|
||||
struct TemporaryAttacher
|
||||
{
|
||||
TemporaryAttacher(love::graphics::opengl::PixelEffect *sp) : s(sp)
|
||||
{
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
|
||||
s->attach();
|
||||
}
|
||||
~TemporaryAttacher()
|
||||
{
|
||||
glUseProgram(activeProgram);
|
||||
}
|
||||
love::graphics::opengl::PixelEffect *s;
|
||||
GLint activeProgram;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
PixelEffect *PixelEffect::current = NULL;
|
||||
|
||||
std::vector<bool> PixelEffect::_unit_available;
|
||||
|
||||
GLint PixelEffect::getTextureUnit(const std::string &name)
|
||||
{
|
||||
std::map<std::string, GLint>::const_iterator it = _texture_unit_pool.find(name);
|
||||
|
||||
if (it != _texture_unit_pool.end())
|
||||
return it->second;
|
||||
|
||||
GLint unit = -1;
|
||||
for (int i = 1; i < _unit_available.size(); ++i)
|
||||
{
|
||||
if (_unit_available[i])
|
||||
{
|
||||
unit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unit == -1)
|
||||
throw love::Exception("No more texture units available");
|
||||
|
||||
_unit_available[unit] = false;
|
||||
_texture_unit_pool[name] = unit;
|
||||
return unit;
|
||||
}
|
||||
|
||||
PixelEffect::PixelEffect(const std::string &code)
|
||||
: _program(0)
|
||||
, _code(code)
|
||||
{
|
||||
if (_unit_available.empty())
|
||||
{
|
||||
GLint max_units;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_units);
|
||||
_unit_available.resize(max_units, true);
|
||||
_unit_available[0] = false;
|
||||
}
|
||||
loadVolatile();
|
||||
}
|
||||
|
||||
bool PixelEffect::loadVolatile()
|
||||
{
|
||||
_program = glCreateProgram();
|
||||
// should only fail if this is called between a glBegin()/glEnd() pair
|
||||
if (_program == 0)
|
||||
throw love::Exception("Cannot create shader program object.");
|
||||
|
||||
GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
// should only fail if this is called between a glBegin()/glEnd() pair
|
||||
if (shader == 0)
|
||||
{
|
||||
glDeleteProgram(_program);
|
||||
throw love::Exception("Cannot create shader object.");
|
||||
}
|
||||
|
||||
// compile fragment shader code
|
||||
const char *src = _code.c_str();
|
||||
GLint strlen = _code.length();
|
||||
glShaderSource(shader, 1, (const GLchar **)&src, &strlen);
|
||||
glCompileShader(shader);
|
||||
|
||||
GLint compile_ok;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_ok);
|
||||
if (GL_FALSE == compile_ok)
|
||||
{
|
||||
// get compiler error
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &strlen);
|
||||
char *error_str = new char[strlen];
|
||||
glGetShaderInfoLog(shader, strlen, NULL, error_str);
|
||||
std::string tmp(error_str);
|
||||
|
||||
// cleanup before throw
|
||||
delete[] error_str;
|
||||
glDeleteShader(shader);
|
||||
glDeleteProgram(_program);
|
||||
|
||||
// XXX: errorlog may contain escape sequences.
|
||||
throw love::Exception("Cannot compile shader:\n%s", tmp.c_str());
|
||||
}
|
||||
|
||||
// link fragment shader
|
||||
GLint link_ok;
|
||||
glAttachShader(_program, shader);
|
||||
glLinkProgram(_program);
|
||||
glGetProgramiv(_program, GL_LINK_STATUS, &link_ok);
|
||||
if (GL_FALSE == link_ok)
|
||||
{
|
||||
// this should not happen if compiling is ok, but one can never be too careful
|
||||
// get linker error
|
||||
std::string tmp(getWarnings());
|
||||
|
||||
// cleanup before throw
|
||||
glDeleteShader(shader);
|
||||
glDeleteProgram(_program);
|
||||
throw love::Exception("Cannot compile shader:\n%s", tmp.c_str());
|
||||
}
|
||||
|
||||
glDeleteShader(shader);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PixelEffect::~PixelEffect()
|
||||
{
|
||||
unloadVolatile();
|
||||
}
|
||||
|
||||
void PixelEffect::unloadVolatile()
|
||||
{
|
||||
glDeleteProgram(_program);
|
||||
}
|
||||
|
||||
std::string PixelEffect::getGLSLVersion()
|
||||
{
|
||||
// GL_SHADING_LANGUAGE_VERSION may not be available in OpenGL < 2.0.
|
||||
const char *tmp = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||
if (NULL == tmp)
|
||||
return "0.0";
|
||||
|
||||
// the version string always begins with a version number of the format
|
||||
// major_number.minor_number
|
||||
// or
|
||||
// major_number.minor_number.release_number
|
||||
// we can keep release_number, since it does not affect the check below.
|
||||
std::string versionString(tmp);
|
||||
size_t minorEndPos = versionString.find(' ');
|
||||
return versionString.substr(0, minorEndPos);
|
||||
}
|
||||
|
||||
|
||||
bool PixelEffect::isSupported()
|
||||
{
|
||||
return GLEE_VERSION_2_0 && getGLSLVersion() >= "1.2";
|
||||
}
|
||||
|
||||
std::string PixelEffect::getWarnings() const
|
||||
{
|
||||
GLint strlen, nullpos;
|
||||
glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &strlen);
|
||||
char *temp_str = new char[strlen+1];
|
||||
// be extra sure that the error string will be 0-terminated
|
||||
memset(temp_str, '\0', strlen+1);
|
||||
glGetProgramInfoLog(_program, strlen, &nullpos, temp_str);
|
||||
temp_str[nullpos] = '\0';
|
||||
|
||||
std::string warnings(temp_str);
|
||||
delete[] temp_str;
|
||||
return warnings;
|
||||
}
|
||||
|
||||
void PixelEffect::attach()
|
||||
{
|
||||
glUseProgram(_program);
|
||||
current = this;
|
||||
}
|
||||
|
||||
void PixelEffect::detach()
|
||||
{
|
||||
glUseProgram(0);
|
||||
current = NULL;
|
||||
}
|
||||
|
||||
void PixelEffect::sendFloat(const std::string &name, int size, const GLfloat *vec, int count)
|
||||
{
|
||||
TemporaryAttacher attacher(this);
|
||||
GLint location = getUniformLocation(name);
|
||||
|
||||
if (size < 1 || size > 4)
|
||||
{
|
||||
throw love::Exception("Invalid variable size: %d (expected 1-4).", size);
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 4:
|
||||
glUniform4fv(location, count, vec);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3fv(location, count, vec);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2fv(location, count, vec);
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
glUniform1fv(location, count, vec);
|
||||
break;
|
||||
}
|
||||
|
||||
// throw error if needed
|
||||
checkSetUniformError();
|
||||
}
|
||||
|
||||
void PixelEffect::sendMatrix(const std::string &name, int size, const GLfloat *m, int count)
|
||||
{
|
||||
TemporaryAttacher attacher(this);
|
||||
GLint location = getUniformLocation(name);
|
||||
|
||||
if (size < 2 || size > 4)
|
||||
{
|
||||
throw love::Exception("Invalid matrix size: %dx%d "
|
||||
"(can only set 2x2, 3x3 or 4x4 matrices).", size,size);
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 4:
|
||||
glUniformMatrix4fv(location, count, GL_FALSE, m);
|
||||
break;
|
||||
case 3:
|
||||
glUniformMatrix3fv(location, count, GL_FALSE, m);
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
glUniformMatrix2fv(location, count, GL_FALSE, m);
|
||||
break;
|
||||
}
|
||||
|
||||
// throw error if needed
|
||||
checkSetUniformError();
|
||||
}
|
||||
|
||||
void PixelEffect::sendImage(const std::string &name, const Image &image)
|
||||
{
|
||||
GLint texture_unit = getTextureUnit(name);
|
||||
|
||||
TemporaryAttacher attacher(this);
|
||||
GLint location = getUniformLocation(name);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + texture_unit);
|
||||
bindTexture(image.getTextureName(), true); // guarantee it gets bound
|
||||
glUniform1i(location, texture_unit);
|
||||
|
||||
// reset texture unit
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
// throw error if needed
|
||||
checkSetUniformError();
|
||||
}
|
||||
|
||||
void PixelEffect::sendCanvas(const std::string &name, const Canvas &canvas)
|
||||
{
|
||||
GLint texture_unit = getTextureUnit(name);
|
||||
|
||||
TemporaryAttacher attacher(this);
|
||||
GLint location = getUniformLocation(name);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + texture_unit);
|
||||
bindTexture(canvas.getTextureName(), true); // guarantee it gets bound
|
||||
glUniform1i(location, texture_unit);
|
||||
|
||||
// reset texture unit
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
// throw error if needed
|
||||
checkSetUniformError();
|
||||
}
|
||||
|
||||
GLint PixelEffect::getUniformLocation(const std::string &name)
|
||||
{
|
||||
std::map<std::string, GLint>::const_iterator it = _uniforms.find(name);
|
||||
if (it != _uniforms.end())
|
||||
return it->second;
|
||||
|
||||
GLint location = glGetUniformLocation(_program, name.c_str());
|
||||
if (location == -1)
|
||||
{
|
||||
throw love::Exception(
|
||||
"Cannot get location of shader variable `%s'.\n"
|
||||
"A common error is to define but not use the variable.", name.c_str());
|
||||
}
|
||||
|
||||
_uniforms[name] = location;
|
||||
return location;
|
||||
}
|
||||
|
||||
void PixelEffect::checkSetUniformError()
|
||||
{
|
||||
GLenum error_code = glGetError();
|
||||
if (GL_INVALID_OPERATION == error_code)
|
||||
{
|
||||
throw love::Exception(
|
||||
"Invalid operation:\n"
|
||||
"- Trying to send the wrong value type to shader variable, or\n"
|
||||
"- Trying to send array values with wrong dimension, or\n"
|
||||
"- Invalid variable name.");
|
||||
}
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_GRAPHICS_EFFECT_H
|
||||
#define LOVE_GRAPHICS_EFFECT_H
|
||||
|
||||
#include "common/Object.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "OpenGL.h"
|
||||
#include "Image.h"
|
||||
#include "Canvas.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// A fragment shader
|
||||
class PixelEffect : public Object, public Volatile
|
||||
{
|
||||
public:
|
||||
PixelEffect(const std::string &code);
|
||||
virtual ~PixelEffect();
|
||||
std::string getWarnings() const;
|
||||
|
||||
virtual bool loadVolatile();
|
||||
virtual void unloadVolatile();
|
||||
|
||||
void attach();
|
||||
static void detach();
|
||||
static std::string getGLSLVersion();
|
||||
static bool isSupported();
|
||||
|
||||
static PixelEffect *current;
|
||||
|
||||
void sendFloat(const std::string &name, int size, const GLfloat *vec, int count);
|
||||
void sendMatrix(const std::string &name, int size, const GLfloat *m, int count);
|
||||
void sendImage(const std::string &name, const Image &image);
|
||||
void sendCanvas(const std::string &name, const Canvas &canvas);
|
||||
|
||||
private:
|
||||
GLint getUniformLocation(const std::string &name);
|
||||
void checkSetUniformError();
|
||||
GLuint _program;
|
||||
std::string _code; // volatile and stuff
|
||||
|
||||
// uniform location buffer
|
||||
std::map<std::string, GLint> _uniforms;
|
||||
|
||||
// texture unit pool for setting images
|
||||
std::map<std::string, GLint> _texture_unit_pool;
|
||||
GLint getTextureUnit(const std::string &name);
|
||||
static std::vector<bool> _unit_available;
|
||||
};
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_GRAPHICS_EFFECT_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -21,8 +21,8 @@
|
||||
#include "Quad.h"
|
||||
#include "common/Matrix.h"
|
||||
|
||||
// GLee
|
||||
#include "GLee.h"
|
||||
// OpenGL
|
||||
#include "OpenGL.h"
|
||||
|
||||
// STD
|
||||
#include <cstring> // For memcpy
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#include "common/config.h"
|
||||
|
||||
#include "Shader.h"
|
||||
#include "Graphics.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
// temporarily attaches a shader program (for setting uniforms, etc)
|
||||
// reattaches the originally active program when destroyed
|
||||
struct TemporaryAttacher
|
||||
{
|
||||
TemporaryAttacher(Shader *shader)
|
||||
: curShader(shader)
|
||||
, prevShader(Shader::current)
|
||||
{
|
||||
curShader->attach(true);
|
||||
}
|
||||
|
||||
~TemporaryAttacher()
|
||||
{
|
||||
if (prevShader != NULL)
|
||||
prevShader->attach();
|
||||
else
|
||||
Shader::detach();
|
||||
}
|
||||
|
||||
Shader *curShader;
|
||||
Shader *prevShader;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
Shader *Shader::current = NULL;
|
||||
|
||||
GLint Shader::maxTextureUnits = 0;
|
||||
std::vector<int> Shader::textureCounters;
|
||||
|
||||
Shader::Shader(const ShaderSources &sources)
|
||||
: shaderSources(sources)
|
||||
, program(0)
|
||||
{
|
||||
if (shaderSources.empty())
|
||||
throw love::Exception("Cannot create shader: no source code!");
|
||||
|
||||
GLint maxtexunits;
|
||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtexunits);
|
||||
maxTextureUnits = std::max(maxtexunits - 1, 0);
|
||||
|
||||
// initialize global texture id counters if needed
|
||||
if (textureCounters.size() < (size_t) maxTextureUnits)
|
||||
textureCounters.resize(maxTextureUnits, 0);
|
||||
|
||||
// load shader source and create program object
|
||||
loadVolatile();
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
if (current == this)
|
||||
detach();
|
||||
|
||||
unloadVolatile();
|
||||
}
|
||||
|
||||
GLuint Shader::compileCode(ShaderType type, const std::string &code)
|
||||
{
|
||||
GLenum glshadertype;
|
||||
const char *shadertypename = NULL;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_VERTEX:
|
||||
glshadertype = GL_VERTEX_SHADER;
|
||||
shadertypename = "vertex";
|
||||
break;
|
||||
case TYPE_FRAGMENT:
|
||||
glshadertype = GL_FRAGMENT_SHADER;
|
||||
shadertypename = "fragment";
|
||||
break;
|
||||
default:
|
||||
throw love::Exception("Cannot create shader object: unknown shader type.");
|
||||
break;
|
||||
}
|
||||
|
||||
// clear existing errors
|
||||
while (glGetError() != GL_NO_ERROR);
|
||||
|
||||
GLuint shaderid = glCreateShader(glshadertype);
|
||||
|
||||
if (shaderid == 0) // oh no!
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
|
||||
if (err == GL_INVALID_ENUM) // invalid or unsupported shader type
|
||||
throw love::Exception("Cannot create %s shader object: %s shaders not supported.", shadertypename, shadertypename);
|
||||
else // other errors should only happen between glBegin() and glEnd()
|
||||
throw love::Exception("Cannot create %s shader object.", shadertypename);
|
||||
}
|
||||
|
||||
const char *src = code.c_str();
|
||||
size_t srclen = code.length();
|
||||
glShaderSource(shaderid, 1, (const GLchar **)&src, (GLint *)&srclen);
|
||||
|
||||
glCompileShader(shaderid);
|
||||
|
||||
GLint status;
|
||||
glGetShaderiv(shaderid, GL_COMPILE_STATUS, &status);
|
||||
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
GLint infologlen;
|
||||
glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen);
|
||||
|
||||
GLchar *errorlog = new GLchar[infologlen + 1];
|
||||
glGetShaderInfoLog(shaderid, infologlen, NULL, errorlog);
|
||||
|
||||
std::string tmp(errorlog);
|
||||
|
||||
delete[] errorlog;
|
||||
glDeleteShader(shaderid);
|
||||
|
||||
throw love::Exception("Cannot compile %s shader code:\n%s", shadertypename, tmp.c_str());
|
||||
}
|
||||
|
||||
return shaderid;
|
||||
}
|
||||
|
||||
void Shader::createProgram(const std::vector<GLuint> &shaderids)
|
||||
{
|
||||
program = glCreateProgram();
|
||||
if (program == 0) // should only fail when called between glBegin() and glEnd()
|
||||
throw love::Exception("Cannot create shader program object.");
|
||||
|
||||
std::vector<GLuint>::const_iterator it;
|
||||
for (it = shaderids.begin(); it != shaderids.end(); ++it)
|
||||
glAttachShader(program, *it);
|
||||
|
||||
glLinkProgram(program);
|
||||
|
||||
for (it = shaderids.begin(); it != shaderids.end(); ++it)
|
||||
glDeleteShader(*it); // flag shaders for auto-deletion when program object is deleted
|
||||
|
||||
GLint status;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
const std::string warnings = getWarnings();
|
||||
glDeleteProgram(program);
|
||||
|
||||
throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::loadVolatile()
|
||||
{
|
||||
// zero out active texture list
|
||||
activeTextureUnits.clear();
|
||||
activeTextureUnits.insert(activeTextureUnits.begin(), maxTextureUnits, 0);
|
||||
|
||||
std::vector<GLuint> shaderids;
|
||||
|
||||
ShaderSources::const_iterator source;
|
||||
for (source = shaderSources.begin(); source != shaderSources.end(); ++source)
|
||||
{
|
||||
GLuint shaderid = compileCode(source->first, source->second);
|
||||
shaderids.push_back(shaderid);
|
||||
}
|
||||
|
||||
if (shaderids.empty())
|
||||
throw love::Exception("Cannot create shader: no valid source code!");
|
||||
|
||||
createProgram(shaderids);
|
||||
|
||||
if (current == this)
|
||||
{
|
||||
current = NULL; // make sure glUseProgram gets called
|
||||
attach();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shader::unloadVolatile()
|
||||
{
|
||||
if (current == this)
|
||||
glUseProgram(0);
|
||||
|
||||
if (program != 0)
|
||||
glDeleteProgram(program);
|
||||
|
||||
program = 0;
|
||||
|
||||
// decrement global texture id counters for texture units which had textures bound from this shader
|
||||
for (size_t i = 0; i < activeTextureUnits.size(); ++i)
|
||||
{
|
||||
if (activeTextureUnits[i] > 0)
|
||||
textureCounters[i] = std::max(textureCounters[i] - 1, 0);
|
||||
}
|
||||
|
||||
// active texture list is probably invalid, clear it
|
||||
activeTextureUnits.clear();
|
||||
activeTextureUnits.insert(activeTextureUnits.begin(), maxTextureUnits, 0);
|
||||
|
||||
// same with uniform location list
|
||||
uniforms.clear();
|
||||
}
|
||||
|
||||
std::string Shader::getWarnings() const
|
||||
{
|
||||
GLint strlen, nullpos;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &strlen);
|
||||
char *tempstr = new char[strlen+1];
|
||||
// be extra sure that the error string will be 0-terminated
|
||||
memset(tempstr, '\0', strlen+1);
|
||||
glGetProgramInfoLog(program, strlen, &nullpos, tempstr);
|
||||
tempstr[nullpos] = '\0';
|
||||
|
||||
std::string warnings(tempstr);
|
||||
delete[] tempstr;
|
||||
return warnings;
|
||||
}
|
||||
|
||||
void Shader::attach(bool temporary)
|
||||
{
|
||||
if (current != this)
|
||||
glUseProgram(program);
|
||||
|
||||
current = this;
|
||||
|
||||
if (!temporary)
|
||||
{
|
||||
// make sure all sent textures are properly bound to their respective texture units
|
||||
// note: list potentially contains texture ids of deleted/invalid textures!
|
||||
for (size_t i = 0; i < activeTextureUnits.size(); ++i)
|
||||
{
|
||||
if (activeTextureUnits[i] > 0)
|
||||
bindTextureToUnit(activeTextureUnits[i], i + 1, false);
|
||||
}
|
||||
setActiveTextureUnit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::detach()
|
||||
{
|
||||
if (current != NULL)
|
||||
glUseProgram(0);
|
||||
|
||||
current = NULL;
|
||||
}
|
||||
|
||||
void Shader::sendFloat(const std::string &name, int size, const GLfloat *vec, int count)
|
||||
{
|
||||
TemporaryAttacher attacher(this);
|
||||
GLint location = getUniformLocation(name);
|
||||
|
||||
if (size < 1 || size > 4)
|
||||
throw love::Exception("Invalid variable size: %d (expected 1-4).", size);
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 4:
|
||||
glUniform4fv(location, count, vec);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3fv(location, count, vec);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2fv(location, count, vec);
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
glUniform1fv(location, count, vec);
|
||||
break;
|
||||
}
|
||||
|
||||
// throw error if needed
|
||||
checkSetUniformError();
|
||||
}
|
||||
|
||||
void Shader::sendMatrix(const std::string &name, int size, const GLfloat *m, int count)
|
||||
{
|
||||
TemporaryAttacher attacher(this);
|
||||
GLint location = getUniformLocation(name);
|
||||
|
||||
if (size < 2 || size > 4)
|
||||
{
|
||||
throw love::Exception("Invalid matrix size: %dx%d "
|
||||
"(can only set 2x2, 3x3 or 4x4 matrices).", size,size);
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 4:
|
||||
glUniformMatrix4fv(location, count, GL_FALSE, m);
|
||||
break;
|
||||
case 3:
|
||||
glUniformMatrix3fv(location, count, GL_FALSE, m);
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
glUniformMatrix2fv(location, count, GL_FALSE, m);
|
||||
break;
|
||||
}
|
||||
|
||||
// throw error if needed
|
||||
checkSetUniformError();
|
||||
}
|
||||
|
||||
void Shader::sendTexture(const std::string &name, GLuint texture)
|
||||
{
|
||||
TemporaryAttacher attacher(this);
|
||||
GLint location = getUniformLocation(name);
|
||||
int textureunit = getTextureUnit(name);
|
||||
|
||||
// bind texture to assigned texture unit and send uniform to shader program
|
||||
bindTextureToUnit(texture, textureunit, false);
|
||||
glUniform1i(location, textureunit);
|
||||
|
||||
// reset texture unit
|
||||
setActiveTextureUnit(0);
|
||||
|
||||
// throw error if needed
|
||||
checkSetUniformError();
|
||||
|
||||
// increment global shader texture id counter for this texture unit, if we haven't already
|
||||
if (activeTextureUnits[textureunit-1] == 0)
|
||||
++textureCounters[textureunit-1];
|
||||
|
||||
// store texture id so it can be re-bound to the proper texture unit when necessary
|
||||
activeTextureUnits[textureunit-1] = texture;
|
||||
}
|
||||
|
||||
void Shader::sendImage(const std::string &name, const Image &image)
|
||||
{
|
||||
sendTexture(name, image.getTextureName());
|
||||
}
|
||||
|
||||
void Shader::sendCanvas(const std::string &name, const Canvas &canvas)
|
||||
{
|
||||
sendTexture(name, canvas.getTextureName());
|
||||
}
|
||||
|
||||
GLint Shader::getUniformLocation(const std::string &name)
|
||||
{
|
||||
std::map<std::string, GLint>::const_iterator it = uniforms.find(name);
|
||||
if (it != uniforms.end())
|
||||
return it->second;
|
||||
|
||||
GLint location = glGetUniformLocation(program, name.c_str());
|
||||
if (location == -1)
|
||||
{
|
||||
throw love::Exception(
|
||||
"Cannot get location of shader variable `%s'.\n"
|
||||
"A common error is to define but not use the variable.", name.c_str());
|
||||
}
|
||||
|
||||
uniforms[name] = location;
|
||||
return location;
|
||||
}
|
||||
|
||||
int Shader::getTextureUnit(const std::string &name)
|
||||
{
|
||||
std::map<std::string, GLint>::const_iterator it = textureUnitPool.find(name);
|
||||
|
||||
if (it != textureUnitPool.end())
|
||||
return it->second;
|
||||
|
||||
int textureunit = 1;
|
||||
|
||||
// prefer texture units which are unused by all other shaders
|
||||
std::vector<int>::iterator nextfreeunit = std::find(textureCounters.begin(), textureCounters.end(), 0);
|
||||
|
||||
if (nextfreeunit != textureCounters.end())
|
||||
textureunit = std::distance(textureCounters.begin(), nextfreeunit) + 1; // we don't want to use unit 0
|
||||
else
|
||||
{
|
||||
// no completely unused texture units exist, try to use next free slot in our own list
|
||||
std::vector<GLuint>::iterator nexttexunit = std::find(activeTextureUnits.begin(), activeTextureUnits.end(), 0);
|
||||
|
||||
if (nexttexunit == activeTextureUnits.end())
|
||||
throw love::Exception("No more texture units available for shader.");
|
||||
|
||||
textureunit = std::distance(activeTextureUnits.begin(), nexttexunit) + 1; // we don't want to use unit 0
|
||||
}
|
||||
|
||||
textureUnitPool[name] = textureunit;
|
||||
return textureunit;
|
||||
}
|
||||
|
||||
void Shader::checkSetUniformError()
|
||||
{
|
||||
GLenum error_code = glGetError();
|
||||
if (GL_INVALID_OPERATION == error_code)
|
||||
{
|
||||
throw love::Exception(
|
||||
"Invalid operation:\n"
|
||||
"- Trying to send the wrong value type to shader variable, or\n"
|
||||
"- Trying to send array values with wrong dimension, or\n"
|
||||
"- Invalid variable name.");
|
||||
}
|
||||
}
|
||||
|
||||
std::string Shader::getGLSLVersion()
|
||||
{
|
||||
// GL_SHADING_LANGUAGE_VERSION may not be available in OpenGL < 2.0.
|
||||
const char *tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||
if (tmp == NULL)
|
||||
return "0.0";
|
||||
|
||||
// the version string always begins with a version number of the format
|
||||
// major_number.minor_number
|
||||
// or
|
||||
// major_number.minor_number.release_number
|
||||
// we can keep release_number, since it does not affect the check below.
|
||||
std::string versionstring(tmp);
|
||||
size_t minorendpos = versionstring.find(' ');
|
||||
return versionstring.substr(0, minorendpos);
|
||||
}
|
||||
|
||||
bool Shader::isSupported()
|
||||
{
|
||||
return GLEE_VERSION_2_0 && getGLSLVersion() >= "1.2";
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_GRAPHICS_SHADER_H
|
||||
#define LOVE_GRAPHICS_SHADER_H
|
||||
|
||||
#include "common/Object.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "OpenGL.h"
|
||||
#include "Image.h"
|
||||
#include "Canvas.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// A GLSL shader
|
||||
class Shader : public Object, public Volatile
|
||||
{
|
||||
public:
|
||||
|
||||
// Pointer to currently active Shader.
|
||||
static Shader *current;
|
||||
|
||||
enum ShaderType
|
||||
{
|
||||
TYPE_VERTEX,
|
||||
TYPE_FRAGMENT,
|
||||
TYPE_MAX_ENUM
|
||||
};
|
||||
|
||||
// Type for a list of shader source codes in the form of sources[shadertype] = code
|
||||
typedef std::map<ShaderType, std::string> ShaderSources;
|
||||
|
||||
/**
|
||||
* Creates a new Shader using a list of source codes.
|
||||
* Sources must contain either vertex or fragment shader code, or both.
|
||||
**/
|
||||
Shader(const ShaderSources &sources);
|
||||
|
||||
virtual ~Shader();
|
||||
|
||||
// Implements Volatile
|
||||
virtual bool loadVolatile();
|
||||
virtual void unloadVolatile();
|
||||
|
||||
/**
|
||||
* Binds this Shader's program to be used when rendering.
|
||||
*
|
||||
* @param temporary True if we just want to send values to the shader with no intention of rendering.
|
||||
**/
|
||||
void attach(bool temporary = false);
|
||||
|
||||
/**
|
||||
* Detach the currently bound Shader.
|
||||
* Causes the GPU rendering pipeline to use fixed functionality in place of shader programs.
|
||||
**/
|
||||
static void detach();
|
||||
|
||||
/**
|
||||
* Returns any warnings this Shader may have generated.
|
||||
**/
|
||||
std::string getWarnings() const;
|
||||
|
||||
/**
|
||||
* Send at least one float or vector value to this Shader as a uniform.
|
||||
*
|
||||
* @param name The name of the uniform variable in the source code.
|
||||
* @param size Number of elements in each vector to send.
|
||||
* A value of 1 indicates a single-component vector (a float).
|
||||
* @param vec Pointer to the float or vector values.
|
||||
* @param count Number of float or vector values.
|
||||
**/
|
||||
void sendFloat(const std::string &name, int size, const GLfloat *vec, int count);
|
||||
|
||||
/**
|
||||
* Send at least one matrix to this Shader as a uniform.
|
||||
*
|
||||
* @param name The name of the uniform variable in the source code.
|
||||
* @param size Number of rows/columns in the matrix.
|
||||
* @param m Pointer to the first element of the first matrix.
|
||||
* @param count Number of matrices to send.
|
||||
**/
|
||||
void sendMatrix(const std::string &name, int size, const GLfloat *m, int count);
|
||||
|
||||
/**
|
||||
* Send an image to this Shader as a uniform.
|
||||
*
|
||||
* @param name The name of the uniform variable in the source code.
|
||||
**/
|
||||
void sendImage(const std::string &name, const Image &image);
|
||||
|
||||
/**
|
||||
* Send a canvas to this Shader as a uniform.
|
||||
*
|
||||
* @param name The name of the uniform variable in the source code.
|
||||
**/
|
||||
void sendCanvas(const std::string &name, const Canvas &canvas);
|
||||
|
||||
static std::string getGLSLVersion();
|
||||
static bool isSupported();
|
||||
|
||||
private:
|
||||
|
||||
GLint getUniformLocation(const std::string &name);
|
||||
void checkSetUniformError();
|
||||
|
||||
GLuint compileCode(ShaderType type, const std::string &code);
|
||||
void createProgram(const std::vector<GLuint> &shaderids);
|
||||
|
||||
int getTextureUnit(const std::string &name);
|
||||
|
||||
void sendTexture(const std::string &name, GLuint texture);
|
||||
|
||||
// List of all shader code attached to this Shader
|
||||
ShaderSources shaderSources;
|
||||
|
||||
GLuint program; // volatile
|
||||
|
||||
// Uniform location buffer map
|
||||
std::map<std::string, GLint> uniforms;
|
||||
|
||||
// Texture unit pool for setting images
|
||||
std::map<std::string, GLint> textureUnitPool; // textureUnitPool[name] = textureunit
|
||||
std::vector<GLuint> activeTextureUnits; // activeTextureUnits[textureunit-1] = textureid
|
||||
|
||||
// Max GPU texture units available for sent images
|
||||
static GLint maxTextureUnits;
|
||||
|
||||
// Counts total number of textures bound to each texture unit in all shaders
|
||||
static std::vector<int> textureCounters;
|
||||
};
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_GRAPHICS_SHADER_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
#include "SpriteBatch.h"
|
||||
|
||||
// STD
|
||||
#include <iostream>
|
||||
// OpenGL
|
||||
#include "OpenGL.h"
|
||||
|
||||
// LOVE
|
||||
#include "Image.h"
|
||||
@@ -107,12 +107,14 @@ int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, fl
|
||||
|
||||
if (color)
|
||||
setColorv(sprite, *color);
|
||||
|
||||
|
||||
addv(sprite, (index == -1 ? next : index));
|
||||
addv(sprite, (index == -1) ? next : index);
|
||||
|
||||
// Increment counter.
|
||||
if (index == -1)
|
||||
return next++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -133,11 +135,12 @@ int SpriteBatch::addq(Quad *quad, float x, float y, float a, float sx, float sy,
|
||||
if (color)
|
||||
setColorv(sprite, *color);
|
||||
|
||||
addv(sprite, (index == -1 ? next : index));
|
||||
addv(sprite, (index == -1) ? next : index);
|
||||
|
||||
// Increment counter.
|
||||
if (index == -1)
|
||||
return next++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -187,6 +190,16 @@ void SpriteBatch::setColor()
|
||||
color = 0;
|
||||
}
|
||||
|
||||
bool SpriteBatch::isEmpty() const
|
||||
{
|
||||
return next == 0;
|
||||
}
|
||||
|
||||
bool SpriteBatch::isFull() const
|
||||
{
|
||||
return next >= size;
|
||||
}
|
||||
|
||||
void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
||||
{
|
||||
const int color_offset = 0;
|
||||
@@ -222,7 +235,9 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
if (color)
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -27,16 +27,12 @@
|
||||
// LOVE
|
||||
#include "common/math.h"
|
||||
#include "common/Object.h"
|
||||
#include "common/Vector.h"
|
||||
#include "common/Matrix.h"
|
||||
#include "common/StringMap.h"
|
||||
#include "graphics/Drawable.h"
|
||||
#include "graphics/Volatile.h"
|
||||
#include "graphics/Color.h"
|
||||
|
||||
// OpenGL
|
||||
#include "GLee.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
@@ -90,6 +86,16 @@ public:
|
||||
*/
|
||||
void setColor();
|
||||
|
||||
/**
|
||||
* Returns whether the SpriteBatch is empty of sprites or not.
|
||||
**/
|
||||
bool isEmpty() const;
|
||||
|
||||
/**
|
||||
* Returns whether the amount of sprites has reached the buffer limit or not.
|
||||
**/
|
||||
bool isFull() const;
|
||||
|
||||
// Implements Drawable.
|
||||
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -248,6 +248,7 @@ void VBO::unload(bool save)
|
||||
// VertexIndex
|
||||
|
||||
size_t VertexIndex::maxSize = 0;
|
||||
size_t VertexIndex::elementSize = 0;
|
||||
std::list<size_t> VertexIndex::sizeRefs;
|
||||
VertexBuffer *VertexIndex::element_array = NULL;
|
||||
|
||||
@@ -287,6 +288,11 @@ GLenum VertexIndex::getType(size_t s) const
|
||||
// if buffer-size > max(GLushort) then GL_UNSIGNED_INT else GL_UNSIGNED_SHORT
|
||||
}
|
||||
|
||||
size_t VertexIndex::getElementSize()
|
||||
{
|
||||
return elementSize;
|
||||
}
|
||||
|
||||
VertexBuffer *VertexIndex::getVertexBuffer() const
|
||||
{
|
||||
return element_array;
|
||||
@@ -342,9 +348,12 @@ void VertexIndex::resize(size_t size)
|
||||
}
|
||||
|
||||
VertexBuffer *new_element_array;
|
||||
|
||||
// Depending on the size, a switch to int and more memory is needed.
|
||||
GLenum target_type = getType(size);
|
||||
size_t array_size = (target_type == GL_UNSIGNED_SHORT ? sizeof(GLushort) : sizeof(GLuint)) * 6 * size;
|
||||
size_t elem_size = (target_type == GL_UNSIGNED_SHORT) ? sizeof(GLushort) : sizeof(GLuint);
|
||||
|
||||
size_t array_size = elem_size * 6 * size;
|
||||
|
||||
// Create may throw out-of-memory exceptions.
|
||||
// VertexIndex will propagate the exception and keep the old VertexBuffer.
|
||||
@@ -362,6 +371,7 @@ void VertexIndex::resize(size_t size)
|
||||
delete element_array;
|
||||
element_array = new_element_array;
|
||||
maxSize = size;
|
||||
elementSize = elem_size;
|
||||
|
||||
switch (target_type)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "graphics/Volatile.h"
|
||||
|
||||
// OpenGL
|
||||
#include "GLee.h"
|
||||
#include "OpenGL.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -331,10 +331,6 @@ private:
|
||||
// Set if the buffer was modified while operating on gpu memory
|
||||
// and needs to be synchronized.
|
||||
bool is_dirty;
|
||||
|
||||
// Usage hint for map()/unmap() pair. Same as `access' parameter in
|
||||
// glBufferData or 0 if not mapped.
|
||||
GLenum mapped_access;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -409,6 +405,15 @@ public:
|
||||
return getType(maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size in bytes of an element in the element array.
|
||||
* Can be used with getPointer to calculate an offset into the array based
|
||||
* on a number of elements.
|
||||
*
|
||||
* @return The size of an element in bytes.
|
||||
**/
|
||||
size_t getElementSize();
|
||||
|
||||
/**
|
||||
* Returns the pointer to the VertexBuffer.
|
||||
* The pointer will change if a new size request or removal causes
|
||||
@@ -463,6 +468,8 @@ private:
|
||||
// The size of the array requested by this instance.
|
||||
size_t size;
|
||||
|
||||
// The size in bytes of an element in the element array.
|
||||
static size_t elementSize;
|
||||
// The current VertexBuffer size. 0 means no VertexBuffer.
|
||||
static size_t maxSize;
|
||||
// The list of sizes. Needs to be kept sorted in ascending order.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -64,6 +64,27 @@ int w_Canvas_getImageData(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Canvas_getPixel(lua_State * L)
|
||||
{
|
||||
Canvas * canvas = luax_checkcanvas(L, 1);
|
||||
int x = luaL_checkint(L, 2);
|
||||
int y = luaL_checkint(L, 3);
|
||||
unsigned char c[4];
|
||||
try
|
||||
{
|
||||
canvas->getPixel(c, x, y);
|
||||
}
|
||||
catch (love::Exception & e)
|
||||
{
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
lua_pushnumber(L, c[0]);
|
||||
lua_pushnumber(L, c[1]);
|
||||
lua_pushnumber(L, c[2]);
|
||||
lua_pushnumber(L, c[3]);
|
||||
return 4;
|
||||
}
|
||||
|
||||
int w_Canvas_setFilter(lua_State *L)
|
||||
{
|
||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||
@@ -202,6 +223,7 @@ static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "renderTo", w_Canvas_renderTo },
|
||||
{ "getImageData", w_Canvas_getImageData },
|
||||
{ "getPixel", w_Canvas_getPixel },
|
||||
{ "setFilter", w_Canvas_setFilter },
|
||||
{ "getFilter", w_Canvas_getFilter },
|
||||
{ "setWrap", w_Canvas_setWrap },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -36,6 +36,7 @@ namespace opengl
|
||||
Canvas *luax_checkcanvas(lua_State *L, int idx);
|
||||
int w_Canvas_renderTo(lua_State *L);
|
||||
int w_Canvas_getImageData(lua_State *L);
|
||||
int w_Canvas_getPixel(lua_State * L);
|
||||
int w_Canvas_setFilter(lua_State *L);
|
||||
int w_Canvas_getFilter(lua_State *L);
|
||||
int w_Canvas_setWrap(lua_State *L);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -93,8 +93,7 @@ int w_Font_getLineHeight(lua_State *L)
|
||||
int w_Font_setFilter(lua_State *L)
|
||||
{
|
||||
Font *t = luax_checkfont(L, 1);
|
||||
|
||||
Image::Filter f;
|
||||
Image::Filter f = t->getFilter();
|
||||
|
||||
const char *minstr = luaL_checkstring(L, 2);
|
||||
const char *magstr = luaL_optstring(L, 3, minstr);
|
||||
@@ -104,15 +103,6 @@ int w_Font_setFilter(lua_State *L)
|
||||
if (!Image::getConstant(magstr, f.mag))
|
||||
return luaL_error(L, "Invalid filter mode: %s", magstr);
|
||||
|
||||
if (lua_isnoneornil(L, 4))
|
||||
f.mipmap = Image::FILTER_NONE; // mipmapping is disabled unless third argument is given
|
||||
else
|
||||
{
|
||||
const char *mipmapstr = luaL_checkstring(L, 4);
|
||||
if (!Image::getConstant(mipmapstr, f.mipmap))
|
||||
return luaL_error(L, "Invalid filter mode: %s", mipmapstr);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
t->setFilter(f);
|
||||
@@ -135,31 +125,7 @@ int w_Font_getFilter(lua_State *L)
|
||||
Image::getConstant(f.mag, magstr);
|
||||
lua_pushstring(L, minstr);
|
||||
lua_pushstring(L, magstr);
|
||||
|
||||
const char *mipmapstr;
|
||||
if (Image::getConstant(f.mipmap, mipmapstr))
|
||||
lua_pushstring(L, mipmapstr);
|
||||
else
|
||||
lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
int w_Font_setMipmapSharpness(lua_State *L)
|
||||
{
|
||||
Font *t = luax_checkfont(L, 1);
|
||||
|
||||
float sharpness = (float) luaL_checknumber(L, 2);
|
||||
t->setMipmapSharpness(sharpness);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Font_getMipmapSharpness(lua_State *L)
|
||||
{
|
||||
Font *t = luax_checkfont(L, 1);
|
||||
lua_pushnumber(L, t->getMipmapSharpness());
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_Font_getAscent(lua_State *L)
|
||||
@@ -192,8 +158,6 @@ static const luaL_Reg functions[] =
|
||||
{ "getLineHeight", w_Font_getLineHeight },
|
||||
{ "setFilter", w_Font_setFilter },
|
||||
{ "getFilter", w_Font_getFilter },
|
||||
{ "setMipmapSharpness", w_Font_setMipmapSharpness },
|
||||
{ "getMipmapSharpness", w_Font_getMipmapSharpness },
|
||||
{ "getAscent", w_Font_getAscent },
|
||||
{ "getDescent", w_Font_getDescent },
|
||||
{ "getBaseline", w_Font_getBaseline },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -40,8 +40,6 @@ int w_Font_setLineHeight(lua_State *L);
|
||||
int w_Font_getLineHeight(lua_State *L);
|
||||
int w_Font_setFilter(lua_State *L);
|
||||
int w_Font_getFilter(lua_State *L);
|
||||
int w_Font_setMipmapSharpness(lua_State *L);
|
||||
int w_Font_getMipmapSharpness(lua_State *L);
|
||||
int w_Font_getAscent(lua_State *L);
|
||||
int w_Font_getDescent(lua_State *L);
|
||||
int w_Font_getBaseline(lua_State *L);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -19,7 +19,7 @@
|
||||
**/
|
||||
|
||||
#include "wrap_Graphics.h"
|
||||
#include "GLee.h"
|
||||
#include "OpenGL.h"
|
||||
#include "graphics/DrawQable.h"
|
||||
#include "image/ImageData.h"
|
||||
#include "font/Rasterizer.h"
|
||||
@@ -491,29 +491,50 @@ int w_newCanvas(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_newPixelEffect(lua_State *L)
|
||||
int w_newShader(lua_State *L)
|
||||
{
|
||||
if (!PixelEffect::isSupported())
|
||||
return luaL_error(L, "Sorry, your graphics card does not support pixel effects.");
|
||||
if (!Shader::isSupported())
|
||||
return luaL_error(L, "Sorry, your graphics card does not support shaders.");
|
||||
|
||||
try
|
||||
{
|
||||
luaL_checkstring(L, 1);
|
||||
// clamp stack to 2 elements
|
||||
lua_settop(L, 2);
|
||||
|
||||
luax_getfunction(L, "graphics", "_effectCodeToGLSL");
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pcall(L, 1, 1, 0);
|
||||
|
||||
const char *code = lua_tostring(L, -1);
|
||||
PixelEffect *effect = instance->newPixelEffect(code);
|
||||
luax_newtype(L, "PixelEffect", GRAPHICS_PIXELEFFECT_T, (void *)effect);
|
||||
// push vertcode and fragcode strings to the top of the stack so they become arguments for the function
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushvalue(L, 2);
|
||||
|
||||
// call effectCodeToGLSL, returned values will be at the top of the stack
|
||||
lua_pcall(L, 2, 2, 0);
|
||||
|
||||
Shader::ShaderSources sources;
|
||||
|
||||
// vertex shader code
|
||||
if (lua_isstring(L, -2))
|
||||
{
|
||||
std::string vertcode(luaL_checkstring(L, -2));
|
||||
sources[Shader::TYPE_VERTEX] = vertcode;
|
||||
}
|
||||
|
||||
// fragment shader code
|
||||
if (lua_isstring(L, -1))
|
||||
{
|
||||
std::string fragcode(luaL_checkstring(L, -1));
|
||||
sources[Shader::TYPE_FRAGMENT] = fragcode;
|
||||
}
|
||||
|
||||
Shader *shader = instance->newShader(sources);
|
||||
luax_newtype(L, "Shader", GRAPHICS_SHADER_T, (void *)shader);
|
||||
}
|
||||
catch(const love::Exception &e)
|
||||
{
|
||||
// memory is freed in Graphics::newPixelEffect
|
||||
// memory is freed in Graphics::newShader
|
||||
luax_getfunction(L, "graphics", "_transformGLSLErrorMessages");
|
||||
lua_pushstring(L, e.what());
|
||||
lua_pcall(L, 1,1, 0);
|
||||
lua_pcall(L, 1, 1, 0);
|
||||
const char *err = lua_tostring(L, -1);
|
||||
return luaL_error(L, "%s", err);
|
||||
}
|
||||
@@ -679,13 +700,19 @@ int w_setDefaultImageFilter(lua_State *L)
|
||||
|
||||
int w_getBlendMode(lua_State *L)
|
||||
{
|
||||
Graphics::BlendMode mode = instance->getBlendMode();
|
||||
const char *str;
|
||||
if (!Graphics::getConstant(mode, str))
|
||||
return luaL_error(L, "Invalid blend mode: %s", str);
|
||||
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
Graphics::BlendMode mode = instance->getBlendMode();
|
||||
const char *str;
|
||||
if (!Graphics::getConstant(mode, str))
|
||||
return luaL_error(L, "Unknown blend mode");
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
catch (love::Exception &e)
|
||||
{
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
int w_getColorMode(lua_State *L)
|
||||
@@ -693,8 +720,7 @@ int w_getColorMode(lua_State *L)
|
||||
Graphics::ColorMode mode = instance->getColorMode();
|
||||
const char *str;
|
||||
if (!Graphics::getConstant(mode, str))
|
||||
return luaL_error(L, "Invalid color mode: %s", str);
|
||||
|
||||
return luaL_error(L, "Unknown color mode");
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
@@ -704,8 +730,10 @@ int w_getDefaultImageFilter(lua_State *L)
|
||||
const Image::Filter &f = instance->getDefaultImageFilter();
|
||||
const char *minstr;
|
||||
const char *magstr;
|
||||
Image::getConstant(f.min, minstr);
|
||||
Image::getConstant(f.mag, magstr);
|
||||
if (!Image::getConstant(f.min, minstr))
|
||||
return luaL_error(L, "Unknown filter mode for argument #1");
|
||||
if (!Image::getConstant(f.mag, magstr))
|
||||
return luaL_error(L, "Unknown filter mode for argument #2");
|
||||
lua_pushstring(L, minstr);
|
||||
lua_pushstring(L, magstr);
|
||||
return 2;
|
||||
@@ -756,7 +784,8 @@ int w_getLineStyle(lua_State *L)
|
||||
{
|
||||
Graphics::LineStyle style = instance->getLineStyle();
|
||||
const char *str;
|
||||
Graphics::getConstant(style, str);
|
||||
if (!Graphics::getConstant(style, str))
|
||||
return luaL_error(L, "Unknown line style");
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
@@ -805,7 +834,11 @@ int w_getPointSize(lua_State *L)
|
||||
|
||||
int w_getPointStyle(lua_State *L)
|
||||
{
|
||||
lua_pushinteger(L, instance->getPointStyle());
|
||||
Graphics::PointStyle style = instance->getPointStyle();
|
||||
const char *str;
|
||||
if (!Graphics::getConstant(style, str))
|
||||
return luaL_error(L, "Unknown point style");
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -856,26 +889,26 @@ int w_getCanvas(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setPixelEffect(lua_State *L)
|
||||
int w_setShader(lua_State *L)
|
||||
{
|
||||
if (lua_isnoneornil(L,1))
|
||||
{
|
||||
PixelEffect::detach();
|
||||
Shader::detach();
|
||||
return 0;
|
||||
}
|
||||
|
||||
PixelEffect *effect = luax_checkpixeleffect(L, 1);
|
||||
effect->attach();
|
||||
Shader *shader = luax_checkshader(L, 1);
|
||||
shader->attach();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getPixelEffect(lua_State *L)
|
||||
int w_getShader(lua_State *L)
|
||||
{
|
||||
PixelEffect *effect = PixelEffect::current;
|
||||
if (effect)
|
||||
Shader *shader = Shader::current;
|
||||
if (shader)
|
||||
{
|
||||
effect->retain();
|
||||
luax_newtype(L, "PixelEffect", GRAPHICS_PIXELEFFECT_T, (void *) effect);
|
||||
shader->retain();
|
||||
luax_newtype(L, "Shader", GRAPHICS_SHADER_T, (void *) shader);
|
||||
}
|
||||
else
|
||||
lua_pushnil(L);
|
||||
@@ -892,7 +925,10 @@ int w_isSupported(lua_State *L)
|
||||
{
|
||||
const char *str = luaL_checkstring(L, i);
|
||||
if (!Graphics::getConstant(str, support))
|
||||
{
|
||||
supported = false;
|
||||
break;
|
||||
}
|
||||
switch (support)
|
||||
{
|
||||
case Graphics::SUPPORT_CANVAS:
|
||||
@@ -903,8 +939,8 @@ int w_isSupported(lua_State *L)
|
||||
if (!Canvas::isHdrSupported())
|
||||
supported = false;
|
||||
break;
|
||||
case Graphics::SUPPORT_PIXELEFFECT:
|
||||
if (!PixelEffect::isSupported())
|
||||
case Graphics::SUPPORT_SHADER:
|
||||
if (!Shader::isSupported())
|
||||
supported = false;
|
||||
break;
|
||||
case Graphics::SUPPORT_NPOT:
|
||||
@@ -990,20 +1026,6 @@ int w_drawq(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_drawTest(lua_State *L)
|
||||
{
|
||||
Image *image = luax_checktype<Image>(L, 1, "Image", GRAPHICS_IMAGE_T);
|
||||
float x = (float)luaL_optnumber(L, 2, 0.0f);
|
||||
float y = (float)luaL_optnumber(L, 3, 0.0f);
|
||||
float angle = (float)luaL_optnumber(L, 4, 0.0f);
|
||||
float sx = (float)luaL_optnumber(L, 5, 1.0f);
|
||||
float sy = (float)luaL_optnumber(L, 6, sx);
|
||||
float ox = (float)luaL_optnumber(L, 7, 0);
|
||||
float oy = (float)luaL_optnumber(L, 8, 0);
|
||||
instance->drawTest(image, x, y, angle, sx, sy, ox, oy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_print(lua_State *L)
|
||||
{
|
||||
const char *str = luaL_checkstring(L, 1);
|
||||
@@ -1323,7 +1345,7 @@ static const luaL_Reg functions[] =
|
||||
{ "newSpriteBatch", w_newSpriteBatch },
|
||||
{ "newParticleSystem", w_newParticleSystem },
|
||||
{ "newCanvas", w_newCanvas },
|
||||
{ "newPixelEffect", w_newPixelEffect },
|
||||
{ "newShader", w_newShader },
|
||||
|
||||
{ "setColor", w_setColor },
|
||||
{ "getColor", w_getColor },
|
||||
@@ -1354,14 +1376,13 @@ static const luaL_Reg functions[] =
|
||||
{ "setCanvas", w_setCanvas },
|
||||
{ "getCanvas", w_getCanvas },
|
||||
|
||||
{ "setPixelEffect", w_setPixelEffect },
|
||||
{ "getPixelEffect", w_getPixelEffect },
|
||||
{ "setShader", w_setShader },
|
||||
{ "getShader", w_getShader },
|
||||
|
||||
{ "isSupported", w_isSupported },
|
||||
|
||||
{ "draw", w_draw },
|
||||
{ "drawq", w_drawq },
|
||||
{ "drawTest", w_drawTest },
|
||||
|
||||
{ "print", w_print },
|
||||
{ "printf", w_printf },
|
||||
@@ -1416,7 +1437,7 @@ static const lua_CFunction types[] =
|
||||
luaopen_spritebatch,
|
||||
luaopen_particlesystem,
|
||||
luaopen_canvas,
|
||||
luaopen_pixeleffect,
|
||||
luaopen_shader,
|
||||
0
|
||||
};
|
||||
|
||||
@@ -1428,7 +1449,7 @@ extern "C" int luaopen_love_graphics(lua_State *L)
|
||||
{
|
||||
instance = new Graphics();
|
||||
}
|
||||
catch(Exception &e)
|
||||
catch (love::Exception &e)
|
||||
{
|
||||
return luaL_error(L, e.what());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "wrap_SpriteBatch.h"
|
||||
#include "wrap_ParticleSystem.h"
|
||||
#include "wrap_Canvas.h"
|
||||
#include "wrap_PixelEffect.h"
|
||||
#include "wrap_Shader.h"
|
||||
#include "Graphics.h"
|
||||
|
||||
namespace love
|
||||
@@ -63,7 +63,7 @@ int w_newImageFont(lua_State *L);
|
||||
int w_newSpriteBatch(lua_State *L);
|
||||
int w_newParticleSystem(lua_State *L);
|
||||
int w_newCanvas(lua_State *L); // comments in function
|
||||
int w_newPixelEffect(lua_State *L);
|
||||
int w_newShader(lua_State *L);
|
||||
int w_setColor(lua_State *L);
|
||||
int w_getColor(lua_State *L);
|
||||
int w_setBackgroundColor(lua_State *L);
|
||||
@@ -90,11 +90,11 @@ int w_getMaxPointSize(lua_State *L);
|
||||
int w_newScreenshot(lua_State *L);
|
||||
int w_setCanvas(lua_State *L);
|
||||
int w_getCanvas(lua_State *L);
|
||||
int w_setPixelEffect(lua_State *L);
|
||||
int w_setShader(lua_State *L);
|
||||
int w_getShader(lua_State *L);
|
||||
int w_isSupported(lua_State *L);
|
||||
int w_draw(lua_State *L);
|
||||
int w_drawq(lua_State *L);
|
||||
int w_drawTest(lua_State *L);
|
||||
int w_print(lua_State *L);
|
||||
int w_printf(lua_State *L);
|
||||
int w_point(lua_State *L);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -50,8 +50,7 @@ int w_Image_getHeight(lua_State *L)
|
||||
int w_Image_setFilter(lua_State *L)
|
||||
{
|
||||
Image *t = luax_checkimage(L, 1);
|
||||
|
||||
Image::Filter f;
|
||||
Image::Filter f = t->getFilter();
|
||||
|
||||
const char *minstr = luaL_checkstring(L, 2);
|
||||
const char *magstr = luaL_optstring(L, 3, minstr);
|
||||
@@ -61,15 +60,6 @@ int w_Image_setFilter(lua_State *L)
|
||||
if (!Image::getConstant(magstr, f.mag))
|
||||
return luaL_error(L, "Invalid filter mode: %s", magstr);
|
||||
|
||||
if (lua_isnoneornil(L, 4))
|
||||
f.mipmap = Image::FILTER_NONE; // mipmapping is disabled unless third argument is given
|
||||
else
|
||||
{
|
||||
const char *mipmapstr = luaL_checkstring(L, 4);
|
||||
if (!Image::getConstant(mipmapstr, f.mipmap))
|
||||
return luaL_error(L, "Invalid filter mode: %s", mipmapstr);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
t->setFilter(f);
|
||||
@@ -92,14 +82,47 @@ int w_Image_getFilter(lua_State *L)
|
||||
Image::getConstant(f.mag, magstr);
|
||||
lua_pushstring(L, minstr);
|
||||
lua_pushstring(L, magstr);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_Image_setMipmapFilter(lua_State *L)
|
||||
{
|
||||
Image *t = luax_checkimage(L, 1);
|
||||
Image::Filter f = t->getFilter();
|
||||
|
||||
if (lua_isnoneornil(L, 2))
|
||||
f.mipmap = Image::FILTER_NONE; // mipmapping is disabled if no argument is given
|
||||
else
|
||||
{
|
||||
const char *mipmapstr = luaL_checkstring(L, 2);
|
||||
if (!Image::getConstant(mipmapstr, f.mipmap))
|
||||
return luaL_error(L, "Invalid filter mode: %s", mipmapstr);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
t->setFilter(f);
|
||||
}
|
||||
catch(love::Exception &e)
|
||||
{
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Image_getMipmapFilter(lua_State *L)
|
||||
{
|
||||
Image *t = luax_checkimage(L, 1);
|
||||
const Image::Filter f = t->getFilter();
|
||||
|
||||
const char *mipmapstr;
|
||||
if (Image::getConstant(f.mipmap, mipmapstr))
|
||||
lua_pushstring(L, mipmapstr);
|
||||
else
|
||||
lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled
|
||||
if (!Image::getConstant(f.mipmap, mipmapstr))
|
||||
return 0; // only return a mipmap filter if mipmapping is enabled
|
||||
|
||||
return 3;
|
||||
lua_pushstring(L, mipmapstr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Image_setWrap(lua_State *L)
|
||||
@@ -159,6 +182,8 @@ static const luaL_Reg functions[] =
|
||||
{ "getFilter", w_Image_getFilter },
|
||||
{ "setWrap", w_Image_setWrap },
|
||||
{ "getWrap", w_Image_getWrap },
|
||||
{ "setMipmapFilter", w_Image_setMipmapFilter },
|
||||
{ "getMipmapFilter", w_Image_getMipmapFilter },
|
||||
{ "setMipmapSharpness", w_Image_setMipmapSharpness },
|
||||
{ "getMipmapSharpness", w_Image_getMipmapSharpness },
|
||||
{ 0, 0 }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -37,6 +37,8 @@ int w_Image_getWidth(lua_State *L);
|
||||
int w_Image_getHeight(lua_State *L);
|
||||
int w_Image_setFilter(lua_State *L);
|
||||
int w_image_getFilter(lua_State *L);
|
||||
int w_Image_setMipmapFilter(lua_State *L);
|
||||
int w_Image_getMipmapFilter(lua_State *L);
|
||||
int w_Image_setWrap(lua_State *L);
|
||||
int w_Image_getWrap(lua_State *L);
|
||||
int w_Image_setMipmapSharpness(lua_State *L);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
+48
-42
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,12 +18,11 @@
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#include "wrap_PixelEffect.h"
|
||||
#include "wrap_Shader.h"
|
||||
#include "wrap_Image.h"
|
||||
#include "wrap_Canvas.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -32,46 +31,50 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
PixelEffect *luax_checkpixeleffect(lua_State *L, int idx)
|
||||
Shader *luax_checkshader(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<PixelEffect>(L, idx, "PixelEffect", GRAPHICS_PIXELEFFECT_T);
|
||||
return luax_checktype<Shader>(L, idx, "Shader", GRAPHICS_SHADER_T);
|
||||
}
|
||||
|
||||
int w_PixelEffect_getWarnings(lua_State *L)
|
||||
int w_Shader_getWarnings(lua_State *L)
|
||||
{
|
||||
PixelEffect *effect = luax_checkpixeleffect(L, 1);
|
||||
lua_pushstring(L, effect->getWarnings().c_str());
|
||||
Shader *shader = luax_checkshader(L, 1);
|
||||
lua_pushstring(L, shader->getWarnings().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _sendScalars(lua_State *L, PixelEffect *effect, const char *name, int count)
|
||||
static int _sendScalars(lua_State *L, Shader *shader, const char *name, int count)
|
||||
{
|
||||
float *values = new float[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (!lua_isnumber(L, 3 + i))
|
||||
if (lua_isnumber(L, 3 + i))
|
||||
values[i] = (float)lua_tonumber(L, 3 + i);
|
||||
else if (lua_isboolean(L, 3 + i))
|
||||
values[i] = (float)lua_toboolean(L, 3 + i);
|
||||
else
|
||||
{
|
||||
delete[] values;
|
||||
return luaL_typerror(L, 3 + i, "number");
|
||||
return luaL_typerror(L, 3 + i, "number or boolean");
|
||||
}
|
||||
values[i] = (float)lua_tonumber(L, 3 + i);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
effect->sendFloat(name, 1, values, count);
|
||||
shader->sendFloat(name, 1, values, count);
|
||||
}
|
||||
catch(love::Exception &e)
|
||||
{
|
||||
delete[] values;
|
||||
return luaL_error(L, e.what());
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
|
||||
delete[] values;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _sendVectors(lua_State *L, PixelEffect *effect, const char *name, int count)
|
||||
static int _sendVectors(lua_State *L, Shader *shader, const char *name, int count)
|
||||
{
|
||||
size_t dimension = lua_objlen(L, 3);
|
||||
float *values = new float[count * dimension];
|
||||
@@ -93,46 +96,49 @@ static int _sendVectors(lua_State *L, PixelEffect *effect, const char *name, int
|
||||
for (size_t k = 1; k <= dimension; ++k)
|
||||
{
|
||||
lua_rawgeti(L, 3 + i, k);
|
||||
values[i * dimension + k - 1] = (float)lua_tonumber(L, -1);
|
||||
if (lua_isboolean(L, -1))
|
||||
values[i * dimension + k - 1] = (float)lua_toboolean(L, -1);
|
||||
else
|
||||
values[i * dimension + k - 1] = (float)lua_tonumber(L, -1);
|
||||
}
|
||||
lua_pop(L, int(dimension));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
effect->sendFloat(name, dimension, values, count);
|
||||
shader->sendFloat(name, dimension, values, count);
|
||||
}
|
||||
catch(love::Exception &e)
|
||||
{
|
||||
delete[] values;
|
||||
return luaL_error(L, e.what());
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
|
||||
delete[] values;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_PixelEffect_sendFloat(lua_State *L)
|
||||
int w_Shader_sendFloat(lua_State *L)
|
||||
{
|
||||
PixelEffect *effect = luax_checkpixeleffect(L, 1);
|
||||
Shader *shader = luax_checkshader(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
int count = lua_gettop(L) - 2;
|
||||
|
||||
if (count < 1)
|
||||
return luaL_error(L, "No variable to send.");
|
||||
|
||||
if (lua_isnumber(L, 3))
|
||||
return _sendScalars(L, effect, name, count);
|
||||
if (lua_isnumber(L, 3) || lua_isboolean(L, 3))
|
||||
return _sendScalars(L, shader, name, count);
|
||||
else if (lua_istable(L, 3))
|
||||
return _sendVectors(L, effect, name, count);
|
||||
return _sendVectors(L, shader, name, count);
|
||||
|
||||
return luaL_typerror(L, 3, "number or table");
|
||||
return luaL_typerror(L, 3, "number, boolean, or table");
|
||||
}
|
||||
|
||||
int w_PixelEffect_sendMatrix(lua_State *L)
|
||||
int w_Shader_sendMatrix(lua_State *L)
|
||||
{
|
||||
int count = lua_gettop(L) - 2;
|
||||
PixelEffect *effect = luax_checkpixeleffect(L, 1);
|
||||
Shader *shader = luax_checkshader(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
|
||||
if (!lua_istable(L, 3))
|
||||
@@ -174,49 +180,49 @@ int w_PixelEffect_sendMatrix(lua_State *L)
|
||||
|
||||
try
|
||||
{
|
||||
effect->sendMatrix(name, dimension, values, count);
|
||||
shader->sendMatrix(name, dimension, values, count);
|
||||
}
|
||||
catch(love::Exception &e)
|
||||
{
|
||||
delete[] values;
|
||||
return luaL_error(L, e.what());
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
|
||||
delete[] values;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_PixelEffect_sendImage(lua_State *L)
|
||||
int w_Shader_sendImage(lua_State *L)
|
||||
{
|
||||
PixelEffect *effect = luax_checkpixeleffect(L, 1);
|
||||
Shader *shader = luax_checkshader(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
Image *img = luax_checkimage(L, 3);
|
||||
|
||||
try
|
||||
{
|
||||
effect->sendImage(name, *img);
|
||||
shader->sendImage(name, *img);
|
||||
}
|
||||
catch(love::Exception &e)
|
||||
{
|
||||
luaL_error(L, e.what());
|
||||
luaL_error(L, "%s", e.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_PixelEffect_sendCanvas(lua_State *L)
|
||||
int w_Shader_sendCanvas(lua_State *L)
|
||||
{
|
||||
PixelEffect *effect = luax_checkpixeleffect(L, 1);
|
||||
Shader *shader = luax_checkshader(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
Canvas *canvas = luax_checkcanvas(L, 3);
|
||||
|
||||
try
|
||||
{
|
||||
effect->sendCanvas(name, *canvas);
|
||||
shader->sendCanvas(name, *canvas);
|
||||
}
|
||||
catch(love::Exception &e)
|
||||
{
|
||||
luaL_error(L, e.what());
|
||||
luaL_error(L, "%s", e.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -225,17 +231,17 @@ int w_PixelEffect_sendCanvas(lua_State *L)
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "getWarnings", w_PixelEffect_getWarnings },
|
||||
{ "sendFloat", w_PixelEffect_sendFloat },
|
||||
{ "sendMatrix", w_PixelEffect_sendMatrix },
|
||||
{ "sendImage", w_PixelEffect_sendImage },
|
||||
{ "sendCanvas", w_PixelEffect_sendCanvas },
|
||||
{ "getWarnings", w_Shader_getWarnings },
|
||||
{ "sendFloat", w_Shader_sendFloat },
|
||||
{ "sendMatrix", w_Shader_sendMatrix },
|
||||
{ "sendImage", w_Shader_sendImage },
|
||||
{ "sendCanvas", w_Shader_sendCanvas },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
extern "C" int luaopen_pixeleffect(lua_State *L)
|
||||
extern "C" int luaopen_shader(lua_State *L)
|
||||
{
|
||||
return luax_register_type(L, "PixelEffect", functions);
|
||||
return luax_register_type(L, "Shader", functions);
|
||||
}
|
||||
|
||||
} // opengl
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -22,7 +22,7 @@
|
||||
#define LOVE_GRAPHICS_OPENGL_WRAP_PROGRAM_H
|
||||
|
||||
#include "common/runtime.h"
|
||||
#include "PixelEffect.h"
|
||||
#include "Shader.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -31,12 +31,12 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
PixelEffect *luax_checkpixeleffect(lua_State *L, int idx);
|
||||
int w_PixelEffect_getWarnings(lua_State *L);
|
||||
int w_PixelEffect_sendFloat(lua_State *L);
|
||||
int w_PixelEffect_sendMatrix(lua_State *L);
|
||||
int w_PixelEffect_sendImage(lua_State *L);
|
||||
extern "C" int luaopen_pixeleffect(lua_State *L);
|
||||
Shader *luax_checkshader(lua_State *L, int idx);
|
||||
int w_Shader_getWarnings(lua_State *L);
|
||||
int w_Shader_sendFloat(lua_State *L);
|
||||
int w_Shader_sendMatrix(lua_State *L);
|
||||
int w_Shader_sendImage(lua_State *L);
|
||||
extern "C" int luaopen_shader(lua_State *L);
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -101,7 +101,6 @@ int w_SpriteBatch_setq(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int w_SpriteBatch_clear(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
@@ -185,6 +184,20 @@ int w_SpriteBatch_setColor(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_isEmpty(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
luax_pushboolean(L, t->isEmpty());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_isFull(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
luax_pushboolean(L, t->isFull());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "add", w_SpriteBatch_add },
|
||||
@@ -197,6 +210,8 @@ static const luaL_Reg functions[] =
|
||||
{ "setImage", w_SpriteBatch_setImage },
|
||||
{ "getImage", w_SpriteBatch_getImage },
|
||||
{ "setColor", w_SpriteBatch_setColor },
|
||||
{ "isEmpty", w_SpriteBatch_isEmpty },
|
||||
{ "isFull", w_SpriteBatch_isFull },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2012 LOVE Development Team
|
||||
* Copyright (c) 2006-2013 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -37,10 +37,13 @@ int w_SpriteBatch_addq(lua_State *L);
|
||||
int w_SpriteBatch_set(lua_State *L);
|
||||
int w_SpriteBatch_setq(lua_State *L);
|
||||
int w_SpriteBatch_clear(lua_State *L);
|
||||
int w_SpriteBatch_lock(lua_State *L);
|
||||
int w_SpriteBatch_unlock(lua_State *L);
|
||||
int w_SpriteBatch_bind(lua_State *L);
|
||||
int w_SpriteBatch_unbind(lua_State *L);
|
||||
int w_SpriteBatch_setImage(lua_State *L);
|
||||
int w_SpriteBatch_getImage(lua_State *L);
|
||||
int w_SpriteBatch_setColor(lua_State *L);
|
||||
int w_SpriteBatch_isEmpty(lua_State *L);
|
||||
int w_SpriteBatch_isFull(lua_State *L);
|
||||
|
||||
extern "C" int luaopen_spritebatch(lua_State *L);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user