2012-03-15 10:42:22 +08:00
|
|
|
/****************************************************************************
|
|
|
|
Copyright 2011 Jeff Lamarche
|
|
|
|
Copyright 2012 Goffredo Marocchi
|
|
|
|
Copyright 2012 Ricardo Quesada
|
2014-01-07 11:25:07 +08:00
|
|
|
Copyright 2012 cocos2d-x.org
|
|
|
|
Copyright 2013-2014 Chukong Technologies Inc.
|
2012-03-15 10:42:22 +08:00
|
|
|
|
|
|
|
http://www.cocos2d-x.org
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN false EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
****************************************************************************/
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
#include "CCDirector.h"
|
2012-03-12 15:22:03 +08:00
|
|
|
#include "CCGLProgram.h"
|
2012-03-15 10:42:22 +08:00
|
|
|
#include "ccGLStateCache.h"
|
2012-03-12 15:22:03 +08:00
|
|
|
#include "ccMacros.h"
|
2012-06-19 16:20:46 +08:00
|
|
|
#include "platform/CCFileUtils.h"
|
2013-10-14 14:01:00 +08:00
|
|
|
#include "uthash.h"
|
|
|
|
#include "CCString.h"
|
2012-04-17 17:55:26 +08:00
|
|
|
// extern
|
|
|
|
#include "kazmath/GL/matrix.h"
|
2012-03-15 10:42:22 +08:00
|
|
|
#include "kazmath/kazmath.h"
|
2012-03-12 15:22:03 +08:00
|
|
|
|
|
|
|
NS_CC_BEGIN
|
|
|
|
|
2012-04-17 17:55:26 +08:00
|
|
|
typedef struct _hashUniformEntry
|
|
|
|
{
|
2012-11-13 11:06:32 +08:00
|
|
|
GLvoid* value; // value
|
2012-04-19 14:35:52 +08:00
|
|
|
unsigned int location; // Key
|
2012-11-13 11:06:32 +08:00
|
|
|
UT_hash_handle hh; // hash entry
|
2012-03-15 10:42:22 +08:00
|
|
|
} tHashUniformEntry;
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2013-07-25 17:48:22 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR = "ShaderPositionTextureColor";
|
2013-12-06 13:24:59 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP = "ShaderPositionTextureColor_noMVP";
|
2013-07-25 17:48:22 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST = "ShaderPositionTextureColorAlphaTest";
|
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_COLOR = "ShaderPositionColor";
|
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_TEXTURE = "ShaderPositionTexture";
|
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_TEXTURE_U_COLOR = "ShaderPositionTexture_uColor";
|
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_TEXTURE_A8_COLOR = "ShaderPositionTextureA8Color";
|
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_U_COLOR = "ShaderPosition_uColor";
|
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR = "ShaderPositionLengthTextureColor";
|
|
|
|
|
2013-12-13 12:42:15 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL = "ShaderLabelNormol";
|
|
|
|
const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_GLOW = "ShaderLabelGlow";
|
|
|
|
const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_OUTLINE = "ShaderLabelOutline";
|
|
|
|
const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_SHADOW = "ShaderLabelShadow";
|
|
|
|
|
|
|
|
|
2013-07-25 17:48:22 +08:00
|
|
|
// uniform names
|
|
|
|
const char* GLProgram::UNIFORM_NAME_P_MATRIX = "CC_PMatrix";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_MV_MATRIX = "CC_MVMatrix";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_MVP_MATRIX = "CC_MVPMatrix";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_TIME = "CC_Time";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_SIN_TIME = "CC_SinTime";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_COS_TIME = "CC_CosTime";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_RANDOM01 = "CC_Random01";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_SAMPLER = "CC_Texture0";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_ALPHA_TEST_VALUE = "CC_alpha_value";
|
|
|
|
|
|
|
|
// Attribute names
|
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_COLOR = "a_color";
|
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_POSITION = "a_position";
|
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_TEX_COORD = "a_texCoord";
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
GLProgram::GLProgram()
|
2013-06-15 14:03:30 +08:00
|
|
|
: _program(0)
|
|
|
|
, _vertShader(0)
|
|
|
|
, _fragShader(0)
|
2013-12-18 17:47:20 +08:00
|
|
|
, _hashForUniforms(nullptr)
|
2013-11-01 08:56:15 +08:00
|
|
|
, _flags()
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
memset(_uniforms, 0, sizeof(_uniforms));
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
GLProgram::~GLProgram()
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-08-22 11:05:06 +08:00
|
|
|
CCLOGINFO("%s %d deallocing GLProgram: %p", __FUNCTION__, __LINE__, this);
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
// there is no need to delete the shaders. They should have been already deleted.
|
2013-07-20 13:01:27 +08:00
|
|
|
CCASSERT(_vertShader == 0, "Vertex Shaders should have been already deleted");
|
|
|
|
CCASSERT(_fragShader == 0, "Fragment Shaders should have been already deleted");
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_program)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-07-26 09:42:53 +08:00
|
|
|
GL::deleteProgram(_program);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
tHashUniformEntry *current_element, *tmp;
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
// Purge uniform hash
|
2013-06-15 14:03:30 +08:00
|
|
|
HASH_ITER(hh, _hashForUniforms, current_element, tmp)
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
HASH_DEL(_hashForUniforms, current_element);
|
2012-04-19 14:35:52 +08:00
|
|
|
free(current_element->value);
|
|
|
|
free(current_element);
|
|
|
|
}
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
bool GLProgram::initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
_program = glCreateProgram();
|
2012-04-17 17:55:26 +08:00
|
|
|
CHECK_GL_ERROR_DEBUG();
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
_vertShader = _fragShader = 0;
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
if (vShaderByteArray)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
if (!compileShader(&_vertShader, GL_VERTEX_SHADER, vShaderByteArray))
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
CCLOG("cocos2d: ERROR: Failed to compile vertex shader");
|
|
|
|
}
|
|
|
|
}
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
// Create and compile fragment shader
|
2012-11-09 12:08:18 +08:00
|
|
|
if (fShaderByteArray)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
if (!compileShader(&_fragShader, GL_FRAGMENT_SHADER, fShaderByteArray))
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
CCLOG("cocos2d: ERROR: Failed to compile fragment shader");
|
|
|
|
}
|
|
|
|
}
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_vertShader)
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
glAttachShader(_program, _vertShader);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
CHECK_GL_ERROR_DEBUG();
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_fragShader)
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
glAttachShader(_program, _fragShader);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2013-12-18 17:47:20 +08:00
|
|
|
_hashForUniforms = nullptr;
|
2012-04-17 17:55:26 +08:00
|
|
|
|
|
|
|
CHECK_GL_ERROR_DEBUG();
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
return true;
|
2012-03-15 10:42:22 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
bool GLProgram::initWithVertexShaderFilename(const char* vShaderFilename, const char* fShaderFilename)
|
2012-03-15 10:42:22 +08:00
|
|
|
{
|
2013-12-25 11:00:27 +08:00
|
|
|
std::string vertexSource = FileUtils::getInstance()->getStringFromFile(FileUtils::getInstance()->fullPathForFilename(vShaderFilename).c_str());
|
|
|
|
std::string fragmentSource = FileUtils::getInstance()->getStringFromFile(FileUtils::getInstance()->fullPathForFilename(fShaderFilename).c_str());
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2013-12-25 11:00:27 +08:00
|
|
|
return initWithVertexShaderByteArray(vertexSource.c_str(), fragmentSource.c_str());
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-12-13 06:38:12 +08:00
|
|
|
std::string GLProgram::getDescription() const
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-12-25 11:00:27 +08:00
|
|
|
return StringUtils::format("<GLProgram = "
|
2013-04-19 17:56:27 +08:00
|
|
|
CC_FORMAT_PRINTF_SIZE_T
|
|
|
|
" | Program = %i, VertexShader = %i, FragmentShader = %i>",
|
2013-12-25 11:00:27 +08:00
|
|
|
(size_t)this, _program, _vertShader, _fragShader);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
bool GLProgram::compileShader(GLuint * shader, GLenum type, const GLchar* source)
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
|
|
|
GLint status;
|
2012-03-15 10:42:22 +08:00
|
|
|
|
2012-03-12 15:22:03 +08:00
|
|
|
if (!source)
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2012-03-12 15:22:03 +08:00
|
|
|
return false;
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const GLchar *sources[] = {
|
2012-11-16 18:12:01 +08:00
|
|
|
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_LINUX && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)
|
2012-11-09 12:08:18 +08:00
|
|
|
(type == GL_VERTEX_SHADER ? "precision highp float;\n" : "precision mediump float;\n"),
|
|
|
|
#endif
|
|
|
|
"uniform mat4 CC_PMatrix;\n"
|
|
|
|
"uniform mat4 CC_MVMatrix;\n"
|
|
|
|
"uniform mat4 CC_MVPMatrix;\n"
|
|
|
|
"uniform vec4 CC_Time;\n"
|
|
|
|
"uniform vec4 CC_SinTime;\n"
|
|
|
|
"uniform vec4 CC_CosTime;\n"
|
|
|
|
"uniform vec4 CC_Random01;\n"
|
|
|
|
"//CC INCLUDES END\n\n",
|
|
|
|
source,
|
|
|
|
};
|
2012-03-12 15:22:03 +08:00
|
|
|
|
|
|
|
*shader = glCreateShader(type);
|
2013-12-18 17:47:20 +08:00
|
|
|
glShaderSource(*shader, sizeof(sources)/sizeof(*sources), sources, nullptr);
|
2012-03-12 15:22:03 +08:00
|
|
|
glCompileShader(*shader);
|
|
|
|
|
|
|
|
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
|
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
if (! status)
|
|
|
|
{
|
|
|
|
GLsizei length;
|
|
|
|
glGetShaderiv(*shader, GL_SHADER_SOURCE_LENGTH, &length);
|
2012-11-16 17:08:34 +08:00
|
|
|
GLchar* src = (GLchar *)malloc(sizeof(GLchar) * length);
|
2012-11-09 12:08:18 +08:00
|
|
|
|
2013-12-18 17:47:20 +08:00
|
|
|
glGetShaderSource(*shader, length, nullptr, src);
|
2012-11-09 12:08:18 +08:00
|
|
|
CCLOG("cocos2d: ERROR: Failed to compile shader:\n%s", src);
|
|
|
|
|
|
|
|
if (type == GL_VERTEX_SHADER)
|
|
|
|
{
|
2013-12-11 22:35:37 +08:00
|
|
|
CCLOG("cocos2d: %s", getVertexShaderLog().c_str());
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
2012-04-19 14:35:52 +08:00
|
|
|
else
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2013-12-11 22:35:37 +08:00
|
|
|
CCLOG("cocos2d: %s", getFragmentShaderLog().c_str());
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
2012-11-16 17:08:34 +08:00
|
|
|
free(src);
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
abort();
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2012-11-13 11:06:32 +08:00
|
|
|
return (status == GL_TRUE);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::addAttribute(const char* attributeName, GLuint index)
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
glBindAttribLocation(_program, index, attributeName);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::updateUniforms()
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-07-25 17:48:22 +08:00
|
|
|
_uniforms[UNIFORM_P_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_P_MATRIX);
|
2013-11-01 08:56:15 +08:00
|
|
|
_uniforms[UNIFORM_MV_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MV_MATRIX);
|
|
|
|
_uniforms[UNIFORM_MVP_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MVP_MATRIX);
|
2012-11-09 12:08:18 +08:00
|
|
|
|
2013-11-01 08:56:15 +08:00
|
|
|
_uniforms[UNIFORM_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_TIME);
|
|
|
|
_uniforms[UNIFORM_SIN_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_SIN_TIME);
|
|
|
|
_uniforms[UNIFORM_COS_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_COS_TIME);
|
|
|
|
|
|
|
|
_uniforms[UNIFORM_RANDOM01] = glGetUniformLocation(_program, UNIFORM_NAME_RANDOM01);
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2013-07-25 17:48:22 +08:00
|
|
|
_uniforms[UNIFORM_SAMPLER] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER);
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2013-12-06 11:04:01 +08:00
|
|
|
_flags.usesP = _uniforms[UNIFORM_P_MATRIX] != -1;
|
|
|
|
_flags.usesMV = _uniforms[UNIFORM_MV_MATRIX] != -1;
|
2013-11-01 08:56:15 +08:00
|
|
|
_flags.usesMVP = _uniforms[UNIFORM_MVP_MATRIX] != -1;
|
|
|
|
_flags.usesTime = (
|
|
|
|
_uniforms[UNIFORM_TIME] != -1 ||
|
|
|
|
_uniforms[UNIFORM_SIN_TIME] != -1 ||
|
|
|
|
_uniforms[UNIFORM_COS_TIME] != -1
|
|
|
|
);
|
|
|
|
_flags.usesRandom = _uniforms[UNIFORM_RANDOM01] != -1;
|
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
this->use();
|
2012-11-09 12:08:18 +08:00
|
|
|
|
|
|
|
// Since sample most probably won't change, set it to 0 now.
|
2013-11-01 08:56:15 +08:00
|
|
|
this->setUniformLocationWith1i(_uniforms[UNIFORM_SAMPLER], 0);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
bool GLProgram::link()
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-07-20 13:01:27 +08:00
|
|
|
CCASSERT(_program != 0, "Cannot link invalid program");
|
2012-11-09 12:08:18 +08:00
|
|
|
|
|
|
|
GLint status = GL_TRUE;
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
glLinkProgram(_program);
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_vertShader)
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
glDeleteShader(_vertShader);
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_fragShader)
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
glDeleteShader(_fragShader);
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
_vertShader = _fragShader = 0;
|
2012-11-09 12:08:18 +08:00
|
|
|
|
2013-07-17 12:53:30 +08:00
|
|
|
#if COCOS2D_DEBUG
|
2013-06-15 14:03:30 +08:00
|
|
|
glGetProgramiv(_program, GL_LINK_STATUS, &status);
|
2012-11-09 12:08:18 +08:00
|
|
|
|
|
|
|
if (status == GL_FALSE)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCLOG("cocos2d: ERROR: Failed to link program: %i", _program);
|
2013-07-26 09:42:53 +08:00
|
|
|
GL::deleteProgram(_program);
|
2013-06-15 14:03:30 +08:00
|
|
|
_program = 0;
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (status == GL_TRUE);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::use()
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-07-26 09:42:53 +08:00
|
|
|
GL::useProgram(_program);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-12-11 22:35:37 +08:00
|
|
|
std::string GLProgram::logForOpenGLObject(GLuint object, GLInfoFunction infoFunc, GLLogFunction logFunc) const
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-12-11 22:35:37 +08:00
|
|
|
std::string ret;
|
2012-03-12 15:22:03 +08:00
|
|
|
GLint logLength = 0, charsWritten = 0;
|
|
|
|
|
|
|
|
infoFunc(object, GL_INFO_LOG_LENGTH, &logLength);
|
|
|
|
if (logLength < 1)
|
2013-12-11 22:35:37 +08:00
|
|
|
return "";
|
2012-03-12 15:22:03 +08:00
|
|
|
|
|
|
|
char *logBytes = (char*)malloc(logLength);
|
|
|
|
logFunc(object, logLength, &charsWritten, logBytes);
|
|
|
|
|
2013-12-11 22:35:37 +08:00
|
|
|
ret = logBytes;
|
2012-03-12 15:22:03 +08:00
|
|
|
|
|
|
|
free(logBytes);
|
2013-12-11 22:35:37 +08:00
|
|
|
return ret;
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-12-11 22:35:37 +08:00
|
|
|
std::string GLProgram::getVertexShaderLog() const
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
return this->logForOpenGLObject(_vertShader, (GLInfoFunction)&glGetShaderiv, (GLLogFunction)&glGetShaderInfoLog);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-12-11 22:35:37 +08:00
|
|
|
std::string GLProgram::getFragmentShaderLog() const
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
return this->logForOpenGLObject(_fragShader, (GLInfoFunction)&glGetShaderiv, (GLLogFunction)&glGetShaderInfoLog);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2013-12-11 22:35:37 +08:00
|
|
|
std::string GLProgram::getProgramLog() const
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
return this->logForOpenGLObject(_program, (GLInfoFunction)&glGetProgramiv, (GLLogFunction)&glGetProgramInfoLog);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2012-04-17 17:55:26 +08:00
|
|
|
// Uniform cache
|
|
|
|
|
2013-12-07 09:42:16 +08:00
|
|
|
bool GLProgram::updateUniformLocation(GLint location, const GLvoid* data, unsigned int bytes)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-11-09 12:08:18 +08:00
|
|
|
if (location < 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
bool updated = true;
|
2013-12-18 17:47:20 +08:00
|
|
|
tHashUniformEntry *element = nullptr;
|
2013-06-15 14:03:30 +08:00
|
|
|
HASH_FIND_INT(_hashForUniforms, &location, element);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
if (! element)
|
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
element = (tHashUniformEntry*)malloc( sizeof(*element) );
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
// key
|
|
|
|
element->location = location;
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
// value
|
|
|
|
element->value = malloc( bytes );
|
|
|
|
memcpy(element->value, data, bytes );
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
HASH_ADD_INT(_hashForUniforms, location, element);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-09 12:08:18 +08:00
|
|
|
if (memcmp(element->value, data, bytes) == 0)
|
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
updated = false;
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
2012-04-19 14:35:52 +08:00
|
|
|
else
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
|
|
|
memcpy(element->value, data, bytes);
|
|
|
|
}
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
return updated;
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-07-07 13:01:21 +08:00
|
|
|
GLint GLProgram::getUniformLocationForName(const char* name) const
|
2013-02-27 09:38:30 +08:00
|
|
|
{
|
2013-12-18 17:47:20 +08:00
|
|
|
CCASSERT(name != nullptr, "Invalid uniform name" );
|
2013-07-20 13:01:27 +08:00
|
|
|
CCASSERT(_program != 0, "Invalid operation. Cannot get uniform location when program is not initialized");
|
2013-02-27 09:38:30 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
return glGetUniformLocation(_program, name);
|
2013-02-27 09:38:30 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith1i(GLint location, GLint i1)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
bool updated = updateUniformLocation(location, &i1, sizeof(i1)*1);
|
2013-03-27 02:20:38 +08:00
|
|
|
|
|
|
|
if( updated )
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
glUniform1i( (GLint)location, i1);
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith2i(GLint location, GLint i1, GLint i2)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
GLint ints[2] = {i1,i2};
|
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(ints));
|
|
|
|
|
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform2i( (GLint)location, i1, i2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith3i(GLint location, GLint i1, GLint i2, GLint i3)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
GLint ints[3] = {i1,i2,i3};
|
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(ints));
|
|
|
|
|
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform3i( (GLint)location, i1, i2, i3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith4i(GLint location, GLint i1, GLint i2, GLint i3, GLint i4)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
GLint ints[4] = {i1,i2,i3,i4};
|
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(ints));
|
|
|
|
|
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform4i( (GLint)location, i1, i2, i3, i4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith2iv(GLint location, GLint* ints, unsigned int numberOfArrays)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(int)*2*numberOfArrays);
|
|
|
|
|
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform2iv( (GLint)location, (GLsizei)numberOfArrays, ints );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith3iv(GLint location, GLint* ints, unsigned int numberOfArrays)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(int)*3*numberOfArrays);
|
|
|
|
|
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform3iv( (GLint)location, (GLsizei)numberOfArrays, ints );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith4iv(GLint location, GLint* ints, unsigned int numberOfArrays)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(int)*4*numberOfArrays);
|
|
|
|
|
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform4iv( (GLint)location, (GLsizei)numberOfArrays, ints );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith1f(GLint location, GLfloat f1)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
bool updated = updateUniformLocation(location, &f1, sizeof(f1)*1);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform1f( (GLint)location, f1);
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith2f(GLint location, GLfloat f1, GLfloat f2)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
GLfloat floats[2] = {f1,f2};
|
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform2f( (GLint)location, f1, f2);
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith3f(GLint location, GLfloat f1, GLfloat f2, GLfloat f3)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
GLfloat floats[3] = {f1,f2,f3};
|
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform3f( (GLint)location, f1, f2, f3);
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformLocationWith4f(GLint location, GLfloat f1, GLfloat f2, GLfloat f3, GLfloat f4)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
GLfloat floats[4] = {f1,f2,f3,f4};
|
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform4f( (GLint)location, f1, f2, f3,f4);
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-12-07 09:42:16 +08:00
|
|
|
void GLProgram::setUniformLocationWith2fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(float)*2*numberOfArrays);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform2fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-12-07 09:42:16 +08:00
|
|
|
void GLProgram::setUniformLocationWith3fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(float)*3*numberOfArrays);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform3fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-12-07 09:42:16 +08:00
|
|
|
void GLProgram::setUniformLocationWith4fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(float)*4*numberOfArrays);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniform4fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-12-07 09:42:16 +08:00
|
|
|
void GLProgram::setUniformLocationWithMatrix2fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices) {
|
2013-10-28 00:58:57 +08:00
|
|
|
bool updated = updateUniformLocation(location, matrixArray, sizeof(float)*4*numberOfMatrices);
|
|
|
|
|
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniformMatrix2fv( (GLint)location, (GLsizei)numberOfMatrices, GL_FALSE, matrixArray);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-07 09:42:16 +08:00
|
|
|
void GLProgram::setUniformLocationWithMatrix3fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices) {
|
2013-10-28 00:58:57 +08:00
|
|
|
bool updated = updateUniformLocation(location, matrixArray, sizeof(float)*9*numberOfMatrices);
|
|
|
|
|
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniformMatrix3fv( (GLint)location, (GLsizei)numberOfMatrices, GL_FALSE, matrixArray);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2013-12-07 09:42:16 +08:00
|
|
|
void GLProgram::setUniformLocationWithMatrix4fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
bool updated = updateUniformLocation(location, matrixArray, sizeof(float)*16*numberOfMatrices);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
if( updated )
|
|
|
|
{
|
|
|
|
glUniformMatrix4fv( (GLint)location, (GLsizei)numberOfMatrices, GL_FALSE, matrixArray);
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::setUniformsForBuiltins()
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2012-11-09 12:08:18 +08:00
|
|
|
kmMat4 matrixMV;
|
2013-12-07 09:42:16 +08:00
|
|
|
kmGLGetMatrix(KM_GL_MODELVIEW, &matrixMV);
|
|
|
|
|
|
|
|
setUniformsForBuiltins(matrixMV);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLProgram::setUniformsForBuiltins(const kmMat4 &matrixMV)
|
|
|
|
{
|
|
|
|
kmMat4 matrixP;
|
2013-11-01 08:56:15 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
kmGLGetMatrix(KM_GL_PROJECTION, &matrixP);
|
2013-11-01 08:56:15 +08:00
|
|
|
|
2013-12-06 11:04:01 +08:00
|
|
|
if(_flags.usesP)
|
2013-12-06 13:24:59 +08:00
|
|
|
setUniformLocationWithMatrix4fv(_uniforms[UNIFORM_P_MATRIX], matrixP.mat, 1);
|
2013-12-06 11:04:01 +08:00
|
|
|
|
|
|
|
if(_flags.usesMV)
|
|
|
|
setUniformLocationWithMatrix4fv(_uniforms[UNIFORM_MV_MATRIX], matrixMV.mat, 1);
|
|
|
|
|
2013-11-01 08:56:15 +08:00
|
|
|
if(_flags.usesMVP) {
|
|
|
|
kmMat4 matrixMVP;
|
|
|
|
kmMat4Multiply(&matrixMVP, &matrixP, &matrixMV);
|
|
|
|
setUniformLocationWithMatrix4fv(_uniforms[UNIFORM_MVP_MATRIX], matrixMVP.mat, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_flags.usesTime) {
|
2013-07-12 06:24:23 +08:00
|
|
|
Director *director = Director::getInstance();
|
2012-11-09 12:08:18 +08:00
|
|
|
// This doesn't give the most accurate global time value.
|
|
|
|
// Cocos2D doesn't store a high precision time value, so this will have to do.
|
|
|
|
// Getting Mach time per frame per shader using time could be extremely expensive.
|
|
|
|
float time = director->getTotalFrames() * director->getAnimationInterval();
|
|
|
|
|
2013-07-25 17:48:22 +08:00
|
|
|
setUniformLocationWith4f(_uniforms[GLProgram::UNIFORM_TIME], time/10.0, time, time*2, time*4);
|
|
|
|
setUniformLocationWith4f(_uniforms[GLProgram::UNIFORM_SIN_TIME], time/8.0, time/4.0, time/2.0, sinf(time));
|
|
|
|
setUniformLocationWith4f(_uniforms[GLProgram::UNIFORM_COS_TIME], time/8.0, time/4.0, time/2.0, cosf(time));
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
|
|
|
|
2013-11-01 08:56:15 +08:00
|
|
|
if(_flags.usesRandom)
|
2013-07-25 17:48:22 +08:00
|
|
|
setUniformLocationWith4f(_uniforms[GLProgram::UNIFORM_RANDOM01], CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1());
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void GLProgram::reset()
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
_vertShader = _fragShader = 0;
|
|
|
|
memset(_uniforms, 0, sizeof(_uniforms));
|
2012-04-17 17:55:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
// it is already deallocated by android
|
2013-07-26 09:42:53 +08:00
|
|
|
//GL::deleteProgram(_program);
|
2013-06-15 14:03:30 +08:00
|
|
|
_program = 0;
|
2012-04-17 17:55:26 +08:00
|
|
|
|
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
tHashUniformEntry *current_element, *tmp;
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
// Purge uniform hash
|
2013-06-15 14:03:30 +08:00
|
|
|
HASH_ITER(hh, _hashForUniforms, current_element, tmp)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
HASH_DEL(_hashForUniforms, current_element);
|
2012-04-19 14:35:52 +08:00
|
|
|
free(current_element->value);
|
|
|
|
free(current_element);
|
|
|
|
}
|
2013-12-18 17:47:20 +08:00
|
|
|
_hashForUniforms = nullptr;
|
2012-03-15 10:42:22 +08:00
|
|
|
}
|
2012-03-12 15:22:03 +08:00
|
|
|
|
|
|
|
NS_CC_END
|