mirror of https://github.com/axmolengine/axmol.git
300 lines
8.5 KiB
C++
300 lines
8.5 KiB
C++
//
|
|
// Created by NiTe Luo on 12/2/13.
|
|
//
|
|
|
|
|
|
#include "CCNewRenderTexture.h"
|
|
#include "CustomCommand.h"
|
|
#include "Renderer.h"
|
|
#include "GroupCommand.h"
|
|
#include "CCConfiguration.h"
|
|
#include "CCDirector.h"
|
|
|
|
NS_CC_BEGIN
|
|
|
|
NewRenderTexture* NewRenderTexture::create(int w, int h, Texture2D::PixelFormat eFormat, GLuint uDepthStencilFormat)
|
|
{
|
|
NewRenderTexture* pRet = new NewRenderTexture();
|
|
|
|
if(pRet && pRet->initWithWidthAndHeight(w, h, eFormat, uDepthStencilFormat))
|
|
{
|
|
pRet->autorelease();
|
|
return pRet;
|
|
}
|
|
CC_SAFE_DELETE(pRet);
|
|
return NULL;
|
|
}
|
|
|
|
NewRenderTexture* NewRenderTexture::create(int w, int h, Texture2D::PixelFormat eFormat)
|
|
{
|
|
NewRenderTexture* pRet = new NewRenderTexture();
|
|
|
|
if(pRet && pRet->initWithWidthAndHeight(w, h, eFormat))
|
|
{
|
|
pRet->autorelease();
|
|
return pRet;
|
|
}
|
|
CC_SAFE_DELETE(pRet);
|
|
return NULL;
|
|
}
|
|
|
|
NewRenderTexture* NewRenderTexture::create(int w, int h)
|
|
{
|
|
NewRenderTexture* pRet = new NewRenderTexture();
|
|
|
|
if(pRet && pRet->initWithWidthAndHeight(w, h, Texture2D::PixelFormat::RGB888 , 0))
|
|
{
|
|
pRet->autorelease();
|
|
return pRet;
|
|
}
|
|
CC_SAFE_DELETE(pRet);
|
|
return NULL;
|
|
}
|
|
|
|
void NewRenderTexture::draw()
|
|
{
|
|
if (_autoDraw)
|
|
{
|
|
//Begin will create a render group using new render target
|
|
begin();
|
|
|
|
//clear screen
|
|
CustomCommand* clearCmd = CustomCommand::getCommandPool().generateCommand();
|
|
clearCmd->init(0, _vertexZ);
|
|
clearCmd->func = CC_CALLBACK_0(NewRenderTexture::onClear, this);
|
|
Renderer::getInstance()->addCommand(clearCmd);
|
|
|
|
//! make sure all children are drawn
|
|
sortAllChildren();
|
|
|
|
Object *pElement;
|
|
CCARRAY_FOREACH(_children, pElement)
|
|
{
|
|
Node *child = static_cast<Node*>(pElement);
|
|
|
|
if (child != _sprite)
|
|
{
|
|
child->visit();
|
|
}
|
|
}
|
|
|
|
//End will pop the current render group
|
|
end();
|
|
}
|
|
}
|
|
|
|
void NewRenderTexture::beginWithClear(float r, float g, float b, float a)
|
|
{
|
|
beginWithClear(r, g, b, a, 0, 0, GL_COLOR_BUFFER_BIT);
|
|
}
|
|
|
|
void NewRenderTexture::beginWithClear(float r, float g, float b, float a, float depthValue)
|
|
{
|
|
beginWithClear(r, g, b, a, depthValue, 0, GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
|
|
void NewRenderTexture::beginWithClear(float r, float g, float b, float a, float depthValue, int stencilValue)
|
|
{
|
|
beginWithClear(r, g, b, a, depthValue, stencilValue, GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
|
|
}
|
|
|
|
void NewRenderTexture::beginWithClear(float r, float g, float b, float a, float depthValue, int stencilValue, GLbitfield flags)
|
|
{
|
|
setClearColor({r, g, b, a});
|
|
|
|
setClearDepth(depthValue);
|
|
|
|
setClearStencil(stencilValue);
|
|
|
|
setClearFlags(flags);
|
|
|
|
this->begin();
|
|
|
|
//clear screen
|
|
CustomCommand* clearCmd = CustomCommand::getCommandPool().generateCommand();
|
|
clearCmd->init(0, _vertexZ);
|
|
clearCmd->func = CC_CALLBACK_0(NewRenderTexture::onClear, this);
|
|
Renderer::getInstance()->addCommand(clearCmd);
|
|
}
|
|
|
|
void NewRenderTexture::begin()
|
|
{
|
|
kmGLMatrixMode(KM_GL_PROJECTION);
|
|
kmGLPushMatrix();
|
|
kmGLGetMatrix(KM_GL_PROJECTION, &_projectionMatrix);
|
|
|
|
kmGLMatrixMode(KM_GL_MODELVIEW);
|
|
kmGLPushMatrix();
|
|
kmGLGetMatrix(KM_GL_MODELVIEW, &_transformMatrix);
|
|
|
|
GroupCommand* groupCommand = GroupCommand::getCommandPool().generateCommand();
|
|
groupCommand->init(0, _vertexZ);
|
|
|
|
Renderer::getInstance()->addCommand(groupCommand);
|
|
Renderer::getInstance()->pushGroup(groupCommand->getRenderQueueID());
|
|
|
|
CustomCommand* beginCmd = CustomCommand::getCommandPool().generateCommand();
|
|
beginCmd->init(0, _vertexZ);
|
|
beginCmd->func = CC_CALLBACK_0(NewRenderTexture::onBegin, this);
|
|
|
|
Renderer::getInstance()->addCommand(beginCmd);
|
|
}
|
|
|
|
void NewRenderTexture::end()
|
|
{
|
|
CustomCommand* endCmd = CustomCommand::getCommandPool().generateCommand();
|
|
endCmd->init(0, _vertexZ);
|
|
endCmd->func = CC_CALLBACK_0(NewRenderTexture::onEnd, this);
|
|
|
|
Renderer::getInstance()->addCommand(endCmd);
|
|
|
|
Renderer::getInstance()->popGroup();
|
|
}
|
|
|
|
void NewRenderTexture::onBegin()
|
|
{
|
|
//
|
|
kmGLGetMatrix(KM_GL_PROJECTION, &_oldProjMatrix);
|
|
kmGLMatrixMode(KM_GL_PROJECTION);
|
|
kmGLLoadMatrix(&_projectionMatrix);
|
|
|
|
kmGLGetMatrix(KM_GL_MODELVIEW, &_oldTransMatrix);
|
|
kmGLMatrixMode(KM_GL_MODELVIEW);
|
|
kmGLLoadMatrix(&_transformMatrix);
|
|
|
|
Director *director = Director::getInstance();
|
|
director->setProjection(director->getProjection());
|
|
|
|
const Size& texSize = _texture->getContentSizeInPixels();
|
|
|
|
// Calculate the adjustment ratios based on the old and new projections
|
|
Size size = director->getWinSizeInPixels();
|
|
float widthRatio = size.width / texSize.width;
|
|
float heightRatio = size.height / texSize.height;
|
|
|
|
// Adjust the orthographic projection and viewport
|
|
glViewport(0, 0, (GLsizei)texSize.width, (GLsizei)texSize.height);
|
|
|
|
|
|
kmMat4 orthoMatrix;
|
|
kmMat4OrthographicProjection(&orthoMatrix, (float)-1.0 / widthRatio, (float)1.0 / widthRatio,
|
|
(float)-1.0 / heightRatio, (float)1.0 / heightRatio, -1,1 );
|
|
kmGLMultMatrix(&orthoMatrix);
|
|
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_oldFBO);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, _FBO);
|
|
|
|
//TODO move this to configration, so we don't check it every time
|
|
/* Certain Qualcomm Andreno gpu's will retain data in memory after a frame buffer switch which corrupts the render to the texture. The solution is to clear the frame buffer before rendering to the texture. However, calling glClear has the unintended result of clearing the current texture. Create a temporary texture to overcome this. At the end of RenderTexture::begin(), switch the attached texture to the second one, call glClear, and then switch back to the original texture. This solution is unnecessary for other devices as they don't have the same issue with switching frame buffers.
|
|
*/
|
|
if (Configuration::getInstance()->checkForGLExtension("GL_QCOM"))
|
|
{
|
|
// -- bind a temporary texture so we can clear the render buffer without losing our texture
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _textureCopy->getName(), 0);
|
|
CHECK_GL_ERROR_DEBUG();
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture->getName(), 0);
|
|
}
|
|
}
|
|
|
|
void NewRenderTexture::onEnd()
|
|
{
|
|
Director *director = Director::getInstance();
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, _oldFBO);
|
|
|
|
// restore viewport
|
|
director->setViewport();
|
|
|
|
//
|
|
kmGLMatrixMode(KM_GL_PROJECTION);
|
|
kmGLLoadMatrix(&_oldProjMatrix);
|
|
|
|
kmGLMatrixMode(KM_GL_MODELVIEW);
|
|
kmGLLoadMatrix(&_oldTransMatrix);
|
|
}
|
|
|
|
void NewRenderTexture::onClear()
|
|
{
|
|
// save clear color
|
|
GLfloat oldClearColor[4] = {0.0f};
|
|
GLfloat oldDepthClearValue = 0.0f;
|
|
GLint oldStencilClearValue = 0;
|
|
|
|
// backup and set
|
|
if (_clearFlags & GL_COLOR_BUFFER_BIT)
|
|
{
|
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, oldClearColor);
|
|
glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearColor.a);
|
|
}
|
|
|
|
if (_clearFlags & GL_DEPTH_BUFFER_BIT)
|
|
{
|
|
glGetFloatv(GL_DEPTH_CLEAR_VALUE, &oldDepthClearValue);
|
|
glClearDepth(_clearDepth);
|
|
}
|
|
|
|
if (_clearFlags & GL_STENCIL_BUFFER_BIT)
|
|
{
|
|
glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &oldStencilClearValue);
|
|
glClearStencil(_clearStencil);
|
|
}
|
|
|
|
// clear
|
|
glClear(_clearFlags);
|
|
|
|
// restore
|
|
if (_clearFlags & GL_COLOR_BUFFER_BIT)
|
|
{
|
|
glClearColor(oldClearColor[0], oldClearColor[1], oldClearColor[2], oldClearColor[3]);
|
|
}
|
|
if (_clearFlags & GL_DEPTH_BUFFER_BIT)
|
|
{
|
|
glClearDepth(oldDepthClearValue);
|
|
}
|
|
if (_clearFlags & GL_STENCIL_BUFFER_BIT)
|
|
{
|
|
glClearStencil(oldStencilClearValue);
|
|
}
|
|
}
|
|
|
|
void NewRenderTexture::clearDepth(float depthValue)
|
|
{
|
|
setClearDepth(depthValue);
|
|
|
|
this->begin();
|
|
|
|
CustomCommand* cmd = CustomCommand::getCommandPool().generateCommand();
|
|
cmd->init(0, _vertexZ);
|
|
cmd->func = CC_CALLBACK_0(NewRenderTexture::onClearDepth, this);
|
|
|
|
Renderer::getInstance()->addCommand(cmd);
|
|
|
|
this->end();
|
|
}
|
|
|
|
void NewRenderTexture::onClearDepth()
|
|
{
|
|
//! save old depth value
|
|
GLfloat depthClearValue;
|
|
glGetFloatv(GL_DEPTH_CLEAR_VALUE, &depthClearValue);
|
|
|
|
glClearDepth(_clearDepth);
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
|
|
// restore clear color
|
|
glClearDepth(depthClearValue);
|
|
}
|
|
|
|
NewRenderTexture::NewRenderTexture()
|
|
:RenderTexture()
|
|
{
|
|
|
|
}
|
|
|
|
NewRenderTexture::~NewRenderTexture()
|
|
{
|
|
|
|
}
|
|
|
|
NS_CC_END |