How to use fragment shader with cocos2d-x 3.1? - cocos2d-x

The code below is from this tutorial: http://www.raywenderlich.com/10862/how-to-create-cool-effects-with-custom-shaders-in-opengl-es-2-0-and-cocos2d-2-x
It is a very cool tutorial, but I don't know how to do that in cocos2d-x 3. I have translated the code below
- (id)init
{
self = [super init];
if (self) {
// 1
sprite = [CCSprite spriteWithFile:#"Default.png"];
sprite.anchorPoint = CGPointZero;
sprite.rotation = 90;
sprite.position = ccp(0, 320);
[self addChild:sprite];
// 2
const GLchar * fragmentSource = (GLchar*) [[NSString stringWithContentsOfFile:[CCFileUtils fullPathFromRelativePath:#"CSEColorRamp.fsh"] encoding:NSUTF8StringEncoding error:nil] UTF8String];
sprite.shaderProgram = [[CCGLProgram alloc] initWithVertexShaderByteArray:ccPositionTextureA8Color_vert
fragmentShaderByteArray:fragmentSource];
[sprite.shaderProgram addAttribute:kCCAttributeNamePosition index:kCCVertexAttrib_Position];
[sprite.shaderProgram addAttribute:kCCAttributeNameTexCoord index:kCCVertexAttrib_TexCoords];
[sprite.shaderProgram link];
[sprite.shaderProgram updateUniforms];
// 3
colorRampUniformLocation = glGetUniformLocation(sprite.shaderProgram->program_, "u_colorRampTexture");
glUniform1i(colorRampUniformLocation, 1);
// 4
colorRampTexture = [[CCTextureCache sharedTextureCache] addImage:#"colorRamp.png"];
[colorRampTexture setAliasTexParameters];
// 5
[sprite.shaderProgram use];
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, [colorRampTexture name]);
glActiveTexture(GL_TEXTURE0);
}
return self;
}
and obtained this:
Vec2 origin = Director::getInstance()->getVisibleOrigin();
sprite = Sprite::create("HelloWorld.png");
sprite->setAnchorPoint(Vec2(0, 0));
sprite->setRotation(3);
sprite->setPosition(origin);
addChild(sprite);
const GLchar * fragmentSource = FileUtils::getInstance()->getStringFromFile("CSEColorRamp.fsh").c_str();
GLProgram* p = GLProgram::createWithByteArrays(ccPositionTextureA8Color_vert, fragmentSource);
sprite->setGLProgram(p);
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
p->link();
p->updateUniforms();
// 3
colorRampUniformLocation = glGetUniformLocation(sprite->getGLProgram()->getProgram(), "u_colorRampTexture");
glUniform1i(colorRampUniformLocation, 1);
// 4
colorRampTexture = Director::getInstance()->getTextureCache()->addImage("colorRamp.png");
colorRampTexture->setAliasTexParameters();
// 5
sprite->getGLProgram()->use();
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, colorRampTexture->getName());
glActiveTexture(GL_TEXTURE0);
But it does not work. It shows a black screen with 2 draw calls. What is wrong? Did I pass all uniforms and attributes normally to the fragment shader. Did I initialize the program correctly?

Here is an example how shader should be used in cocos2d-x 3.1:
.h file
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
using namespace cocos2d;
class HelloWorld : public cocos2d::Layer
{
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
virtual void visit(Renderer *renderer, const Mat4 &transform, bool transformUpdated) override;
//we call our actual opengl commands here
void onDraw();
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
private:
CustomCommand _customCommand;
GLuint vao;
GLuint vertexVBO;
GLuint colorVBO;
};
#endif // __HELLOWORLD_SCENE_H__
.cpp file
#include "HelloWorldScene.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
//create my own program
auto program = new GLProgram;
program->initWithFilenames("myVertextShader.vert", "myFragmentShader.frag");
program->link();
//set uniform locations
program->updateUniforms();
// this->setGLProgram(GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_COLOR));
this->setGLProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
typedef struct {
float Position[2];
float Color[4];
} Vertex;
// auto size = Director::getInstance()->getVisibleSize();
Vertex data[] =
{
{{-1,-1},{0,1,0,1}},
{{1,-1},{1,0,0,1}},
{ {-1,1},{0,0,1,1}},
{{1,1},{0,1,0,1}}
};
GLubyte indices[] = { 0,1,2, //第一个三角形索引
2,3,1}; //第二个三角形索引
glGenBuffers(1, &vertexVBO);
glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
GLuint positionLocation = glGetAttribLocation(program->getProgram(), "a_position");
// CCLOG("position =%d", positionLocation);
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation,
2,
GL_FLOAT,
GL_FALSE,
sizeof(Vertex),
(GLvoid*)offsetof(Vertex,Position));
//set for color
// glGenBuffers(1, &colorVBO);
// glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
// glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
GLuint colorLocation = glGetAttribLocation(program->getProgram(), "a_color");
glEnableVertexAttribArray(colorLocation);
glVertexAttribPointer(colorLocation,
4,
GL_FLOAT,
GL_FALSE,
sizeof(Vertex),
(GLvoid*)offsetof(Vertex,Color));
GLuint indexVBO;
glGenBuffers(1, &indexVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices) , indices, GL_STATIC_DRAW);
program->autorelease();
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// 使用vao http://blog.sina.com.cn/s/blog_4a657c5a01016f8s.html
return true;
}
void HelloWorld::visit(cocos2d::Renderer *renderer, const Mat4 &transform, bool transformUpdated)
{
Layer::draw(renderer, transform, transformUpdated);
//send custom command to tell the renderer to call opengl commands
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this);
renderer->addCommand(&_customCommand);
}
void HelloWorld::onDraw()
{
//question1: why the triangle goes to the up side
//如果使用对等矩阵,则三角形绘制会在最前面
Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
auto glProgram = getGLProgram();
glProgram->use();
//set uniform values, the order of the line is very important
glProgram->setUniformsForBuiltins();
auto size = Director::getInstance()->getWinSize();
//use vao
glBindVertexArray(vao);
GLuint uColorLocation = glGetUniformLocation(glProgram->getProgram(), "u_color");
float uColor[] = {1.0, 0.0, 0.0, 1.0};
glUniform4fv(uColorLocation,1, uColor);
// glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE,(GLvoid*)0);
glBindVertexArray(0);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 6);
CHECK_GL_ERROR_DEBUG();
Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
myVertextShader.vert vertex shader
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_fragmentColor;
uniform vec4 u_color;
void main()
{
gl_Position = CC_MVPMatrix * a_position;
v_fragmentColor = a_color * u_color;
}
myFragmentShader.frag fragment shader
varying vec4 v_fragmentColor;
void main()
{
gl_FragColor = v_fragmentColor;
}
I have used this source: http://4gamers.cn/blog/categories/opengl-es/

Related

How can I draw something on the sprite not behind sprite

I use cocos2dx v3.8, and successful draw things with override draw like:
void Box2dManager::draw(Renderer *renderer, const Mat4& transform, uint32_t flags){
GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POSITION );
Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
box2dWorld->DrawDebugData();
Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
// super::draw(renderer, transform, flags);
}
but It always behind the sprites. It can't change after modify z-order.
SOLVED
Now I can fix cocos2d v3.x box2d DrawDebugData problem.
And I paste all the cocos2dx solve code.
v2: (simple, because v2 engine opengl draw is each single task)
void Box2dManager::draw(){
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
box2dWorld->DrawDebugData();
kmGLPopMatrix();
}
v3: (v3 engine push the draw commond to core with quence, so you need create a callback )
void Box2dManager::draw(Renderer *renderer, const Mat4& transform, uint32_t flags){
super::draw(renderer, transform, _transformUpdated);
GL::enableVertexAttribs( cocos2d::GL::VERTEX_ATTRIB_FLAG_POSITION );
Director* director = Director::getInstance();
CCASSERT(nullptr != director, "Director is null when seting matrix stack");
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
_modelViewMV = director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(Box2dManager::onDraw, this);
renderer->addCommand(&_customCommand);
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
void Box2dManager::onDraw() {
Director* director = Director::getInstance();
CCASSERT(nullptr != director, "Director is null when seting matrix stack");
Mat4 oldMV;
oldMV = director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewMV);
box2dWorld->DrawDebugData();
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, oldMV);
}
refrence:
http://discuss.cocos2d-x.org/t/box2d-debug-drawing-for-cocos2d-x-3-0/11912/2
http://blog.csdn.net/zszeng/article/details/50000757
Now I can fix cocos2d v3.x box2d DrawDebugData problem.
And I paste all the cocos2dx solve code.
v2: (simple, because v2 engine opengl draw is each single task)
void Box2dManager::draw(){
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
box2dWorld->DrawDebugData();
kmGLPopMatrix();
}
v3: (v3 engine push the draw commond to core with quence, so you need create a callback )
void Box2dManager::draw(Renderer *renderer, const Mat4& transform, uint32_t flags){
super::draw(renderer, transform, _transformUpdated);
GL::enableVertexAttribs( cocos2d::GL::VERTEX_ATTRIB_FLAG_POSITION );
Director* director = Director::getInstance();
CCASSERT(nullptr != director, "Director is null when seting matrix stack");
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
_modelViewMV = director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(Box2dManager::onDraw, this);
renderer->addCommand(&_customCommand);
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
void Box2dManager::onDraw() {
Director* director = Director::getInstance();
CCASSERT(nullptr != director, "Director is null when seting matrix stack");
Mat4 oldMV;
oldMV = director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewMV);
box2dWorld->DrawDebugData();
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, oldMV);
}
refrence:
http://discuss.cocos2d-x.org/t/box2d-debug-drawing-for-cocos2d-x-3-0/11912/2
http://blog.csdn.net/zszeng/article/details/50000757
How about you use a DrawNode and add it as a child? It would be easier to maintain if you were to use a node that you manage on the drawing tree.
auto myDrawing = DrawNode::create();
myDrawing::drawRect(p1, p2, p3, Color4F(255, 255, 0, 255));
myDrawing::setLineWidth(2)
this->addChild(myDrawing);
virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform,uint32_t flags) override;
cocos2d::CustomCommand _customCmd;
void onDraw(const cocos2d::Mat4 &transform, uint32_t flags);
void linedraw:: draw(cocos2d::Renderer* renderer, const cocos2d::Mat4 &transform, uint32_t flags){
//cocos2d::Layer::draw(renderer, transform, flags);
_customCmd.init(1);
_customCmd.func = CC_CALLBACK_0(linedraw::onDraw, this, transform, flags);
renderer->addCommand(&_customCmd);
}
void linedraw:: onDraw(const cocos2d::Mat4 &transform, uint32_t flags)
{
}

Refering within the class to constructor with the this pointer

#include "stdafx.h"
ref class station{
public:
station(){
};
void wrapper_1()
{
this->somefunct(); /*happy*/
};
void wrapper_2()
{
this->station(); /*not happy*/
};
void somefunct(){
System::Console::WriteLine(L"abcde");
};
};
int main(array<System::String^>^ args)
{
station^ temp_1 = gcnew station();
temp_1->wrapper_1();
System::Console::ReadLine();
};
I want to use the this pointer to call my constructor within my station class, it doesn't like this and throws the following error:
error C2273: 'function-style cast' : illegal as right side of '->'
operator.
Can someone explain to me how the constructor differs to other functions when using the pointer this to point to the function. I don't want to take the easy way out using station::station();
example of what I meant to #hans-passant
#include "stdafx.h"
ref class station{
public:
station(int par_1,int par_2)
{
int sum = par_1 + par_2;
System::Console::WriteLine(System::Convert::ToString(sum));
//default value output 13
};
station(){
int pass_1 = 5;
int pass_2 = 8;
station(pass_1,pass_2); /* But why couldn't I use this->station(pass_1,pass_2);*/
};
};
int main(array<System::String^>^ args)
{
station^ obj = gcnew station();
System::Console::ReadLine();
};

How to set shader for Armature object in Cocos2dx

I have 3 questions:
I know when I want to set shader for Sprite object by using spr1->setShaderProgram(glProgram). However, I want to set shader for an Armature object. How can I do that?
In CCSprite, I can use setBlendFunc, what about in Armature.
I read this article http://blog.muditjaju.infiniteeurekas.in/?p=1 and I see the idea to detect collision between 2 sprites. But I want to write a extended function which can detect collision between different object like sprite vs sprite, sprite vs Armature, Amature vs Armature. How can I do that?
Thanks
Today I met the same situation like you. And luckily I found a solution from someone else. The main point is to write a subclass of Armature, say ShaderArmature, and rendering every bone's every child with a shader ---- in my case, the shader is for graying the armature.
You can create a ShaderArmature object and call its setgrayState() to enable graying and setUsuaState() to remove graying effect.
1, Add the ShaderArmature.h & ShaderArmature.cpp in the same directory of Armature.h.
ShaderArmature.h
//
// Created by Wangyq on 2017/8/13.
//
//
#ifndef __SHADERARMATURE_H__
#define __SHADERARMATURE_H__
//
//---------shaderArmature.h
///
#include "cocos2d.h"
//#include "extensions/cocos-ext.h"
#include "cocostudio/CocoStudio.h"
//USING_NS_CC_EXT;
USING_NS_CC;
namespace cocostudio{
class CC_STUDIO_DLL ShaderArmature : public Armature
{
public:
ShaderArmature();
virtual ~ShaderArmature();
bool init(const std::string& name) override;
static ShaderArmature *create(const std::string& name) ;
virtual void initShader(bool shaderState);
// void setBackgroundNotification();
// draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t flags)
virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t transformUpdated) override;
// void listenBackToForeground(Ref *obj);
void setIceState();
void setUsuaState();
void setblurState();
void setbanishState();
void setfrozenState();
void setgrayState();
void setinvisState();
void setmirrorState();
void setpoisonState();
void setstoneState();
protected:
std::string _fragSourceFile;
std::string _vertSourceFile;
//GLchar * fragSource;
//GLchar * vertSource;
GLchar fragSource[2048];
GLchar vertSource[2048];
bool bSetShader;
};
}
#endif /* __SHADERARMATURE_H__ */
ShaderArmature.cpp
//
// ShaderArmature.cpp
// cocos2d_libs
//
// Created by Wangyq on 2017/8/13.
//
//
#include "ShaderArmature.h"
using namespace cocos2d;
namespace cocostudio {
ShaderArmature::ShaderArmature(){
}
ShaderArmature::~ShaderArmature(){
}
bool ShaderArmature::init(const std::string& name)
{
return Armature::init(name);
}
ShaderArmature *ShaderArmature::create(const std::string& name)
{
ShaderArmature *armature = new ShaderArmature;
if (armature && armature->init(name))
{
armature->autorelease();
return armature;
}
else{
CC_SAFE_DELETE(armature);
return nullptr;
}
}
void ShaderArmature::initShader(bool shaderState){
//Traverse every bone to set shader
for (auto& object : _boneDic)
{
if (Bone *bone = dynamic_cast<Bone *>(object.second))
{
if (bone == nullptr)
continue;
//-----------------!! IMPORTANT !!-----------------
//Each bone may have more than one child, like several frames, also need to assign shader to them
//Without this step, only the first frame will have the shader effect.
const Vector<DecorativeDisplay*> list = bone->getDisplayManager()->getDecorativeDisplayList();
for (auto& display : list)
{
Node* node = display->getDisplay();
if (node == nullptr)
continue;
if (shaderState){
auto program = new GLProgram();
program->initWithByteArrays(vertSource, fragSource);
node->setGLProgram(program);
program->autorelease();
CHECK_GL_ERROR_DEBUG();
program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);
CHECK_GL_ERROR_DEBUG();
program->link();
CHECK_GL_ERROR_DEBUG();
program->updateUniforms();
CHECK_GL_ERROR_DEBUG();
}
else{//addNormal shader
node->setGLProgram(ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));
}
}
}
}
}
void ShaderArmature::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
Armature::draw(renderer, transform, flags);
}
void ShaderArmature::setIceState(){
_fragSourceFile = "shader/IceShader.fsh";
_vertSourceFile = "shader/IceShader.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setUsuaState(){
initShader(false);
}
void ShaderArmature::setblurState(){
_fragSourceFile = "shader/Blur.fsh";
_vertSourceFile = "shader/Blur.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setbanishState(){
_fragSourceFile = "shader/BanishShader.fsh";
_vertSourceFile = "shader/BanishShader.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setfrozenState(){
_fragSourceFile = "shader/FrozenShader.fsh";
_vertSourceFile = "shader/FrozenShader.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setgrayState(){
_fragSourceFile = "shader/GrayScalingShader.fsh";
_vertSourceFile = "shader/GrayScalingShader.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setinvisState(){
_fragSourceFile = "shader/InvisibleShader.fsh";
_vertSourceFile = "shader/InvisibleShader.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setmirrorState(){
_fragSourceFile = "shader/MirrorShader.fsh";
_vertSourceFile = "shader/MirrorShader.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setpoisonState(){
_fragSourceFile = "shader/PoisonShader.fsh";
_vertSourceFile = "shader/PoisonShader.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
void ShaderArmature::setstoneState(){
_fragSourceFile = "shader/StoneShader.fsh";
_vertSourceFile = "shader/StoneShader.vsh";
fragSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_fragSourceFile).c_str())->getCString();
vertSource = (GLchar*)String::createWithContentsOfFile(
FileUtils::getInstance()->fullPathForFilename(_vertSourceFile).c_str())->getCString();
initShader(true);
}
}
2, For shader files, I put them in the folder "res/shader". Every shader consists of 2 files -- a .vsh file & a .fsh file. Take graying for example:
GrayScalingShader.fsh
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform sampler2D u_texture;
void main()
{
vec4 normalColor = v_fragmentColor * texture2D(u_texture, v_texCoord);
//float gray = 0.299*0.5*normalColor.r + 0.587*0.5*normalColor.g + 0.114*0.5*normalColor.b;
//gl_FragColor = vec4(gray*0.8 + normalColor.r*0.2, gray*0.8 + normalColor.g*0.2, gray*0.8 + normalColor.b*0.2, normalColor.a*0.3);
float gray = dot(normalColor.rgb, vec3(0.299 * 0.5, 0.587 * 0.5, 0.114 * 0.5));
gl_FragColor = vec4(gray, gray, gray, normalColor.a * 1);
}
GrayScalingShader.vsh
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
#else
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
#endif
void main()
{
//gl_Position = CC_MVPMatrix * a_position;
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
Hope this would be helpful.

How to insert text in CCTextFieldTTF?

I used setString but the string is not updated, so I have to write a CCLabel to show the string, which I feel very weird because showing the user input should be part of the textfield.. Do I missed anything?
I read the test_input example, it uses a CCLabel to show the user input, which I think is a really bad design.
You don't need a Label to show user input.
I have edited the default HelloWorld file with added CCTextFieldttf working example.
This is how your HelloWorld.h file should look
class HelloWorld : public cocos2d::CCLayer, public cocos2d::CCTextFieldDelegate
{
public:
virtual bool init();
static cocos2d::CCScene* scene();
void createTF();
cocos2d::CCTextFieldTTF* tf;
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
virtual void registerWithTouchDispatcher();
//CCtextFieldttf delegate begin
virtual bool onTextFieldAttachWithIME(CCTextFieldTTF * pSender);
virtual bool onTextFieldDetachWithIME(CCTextFieldTTF * pSender);
virtual bool onTextFieldInsertText(CCTextFieldTTF * pSender, const char * text, int nLen);
virtual bool onTextFieldDeleteBackward(CCTextFieldTTF * pSender, const char * delText, int nLen);
virtual bool onDraw(CCTextFieldTTF * pSender);
//CCtextFieldttf delegate end
CREATE_FUNC(HelloWorld);
};
This is how your HelloWorld.cpp should be for minimum usage of CCTextFieldttf
CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
if ( !CCLayer::init() )
{
return false;
}
this->setTouchEnabled(true);
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
createTF();
CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
// position the label on the center of the screen
pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - pLabel->getContentSize().height));
this->addChild(pLabel, 1);
return true;
}
void HelloWorld::createTF()
{
tf = CCTextFieldTTF::textFieldWithPlaceHolder("123", CCSizeMake(100, 100), kCCTextAlignmentCenter, "helvetica", 20);
tf->setColorSpaceHolder(ccWHITE);
tf->setPosition(ccp(200,200));
tf->setHorizontalAlignment(kCCTextAlignmentCenter);
tf->setVerticalAlignment(kCCVerticalTextAlignmentCenter);
tf->setDelegate(this);
addChild(tf);
}
void HelloWorld::registerWithTouchDispatcher()
{
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, false);
}
bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
CCLog("inside touchbegan");
return true;
}
void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
CCLog("inside touchend");
tf->attachWithIME();
}
bool HelloWorld::onTextFieldAttachWithIME(CCTextFieldTTF * pSender)
{
return false;
}
bool HelloWorld::onTextFieldDetachWithIME(CCTextFieldTTF * pSender)
{
return false;
}
bool HelloWorld::onTextFieldInsertText(CCTextFieldTTF * pSender, const char * text, int nLen)
{
return false;
}
bool HelloWorld::onTextFieldDeleteBackward(CCTextFieldTTF * pSender, const char * delText, int nLen)
{
return false;
}
bool HelloWorld::onDraw(CCTextFieldTTF * pSender)
{
return false;
}
The CCTextFieldDelegate methods are implemented to gain more control over what is entered into CCTextFieldTTF. The only thing that CCTextFieldttf lacks is you have to call CCTextFieldTTF's attachWithIME() method yourself like in the above code it is being called in "ccTouchEnded".
in header
class CustomMultiplayerScene : public PZGBaseMenuScene,public CCIMEDelegate
{
public:
void keyboardWillShow(cocos2d::CCIMEKeyboardNotificationInfo &info);
void keyboardWillHide(cocos2d::CCIMEKeyboardNotificationInfo &info);
void ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
};
in .cpp
CCTextFieldTTF *textfield = CCTextFieldTTF::textFieldWithPlaceHolder("Enter Name:", CCSize(480,30), kCCTextAlignmentCenter, "Arial", 12);
// textfield->setAnchorPoint(CCPointZero);
textfield->setPosition(ccp(screenSize.width/2,200));
textfield->setTag(100);
this->addChild(textfield,4);
CCLabelTTF *label = CCLabelTTF::create("ID : ", "", 12);
label->setPosition(ccp(screenSize.width/2,100));
label->setTag(200);
this->addChild(label,4);
implement methods in .cpp
void CustomMultiplayerScene::keyboardWillShow(CCIMEKeyboardNotificationInfo &info)
{
CCLOG("keyboardWillShow");
CCTextFieldTTF *textfield = (CCTextFieldTTF *)this->getChildByTag(100);
textfield->setString("");
}
void CustomMultiplayerScene::keyboardWillHide(CCIMEKeyboardNotificationInfo &info)
{
CCLog("keyboardWillHide");
CCTextFieldTTF *textfield = (CCTextFieldTTF *)this->getChildByTag(100);
CCLabelTTF *label = (CCLabelTTF *)this->getChildByTag(200);
label->setString(textfield->getString());
}
void CustomMultiplayerScene::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
CCTouch *pTouch = (CCTouch *)pTouches->anyObject();
CCPoint point = pTouch->getLocationInView();
point = CCDirector::sharedDirector()->convertToGL(point);
CCTextFieldTTF *textfield = (CCTextFieldTTF *)this->getChildByTag(100);
CCRect rect = textfield->boundingBox();
if(rect.containsPoint(point)) {
textfield->attachWithIME();
}
}
CCTextFieldTTF * pTextField = CCTextFieldTTF::textFieldWithPlaceHolder("click here for input",
"Thonburi",
20);
addChild(pTextField);

JCuda. Reusing already used pointer

I have a trouble working with JCUDA. I have a task to make 1D FFT using CUFFT library, but the result should be multiply on 2. So I decided to make 1D FFT with type CUFFT_R2C. Class responsible for this going next:
public class FFTTransformer {
private Pointer inputDataPointer;
private Pointer outputDataPointer;
private int fftType;
private float[] inputData;
private float[] outputData;
private int batchSize = 1;
public FFTTransformer (int type, float[] inputData) {
this.fftType = type;
this.inputData = inputData;
inputDataPointer = new CUdeviceptr();
JCuda.cudaMalloc(inputDataPointer, inputData.length * Sizeof.FLOAT);
JCuda.cudaMemcpy(inputDataPointer, Pointer.to(inputData),
inputData.length * Sizeof.FLOAT, cudaMemcpyKind.cudaMemcpyHostToDevice);
outputDataPointer = new CUdeviceptr();
JCuda.cudaMalloc(outputDataPointer, (inputData.length + 2) * Sizeof.FLOAT);
}
public Pointer getInputDataPointer() {
return inputDataPointer;
}
public Pointer getOutputDataPointer() {
return outputDataPointer;
}
public int getFftType() {
return fftType;
}
public void setFftType(int fftType) {
this.fftType = fftType;
}
public float[] getInputData() {
return inputData;
}
public int getBatchSize() {
return batchSize;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
public float[] getOutputData() {
return outputData;
}
private void R2CTransform() {
cufftHandle plan = new cufftHandle();
JCufft.cufftPlan1d(plan, inputData.length, cufftType.CUFFT_R2C, batchSize);
JCufft.cufftExecR2C(plan, inputDataPointer, outputDataPointer);
JCufft.cufftDestroy(plan);
}
private void C2CTransform(){
cufftHandle plan = new cufftHandle();
JCufft.cufftPlan1d(plan, inputData.length, cufftType.CUFFT_C2C, batchSize);
JCufft.cufftExecC2C(plan, inputDataPointer, outputDataPointer, fftType);
JCufft.cufftDestroy(plan);
}
public void transform(){
if (fftType == JCufft.CUFFT_FORWARD) {
R2CTransform();
} else {
C2CTransform();
}
}
public float[] getFFTResult() {
outputData = new float[inputData.length + 2];
JCuda.cudaMemcpy(Pointer.to(outputData), outputDataPointer,
outputData.length * Sizeof.FLOAT, cudaMemcpyKind.cudaMemcpyDeviceToHost);
return outputData;
}
public void releaseGPUResources(){
JCuda.cudaFree(inputDataPointer);
JCuda.cudaFree(outputDataPointer);
}
public static void main(String... args) {
float[] inputData = new float[65536];
for(int i = 0; i < inputData.length; i++) {
inputData[i] = (float) Math.sin(i);
}
FFTTransformer transformer = new FFTTransformer(JCufft.CUFFT_FORWARD, inputData);
transformer.transform();
float[] result = transformer.getFFTResult();
HilbertSpectrumTicksKernelInvoker.multiplyOn2(transformer.getOutputDataPointer(), inputData.length+2);
transformer.releaseGPUResources();
}
}
Method which responsible for multiplying uses cuda kernel function.
Java method code:
public static void multiplyOn2(Pointer inputDataPointer, int dataSize){
// Enable exceptions and omit all subsequent error checks
JCudaDriver.setExceptionsEnabled(true);
// Create the PTX file by calling the NVCC
String ptxFileName = null;
try {
ptxFileName = FileService.preparePtxFile("resources\\HilbertSpectrumTicksKernel.cu");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Initialize the driver and create a context for the first device.
cuInit(0);
CUdevice device = new CUdevice();
cuDeviceGet(device, 0);
CUcontext context = new CUcontext();
cuCtxCreate(context, 0, device);
// Load the ptx file.
CUmodule module = new CUmodule();
cuModuleLoad(module, ptxFileName);
// Obtain a function pointer to the "add" function.
CUfunction function = new CUfunction();
cuModuleGetFunction(function, module, "calcSpectrumSamples");
// Set up the kernel parameters: A pointer to an array
// of pointers which point to the actual values.
int N = (dataSize + 1) / 2 + 1;
int pair = (dataSize + 1) % 2 > 0 ? 1 : -1;
Pointer kernelParameters = Pointer.to(Pointer.to(inputDataPointer),
Pointer.to(new int[] { dataSize }),
Pointer.to(new int[] { N }), Pointer.to(new int[] { pair }));
// Call the kernel function.
int blockSizeX = 128;
int gridSizeX = (int) Math.ceil((double) dataSize / blockSizeX);
cuLaunchKernel(function, gridSizeX, 1, 1, // Grid dimension
blockSizeX, 1, 1, // Block dimension
0, null, // Shared memory size and stream
kernelParameters, null // Kernel- and extra parameters
);
cuCtxSynchronize();
// Allocate host output memory and copy the device output
// to the host.
float freq[] = new float[dataSize];
cuMemcpyDtoH(Pointer.to(freq), (CUdeviceptr)inputDataPointer, dataSize
* Sizeof.FLOAT);
And the kernel function is next:
extern "C"
__global__ void calcSpectrumSamples(float* complexData, int dataSize, int N, int pair) {
int i = threadIdx.x + blockIdx.x * blockDim.x;
if(i >= dataSize) return;
complexData[i] = complexData[i] * 2;
}
But when I'm trying to pass the pointer which points to the result of FFT (in device memory) to the multiplyOn2 method, it throws the exception on cuCtxSynchronize() call. Exception:
Exception in thread "main" jcuda.CudaException: CUDA_ERROR_UNKNOWN
at jcuda.driver.JCudaDriver.checkResult(JCudaDriver.java:263)
at jcuda.driver.JCudaDriver.cuCtxSynchronize(JCudaDriver.java:1709)
at com.ifntung.cufft.HilbertSpectrumTicksKernelInvoker.multiplyOn2(HilbertSpectrumTicksKernelInvoker.java:73)
at com.ifntung.cufft.FFTTransformer.main(FFTTransformer.java:123)
I was trying to do the same using Visual Studion C++ and there no problems with this. Could you please help me.
P.S.
I can solve this prolem, but I need to copy data from device memory to host memory and then copy back with creating new pointers every time before calling new cuda functions, which slows my program executing.
Where exactly does the error occurs at which line?
The Cuda error can also be a previous error.
Why do you use Pointer.to(inputDataPointer), you already have that device pointer. Now you pass a pointer to the device pointer to the device?
Pointer kernelParameters = Pointer.to(Pointer.to(inputDataPointer),
I also recommend to use "this" qualifier or any other marking to detect instance variables. I hate and refuse to look through code, especially as nested and long as your example if I cannot see which scope the variable in methods have trying to debug it by just reading it.
I don't wanna ask myself always where the hell comes this variable from.
If a complex code in a question at SO is not formatted properly I don't read it.