Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyufei49 committed Aug 19, 2014
1 parent 9f2216c commit 430890a
Show file tree
Hide file tree
Showing 11 changed files with 568 additions and 0 deletions.
215 changes: 215 additions & 0 deletions Classes/FilterNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#include "FilterNode.h"
#include "cocos-ext.h"

FilterNode::FilterNode():_srcNode(NULL)
{ }

FilterNode::~FilterNode()
{
CCLog("------------");
}

CCGLProgram* FilterNode::commonPrograme(const GLchar* src)
{
CCGLProgram* pp = new CCGLProgram();
if (pp) {
pp->initWithVertexShaderByteArray(ccPositionTextureColor_vert, src);
pp->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
pp->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
pp->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
pp->link();
pp->updateUniforms();
}
return pp;
}

FilterNode* FilterNode::create(CCNode* src, const CCSize& size)
{
FilterNode* ret = new FilterNode();
if (ret && ret->init(src, size)) {
ret->autorelease();
return ret;
} else {
CC_SAFE_RELEASE(ret);
return NULL;
}
}

bool FilterNode::init(CCNode* src, const CCSize& size)
{
bool bRet = false;
do {
if (_srcNode) {
CCLog("init can only be called once!");
}
CC_BREAK_IF(!CCRenderTexture::initWithWidthAndHeight(size.width, size.height,
kCCTexture2DPixelFormat_RGBA8888));
_srcNode = src;
if (_srcNode)
_pos = _srcNode->getPosition();
else
_pos = CCPointZero;
bRet = true;
}while(0);
return bRet;
}

void FilterNode::capture()
{
if (!_srcNode){ return; }
CCPoint pos = _srcNode->getPosition();
CCPoint ar = _srcNode->getAnchorPoint();
_pos = ccpSub(pos, _pos);
_srcNode->setPosition(ar.x * _srcNode->getContentSize().width, ar.y * _srcNode->getContentSize().height);
this->beginWithClear(0, 0, 0, 0);
_srcNode->visit();
this->end();
_srcNode->setPosition(pos);
this->getSprite()->setPosition(ccpAdd(this->getSprite()->getPosition(), _pos));
_pos = pos;
}

/*********************| GuassianBlur class |*********************/
static GLchar* hblurSrc = NULL;
static GLchar* vblurSrc = NULL;
static GaussianBlur* _scSizeBlurNode = NULL;

GaussianBlur::GaussianBlur():f1(NULL), f2(NULL), _showing(false)
{ }

GaussianBlur::~GaussianBlur()
{
CC_SAFE_RELEASE_NULL(f1);
CC_SAFE_RELEASE_NULL(f2);
}

bool GaussianBlur::do_ready()
{
unsigned long l = 0;
unsigned char* data = NULL;
if (!hblurSrc) {
hblurSrc = (GLchar*)CCFileUtils::sharedFileUtils()->getFileData("shaders/hblur.fsh", "rb", &l);
hblurSrc[l] = 0;
}
if (!vblurSrc) {
vblurSrc = (GLchar*)CCFileUtils::sharedFileUtils()->getFileData("shaders/vblur.fsh", "rb", &l);
vblurSrc[l] = 0;
}
screenBlurNodeInstance();
return hblurSrc && vblurSrc;
}

void GaussianBlur::do_free()
{
CC_SAFE_DELETE_ARRAY(hblurSrc);
CC_SAFE_DELETE_ARRAY(vblurSrc);
CC_SAFE_RELEASE_NULL(_scSizeBlurNode);
}

GaussianBlur*GaussianBlur::create(CCNode* src, const CCSize& size)
{
GaussianBlur* ret = new GaussianBlur();
if (ret && ret->init(src, size)) {
ret->autorelease();
return ret;
} else {
CC_SAFE_DELETE(ret);
return NULL;
}
}

GaussianBlur*GaussianBlur::screenBlurNodeInstance()
{
if (_scSizeBlurNode)
return _scSizeBlurNode;
_scSizeBlurNode = new GaussianBlur();
_scSizeBlurNode->retain();
_scSizeBlurNode->init(NULL, CCDirector::sharedDirector()->getVisibleSize(), true);
return _scSizeBlurNode;
}

bool GaussianBlur::init(CCNode* src, const CCSize& size, bool reused)
{
bool bRet = false;
do {
CC_BREAK_IF(!CCNode::init());
f1 = FilterNode::create(src, size);
CC_BREAK_IF(!f1);
f1->retain();
CCGLProgram* s = FilterNode::commonPrograme(hblurSrc);
f1->filter(s);
setBlurSize(size, 1);
f1->capture();
s->release();

f2 = FilterNode::create(f1->getSprite(), size);
CC_BREAK_IF(!f2);
s = FilterNode::commonPrograme(vblurSrc);
f2->filter(s);
setBlurSize(size, 2);
f2->retain();
f2->capture();
s->release();

this->setContentSize(size);
this->setAnchorPoint(CCPointZero);
this->setPosition(CCPointZero);
f2->setPosition(size.width /2, size.height/2);
this->addChild(f2);

bRet = true;
}while(0);
return bRet;
}

void GaussianBlur::setBlurSize(const CCSize& size, const int which , GLfloat ratio)
{
CCGLProgram* s = NULL;
GLint blurSLoc = 0;
if (!which || 1 == which) {
s = f1->getSprite()->getShaderProgram();
blurSLoc = glGetUniformLocation(s->getProgram(), "ratio");
s->setUniformLocationWith1f(blurSLoc, ratio);
blurSLoc = glGetUniformLocation(s->getProgram(), "hsize");
s->setUniformLocationWith1f(blurSLoc, (GLfloat)(size.width));
}
if (!which || 2 == which) {
s = f2->getSprite()->getShaderProgram();
blurSLoc = glGetUniformLocation(s->getProgram(), "ratio");
s->setUniformLocationWith1f(blurSLoc, ratio);
blurSLoc = glGetUniformLocation(s->getProgram(), "vsize");
s->setUniformLocationWith1f(blurSLoc, (GLfloat)(size.height));
}
}

bool GaussianBlur::reset(CCNode* src)
{
f1->changeNode(src);
f2->changeNode(f1->getSprite());
}

void GaussianBlur::cleanFromWorld()
{
realtime(false);
this->removeFromParent();
this->removeAllChildren();
this->addChild(f2);
_showing = false;
}

void GaussianBlur::show()
{
if (_showing) return;
CCScene* s =CCDirector::sharedDirector()->getRunningScene();
if (s) {
_showing = true;
s->addChild(this);
}
}

void GaussianBlur::capture()
{
f1->capture();
f2->capture();
}

120 changes: 120 additions & 0 deletions Classes/FilterNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#ifndef FILETERSPRITE_H
#define FILETERSPRITE_H

/**
* Desc: 特效node
* Auth: 张宇飞
* Date: 2014-08-19
*/

#include "cocos2d.h"
USING_NS_CC;

class FilterProto
{
public:
FilterProto():_rt(false) {}
virtual void capture() = 0;
virtual void updateCapture(bool b) = 0;
void realtime(bool b) {
if (b != _rt) {
_rt = b;
updateCapture(b);
}
}
inline bool isRealTime() {return _rt;}
private:
bool _rt;
};

#define UPCAP_FUNC(_cls_, _freshfunc_) \
void updateCapture(bool b) { \
if (b) \
this->schedule(schedule_selector(_cls_::_freshfunc_)); \
else \
this->unschedule(schedule_selector(_cls_::_freshfunc_));\
}

/**
* @brief The FilterNode class
*/
class FilterNode : public CCRenderTexture, public FilterProto
{
public:
FilterNode();
~FilterNode();
public:
static CCGLProgram* commonPrograme(const GLchar* src);
static FilterNode* create(CCNode* src, const CCSize& size);
inline static FilterNode* create(CCNode* src) {
if (src) return create(src, src->getContentSize());
return NULL;
}
public:
bool init(CCNode* src, const CCSize& size);
/* set filter */
inline void filter(CCGLProgram* shader) {
this->getSprite()->setShaderProgram(shader);
}
inline void changeNode(CCNode* src) {_srcNode = src; capture();}

/* take a capture means do draw elements once 快照 */
void capture();
UPCAP_FUNC(FilterNode, freshCapture)
private:
void freshCapture(float dt) { capture();}
private:
CCNode* _srcNode;
CCPoint _pos;
};

/**
* @brief The GaussianBlur class use two FilterNode, one with horizontal blur and
* send result to next FilerNode with vertical blur .Then sencond result will show
* as Gaussian blur effect
* 中文:这个类用了两个FilterNode来实现高斯模糊。第一个用横向的模糊,结果作为第二个的
* 输入进行纵向模糊,得到的结果就是需要的了。
*/
class GaussianBlur : public CCNode, public FilterProto
{
public:
GaussianBlur();
~GaussianBlur();
public:
/* call this at global init time */
static bool do_ready();
/* call this at global end time */
static void do_free();

static GaussianBlur* create(CCNode* src, const CCSize& size);
inline static GaussianBlur* create(CCNode* src) {
if (src) return create(src, src->getContentSize());
return NULL;
}
/**
* @brief screenBlurNode get a blur node instance with screen size(中文:获取一个屏幕大小的模糊单例)
*/
static GaussianBlur* screenBlurNodeInstance();
public:
bool init(CCNode* src, const CCSize& size, bool reused = false);
/**
* @brief setBlurSize 设置模糊程度
* @param size 模糊范围
* @param which 0 all , 1 horizontal blur, 2 vertical blur(中文:0横纵向同时模糊,1横向模糊设定,2纵向模糊设定)
* @param ratio 模糊半径
*/
void setBlurSize(const CCSize& size, const int which = 0, GLfloat ratio = 3.0);
bool reset(CCNode* src);
void cleanFromWorld();
/* @brief show try use runningScene()->addChild to show this(中文:尝试用getRunningScene()->addChild来显示当前节点 */
void show();
void capture();
UPCAP_FUNC(GaussianBlur, freshCapture)
private:
void freshCapture(float dt) { capture();}
private:
FilterNode *f1, *f2;
bool _showing;
};

#endif // FILETERSPRITE_H
Loading

0 comments on commit 430890a

Please sign in to comment.