added C++side support for combinations of vertex and fragment shaders in pixeleffects

This commit is contained in:
Alexander Szpakowski
2012-12-20 03:42:48 -04:00
parent a8dc813258
commit 28e3b105e9
4 changed files with 117 additions and 52 deletions
+2 -1
View File
@@ -22,7 +22,8 @@ glob:*.lib
glob:*.ncb
glob:*.exe
glob:*.bat
glob:platform/macosx/build
glob:platform/macosx/build
glob:platform/macosx/DerivedData
glob:platform/macosx/love.xcodeproj/bill*
glob:platform/macosx/love.xcodeproj/xcuserdata
glob:platform/macosx/love.xcodeproj/project.xcworkspace
+1 -1
View File
@@ -455,7 +455,7 @@ PixelEffect *Graphics::newPixelEffect(const std::string &code)
PixelEffect *effect = NULL;
try
{
effect = new PixelEffect(code);
effect = new PixelEffect("", code);
}
catch(love::Exception &e)
{
+107 -48
View File
@@ -69,72 +69,130 @@ GLint PixelEffect::getTextureUnit(const std::string &name)
return _current_texture_unit;
}
PixelEffect::PixelEffect(const std::string &code)
PixelEffect::PixelEffect(const std::string &vertcode, const std::string &fragcode)
: _program(0)
, _code(code)
, _vertcode(vertcode)
, _fragcode(fragcode)
{
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &_max_texture_units);
loadVolatile();
}
bool PixelEffect::loadVolatile()
GLuint PixelEffect::createShader(GLenum type, const std::string &code)
{
_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)
const char *shadertypename = NULL;
switch (type)
{
glDeleteProgram(_program);
throw love::Exception("Cannot create shader object.");
case GL_VERTEX_SHADER:
shadertypename = "vertex";
break;
case GL_GEOMETRY_SHADER_ARB:
shadertypename = "geometry";
case GL_FRAGMENT_SHADER:
default:
shadertypename = "fragment";
break;
}
// compile fragment shader code
const char *src = _code.c_str();
GLint strlen = _code.length();
glShaderSource(shader, 1, (const GLchar **)&src, &strlen);
GLuint shader = glCreateShader(type);
if (shader == 0) // should only fail when called 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(shader, 1, (const GLchar **)&src, (GLint *)&srclen);
glCompileShader(shader);
GLint compile_ok;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_ok);
if (GL_FALSE == compile_ok)
GLint compile_status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
if (compile_status == GL_FALSE)
{
// 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;
GLint infologlen;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologlen);
GLchar *errorlog = new GLchar[infologlen + 1];
glGetShaderInfoLog(shader, infologlen, NULL, errorlog);
std::string tmp(errorlog);
delete[] errorlog;
glDeleteShader(shader);
glDeleteProgram(_program);
// XXX: errorlog may contain escape sequences.
throw love::Exception("Cannot compile shader:\n%s", tmp.c_str());
throw love::Exception("Cannot compile %s shader:\n%s", shadertypename, tmp.c_str());
}
return shader;
}
// link fragment shader
GLuint PixelEffect::createProgram(const std::vector<GLuint> &shaders)
{
GLuint 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 = shaders.begin(); it != shaders.end(); ++it)
glAttachShader(program, *it);
glLinkProgram(program);
for (it = shaders.begin(); it != shaders.end(); ++it)
glDetachShader(program, *it);
GLint link_ok;
glAttachShader(_program, shader);
glLinkProgram(_program);
glGetProgramiv(_program, GL_LINK_STATUS, &link_ok);
if (GL_FALSE == link_ok)
glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
if (link_ok == GL_FALSE)
{
// this should not happen if compiling is ok, but one can never be too careful
// get linker error
std::string tmp(getWarnings());
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;
// cleanup before throw
glDeleteShader(shader);
glDeleteProgram(_program);
throw love::Exception("Cannot compile shader:\n%s", tmp.c_str());
glDeleteProgram(program);
throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
}
return program;
}
glDeleteShader(shader);
bool PixelEffect::loadVolatile()
{
std::vector<GLuint> shaders;
if (_vertcode.length() > 0)
shaders.push_back(createShader(GL_VERTEX_SHADER, _vertcode));
if (_fragcode.length() > 0)
shaders.push_back(createShader(GL_FRAGMENT_SHADER, _fragcode));
if (shaders.size() == 0)
throw love::Exception("Cannot create PixelEffect: no source code!");
try
{
_program = createProgram(shaders);
}
catch (love::Exception &e)
{
std::vector<GLuint>::iterator it;
for (it = shaders.begin(); it != shaders.end(); ++it)
glDeleteShader(*it);
throw;
}
std::vector<GLuint>::iterator it;
for (it = shaders.begin(); it != shaders.end(); ++it)
glDeleteShader(*it);
return true;
}
@@ -146,7 +204,8 @@ PixelEffect::~PixelEffect()
void PixelEffect::unloadVolatile()
{
glDeleteProgram(_program);
if (_program != 0)
glDeleteProgram(_program);
}
std::string PixelEffect::getGLSLVersion()
+7 -2
View File
@@ -24,6 +24,7 @@
#include "common/Object.h"
#include <string>
#include <map>
#include <vector>
#include "OpenGL.h"
#include "Image.h"
#include "Canvas.h"
@@ -38,7 +39,7 @@ namespace opengl
class PixelEffect : public Object, public Volatile
{
public:
PixelEffect(const std::string &code);
PixelEffect(const std::string &vertcode, const std::string &fragcode);
virtual ~PixelEffect();
std::string getWarnings() const;
@@ -60,8 +61,12 @@ public:
private:
GLint getUniformLocation(const std::string &name);
void checkSetUniformError();
GLuint createShader(GLenum type, const std::string &code);
GLuint createProgram(const std::vector<GLuint> &shaders);
GLuint _program;
std::string _code; // volatile and stuff
std::string _vertcode;
std::string _fragcode; // volatile and stuff
// uniform location buffer
std::map<std::string, GLint> _uniforms;