axmol/tests/cpp-tests/Classes/ShaderTest/ShaderTest.cpp

891 lines
20 KiB
C++
Raw Normal View History

#include "ShaderTest.h"
#include "../testResource.h"
#include "cocos2d.h"
2014-05-10 02:48:11 +08:00
#include "ShaderTest.vsh.h"
#include "shaderTest.psh.h"
static int sceneIdx = -1;
2014-05-10 02:48:11 +08:00
#define MAX_LAYER 11
static Layer* createShaderLayer(int nIndex)
{
switch (sceneIdx)
{
2014-05-10 02:48:11 +08:00
case 0: return new ShaderFalme();
case 1: return new ShaderMandelbrot();
case 2: return new ShaderJulia();
case 3: return new ShaderHeart();
case 4: return new ShaderFlower();
case 5: return new ShaderPlasma();
case 6: return new ShaderBlur();
case 7: return new ShaderRetroEffect();
2014-05-10 02:48:11 +08:00
case 8: return new ShaderMonjori();
case 9: return new ShaderStarNest();
case 10: return new ShaderRelentless();
}
return NULL;
}
static Layer* nextAction(void)
{
sceneIdx++;
sceneIdx = sceneIdx % MAX_LAYER;
auto layer = createShaderLayer(sceneIdx);
layer->autorelease();
return layer;
}
static Layer* backAction(void)
{
sceneIdx--;
int total = MAX_LAYER;
if( sceneIdx < 0 )
sceneIdx += total;
auto layer = createShaderLayer(sceneIdx);
layer->autorelease();
return layer;
}
static Layer* restartAction(void)
{
auto layer = createShaderLayer(sceneIdx);
layer->autorelease();
return layer;
}
ShaderTestDemo::ShaderTestDemo()
{
}
void ShaderTestDemo::backCallback(Ref* sender)
{
auto s = new ShaderTestScene();
s->addChild( backAction() );
Director::getInstance()->replaceScene(s);
s->release();
}
void ShaderTestDemo::nextCallback(Ref* sender)
{
auto s = new ShaderTestScene();//CCScene::create();
s->addChild( nextAction() );
Director::getInstance()->replaceScene(s);
s->release();
}
std::string ShaderTestDemo::title() const
{
return "No title";
}
std::string ShaderTestDemo::subtitle() const
{
return "";
}
void ShaderTestDemo::restartCallback(Ref* sender)
{
auto s = new ShaderTestScene();
s->addChild(restartAction());
Director::getInstance()->replaceScene(s);
s->release();
}
///---------------------------------------
//
// ShaderNode
//
///---------------------------------------
enum
{
SIZE_X = 256,
SIZE_Y = 256,
};
ShaderNode::ShaderNode()
2014-04-02 15:25:50 +08:00
:_center(Vector2(0.0f, 0.0f))
,_resolution(Vector2(0.0f, 0.0f))
,_time(0.0f)
{
}
ShaderNode::~ShaderNode()
{
}
ShaderNode* ShaderNode::shaderNodeWithVertex(const char *vert, const char *frag)
{
auto node = new ShaderNode();
node->initWithVertex(vert, frag);
node->autorelease();
return node;
}
bool ShaderNode::initWithVertex(const char *vert, const char *frag)
{
#if CC_ENABLE_CACHE_TEXTURE_DATA
auto listener = EventListenerCustom::create(EVENT_COME_TO_FOREGROUND, [this](EventCustom* event){
2014-05-09 07:42:36 +08:00
this->setGLProgram(nullptr);
loadShaderVertex(_vertFileName.c_str(), _fragFileName.c_str());
});
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
#endif
loadShaderVertex(vert, frag);
_time = 0;
2014-04-02 15:25:50 +08:00
_resolution = Vector2(SIZE_X, SIZE_Y);
getGLProgramState()->setUniformVec2("resolution", _resolution);
scheduleUpdate();
setContentSize(Size(SIZE_X, SIZE_Y));
setAnchorPoint(Vector2(0.5f, 0.5f));
_vertFileName = vert;
_fragFileName = frag;
return true;
}
void ShaderNode::loadShaderVertex(const char *vert, const char *frag)
{
2014-05-08 05:38:41 +08:00
auto shader = GLProgram::createWithFilenames(vert, frag);
2014-05-09 06:43:12 +08:00
this->setGLProgram(shader);
}
2012-06-08 13:55:28 +08:00
void ShaderNode::update(float dt)
{
_time += dt;
}
2014-04-15 16:16:14 +08:00
void ShaderNode::setPosition(const Vector2 &newPosition)
{
Node::setPosition(newPosition);
auto position = getPosition();
2014-04-02 15:25:50 +08:00
_center = Vector2(position.x * CC_CONTENT_SCALE_FACTOR(), position.y * CC_CONTENT_SCALE_FACTOR());
getGLProgramState()->setUniformVec2("center", _center);
}
2014-04-08 22:07:35 +08:00
void ShaderNode::draw(Renderer *renderer, const Matrix &transform, bool transformUpdated)
{
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(ShaderNode::onDraw, this, transform, transformUpdated);
renderer->addCommand(&_customCommand);
2013-12-25 16:38:43 +08:00
}
2014-04-10 10:16:16 +08:00
void ShaderNode::onDraw(const Matrix &transform, bool transformUpdated)
2013-12-25 16:38:43 +08:00
{
float w = SIZE_X, h = SIZE_Y;
GLfloat vertices[12] = {0,0, w,0, w,h, 0,0, 0,h, w,h};
2014-05-09 06:43:12 +08:00
auto glProgramState = getGLProgramState();
glProgramState->setVertexAttribPointer("a_position", 2, GL_FLOAT, GL_FALSE, 0, vertices);
glProgramState->apply(transform);
2014-05-09 03:34:26 +08:00
glDrawArrays(GL_TRIANGLES, 0, 6);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,6);
}
/// ShaderMonjori
ShaderMonjori::ShaderMonjori()
{
init();
}
bool ShaderMonjori::init()
{
if (ShaderTestDemo::init())
{
auto sn = ShaderNode::shaderNodeWithVertex("Shaders/example_Monjori.vsh", "Shaders/example_Monjori.fsh");
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
addChild(sn);
return true;
}
return false;
}
std::string ShaderMonjori::title() const
{
return "Shader: Frag shader";
}
std::string ShaderMonjori::subtitle() const
{
return "Monjori plane deformations";
}
/// ShaderMandelbrot
ShaderMandelbrot::ShaderMandelbrot()
{
init();
}
bool ShaderMandelbrot::init()
{
if (ShaderTestDemo::init())
{
auto sn = ShaderNode::shaderNodeWithVertex("Shaders/example_Mandelbrot.vsh", "Shaders/example_Mandelbrot.fsh");
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
addChild(sn);
return true;
}
return false;
}
std::string ShaderMandelbrot::title() const
{
return "Shader: Frag shader";
}
std::string ShaderMandelbrot::subtitle() const
{
return "Mandelbrot shader with Zoom";
}
/// ShaderJulia
ShaderJulia::ShaderJulia()
{
init();
}
bool ShaderJulia::init()
{
if (ShaderTestDemo::init())
{
auto sn = ShaderNode::shaderNodeWithVertex("Shaders/example_Julia.vsh", "Shaders/example_Julia.fsh");
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
addChild(sn);
return true;
}
return false;
}
std::string ShaderJulia::title() const
{
return "Shader: Frag shader";
}
std::string ShaderJulia::subtitle() const
{
return "Julia shader";
}
/// ShaderHeart
ShaderHeart::ShaderHeart()
{
init();
}
bool ShaderHeart::init()
{
if (ShaderTestDemo::init())
{
auto sn = ShaderNode::shaderNodeWithVertex("Shaders/example_Heart.vsh", "Shaders/example_Heart.fsh");
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
addChild(sn);
return true;
}
return false;
}
std::string ShaderHeart::title() const
{
return "Shader: Frag shader";
}
std::string ShaderHeart::subtitle() const
{
return "Heart";
}
/// ShaderFlower
ShaderFlower::ShaderFlower()
{
init();
}
bool ShaderFlower::init()
{
if (ShaderTestDemo::init())
{
auto sn = ShaderNode::shaderNodeWithVertex("Shaders/example_Flower.vsh", "Shaders/example_Flower.fsh");
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
addChild(sn);
return true;
}
return false;
}
std::string ShaderFlower::title() const
{
return "Shader: Frag shader";
}
std::string ShaderFlower::subtitle() const
{
return "Flower";
}
/// ShaderPlasma
ShaderPlasma::ShaderPlasma()
{
init();
}
bool ShaderPlasma::init()
{
if (ShaderTestDemo::init())
{
auto sn = ShaderNode::shaderNodeWithVertex("Shaders/example_Plasma.vsh", "Shaders/example_Plasma.fsh");
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
addChild(sn);
return true;
}
return false;
}
std::string ShaderPlasma::title() const
{
return "Shader: Frag shader";
}
std::string ShaderPlasma::subtitle() const
{
return "Plasma";
}
// ShaderBlur
class SpriteBlur : public Sprite
{
public:
~SpriteBlur();
void setBlurSize(float f);
bool initWithTexture(Texture2D* texture, const Rect& rect);
2014-04-08 22:07:35 +08:00
virtual void draw(Renderer *renderer, const Matrix &transform, bool transformUpdated) override;
void initProgram();
static SpriteBlur* create(const char *pszFileName);
2013-12-25 16:54:09 +08:00
protected:
2014-04-11 18:03:07 +08:00
void onDraw(const Matrix &transform, bool transformUpdated);
int _blurRadius;
Vector2 _pixelSize;
int _samplingRadius;
//gaussian = cons * exp( (dx*dx + dy*dy) * scale);
float _scale;
float _cons;
float _weightSum;
CustomCommand _customCommand;
};
SpriteBlur::~SpriteBlur()
{
}
SpriteBlur* SpriteBlur::create(const char *pszFileName)
{
SpriteBlur* pRet = new SpriteBlur();
if (pRet && pRet->initWithFile(pszFileName))
{
pRet->autorelease();
}
else
{
CC_SAFE_DELETE(pRet);
}
return pRet;
}
bool SpriteBlur::initWithTexture(Texture2D* texture, const Rect& rect)
{
_blurRadius = 0;
if( Sprite::initWithTexture(texture, rect) )
{
#if CC_ENABLE_CACHE_TEXTURE_DATA
auto listener = EventListenerCustom::create(EVENT_COME_TO_FOREGROUND, [this](EventCustom* event){
2014-05-09 07:42:36 +08:00
setGLProgram(nullptr);
initProgram();
});
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
#endif
auto s = getTexture()->getContentSizeInPixels();
_pixelSize = Vector2(1/s.width, 1/s.height);
2014-05-09 03:34:26 +08:00
_samplingRadius = 0;
this->initProgram();
getGLProgramState()->setUniformVec2("onePixelSize", _pixelSize);
2014-05-09 03:34:26 +08:00
return true;
}
return false;
}
void SpriteBlur::initProgram()
{
GLchar * fragSource = (GLchar*) String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename("Shaders/example_Blur.fsh").c_str())->getCString();
2014-05-08 05:38:41 +08:00
auto program = GLProgram::createWithByteArrays(ccPositionTextureColor_vert, fragSource);
2014-05-09 06:43:12 +08:00
setGLProgram(program);
2014-05-09 03:34:26 +08:00
2014-05-09 06:43:12 +08:00
auto glProgramState = getGLProgramState();
2014-05-09 03:34:26 +08:00
#define kQuadSize sizeof(_quad.bl)
size_t offset = (size_t)&_quad;
// position
int diff = offsetof( V3F_C4B_T2F, vertices);
2014-05-09 06:43:12 +08:00
glProgramState->setVertexAttribPointer("a_position", 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));
2014-05-09 03:34:26 +08:00
// texcoord
diff = offsetof( V3F_C4B_T2F, texCoords);
2014-05-09 06:43:12 +08:00
glProgramState->setVertexAttribPointer("a_texCoord", 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
2014-05-09 03:34:26 +08:00
// color
diff = offsetof( V3F_C4B_T2F, colors);
2014-05-09 06:43:12 +08:00
glProgramState->setVertexAttribPointer("a_color", 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));
}
2014-04-08 22:07:35 +08:00
void SpriteBlur::draw(Renderer *renderer, const Matrix &transform, bool transformUpdated)
2013-12-25 16:54:09 +08:00
{
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(SpriteBlur::onDraw, this, transform, transformUpdated);
renderer->addCommand(&_customCommand);
2013-12-25 16:54:09 +08:00
}
2014-04-11 18:03:07 +08:00
void SpriteBlur::onDraw(const Matrix &transform, bool transformUpdated)
{
GL::blendFunc(_blendFunc.src, _blendFunc.dst);
GL::bindTexture2D(_texture->getName());
2014-05-09 06:43:12 +08:00
auto glProgramState = getGLProgramState();
glProgramState->apply(transform);
2014-05-09 03:34:26 +08:00
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4);
}
void SpriteBlur::setBlurSize(float f)
{
if(_blurRadius == (int)f)
return;
_blurRadius = (int)f;
_samplingRadius = _blurRadius;
if (_samplingRadius > 10)
{
_samplingRadius = 10;
}
if (_blurRadius > 0)
{
float sigma = _blurRadius / 2.0f;
_scale = -0.5f / (sigma * sigma);
_cons = -1.0f * _scale / 3.141592f;
_weightSum = -_cons;
float weight;
int squareX;
for(int dx = 0; dx <= _samplingRadius; ++dx)
{
squareX = dx * dx;
weight = _cons * exp(squareX * _scale);
_weightSum += 2.0 * weight;
for (int dy = 1; dy <= _samplingRadius; ++dy)
{
weight = _cons * exp((squareX + dy * dy) * _scale);
_weightSum += 4.0 * weight;
}
}
}
log("_blurRadius:%d",_blurRadius);
2014-05-09 03:34:26 +08:00
getGLProgramState()->setUniformVec4("gaussianCoefficient", Vector4(_samplingRadius, _scale, _cons, _weightSum));
}
// ShaderBlur
ShaderBlur::ShaderBlur()
{
init();
}
std::string ShaderBlur::title() const
{
return "Shader: Frag shader";
}
std::string ShaderBlur::subtitle() const
{
return "Gaussian blur";
}
ControlSlider* ShaderBlur::createSliderCtl()
{
auto screenSize = Director::getInstance()->getWinSize();
ControlSlider *slider = ControlSlider::create("extensions/sliderTrack.png","extensions/sliderProgress.png" ,"extensions/sliderThumb.png");
slider->setAnchorPoint(Vector2(0.5f, 1.0f));
slider->setMinimumValue(0.0f); // Sets the min value of range
slider->setMaximumValue(25.0f); // Sets the max value of range
slider->setPosition(Vector2(screenSize.width / 2.0f, screenSize.height / 3.0f));
// When the value of the slider will change, the given selector will be call
slider->addTargetWithActionForControlEvents(this, cccontrol_selector(ShaderBlur::sliderAction), Control::EventType::VALUE_CHANGED);
slider->setValue(2.0f);
return slider;
}
bool ShaderBlur::init()
{
if( ShaderTestDemo::init() )
{
_blurSprite = SpriteBlur::create("Images/grossini.png");
auto sprite = Sprite::create("Images/grossini.png");
auto s = Director::getInstance()->getWinSize();
_blurSprite->setPosition(Vector2(s.width/3, s.height/2));
sprite->setPosition(Vector2(2*s.width/3, s.height/2));
addChild(_blurSprite);
addChild(sprite);
_sliderCtl = createSliderCtl();
addChild(_sliderCtl);
return true;
}
return false;
}
void ShaderBlur::sliderAction(Ref* sender, Control::EventType controlEvent)
{
ControlSlider* pSlider = (ControlSlider*)sender;
_blurSprite->setBlurSize(pSlider->getValue());
}
// ShaderRetroEffect
ShaderRetroEffect::ShaderRetroEffect()
: _label(nullptr)
, _accum(0.0f)
{
init();
}
bool ShaderRetroEffect::init()
{
if( ShaderTestDemo::init() ) {
2014-05-08 05:38:41 +08:00
GLchar * fragSource = (GLchar*) String::createWithContentsOfFile(FileUtils::getInstance()->fullPathForFilename("Shaders/example_HorizontalColor.fsh"))->getCString();
auto p = GLProgram::createWithByteArrays(ccPositionTexture_vert, fragSource);
auto director = Director::getInstance();
auto s = director->getWinSize();
_label = Label::createWithBMFont("fonts/west_england-64.fnt","RETRO EFFECT");
_label->setAnchorPoint(Vector2::ANCHOR_MIDDLE);
_label->setGLProgram(p);
_label->setPosition(Vector2(s.width/2,s.height/2));
addChild(_label);
scheduleUpdate();
return true;
}
return false;
}
2012-06-08 13:55:28 +08:00
void ShaderRetroEffect::update(float dt)
{
_accum += dt;
int letterCount = _label->getStringLength();
for (int i = 0; i < letterCount; ++i)
{
auto sprite = _label->getLetter(i);
auto oldPosition = sprite->getPosition();
sprite->setPosition(Vector2( oldPosition.x, sinf( _accum * 2 + i/2.0) * 20 ));
// add fabs() to prevent negative scaling
float scaleY = ( sinf( _accum * 2 + i/2.0 + 0.707) );
sprite->setScaleY(scaleY);
}
}
std::string ShaderRetroEffect::title() const
{
return "Shader: Retro test";
}
std::string ShaderRetroEffect::subtitle() const
{
return "sin() effect with moving colors";
}
2014-05-10 02:48:11 +08:00
UniformShaderNode::UniformShaderNode()
:_center(Vector2(0.0f, 0.0f))
,_resolution(Vector2(0.0f, 0.0f))
,_time(0.0f)
{
}
UniformShaderNode::~UniformShaderNode()
{
}
bool UniformShaderNode::initWithVertex(const char *vert, const char *frag)
{
#if CC_ENABLE_CACHE_TEXTURE_DATA
auto listener = EventListenerCustom::create(EVENT_COME_TO_FOREGROUND, [this](EventCustom* event){
this->setGLProgram(nullptr);
loadShaderVertex(_vertFileName.c_str(), _fragFileName.c_str());
});
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
#endif
loadShaderVertex(vert, frag);
_time = 0;
auto s = Director::getInstance()->getWinSize();
_resolution = Vector2(s.width * CC_CONTENT_SCALE_FACTOR(), s.height * CC_CONTENT_SCALE_FACTOR());
getGLProgramState()->setUniformVec2("resolution", _resolution);
scheduleUpdate();
//setContentSize(Size(getContentSize().width, getContentSize().height));
setAnchorPoint(Vector2(0.5f, 0.5f));
_vertFileName = vert;
_fragFileName = frag;
2014-05-10 05:43:20 +08:00
return true;
2014-05-10 02:48:11 +08:00
}
void UniformShaderNode::loadShaderVertex(const char *vert, const char *frag)
{
auto shader = GLProgram::createWithByteArrays(vert, frag);
this->setGLProgram(shader);
}
void UniformShaderNode::update(float dt)
{
_time += dt;
}
void UniformShaderNode::setPosition(const Vector2 &newPosition)
{
Node::setPosition(newPosition);
auto position = getPosition();
//_center = Vector2(position.x * CC_CONTENT_SCALE_FACTOR(), position.y * CC_CONTENT_SCALE_FACTOR());
// getGLProgramState()->setUniformVec2("center", _center);
}
void UniformShaderNode::draw(Renderer *renderer, const Matrix &transform, bool transformUpdated)
{
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(UniformShaderNode::onDraw, this, transform, transformUpdated);
renderer->addCommand(&_customCommand);
}
UniformShaderNode* UniformShaderNode::shaderNodeWithVertex(const char *vert, const char *frag)
{
auto node = new UniformShaderNode();
node->initWithVertex(vert, frag);
node->autorelease();
return node;
}
void UniformShaderNode::onDraw(const Matrix &transform, bool transformUpdated)
{
float w = getContentSize().width, h = getContentSize().height;
GLfloat vertices[12] = {0,0, w,0, w,h, 0,0, 0,h, w,h};
auto glProgramState = getGLProgramState();
glProgramState->setVertexAttribPointer("a_position", 2, GL_FLOAT, GL_FALSE, 0, vertices);
glProgramState->apply(transform);
glDrawArrays(GL_TRIANGLES, 0, 6);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,6);
}
ShaderRelentless::ShaderRelentless()
{
init();
}
std::string ShaderRelentless::title() const
{
return "ShaderToy Test";
}
std::string ShaderRelentless::subtitle() const
{
return "Relentless";
}
bool ShaderRelentless::init()
{
if (ShaderTestDemo::init())
{
auto sn = UniformShaderNode::shaderNodeWithVertex(shadertestvsh, shadertoyRelentlessFrag);
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
sn->setContentSize(Size(s.width,s.height));
addChild(sn);
return true;
}
return false;
}
ShaderStarNest::ShaderStarNest()
{
init();
}
std::string ShaderStarNest::title() const
{
return "ShaderToy Test";
}
std::string ShaderStarNest::subtitle() const
{
return "Star Nest";
}
bool ShaderStarNest::init()
{
if (ShaderTestDemo::init())
{
auto sn = UniformShaderNode::shaderNodeWithVertex(shadertestvsh, starNestFrg);
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
sn->setContentSize(Size(s.width,s.height));
addChild(sn);
return true;
}
return false;
}
ShaderFalme::ShaderFalme()
{
init();
}
std::string ShaderFalme::title() const
{
return "ShaderToy Test";
}
std::string ShaderFalme::subtitle() const
{
return "Flame";
}
bool ShaderFalme::init()
{
if (ShaderTestDemo::init())
{
auto sn = UniformShaderNode::shaderNodeWithVertex(shadertestvsh, starFlame);
auto s = Director::getInstance()->getWinSize();
sn->setPosition(Vector2(s.width/2, s.height/2));
sn->setContentSize(Size(s.width,s.height));
addChild(sn);
return true;
}
return false;
}
///---------------------------------------
2012-11-20 16:16:16 +08:00
//
// ShaderTestScene
//
///---------------------------------------
void ShaderTestScene::runThisTest()
{
sceneIdx = -1;
addChild(nextAction());
Director::getInstance()->replaceScene(this);
}