Source

love-openzdk / src / modules / graphics / opengl2 / Shader.cpp

/**
* Copyright (c) 2006-2010 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.
**/

// C++
#include <cassert>

// OpenGL
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

// LOVE
#include "GLUtilities.h"
#include "Shader.h"

namespace love
{
namespace graphics
{
namespace opengl2
{
	Shader::Shader(Domain domain, Format format, const void * data, size_t length)
		: shaderId(0), domain(domain), format(format)
	{
		// Sort out our arguments
		assert(data);
		assert(length > 0);
		if (!isLoadable(format))
			throw love::Exception("The specified shader is not loadable on this system");
		GLenum gltype = 0;
		if (domain == DOMAIN_VERTEX)
			gltype = GL_VERTEX_SHADER;
		else if (domain == DOMAIN_FRAGMENT)
			gltype = GL_FRAGMENT_SHADER;
		else
			assert(0);
		GLenum glformat = 0;
		if (format == FORMAT_SOURCE_GLSL)
			glformat = 0;
#if LOVE_GL2_TARGET_ES2
		else if (format == FORMAT_BINARY_TEGRA)
			glformat = GL_NVIDIA_PLATFORM_BINARY_NV;
#endif
		else
			assert(0);

		// Load 'er up
		LGLErrorResetD();
		GLuint id = glCreateShader(gltype);
		GLint successful = GL_FALSE;
#if LOVE_GL2_TARGET_ES2
		if (glformat != 0)
		{
			glShaderBinary(1, &id, format, data, length);
			successful = GL_TRUE;
		}
		else
#endif
		{
			GLint len = (GLint)length;
			glShaderSource(id, 1, (const char **)&data, &len);
			glCompileShader(id);
			glGetShaderiv(id, GL_COMPILE_STATUS, &successful);
		}

		// Finish up and store the shader ID
		LGLErrorCheckD();
		if (!successful)
		{
			glDeleteShader(id);
			throw love::Exception("An error was encountered when compiling the shader");
		}
		shaderId = id;

		// Initialize the shader's reference count
		refCount = new unsigned int(1);
	}

	Shader::Shader(const Shader & src) :
		shaderId(src.shaderId), domain(src.domain), format(src.format)
	{
		// Increment the reference count for the underlying shader
		refCount = &++*src.refCount;
	}

	Shader::Domain Shader::getDomain() const
	{
		return domain;
	}

	Shader::Format Shader::getFormat() const
	{
		return format;
	}

	bool Shader::isLoadable(Format format)
	{
		if (format == FORMAT_BINARY_TEGRA)
		{
#if LOVE_GL2_TARGET_ES2
#if LOVE_ZUNEHD
			// The Zune HD's compositor has a broken glGet, and this is always true
			return true;
#else
			// Test if we support NVIDIA Tegra binary shaders
			GLboolean nvShadersSupported = GL_FALSE;
			GLint nFormats = 0;
			glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats);
			if (nFormats > 0)
			{
				GLint * formats = (GLint *)alloca(sizeof(GLint) * nFormats);
				glGetIntegerv(GL_SHADER_BINARY_FORMATS, formats);
				for (GLint i = 0; i < nFormats; ++i)
				{
					if (formats[i] == GL_NVIDIA_PLATFORM_BINARY_NV)
						return true;
				}
			}
#endif // LOVE_ZUNEHD
#endif // LOVE_GL2_TARGET_ES2
		}
		else if (format == FORMAT_SOURCE_GLSL)
		{	
#if LOVE_ZUNEHD
			// The Zune HD's compositor has a broken glGet, and this is always false
			return false;
#else
			// Test if we support GLSL source shaders
			GLboolean glslShadersSupported = GL_FALSE;
			glGetBooleanv(GL_SHADER_COMPILER, &glslShadersSupported);
			if (glslShadersSupported)
				return true;
#endif // LOVE_ZUNEHD
		}
		return false;
	}

	Shader & Shader::operator=(const Shader & src)
	{
		// Decrement the ref count on this shader and transfer over the new one
		if (refCount != src.refCount)
		{
			if (--*refCount <= 0)
				this->~Shader();
			shaderId = src.shaderId;
			domain = src.domain;
			format = src.format;
			refCount = &++*src.refCount;
		}
		return *this;
	}

	Shader::~Shader()
	{
		// Delete the OpenGL shader object if the reference count hits zero
		if (--*refCount <= 0)
		{
			glDeleteShader(shaderId);
			delete refCount;
		}
	}

} // opengl2
} // graphics
} // love
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.