Commits

Anonymous committed da5c460

Add missing files

  • Participants
  • Parent commits f468ee7

Comments (0)

Files changed (5)

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

+#include "PixelEffect.h"
+#include "GLee.h"
+#include <limits>
+#include <sstream>
+#include <iostream>
+
+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
+{
+	std::map<std::string, GLint> PixelEffect::_texture_unit_pool;
+	GLint PixelEffect::_current_texture_unit = 0;
+	GLint PixelEffect::_max_texture_units = 0;
+
+	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;
+
+		if (++_current_texture_unit >= _max_texture_units)
+			throw love::Exception("No more texture units available");
+
+		_texture_unit_pool[name] = _current_texture_unit;
+		return _current_texture_unit;
+	}
+
+
+	PixelEffect::PixelEffect(const std::string& code)
+		: _program(0), _code(code)
+	{
+		glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &_max_texture_units);
+		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::stringstream error_message;
+			error_message << "Cannot compile shader:" << std::endl << std::string(error_str);
+
+			// cleanup before throw
+			delete[] error_str;
+			glDeleteShader(shader);
+			glDeleteProgram(_program);
+			throw love::Exception(error_message.str().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::stringstream error_message;
+			error_message << "Cannot compile shader:" << std::endl << getWarnings();
+
+			// cleanup before throw
+			glDeleteShader(shader);
+			glDeleteProgram(_program);
+			throw love::Exception(error_message.str().c_str());
+		}
+
+		glDeleteShader(shader);
+		return true;
+	}
+
+	PixelEffect::~PixelEffect()
+	{
+		unloadVolatile();
+	}
+
+	void PixelEffect::unloadVolatile()
+	{
+		glDeleteProgram(_program);
+	}
+
+	bool PixelEffect::isSupported()
+	{
+		return GLEE_VERSION_2_0 && GLEE_ARB_shader_objects && GLEE_ARB_fragment_shader;
+	}
+
+	std::string PixelEffect::getWarnings() const
+	{
+		GLint strlen;
+		glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &strlen);
+		char *temp_str = new char[strlen];
+		glGetProgramInfoLog(_program, strlen, NULL, temp_str);
+
+		std::string warnings(temp_str);
+		delete[] temp_str;
+		return warnings;
+	}
+
+	void PixelEffect::attach()
+	{
+		glUseProgram(_program);
+	}
+
+	void PixelEffect::detach()
+	{
+		glUseProgram(0);
+	}
+
+	void PixelEffect::sendFloat(const std::string& name, int count, const GLfloat* vec)
+	{
+		TemporaryAttacher attacher(this);
+		GLint location = getUniformLocation(name);
+
+		if (count < 1 || count > 4) {
+			throw love::Exception("Invalid variable count: %d (expected 1-4).", count);
+		}
+
+		switch (count) {
+			case 4:
+				glUniform4fv(location, 1, vec);
+				break;
+			case 3:
+				glUniform3fv(location, 1, vec);
+				break;
+			case 2:
+				glUniform2fv(location, 1, vec);
+				break;
+			case 1:
+			default:
+				glUniform1fv(location, 1, vec);
+				break;
+		}
+
+		// throw error if needed
+		checkSetUniformError();
+	}
+
+	void PixelEffect::sendMatrix(const std::string& name, int size, const GLfloat* m)
+	{
+		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, 1, GL_FALSE, m);
+				break;
+			case 3:
+				glUniformMatrix3fv(location, 1, GL_FALSE, m);
+				break;
+			case 2:
+			default:
+				glUniformMatrix2fv(location, 1, 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);
+		glBindTexture(GL_TEXTURE_2D, image.getTextureName());
+		glUniform1i(location, texture_unit);
+
+		// reset texture unit
+		glActiveTexture(GL_TEXTURE0);
+
+		// throw error if needed
+		checkSetUniformError();
+	}
+
+	void PixelEffect::sendFramebuffer(const std::string& name, const Framebuffer& fb)
+	{
+		GLint texture_unit = getTextureUnit(name);
+
+		TemporaryAttacher attacher(this);
+		GLint location = getUniformLocation(name);
+
+		glActiveTexture(GL_TEXTURE0 + texture_unit);
+		glBindTexture(GL_TEXTURE_2D, fb.getTextureName());
+		glUniform1i(location, texture_unit);
+
+		// reset texture unit
+		glActiveTexture(GL_TEXTURE0);
+
+		// throw error if needed
+		checkSetUniformError();
+	}
+
+	GLint PixelEffect::getUniformLocation(const std::string& name)
+	{
+		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());
+		}
+		return location;
+	}
+
+	void PixelEffect::checkSetUniformError()
+	{
+		GLenum error_code = glGetError();
+		if (GL_INVALID_OPERATION == error_code) {
+			throw love::Exception(
+				"Invalid operation:\n"
+				"Trying to send more than one value to a float variable, or"
+				"Size of shader variable does not match indicated size, or"
+				"Invalid variable name.");
+		}
+	}
+} // opengl
+} // graphics
+} // love

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

+#ifndef LOVE_GRAPHICS_EFFECT_H
+#define LOVE_GRAPHICS_EFFECT_H
+
+#include <common/Object.h>
+#include <string>
+#include <map>
+#include "Image.h"
+#include "Framebuffer.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+	// A fragment shader
+	class PixelEffect : public Volatile // 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 bool isSupported();
+
+		void sendFloat(const std::string& name, int count, const GLfloat* vec);
+		void sendMatrix(const std::string& name, int size, const GLfloat* m);
+		void sendImage(const std::string& name, const Image& image);
+		void sendFramebuffer(const std::string& name, const Framebuffer& fb);
+
+	private:
+		GLint getUniformLocation(const std::string& name);
+		void checkSetUniformError();
+		GLuint _program;
+		std::string _code; // volatile and stuff
+
+		// texture unit pool for setting images
+		static std::map<std::string, GLint> _texture_unit_pool;
+		static GLint _current_texture_unit;
+		static GLint _max_texture_units;
+		static GLint getTextureUnit(const std::string& name);
+	};
+
+} // opengl
+} // graphics
+} // love
+
+#endif // LOVE_GRAPHICS_EFFECT_H

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

 #include <font/Rasterizer.h>
 
 #include <scripts/graphics.lua.h>
-#include "GLInfo.h"
 
 namespace love
 {

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

+#include "wrap_PixelEffect.h"
+#include "wrap_Image.h"
+#include "wrap_Framebuffer.h"
+#include <string>
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+	PixelEffect * luax_checkpixeleffect(lua_State * L, int idx)
+	{
+		return luax_checktype<PixelEffect>(L, idx, "PixelEffect", GRAPHICS_PIXELEFFECT_T);
+	}
+
+	int w_PixelEffect_getWarnings(lua_State * L)
+	{
+		PixelEffect * effect = luax_checkpixeleffect(L, 1);
+		lua_pushstring(L, effect->getWarnings().c_str());
+		return 1;
+	}
+
+	int w_PixelEffect_sendFloat(lua_State * L)
+	{
+		size_t count = lua_gettop(L) - 2;
+		PixelEffect * effect = luax_checkpixeleffect(L, 1);
+		const char* name = luaL_checkstring(L, 2);
+
+		if (count < 1 || count > 4)
+			return luaL_error(L, "Invalid variable count (expected 1-4, got %d).", count);
+
+		float values[4] = {0,0,0,0};
+		for (int i = 0; i < count; ++i)
+			values[i] = luaL_checknumber(L, i+1 + 2);
+
+		try {
+			effect->sendFloat(name, count, values);
+		} catch(love::Exception& e) {
+			luaL_error(L, e.what());
+		}
+
+		return 0;
+	}
+
+	int w_PixelEffect_sendMatrix(lua_State * L)
+	{
+		size_t count = lua_gettop(L) - 3;
+		PixelEffect * effect = luax_checkpixeleffect(L, 1);
+		const char* name = luaL_checkstring(L, 2);
+		int size = luaL_checkinteger(L, 3);
+
+		if (size < 2 || size > 4)
+			return luaL_error(L, "Invalid matrix size: %dx%d (only 2x2, 3x3 and 4x4 matrices are supported).", count, count);
+
+		float values[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+		for (int i = 0; i < count; ++i)
+			values[i] = luaL_checknumber(L, i+1 + 3);
+
+		try {
+			effect->sendFloat(name, size, values);
+		} catch(love::Exception& e) {
+			luaL_error(L, e.what());
+		}
+
+		return 0;
+	}
+
+	int w_PixelEffect_sendImage(lua_State * L)
+	{
+		PixelEffect * effect = luax_checkpixeleffect(L, 1);
+		const char* name = luaL_checkstring(L, 2);
+		Image* img = luax_checkimage(L, 3);
+
+		try {
+			effect->sendImage(name, *img);
+		} catch(love::Exception& e) {
+			luaL_error(L, e.what());
+		}
+
+		return 0;
+	}
+
+	int w_PixelEffect_sendFramebuffer(lua_State * L)
+	{
+		PixelEffect * effect = luax_checkpixeleffect(L, 1);
+		const char* name = luaL_checkstring(L, 2);
+		Framebuffer* fb = luax_checkfbo(L, 3);
+
+		try {
+			effect->sendFramebuffer(name, *fb);
+		} catch(love::Exception& e) {
+			luaL_error(L, e.what());
+		}
+
+		return 0;
+	}
+
+
+	static const luaL_Reg functions[] = {
+		{ "getWarnings",     w_PixelEffect_getWarnings },
+		{ "sendFloat",       w_PixelEffect_sendFloat },
+		{ "sendMatrix",      w_PixelEffect_sendMatrix },
+		{ "sendImage",       w_PixelEffect_sendImage },
+		{ "sendFramebuffer", w_PixelEffect_sendFramebuffer },
+		{ 0, 0 }
+	};
+
+	int luaopen_pixeleffect(lua_State * L)
+	{
+		return luax_register_type(L, "PixelEffect", functions);
+	}
+
+} // opengl
+} // graphics
+} // love
+

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

+#ifndef LOVE_GRAPHICS_OPENGL_WRAP_PROGRAM_H
+#define LOVE_GRAPHICS_OPENGL_WRAP_PROGRAM_H
+
+#include <common/runtime.h>
+#include "PixelEffect.h"
+
+namespace love
+{
+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);
+	int luaopen_pixeleffect(lua_State * L);
+} // opengl
+} // graphics
+} // love
+
+#endif