Commits

Alex Szpakowski  committed b22aa07

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

  • Participants
  • Parent commits 2902c71

Comments (0)

Files changed (4)

 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

File src/modules/graphics/opengl/Graphics.cpp

 	PixelEffect *effect = NULL;
 	try
 	{
-		effect = new PixelEffect(code);
+		effect = new PixelEffect("", code);
 	}
 	catch(love::Exception &e)
 	{

File src/modules/graphics/opengl/PixelEffect.cpp

 	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();
 }
 
+GLuint PixelEffect::createShader(GLenum type, const std::string &code)
+{
+	const char *shadertypename = NULL;
+	switch (type)
+	{
+	case GL_VERTEX_SHADER:
+		shadertypename = "vertex";
+		break;
+	case GL_GEOMETRY_SHADER_ARB:
+		shadertypename = "geometry";
+	case GL_FRAGMENT_SHADER:
+	default:
+		shadertypename = "fragment";
+		break;
+	}
+	
+	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_status;
+	glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+	if (compile_status == GL_FALSE)
+	{
+		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);
+		
+		throw love::Exception("Cannot compile %s shader:\n%s", shadertypename, tmp.c_str());
+	}
+	
+	return 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;
+	glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
+	if (link_ok == GL_FALSE)
+	{
+		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;
+
+		glDeleteProgram(program);
+		
+		throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
+	}
+	
+	return program;
+}
+
 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)
+{	
+	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
 	{
-		glDeleteProgram(_program);
-		throw love::Exception("Cannot create shader object.");
+		_program = createProgram(shaders);
 	}
-
-	// 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)
+	catch (love::Exception &e)
 	{
-		// 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());
+		std::vector<GLuint>::iterator it;
+		for (it = shaders.begin(); it != shaders.end(); ++it)
+			glDeleteShader(*it);
+		
+		throw;
 	}
-
-	// 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);
+	
+	std::vector<GLuint>::iterator it;
+	for (it = shaders.begin(); it != shaders.end(); ++it)
+		glDeleteShader(*it);
 
 	return true;
 }
 
 void PixelEffect::unloadVolatile()
 {
-	glDeleteProgram(_program);
+	if (_program != 0)
+		glDeleteProgram(_program);
 }
 
 std::string PixelEffect::getGLSLVersion()

File src/modules/graphics/opengl/PixelEffect.h

 #include "common/Object.h"
 #include <string>
 #include <map>
+#include <vector>
 #include "OpenGL.h"
 #include "Image.h"
 #include "Canvas.h"
 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;
 
 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;