mirror of https://github.com/axmolengine/axmol.git
fixed #1139: fix the bug that screen becomes black when backing to foreground on Android
This commit is contained in:
parent
1fe71210ed
commit
04c0d794af
|
@ -4,6 +4,8 @@
|
|||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
|
||||
#include "HelloWorldScene.h"
|
||||
|
||||
#define LOG_TAG "main"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
|
||||
|
||||
|
@ -34,8 +36,11 @@ void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thi
|
|||
}
|
||||
else
|
||||
{
|
||||
ccDrawInit();
|
||||
ccGLInvalidateStateCache();
|
||||
cocos2d::CCDirector::sharedDirector()->setGLDefaultValues();
|
||||
CCShaderCache::sharedShaderCache()->reloadDefaultShaders();
|
||||
cocos2d::CCTextureCache::reloadAllTextures();
|
||||
cocos2d::CCDirector::sharedDirector()->setGLDefaultValues();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,11 +57,18 @@ static void lazy_init( void )
|
|||
shader_ = CCShaderCache::sharedShaderCache()->programForKey(kCCShader_Position_uColor);
|
||||
|
||||
colorLocation_ = glGetUniformLocation( shader_->getProgram(), "u_color");
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
pointSizeLocation_ = glGetUniformLocation( shader_->getProgram(), "u_pointSize");
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// When back to foreground on android, we want to it to inilialize again
|
||||
void ccDrawInit()
|
||||
{
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
void ccDrawPoint( const CCPoint& point )
|
||||
|
@ -132,11 +139,16 @@ void ccDrawLine( const CCPoint& origin, const CCPoint& destination )
|
|||
};
|
||||
|
||||
shader_->use();
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
shader_->setUniformForModelViewProjectionMatrix();
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
shader_->setUniformLocationWith4fv(colorLocation_, (GLfloat*) &color_.r, 1);
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
|
||||
CC_INCREMENT_GL_DRAWS(1);
|
||||
|
|
|
@ -49,6 +49,9 @@ THE SOFTWARE.
|
|||
|
||||
NS_CC_BEGIN
|
||||
|
||||
/** initlialize context */
|
||||
void CC_DLL ccDrawInit();
|
||||
|
||||
/** draws a point given x and y coordinate measured in points */
|
||||
void CC_DLL ccDrawPoint( const CCPoint& point );
|
||||
|
||||
|
|
|
@ -71,11 +71,11 @@ struct _hashUniformEntry;
|
|||
typedef void (*GLInfoFunction)(GLuint program, GLenum pname, GLint* params);
|
||||
typedef void (*GLLogFunction) (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
|
||||
|
||||
/** CCGLProgram
|
||||
Class that implements a glProgram
|
||||
|
||||
|
||||
@since v2.0.0
|
||||
/** CCGLProgram
|
||||
Class that implements a glProgram
|
||||
|
||||
|
||||
@since v2.0.0
|
||||
*/
|
||||
class CC_DLL CCGLProgram : public CCObject
|
||||
{
|
||||
|
@ -84,7 +84,7 @@ public:
|
|||
|
||||
CCGLProgram();
|
||||
virtual ~CCGLProgram();
|
||||
/** Initializes the CCGLProgram with a vertex and fragment with bytes array */
|
||||
/** Initializes the CCGLProgram with a vertex and fragment with bytes array */
|
||||
bool initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray);
|
||||
/** Initializes the CCGLProgram with a vertex and fragment with contents of filenames */
|
||||
bool initWithVertexShaderFilename(const char* vShaderFilename, const char* fShaderFilename);
|
||||
|
@ -103,34 +103,34 @@ public:
|
|||
|
||||
*/
|
||||
void updateUniforms();
|
||||
/** calls glUniform1i only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith1i(unsigned int location, GLint i1);
|
||||
|
||||
/** calls glUniform1f only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith1f(unsigned int location, GLfloat f1);
|
||||
|
||||
/** calls glUniform2f only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith2f(unsigned int location, GLfloat f1, GLfloat f2);
|
||||
|
||||
/** calls glUniform3f only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith3f(unsigned int location, GLfloat f1, GLfloat f2, GLfloat f3);
|
||||
|
||||
/** calls glUniform4f only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith4f(unsigned int location, GLfloat f1, GLfloat f2, GLfloat f3, GLfloat f4);
|
||||
|
||||
/** calls glUniform2fv only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith2fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays);
|
||||
|
||||
/** calls glUniform3fv only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith3fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays);
|
||||
|
||||
/** calls glUniform4fv only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith4fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays);
|
||||
|
||||
/** calls glUniformMatrix4fv only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationwithMatrix4fv(unsigned int location, GLfloat* matrixArray, unsigned int numberOfMatrices);
|
||||
|
||||
/** will update the MVP matrix on the MVP uniform if it is different than the previous call for this same shader program. */
|
||||
/** calls glUniform1i only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith1i(unsigned int location, GLint i1);
|
||||
|
||||
/** calls glUniform1f only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith1f(unsigned int location, GLfloat f1);
|
||||
|
||||
/** calls glUniform2f only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith2f(unsigned int location, GLfloat f1, GLfloat f2);
|
||||
|
||||
/** calls glUniform3f only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith3f(unsigned int location, GLfloat f1, GLfloat f2, GLfloat f3);
|
||||
|
||||
/** calls glUniform4f only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith4f(unsigned int location, GLfloat f1, GLfloat f2, GLfloat f3, GLfloat f4);
|
||||
|
||||
/** calls glUniform2fv only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith2fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays);
|
||||
|
||||
/** calls glUniform3fv only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith3fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays);
|
||||
|
||||
/** calls glUniform4fv only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationWith4fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays);
|
||||
|
||||
/** calls glUniformMatrix4fv only if the values are different than the previous call for this same shader program. */
|
||||
void setUniformLocationwithMatrix4fv(unsigned int location, GLfloat* matrixArray, unsigned int numberOfMatrices);
|
||||
|
||||
/** will update the MVP matrix on the MVP uniform if it is different than the previous call for this same shader program. */
|
||||
void setUniformForModelViewProjectionMatrix();
|
||||
|
||||
/** returns the vertexShader error log */
|
||||
|
@ -139,6 +139,10 @@ public:
|
|||
const char* fragmentShaderLog();
|
||||
/** returns the program error log */
|
||||
const char* programLog();
|
||||
|
||||
// reload all shaders, this function is designed for android
|
||||
// when opengl context lost, so don't call it.
|
||||
void reset();
|
||||
|
||||
inline const GLuint getProgram() { return m_uProgram; }
|
||||
|
||||
|
|
|
@ -51,6 +51,9 @@ public:
|
|||
|
||||
/** loads the default shaders */
|
||||
void loadDefaultShaders();
|
||||
|
||||
/** reload the default shaders */
|
||||
void reloadDefaultShaders();
|
||||
|
||||
/** returns a GL program for a given key */
|
||||
CCGLProgram * programForKey(const char* key);
|
||||
|
@ -60,6 +63,7 @@ public:
|
|||
|
||||
private:
|
||||
bool init();
|
||||
void loadDefaultShader(CCGLProgram *program, int type);
|
||||
|
||||
CCDictionary* m_pPrograms;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "CCPlatformMacros.h"
|
||||
#include "utility.h"
|
||||
|
||||
struct kmVec3;
|
||||
struct kmVec3;
|
||||
struct kmMat3;
|
||||
struct kmQuaternion;
|
||||
struct kmPlane;
|
||||
|
@ -38,7 +38,7 @@ struct kmPlane;
|
|||
A 4x4 matrix
|
||||
|
||||
| 0 4 8 12 |
|
||||
mat = | 1 5 9 13 |
|
||||
mat = | 1 5 9 13 |
|
||||
| 2 6 10 14 |
|
||||
| 3 7 11 15 |
|
||||
*/
|
||||
|
@ -83,10 +83,10 @@ CC_DLL struct kmVec3* const kmMat4GetForwardVec3(struct kmVec3* pOut, const kmMa
|
|||
CC_DLL kmMat4* const kmMat4PerspectiveProjection(kmMat4* pOut, kmScalar fovY, kmScalar aspect, kmScalar zNear, kmScalar zFar);
|
||||
CC_DLL kmMat4* const kmMat4OrthographicProjection(kmMat4* pOut, kmScalar left, kmScalar right, kmScalar bottom, kmScalar top, kmScalar nearVal, kmScalar farVal);
|
||||
CC_DLL kmMat4* const kmMat4LookAt(kmMat4* pOut, const struct kmVec3* pEye, const struct kmVec3* pCenter, const struct kmVec3* pUp);
|
||||
|
||||
CC_DLL kmMat4* const kmMat4RotationAxisAngle(kmMat4* pOut, const struct kmVec3* axis, kmScalar radians);
|
||||
|
||||
CC_DLL kmMat4* const kmMat4RotationAxisAngle(kmMat4* pOut, const struct kmVec3* axis, kmScalar radians);
|
||||
CC_DLL struct kmMat3* const kmMat4ExtractRotation(struct kmMat3* pOut, const kmMat4* pIn);
|
||||
CC_DLL struct kmPlane* const kmMat4ExtractPlane(struct kmPlane* pOut, const kmMat4* pIn, const kmEnum plane);
|
||||
CC_DLL struct kmPlane* const kmMat4ExtractPlane(struct kmPlane* pOut, const kmMat4* pIn, const kmEnum plane);
|
||||
CC_DLL struct kmVec3* const kmMat4RotationToAxisAngle(struct kmVec3* pAxis, kmScalar* radians, const kmMat4* pIn);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -31,17 +31,17 @@ THE SOFTWARE.
|
|||
#include "CCFileUtils.h"
|
||||
#include "support/data_support/uthash.h"
|
||||
#include "CCString.h"
|
||||
// extern
|
||||
#include "kazmath/GL/matrix.h"
|
||||
// extern
|
||||
#include "kazmath/GL/matrix.h"
|
||||
#include "kazmath/kazmath.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
typedef struct _hashUniformEntry
|
||||
{
|
||||
GLvoid* value; // value
|
||||
unsigned int location; // Key
|
||||
UT_hash_handle hh; // hash entry
|
||||
typedef struct _hashUniformEntry
|
||||
{
|
||||
GLvoid* value; // value
|
||||
unsigned int location; // Key
|
||||
UT_hash_handle hh; // hash entry
|
||||
} tHashUniformEntry;
|
||||
|
||||
CCGLProgram::CCGLProgram()
|
||||
|
@ -55,7 +55,7 @@ CCGLProgram::CCGLProgram()
|
|||
|
||||
CCGLProgram::~CCGLProgram()
|
||||
{
|
||||
CCLOGINFO("cocos2d: deallocing 0x%X", this);
|
||||
CCLOGINFO("cocos2d: %s %d deallocing 0x%X", __FUNCTION__, __LINE__, this);
|
||||
|
||||
// there is no need to delete the shaders. They should have been already deleted.
|
||||
CCAssert( m_uVertShader == 0, "Vertex Shaders should have been already deleted");
|
||||
|
@ -66,19 +66,20 @@ CCGLProgram::~CCGLProgram()
|
|||
ccGLDeleteProgram(m_uProgram);
|
||||
}
|
||||
|
||||
tHashUniformEntry *current_element, *tmp;
|
||||
|
||||
// Purge uniform hash
|
||||
HASH_ITER(hh, m_pHashForUniforms, current_element, tmp) {
|
||||
HASH_DEL(m_pHashForUniforms, current_element);
|
||||
free(current_element->value);
|
||||
free(current_element);
|
||||
tHashUniformEntry *current_element, *tmp;
|
||||
|
||||
// Purge uniform hash
|
||||
HASH_ITER(hh, m_pHashForUniforms, current_element, tmp) {
|
||||
HASH_DEL(m_pHashForUniforms, current_element);
|
||||
free(current_element->value);
|
||||
free(current_element);
|
||||
}
|
||||
}
|
||||
|
||||
bool CCGLProgram::initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)
|
||||
{
|
||||
m_uProgram = glCreateProgram();
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
m_uVertShader = m_uFragShader = 0;
|
||||
|
||||
|
@ -101,20 +102,23 @@ bool CCGLProgram::initWithVertexShaderByteArray(const GLchar* vShaderByteArray,
|
|||
if( m_uVertShader ) {
|
||||
glAttachShader(m_uProgram, m_uVertShader);
|
||||
}
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
if( m_uFragShader ) {
|
||||
glAttachShader(m_uProgram, m_uFragShader);
|
||||
}
|
||||
m_pHashForUniforms = NULL;
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCGLProgram::initWithVertexShaderFilename(const char* vShaderFilename, const char* fShaderFilename)
|
||||
{
|
||||
const GLchar * vertexSource = (GLchar*) CCString::stringWithContentsOfFile(CCFileUtils::fullPathFromRelativePath(vShaderFilename))->getCString();
|
||||
const GLchar * fragmentSource = (GLchar*) CCString::stringWithContentsOfFile(CCFileUtils::fullPathFromRelativePath(fShaderFilename))->getCString();
|
||||
|
||||
const GLchar * vertexSource = (GLchar*) CCString::stringWithContentsOfFile(CCFileUtils::fullPathFromRelativePath(vShaderFilename))->getCString();
|
||||
const GLchar * fragmentSource = (GLchar*) CCString::stringWithContentsOfFile(CCFileUtils::fullPathFromRelativePath(fShaderFilename))->getCString();
|
||||
|
||||
return initWithVertexShaderByteArray(vertexSource, fragmentSource);
|
||||
}
|
||||
|
||||
|
@ -132,9 +136,12 @@ bool CCGLProgram::compileShader(GLuint * shader, GLenum type, const GLchar* sour
|
|||
|
||||
*shader = glCreateShader(type);
|
||||
glShaderSource(*shader, 1, &source, NULL);
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
glCompileShader(*shader);
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
if( ! status ) {
|
||||
if( type == GL_VERTEX_SHADER )
|
||||
|
@ -169,7 +176,7 @@ bool CCGLProgram::link()
|
|||
{
|
||||
glLinkProgram(m_uProgram);
|
||||
|
||||
#if DEBUG
|
||||
//#if DEBUG
|
||||
GLint status;
|
||||
glValidateProgram(m_uProgram);
|
||||
|
||||
|
@ -184,7 +191,7 @@ bool CCGLProgram::link()
|
|||
m_uVertShader = m_uFragShader = m_uProgram = 0;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
if (m_uVertShader)
|
||||
glDeleteShader(m_uVertShader);
|
||||
|
@ -233,144 +240,167 @@ const char* CCGLProgram::programLog()
|
|||
return this->logForOpenGLObject(m_uProgram, (GLInfoFunction)&glGetProgramiv, (GLLogFunction)&glGetProgramInfoLog);
|
||||
}
|
||||
|
||||
// Uniform cache
|
||||
|
||||
bool CCGLProgram::updateUniformLocation(unsigned int location, GLvoid* data, unsigned int bytes)
|
||||
{
|
||||
bool updated = true;
|
||||
tHashUniformEntry *element = NULL;
|
||||
HASH_FIND_INT(m_pHashForUniforms, &location, element);
|
||||
|
||||
if( ! element ) {
|
||||
|
||||
element = (tHashUniformEntry*)malloc( sizeof(*element) );
|
||||
|
||||
// key
|
||||
element->location = location;
|
||||
|
||||
// value
|
||||
element->value = malloc( bytes );
|
||||
memcpy(element->value, data, bytes );
|
||||
|
||||
HASH_ADD_INT(m_pHashForUniforms, location, element);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( memcmp( element->value, data, bytes) == 0 )
|
||||
updated = false;
|
||||
else
|
||||
memcpy( element->value, data, bytes );
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith1i(unsigned int location, GLint i1)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, &i1, sizeof(i1)*1);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform1i( (GLint)location, i1);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith1f(unsigned int location, GLfloat f1)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, &f1, sizeof(f1)*1);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform1f( (GLint)location, f1);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith2f(unsigned int location, GLfloat f1, GLfloat f2)
|
||||
{
|
||||
GLfloat floats[2] = {f1,f2};
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform2f( (GLint)location, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith3f(unsigned int location, GLfloat f1, GLfloat f2, GLfloat f3)
|
||||
{
|
||||
GLfloat floats[3] = {f1,f2,f3};
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform3f( (GLint)location, f1, f2, f3);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith4f(unsigned int location, GLfloat f1, GLfloat f2, GLfloat f3, GLfloat f4)
|
||||
{
|
||||
GLfloat floats[4] = {f1,f2,f3,f4};
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform4f( (GLint)location, f1, f2, f3,f4);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith2fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(float)*2*numberOfArrays);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform2fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith3fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(float)*3*numberOfArrays);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform3fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith4fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(float)*4*numberOfArrays);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform4fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCGLProgram::setUniformLocationwithMatrix4fv(unsigned int location, GLfloat* matrixArray, unsigned int numberOfMatrices)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, matrixArray, sizeof(float)*16*numberOfMatrices);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniformMatrix4fv( (GLint)location, (GLsizei)numberOfMatrices, GL_FALSE, matrixArray);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformForModelViewProjectionMatrix()
|
||||
{
|
||||
kmMat4 matrixP;
|
||||
kmMat4 matrixMV;
|
||||
kmMat4 matrixMVP;
|
||||
|
||||
kmGLGetMatrix(KM_GL_PROJECTION, &matrixP );
|
||||
kmGLGetMatrix(KM_GL_MODELVIEW, &matrixMV );
|
||||
|
||||
kmMat4Multiply(&matrixMVP, &matrixP, &matrixMV);
|
||||
|
||||
setUniformLocationwithMatrix4fv(m_uUniforms[kCCUniformMVPMatrix], matrixMVP.mat, 1);
|
||||
// Uniform cache
|
||||
|
||||
bool CCGLProgram::updateUniformLocation(unsigned int location, GLvoid* data, unsigned int bytes)
|
||||
{
|
||||
bool updated = true;
|
||||
tHashUniformEntry *element = NULL;
|
||||
HASH_FIND_INT(m_pHashForUniforms, &location, element);
|
||||
|
||||
if( ! element ) {
|
||||
|
||||
element = (tHashUniformEntry*)malloc( sizeof(*element) );
|
||||
|
||||
// key
|
||||
element->location = location;
|
||||
|
||||
// value
|
||||
element->value = malloc( bytes );
|
||||
memcpy(element->value, data, bytes );
|
||||
|
||||
HASH_ADD_INT(m_pHashForUniforms, location, element);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( memcmp( element->value, data, bytes) == 0 )
|
||||
updated = false;
|
||||
else
|
||||
memcpy( element->value, data, bytes );
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith1i(unsigned int location, GLint i1)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, &i1, sizeof(i1)*1);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform1i( (GLint)location, i1);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith1f(unsigned int location, GLfloat f1)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, &f1, sizeof(f1)*1);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform1f( (GLint)location, f1);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith2f(unsigned int location, GLfloat f1, GLfloat f2)
|
||||
{
|
||||
GLfloat floats[2] = {f1,f2};
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform2f( (GLint)location, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith3f(unsigned int location, GLfloat f1, GLfloat f2, GLfloat f3)
|
||||
{
|
||||
GLfloat floats[3] = {f1,f2,f3};
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform3f( (GLint)location, f1, f2, f3);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith4f(unsigned int location, GLfloat f1, GLfloat f2, GLfloat f3, GLfloat f4)
|
||||
{
|
||||
GLfloat floats[4] = {f1,f2,f3,f4};
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(floats));
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform4f( (GLint)location, f1, f2, f3,f4);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith2fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(float)*2*numberOfArrays);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform2fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith3fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(float)*3*numberOfArrays);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform3fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformLocationWith4fv(unsigned int location, GLfloat* floats, unsigned int numberOfArrays)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, floats, sizeof(float)*4*numberOfArrays);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniform4fv( (GLint)location, (GLsizei)numberOfArrays, floats );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCGLProgram::setUniformLocationwithMatrix4fv(unsigned int location, GLfloat* matrixArray, unsigned int numberOfMatrices)
|
||||
{
|
||||
bool updated = updateUniformLocation(location, matrixArray, sizeof(float)*16*numberOfMatrices);
|
||||
|
||||
if( updated )
|
||||
{
|
||||
glUniformMatrix4fv( (GLint)location, (GLsizei)numberOfMatrices, GL_FALSE, matrixArray);
|
||||
}
|
||||
}
|
||||
|
||||
void CCGLProgram::setUniformForModelViewProjectionMatrix()
|
||||
{
|
||||
kmMat4 matrixP;
|
||||
kmMat4 matrixMV;
|
||||
kmMat4 matrixMVP;
|
||||
|
||||
kmGLGetMatrix(KM_GL_PROJECTION, &matrixP );
|
||||
kmGLGetMatrix(KM_GL_MODELVIEW, &matrixMV );
|
||||
|
||||
kmMat4Multiply(&matrixMVP, &matrixP, &matrixMV);
|
||||
|
||||
setUniformLocationwithMatrix4fv(m_uUniforms[kCCUniformMVPMatrix], matrixMVP.mat, 1);
|
||||
}
|
||||
|
||||
void CCGLProgram::reset()
|
||||
{
|
||||
m_uVertShader = m_uFragShader = 0;
|
||||
memset(m_uUniforms, 0, sizeof(m_uUniforms));
|
||||
|
||||
|
||||
// it is already deallocated by android
|
||||
//ccGLDeleteProgram(m_uProgram);
|
||||
m_uProgram = 0;
|
||||
|
||||
|
||||
tHashUniformEntry *current_element, *tmp;
|
||||
|
||||
// Purge uniform hash
|
||||
HASH_ITER(hh, m_pHashForUniforms, current_element, tmp)
|
||||
{
|
||||
HASH_DEL(m_pHashForUniforms, current_element);
|
||||
free(current_element->value);
|
||||
free(current_element);
|
||||
}
|
||||
m_pHashForUniforms = NULL;
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
|
|
|
@ -31,6 +31,26 @@ THE SOFTWARE.
|
|||
|
||||
NS_CC_BEGIN
|
||||
|
||||
#define kCCShader_PositionTextureColor "ShaderPositionTextureColor"
|
||||
#define kCCShader_PositionTextureColorAlphaTest "ShaderPositionTextureColorAlphaTest"
|
||||
#define kCCShader_PositionColor "ShaderPositionColor"
|
||||
#define kCCShader_PositionTexture "ShaderPositionTexture"
|
||||
#define kCCShader_PositionTexture_uColor "ShaderPositionTexture_uColor"
|
||||
#define kCCShader_PositionTextureA8Color "ShaderPositionTextureA8Color"
|
||||
#define kCCShader_Position_uColor "ShaderPosition_uColor"
|
||||
|
||||
enum {
|
||||
kCCShaderType_PositionTextureColor,
|
||||
kCCShaderType_PositionTextureColorAlphaTest,
|
||||
kCCShaderType_PositionColor,
|
||||
kCCShaderType_PositionTexture,
|
||||
kCCShaderType_PositionTexture_uColor,
|
||||
kCCShaderType_PositionTextureA8Color,
|
||||
kCCShaderType_Position_uColor,
|
||||
|
||||
kCCShaderType_MAX,
|
||||
};
|
||||
|
||||
static CCShaderCache *_sharedShaderCache = 0;
|
||||
|
||||
CCShaderCache* CCShaderCache::sharedShaderCache()
|
||||
|
@ -73,119 +93,177 @@ void CCShaderCache::loadDefaultShaders()
|
|||
{
|
||||
// Position Texture Color shader
|
||||
CCGLProgram *p = new CCGLProgram();
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColor_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
p->link();
|
||||
p->updateUniforms();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTextureColor);
|
||||
|
||||
m_pPrograms->setObject(p, kCCShader_PositionTextureColor);
|
||||
p->release();
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
// Position Texture Color alpha test
|
||||
p = new CCGLProgram();
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColorAlphaTest_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
p->link();
|
||||
p->updateUniforms();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTextureColorAlphaTest);
|
||||
|
||||
m_pPrograms->setObject(p, kCCShader_PositionTextureColorAlphaTest);
|
||||
p->release();
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
//
|
||||
// Position, Color shader
|
||||
//
|
||||
p = new CCGLProgram();
|
||||
p->initWithVertexShaderByteArray(ccPositionColor_vert ,ccPositionColor_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
|
||||
|
||||
p->link();
|
||||
p->updateUniforms();
|
||||
loadDefaultShader(p, kCCShaderType_PositionColor);
|
||||
|
||||
m_pPrograms->setObject(p, kCCShader_PositionColor);
|
||||
p->release();
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
//
|
||||
// Position Texture shader
|
||||
//
|
||||
p = new CCGLProgram();
|
||||
p->initWithVertexShaderByteArray(ccPositionTexture_vert ,ccPositionTexture_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
p->link();
|
||||
p->updateUniforms();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTexture);
|
||||
|
||||
m_pPrograms->setObject(p, kCCShader_PositionTexture);
|
||||
p->release();
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
//
|
||||
// Position, Texture attribs, 1 Color as uniform shader
|
||||
//
|
||||
p = new CCGLProgram();
|
||||
p->initWithVertexShaderByteArray(ccPositionTexture_uColor_vert, ccPositionTexture_uColor_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
p->link();
|
||||
p->updateUniforms();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTexture_uColor);
|
||||
|
||||
m_pPrograms->setObject(p ,kCCShader_PositionTexture_uColor);
|
||||
p->release();
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
//
|
||||
// Position Texture A8 Color shader
|
||||
//
|
||||
p = new CCGLProgram();
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureA8Color_vert, ccPositionTextureA8Color_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
p->link();
|
||||
p->updateUniforms();
|
||||
|
||||
m_pPrograms->setObject(p, kCCShader_PositionTextureA8Color);
|
||||
loadDefaultShader(p, kCCShaderType_PositionTextureA8Color);
|
||||
|
||||
m_pPrograms->setObject(p, kCCShader_PositionTextureA8Color);
|
||||
p->release();
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
//
|
||||
// Position and 1 color passed as a uniform (to similate glColor4ub )
|
||||
//
|
||||
p = new CCGLProgram();
|
||||
loadDefaultShader(p, kCCShaderType_Position_uColor);
|
||||
|
||||
m_pPrograms->setObject(p, kCCShader_Position_uColor);
|
||||
p->release();
|
||||
}
|
||||
|
||||
//
|
||||
// Position and 1 color passed as a uniform (to similate glColor4ub )
|
||||
//
|
||||
p = new CCGLProgram();
|
||||
p->initWithVertexShaderByteArray(ccPosition_uColor_vert, ccPosition_uColor_frag);
|
||||
|
||||
p->addAttribute("aVertex", kCCVertexAttrib_Position);
|
||||
|
||||
p->link();
|
||||
p->updateUniforms();
|
||||
|
||||
m_pPrograms->setObject(p, kCCShader_Position_uColor);
|
||||
p->release();
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
void CCShaderCache::reloadDefaultShaders()
|
||||
{
|
||||
// reset all programs and reload them
|
||||
|
||||
// Position Texture Color shader
|
||||
CCGLProgram *p = programForKey(kCCShader_PositionTextureColor);
|
||||
p->reset();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTextureColor);
|
||||
|
||||
// Position Texture Color alpha test
|
||||
p = programForKey(kCCShader_PositionTextureColorAlphaTest);
|
||||
p->reset();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTextureColorAlphaTest);
|
||||
|
||||
//
|
||||
// Position, Color shader
|
||||
//
|
||||
p = programForKey(kCCShader_PositionColor);
|
||||
p->reset();
|
||||
loadDefaultShader(p, kCCShaderType_PositionColor);
|
||||
|
||||
//
|
||||
// Position Texture shader
|
||||
//
|
||||
p = programForKey(kCCShader_PositionTexture);
|
||||
p->reset();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTexture);
|
||||
|
||||
//
|
||||
// Position, Texture attribs, 1 Color as uniform shader
|
||||
//
|
||||
p = programForKey(kCCShader_PositionTexture_uColor);
|
||||
p->reset();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTexture_uColor);
|
||||
|
||||
//
|
||||
// Position Texture A8 Color shader
|
||||
//
|
||||
p = programForKey(kCCShader_PositionTextureA8Color);
|
||||
p->reset();
|
||||
loadDefaultShader(p, kCCShaderType_PositionTextureA8Color);
|
||||
|
||||
//
|
||||
// Position and 1 color passed as a uniform (to similate glColor4ub )
|
||||
//
|
||||
p = programForKey(kCCShader_Position_uColor);
|
||||
p->reset();
|
||||
loadDefaultShader(p, kCCShaderType_Position_uColor);
|
||||
}
|
||||
|
||||
void CCShaderCache::loadDefaultShader(CCGLProgram *p, int type)
|
||||
{
|
||||
switch (type) {
|
||||
case kCCShaderType_PositionTextureColor:
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColor_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
break;
|
||||
case kCCShaderType_PositionTextureColorAlphaTest:
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColorAlphaTest_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
break;
|
||||
case kCCShaderType_PositionColor:
|
||||
p->initWithVertexShaderByteArray(ccPositionColor_vert ,ccPositionColor_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
|
||||
|
||||
break;
|
||||
case kCCShaderType_PositionTexture:
|
||||
p->initWithVertexShaderByteArray(ccPositionTexture_vert ,ccPositionTexture_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
break;
|
||||
case kCCShaderType_PositionTexture_uColor:
|
||||
p->initWithVertexShaderByteArray(ccPositionTexture_uColor_vert, ccPositionTexture_uColor_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
break;
|
||||
case kCCShaderType_PositionTextureA8Color:
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureA8Color_vert, ccPositionTextureA8Color_frag);
|
||||
|
||||
p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
|
||||
p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
|
||||
p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
|
||||
|
||||
break;
|
||||
case kCCShaderType_Position_uColor:
|
||||
p->initWithVertexShaderByteArray(ccPosition_uColor_vert, ccPosition_uColor_frag);
|
||||
|
||||
p->addAttribute("aVertex", kCCVertexAttrib_Position);
|
||||
|
||||
break;
|
||||
default:
|
||||
CCLOG("cocos2d: %s:%d, error shader type", __FUNCTION__, __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
p->link();
|
||||
p->updateUniforms();
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
}
|
||||
|
||||
CCGLProgram* CCShaderCache::programForKey(const char* key)
|
||||
|
|
|
@ -28,7 +28,7 @@ THE SOFTWARE.
|
|||
#include "CCTextureAtlas.h"
|
||||
#include "CCTextureCache.h"
|
||||
#include "ccMacros.h"
|
||||
#include "CCGLProgram.h"
|
||||
#include "CCGLProgram.h"
|
||||
#include "ccGLStateCache.h"
|
||||
// support
|
||||
#include "CCTexture2D.h"
|
||||
|
@ -50,7 +50,7 @@ CCTextureAtlas::CCTextureAtlas()
|
|||
|
||||
CCTextureAtlas::~CCTextureAtlas()
|
||||
{
|
||||
CCLOGINFO("cocos2d: CCTextureAtlas deallocing %p."this);
|
||||
CCLOGINFO("cocos2d: CCTextureAtlas deallocing %p.", this);
|
||||
|
||||
CC_SAFE_FREE(m_pQuads);
|
||||
CC_SAFE_FREE(m_pIndices);
|
||||
|
@ -87,7 +87,7 @@ void CCTextureAtlas::setTexture(CCTexture2D * var)
|
|||
|
||||
ccV3F_C4B_T2F_Quad* CCTextureAtlas::getQuads()
|
||||
{
|
||||
//if someone accesses the quads directly, presume that changes will be made
|
||||
//if someone accesses the quads directly, presume that changes will be made
|
||||
m_bDirty = true;
|
||||
return m_pQuads;
|
||||
}
|
||||
|
@ -172,12 +172,12 @@ bool CCTextureAtlas::initWithTexture(CCTexture2D *texture, unsigned int capacity
|
|||
memset( m_pQuads, 0, m_uCapacity * sizeof(ccV3F_C4B_T2F_Quad) );
|
||||
memset( m_pIndices, 0, m_uCapacity * 6 * sizeof(GLushort) );
|
||||
|
||||
this->setupIndices();
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_VAO
|
||||
setupVBOandVAO();
|
||||
#else
|
||||
setupVBO();
|
||||
this->setupIndices();
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_VAO
|
||||
setupVBOandVAO();
|
||||
#else
|
||||
setupVBO();
|
||||
#endif
|
||||
|
||||
m_bDirty = true;
|
||||
|
@ -217,62 +217,62 @@ void CCTextureAtlas::setupIndices()
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//TextureAtlas - VAO / VBO specific
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_VAO
|
||||
void CCTextureAtlas::setupVBOandVAO()
|
||||
{
|
||||
glGenVertexArrays(1, &m_uVAOname);
|
||||
glBindVertexArray(m_uVAOname);
|
||||
|
||||
#define kQuadSize sizeof(m_pQuads[0].bl)
|
||||
|
||||
glGenBuffers(2, &m_pBuffersVBO[0]);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uCapacity, m_pQuads, GL_DYNAMIC_DRAW);
|
||||
|
||||
// vertices
|
||||
glEnableVertexAttribArray(kCCVertexAttrib_Position);
|
||||
glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));
|
||||
|
||||
// colors
|
||||
glEnableVertexAttribArray(kCCVertexAttrib_Color);
|
||||
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));
|
||||
|
||||
// tex coords
|
||||
glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
|
||||
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, texCoords));
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uCapacity * 6, m_pIndices, GL_STATIC_DRAW);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
}
|
||||
#else // CC_TEXTURE_ATLAS_USE_VAO
|
||||
void CCTextureAtlas::setupVBO()
|
||||
{
|
||||
glGenBuffers(2, &m_pBuffersVBO[0]);
|
||||
|
||||
mapBuffers();
|
||||
}
|
||||
#endif // ! // CC_TEXTURE_ATLAS_USE_VAO
|
||||
|
||||
|
||||
//TextureAtlas - VAO / VBO specific
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_VAO
|
||||
void CCTextureAtlas::setupVBOandVAO()
|
||||
{
|
||||
glGenVertexArrays(1, &m_uVAOname);
|
||||
glBindVertexArray(m_uVAOname);
|
||||
|
||||
#define kQuadSize sizeof(m_pQuads[0].bl)
|
||||
|
||||
glGenBuffers(2, &m_pBuffersVBO[0]);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uCapacity, m_pQuads, GL_DYNAMIC_DRAW);
|
||||
|
||||
// vertices
|
||||
glEnableVertexAttribArray(kCCVertexAttrib_Position);
|
||||
glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));
|
||||
|
||||
// colors
|
||||
glEnableVertexAttribArray(kCCVertexAttrib_Color);
|
||||
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));
|
||||
|
||||
// tex coords
|
||||
glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
|
||||
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, texCoords));
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uCapacity * 6, m_pIndices, GL_STATIC_DRAW);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
}
|
||||
#else // CC_TEXTURE_ATLAS_USE_VAO
|
||||
void CCTextureAtlas::setupVBO()
|
||||
{
|
||||
glGenBuffers(2, &m_pBuffersVBO[0]);
|
||||
|
||||
mapBuffers();
|
||||
}
|
||||
#endif // ! // CC_TEXTURE_ATLAS_USE_VAO
|
||||
|
||||
void CCTextureAtlas::mapBuffers()
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uCapacity, m_pQuads, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uCapacity * 6, m_pIndices, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uCapacity, m_pQuads, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uCapacity * 6, m_pIndices, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
}
|
||||
|
||||
|
@ -317,32 +317,32 @@ void CCTextureAtlas::insertQuad(ccV3F_C4B_T2F_Quad *quad, unsigned int index)
|
|||
|
||||
void CCTextureAtlas::insertQuads(ccV3F_C4B_T2F_Quad* quads, unsigned int index, unsigned int amount)
|
||||
{
|
||||
CCAssert(index + amount <= m_uCapacity, "insertQuadWithTexture: Invalid index + amount");
|
||||
|
||||
m_uTotalQuads += amount;
|
||||
|
||||
CCAssert( m_uTotalQuads <= m_uCapacity, "invalid totalQuads");
|
||||
|
||||
// issue #575. index can be > totalQuads
|
||||
int remaining = (m_uTotalQuads-1) - index - amount;
|
||||
|
||||
// last object doesn't need to be moved
|
||||
if( remaining > 0)
|
||||
{
|
||||
// tex coordinates
|
||||
memmove( &m_pQuads[index+amount],&m_pQuads[index], sizeof(m_pQuads[0]) * remaining );
|
||||
}
|
||||
|
||||
|
||||
unsigned int max = index + amount;
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = index; i < max ; i++)
|
||||
{
|
||||
m_pQuads[index] = quads[j];
|
||||
index++;
|
||||
j++;
|
||||
}
|
||||
|
||||
CCAssert(index + amount <= m_uCapacity, "insertQuadWithTexture: Invalid index + amount");
|
||||
|
||||
m_uTotalQuads += amount;
|
||||
|
||||
CCAssert( m_uTotalQuads <= m_uCapacity, "invalid totalQuads");
|
||||
|
||||
// issue #575. index can be > totalQuads
|
||||
int remaining = (m_uTotalQuads-1) - index - amount;
|
||||
|
||||
// last object doesn't need to be moved
|
||||
if( remaining > 0)
|
||||
{
|
||||
// tex coordinates
|
||||
memmove( &m_pQuads[index+amount],&m_pQuads[index], sizeof(m_pQuads[0]) * remaining );
|
||||
}
|
||||
|
||||
|
||||
unsigned int max = index + amount;
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = index; i < max ; i++)
|
||||
{
|
||||
m_pQuads[index] = quads[j];
|
||||
index++;
|
||||
j++;
|
||||
}
|
||||
|
||||
m_bDirty = true;
|
||||
}
|
||||
|
||||
|
@ -399,17 +399,17 @@ void CCTextureAtlas::removeQuadAtIndex(unsigned int index)
|
|||
|
||||
void CCTextureAtlas::removeQuadsAtIndex(unsigned int index, unsigned int amount)
|
||||
{
|
||||
CCAssert(index + amount <= m_uTotalQuads, "removeQuadAtIndex: index + amount out of bounds");
|
||||
|
||||
unsigned int remaining = (m_uTotalQuads) - (index + amount);
|
||||
|
||||
m_uTotalQuads -= amount;
|
||||
|
||||
if ( remaining )
|
||||
{
|
||||
memmove( &m_pQuads[index], &m_pQuads[index+amount], sizeof(m_pQuads[0]) * remaining );
|
||||
}
|
||||
|
||||
CCAssert(index + amount <= m_uTotalQuads, "removeQuadAtIndex: index + amount out of bounds");
|
||||
|
||||
unsigned int remaining = (m_uTotalQuads) - (index + amount);
|
||||
|
||||
m_uTotalQuads -= amount;
|
||||
|
||||
if ( remaining )
|
||||
{
|
||||
memmove( &m_pQuads[index], &m_pQuads[index+amount], sizeof(m_pQuads[0]) * remaining );
|
||||
}
|
||||
|
||||
m_bDirty = true;
|
||||
}
|
||||
|
||||
|
@ -492,58 +492,58 @@ bool CCTextureAtlas::resizeCapacity(unsigned int newCapacity)
|
|||
return true;
|
||||
}
|
||||
|
||||
void CCTextureAtlas::increaseTotalQuadsWith(unsigned int amount)
|
||||
{
|
||||
m_uTotalQuads += amount;
|
||||
}
|
||||
|
||||
void CCTextureAtlas::moveQuadsFromIndex(unsigned int oldIndex, unsigned int amount, unsigned int newIndex)
|
||||
{
|
||||
CCAssert(newIndex + amount <= m_uTotalQuads, "insertQuadFromIndex:atIndex: Invalid index");
|
||||
CCAssert(oldIndex < m_uTotalQuads, "insertQuadFromIndex:atIndex: Invalid index");
|
||||
|
||||
if( oldIndex == newIndex )
|
||||
{
|
||||
return;
|
||||
}
|
||||
//create buffer
|
||||
size_t quadSize = sizeof(ccV3F_C4B_T2F_Quad);
|
||||
ccV3F_C4B_T2F_Quad* tempQuads = (ccV3F_C4B_T2F_Quad*)malloc( quadSize * amount);
|
||||
memcpy( tempQuads, &m_pQuads[oldIndex], quadSize * amount );
|
||||
|
||||
if (newIndex < oldIndex)
|
||||
{
|
||||
// move quads from newIndex to newIndex + amount to make room for buffer
|
||||
memmove( &m_pQuads[newIndex], &m_pQuads[newIndex+amount], (oldIndex-newIndex)*quadSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// move quads above back
|
||||
memmove( &m_pQuads[oldIndex], &m_pQuads[oldIndex+amount], (newIndex-oldIndex)*quadSize);
|
||||
}
|
||||
memcpy( &m_pQuads[newIndex], tempQuads, amount*quadSize);
|
||||
|
||||
free(tempQuads);
|
||||
|
||||
m_bDirty = true;
|
||||
}
|
||||
|
||||
void CCTextureAtlas::moveQuadsFromIndex(unsigned int index, unsigned int newIndex)
|
||||
void CCTextureAtlas::increaseTotalQuadsWith(unsigned int amount)
|
||||
{
|
||||
CCAssert(newIndex + (m_uTotalQuads - index) <= m_uCapacity, "moveQuadsFromIndex move is out of bounds");
|
||||
|
||||
m_uTotalQuads += amount;
|
||||
}
|
||||
|
||||
void CCTextureAtlas::moveQuadsFromIndex(unsigned int oldIndex, unsigned int amount, unsigned int newIndex)
|
||||
{
|
||||
CCAssert(newIndex + amount <= m_uTotalQuads, "insertQuadFromIndex:atIndex: Invalid index");
|
||||
CCAssert(oldIndex < m_uTotalQuads, "insertQuadFromIndex:atIndex: Invalid index");
|
||||
|
||||
if( oldIndex == newIndex )
|
||||
{
|
||||
return;
|
||||
}
|
||||
//create buffer
|
||||
size_t quadSize = sizeof(ccV3F_C4B_T2F_Quad);
|
||||
ccV3F_C4B_T2F_Quad* tempQuads = (ccV3F_C4B_T2F_Quad*)malloc( quadSize * amount);
|
||||
memcpy( tempQuads, &m_pQuads[oldIndex], quadSize * amount );
|
||||
|
||||
if (newIndex < oldIndex)
|
||||
{
|
||||
// move quads from newIndex to newIndex + amount to make room for buffer
|
||||
memmove( &m_pQuads[newIndex], &m_pQuads[newIndex+amount], (oldIndex-newIndex)*quadSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// move quads above back
|
||||
memmove( &m_pQuads[oldIndex], &m_pQuads[oldIndex+amount], (newIndex-oldIndex)*quadSize);
|
||||
}
|
||||
memcpy( &m_pQuads[newIndex], tempQuads, amount*quadSize);
|
||||
|
||||
free(tempQuads);
|
||||
|
||||
m_bDirty = true;
|
||||
}
|
||||
|
||||
void CCTextureAtlas::moveQuadsFromIndex(unsigned int index, unsigned int newIndex)
|
||||
{
|
||||
CCAssert(newIndex + (m_uTotalQuads - index) <= m_uCapacity, "moveQuadsFromIndex move is out of bounds");
|
||||
|
||||
memmove(m_pQuads + newIndex,m_pQuads + index, (m_uTotalQuads - index) * sizeof(m_pQuads[0]));
|
||||
}
|
||||
|
||||
void CCTextureAtlas::fillWithEmptyQuadsFromIndex(unsigned int index, unsigned int amount)
|
||||
{
|
||||
ccV3F_C4B_T2F_Quad quad;
|
||||
memset(&quad, 0, sizeof(quad));
|
||||
|
||||
unsigned int to = index + amount;
|
||||
for (int i = index ; i < to ; i++)
|
||||
{
|
||||
m_pQuads[i] = quad;
|
||||
ccV3F_C4B_T2F_Quad quad;
|
||||
memset(&quad, 0, sizeof(quad));
|
||||
|
||||
unsigned int to = index + amount;
|
||||
for (int i = index ; i < to ; i++)
|
||||
{
|
||||
m_pQuads[i] = quad;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,82 +562,82 @@ void CCTextureAtlas::drawNumberOfQuads(unsigned int n)
|
|||
void CCTextureAtlas::drawNumberOfQuads(unsigned int n, unsigned int start)
|
||||
{
|
||||
if (0 == n) return;
|
||||
ccGLBindTexture2D( m_pTexture->getName() );
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_VAO
|
||||
|
||||
//
|
||||
// Using VBO and VAO
|
||||
//
|
||||
|
||||
// XXX: update is done in draw... perhaps it should be done in a timer
|
||||
if (m_bDirty)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*start, sizeof(m_pQuads[0]) * n , &m_pQuads[start] );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
m_bDirty = false;
|
||||
}
|
||||
|
||||
glBindVertexArray( m_uVAOname );
|
||||
|
||||
#if CC_REBIND_INDICES_BUFFER
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
|
||||
#endif
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
|
||||
glDrawElements(GL_TRIANGLE_STRIP, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])) );
|
||||
#else
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])) );
|
||||
#endif // CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
|
||||
|
||||
#if CC_REBIND_INDICES_BUFFER
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
#endif
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
#else // ! CC_TEXTURE_ATLAS_USE_VAO
|
||||
|
||||
//
|
||||
// Using VBO without VAO
|
||||
//
|
||||
|
||||
#define kQuadSize sizeof(m_pQuads[0].bl)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
|
||||
|
||||
// XXX: update is done in draw... perhaps it should be done in a timer
|
||||
if (m_bDirty) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*start, sizeof(m_pQuads[0]) * n , &m_pQuads[start] );
|
||||
m_bDirty = false;
|
||||
}
|
||||
|
||||
ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
|
||||
|
||||
// vertices
|
||||
glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));
|
||||
|
||||
// colors
|
||||
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));
|
||||
|
||||
// tex coords
|
||||
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, texCoords));
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
|
||||
glDrawElements(GL_TRIANGLE_STRIP, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])) );
|
||||
#else
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])) );
|
||||
#endif // CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
#endif // CC_TEXTURE_ATLAS_USE_VAO
|
||||
|
||||
CC_INCREMENT_GL_DRAWS(1);
|
||||
ccGLBindTexture2D( m_pTexture->getName() );
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_VAO
|
||||
|
||||
//
|
||||
// Using VBO and VAO
|
||||
//
|
||||
|
||||
// XXX: update is done in draw... perhaps it should be done in a timer
|
||||
if (m_bDirty)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*start, sizeof(m_pQuads[0]) * n , &m_pQuads[start] );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
m_bDirty = false;
|
||||
}
|
||||
|
||||
glBindVertexArray( m_uVAOname );
|
||||
|
||||
#if CC_REBIND_INDICES_BUFFER
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
|
||||
#endif
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
|
||||
glDrawElements(GL_TRIANGLE_STRIP, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])) );
|
||||
#else
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])) );
|
||||
#endif // CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
|
||||
|
||||
#if CC_REBIND_INDICES_BUFFER
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
#endif
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
#else // ! CC_TEXTURE_ATLAS_USE_VAO
|
||||
|
||||
//
|
||||
// Using VBO without VAO
|
||||
//
|
||||
|
||||
#define kQuadSize sizeof(m_pQuads[0].bl)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
|
||||
|
||||
// XXX: update is done in draw... perhaps it should be done in a timer
|
||||
if (m_bDirty) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*start, sizeof(m_pQuads[0]) * n , &m_pQuads[start] );
|
||||
m_bDirty = false;
|
||||
}
|
||||
|
||||
ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
|
||||
|
||||
// vertices
|
||||
glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));
|
||||
|
||||
// colors
|
||||
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));
|
||||
|
||||
// tex coords
|
||||
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, texCoords));
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
|
||||
|
||||
#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
|
||||
glDrawElements(GL_TRIANGLE_STRIP, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])) );
|
||||
#else
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])) );
|
||||
#endif // CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
#endif // CC_TEXTURE_ATLAS_USE_VAO
|
||||
|
||||
CC_INCREMENT_GL_DRAWS(1);
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,11 @@ void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thi
|
|||
}
|
||||
else
|
||||
{
|
||||
ccDrawInit();
|
||||
ccGLInvalidateStateCache();
|
||||
cocos2d::CCDirector::sharedDirector()->setGLDefaultValues();
|
||||
CCShaderCache::sharedShaderCache()->reloadDefaultShaders();
|
||||
cocos2d::CCTextureCache::reloadAllTextures();
|
||||
cocos2d::CCDirector::sharedDirector()->setGLDefaultValues();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue