Merged rude/love into default

This commit is contained in:
Alex Szpakowski
2013-01-29 11:25:38 -04:00
33 changed files with 46813 additions and 26202 deletions
+2 -1
View File
@@ -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 -1
View File
@@ -87,7 +87,7 @@ public:
{
SUPPORT_CANVAS = 1,
SUPPORT_HDR_CANVAS,
SUPPORT_PIXELEFFECT,
SUPPORT_SHADER,
SUPPORT_NPOT,
SUPPORT_SUBTRACTIVE,
SUPPORT_MIPMAP,
+1 -2
View File
@@ -30,7 +30,6 @@
#include "common/math.h"
#include "common/Matrix.h"
#include "OpenGL.h"
#include "GLee.h"
namespace love
{
@@ -98,7 +97,7 @@ public:
static void bindDefaultCanvas();
private:
friend class PixelEffect;
friend class Shader;
GLuint getTextureName() const
{
return img;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+19 -19
View File
@@ -45,8 +45,6 @@ Graphics::Graphics()
, userMatrices(0)
{
currentWindow = love::window::sdl::Window::getSingleton();
resetBoundTexture();
}
Graphics::~Graphics()
@@ -116,6 +114,8 @@ bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int f
// Unload all volatile objects. These must be reloaded after
// the display mode change.
Volatile::unloadAll();
uninitializeContext();
bool success = currentWindow->setWindow(width, height, fullscreen, vsync, fsaa);
// Regardless of failure, we'll have to set up OpenGL once again.
@@ -125,6 +125,8 @@ bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int f
// Okay, setup OpenGL.
initializeContext();
// Enable blending
glEnable(GL_BLEND);
@@ -138,6 +140,7 @@ bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int f
// Enable textures
glEnable(GL_TEXTURE_2D);
setActiveTextureUnit(0);
// Set the viewport to top-left corner
glViewport(0, 0, width, height);
@@ -190,7 +193,7 @@ void Graphics::reset()
DisplayState s;
discardStencil();
Canvas::bindDefaultCanvas();
PixelEffect::detach();
Shader::detach();
restoreState(s);
}
@@ -450,20 +453,21 @@ 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;
Shader *shader = NULL;
try
{
effect = new PixelEffect(code);
shader = new Shader(sources);
}
catch(love::Exception &e)
catch(love::Exception &)
{
if (effect)
delete effect;
throw(e);
if (shader)
delete shader;
throw;
}
return effect;
return shader;
}
void Graphics::setColor(const Color &c)
@@ -743,11 +747,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:
@@ -941,7 +944,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);
@@ -951,7 +954,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;
@@ -1035,12 +1037,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;
@@ -1059,12 +1060,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);
}
}
+3 -4
View File
@@ -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"
namespace love
{
@@ -271,7 +270,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.
+2 -4
View File
@@ -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;
+145 -9
View File
@@ -18,7 +18,10 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
#include <vector>
#include <algorithm>
#include "OpenGL.h"
#include "common/Exception.h"
namespace love
{
@@ -27,33 +30,160 @@ 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;
textureUnits.clear();
// initialize multiple texture unit support, if available
if (GLEE_VERSION_1_3 || GLEE_ARB_multitexture)
{
GLint maxtextureunits;
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxtextureunits);
// shaders/GL2.0 added "Texture Image Units." Total max texture units is the greater of the two
if (GLEE_VERSION_2_0 || GLEE_ARB_vertex_shader)
{
GLint maxtextureimageunits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureimageunits);
maxtextureunits = std::max(maxtextureunits, maxtextureimageunits);
}
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)
{
if (GLEE_VERSION_1_3)
glActiveTexture(GL_TEXTURE0 + i);
else
glActiveTextureARB(GL_TEXTURE0 + i);
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &textureUnits[i]);
}
if (GLEE_VERSION_1_3)
glActiveTexture(curgltextureunit);
else
glActiveTextureARB(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]);
}
// 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)
{
initializeContext();
if (textureunit < 0 || (size_t) textureunit >= textureUnits.size())
throw love::Exception("Invalid texture unit index (%d).", textureunit);
if (textureunit != curTextureUnit)
{
boundTexture = texture;
if (GLEE_VERSION_1_3)
glActiveTexture(GL_TEXTURE0 + textureunit);
else if (GLEE_ARB_multitexture)
glActiveTextureARB(GL_TEXTURE0 + textureunit);
else
throw love::Exception("Multitexturing not supported.");
}
curTextureUnit = textureunit;
}
void bindTexture(GLuint texture)
{
initializeContext();
if (texture != textureUnits[curTextureUnit])
{
textureUnits[curTextureUnit] = texture;
glBindTexture(GL_TEXTURE_2D, texture);
}
}
void bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev)
{
initializeContext();
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;
initializeContext();
// 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);
}
void setTextureFilter(const graphics::Image::Filter &f)
{
initializeContext();
GLint gmin, gmag;
if (f.mipmap == Image::FILTER_NONE)
@@ -95,6 +225,8 @@ void setTextureFilter(const graphics::Image::Filter &f)
graphics::Image::Filter getTextureFilter()
{
initializeContext();
GLint gmin, gmag;
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin);
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag);
@@ -144,6 +276,8 @@ graphics::Image::Filter getTextureFilter()
void setTextureWrap(const graphics::Image::Wrap &w)
{
initializeContext();
GLint gs, gt;
switch (w.s)
@@ -174,6 +308,8 @@ void setTextureWrap(const graphics::Image::Wrap &w)
graphics::Image::Wrap getTextureWrap()
{
initializeContext();
GLint gs, gt;
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs);
+32 -14
View File
@@ -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();
@@ -22,7 +22,7 @@
#include "common/math.h"
#include "GLee.h"
#include "OpenGL.h"
#include <cmath>
#include <cstdlib>
-346
View File
@@ -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
-80
View File
@@ -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
+2 -2
View File
@@ -21,8 +21,8 @@
#include "Quad.h"
#include "common/Matrix.h"
// GLee
#include "GLee.h"
// OpenGL
#include "OpenGL.h"
// STD
#include <cstring> // For memcpy
+455
View File
@@ -0,0 +1,455 @@
/**
* 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 <algorithm>
#include "Shader.h"
#include "Graphics.h"
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
+159
View File
@@ -0,0 +1,159 @@
/**
* 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_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
+6 -1
View File
@@ -23,6 +23,9 @@
// STD
#include <iostream>
// OpenGL
#include "OpenGL.h"
// LOVE
#include "Image.h"
#include "Quad.h"
@@ -222,7 +225,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();
}
@@ -34,9 +34,6 @@
#include "graphics/Volatile.h"
#include "graphics/Color.h"
// OpenGL
#include "GLee.h"
namespace love
{
namespace graphics
+1 -1
View File
@@ -26,7 +26,7 @@
#include "graphics/Volatile.h"
// OpenGL
#include "GLee.h"
#include "OpenGL.h"
namespace love
{
+48 -27
View File
@@ -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"
@@ -433,29 +433,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);
}
@@ -798,26 +819,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);
@@ -845,8 +866,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:
@@ -1265,7 +1286,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 },
@@ -1296,8 +1317,8 @@ 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 },
@@ -1358,7 +1379,7 @@ static const lua_CFunction types[] =
luaopen_spritebatch,
luaopen_particlesystem,
luaopen_canvas,
luaopen_pixeleffect,
luaopen_shader,
0
};
+4 -3
View File
@@ -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,7 +90,8 @@ 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);
@@ -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
@@ -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
+3
View File
@@ -63,6 +63,8 @@ Window::_currentMode::_currentMode()
bool Window::setWindow(int width, int height, bool fullscreen, bool vsync, int fsaa)
{
bool mouseVisible = getMouseVisible();
int keyrepeatDelay, keyrepeatInterval;
SDL_GetKeyRepeat(&keyrepeatDelay, &keyrepeatInterval);
// We need to restart the subsystem for two reasons:
// 1) Special case for fullscreen -> windowed. Windows XP did not
@@ -87,6 +89,7 @@ bool Window::setWindow(int width, int height, bool fullscreen, bool vsync, int f
// Set caption.
setWindowTitle(windowTitle);
setMouseVisible(mouseVisible);
SDL_EnableKeyRepeat(keyrepeatDelay, keyrepeatInterval);
// Set GL attributes
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);