头文件
#ifndef __EFFECT_SPRITE_H__ #define __EFFECT_SPRITE_H__ #include "cocos2d.h" USING_NS_CC; class EffectSprite; class Effect : public Ref { public: GLProgramState* getGLProgramState() const { return _glprogramstate; } virtual void setTarget(EffectSprite *sprite){} protected: bool initGLProgramState(const std::string &fragmentFilename) { auto fileUtiles = FileUtils::getInstance(); auto fragmentFullPath = fileUtiles->fullPathForFilename(fragmentFilename); auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath); auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str()); #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WP8 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) _fragSource = fragSource; #endif _glprogramstate = GLProgramState::getOrCreateWithGLProgram(glprogram); _glprogramstate->retain(); return _glprogramstate != nullptr; } Effect() : _glprogramstate(nullptr) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WP8 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) _backgroundListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom*) { auto glProgram = _glprogramstate->getGLProgram(); glProgram->reset(); glProgram->initWithByteArrays(ccPositionTextureColor_noMVP_vert, _fragSource.c_str()); glProgram->link(); glProgram->updateUniforms(); } ); Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backgroundListener, -1); #endif } virtual ~Effect() { CC_SAFE_RELEASE_NULL(_glprogramstate); #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WP8 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) Director::getInstance()->getEventDispatcher()->removeEventListener(_backgroundListener); #endif } GLProgramState *_glprogramstate; #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WP8 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) std::string _fragSource; EventListenerCustom* _backgroundListener; #endif }; class EffectSprite : public Sprite { public: static EffectSprite *create(const std::string& filename) { auto ret = new (std::nothrow) EffectSprite; if (ret && ret->initWithFile(filename)) { ret->autorelease(); return ret; } CC_SAFE_RELEASE(ret); return nullptr; } void setEffect(Effect* effect) { if (_defaultEffect != effect) { effect->setTarget(this); CC_SAFE_RELEASE(_defaultEffect); _defaultEffect = effect; CC_SAFE_RETAIN(_defaultEffect); setGLProgramState(_defaultEffect->getGLProgramState()); } } /*void addEffect(Effect *effect, ssize_t order) { effect->retain(); effect->setTarget(this); _effects.push_back(std::make_tuple(order, effect, QuadCommand())); std::sort(std::begin(_effects), std::end(_effects), tuple_sort); }*/ void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override { #if CC_USE_CULLING // Don't do calculate the culling if the transform was not updated _insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; if (_insideBounds) #endif { // negative effects: order < 0 int idx = 0; for (auto &effect : _effects) { if (std::get<0>(effect) >= 0) break; QuadCommand &q = std::get<2>(effect); q.init(_globalZOrder, _texture->getName(), std::get<1>(effect)->getGLProgramState(), _blendFunc, &_quad, 1, transform/*, flags*/); renderer->addCommand(&q); idx++; } // normal effect: order == 0 _quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform/*, flags*/); renderer->addCommand(&_quadCommand); // postive effects: oder >= 0 for (auto it = std::begin(_effects) + idx; it != std::end(_effects); ++it) { QuadCommand &q = std::get<2>(*it); q.init(_globalZOrder, _texture->getName(), std::get<1>(*it)->getGLProgramState(), _blendFunc, &_quad, 1, transform/*, flags*/); renderer->addCommand(&q); idx++; } } } protected: EffectSprite() : _defaultEffect(nullptr) { _effects.reserve(2); } ~EffectSprite() { for (auto &tuple : _effects) { std::get<1>(tuple)->release(); } CC_SAFE_RELEASE(_defaultEffect); } std::vector<std::tuple<ssize_t, Effect*, QuadCommand>> _effects; Effect* _defaultEffect; }; // Outline class EffectOutline : public Effect { public: CREATE_FUNC(EffectOutline); bool init() { initGLProgramState("Shaders/example_outline.fsh"); Vec3 color(1.0f, 0.2f, 0.3f); GLfloat radius = 0.01f; GLfloat threshold = 1.75; _glprogramstate->setUniformVec3("u_outlineColor", color); _glprogramstate->setUniformFloat("u_radius", radius); _glprogramstate->setUniformFloat("u_threshold", threshold); return true; } }; // Noise class EffectNoise : public Effect { public: CREATE_FUNC(EffectNoise); protected: bool init() { initGLProgramState("Shaders/example_Noisy.fsh"); return true; } virtual void setTarget(EffectSprite* sprite) override { auto s = sprite->getTexture()->getContentSizeInPixels(); getGLProgramState()->setUniformVec2("resolution", Vec2(s.width, s.height)); } }; // Edge Detect class EffectEdgeDetect : public Effect { public: CREATE_FUNC(EffectEdgeDetect); protected: bool init() { initGLProgramState("Shaders/example_edgeDetection.fsh"); return true; } virtual void setTarget(EffectSprite* sprite) override { auto s = sprite->getTexture()->getContentSizeInPixels(); getGLProgramState()->setUniformVec2("resolution", Vec2(s.width, s.height)); } }; // Grey class EffectGreyScale : public Effect { public: CREATE_FUNC(EffectGreyScale); protected: bool init() { initGLProgramState("Shaders/example_greyScale.fsh"); return true; } }; // Sepia class EffectSepia : public Effect { public: CREATE_FUNC(EffectSepia); protected: bool init() { initGLProgramState("Shaders/example_sepia.fsh"); return true; } }; // bloom class EffectBloom : public Effect { public: CREATE_FUNC(EffectBloom); protected: bool init() { initGLProgramState("Shaders/example_bloom.fsh"); return true; } virtual void setTarget(EffectSprite* sprite) override { auto s = sprite->getTexture()->getContentSizeInPixels(); getGLProgramState()->setUniformVec2("resolution", Vec2(s.width, s.height)); } }; // cel shading class EffectCelShading : public Effect { public: CREATE_FUNC(EffectCelShading); protected: bool init() { initGLProgramState("Shaders/example_celShading.fsh"); return true; } virtual void setTarget(EffectSprite* sprite) override { auto s = sprite->getTexture()->getContentSizeInPixels(); getGLProgramState()->setUniformVec2("resolution", Vec2(s.width, s.height)); } }; // Lens Flare class EffectLensFlare : public Effect { public: CREATE_FUNC(EffectLensFlare); protected: bool init() { initGLProgramState("Shaders/example_lensFlare.fsh"); return true; } virtual void setTarget(EffectSprite* sprite) override { auto s = sprite->getTexture()->getContentSizeInPixels(); getGLProgramState()->setUniformVec2("textureResolution", Vec2(s.width, s.height)); s = Director::getInstance()->getWinSize(); getGLProgramState()->setUniformVec2("resolution", Vec2(s.width, s.height)); } }; class EffectNormalMapped : public Effect { public: CREATE_FUNC(EffectNormalMapped); static EffectNormalMapped* create(const std::string&normalMapFileName) { EffectNormalMapped *normalMappedSprite = new (std::nothrow) EffectNormalMapped(); if (normalMappedSprite && normalMappedSprite->init() && normalMappedSprite->initNormalMap(normalMapFileName)) { normalMappedSprite->autorelease(); return normalMappedSprite; } CC_SAFE_DELETE(normalMappedSprite); return nullptr; } void setKBump(float value); void setLightPos(const Vec3& pos); void setLightColor(const Color4F& color); float getKBump()const{ return _kBump; } protected: bool init(); bool initNormalMap(const std::string&normalMapFileName); virtual void setTarget(EffectSprite* sprite) override; EffectSprite* _sprite; Vec3 _lightPos; Color4F _lightColor; float _kBump; }; bool EffectNormalMapped::init() { initGLProgramState("Shaders3D/Normal.frag"); _kBump = 2; return true; } bool EffectNormalMapped::initNormalMap(const std::string& normalMapFileName) { auto normalMapTextrue = Director::getInstance()->getTextureCache()->addImage(normalMapFileName); getGLProgramState()->setUniformTexture("u_normalMap", normalMapTextrue); return true; } void EffectNormalMapped::setTarget(EffectSprite* sprite) { _sprite = sprite; getGLProgramState()->setUniformFloat("u_kBump", _kBump); getGLProgramState()->setUniformVec2("u_contentSize", Vec2(sprite->getContentSize().width, sprite->getContentSize().height)); } void EffectNormalMapped::setKBump(float value) { _kBump = value; auto glProgramState = getGLProgramState(); if (glProgramState) glProgramState->setUniformFloat("u_kBump", _kBump); } void EffectNormalMapped::setLightPos(const Vec3& pos) { _lightPos = pos; auto glProgramState = getGLProgramState(); if (glProgramState) glProgramState->setUniformVec4("u_lightPosInLocalSpace", Vec4(_lightPos.x, _lightPos.y, _lightPos.z, 1)); } void EffectNormalMapped::setLightColor(const Color4F& color) { _lightColor = color; auto glProgramState = getGLProgramState(); if (glProgramState) getGLProgramState()->setUniformVec3("u_diffuseL", Vec3(_lightColor.r, _lightColor.g, _lightColor.b)); } #endif //__EFFECT_SPRITE_H__
auto _sprite = EffectSprite::create("HelloWorld.png"); _sprite->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y)); addChild(_sprite); _sprite->setEffect(EffectGreyScale::create());