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
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2012-03-15 10:42:22 +08:00
|
|
|
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
|
|
|
|
2014-05-09 09:01:48 +08:00
|
|
|
#include "renderer/CCGLProgram.h"
|
2014-05-10 04:24:56 +08:00
|
|
|
|
|
|
|
#ifndef WIN32
|
2014-05-07 08:58:14 +08:00
|
|
|
#include <alloca.h>
|
2014-05-10 04:24:56 +08:00
|
|
|
#endif
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2014-05-17 05:36:00 +08:00
|
|
|
#include "base/CCDirector.h"
|
2016-06-15 15:01:26 +08:00
|
|
|
#include "base/ccUTF8.h"
|
2014-05-17 05:36:00 +08:00
|
|
|
#include "base/uthash.h"
|
|
|
|
#include "renderer/ccGLStateCache.h"
|
|
|
|
#include "platform/CCFileUtils.h"
|
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
// helper functions
|
|
|
|
|
|
|
|
static void replaceDefines(const std::string& compileTimeDefines, std::string& out)
|
|
|
|
{
|
|
|
|
// Replace semicolons with '#define ... \n'
|
2016-03-07 22:05:20 +08:00
|
|
|
if (!compileTimeDefines.empty())
|
2015-05-06 04:07:32 +08:00
|
|
|
{
|
2016-04-07 04:27:59 +08:00
|
|
|
// append ';' if the last char doesn't have one
|
|
|
|
auto copyDefines = compileTimeDefines;
|
|
|
|
if (copyDefines[copyDefines.length()-1] != ';')
|
|
|
|
copyDefines.append(1, ';');
|
|
|
|
|
2016-03-07 22:05:20 +08:00
|
|
|
std::string currentDefine;
|
2016-04-07 04:27:59 +08:00
|
|
|
|
|
|
|
for (auto itChar: copyDefines)
|
2015-05-06 04:07:32 +08:00
|
|
|
{
|
2016-03-07 22:05:20 +08:00
|
|
|
if (itChar == ';')
|
|
|
|
{
|
|
|
|
if (!currentDefine.empty())
|
|
|
|
{
|
|
|
|
out.append("\n#define " + currentDefine);
|
|
|
|
currentDefine.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentDefine.append(1, itChar);
|
|
|
|
}
|
2015-05-06 04:07:32 +08:00
|
|
|
}
|
|
|
|
out += "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-22 20:58:07 +08:00
|
|
|
|
2012-03-12 15:22:03 +08:00
|
|
|
NS_CC_BEGIN
|
2016-07-25 17:31:54 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_ETC1AS_POSITION_TEXTURE_COLOR = "#ShaderETC1ASPositionTextureColor";
|
|
|
|
const char* GLProgram::SHADER_NAME_ETC1AS_POSITION_TEXTURE_COLOR_NO_MVP = "#ShaderETC1ASPositionTextureColor_noMVP";
|
|
|
|
|
|
|
|
const char* GLProgram::SHADER_NAME_ETC1AS_POSITION_TEXTURE_GRAY = "#ShaderETC1ASPositionTextureGray";
|
|
|
|
const char* GLProgram::SHADER_NAME_ETC1AS_POSITION_TEXTURE_GRAY_NO_MVP = "#ShaderETC1ASPositionTextureGray_noMVP";
|
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";
|
2014-03-10 15:12:44 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST_NO_MV = "ShaderPositionTextureColorAlphaTest_NoMV";
|
2013-07-25 17:48:22 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_COLOR = "ShaderPositionColor";
|
2015-01-20 16:50:51 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_COLOR_TEXASPOINTSIZE = "ShaderPositionColorTexAsPointsize";
|
2014-01-07 22:08:00 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_COLOR_NO_MVP = "ShaderPositionColor_noMVP";
|
2015-03-21 14:50:48 +08:00
|
|
|
|
2013-07-25 17:48:22 +08:00
|
|
|
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";
|
2015-04-20 17:00:40 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_POSITION_GRAYSCALE = "ShaderUIGrayScale";
|
2014-03-21 09:47:29 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL = "ShaderLabelDFNormal";
|
2014-03-20 20:56:10 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_GLOW = "ShaderLabelDFGlow";
|
|
|
|
const char* GLProgram::SHADER_NAME_LABEL_NORMAL = "ShaderLabelNormal";
|
2014-03-05 16:51:16 +08:00
|
|
|
const char* GLProgram::SHADER_NAME_LABEL_OUTLINE = "ShaderLabelOutline";
|
2013-12-13 12:42:15 +08:00
|
|
|
|
2014-05-19 05:49:16 +08:00
|
|
|
const char* GLProgram::SHADER_3D_POSITION = "Shader3DPosition";
|
|
|
|
const char* GLProgram::SHADER_3D_POSITION_TEXTURE = "Shader3DPositionTexture";
|
2014-06-05 16:36:01 +08:00
|
|
|
const char* GLProgram::SHADER_3D_SKINPOSITION_TEXTURE = "Shader3DSkinPositionTexture";
|
2014-08-21 11:33:00 +08:00
|
|
|
const char* GLProgram::SHADER_3D_POSITION_NORMAL = "Shader3DPositionNormal";
|
|
|
|
const char* GLProgram::SHADER_3D_POSITION_NORMAL_TEXTURE = "Shader3DPositionNormalTexture";
|
|
|
|
const char* GLProgram::SHADER_3D_SKINPOSITION_NORMAL_TEXTURE = "Shader3DSkinPositionNormalTexture";
|
2015-11-25 10:45:03 +08:00
|
|
|
const char* GLProgram::SHADER_3D_POSITION_BUMPEDNORMAL_TEXTURE = "Shader3DPositionBumpedNormalTexture";
|
|
|
|
const char* GLProgram::SHADER_3D_SKINPOSITION_BUMPEDNORMAL_TEXTURE = "Shader3DSkinPositionBumpedNormalTexture";
|
2015-02-11 18:14:22 +08:00
|
|
|
const char* GLProgram::SHADER_3D_PARTICLE_COLOR = "Shader3DParticleColor";
|
|
|
|
const char* GLProgram::SHADER_3D_PARTICLE_TEXTURE = "Shader3DParticleTexture";
|
2015-03-26 11:59:26 +08:00
|
|
|
const char* GLProgram::SHADER_3D_SKYBOX = "Shader3DSkybox";
|
2015-03-30 13:45:50 +08:00
|
|
|
const char* GLProgram::SHADER_3D_TERRAIN = "Shader3DTerrain";
|
2015-05-07 15:09:06 +08:00
|
|
|
const char* GLProgram::SHADER_CAMERA_CLEAR = "ShaderCameraClear";
|
2014-05-19 05:49:16 +08:00
|
|
|
|
2013-12-13 12:42:15 +08:00
|
|
|
|
2013-07-25 17:48:22 +08:00
|
|
|
// uniform names
|
2014-08-18 17:10:07 +08:00
|
|
|
const char* GLProgram::UNIFORM_NAME_AMBIENT_COLOR = "CC_AmbientColor";
|
2013-07-25 17:48:22 +08:00
|
|
|
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";
|
2014-08-15 19:15:14 +08:00
|
|
|
const char* GLProgram::UNIFORM_NAME_NORMAL_MATRIX = "CC_NormalMatrix";
|
2013-07-25 17:48:22 +08:00
|
|
|
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";
|
2014-05-14 09:12:58 +08:00
|
|
|
const char* GLProgram::UNIFORM_NAME_SAMPLER0 = "CC_Texture0";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_SAMPLER1 = "CC_Texture1";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_SAMPLER2 = "CC_Texture2";
|
|
|
|
const char* GLProgram::UNIFORM_NAME_SAMPLER3 = "CC_Texture3";
|
2013-07-25 17:48:22 +08:00
|
|
|
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";
|
2014-08-18 18:02:58 +08:00
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_TEX_COORD1 = "a_texCoord1";
|
2014-08-21 18:14:24 +08:00
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_TEX_COORD2 = "a_texCoord2";
|
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_TEX_COORD3 = "a_texCoord3";
|
2014-05-09 03:34:26 +08:00
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_NORMAL = "a_normal";
|
2014-06-04 18:17:09 +08:00
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_BLEND_WEIGHT = "a_blendWeight";
|
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_BLEND_INDEX = "a_blendIndex";
|
2015-11-25 10:45:03 +08:00
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_TANGENT = "a_tangent";
|
|
|
|
const char* GLProgram::ATTRIBUTE_NAME_BINORMAL = "a_binormal";
|
|
|
|
|
|
|
|
|
2014-03-25 16:54:29 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
static const char * COCOS2D_SHADER_UNIFORMS =
|
|
|
|
"uniform mat4 CC_PMatrix;\n"
|
|
|
|
"uniform mat4 CC_MVMatrix;\n"
|
|
|
|
"uniform mat4 CC_MVPMatrix;\n"
|
|
|
|
"uniform mat3 CC_NormalMatrix;\n"
|
|
|
|
"uniform vec4 CC_Time;\n"
|
|
|
|
"uniform vec4 CC_SinTime;\n"
|
|
|
|
"uniform vec4 CC_CosTime;\n"
|
|
|
|
"uniform vec4 CC_Random01;\n"
|
|
|
|
"uniform sampler2D CC_Texture0;\n"
|
|
|
|
"uniform sampler2D CC_Texture1;\n"
|
|
|
|
"uniform sampler2D CC_Texture2;\n"
|
|
|
|
"uniform sampler2D CC_Texture3;\n"
|
|
|
|
"//CC INCLUDES END\n\n";
|
|
|
|
|
|
|
|
static const std::string EMPTY_DEFINE;
|
|
|
|
|
2014-05-08 05:38:41 +08:00
|
|
|
GLProgram* GLProgram::createWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)
|
2015-05-06 04:07:32 +08:00
|
|
|
{
|
|
|
|
return createWithByteArrays(vShaderByteArray, fShaderByteArray, EMPTY_DEFINE);
|
|
|
|
}
|
|
|
|
|
|
|
|
GLProgram* GLProgram::createWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray, const std::string& compileTimeDefines)
|
2014-05-08 05:38:41 +08:00
|
|
|
{
|
|
|
|
auto ret = new (std::nothrow) GLProgram();
|
2015-05-06 04:07:32 +08:00
|
|
|
if(ret && ret->initWithByteArrays(vShaderByteArray, fShaderByteArray, compileTimeDefines)) {
|
2014-05-09 07:04:59 +08:00
|
|
|
ret->link();
|
|
|
|
ret->updateUniforms();
|
2014-05-08 05:38:41 +08:00
|
|
|
ret->autorelease();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(ret);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
|
2014-05-08 05:38:41 +08:00
|
|
|
GLProgram* GLProgram::createWithFilenames(const std::string& vShaderFilename, const std::string& fShaderFilename)
|
2015-05-06 04:07:32 +08:00
|
|
|
{
|
|
|
|
return createWithFilenames(vShaderFilename, fShaderFilename, EMPTY_DEFINE);
|
|
|
|
}
|
|
|
|
|
|
|
|
GLProgram* GLProgram::createWithFilenames(const std::string& vShaderFilename, const std::string& fShaderFilename, const std::string& compileTimeDefines)
|
2014-05-08 05:38:41 +08:00
|
|
|
{
|
|
|
|
auto ret = new (std::nothrow) GLProgram();
|
2015-05-06 04:07:32 +08:00
|
|
|
if(ret && ret->initWithFilenames(vShaderFilename, fShaderFilename, compileTimeDefines)) {
|
2014-05-09 07:04:59 +08:00
|
|
|
ret->link();
|
|
|
|
ret->updateUniforms();
|
2014-05-08 05:38:41 +08:00
|
|
|
ret->autorelease();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(ret);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
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-11-01 08:56:15 +08:00
|
|
|
, _flags()
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2014-12-04 18:37:57 +08:00
|
|
|
_director = Director::getInstance();
|
|
|
|
CCASSERT(nullptr != _director, "Director is null when init a GLProgram");
|
2014-05-14 09:12:58 +08:00
|
|
|
memset(_builtInUniforms, 0, sizeof(_builtInUniforms));
|
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
|
|
|
|
2015-11-17 13:38:42 +08:00
|
|
|
clearShader();
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2015-04-20 17:00:40 +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
|
|
|
|
2014-10-21 17:29:24 +08:00
|
|
|
for (auto e : _hashForUniforms)
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2015-01-26 18:40:00 +08:00
|
|
|
free(e.second.first);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2014-10-21 17:29:24 +08:00
|
|
|
_hashForUniforms.clear();
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2014-03-05 05:51:43 +08:00
|
|
|
bool GLProgram::initWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2015-05-06 04:07:32 +08:00
|
|
|
return initWithByteArrays(vShaderByteArray, fShaderByteArray, EMPTY_DEFINE);
|
|
|
|
}
|
2014-03-22 20:58:07 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
bool GLProgram::initWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray, const std::string& compileTimeDefines)
|
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
|
|
|
|
2016-03-29 09:52:17 +08:00
|
|
|
// convert defines here. If we do it in "compileShader" we will do it twice.
|
2015-05-06 04:07:32 +08:00
|
|
|
// a cache for the defines could be useful, but seems like overkill at this point
|
|
|
|
std::string replacedDefines = "";
|
|
|
|
replaceDefines(compileTimeDefines, replacedDefines);
|
|
|
|
|
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)
|
|
|
|
{
|
2015-05-06 04:07:32 +08:00
|
|
|
if (!compileShader(&_vertShader, GL_VERTEX_SHADER, vShaderByteArray, replacedDefines))
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
CCLOG("cocos2d: ERROR: Failed to compile vertex shader");
|
2014-04-28 09:51:10 +08:00
|
|
|
return false;
|
2014-03-22 20:58:07 +08:00
|
|
|
}
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
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)
|
|
|
|
{
|
2015-05-06 04:07:32 +08:00
|
|
|
if (!compileShader(&_fragShader, GL_FRAGMENT_SHADER, fShaderByteArray, replacedDefines))
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
CCLOG("cocos2d: ERROR: Failed to compile fragment shader");
|
2014-04-28 09:51:10 +08:00
|
|
|
return false;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2014-10-21 17:29:24 +08:00
|
|
|
_hashForUniforms.clear();
|
2015-04-20 17:00:40 +08:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
bool GLProgram::initWithFilenames(const std::string& vShaderFilename, const std::string& fShaderFilename)
|
2014-03-22 20:58:07 +08:00
|
|
|
{
|
2015-05-06 04:07:32 +08:00
|
|
|
return initWithFilenames(vShaderFilename, fShaderFilename, EMPTY_DEFINE);
|
2014-03-22 20:58:07 +08:00
|
|
|
}
|
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
bool GLProgram::initWithFilenames(const std::string& vShaderFilename, const std::string& fShaderFilename, const std::string& compileTimeDefines)
|
2012-03-15 10:42:22 +08:00
|
|
|
{
|
2014-03-05 05:51:43 +08:00
|
|
|
auto fileUtils = FileUtils::getInstance();
|
|
|
|
std::string vertexSource = fileUtils->getStringFromFile(FileUtils::getInstance()->fullPathForFilename(vShaderFilename));
|
|
|
|
std::string fragmentSource = fileUtils->getStringFromFile(FileUtils::getInstance()->fullPathForFilename(fShaderFilename));
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
return initWithByteArrays(vertexSource.c_str(), fragmentSource.c_str(), compileTimeDefines);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2014-05-09 03:34:26 +08:00
|
|
|
void GLProgram::bindPredefinedVertexAttribs()
|
|
|
|
{
|
|
|
|
static const struct {
|
|
|
|
const char *attributeName;
|
|
|
|
int location;
|
|
|
|
} attribute_locations[] =
|
|
|
|
{
|
|
|
|
{GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION},
|
|
|
|
{GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR},
|
|
|
|
{GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD},
|
2014-08-18 18:02:58 +08:00
|
|
|
{GLProgram::ATTRIBUTE_NAME_TEX_COORD1, GLProgram::VERTEX_ATTRIB_TEX_COORD1},
|
2014-08-21 18:14:24 +08:00
|
|
|
{GLProgram::ATTRIBUTE_NAME_TEX_COORD2, GLProgram::VERTEX_ATTRIB_TEX_COORD2},
|
|
|
|
{GLProgram::ATTRIBUTE_NAME_TEX_COORD3, GLProgram::VERTEX_ATTRIB_TEX_COORD3},
|
2014-05-09 03:34:26 +08:00
|
|
|
{GLProgram::ATTRIBUTE_NAME_NORMAL, GLProgram::VERTEX_ATTRIB_NORMAL},
|
|
|
|
};
|
|
|
|
|
|
|
|
const int size = sizeof(attribute_locations) / sizeof(attribute_locations[0]);
|
|
|
|
|
|
|
|
for(int i=0; i<size;i++) {
|
|
|
|
glBindAttribLocation(_program, attribute_locations[i].location, attribute_locations[i].attributeName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-07 08:58:14 +08:00
|
|
|
void GLProgram::parseVertexAttribs()
|
2014-05-07 02:03:24 +08:00
|
|
|
{
|
2015-06-16 14:04:50 +08:00
|
|
|
//_vertexAttribs.clear();
|
2014-05-07 02:03:24 +08:00
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
// Query and store vertex attribute meta-data from the program.
|
|
|
|
GLint activeAttributes;
|
|
|
|
GLint length;
|
|
|
|
glGetProgramiv(_program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
|
|
|
|
if(activeAttributes > 0)
|
|
|
|
{
|
2014-05-07 08:58:14 +08:00
|
|
|
VertexAttrib attribute;
|
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
glGetProgramiv(_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length);
|
|
|
|
if(length > 0)
|
|
|
|
{
|
|
|
|
GLchar* attribName = (GLchar*) alloca(length + 1);
|
2014-05-07 08:58:14 +08:00
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
for(int i = 0; i < activeAttributes; ++i)
|
|
|
|
{
|
|
|
|
// Query attribute info.
|
|
|
|
glGetActiveAttrib(_program, i, length, nullptr, &attribute.size, &attribute.type, attribName);
|
|
|
|
attribName[length] = '\0';
|
2014-05-09 05:01:03 +08:00
|
|
|
attribute.name = std::string(attribName);
|
2014-05-07 08:58:14 +08:00
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
// Query the pre-assigned attribute location
|
|
|
|
attribute.index = glGetAttribLocation(_program, attribName);
|
2014-05-14 09:12:58 +08:00
|
|
|
_vertexAttribs[attribute.name] = attribute;
|
2014-08-15 19:15:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-15 12:15:56 +08:00
|
|
|
else
|
|
|
|
{
|
2014-11-20 11:41:16 +08:00
|
|
|
GLchar ErrorLog[1024];
|
2016-05-25 02:09:11 +08:00
|
|
|
glGetProgramInfoLog(_program, sizeof(ErrorLog), nullptr, ErrorLog);
|
2014-11-20 11:41:16 +08:00
|
|
|
CCLOG("Error linking shader program: '%s'\n", ErrorLog);
|
2014-11-15 12:15:56 +08:00
|
|
|
}
|
2014-05-07 08:58:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLProgram::parseUniforms()
|
|
|
|
{
|
2015-06-16 14:04:50 +08:00
|
|
|
//_userUniforms.clear();
|
2014-05-07 02:19:51 +08:00
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
// Query and store uniforms from the program.
|
|
|
|
GLint activeUniforms;
|
|
|
|
glGetProgramiv(_program, GL_ACTIVE_UNIFORMS, &activeUniforms);
|
|
|
|
if(activeUniforms > 0)
|
|
|
|
{
|
2014-05-07 08:58:14 +08:00
|
|
|
GLint length;
|
2014-08-15 19:15:14 +08:00
|
|
|
glGetProgramiv(_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &length);
|
|
|
|
if(length > 0)
|
|
|
|
{
|
2014-05-07 08:58:14 +08:00
|
|
|
Uniform uniform;
|
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
GLchar* uniformName = (GLchar*)alloca(length + 1);
|
2014-05-07 08:58:14 +08:00
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
for(int i = 0; i < activeUniforms; ++i)
|
|
|
|
{
|
|
|
|
// Query uniform info.
|
|
|
|
glGetActiveUniform(_program, i, length, nullptr, &uniform.size, &uniform.type, uniformName);
|
|
|
|
uniformName[length] = '\0';
|
2014-05-08 11:20:19 +08:00
|
|
|
|
2014-05-13 14:51:37 +08:00
|
|
|
// Only add uniforms that are not built-in.
|
2014-05-08 11:20:19 +08:00
|
|
|
// The ones that start with 'CC_' are built-ins
|
|
|
|
if(strncmp("CC_", uniformName, 3) != 0) {
|
|
|
|
|
|
|
|
// remove possible array '[]' from uniform name
|
2014-10-13 15:17:22 +08:00
|
|
|
if(length > 3)
|
2014-05-08 11:20:19 +08:00
|
|
|
{
|
|
|
|
char* c = strrchr(uniformName, '[');
|
|
|
|
if(c)
|
|
|
|
{
|
|
|
|
*c = '\0';
|
|
|
|
}
|
|
|
|
}
|
2014-05-08 11:38:15 +08:00
|
|
|
uniform.name = std::string(uniformName);
|
|
|
|
uniform.location = glGetUniformLocation(_program, uniformName);
|
2015-04-20 17:00:40 +08:00
|
|
|
GLenum __gl_error_code = glGetError();
|
|
|
|
if (__gl_error_code != GL_NO_ERROR)
|
|
|
|
{
|
2016-03-07 22:05:20 +08:00
|
|
|
CCLOG("error: 0x%x uniformName: %s", (int)__gl_error_code, uniformName);
|
2015-04-20 17:00:40 +08:00
|
|
|
}
|
2014-06-10 19:53:06 +08:00
|
|
|
assert(__gl_error_code == GL_NO_ERROR);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2014-05-14 09:12:58 +08:00
|
|
|
_userUniforms[uniform.name] = uniform;
|
2014-05-08 11:20:19 +08:00
|
|
|
}
|
2014-08-15 19:15:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-15 12:15:56 +08:00
|
|
|
else
|
|
|
|
{
|
2014-11-20 11:41:16 +08:00
|
|
|
GLchar ErrorLog[1024];
|
2016-05-25 02:09:11 +08:00
|
|
|
glGetProgramInfoLog(_program, sizeof(ErrorLog), nullptr, ErrorLog);
|
2014-11-20 11:41:16 +08:00
|
|
|
CCLOG("Error linking shader program: '%s'\n", ErrorLog);
|
|
|
|
|
2014-11-15 12:15:56 +08:00
|
|
|
}
|
|
|
|
|
2014-05-07 02:03:24 +08:00
|
|
|
}
|
|
|
|
|
2014-05-08 01:44:45 +08:00
|
|
|
Uniform* GLProgram::getUniform(const std::string &name)
|
2014-05-07 02:03:24 +08:00
|
|
|
{
|
2014-05-14 09:12:58 +08:00
|
|
|
const auto itr = _userUniforms.find(name);
|
|
|
|
if( itr != _userUniforms.end())
|
2014-05-08 01:44:45 +08:00
|
|
|
return &itr->second;
|
2014-05-07 08:58:14 +08:00
|
|
|
return nullptr;
|
2014-05-07 02:03:24 +08:00
|
|
|
}
|
|
|
|
|
2014-05-07 08:58:14 +08:00
|
|
|
VertexAttrib* GLProgram::getVertexAttrib(const std::string &name)
|
2014-05-07 02:19:51 +08:00
|
|
|
{
|
2014-05-14 09:12:58 +08:00
|
|
|
const auto itr = _vertexAttribs.find(name);
|
|
|
|
if( itr != _vertexAttribs.end())
|
2014-05-07 08:58:14 +08:00
|
|
|
return &itr->second;
|
|
|
|
return nullptr;
|
2014-05-07 02:19:51 +08:00
|
|
|
}
|
2014-05-07 02:03:24 +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)
|
2015-05-06 04:07:32 +08:00
|
|
|
{
|
|
|
|
return compileShader(shader, type, source, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GLProgram::compileShader(GLuint* shader, GLenum type, const GLchar* source, const std::string& convertedDefines)
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
|
|
|
GLint status;
|
2015-04-20 17:00:40 +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
|
|
|
}
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
const GLchar *sources[] = {
|
2014-10-23 22:13:38 +08:00
|
|
|
#if CC_TARGET_PLATFORM == CC_PLATFORM_WINRT
|
|
|
|
(type == GL_VERTEX_SHADER ? "precision mediump float;\n precision mediump int;\n" : "precision mediump float;\n precision mediump int;\n"),
|
|
|
|
#elif (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_LINUX && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)
|
2014-08-26 14:25:01 +08:00
|
|
|
(type == GL_VERTEX_SHADER ? "precision highp float;\n precision highp int;\n" : "precision mediump float;\n precision mediump int;\n"),
|
2012-11-09 12:08:18 +08:00
|
|
|
#endif
|
2015-05-06 04:07:32 +08:00
|
|
|
COCOS2D_SHADER_UNIFORMS,
|
|
|
|
convertedDefines.c_str(),
|
|
|
|
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;
|
2014-04-28 09:51:10 +08:00
|
|
|
glGetShaderiv(*shader, GL_SHADER_SOURCE_LENGTH, &length);
|
|
|
|
GLchar* src = (GLchar *)malloc(sizeof(GLchar) * length);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2014-04-28 09:51:10 +08:00
|
|
|
glGetShaderSource(*shader, length, nullptr, src);
|
|
|
|
CCLOG("cocos2d: ERROR: Failed to compile shader:\n%s", src);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
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
|
|
|
|
2016-03-07 22:05:20 +08:00
|
|
|
return false;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2016-03-07 22:05:20 +08:00
|
|
|
|
2012-11-13 11:06:32 +08:00
|
|
|
return (status == GL_TRUE);
|
2012-03-12 15:22:03 +08:00
|
|
|
}
|
|
|
|
|
2014-05-07 08:58:14 +08:00
|
|
|
GLint GLProgram::getAttribLocation(const std::string &attributeName) const
|
2014-03-05 05:51:43 +08:00
|
|
|
{
|
2014-05-07 08:58:14 +08:00
|
|
|
return glGetAttribLocation(_program, attributeName.c_str());
|
2014-03-05 05:51:43 +08:00
|
|
|
}
|
|
|
|
|
2014-05-07 08:58:14 +08:00
|
|
|
GLint GLProgram::getUniformLocation(const std::string &attributeName) const
|
2014-03-05 05:51:43 +08:00
|
|
|
{
|
2014-05-07 08:58:14 +08:00
|
|
|
return glGetUniformLocation(_program, attributeName.c_str());
|
2014-03-05 05:51:43 +08:00
|
|
|
}
|
|
|
|
|
2014-05-07 08:58:14 +08:00
|
|
|
void GLProgram::bindAttribLocation(const std::string &attributeName, GLuint index) const
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
2014-05-07 08:58:14 +08:00
|
|
|
glBindAttribLocation(_program, index, attributeName.c_str());
|
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
|
|
|
{
|
2014-08-18 17:10:07 +08:00
|
|
|
_builtInUniforms[UNIFORM_AMBIENT_COLOR] = glGetUniformLocation(_program, UNIFORM_NAME_AMBIENT_COLOR);
|
2014-05-14 09:12:58 +08:00
|
|
|
_builtInUniforms[UNIFORM_P_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_P_MATRIX);
|
|
|
|
_builtInUniforms[UNIFORM_MV_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MV_MATRIX);
|
|
|
|
_builtInUniforms[UNIFORM_MVP_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MVP_MATRIX);
|
2014-08-15 19:15:14 +08:00
|
|
|
_builtInUniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_NORMAL_MATRIX);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2014-05-14 09:12:58 +08:00
|
|
|
_builtInUniforms[UNIFORM_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_TIME);
|
|
|
|
_builtInUniforms[UNIFORM_SIN_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_SIN_TIME);
|
|
|
|
_builtInUniforms[UNIFORM_COS_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_COS_TIME);
|
2013-11-01 08:56:15 +08:00
|
|
|
|
2014-05-14 09:12:58 +08:00
|
|
|
_builtInUniforms[UNIFORM_RANDOM01] = glGetUniformLocation(_program, UNIFORM_NAME_RANDOM01);
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2014-05-14 09:12:58 +08:00
|
|
|
_builtInUniforms[UNIFORM_SAMPLER0] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER0);
|
|
|
|
_builtInUniforms[UNIFORM_SAMPLER1] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER1);
|
|
|
|
_builtInUniforms[UNIFORM_SAMPLER2] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER2);
|
|
|
|
_builtInUniforms[UNIFORM_SAMPLER3] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER3);
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2014-05-14 09:12:58 +08:00
|
|
|
_flags.usesP = _builtInUniforms[UNIFORM_P_MATRIX] != -1;
|
|
|
|
_flags.usesMV = _builtInUniforms[UNIFORM_MV_MATRIX] != -1;
|
|
|
|
_flags.usesMVP = _builtInUniforms[UNIFORM_MVP_MATRIX] != -1;
|
2014-08-15 19:15:14 +08:00
|
|
|
_flags.usesNormal = _builtInUniforms[UNIFORM_NORMAL_MATRIX] != -1;
|
2014-04-28 09:51:10 +08:00
|
|
|
_flags.usesTime = (
|
2014-05-14 09:12:58 +08:00
|
|
|
_builtInUniforms[UNIFORM_TIME] != -1 ||
|
|
|
|
_builtInUniforms[UNIFORM_SIN_TIME] != -1 ||
|
|
|
|
_builtInUniforms[UNIFORM_COS_TIME] != -1
|
2013-11-01 08:56:15 +08:00
|
|
|
);
|
2014-05-14 09:12:58 +08:00
|
|
|
_flags.usesRandom = _builtInUniforms[UNIFORM_RANDOM01] != -1;
|
2013-11-01 08:56:15 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
this->use();
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2014-05-14 09:12:58 +08:00
|
|
|
// Since sample most probably won't change, set it to 0,1,2,3 now.
|
|
|
|
if(_builtInUniforms[UNIFORM_SAMPLER0] != -1)
|
|
|
|
setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER0], 0);
|
|
|
|
if(_builtInUniforms[UNIFORM_SAMPLER1] != -1)
|
|
|
|
setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER1], 1);
|
|
|
|
if(_builtInUniforms[UNIFORM_SAMPLER2] != -1)
|
|
|
|
setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER2], 2);
|
|
|
|
if(_builtInUniforms[UNIFORM_SAMPLER3] != -1)
|
|
|
|
setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER3], 3);
|
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");
|
2014-03-22 20:58:07 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
GLint status = GL_TRUE;
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2014-05-09 03:34:26 +08:00
|
|
|
bindPredefinedVertexAttribs();
|
|
|
|
|
|
|
|
glLinkProgram(_program);
|
2014-05-08 03:41:04 +08:00
|
|
|
|
2016-07-27 23:48:10 +08:00
|
|
|
// Calling glGetProgramiv(...GL_LINK_STATUS...) will force linking of the program at this moment.
|
|
|
|
// Otherwise, they might be linked when they are used for the first time. (I guess this depends on the driver implementation)
|
|
|
|
// So it might slow down the "booting" process on certain devices. But, on the other hand it is important to know if the shader
|
|
|
|
// linked succesfully. Some shaders might be downloaded in runtime so, release version should have this check.
|
|
|
|
// For more info, see Github issue #16231
|
2013-06-15 14:03:30 +08:00
|
|
|
glGetProgramiv(_program, GL_LINK_STATUS, &status);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
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
|
|
|
}
|
2016-07-27 20:31:32 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
parseVertexAttribs();
|
|
|
|
parseUniforms();
|
|
|
|
|
|
|
|
clearShader();
|
|
|
|
}
|
2014-03-22 20:58:07 +08:00
|
|
|
|
2012-11-09 12:08:18 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-01-04 21:51:22 +08:00
|
|
|
static std::string logForOpenGLShader(GLuint shader)
|
2012-03-12 15:22:03 +08:00
|
|
|
{
|
1. We should define `std::string ret` in where we really need it. According to my test on android platform the function returns at `return "";`, which makes the `ret` unnecessary.
2. `charsWritten` is not used, we should either delete it or use it. Because we don't check the bytes written, I think we can just delete it.
3. We don't need (logLength+1) space for `logBytes`, because `logBytes` returned by calling glGetShaderInfoLog(shader, logLength, nullptr, logBytes) takes `logLength` bytes at most, including the ending null character, i.e. `(strlen(logBytes) + 1 == logLength)` always yield true. According to the offical opengles sdk docs: https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderInfoLog.xml.
and
https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderiv.xml
4. We don't need `logBytes[logLength] = '\0';`, because `logBytes` returned is already null-terminated.
2016-01-25 12:22:30 +08:00
|
|
|
GLint logLength = 0;
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2015-01-04 21:51:22 +08:00
|
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
|
2012-03-12 15:22:03 +08:00
|
|
|
if (logLength < 1)
|
2013-12-11 22:35:37 +08:00
|
|
|
return "";
|
2012-03-12 15:22:03 +08:00
|
|
|
|
1. We should define `std::string ret` in where we really need it. According to my test on android platform the function returns at `return "";`, which makes the `ret` unnecessary.
2. `charsWritten` is not used, we should either delete it or use it. Because we don't check the bytes written, I think we can just delete it.
3. We don't need (logLength+1) space for `logBytes`, because `logBytes` returned by calling glGetShaderInfoLog(shader, logLength, nullptr, logBytes) takes `logLength` bytes at most, including the ending null character, i.e. `(strlen(logBytes) + 1 == logLength)` always yield true. According to the offical opengles sdk docs: https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderInfoLog.xml.
and
https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderiv.xml
4. We don't need `logBytes[logLength] = '\0';`, because `logBytes` returned is already null-terminated.
2016-01-25 12:22:30 +08:00
|
|
|
char *logBytes = (char*)malloc(sizeof(char) * logLength);
|
|
|
|
glGetShaderInfoLog(shader, logLength, nullptr, logBytes);
|
|
|
|
std::string ret(logBytes);
|
2015-01-04 21:51:22 +08:00
|
|
|
|
|
|
|
free(logBytes);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string logForOpenGLProgram(GLuint program)
|
|
|
|
{
|
1. We should define `std::string ret` in where we really need it. According to my test on android platform the function returns at `return "";`, which makes the `ret` unnecessary.
2. `charsWritten` is not used, we should either delete it or use it. Because we don't check the bytes written, I think we can just delete it.
3. We don't need (logLength+1) space for `logBytes`, because `logBytes` returned by calling glGetShaderInfoLog(shader, logLength, nullptr, logBytes) takes `logLength` bytes at most, including the ending null character, i.e. `(strlen(logBytes) + 1 == logLength)` always yield true. According to the offical opengles sdk docs: https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderInfoLog.xml.
and
https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderiv.xml
4. We don't need `logBytes[logLength] = '\0';`, because `logBytes` returned is already null-terminated.
2016-01-25 12:22:30 +08:00
|
|
|
GLint logLength = 0;
|
2015-01-04 21:51:22 +08:00
|
|
|
|
|
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
|
|
|
|
if (logLength < 1)
|
|
|
|
return "";
|
2012-03-12 15:22:03 +08:00
|
|
|
|
1. We should define `std::string ret` in where we really need it. According to my test on android platform the function returns at `return "";`, which makes the `ret` unnecessary.
2. `charsWritten` is not used, we should either delete it or use it. Because we don't check the bytes written, I think we can just delete it.
3. We don't need (logLength+1) space for `logBytes`, because `logBytes` returned by calling glGetShaderInfoLog(shader, logLength, nullptr, logBytes) takes `logLength` bytes at most, including the ending null character, i.e. `(strlen(logBytes) + 1 == logLength)` always yield true. According to the offical opengles sdk docs: https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderInfoLog.xml.
and
https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderiv.xml
4. We don't need `logBytes[logLength] = '\0';`, because `logBytes` returned is already null-terminated.
2016-01-25 12:22:30 +08:00
|
|
|
char *logBytes = (char*)malloc(sizeof(char) * logLength);
|
|
|
|
glGetProgramInfoLog(program, logLength, nullptr, logBytes);
|
|
|
|
std::string 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
|
|
|
{
|
2015-01-04 21:51:22 +08:00
|
|
|
return cocos2d::logForOpenGLShader(_vertShader);
|
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
|
|
|
{
|
2015-01-04 21:51:22 +08:00
|
|
|
return cocos2d::logForOpenGLShader(_fragShader);
|
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
|
|
|
{
|
2015-01-04 21:51:22 +08:00
|
|
|
return logForOpenGLProgram(_program);
|
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;
|
|
|
|
}
|
2014-03-06 10:50:09 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
bool updated = true;
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2014-10-21 17:29:24 +08:00
|
|
|
auto element = _hashForUniforms.find(location);
|
|
|
|
if (element == _hashForUniforms.end())
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2014-10-21 17:29:24 +08:00
|
|
|
GLvoid* value = malloc(bytes);
|
|
|
|
memcpy(value, data, bytes );
|
2015-01-26 18:40:00 +08:00
|
|
|
_hashForUniforms.insert(std::make_pair(location, std::make_pair(value, bytes)));
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-07-13 02:10:16 +08:00
|
|
|
if (element->second.second < bytes)
|
2012-11-09 12:08:18 +08:00
|
|
|
{
|
2016-07-13 02:10:16 +08:00
|
|
|
GLvoid* value = realloc(element->second.first, bytes);
|
|
|
|
memcpy(value, data, bytes);
|
|
|
|
_hashForUniforms[location] = std::make_pair(value, bytes);
|
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
|
|
|
{
|
2016-07-13 02:10:16 +08:00
|
|
|
if (memcmp(element->second.first, data, bytes) == 0)
|
2015-01-27 16:31:15 +08:00
|
|
|
{
|
2016-07-13 02:10:16 +08:00
|
|
|
updated = false;
|
2015-01-27 16:31:15 +08:00
|
|
|
}
|
|
|
|
else
|
2015-01-26 18:40:00 +08:00
|
|
|
memcpy(element->second.first, data, bytes);
|
2012-11-09 12:08:18 +08:00
|
|
|
}
|
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");
|
2015-04-20 17:00:40 +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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, &i1, sizeof(i1)*1);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +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};
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(ints));
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
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};
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(ints));
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
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};
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(ints));
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(int)*2*numberOfArrays);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(int)*3*numberOfArrays);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, ints, sizeof(int)*4*numberOfArrays);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2013-03-27 02:20:38 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, &f1, sizeof(f1)*1);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
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};
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
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};
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
glUniform4f( (GLint)location, f1, f2, f3,f4);
|
|
|
|
}
|
2012-04-17 17:55:26 +08:00
|
|
|
}
|
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
|
|
|
|
void GLProgram::setUniformLocationWith1fv( GLint location, const GLfloat* floats, unsigned int numberOfArrays )
|
|
|
|
{
|
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(float)*numberOfArrays);
|
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2014-08-15 19:15:14 +08:00
|
|
|
{
|
|
|
|
glUniform1fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(float)*2*numberOfArrays);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(float)*3*numberOfArrays);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, floats, sizeof(float)*4*numberOfArrays);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
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) {
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, matrixArray, sizeof(float)*4*numberOfMatrices);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2013-10-28 00:58:57 +08:00
|
|
|
{
|
|
|
|
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) {
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, matrixArray, sizeof(float)*9*numberOfMatrices);
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2013-10-28 00:58:57 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2014-05-13 14:51:37 +08:00
|
|
|
bool updated = updateUniformLocation(location, matrixArray, sizeof(float)*16*numberOfMatrices);
|
2012-04-17 17:55:26 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (updated)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2014-12-04 18:37:57 +08:00
|
|
|
setUniformsForBuiltins(_director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW));
|
2013-12-07 09:42:16 +08:00
|
|
|
}
|
|
|
|
|
2014-05-15 01:07:09 +08:00
|
|
|
void GLProgram::setUniformsForBuiltins(const Mat4 &matrixMV)
|
2013-12-07 09:42:16 +08:00
|
|
|
{
|
2016-02-09 03:25:37 +08:00
|
|
|
const auto& matrixP = _director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
|
2013-11-01 08:56:15 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (_flags.usesP)
|
2014-05-14 09:12:58 +08:00
|
|
|
setUniformLocationWithMatrix4fv(_builtInUniforms[UNIFORM_P_MATRIX], matrixP.m, 1);
|
2013-12-06 11:04:01 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (_flags.usesMV)
|
2014-05-14 09:12:58 +08:00
|
|
|
setUniformLocationWithMatrix4fv(_builtInUniforms[UNIFORM_MV_MATRIX], matrixMV.m, 1);
|
2013-12-06 11:04:01 +08:00
|
|
|
|
2016-02-09 03:25:37 +08:00
|
|
|
if (_flags.usesMVP)
|
|
|
|
{
|
2014-05-15 01:07:09 +08:00
|
|
|
Mat4 matrixMVP = matrixP * matrixMV;
|
2014-05-14 09:12:58 +08:00
|
|
|
setUniformLocationWithMatrix4fv(_builtInUniforms[UNIFORM_MVP_MATRIX], matrixMVP.m, 1);
|
2013-11-01 08:56:15 +08:00
|
|
|
}
|
|
|
|
|
2014-08-15 19:15:14 +08:00
|
|
|
if (_flags.usesNormal)
|
|
|
|
{
|
|
|
|
Mat4 mvInverse = matrixMV;
|
|
|
|
mvInverse.m[12] = mvInverse.m[13] = mvInverse.m[14] = 0.0f;
|
|
|
|
mvInverse.inverse();
|
|
|
|
mvInverse.transpose();
|
|
|
|
GLfloat normalMat[9];
|
|
|
|
normalMat[0] = mvInverse.m[0];normalMat[1] = mvInverse.m[1];normalMat[2] = mvInverse.m[2];
|
2014-08-17 21:33:33 +08:00
|
|
|
normalMat[3] = mvInverse.m[4];normalMat[4] = mvInverse.m[5];normalMat[5] = mvInverse.m[6];
|
|
|
|
normalMat[6] = mvInverse.m[8];normalMat[7] = mvInverse.m[9];normalMat[8] = mvInverse.m[10];
|
2014-08-15 19:15:14 +08:00
|
|
|
setUniformLocationWithMatrix3fv(_builtInUniforms[UNIFORM_NORMAL_MATRIX], normalMat, 1);
|
|
|
|
}
|
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (_flags.usesTime) {
|
2014-04-28 09:51:10 +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.
|
2014-12-04 18:37:57 +08:00
|
|
|
float time = _director->getTotalFrames() * _director->getAnimationInterval();
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2016-07-04 22:12:45 +08:00
|
|
|
setUniformLocationWith4f(_builtInUniforms[GLProgram::UNIFORM_TIME], time/10.0f, time, time*2, time*4);
|
|
|
|
setUniformLocationWith4f(_builtInUniforms[GLProgram::UNIFORM_SIN_TIME], time/8.0f, time/4.0f, time/2.0f, sinf(time));
|
|
|
|
setUniformLocationWith4f(_builtInUniforms[GLProgram::UNIFORM_COS_TIME], time/8.0f, time/4.0f, time/2.0f, cosf(time));
|
2014-04-28 09:51:10 +08:00
|
|
|
}
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2015-05-06 04:07:32 +08:00
|
|
|
if (_flags.usesRandom)
|
2014-05-14 09:12:58 +08:00
|
|
|
setUniformLocationWith4f(_builtInUniforms[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;
|
2014-05-14 09:12:58 +08:00
|
|
|
memset(_builtInUniforms, 0, sizeof(_builtInUniforms));
|
2015-04-20 17:00:40 +08:00
|
|
|
|
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
|
|
|
|
2014-10-21 17:29:24 +08:00
|
|
|
for (auto e: _hashForUniforms)
|
2012-04-17 17:55:26 +08:00
|
|
|
{
|
2015-01-26 18:40:00 +08:00
|
|
|
free(e.second.first);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2015-04-20 17:00:40 +08:00
|
|
|
|
2014-10-21 17:29:24 +08:00
|
|
|
_hashForUniforms.clear();
|
2012-03-15 10:42:22 +08:00
|
|
|
}
|
2012-03-12 15:22:03 +08:00
|
|
|
|
2015-11-17 14:29:56 +08:00
|
|
|
inline void GLProgram::clearShader()
|
2015-11-17 13:38:42 +08:00
|
|
|
{
|
|
|
|
if (_vertShader)
|
|
|
|
{
|
|
|
|
glDeleteShader(_vertShader);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_fragShader)
|
|
|
|
{
|
|
|
|
glDeleteShader(_fragShader);
|
|
|
|
}
|
|
|
|
|
|
|
|
_vertShader = _fragShader = 0;
|
|
|
|
}
|
|
|
|
|
2012-03-12 15:22:03 +08:00
|
|
|
NS_CC_END
|
2015-05-06 04:07:32 +08:00
|
|
|
|