Hm as your attachment quota has exceeded I paste the code into this post:
ParticleManager.h
#import "cocos2d.h"
#import "myCocosExtensions.h"
#import "Globals.h"
@interface ParticleManager : CCNode {
// Array of particles
tCCParticle *particles;
// Maximum particles
int totalParticles;
// Texture of the particles
CCTexture2D *texture;
// particle idx
int particleIdx;
// Array of (x,y,size)
ccPointSprite *vertices;
// vertices buffer id
GLuint verticesID;
// additive color or blend
BOOL blendAdditive;
ccBlendFunc blendFunc;
}
@property (nonatomic, readwrite, retain) CCTexture2D* texture;
@property (nonatomic, readwrite) BOOL blendAdditive;
@property (nonatomic, readonly) int particleIdx;
- (void) update: (ccTime) dt;
@end
@interface ParticleManagerManager : CCNode
{
NSMutableDictionary* dict;
uint particleCount;
}
- (void) setGravityMulti:(float)gm;
@end
ParticleManager.m
#import "ParticleManager.h"
#import "GameState.h"
int sParticleManagerCounter=0;
int sParticleManagerManagerCounter=0;
extern GameState sGameState;
@implementation ParticleManager
@synthesize texture;
@synthesize blendAdditive;
@synthesize particleIdx;
- (id) init
{
if(!(self=[super init])) return nil;
sParticleManagerCounter++;
texture = nil;
totalParticles = 0;
vertices = NULL;
// default: additive
blendAdditive = NO;
// blend function
blendFunc = (ccBlendFunc) { CC_BLEND_SRC, CC_BLEND_DST };
// [self schedule:@selector(step:)];
return self;
}
- (void) dealloc
{
sParticleManagerCounter--;
if(vertices)
{
free(vertices);
glDeleteBuffers(1, &verticesID);
}
[texture release];
[super dealloc];
}
- (void) removeChild:(CCNode *)node cleanup:(BOOL)cleanup
{
assert(false); // not supported (and needed) yet
}
- (id) addChild:(id)child z:(int)z tag:(int) aTag
{
totalParticles += [((CCParticleSystem*)child) totalParticles];
[super addChild:child z:z tag:aTag];
return self;
}
- (void) update:(ccTime)dt
{
if (!vertices) {
vertices = malloc( sizeof(ccPointSprite) * totalParticles);
assert(vertices);
if( ! vertices ) {
NSLog(@"Particle manager: not enough memory");
if( vertices )
free(vertices);
return;
}
// initial binding // not really sure if this is needed
glGenBuffers(1, &verticesID);
glBindBuffer(GL_ARRAY_BUFFER, verticesID);
glBufferData(GL_ARRAY_BUFFER, sizeof(ccPointSprite)*totalParticles, vertices, GL_DYNAMIC_DRAW); // 1 //vertices
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
particleIdx=0;
for(CCPointParticleSystem* ps in children_)
{
if (particleIdx < totalParticles) {
[ps setVertices:&vertices[particleIdx]];
[ps update:dt];
// assert([ps particleIdx] <
particleIdx+=[ps particleIdx];
}
}
if(particleIdx>0)
{
glBindBuffer(GL_ARRAY_BUFFER, verticesID);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(ccPointSprite)*particleIdx, vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
#ifndef RELEASE_FINAL
GLenum glError = glGetError();
NSAssert1(glError == GL_NO_ERROR, @"glError %d", glError);
#endif
}
}
- (void) draw
{
if(particleIdx>0)
{
glBindTexture(GL_TEXTURE_2D, texture.name);
glTexEnvi( GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE );
glBindBuffer(GL_ARRAY_BUFFER, verticesID);
glVertexPointer(2,GL_FLOAT,sizeof(vertices[0]),0);
glColorPointer(4, GL_FLOAT, sizeof(vertices[0]),(GLvoid*) offsetof(ccPointSprite, colors) );
glPointSizePointerOES(GL_FLOAT,sizeof(vertices[0]),(GLvoid*) offsetof(ccPointSprite, size) );
BOOL newBlend = NO;
if( blendAdditive )
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
else if( blendFunc.src != CC_BLEND_SRC || blendFunc.dst != CC_BLEND_DST ) {
newBlend = YES;
glBlendFunc( blendFunc.src, blendFunc.dst );
}
// save color mode
#if 0
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &colorMode);
if( colorModulate )
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
else
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
#endif
glDrawArrays(GL_POINTS, 0, particleIdx);
// restore blend state
if( blendAdditive || newBlend )
glBlendFunc( CC_BLEND_SRC, CC_BLEND_DST);
// // restore blend state
// if( blendAdditive || ! premultipliedColors )
// glBlendFunc( CC_BLEND_SRC, CC_BLEND_DST);
#if 0
// restore color mode
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, colorMode);
#endif
// unbind VBO buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
-(void) setTexture:(CCTexture2D*) t
{
[texture release];
texture = [t retain];
if( ! [t hasPremultipliedAlpha] ) {
blendFunc.src = GL_SRC_ALPHA;
blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
}
}
@end
@implementation ParticleManagerManager
- (id) init
{
if(!(self=[super init])) return nil;
sParticleManagerManagerCounter++;
dict = [[NSMutableDictionary dictionaryWithCapacity:10] retain];
[self schedule:@selector(step:)];
return self;
}
- (void) dealloc
{
sParticleManagerManagerCounter--;
[self unschedule:@selector(step:)];
[dict release];
[super dealloc];
}
- (void) step:(ccTime)delta
{
particleCount=0;
for(ParticleManager *psm in children_)
{
[psm update:delta];
particleCount+=psm.particleIdx;
}
}
- (id) addChild:(id)child z:(int)z tag:(int) aTag
{
if([((CCParticleSystem*)child) totalParticles] == 0) return self;
uint name = [[((CCParticleSystem*)child) texture] name];
BOOL blendMode = [((CCParticleSystem*)child) blendAdditive];
NSString* key = [NSString stringWithFormat:@"%d%d%d", name, blendMode, aTag];
ParticleManager* psm = [dict objectForKey:key];
if(psm==nil)
{
psm = [ParticleManager node];
[psm setTexture:[((CCParticleSystem*)child) texture]];
[psm setBlendAdditive:blendMode];
[dict setObject:psm forKey:key];
[super addChild:psm z:z tag:aTag];
}
[psm addChild:child z:z tag:aTag];
return self;
}
- (void) setScale:(float)s
{
for(ParticleManager *psm in children_)
{
for(CCParticleSystem *ps in [psm children])
{
[ps setParticleScale:s];
}
}
}
- (void) setGravityMulti:(float)gm
{
for(ParticleManager *psm in children_)
{
for(CCParticleSystem *ps in [psm children])
{
[ps setGravityMulti:gm];
}
}
}
-(void) visit
{
if (!visible_ || particleCount==0)
return;
// glEnable(GL_TEXTURE_2D);
// glEnable(GL_POINT_SPRITE_OES);
// glTexEnvi( GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE );
// glEnableClientState(GL_VERTEX_ARRAY);
// glEnableClientState(GL_COLOR_ARRAY);
// glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
//
// [children makeObjectsPerformSelector:@selector(draw)];
//
// // unbind VBO buffer
//// glBindBuffer(GL_ARRAY_BUFFER, 0);
//
// glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
// glDisableClientState(GL_COLOR_ARRAY);
// glDisableClientState(GL_VERTEX_ARRAY);
// glDisable(GL_TEXTURE_2D);
// glDisable(GL_POINT_SPRITE_OES);
// 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_COLOR_ARRAY
// Unneeded states: GL_TEXTURE_COORD_ARRAY
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_POINT_SPRITE_OES);
glTexEnvi( GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE );
glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
[children_ makeObjectsPerformSelector:@selector(draw)];
glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
glDisable(GL_POINT_SPRITE_OES);
// restore GL default state
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
@end
We also made some changes to CCParticleSystem and CCPointParticleSystem (We do not use Quad particles yet). They check if the system is managed.