Merge branch 'upto-0.99.5' of https://github.com/yangws/cocos2d-x into yangws-upto-0.99.5

This commit is contained in:
minggo 2010-12-27 10:55:59 +08:00
commit 4e35a660dc
12 changed files with 1443 additions and 1197 deletions

View File

@ -23,50 +23,54 @@ THE SOFTWARE.
****************************************************************************/
#ifndef __CCMOTION_STREAK_H__
#define __CCMOTION_STREAK_H__
#include "CCNode.h"
#include "CCProtocols.h"
namespace cocos2d {
class CCRibbon;
/**
* @brief CCMotionStreak manages a Ribbon based on it's motion in absolute space.
* You construct it with a fadeTime, minimum segment size, texture path, texture
* length and color. The fadeTime controls how long it takes each vertex in
* the streak to fade out, the minimum segment size it how many pixels the
* streak will move before adding a new ribbon segement, and the texture
* length is the how many pixels the texture is stretched across. The texture
* is vertically aligned along the streak segemnts.
*
* Limitations:
* CCMotionStreak, by default, will use the GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA blending function.
* This blending function might not be the correct one for certain textures.
* But you can change it by using:
* [obj setBlendFunc: (ccBlendfunc) {new_src_blend_func, new_dst_blend_func}];
*
* @since v0.8.1
*/
class CCX_DLL CCMotionStreak : public CCNode, public CCTextureProtocol
{
/** Ribbon used by MotionStreak (weak reference) */
CCX_PROPERTY_READONLY(CCRibbon*, m_pRibbon, Ribbon)
//CCTextureProtocol methods
CCX_PROPERTY(CCTexture2D*, m_pTexture, Texture)
CCX_PROPERTY(ccBlendFunc, m_tBlendFunc, BlendFunc)
public:
CCMotionStreak(){}
virtual ~CCMotionStreak(){}
/** creates the a MotionStreak. The image will be loaded using the TextureMgr. */
static CCMotionStreak * streakWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color);
class CCRibbon;
/**
* @brief CCMotionStreak manages a Ribbon based on it's motion in absolute space.
* You construct it with a fadeTime, minimum segment size, texture path, texture
* length and color. The fadeTime controls how long it takes each vertex in
* the streak to fade out, the minimum segment size it how many pixels the
* streak will move before adding a new ribbon segement, and the texture
* length is the how many pixels the texture is stretched across. The texture
* is vertically aligned along the streak segemnts.
*
* Limitations:
* CCMotionStreak, by default, will use the GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA blending function.
* This blending function might not be the correct one for certain textures.
* But you can change it by using:
* [obj setBlendFunc: (ccBlendfunc) {new_src_blend_func, new_dst_blend_func}];
*
* @since v0.8.1
*/
class CCX_DLL CCMotionStreak : public CCNode, public CCTextureProtocol
{
/** Ribbon used by MotionStreak (weak reference) */
CCX_PROPERTY_READONLY(CCRibbon*, m_pRibbon, Ribbon)
//CCTextureProtocol methods
CCX_PROPERTY(CCTexture2D*, m_pTexture, Texture)
CCX_PROPERTY(ccBlendFunc, m_tBlendFunc, BlendFunc)
public:
CCMotionStreak(){}
virtual ~CCMotionStreak(){}
/** creates the a MotionStreak. The image will be loaded using the TextureMgr. */
static CCMotionStreak * streakWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color);
/** initializes a MotionStreak. The file will be loaded using the TextureMgr. */
bool initWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color);
/** initializes a MotionStreak. The file will be loaded using the TextureMgr. */
bool initWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color);
/** polling function */
void update(ccTime delta);
protected:
float m_fSegThreshold;
float m_fWidth;
CGPoint m_tLastLocation;
};
/** polling function */
void update(ccTime delta);
protected:
float m_fSegThreshold;
float m_fWidth;
CGPoint m_tLastLocation;
};
} // namespace cocos2d
#endif //__CCMOTION_STREAK_H__
#endif //__CCMOTION_STREAK_H__

View File

@ -80,7 +80,7 @@ public:
static CCProgressTimer* progressWithTexture(CCTexture2D *pTexture);
protected:
CGPoint vertexFromTexCoord(CGPoint texCoord);
ccVertex2F vertexFromTexCoord(CGPoint texCoord);
void updateProgress(void);
void updateBar(void);
void updateRadial(void);

View File

@ -24,50 +24,81 @@ THE SOFTWARE.
#ifndef __CCRENDER_TEXTURE_H__
#define __CCRENDER_TEXTURE_H__
#include "NSData.h"
#include "CCNode.h"
#include "CCSprite.h"
namespace cocos2d {
enum tImageFormat
{
kImageFormatJPG = 0,
kImageFormatPNG = 1
};
/**
@brief RenderTexture is a generic rendering target. To render things into it,
simply construct a render target, call begin on it, call visit on any cocos
scenes or objects to render them, and call end. For convienience, render texture
adds a sprite as it's display child with the results, so you can simply add
the render texture to your scene and treat it like any other CocosNode.
There are also functions for saving the render texture to disk in PNG or JPG format.
enum eImageFormat
{
kCCImageFormatJPG = 0,
kCCImageFormatPNG = 1,
kCCImageFormatRawData = 2
};
/**
@brief CCRenderTexture is a generic rendering target. To render things into it,
simply construct a render target, call begin on it, call visit on any cocos
scenes or objects to render them, and call end. For convienience, render texture
adds a sprite as it's display child with the results, so you can simply add
the render texture to your scene and treat it like any other CocosNode.
There are also functions for saving the render texture to disk in PNG or JPG format.
@since v0.8.1
*/
class CCX_DLL CCRenderTexture : public CCNode
{
/** sprite being used */
CCX_PROPERTY(CCSprite*, m_pSprite, Sprite)
public:
CCRenderTexture(){}
virtual ~CCRenderTexture();
/** creates a RenderTexture object with width and height */
static CCRenderTexture *renderTextureWithWidthAndHeight(int width, int height);
/** initializes a RenderTexture object with width and height */
bool initWithWidthAndHeight(int width, int height);
void begin();
void end();
/** get buffer as UIImage */
UIImage *getUIImageFromBuffer();
/** saves the texture into a file */
bool saveBuffer(const char *name);
/** saves the texture into a file. The format can be JPG or PNG */
bool saveBuffer(const char *name, int format);
/** clears the texture with a color */
void clear(float r, float g, float b, float a);
protected:
GLuint m_uFBO;
GLint m_nOldFBO;
CCTexture2D* m_pTexture;
};
@since v0.8.1
*/
class CCX_DLL CCRenderTexture : public CCNode
{
/** The CCSprite being used.
The sprite, by default, will use the following blending function: GL_ONE, GL_ONE_MINUS_SRC_ALPHA.
The blending function can be changed in runtime by calling:
- [[renderTexture sprite] setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE_MINUS_SRC_ALPHA}];
*/
CCX_PROPERTY(CCSprite*, m_pSprite, Sprite)
public:
CCRenderTexture(){}
virtual ~CCRenderTexture();
/** creates a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid */
static CCRenderTexture * renderTextureWithWidthAndHeight(int w, int h, CCTexture2DPixelFormat eFormat);
/** creates a RenderTexture object with width and height in Points, pixel format is RGBA8888 */
static CCRenderTexture * renderTextureWithWidthAndHeight(int w, int h);
/** initializes a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid */
bool initWithWidthAndHeight(int w, int h, CCTexture2DPixelFormat eFormat);
/** starts grabbing */
void begin();
/** starts rendering to the texture while clearing the texture first.
This is more efficient then calling -clear first and then -begin */
void beginWithClear(float r, float g, float b, float a);
/** ends grabbing */
void end();
/** clears the texture with a color */
void clear(float r, float g, float b, float a);
/** saves the texture into a file */
bool saveBuffer(const char *name);
/** saves the texture into a file. The format can be JPG or PNG */
bool saveBuffer(const char *name, int format);
/* get buffer as UIImage, can only save a render buffer which has a RGBA8888 pixel format */
NSData *getUIImageAsDataFromBuffer(int format);
protected:
GLuint m_uFBO;
GLint m_nOldFBO;
CCTexture2D* m_pTexture;
GLenum m_ePixelFormat;
GLfloat m_aClearColor[4];
private:
void saveGLstate();
void restoreGLstate();
};
} // namespace cocos2d
#endif //__CCRENDER_TEXTURE_H__

View File

@ -23,89 +23,96 @@ THE SOFTWARE.
****************************************************************************/
#ifndef __CCRIBBON_H__
#define __CCRIBBON_H__
/*#include <GLES/egl.h>*/
#include "CCNode.h"
#include "CCProtocols.h"
namespace cocos2d {
class CCRibbonSegment;
/**
* @brief A CCRibbon is a dynamically generated list of polygons drawn as a single or series
* of triangle strips. The primary use of CCRibbon is as the drawing class of Motion Streak,
* but it is quite useful on it's own. When manually drawing a ribbon, you can call addPointAt
* and pass in the parameters for the next location in the ribbon. The system will automatically
* generate new polygons, texture them accourding to your texture width, etc, etc.
*
* CCRibbon data is stored in a CCRibbonSegment class. This class statically allocates enough verticies and
* texture coordinates for 50 locations (100 verts or 48 triangles). The ribbon class will allocate
* new segments when they are needed, and reuse old ones if available. The idea is to avoid constantly
* allocating new memory and prefer a more static method. However, since there is no way to determine
* the maximum size of some ribbons (motion streaks), a truely static allocation is not possible.
*
* @since v0.8.1
*/
class CCX_DLL CCRibbon : public CCNode, public CCTextureProtocol
{
/** Texture used by the ribbon. Conforms to CCTextureProtocol protocol */
CCX_PROPERTY(CCTexture2D*, m_pTexture, Texture)
/** Texture lenghts in pixels */
CCX_PROPERTY(float, m_fTextureLength, TextureLength)
/** GL blendind function */
CCX_PROPERTY(ccBlendFunc, m_tBlendFunc, BlendFunc)
/** color used by the Ribbon (RGBA) */
CCX_PROPERTY(ccColor4B, m_tColor, Color)
public:
CCRibbon(){}
virtual ~CCRibbon();
/** creates the ribbon */
static CCRibbon * ribbonWithWidth(float w, const char *path, float length, ccColor4B color, float fade);
/** init the ribbon */
bool initWithWidth(float w, const char *path, float length, ccColor4B color, float fade);
/** add a point to the ribbon */
void addPointAt(CGPoint location, float width);
/** polling function */
void update(ccTime delta);
/** determine side of line */
float sideOfLine(CGPoint p, CGPoint l1, CGPoint l2);
// super method
virtual void draw();
private:
/** rotates a point around 0, 0 */
CGPoint rotatePoint(CGPoint vec, float rotation);
protected:
NSMutableArray<CCRibbonSegment*> *m_pSegments;
NSMutableArray<CCRibbonSegment*> *m_pDeletedSegments;
class CCRibbonSegment;
/**
* @brief A CCRibbon is a dynamically generated list of polygons drawn as a single or series
* of triangle strips. The primary use of CCRibbon is as the drawing class of Motion Streak,
* but it is quite useful on it's own. When manually drawing a ribbon, you can call addPointAt
* and pass in the parameters for the next location in the ribbon. The system will automatically
* generate new polygons, texture them accourding to your texture width, etc, etc.
*
* CCRibbon data is stored in a CCRibbonSegment class. This class statically allocates enough verticies and
* texture coordinates for 50 locations (100 verts or 48 triangles). The ribbon class will allocate
* new segments when they are needed, and reuse old ones if available. The idea is to avoid constantly
* allocating new memory and prefer a more static method. However, since there is no way to determine
* the maximum size of some ribbons (motion streaks), a truely static allocation is not possible.
*
* @since v0.8.1
*/
class CCX_DLL CCRibbon : public CCNode, public CCTextureProtocol
{
/** Texture used by the ribbon. Conforms to CCTextureProtocol protocol */
CCX_PROPERTY(CCTexture2D*, m_pTexture, Texture)
/** Texture lengths in pixels */
CCX_PROPERTY(float, m_fTextureLength, TextureLength)
/** GL blendind function */
CCX_PROPERTY(ccBlendFunc, m_tBlendFunc, BlendFunc)
/** color used by the Ribbon (RGBA) */
CCX_PROPERTY(ccColor4B, m_tColor, Color)
public:
CCRibbon() : m_pTexture(0), m_pSegments(0), m_pDeletedSegments(0){}
virtual ~CCRibbon();
/** creates the ribbon */
static CCRibbon * ribbonWithWidth(float w, const char *path, float length, ccColor4B color, float fade);
/** init the ribbon */
bool initWithWidth(float w, const char *path, float length, ccColor4B color, float fade);
/** add a point to the ribbon */
void addPointAt(CGPoint location, float width);
/** polling function */
void update(ccTime delta);
/** determine side of line */
float sideOfLine(CGPoint p, CGPoint l1, CGPoint l2);
// super method
virtual void draw();
private:
/** rotates a point around 0, 0 */
CGPoint rotatePoint(CGPoint vec, float rotation);
protected:
NSMutableArray<CCRibbonSegment*> *m_pSegments;
NSMutableArray<CCRibbonSegment*> *m_pDeletedSegments;
CGPoint m_tLastPoint1;
CGPoint m_tLastPoint2;
CGPoint m_tLastLocation;
int m_nVertCount_;
float m_fTexVPos;
float m_fCurTime;
float m_fFadeTime;
float m_fDelta;
float m_fLastWidth;
float m_fLastSign;
bool m_bPastFirstPoint;
};
CGPoint m_tLastPoint1;
CGPoint m_tLastPoint2;
CGPoint m_tLastLocation;
// int m_nVertCount_;
float m_fTexVPos;
float m_fCurTime;
float m_fFadeTime;
float m_fDelta;
float m_fLastWidth;
float m_fLastSign;
bool m_bPastFirstPoint;
};
/** @brief object to hold ribbon segment data */
class CCX_DLL CCRibbonSegment : public NSObject
{
public:
GLfloat m_pVerts[50*6];
GLfloat m_pCoords[50*4];
GLubyte m_pColors[50*8];
float m_pCreationTime[50];
bool m_bFinished;
unsigned int m_uEnd;
unsigned int m_uBegin;
public:
CCRibbonSegment(){}
virtual ~CCRibbonSegment();
char * description();
bool init();
void reset();
void draw(float curTime, float fadeTime, ccColor4B color);
};
/** @brief object to hold ribbon segment data */
class CCX_DLL CCRibbonSegment : public NSObject
{
public:
GLfloat m_pVerts[50*6];
GLfloat m_pCoords[50*4];
GLubyte m_pColors[50*8];
float m_pCreationTime[50];
bool m_bFinished;
unsigned int m_uEnd;
unsigned int m_uBegin;
public:
CCRibbonSegment(){}
virtual ~CCRibbonSegment();
char * description();
bool init();
void reset();
void draw(float curTime, float fadeTime, ccColor4B color);
};
} // namespace cocos2d
#endif //__CCRIBBON_H__

View File

@ -25,74 +25,81 @@ THE SOFTWARE.
#include "CGPointExtension.h"
#include "CCRibbon.h"
namespace cocos2d {
/*
* Motion Streak manages a Ribbon based on it's motion in absolute space.
* You construct it with a fadeTime, minimum segment size, texture path, texture
* length and color. The fadeTime controls how long it takes each vertex in
* the streak to fade out, the minimum segment size it how many pixels the
* streak will move before adding a new ribbon segement, and the texture
* length is the how many pixels the texture is stretched across. The texture
* is vertically aligned along the streak segemnts.
*/
//implementation CCMotionStreak
CCMotionStreak * CCMotionStreak::streakWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color)
{
CCMotionStreak *pRet = new CCMotionStreak();
if(pRet && pRet->initWithFade(fade, seg, imagePath, width, length, color))
{
pRet->autorelease();
return pRet;
}
CCX_SAFE_DELETE(pRet)
return NULL;
}
bool CCMotionStreak::initWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color)
{
m_fSegThreshold = seg;
m_fWidth = width;
m_tLastLocation = CGPointZero;
m_pRibbon = CCRibbon::ribbonWithWidth(m_fWidth, imagePath, length, color, fade);
this->addChild(m_pRibbon);
// update ribbon position
this->schedule(schedule_selector(CCMotionStreak::update), 0);
return true;
}
void CCMotionStreak::update(ccTime delta)
{
CGPoint location = this->convertToWorldSpace(CGPointZero);
m_pRibbon->setPosition(ccp(-1*location.x, -1*location.y));
float len = sqrtf(powf(m_tLastLocation.x - location.x, 2) + powf(m_tLastLocation.y - location.y, 2));
if (len > m_fSegThreshold)
{
m_pRibbon->addPointAt(location, m_fWidth);
m_tLastLocation = location;
}
m_pRibbon->update(delta);
}
//MotionStreak - CocosNodeTexture protocol
void CCMotionStreak::setTexture(CCTexture2D* texture)
{
m_pRibbon->setTexture(texture);
}
CCTexture2D * CCMotionStreak::getTexture()
{
return m_pRibbon->getTexture();
}
ccBlendFunc CCMotionStreak::getBlendFunc()
{
return m_pRibbon->getBlendFunc();
}
void CCMotionStreak::setBlendFunc(ccBlendFunc blendFunc)
{
m_pRibbon->setBlendFunc(blendFunc);
}
CCRibbon * CCMotionStreak::getRibbon()
{
return m_pRibbon;
}
}// namespace cocos2d
/*
* Motion Streak manages a Ribbon based on it's motion in absolute space.
* You construct it with a fadeTime, minimum segment size, texture path, texture
* length and color. The fadeTime controls how long it takes each vertex in
* the streak to fade out, the minimum segment size it how many pixels the
* streak will move before adding a new ribbon segement, and the texture
* length is the how many pixels the texture is stretched across. The texture
* is vertically aligned along the streak segemnts.
*/
//implementation CCMotionStreak
CCMotionStreak * CCMotionStreak::streakWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color)
{
CCMotionStreak *pRet = new CCMotionStreak();
if(pRet && pRet->initWithFade(fade, seg, imagePath, width, length, color))
{
pRet->autorelease();
return pRet;
}
CCX_SAFE_DELETE(pRet)
return NULL;
}
bool CCMotionStreak::initWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color)
{
m_fSegThreshold = seg;
m_fWidth = width;
m_tLastLocation = CGPointZero;
m_pRibbon = CCRibbon::ribbonWithWidth(m_fWidth, imagePath, length, color, fade);
this->addChild(m_pRibbon);
// update ribbon position
this->schedule(schedule_selector(CCMotionStreak::update), 0);
return true;
}
void CCMotionStreak::update(ccTime delta)
{
CGPoint location = this->convertToWorldSpace(CGPointZero);
m_pRibbon->setPosition(ccp(-1*location.x, -1*location.y));
float len = ccpLength(ccpSub(m_tLastLocation, location));
if (len > m_fSegThreshold)
{
m_pRibbon->addPointAt(location, m_fWidth);
m_tLastLocation = location;
}
m_pRibbon->update(delta);
}
//MotionStreak - CocosNodeTexture protocol
void CCMotionStreak::setTexture(CCTexture2D* texture)
{
m_pRibbon->setTexture(texture);
}
CCTexture2D * CCMotionStreak::getTexture()
{
return m_pRibbon->getTexture();
}
ccBlendFunc CCMotionStreak::getBlendFunc()
{
return m_pRibbon->getBlendFunc();
}
void CCMotionStreak::setBlendFunc(ccBlendFunc blendFunc)
{
m_pRibbon->setBlendFunc(blendFunc);
}
CCRibbon * CCMotionStreak::getRibbon()
{
return m_pRibbon;
}
}// namespace cocos2d

File diff suppressed because it is too large Load Diff

View File

@ -26,145 +26,312 @@ THE SOFTWARE.
#include "CCDirector.h"
#include "platform/platform.h"
#include "CCXUIImage.h"
#include "Support/ccUtls.h"
#include <GLES/glext.h>
namespace cocos2d {
// implementation CCRenderTexture
CCSprite * CCRenderTexture::getSprite()
{
return m_pSprite;
}
void CCRenderTexture::setSprite(CCSprite* var)
{
m_pSprite = var;
}
// implementation CCRenderTexture
CCRenderTexture::CCRenderTexture()
: m_pSprite(NULL)
, m_uFBO(0)
, m_nOldFBO(0)
, m_pTexture(0)
, m_ePixelFormat(kCCPixelFormatRGBA8888)
{
memset(m_aClearColor, 0, sizeof(m_aClearColor));
}
CCRenderTexture * CCRenderTexture::renderTextureWithWidthAndHeight(int width, int height)
{
CCRenderTexture *pRet = new CCRenderTexture();
CCRenderTexture::~CCRenderTexture()
{
removeAllChildrenWithCleanup(true);
ccglDeleteFramebuffers(1, &m_uFBO);
}
if(pRet && pRet->initWithWidthAndHeight(width,height))
{
pRet->autorelease();
return pRet;
}
CCX_SAFE_DELETE(pRet)
return NULL;
}
bool CCRenderTexture::initWithWidthAndHeight(int width, int height)
{
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &m_nOldFBO);
CCTexture2DPixelFormat format = kCCTexture2DPixelFormat_RGBA8888;
// textures must be power of two squared
int pow = 8;
while (pow < width || pow < height)
{
pow*=2;
}
void *data = malloc((int)(pow * pow * 4));
memset(data, 0, (int)(pow * pow * 4));
m_pTexture = new CCTexture2D();
m_pTexture->initWithData(data, format, pow, pow, CGSizeMake((float)width, (float)height));
free( data );
// generate FBO
glGenFramebuffersOES(1, &m_uFBO);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_uFBO);
// associate texture with FBO
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, m_pTexture->getName(), 0);
CCSprite * CCRenderTexture::getSprite()
{
return m_pSprite;
}
void CCRenderTexture::setSprite(CCSprite* var)
{
m_pSprite = var;
}
// check if it worked (probably worth doing :) )
GLuint status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
if (status != GL_FRAMEBUFFER_COMPLETE_OES)
{
NSAssert(0, "Render Texture : Could not attach texture to framebuffer")
CCX_SAFE_DELETE(m_pTexture);
return false;
}
m_pSprite = CCSprite::spriteWithTexture(m_pTexture);
m_pTexture->release();
m_pSprite->setScaleY(-1);
this->addChild(m_pSprite);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_nOldFBO);
return true;
}
CCRenderTexture::~CCRenderTexture()
{
glDeleteFramebuffersOES(1, &m_uFBO);
}
void CCRenderTexture::begin()
{
CC_DISABLE_DEFAULT_GL_STATES();
// Save the current matrix
glPushMatrix();
CCRenderTexture * CCRenderTexture::renderTextureWithWidthAndHeight(int w, int h, CCTexture2DPixelFormat eFormat)
{
CCRenderTexture *pRet = new CCRenderTexture();
CGSize textureSize = m_pTexture->getContentSize();
if(pRet && pRet->initWithWidthAndHeight(w, h, eFormat))
{
pRet->autorelease();
return pRet;
}
CCX_SAFE_DELETE(pRet);
return NULL;
}
// Calculate the adjustment ratios based on the old and new projections
CGSize size = CCDirector::sharedDirector()->getDisplaySize();
float widthRatio = size.width / textureSize.width;
float heightRatio = size.height / textureSize.height;
CCRenderTexture * CCRenderTexture::renderTextureWithWidthAndHeight(int w, int h)
{
CCRenderTexture *pRet = new CCRenderTexture();
// Adjust the orthographic propjection and viewport
glOrthof((float)-1.0 / widthRatio, (float)1.0 / widthRatio, (float)-1.0 / heightRatio, (float)1.0 / heightRatio, -1,1);
glViewport(0, 0, (GLsizei)textureSize.width, (GLsizei)textureSize.height);
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &m_nOldFBO);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_uFBO);//Will direct drawing to the frame buffer created above
CC_ENABLE_DEFAULT_GL_STATES();
}
void CCRenderTexture::end()
if(pRet && pRet->initWithWidthAndHeight(w, h, kCCTexture2DPixelFormat_RGBA8888))
{
glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_nOldFBO);
// Restore the original matrix and viewport
glPopMatrix();
CGSize size = CCDirector::sharedDirector()->getDisplaySize();
glViewport(0, 0, (GLsizei)size.width, (GLsizei)size.height);
pRet->autorelease();
return pRet;
}
CCX_SAFE_DELETE(pRet)
return NULL;
}
bool CCRenderTexture::initWithWidthAndHeight(int w, int h, CCTexture2DPixelFormat eFormat)
{
bool bRet = false;
do
{
w *= CC_CONTENT_SCALE_FACTOR();
h *= CC_CONTENT_SCALE_FACTOR();
glColorMask(true, true, true, true);
}
void CCRenderTexture::clear(float r, float g, float b, float a)
{
this->begin();
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColorMask(true, true, true, false);
this->end();
}
bool CCRenderTexture::saveBuffer(const char *name)
{
return this->saveBuffer(name, kImageFormatJPG);
}
bool CCRenderTexture::saveBuffer(const char *name, int format)
{
bool bRet = false;
UIImage *myImage = this->getUIImageFromBuffer();
if (myImage)
{
bRet = myImage->save(name, format);
delete myImage;
}
return bRet;
}
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &m_nOldFBO);
/* get buffer as UIImage */
UIImage * CCRenderTexture::getUIImageFromBuffer()
{
int tx = (int)m_pTexture->getContentSize().width;
int ty = (int)m_pTexture->getContentSize().height;
char * pBuffer = new char[tx * ty * 4];
this->begin();
glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, pBuffer);
this->end();
UIImage *pRet = new UIImage();
pRet->initWithBuffer(tx, ty, (unsigned char*)pBuffer);
delete[] pBuffer;
return pRet;
}
// textures must be power of two squared
unsigned int powW = ccNextPOT(w);
unsigned int powH = ccNextPOT(h);
void *data = malloc((int)(powW * powH * 4));
CCX_BREAK_IF(! data);
memset(data, 0, (int)(powW * powH * 4));
m_ePixelFormat = eFormat;
m_pTexture = new CCTexture2D();
CCX_BREAK_IF(! m_pTexture);
m_pTexture->initWithData(data, m_ePixelFormat, powW, powH, CGSizeMake((float)w, (float)h));
free( data );
// generate FBO
ccglGenFramebuffers(1, &m_uFBO);
ccglBindFramebuffer(CC_GL_FRAMEBUFFER, m_uFBO);
// associate texture with FBO
ccglFramebufferTexture2D(CC_GL_FRAMEBUFFER, CC_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pTexture->getName(), 0);
// check if it worked (probably worth doing :) )
GLuint status = ccglCheckFramebufferStatus(CC_GL_FRAMEBUFFER);
if (status != CC_GL_FRAMEBUFFER_COMPLETE)
{
NSAssert(0, "Render Texture : Could not attach texture to framebuffer");
CCX_SAFE_DELETE(m_pTexture);
break;
}
m_pTexture->setAliasTexParameters();
m_pSprite = CCSprite::spriteWithTexture(m_pTexture);
m_pTexture->release();
m_pSprite->setScaleY(-1);
this->addChild(m_pSprite);
ccBlendFunc tBlendFunc = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA };
m_pSprite->setBlendFunc(tBlendFunc);
ccglBindFramebuffer(CC_GL_FRAMEBUFFER, m_nOldFBO);
bRet = true;
} while (0);
return bRet;
}
void CCRenderTexture::begin()
{
saveGLstate();
CC_DISABLE_DEFAULT_GL_STATES();
// Save the current matrix
glPushMatrix();
CGSize texSize = m_pTexture->getContentSizeInPixels();
// Calculate the adjustment ratios based on the old and new projections
CGSize size = CCDirector::sharedDirector()->getDisplaySizeInPixels();
float widthRatio = size.width / texSize.width;
float heightRatio = size.height / texSize.height;
// Adjust the orthographic propjection and viewport
ccglOrtho((float)-1.0 / widthRatio, (float)1.0 / widthRatio, (float)-1.0 / heightRatio, (float)1.0 / heightRatio, -1,1);
glViewport(0, 0, (GLsizei)texSize.width, (GLsizei)texSize.height);
glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &m_nOldFBO);
ccglBindFramebuffer(CC_GL_FRAMEBUFFER, m_uFBO);//Will direct drawing to the frame buffer created above
CC_ENABLE_DEFAULT_GL_STATES();
}
void CCRenderTexture::beginWithClear(float r, float g, float b, float a)
{
this->saveGLstate();
CC_DISABLE_DEFAULT_GL_STATES();
// Save the current matrix
glPushMatrix();
CGSize texSize = m_pTexture->getContentSizeInPixels();
// Calculate the adjustment ratios based on the old and new projections
CGSize size = CCDirector::sharedDirector()->getDisplaySizeInPixels();
float widthRatio = size.width / texSize.width;
float heightRatio = size.height / texSize.height;
// Adjust the orthographic propjection and viewport
ccglOrtho((float)-1.0 / widthRatio, (float)1.0 / widthRatio, (float)-1.0 / heightRatio, (float)1.0 / heightRatio, -1,1);
glViewport(0, 0, texSize.width, texSize.height);
glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &m_oldFBO);
ccglBindFramebuffer(CC_GL_FRAMEBUFFER, m_fbo);//Will direct drawing to the frame buffer created above
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
CC_ENABLE_DEFAULT_GL_STATES();
}
void CCRenderTexture::end()
{
ccglBindFramebuffer(CC_GL_FRAMEBUFFER, m_nOldFBO);
// Restore the original matrix and viewport
glPopMatrix();
CGSize size = CCDirector::sharedDirector()->getDisplaySizeInPixels();
glViewport(0, 0, (GLsizei)size.width, (GLsizei)size.height);
this->restoreGLstate();
}
void CCRenderTexture::clear(float r, float g, float b, float a)
{
this->begin();
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
this->end();
}
void CCRenderTexture::saveGLstate()
{
glGetFloatv(GL_COLOR_CLEAR_VALUE, m_aClearColor);
}
void CCRenderTexture::restoreGLstate()
{
glClearColor(m_aClearColor[0], m_aClearColor[1], m_aClearColor[2], m_aClearColor[3]);
}
bool CCRenderTexture::saveBuffer(const char *name)
{
return this->saveBuffer(name, kCCImageFormatJPG);
}
bool CCRenderTexture::saveBuffer(const char *fileName, int format)
{
bool bRet = false;
//@ todo CCRenderTexture::saveBuffer
// UIImage *myImage = this->getUIImageFromBuffer(format);
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *documentsDirectory = [paths objectAtIndex:0];
// NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:fileName];
// NSData * data = this->getUIImageAsDataFromBuffer(format);
// if (data)
// {
// bRet = data->writeToFile(path, true);
// delete data;
// bRet = true;
// }
return bRet;
}
NSData * CCRenderTexture::getUIImageAsDataFromBuffer(int format)
{
NSData * pData = NULL;
//@ todo CCRenderTexture::getUIImageAsDataFromBuffer
// #include "Availability.h"
// #include "UIKit.h"
// GLubyte * pBuffer = NULL;
// GLubyte * pPixels = NULL;
// do
// {
// CCX_BREAK_IF(! m_pTexture);
//
// NSAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888, "only RGBA8888 can be saved as image");
//
// CGSize s = m_pTexture->getContentSizeInPixels();
// int tx = s.width;
// int ty = s.height;
//
// int bitsPerComponent = 8;
// int bitsPerPixel = 32;
//
// int bytesPerRow = (bitsPerPixel / 8) * tx;
// int myDataLength = bytesPerRow * ty;
//
// CCX_BREAK_IF(! (pBuffer = new GLubyte[tx * ty * 4]));
// CCX_BREAK_IF(! (pPixels = new GLubyte[tx * ty * 4]));
//
// this->begin();
// glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, pBuffer);
// this->end();
//
// int x,y;
//
// for(y = 0; y <ty; y++) {
// for(x = 0; x <tx * 4; x++) {
// pPixels[((ty - 1 - y) * tx * 4 + x)] = pBuffer[(y * 4 * tx + x)];
// }
// }
//
// if (format == kCCImageFormatRawData)
// {
// pData = NSData::dataWithBytesNoCopy(pPixels, myDataLength);
// break;
// }
//@ todo impliment save to jpg or png
/*
CGImageCreate(size_t width, size_t height,
size_t bitsPerComponent, size_t bitsPerPixel, size_t bytesPerRow,
CGColorSpaceRef space, CGBitmapInfo bitmapInfo, CGDataProviderRef provider,
const CGFloat decode[], bool shouldInterpolate,
CGColorRenderingIntent intent)
*/
// make data provider with data.
// CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault;
// CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, myDataLength, NULL);
// CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
// CGImageRef iref = CGImageCreate(tx, ty,
// bitsPerComponent, bitsPerPixel, bytesPerRow,
// colorSpaceRef, bitmapInfo, provider,
// NULL, false,
// kCGRenderingIntentDefault);
//
// UIImage* image = [[UIImage alloc] initWithCGImage:iref];
//
// CGImageRelease(iref);
// CGColorSpaceRelease(colorSpaceRef);
// CGDataProviderRelease(provider);
//
//
//
// if (format == kCCImageFormatPNG)
// data = UIImagePNGRepresentation(image);
// else
// data = UIImageJPEGRepresentation(image, 1.0f);
//
// [image release];
// } while (0);
//
// CCX_SAFE_DELETE_ARRAY(pBuffer);
// CCX_SAFE_DELETE_ARRAY(pPixels);
return pData;
}
} // namespace cocos2d

View File

@ -21,380 +21,399 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCRibbon.h"
#include "CCTextureCache.h"
#include "CGPointExtension.h"
namespace cocos2d {
/*
* A ribbon is a dynamically generated list of polygons drawn as a single or series
* of triangle strips. The primary use of Ribbon is as the drawing class of Motion Streak,
* but it is quite useful on it's own. When manually drawing a ribbon, you can call addPointAt
* and pass in the parameters for the next location in the ribbon. The system will automatically
* generate new polygons, texture them accourding to your texture width, etc, etc.
*
* Ribbon data is stored in a RibbonSegment class. This class statically allocates enough verticies and
* texture coordinates for 50 locations (100 verts or 48 triangles). The ribbon class will allocate
* new segments when they are needed, and reuse old ones if available. The idea is to avoid constantly
* allocating new memory and prefer a more static method. However, since there is no way to determine
* the maximum size of some ribbons (motion streaks), a truely static allocation is not possible.
*
/*
* A ribbon is a dynamically generated list of polygons drawn as a single or series
* of triangle strips. The primary use of Ribbon is as the drawing class of Motion Streak,
* but it is quite useful on it's own. When manually drawing a ribbon, you can call addPointAt
* and pass in the parameters for the next location in the ribbon. The system will automatically
* generate new polygons, texture them accourding to your texture width, etc, etc.
*
* Ribbon data is stored in a RibbonSegment class. This class statically allocates enough verticies and
* texture coordinates for 50 locations (100 verts or 48 triangles). The ribbon class will allocate
* new segments when they are needed, and reuse old ones if available. The idea is to avoid constantly
* allocating new memory and prefer a more static method. However, since there is no way to determine
* the maximum size of some ribbons (motion streaks), a truely static allocation is not possible.
*
*/
//
// Ribbon
//
CCRibbon * CCRibbon::ribbonWithWidth(float w, const char *path, float length, ccColor4B color, float fade)
{
CCRibbon *pRet = new CCRibbon();
if(pRet && pRet->initWithWidth(w, path, length, color, fade))
{
pRet->autorelease();
return pRet;
}
CCX_SAFE_DELETE(pRet)
return NULL;
}
bool CCRibbon::initWithWidth(float w, const char *path, float length, ccColor4B color, float fade)
{
m_pSegments = new NSMutableArray<CCRibbonSegment*>();
m_pDeletedSegments = new NSMutableArray<CCRibbonSegment*>();
/* 1 initial segment */
CCRibbonSegment* seg = new CCRibbonSegment();
seg->init();
m_pSegments->addObject(seg);
seg->release();
m_fTextureLength = length;
m_tColor = color;
m_fFadeTime = fade;
m_tLastLocation = CGPointZero;
m_fLastWidth = w/2;
m_fTexVPos = 0.0f;
m_fCurTime = 0;
m_bPastFirstPoint = false;
/* XXX:
Ribbon, by default uses this blend function, which might not be correct
if you are using premultiplied alpha images,
but 99% you might want to use this blending function regarding of the texture
*/
m_tBlendFunc.src = GL_SRC_ALPHA;
m_tBlendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
//
// Ribbon
//
CCRibbon * CCRibbon::ribbonWithWidth(float w, const char *path, float length, ccColor4B color, float fade)
m_pTexture = CCTextureCache::sharedTextureCache()->addImage(path);
CCX_SAFE_RETAIN(m_pTexture);
/* default texture parameter */
ccTexParams params = { GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT };
m_pTexture->setTexParameters(&params);
return true;
}
CCRibbon::~CCRibbon()
{
CCX_SAFE_RELEASE(m_pSegments);
CCX_SAFE_RELEASE(m_pDeletedSegments);
CCX_SAFE_RELEASE(m_pTexture);
}
CGPoint CCRibbon::rotatePoint(CGPoint vec, float rotation)
{
float xtemp = (vec.x * cosf(rotation)) - (vec.y * sinf(rotation));
vec.y = (vec.x * sinf(rotation)) + (vec.y * cosf(rotation));
vec.x = xtemp;
return vec;
}
void CCRibbon::update(ccTime delta)
{
m_fCurTime += delta;
m_fDelta = delta;
}
float CCRibbon::sideOfLine(CGPoint p, CGPoint l1, CGPoint l2)
{
CGPoint vp = ccpPerp(ccpSub(l1, l2));
CGPoint vx = ccpSub(p, l1);
return ccpDot(vx, vp);
}
// adds a new segment to the ribbon
void CCRibbon::addPointAt(CGPoint location, float width)
{
location.x *= CC_CONTENT_SCALE_FACTOR();
location.y *= CC_CONTENT_SCALE_FACTOR();
width = width * 0.5f;
// if this is the first point added, cache it and return
if (!m_bPastFirstPoint)
{
CCRibbon *pRet = new CCRibbon();
if(pRet && pRet->initWithWidth(w, path, length, color, fade))
{
pRet->autorelease();
return pRet;
}
CCX_SAFE_DELETE(pRet)
return NULL;
}
bool CCRibbon::initWithWidth(float w, const char *path, float length, ccColor4B color, float fade)
{
m_pSegments = new NSMutableArray<CCRibbonSegment*>();
m_pDeletedSegments = new NSMutableArray<CCRibbonSegment*>();
/* 1 initial segment */
CCRibbonSegment* seg = new CCRibbonSegment();
seg->init();
m_pSegments->addObject(seg);
seg->release();
m_fTextureLength = length;
m_tColor = color;
m_fFadeTime = fade;
m_tLastLocation = CGPointZero;
m_fLastWidth = w/2;
m_fTexVPos = 0.0f;
m_fCurTime = 0;
m_bPastFirstPoint = false;
/* XXX:
Ribbon, by default uses this blend function, which might not be correct
if you are using premultiplied alpha images,
but 99% you might want to use this blending function regarding of the texture
*/
m_tBlendFunc.src = GL_SRC_ALPHA;
m_tBlendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
m_pTexture = CCTextureCache::sharedTextureCache()->addImage(path);
CCX_SAFE_RETAIN(m_pTexture);
/* default texture parameter */
ccTexParams params = { GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT };
m_pTexture->setTexParameters(&params);
return true;
}
CCRibbon::~CCRibbon()
{
m_pSegments->release();
m_pDeletedSegments->release();
m_pTexture->release();
}
CGPoint CCRibbon::rotatePoint(CGPoint vec, float rotation)
{
float xtemp = (vec.x * cosf(rotation)) - (vec.y * sinf(rotation));
vec.y = (vec.x * sinf(rotation)) + (vec.y * cosf(rotation));
vec.x = xtemp;
return vec;
}
void CCRibbon::update(ccTime delta)
{
m_fCurTime += delta;
m_fDelta = delta;
}
float CCRibbon::sideOfLine(CGPoint p, CGPoint l1, CGPoint l2)
{
CGPoint vp = ccpPerp(ccpSub(l1, l2));
CGPoint vx = ccpSub(p, l1);
return ccpDot(vx, vp);
}
// adds a new segment to the ribbon
void CCRibbon::addPointAt(CGPoint location, float width)
{
width = width * 0.5f;
// if this is the first point added, cache it and return
if (!m_bPastFirstPoint)
{
m_fLastWidth = width;
m_tLastLocation = location;
m_bPastFirstPoint = true;
return;
}
CGPoint sub = ccpSub(m_tLastLocation, location);
float r = ccpToAngle(sub) + (float)M_PI_2;
CGPoint p1 = ccpAdd(this->rotatePoint(ccp(-width, 0), r), location);
CGPoint p2 = ccpAdd(this->rotatePoint(ccp(+width, 0), r), location);
float len = sqrtf(powf(m_tLastLocation.x - location.x, 2) + powf(m_tLastLocation.y - location.y, 2));
float tend = m_fTexVPos + len/m_fTextureLength;
CCRibbonSegment* seg;
// grab last segment
seg = m_pSegments->getLastObject();
// lets kill old segments
if (m_pSegments && m_pSegments->count()>0)
{
NSMutableArray<CCRibbonSegment*>::NSMutableArrayIterator it;
for (it = m_pSegments->begin(); it != m_pSegments->end(); ++it)
{
if (*it != seg && (*it)->m_bFinished)
{
m_pDeletedSegments->addObject(*it);
}
}
}
m_pSegments->removeObjectsInArray(m_pDeletedSegments);
// is the segment full?
if (seg->m_uEnd >= 50)
{
m_pSegments->removeObjectsInArray(m_pDeletedSegments);
}
// grab last segment and append to it if it's not full
seg = m_pSegments->getLastObject();
// is the segment full?
if (seg->m_uEnd >= 50)
{
CCRibbonSegment* newSeg;
// grab it from the cache if we can
if (m_pDeletedSegments->count() > 0)
{
newSeg = m_pDeletedSegments->getObjectAtIndex(0);
newSeg->retain(); // will be released later
m_pDeletedSegments->removeObject(newSeg);
newSeg->reset();
}
else
{
newSeg = new CCRibbonSegment(); // will be released later
newSeg->init();
}
newSeg->m_pCreationTime[0] = seg->m_pCreationTime[seg->m_uEnd- 1];
int v = (seg->m_uEnd-1)*6;
int c = (seg->m_uEnd-1)*4;
newSeg->m_pVerts[0] = seg->m_pVerts[v];
newSeg->m_pVerts[1] = seg->m_pVerts[v+1];
newSeg->m_pVerts[2] = seg->m_pVerts[v+2];
newSeg->m_pVerts[3] = seg->m_pVerts[v+3];
newSeg->m_pVerts[4] = seg->m_pVerts[v+4];
newSeg->m_pVerts[5] = seg->m_pVerts[v+5];
newSeg->m_pCoords[0] = seg->m_pCoords[c];
newSeg->m_pCoords[1] = seg->m_pCoords[c+1];
newSeg->m_pCoords[2] = seg->m_pCoords[c+2];
newSeg->m_pCoords[3] = seg->m_pCoords[c+3];
newSeg->m_uEnd++;
seg = newSeg;
m_pSegments->addObject(seg);
newSeg->release();// it was retained before
}
if (seg->m_uEnd == 0)
{
// first edge has to get rotation from the first real polygon
CGPoint lp1 = ccpAdd(this->rotatePoint(ccp(-m_fLastWidth, 0), r), m_tLastLocation);
CGPoint lp2 = ccpAdd(this->rotatePoint(ccp(+m_fLastWidth, 0), r), m_tLastLocation);
seg->m_pCreationTime[0] = m_fCurTime - m_fDelta;
seg->m_pVerts[0] = lp1.x;
seg->m_pVerts[1] = lp1.y;
seg->m_pVerts[2] = 0.0f;
seg->m_pVerts[3] = lp2.x;
seg->m_pVerts[4] = lp2.y;
seg->m_pVerts[5] = 0.0f;
seg->m_pCoords[0] = 0.0f;
seg->m_pCoords[1] = m_fTexVPos;
seg->m_pCoords[2] = 1.0f;
seg->m_pCoords[3] = m_fTexVPos;
seg->m_uEnd++;
}
int v = seg->m_uEnd*6;
int c = seg->m_uEnd*4;
// add new vertex
seg->m_pCreationTime[seg->m_uEnd] = m_fCurTime;
seg->m_pVerts[v] = p1.x;
seg->m_pVerts[v+1] = p1.y;
seg->m_pVerts[v+2] = 0.0f;
seg->m_pVerts[v+3] = p2.x;
seg->m_pVerts[v+4] = p2.y;
seg->m_pVerts[v+5] = 0.0f;
seg->m_pCoords[c] = 0.0f;
seg->m_pCoords[c+1] = tend;
seg->m_pCoords[c+2] = 1.0f;
seg->m_pCoords[c+3] = tend;
m_fTexVPos = tend;
m_tLastLocation = location;
m_tLastPoint1 = p1;
m_tLastPoint2 = p2;
m_fLastWidth = width;
seg->m_uEnd++;
m_tLastLocation = location;
m_bPastFirstPoint = true;
return;
}
void CCRibbon::draw()
CGPoint sub = ccpSub(m_tLastLocation, location);
float r = ccpToAngle(sub) + (float)M_PI_2;
CGPoint p1 = ccpAdd(this->rotatePoint(ccp(-width, 0), r), location);
CGPoint p2 = ccpAdd(this->rotatePoint(ccp(+width, 0), r), location);
float len = sqrtf(powf(m_tLastLocation.x - location.x, 2) + powf(m_tLastLocation.y - location.y, 2));
float tend = m_fTexVPos + len/m_fTextureLength;
CCRibbonSegment* seg;
// grab last segment
seg = m_pSegments->getLastObject();
// lets kill old segments
if (m_pSegments && m_pSegments->count()>0)
{
if (m_pSegments->count() > 0)
NSMutableArray<CCRibbonSegment*>::NSMutableArrayIterator it;
for (it = m_pSegments->begin(); it != m_pSegments->end(); ++it)
{
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY
// Unneeded states: GL_COLOR_ARRAY
glDisableClientState(GL_COLOR_ARRAY);
glBindTexture(GL_TEXTURE_2D, m_pTexture->getName());
bool newBlend = false;
if( m_tBlendFunc.src != CC_BLEND_SRC || m_tBlendFunc.dst != CC_BLEND_DST )
if (*it != seg && (*it)->m_bFinished)
{
newBlend = true;
glBlendFunc( m_tBlendFunc.src, m_tBlendFunc.dst );
m_pDeletedSegments->addObject(*it);
}
if(m_pSegments && m_pSegments->count() > 0)
{
CCRibbonSegment* seg;
NSMutableArray<CCRibbonSegment*>::NSMutableArrayIterator it;
for( it = m_pSegments->begin(); it != m_pSegments->end(); it++)
{
seg = (CCRibbonSegment*)*it;
seg->draw(m_fCurTime, m_fFadeTime, m_tColor);
}
}
if( newBlend )
{
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
}
// restore default GL state
glEnableClientState( GL_COLOR_ARRAY );
}
}
// Ribbon - CocosNodeTexture protocol
void CCRibbon::setTexture(CCTexture2D* var)
m_pSegments->removeObjectsInArray(m_pDeletedSegments);
// is the segment full?
if (seg->m_uEnd >= 50)
{
CCX_SAFE_RETAIN(var);
CCX_SAFE_RELEASE(m_pTexture);
m_pTexture = var;
this->setContentSize(m_pTexture->getContentSize());
/* XXX Don't update blending function in Ribbons */
m_pSegments->removeObjectsInArray(m_pDeletedSegments);
}
CCTexture2D *CCRibbon::getTexture()
// grab last segment and append to it if it's not full
seg = m_pSegments->getLastObject();
// is the segment full?
if (seg->m_uEnd >= 50)
{
return m_pTexture;
}
void CCRibbon::setTextureLength(float var)
{
m_fTextureLength = var;
}
float CCRibbon::getTextureLength()
{
return m_fTextureLength;
}
void CCRibbon::setBlendFunc(ccBlendFunc var)
{
m_tBlendFunc = var;
}
ccBlendFunc CCRibbon::getBlendFunc()
{
return m_tBlendFunc;
}
void CCRibbon::setColor(ccColor4B var)
{
m_tColor = var;
}
ccColor4B CCRibbon::getColor()
{
return m_tColor;
}
//
//RibbonSegment
//
bool CCRibbonSegment::init()
{
this->reset();
return true;
}
char * CCRibbonSegment::description()
{
char *ret = new char[100] ;
sprintf(ret, "<CCRibbonSegment | end = %u, begin = %u>", m_uEnd, m_uBegin);
return ret;
}
CCRibbonSegment::~CCRibbonSegment()
{
CCLOGINFO("cocos2d: deallocing.");
}
void CCRibbonSegment::reset()
{
m_uEnd = 0;
m_uBegin = 0;
m_bFinished = false;
}
void CCRibbonSegment::draw(float curTime, float fadeTime, ccColor4B color)
{
GLubyte r = color.r;
GLubyte g = color.g;
GLubyte b = color.b;
GLubyte a = color.a;
if (m_uBegin < 50)
CCRibbonSegment* newSeg;
// grab it from the cache if we can
if (m_pDeletedSegments->count() > 0)
{
// the motion streak class will call update and cause time to change, thus, if curTime_ != 0
// we have to generate alpha for the ribbon each frame.
if (curTime == 0)
{
// no alpha over time, so just set the color
glColor4ub(r,g,b,a);
}
else
{
// generate alpha/color for each point
glEnableClientState(GL_COLOR_ARRAY);
unsigned int i = m_uBegin;
for (; i < m_uEnd; ++i)
{
int idx = i*8;
m_pColors[idx] = r;
m_pColors[idx+1] = g;
m_pColors[idx+2] = b;
m_pColors[idx+4] = r;
m_pColors[idx+5] = g;
m_pColors[idx+6] = b;
float alive = ((curTime - m_pCreationTime[i]) / fadeTime);
if (alive > 1)
{
m_uBegin++;
m_pColors[idx+3] = 0;
m_pColors[idx+7] = 0;
}
else
{
m_pColors[idx+3] = (GLubyte)(255.f - (alive * 255.f));
m_pColors[idx+7] = m_pColors[idx+3];
}
}
glColorPointer(4, GL_UNSIGNED_BYTE, 0, &m_pColors[m_uBegin*8]);
}
glVertexPointer(3, GL_FLOAT, 0, &m_pVerts[m_uBegin*6]);
glTexCoordPointer(2, GL_FLOAT, 0, &m_pCoords[m_uBegin*4]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (m_uEnd - m_uBegin) * 2);
newSeg = m_pDeletedSegments->getObjectAtIndex(0);
newSeg->retain(); // will be released later
m_pDeletedSegments->removeObject(newSeg);
newSeg->reset();
}
else
{
m_bFinished = true;
newSeg = new CCRibbonSegment(); // will be released later
newSeg->init();
}
newSeg->m_pCreationTime[0] = seg->m_pCreationTime[seg->m_uEnd- 1];
int v = (seg->m_uEnd-1)*6;
int c = (seg->m_uEnd-1)*4;
newSeg->m_pVerts[0] = seg->m_pVerts[v];
newSeg->m_pVerts[1] = seg->m_pVerts[v+1];
newSeg->m_pVerts[2] = seg->m_pVerts[v+2];
newSeg->m_pVerts[3] = seg->m_pVerts[v+3];
newSeg->m_pVerts[4] = seg->m_pVerts[v+4];
newSeg->m_pVerts[5] = seg->m_pVerts[v+5];
newSeg->m_pCoords[0] = seg->m_pCoords[c];
newSeg->m_pCoords[1] = seg->m_pCoords[c+1];
newSeg->m_pCoords[2] = seg->m_pCoords[c+2];
newSeg->m_pCoords[3] = seg->m_pCoords[c+3];
newSeg->m_uEnd++;
seg = newSeg;
m_pSegments->addObject(seg);
newSeg->release();// it was retained before
}
if (seg->m_uEnd == 0)
{
// first edge has to get rotation from the first real polygon
CGPoint lp1 = ccpAdd(this->rotatePoint(ccp(-m_fLastWidth, 0), r), m_tLastLocation);
CGPoint lp2 = ccpAdd(this->rotatePoint(ccp(+m_fLastWidth, 0), r), m_tLastLocation);
seg->m_pCreationTime[0] = m_fCurTime - m_fDelta;
seg->m_pVerts[0] = lp1.x;
seg->m_pVerts[1] = lp1.y;
seg->m_pVerts[2] = 0.0f;
seg->m_pVerts[3] = lp2.x;
seg->m_pVerts[4] = lp2.y;
seg->m_pVerts[5] = 0.0f;
seg->m_pCoords[0] = 0.0f;
seg->m_pCoords[1] = m_fTexVPos;
seg->m_pCoords[2] = 1.0f;
seg->m_pCoords[3] = m_fTexVPos;
seg->m_uEnd++;
}
}// namespace cocos2d
int v = seg->m_uEnd*6;
int c = seg->m_uEnd*4;
// add new vertex
seg->m_pCreationTime[seg->m_uEnd] = m_fCurTime;
seg->m_pVerts[v] = p1.x;
seg->m_pVerts[v+1] = p1.y;
seg->m_pVerts[v+2] = 0.0f;
seg->m_pVerts[v+3] = p2.x;
seg->m_pVerts[v+4] = p2.y;
seg->m_pVerts[v+5] = 0.0f;
seg->m_pCoords[c] = 0.0f;
seg->m_pCoords[c+1] = tend;
seg->m_pCoords[c+2] = 1.0f;
seg->m_pCoords[c+3] = tend;
m_fTexVPos = tend;
m_tLastLocation = location;
m_tLastPoint1 = p1;
m_tLastPoint2 = p2;
m_fLastWidth = width;
seg->m_uEnd++;
}
void CCRibbon::draw()
{
if (m_pSegments->count() > 0)
{
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY
// Unneeded states: GL_COLOR_ARRAY
glDisableClientState(GL_COLOR_ARRAY);
glBindTexture(GL_TEXTURE_2D, m_pTexture->getName());
bool newBlend = ( m_tBlendFunc.src != CC_BLEND_SRC || m_tBlendFunc.dst != CC_BLEND_DST ) ? true : false;
if( newBlend )
{
glBlendFunc( m_tBlendFunc.src, m_tBlendFunc.dst );
}
if(m_pSegments && m_pSegments->count() > 0)
{
CCRibbonSegment* seg;
NSMutableArray<CCRibbonSegment*>::NSMutableArrayIterator it;
for( it = m_pSegments->begin(); it != m_pSegments->end(); it++)
{
seg = (CCRibbonSegment*)*it;
seg->draw(m_fCurTime, m_fFadeTime, m_tColor);
}
}
if( newBlend )
{
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
}
// restore default GL state
glEnableClientState( GL_COLOR_ARRAY );
}
}
// Ribbon - CocosNodeTexture protocol
void CCRibbon::setTexture(CCTexture2D* var)
{
CCX_SAFE_RETAIN(var);
CCX_SAFE_RELEASE(m_pTexture);
m_pTexture = var;
this->setContentSize(m_pTexture->getContentSizeInPixels());
/* XXX Don't update blending function in Ribbons */
}
CCTexture2D *CCRibbon::getTexture()
{
return m_pTexture;
}
void CCRibbon::setTextureLength(float var)
{
m_fTextureLength = var;
}
float CCRibbon::getTextureLength()
{
return m_fTextureLength;
}
void CCRibbon::setBlendFunc(ccBlendFunc var)
{
m_tBlendFunc = var;
}
ccBlendFunc CCRibbon::getBlendFunc()
{
return m_tBlendFunc;
}
void CCRibbon::setColor(ccColor4B var)
{
m_tColor = var;
}
ccColor4B CCRibbon::getColor()
{
return m_tColor;
}
//
//RibbonSegment
//
bool CCRibbonSegment::init()
{
this->reset();
return true;
}
char * CCRibbonSegment::description()
{
char *ret = new char[100] ;
sprintf(ret, "<CCRibbonSegment | end = %u, begin = %u>", m_uEnd, m_uBegin);
return ret;
}
CCRibbonSegment::~CCRibbonSegment()
{
CCLOGINFO("cocos2d: deallocing.");
}
void CCRibbonSegment::reset()
{
m_uEnd = 0;
m_uBegin = 0;
m_bFinished = false;
}
void CCRibbonSegment::draw(float curTime, float fadeTime, ccColor4B color)
{
GLubyte r = color.r;
GLubyte g = color.g;
GLubyte b = color.b;
GLubyte a = color.a;
if (m_uBegin < 50)
{
// the motion streak class will call update and cause time to change, thus, if curTime_ != 0
// we have to generate alpha for the ribbon each frame.
if (curTime == 0)
{
// no alpha over time, so just set the color
glColor4ub(r,g,b,a);
}
else
{
// generate alpha/color for each point
glEnableClientState(GL_COLOR_ARRAY);
unsigned int i = m_uBegin;
for (; i < m_uEnd; ++i)
{
int idx = i*8;
m_pColors[idx] = r;
m_pColors[idx+1] = g;
m_pColors[idx+2] = b;
m_pColors[idx+4] = r;
m_pColors[idx+5] = g;
m_pColors[idx+6] = b;
float alive = ((curTime - m_pCreationTime[i]) / fadeTime);
if (alive > 1)
{
m_uBegin++;
m_pColors[idx+3] = 0;
m_pColors[idx+7] = 0;
}
else
{
m_pColors[idx+3] = (GLubyte)(255.f - (alive * 255.f));
m_pColors[idx+7] = m_pColors[idx+3];
}
}
glColorPointer(4, GL_UNSIGNED_BYTE, 0, &m_pColors[m_uBegin*8]);
}
glVertexPointer(3, GL_FLOAT, 0, &m_pVerts[m_uBegin*6]);
glTexCoordPointer(2, GL_FLOAT, 0, &m_pCoords[m_uBegin*4]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (m_uEnd - m_uBegin) * 2);
}
else
{
m_bFinished = true;
}
}
}// namespace cocos2d

View File

@ -81,6 +81,7 @@ public: inline varType get##funName(void){ return varName; }\
public: inline void set##funName(varType var){ varName = var; }
#define CCX_SAFE_DELETE(p) if(p) { delete p; p=NULL; }
#define CCX_SAFE_DELETE_ARRAY(p) if(p) { delete[] p; p=NULL; }
#define CCX_SAFE_FREE(p) if(p) { free(p); p=NULL; }
#define CCX_SAFE_RELEASE(p) if(p) { p->release(); }
#define CCX_SAFE_RELEASE_NULL(p) if(p) { p->release(); p = NULL; }

View File

@ -116,7 +116,7 @@ UIImage::~UIImage(void)
}
}
bool UIImage::initWithContentsOfFile(const string &strPath, tImageFormat imageType)
bool UIImage::initWithContentsOfFile(const string &strPath, eImageFormat imageType)
{
bool bRet = false;
@ -138,11 +138,11 @@ bool UIImage::initWithContentsOfFile(const string &strPath, tImageFormat imageTy
{
switch (imageType)
{
case kImageFormatPNG:
case kCCImageFormatPNG:
// use libpng load image
bRet = loadPngFromStream(pBuffer, nSize);
break;
case kImageFormatJPG:
case kCCImageFormatJPG:
bRet = loadJpgFromStream(pBuffer, nSize);
break;
default:

View File

@ -64,7 +64,7 @@ public:
- kImageFormatJPG -> jpeg
@return true if load correctly
*/
bool initWithContentsOfFile(const std::string &strPath, tImageFormat imageType = kImageFormatPNG);
bool initWithContentsOfFile(const std::string &strPath, eImageFormat imageType = kCCImageFormatPNG);
/**
Load image from stream buffer.
@param pBuffer stream buffer that hold the image data

View File

@ -207,7 +207,7 @@ CCTexture2D * CCTextureCache::addImage(const char * path)
else if (std::string::npos != lowerCase.find(".jpg") || std::string::npos != lowerCase.find(".jpeg"))
{
UIImage * image = new UIImage();
if(! image->initWithContentsOfFile(fullpath, kImageFormatJPG))
if(! image->initWithContentsOfFile(fullpath, kCCImageFormatJPG))
{
delete image;
break;
@ -235,7 +235,7 @@ CCTexture2D * CCTextureCache::addImage(const char * path)
#else
// prevents overloading the autorelease pool
UIImage * image = new UIImage();
if(! image->initWithContentsOfFile(fullpath, kImageFormatPNG))
if(! image->initWithContentsOfFile(fullpath, kCCImageFormatPNG))
{
delete image;
break;