
local SceneIdx  = -1
local MAX_LAYER = 42

local emitter = nil
local background = nil

local labelAtlas = nil
local titleLabel = nil
local subtitleLabel = nil
local baseLayer_entry = nil

local s = CCDirector:sharedDirector():getWinSize()

local function backAction()
	SceneIdx = SceneIdx - 1
    if SceneIdx < 0 then
        SceneIdx = SceneIdx + MAX_LAYER
    end

    return CreateParticleLayer()
end

local function restartAction()
	return CreateParticleLayer()
end

local function nextAction()
	SceneIdx = SceneIdx + 1
    SceneIdx = math.mod(SceneIdx, MAX_LAYER)

    return CreateParticleLayer()
end

local function backCallback(sender)
	local scene = CCScene:create()

	scene:addChild(backAction())
	scene:addChild(CreateBackMenuItem())

	CCDirector:sharedDirector():replaceScene(scene)
end

local function restartCallback(sender)
	local scene = CCScene:create()

	scene:addChild(restartAction())
	scene:addChild(CreateBackMenuItem())

	CCDirector:sharedDirector():replaceScene(scene)
end

local function nextCallback(sender)
	local scene = CCScene:create()

	scene:addChild(nextAction())
	scene:addChild(CreateBackMenuItem())

	CCDirector:sharedDirector():replaceScene(scene)
end

local function toggleCallback(sender)
	if emitter ~= nil then
        if emitter:getPositionType() == kCCPositionTypeGrouped then
            emitter:setPositionType(kCCPositionTypeFree)
        elseif emitter:getPositionType() == kCCPositionTypeFree then
            emitter:setPositionType(kCCPositionTypeRelative)
        elseif emitter:getPositionType() == kCCPositionTypeRelative then
            emitter:setPositionType(kCCPositionTypeGrouped)
		end
    end
end

local function setEmitterPosition()
    if emitter ~= nil then
		emitter:setPosition(s.width / 2, s.height / 2)
	end
end

local function update(dt)
	if emitter ~= nil then
		local str = "" .. emitter:getParticleCount()
--  	labelAtlas:setString("" .. str)
    end
end

local function baseLayer_onEnterOrExit(tag)
	local scheduler = CCDirector:sharedDirector():getScheduler()
	if tag == "enter" then
		baseLayer_entry = scheduler:scheduleScriptFunc(update, 0, false)
	elseif tag == "exit" then
		scheduler:unscheduleScriptEntry(baseLayer_entry)
	end
end

local function getBaseLayer()
	local layer = CCLayerColor:create(ccc4(127,127,127,255))

    emitter = nil

    titleLabel = CCLabelTTF:create("", "Arial", 28)
    layer:addChild(titleLabel, 100, 1000)
    titleLabel:setPosition(s.width / 2, s.height - 50)

    subtitleLabel = CCLabelTTF:create("", "Arial", 16)
    layer:addChild(subtitleLabel, 100)
    subtitleLabel:setPosition(s.width / 2, s.height - 80)


    local item1 = CCMenuItemImage:create(s_pPathB1, s_pPathB2)
    local item2 = CCMenuItemImage:create(s_pPathR1, s_pPathR2)
    local item3 = CCMenuItemImage:create(s_pPathF1, s_pPathF2)
	local item4 = CCMenuItemToggle:create(CCMenuItemFont:create("Free Movement"))
	item4:addSubItem(CCMenuItemFont:create("Relative Movement"))
	item4:addSubItem(CCMenuItemFont:create("Grouped Movement"))
	item1:registerScriptTapHandler(backCallback)
	item2:registerScriptTapHandler(restartCallback)
	item3:registerScriptTapHandler(nextCallback)
	item4:registerScriptTapHandler(toggleCallback)

    local menu = CCMenu:create()
	menu:addChild(item1)
	menu:addChild(item2)
	menu:addChild(item3)
	menu:addChild(item4)

    menu:setPosition(CCPointMake(0, 0))
    item1:setPosition(CCPointMake(s.width/2 - item2:getContentSize().width * 2, item2:getContentSize().height / 2))
    item2:setPosition(CCPointMake(s.width/2, item2:getContentSize().height / 2))
    item3:setPosition(CCPointMake(s.width/2 + item2:getContentSize().width * 2, item2:getContentSize().height / 2))
	item4:setPosition(ccp(0, 100))
    item4:setAnchorPoint(ccp(0, 0))

    layer:addChild(menu, 100)

    labelAtlas = CCLabelAtlas:create("0000", "fps_images.png", 12, 32, string.byte('.'))
    layer:addChild(labelAtlas, 100)
    labelAtlas:setPosition(ccp(s.width - 66, 50))

    -- moving background
    background = CCSprite:create(s_back3)
    layer:addChild(background, 5)
    background:setPosition(ccp(s.width / 2, s.height - 180))

    local move = CCMoveBy:create(4, ccp(300, 0))
    local move_back = move:reverse()
    local seq = CCSequence:createWithTwoActions(move, move_back)
    background:runAction(CCRepeatForever:create(seq))

	local function onTouchEnded(x, y)
		local pos = CCPointMake(0, 0)
		if background ~= nil then
			pos = background:convertToWorldSpace(CCPointMake(0, 0))
		end

		if emitter ~= nil then
			local newPos = ccpSub(CCPointMake(x, y), pos)
			emitter:setPosition(newPos.x, newPos.y)
		end
	end

    local function onTouch(eventType, x, y)
        if eventType == "began" then
            return true
        else
            return onTouchEnded(x, y)
        end
    end

	layer:setTouchEnabled(true)
    layer:registerScriptTouchHandler(onTouch)
	layer:registerScriptHandler(baseLayer_onEnterOrExit)

	return layer
end

---------------------------------
--  ParticleReorder
---------------------------------
local ParticleReorder_Order = nil
local ParticleReorder_entry = nil
local ParticleReorder_layer = nil

local function reorderParticles(dt)
	update(dt)

	for i = 0, 1 do
        local parent = ParticleReorder_layer:getChildByTag(1000 + i)
        local child1 = parent:getChildByTag(1)
        local child2 = parent:getChildByTag(2)
        local child3 = parent:getChildByTag(3)

        if math.mod(ParticleReorder_Order, 3) == 0 then
            parent:reorderChild(child1, 1)
            parent:reorderChild(child2, 2)
            parent:reorderChild(child3, 3)

        elseif math.mod(ParticleReorder_Order, 3) == 1 then
            parent:reorderChild(child1, 3)
            parent:reorderChild(child2, 1)
            parent:reorderChild(child3, 2)

        elseif math.mod(ParticleReorder_Order, 3) == 2 then
            parent:reorderChild(child1, 2)
            parent:reorderChild(child2, 3)
            parent:reorderChild(child3, 1)
		end
    end

    ParticleReorder_Order = ParticleReorder_Order + 1
end

local function ParticleReorder_onEnterOrExit(tag)
	local scheduler = CCDirector:sharedDirector():getScheduler()
	if tag == "enter" then
		ParticleReorder_entry = scheduler:scheduleScriptFunc(reorderParticles, 1.0, false)
	elseif tag == "exit" then
		scheduler:unscheduleScriptEntry(ParticleReorder_entry)
	end
end

local function ParticleReorder()
	ParticleReorder_layer = getBaseLayer()

	ParticleReorder_Order = 0
    ParticleReorder_layer:setColor(ccc3(0, 0, 0))
    ParticleReorder_layer:removeChild(background, true)
    background = nil

    local ignore = CCParticleSystemQuad:create("Particles/SmallSun.plist")
    local parent1 = CCNode:create()
    local parent2 = CCParticleBatchNode:createWithTexture(ignore:getTexture())
    ignore:unscheduleUpdate()

    for i = 0, 1 do
		local parent = nil
        if i == 0 then
			parent = parent1
		else
			parent = parent2
		end

        local emitter1 = CCParticleSystemQuad:create("Particles/SmallSun.plist")
        emitter1:setStartColor(ccc4f(1,0,0,1))
        emitter1:setBlendAdditive(false)
        local emitter2 = CCParticleSystemQuad:create("Particles/SmallSun.plist")
        emitter2:setStartColor(ccc4f(0,1,0,1))
        emitter2:setBlendAdditive(false)
        local emitter3 = CCParticleSystemQuad:create("Particles/SmallSun.plist")
        emitter3:setStartColor(ccc4f(0,0,1,1))
        emitter3:setBlendAdditive(false)

		local neg = nil
		if i == 0 then
			neg = 1
		else
			neg = -1
		end

        emitter1:setPosition(ccp( s.width / 2 - 30, s.height / 2 + 60 * neg))
        emitter2:setPosition(ccp( s.width / 2, s.height / 2 + 60 * neg))
        emitter3:setPosition(ccp( s.width / 2 + 30, s.height / 2 + 60 * neg))

        parent:addChild(emitter1, 0, 1)
        parent:addChild(emitter2, 0, 2)
        parent:addChild(emitter3, 0, 3)

        ParticleReorder_layer:addChild(parent, 10, 1000 + i)
    end

	ParticleReorder_layer:registerScriptHandler(ParticleReorder_onEnterOrExit)

	titleLabel:setString("Reordering particles")
	subtitleLabel:setString("Reordering particles with and without batches batches")
	return ParticleReorder_layer
end

---------------------------------
--  ParticleBatchHybrid
---------------------------------
local ParticleBatchHybrid_entry = nil
local ParticleBatchHybrid_parent1 = nil
local ParticleBatchHybrid_parent2 = nil

local function switchRender(dt)
	update(dt)

	local cond = (emitter:getBatchNode() ~= nil)
	emitter:removeFromParentAndCleanup(false)
	local str = "Particle: Using new parent: "
	local newParent = nil
	if cond == true then
		newParent = ParticleBatchHybrid_parent2
		str = str .. "CCNode"
	else
		newParent = ParticleBatchHybrid_parent1
		str = str .. "CCParticleBatchNode"
	end
	newParent:addChild(emitter)
	cclog(str)
end

local function ParticleBatchHybrid_onEnterOrExit(tag)
	local scheduler = CCDirector:sharedDirector():getScheduler()
	if tag == "enter" then
		ParticleBatchHybrid_entry = scheduler:scheduleScriptFunc(switchRender, 2.0, false)
	elseif tag == "exit" then
		scheduler:unscheduleScriptEntry(ParticleBatchHybrid_entry)
		--emitter:release()
	end
end

local function ParticleBatchHybrid()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    emitter = CCParticleSystemQuad:create("Particles/LavaFlow.plist")
	---- emitter:retain()
    local batch = CCParticleBatchNode:createWithTexture(emitter:getTexture())
    batch:addChild(emitter)
    layer:addChild(batch, 10)

	local node = CCNode:create()
	layer:addChild(node)
	ParticleBatchHybrid_parent1 = batch
	ParticleBatchHybrid_parent2 = node

	layer:registerScriptHandler(ParticleBatchHybrid_onEnterOrExit)

	titleLabel:setString("Paticle Batch")
	subtitleLabel:setString("Hybrid: batched and non batched every 2 seconds")
	return layer
end

---------------------------------
--  ParticleBatchMultipleEmitters
---------------------------------
local function ParticleBatchMultipleEmitters()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    local emitter1 = CCParticleSystemQuad:create("Particles/LavaFlow.plist")
    emitter1:setStartColor(ccc4f(1,0,0,1))
    local emitter2 = CCParticleSystemQuad:create("Particles/LavaFlow.plist")
    emitter2:setStartColor(ccc4f(0,1,0,1))
    local emitter3 = CCParticleSystemQuad:create("Particles/LavaFlow.plist")
    emitter3:setStartColor(ccc4f(0,0,1,1))

    emitter1:setPosition(ccp(s.width / 1.25, s.height / 1.25))
    emitter2:setPosition(ccp(s.width / 2, s.height / 2))
    emitter3:setPosition(ccp(s.width / 4, s.height / 4))

    local batch = CCParticleBatchNode:createWithTexture(emitter1:getTexture())

    batch:addChild(emitter1, 0)
    batch:addChild(emitter2, 0)
    batch:addChild(emitter3, 0)

    layer:addChild(batch, 10)

	titleLabel:setString("Paticle Batch")
	subtitleLabel:setString("Multiple emitters. One Batch")
	return layer
end

---------------------------------
--  DemoFlower
---------------------------------
local function DemoFlower()
	local layer = getBaseLayer()

	emitter = CCParticleFlower:create()
	-- emitter:retain()
    background:addChild(emitter, 10)
    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_stars1))

    setEmitterPosition()

	titleLabel:setString("ParticleFlower")
	return layer
end

---------------------------------
--  DemoGalaxy
---------------------------------
local function DemoGalaxy()
	local layer = getBaseLayer()

	emitter = CCParticleGalaxy:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    setEmitterPosition()

	titleLabel:setString("ParticleGalaxy")
	return layer
end

---------------------------------
--  DemoFirework
---------------------------------
local function DemoFirework()
	local layer = getBaseLayer()

	emitter = CCParticleFireworks:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_stars1))

    setEmitterPosition()

	titleLabel:setString("ParticleFireworks")
	return layer
end

---------------------------------
--  DemoSpiral
---------------------------------
local function DemoSpiral()
	local layer = getBaseLayer()

	emitter = CCParticleSpiral:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    setEmitterPosition()

	titleLabel:setString("ParticleSpiral")
	return layer
end

---------------------------------
--  DemoSun
---------------------------------
local function DemoSun()
	local layer = getBaseLayer()

	emitter = CCParticleSun:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    setEmitterPosition()

	titleLabel:setString("ParticleSun")
	return layer
end

---------------------------------
--  DemoMeteor
---------------------------------
local function DemoMeteor()
	local layer = getBaseLayer()

	emitter = CCParticleMeteor:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    setEmitterPosition()

	titleLabel:setString("ParticleMeteor")
	return layer
end

---------------------------------
--  DemoFire
---------------------------------
local function DemoFire()
	local layer = getBaseLayer()

	emitter = CCParticleFire:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))
    local pos_x, pos_y = emitter:getPosition()
    emitter:setPosition(pos_x, 100)

	titleLabel:setString("ParticleFire")
	return layer
end

---------------------------------
--  DemoSmoke
---------------------------------
local function DemoSmoke()
	local layer = getBaseLayer()

	emitter = CCParticleSmoke:create()
    -- emitter:retain()
    background:addChild(emitter, 10)
    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    local pos_x, pos_y = emitter:getPosition()
    emitter:setPosition(pos_x, 100)

    setEmitterPosition()

	titleLabel:setString("ParticleSmoke")
	return layer
end

---------------------------------
--  DemoExplosion
---------------------------------
local function DemoExplosion()
	local layer = getBaseLayer()

	emitter = CCParticleExplosion:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_stars1))

    emitter:setAutoRemoveOnFinish(true)

    setEmitterPosition()

	titleLabel:setString("ParticleExplosion")
	return layer
end

---------------------------------
--  DemoSnow
---------------------------------
local function DemoSnow()
	local layer = getBaseLayer()

	emitter = CCParticleSnow:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    local pos_x, pos_y = emitter:getPosition()
    emitter:setPosition(pos_x, pos_y - 110)
    emitter:setLife(3)
    emitter:setLifeVar(1)

    -- gravity
    emitter:setGravity(CCPointMake(0, -10))

    -- speed of particles
    emitter:setSpeed(130)
    emitter:setSpeedVar(30)

    local startColor = emitter:getStartColor()
    startColor.r = 0.9
    startColor.g = 0.9
    startColor.b = 0.9
    emitter:setStartColor(startColor)

    local startColorVar = emitter:getStartColorVar()
    startColorVar.b = 0.1
    emitter:setStartColorVar(startColorVar)

    emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife())

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_snow))

    setEmitterPosition()

	titleLabel:setString("ParticleSnow")
	return layer
end

---------------------------------
--  DemoRain
---------------------------------
local function DemoRain()
	local layer = getBaseLayer()

	emitter = CCParticleRain:create()
    -- emitter:retain()
    background:addChild(emitter, 10)

    local pos_x, pos_y = emitter:getPosition()
    emitter:setPosition(pos_x, pos_y - 100)
    emitter:setLife(4)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    setEmitterPosition()

	titleLabel:setString("ParticleRain")
	return layer
end

---------------------------------
--  DemoBigFlower
---------------------------------
local function DemoBigFlower()
	local layer = getBaseLayer()

	emitter = CCParticleSystemQuad:new()
    emitter:initWithTotalParticles(50)
    emitter:autorelease()

    background:addChild(emitter, 10)
    ----emitter:release()    -- win32 :  use this line or remove this line and use autorelease()
    emitter:setTexture( CCTextureCache:sharedTextureCache():addImage(s_stars1) )
    emitter:setDuration(-1)

    -- gravity
    emitter:setGravity(CCPointMake(0, 0))

    -- angle
    emitter:setAngle(90)
    emitter:setAngleVar(360)

    -- speed of particles
    emitter:setSpeed(160)
    emitter:setSpeedVar(20)

    -- radial
    emitter:setRadialAccel(-120)
    emitter:setRadialAccelVar(0)

    -- tagential
    emitter:setTangentialAccel(30)
    emitter:setTangentialAccelVar(0)

    -- emitter position
    emitter:setPosition(160, 240)
    emitter:setPosVar(ccp(0, 0))

    -- life of particles
    emitter:setLife(4)
    emitter:setLifeVar(1)

    -- spin of particles
    emitter:setStartSpin(0)
    emitter:setStartSizeVar(0)
    emitter:setEndSpin(0)
    emitter:setEndSpinVar(0)

    -- color of particles
    emitter:setStartColor(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setStartColorVar(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setEndColor(ccc4f(0.1, 0.1, 0.1, 0.2))
    emitter:setEndColorVar(ccc4f(0.1, 0.1, 0.1, 0.2))

    -- size, in pixels
    emitter:setStartSize(80.0)
    emitter:setStartSizeVar(40.0)
    emitter:setEndSize(kParticleStartSizeEqualToEndSize)

    -- emits per second
    emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife())

    -- additive
    emitter:setBlendAdditive(true)

    setEmitterPosition()

	titleLabel:setString("ParticleBigFlower")
	return layer
end

---------------------------------
--  DemoRotFlower
---------------------------------
local function DemoRotFlower()
	local layer = getBaseLayer()

	emitter = CCParticleSystemQuad:new()
    emitter:initWithTotalParticles(300)
    emitter:autorelease()

    background:addChild(emitter, 10)
    ----emitter:release()    -- win32 : Remove this line
    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_stars2))

    -- duration
    emitter:setDuration(-1)

    -- gravity
    emitter:setGravity(ccp(0, 0))

    -- angle
    emitter:setAngle(90)
    emitter:setAngleVar(360)

    -- speed of particles
    emitter:setSpeed(160)
    emitter:setSpeedVar(20)

    -- radial
    emitter:setRadialAccel(-120)
    emitter:setRadialAccelVar(0)

    -- tagential
    emitter:setTangentialAccel(30)
    emitter:setTangentialAccelVar(0)

    -- emitter position
    emitter:setPosition(160, 240)
    emitter:setPosVar(ccp(0, 0))

    -- life of particles
    emitter:setLife(3)
    emitter:setLifeVar(1)

    -- spin of particles
    emitter:setStartSpin(0)
    emitter:setStartSpinVar(0)
    emitter:setEndSpin(0)
    emitter:setEndSpinVar(2000)

    -- color of particles
	emitter:setStartColor(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setStartColorVar(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setEndColor(ccc4f(0.1, 0.1, 0.1, 0.2))
    emitter:setEndColorVar(ccc4f(0.1, 0.1, 0.1, 0.2))

    -- size, in pixels
    emitter:setStartSize(30.0)
    emitter:setStartSizeVar(0)
    emitter:setEndSize(kParticleStartSizeEqualToEndSize)

    -- emits per second
    emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife())

    -- additive
    emitter:setBlendAdditive(false)

    setEmitterPosition()

	titleLabel:setString("ParticleRotFlower")
	return layer
end

---------------------------------
--  DemoModernArt
---------------------------------
local function DemoModernArt()
	local layer = getBaseLayer()

	emitter = CCParticleSystemQuad:new()
    emitter:initWithTotalParticles(1000)
    emitter:autorelease()

    background:addChild(emitter, 10)
    ----emitter:release()

    -- duration
    emitter:setDuration(-1)

    -- gravity
    emitter:setGravity(CCPointMake(0,0))

    -- angle
    emitter:setAngle(0)
    emitter:setAngleVar(360)

    -- radial
    emitter:setRadialAccel(70)
    emitter:setRadialAccelVar(10)

    -- tagential
    emitter:setTangentialAccel(80)
    emitter:setTangentialAccelVar(0)

    -- speed of particles
    emitter:setSpeed(50)
    emitter:setSpeedVar(10)

    -- emitter position
    emitter:setPosition(s.width / 2, s.height / 2)
    emitter:setPosVar(ccp(0, 0))

    -- life of particles
    emitter:setLife(2.0)
    emitter:setLifeVar(0.3)

    -- emits per frame
    emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife())

    -- color of particles
	emitter:setStartColor(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setStartColorVar(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setEndColor(ccc4f(0.1, 0.1, 0.1, 0.2))
    emitter:setEndColorVar(ccc4f(0.1, 0.1, 0.1, 0.2))

    -- size, in pixels
    emitter:setStartSize(1.0)
    emitter:setStartSizeVar(1.0)
    emitter:setEndSize(32.0)
    emitter:setEndSizeVar(8.0)

    -- texture
    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    -- additive
    emitter:setBlendAdditive(false)

    setEmitterPosition()

	titleLabel:setString("Varying size")
	return layer
end

---------------------------------
--  DemoRing
---------------------------------
local function DemoRing()
	local layer = getBaseLayer()

	emitter = CCParticleFlower:create()
    -- emitter:retain()

    background:addChild(emitter, 10)

    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_stars1))
    emitter:setLifeVar(0)
    emitter:setLife(10)
    emitter:setSpeed(100)
    emitter:setSpeedVar(0)
    emitter:setEmissionRate(10000)

    setEmitterPosition()

	titleLabel:setString("Ring Demo")
	return layer
end

---------------------------------
--  ParallaxParticle
---------------------------------
local function ParallaxParticle()
	local layer = getBaseLayer()

	background:getParent():removeChild(background, true)
    background = nil

    local p = CCParallaxNode:create()
    layer:addChild(p, 5)

    local p1 = CCSprite:create(s_back3)
    local p2 = CCSprite:create(s_back3)

    p:addChild(p1, 1, CCPointMake(0.5, 1), CCPointMake(0, 250))
    p:addChild(p2, 2, CCPointMake(1.5, 1), CCPointMake(0, 50))

    emitter = CCParticleFlower:create()
    -- emitter:retain()
    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    p1:addChild(emitter, 10)
    emitter:setPosition(250, 200)

    local par = CCParticleSun:create()
    p2:addChild(par, 10)
    par:setTexture(CCTextureCache:sharedTextureCache():addImage(s_fire))

    local move = CCMoveBy:create(4, CCPointMake(300,0))
    local move_back = move:reverse()
    local seq = CCSequence:createWithTwoActions(move, move_back)
    p:runAction(CCRepeatForever:create(seq))

	titleLabel:setString("Parallax + Particles")
	return layer
end

---------------------------------
--  DemoParticleFromFile
---------------------------------
local function DemoParticleFromFile(name)
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    emitter = CCParticleSystemQuad:new()
	emitter:autorelease()
    local filename = "Particles/" .. name .. ".plist"
    emitter:initWithFile(filename)
    layer:addChild(emitter, 10)

    setEmitterPosition()

	titleLabel:setString(name)
	return layer
end

---------------------------------
--  RadiusMode1
---------------------------------
local function RadiusMode1()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    emitter = CCParticleSystemQuad:new()
    emitter:initWithTotalParticles(200)
    layer:addChild(emitter, 10)
    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage("Images/stars-grayscale.png"))

    -- duration
    emitter:setDuration(kCCParticleDurationInfinity)

    -- radius mode
    emitter:setEmitterMode(kCCParticleModeRadius)

    -- radius mode: start and end radius in pixels
    emitter:setStartRadius(0)
    emitter:setStartRadiusVar(0)
    emitter:setEndRadius(160)
    emitter:setEndRadiusVar(0)

    -- radius mode: degrees per second
    emitter:setRotatePerSecond(180)
    emitter:setRotatePerSecondVar(0)


    -- angle
    emitter:setAngle(90)
    emitter:setAngleVar(0)

    -- emitter position
    emitter:setPosition(s.width / 2, s.height / 2)
    emitter:setPosVar(ccp(0, 0))

    -- life of particles
    emitter:setLife(5)
    emitter:setLifeVar(0)

    -- spin of particles
    emitter:setStartSpin(0)
    emitter:setStartSpinVar(0)
    emitter:setEndSpin(0)
    emitter:setEndSpinVar(0)

    -- color of particles
    emitter:setStartColor(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setStartColorVar(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setEndColor(ccc4f(0.1, 0.1, 0.1, 0.2))
    emitter:setEndColorVar(ccc4f(0.1, 0.1, 0.1, 0.2))

    -- size, in pixels
    emitter:setStartSize(32)
    emitter:setStartSizeVar(0)
    emitter:setEndSize(kCCParticleStartSizeEqualToEndSize)

    -- emits per second
    emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife())

    -- additive
    emitter:setBlendAdditive(false)

	titleLabel:setString("Radius Mode: Spiral")
	return layer
end

---------------------------------
--  RadiusMode2
---------------------------------
local function RadiusMode2()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    emitter = CCParticleSystemQuad:new()
    emitter:initWithTotalParticles(200)
    layer:addChild(emitter, 10)
    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage("Images/stars-grayscale.png"))

    -- duration
    emitter:setDuration(kCCParticleDurationInfinity)

    -- radius mode
    emitter:setEmitterMode(kCCParticleModeRadius)

    -- radius mode: start and end radius in pixels
    emitter:setStartRadius(100)
    emitter:setStartRadiusVar(0)
    emitter:setEndRadius(kCCParticleStartRadiusEqualToEndRadius)
    emitter:setEndRadiusVar(0)

    -- radius mode: degrees per second
    emitter:setRotatePerSecond(45)
    emitter:setRotatePerSecondVar(0)

    -- angle
    emitter:setAngle(90)
    emitter:setAngleVar(0)

    -- emitter position
    emitter:setPosition(s.width / 2, s.height / 2)
    emitter:setPosVar(ccp(0, 0))

    -- life of particles
    emitter:setLife(4)
    emitter:setLifeVar(0)

    -- spin of particles
    emitter:setStartSpin(0)
    emitter:setStartSpinVar(0)
    emitter:setEndSpin(0)
    emitter:setEndSpinVar(0)

    -- color of particles
    emitter:setStartColor(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setStartColorVar(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setEndColor(ccc4f(0.1, 0.1, 0.1, 0.2))
    emitter:setEndColorVar(ccc4f(0.1, 0.1, 0.1, 0.2))

    -- size, in pixels
    emitter:setStartSize(32)
    emitter:setStartSizeVar(0)
    emitter:setEndSize(kCCParticleStartSizeEqualToEndSize)

    -- emits per second
    emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife())

    -- additive
    emitter:setBlendAdditive(false)

	titleLabel:setString("Radius Mode: Semi Circle")
	return layer
end

---------------------------------
--  Issue704
---------------------------------
local function Issue704()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    emitter = CCParticleSystemQuad:new()
    emitter:initWithTotalParticles(100)
    layer:addChild(emitter, 10)
    emitter:setTexture(CCTextureCache:sharedTextureCache():addImage("Images/fire.png"))

    -- duration
    emitter:setDuration(kCCParticleDurationInfinity)

    -- radius mode
    emitter:setEmitterMode(kCCParticleModeRadius)

    -- radius mode: start and end radius in pixels
    emitter:setStartRadius(50)
    emitter:setStartRadiusVar(0)
    emitter:setEndRadius(kCCParticleStartRadiusEqualToEndRadius)
    emitter:setEndRadiusVar(0)

    -- radius mode: degrees per second
    emitter:setRotatePerSecond(0)
    emitter:setRotatePerSecondVar(0)


    -- angle
    emitter:setAngle(90)
    emitter:setAngleVar(0)

    -- emitter position
    emitter:setPosition(s.width / 2, s.height / 2)
    emitter:setPosVar(ccp(0, 0))

    -- life of particles
    emitter:setLife(5)
    emitter:setLifeVar(0)

    -- spin of particles
    emitter:setStartSpin(0)
    emitter:setStartSpinVar(0)
    emitter:setEndSpin(0)
    emitter:setEndSpinVar(0)

    -- color of particles
    emitter:setStartColor(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setStartColorVar(ccc4f(0.5, 0.5, 0.5, 1.0))
    emitter:setEndColor(ccc4f(0.1, 0.1, 0.1, 0.2))
    emitter:setEndColorVar(ccc4f(0.1, 0.1, 0.1, 0.2))

    -- size, in pixels
    emitter:setStartSize(16)
    emitter:setStartSizeVar(0)
    emitter:setEndSize(kCCParticleStartSizeEqualToEndSize)

    -- emits per second
    emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife())

    -- additive
    emitter:setBlendAdditive(false)

    local rot = CCRotateBy:create(16, 360)
    emitter:runAction(CCRepeatForever:create(rot))

	titleLabel:setString("Issue 704. Free + Rot")
	subtitleLabel:setString("Emitted particles should not rotate")
	return layer
end

---------------------------------
--  Issue870
---------------------------------
local Issue870_index = nil
local Issue870_entry = nil

local function updateQuads(dt)
	update(dt)

	Issue870_index = math.mod(Issue870_index + 1, 4)
    local rect = CCRectMake(Issue870_index * 32, 0, 32, 32)
    emitter:setTextureWithRect(emitter:getTexture(), rect)
end

local function Issue870_onEnterOrExit(tag)
	local scheduler = CCDirector:sharedDirector():getScheduler()
	if tag == "enter" then
		Issue870_entry = scheduler:scheduleScriptFunc(updateQuads, 2.0, false)
	elseif tag == "exit" then
		scheduler:unscheduleScriptEntry(Issue870_entry)
	end
end

local function Issue870()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    local system = CCParticleSystemQuad:new()
    system:initWithFile("Particles/SpinningPeas.plist")
    system:setTextureWithRect(CCTextureCache:sharedTextureCache():addImage("Images/particles.png"), CCRectMake(0,0,32,32))
    layer:addChild(system, 10)
    emitter = system

    Issue870_index = 0
	layer:registerScriptHandler(Issue870_onEnterOrExit)

	titleLabel:setString("Issue 870. SubRect")
	subtitleLabel:setString("Every 2 seconds the particle should change")
	return layer
end

---------------------------------
--  MultipleParticleSystems
---------------------------------
local function MultipleParticleSystems()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    CCTextureCache:sharedTextureCache():addImage("Images/particles.png")

    for i = 0, 4 do
        local particleSystem = CCParticleSystemQuad:create("Particles/SpinningPeas.plist")
        particleSystem:setPosition(i * 50, i * 50)
        particleSystem:setPositionType(kCCPositionTypeGrouped)
        layer:addChild(particleSystem)
    end

    emitter = nil

	titleLabel:setString("Multiple particle systems")
	subtitleLabel:setString("v1.1 test: FPS should be lower than next test")
	return layer
end

---------------------------------
--  MultipleParticleSystemsBatched
---------------------------------
local function MultipleParticleSystemsBatched()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    local batchNode = CCParticleBatchNode:createWithTexture(nil, 3000)
    layer:addChild(batchNode, 1, 2)

    for i = 0, 4 do
        local particleSystem = CCParticleSystemQuad:create("Particles/SpinningPeas.plist")
        particleSystem:setPositionType(kCCPositionTypeGrouped)
        particleSystem:setPosition(i * 50, i * 50)
        batchNode:setTexture(particleSystem:getTexture())
        batchNode:addChild(particleSystem)
    end

    emitter = nil

	titleLabel:setString("Multiple particle systems batched")
	subtitleLabel:setString("v1.1 test: should perform better than previous test")
	return layer
end

---------------------------------
--  AddAndDeleteParticleSystems
---------------------------------
local AddAndDeleteParticleSystems_entry = nil
local AddAndDeleteParticleSystems_batchNode = nil

local function removeSystem(dt)
	update(dt)

	local ChildrenCount = AddAndDeleteParticleSystems_batchNode:getChildren():count()
    if ChildrenCount > 0 then
        cclog("remove random system")
        local rand = math.mod(math.random(1, 999999), ChildrenCount - 1)
        AddAndDeleteParticleSystems_batchNode:removeChild(AddAndDeleteParticleSystems_batchNode:getChildren():objectAtIndex(rand), true)

		--add new
        local particleSystem = CCParticleSystemQuad:create("Particles/Spiral.plist")
        particleSystem:setPositionType(kCCPositionTypeGrouped)
        particleSystem:setTotalParticles(200)

        particleSystem:setPosition(math.mod(math.random(1, 999999), 300) ,math.mod(math.random(1, 999999), 400))

        cclog("add a new system")
		local randZ = math.floor(math.random() * 100)
        AddAndDeleteParticleSystems_batchNode:addChild(particleSystem, randZ, -1)
    end
end

local function AddAndDeleteParticleSystems_onEnterOrExit(tag)
	local scheduler = CCDirector:sharedDirector():getScheduler()
	if tag == "enter" then
		AddAndDeleteParticleSystems_entry = scheduler:scheduleScriptFunc(removeSystem, 2.0, false)
	elseif tag == "exit" then
		scheduler:unscheduleScriptEntry(AddAndDeleteParticleSystems_entry)
	end
end

local function AddAndDeleteParticleSystems()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    --adds the texture inside the plist to the texture cache
    AddAndDeleteParticleSystems_batchNode = CCParticleBatchNode:createWithTexture(nil, 16000)

    layer:addChild(AddAndDeleteParticleSystems_batchNode, 1, 2)

    for i = 0, 5 do
        local particleSystem = CCParticleSystemQuad:create("Particles/Spiral.plist")
        AddAndDeleteParticleSystems_batchNode:setTexture(particleSystem:getTexture())

        particleSystem:setPositionType(kCCPositionTypeGrouped)
        particleSystem:setTotalParticles(200)

        particleSystem:setPosition(i * 15 + 100, i * 15 + 100)

        local randZ = math.floor(math.random() * 100)
        AddAndDeleteParticleSystems_batchNode:addChild(particleSystem, randZ, -1)
	end

    layer:registerScriptHandler(AddAndDeleteParticleSystems_onEnterOrExit)
    emitter = nil

	titleLabel:setString("Add and remove Particle System")
	subtitleLabel:setString("v1.1 test: every 2 sec 1 system disappear, 1 appears")
	return layer
end

---------------------------------
--  ReorderParticleSystems *
--    problem
---------------------------------
local ReorderParticleSystems_entry = nil
local ReorderParticleSystems_batchNode = nil

local function reorderSystem(dt)
	update(dt)

	local child = ReorderParticleSystems_batchNode:getChildren():randomObject()
	-- problem: there's no getZOrder() for CCObject
	-- ReorderParticleSystems_batchNode:reorderChild(child, child:getZOrder() - 1)
	ReorderParticleSystems_batchNode:reorderChild(child, math.random(0, 99999))
end

local function ReorderParticleSystems_onEnterOrExit(tag)
	local scheduler = CCDirector:sharedDirector():getScheduler()
	if tag == "enter" then
		ReorderParticleSystems_entry = scheduler:scheduleScriptFunc(reorderSystem, 2.0, false)
	elseif tag == "exit" then
		scheduler:unscheduleScriptEntry(ReorderParticleSystems_entry)
	end
end

local function ReorderParticleSystems()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background ,true)
    background = nil

    ReorderParticleSystems_batchNode = CCParticleBatchNode:create("Images/stars-grayscale.png", 3000)

    layer:addChild(ReorderParticleSystems_batchNode, 1, 2)

    for i = 0, 2 do
        local particleSystem = CCParticleSystemQuad:new()
        particleSystem:initWithTotalParticles(200)
        particleSystem:setTexture(ReorderParticleSystems_batchNode:getTexture())

        -- duration
        particleSystem:setDuration(kCCParticleDurationInfinity)

        -- radius mode
        particleSystem:setEmitterMode(kCCParticleModeRadius)

        -- radius mode: 100 pixels from center
        particleSystem:setStartRadius(100)
        particleSystem:setStartRadiusVar(0)
        particleSystem:setEndRadius(kCCParticleStartRadiusEqualToEndRadius)
        particleSystem:setEndRadiusVar(0)    -- not used when start == end

        -- radius mode: degrees per second
        -- 45 * 4 seconds of life = 180 degrees
        particleSystem:setRotatePerSecond(45)
        particleSystem:setRotatePerSecondVar(0)


        -- angle
        particleSystem:setAngle(90)
        particleSystem:setAngleVar(0)

        -- emitter position
        particleSystem:setPosVar(ccp(0, 0))

        -- life of particles
        particleSystem:setLife(4)
        particleSystem:setLifeVar(0)

        -- spin of particles
        particleSystem:setStartSpin(0)
        particleSystem:setStartSpinVar(0)
        particleSystem:setEndSpin(0)
        particleSystem:setEndSpinVar(0)

        -- color of particles
		local startColor = ccColor4F:new()
		startColor.r = 0
		startColor.g = 0
		startColor.b = 0
		startColor.a = 1
		if i == 0 then startColor.r = 1
		elseif i == 1 then startColor.g = 1
		elseif i == 2 then startColor.b = 1
		end

        particleSystem:setStartColor(startColor)
        particleSystem:setStartColorVar(ccc4f(0, 0, 0, 0))

		local endColor = startColor
        particleSystem:setEndColor(endColor)
        particleSystem:setEndColorVar(ccc4f(0, 0, 0, 0))

        -- size, in pixels
        particleSystem:setStartSize(32)
        particleSystem:setStartSizeVar(0)
        particleSystem:setEndSize(kCCParticleStartSizeEqualToEndSize)

        -- emits per second
        particleSystem:setEmissionRate(particleSystem:getTotalParticles() / particleSystem:getLife())

        -- additive
        particleSystem:setPosition(i * 10 + 120, 200)

        ReorderParticleSystems_batchNode:addChild(particleSystem)
        particleSystem:setPositionType(kCCPositionTypeFree)

        particleSystem:release()
    end

    layer:registerScriptHandler(ReorderParticleSystems_onEnterOrExit)
    emitter = nil

	titleLabel:setString("reorder systems")
	subtitleLabel:setString("changes every 2 seconds")
	return layer
end

---------------------------------
--  PremultipliedAlphaTest
---------------------------------
local function PremultipliedAlphaTest()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 255))
    layer:removeChild(background, true)
    background = nil

    emitter = CCParticleSystemQuad:create("Particles/BoilingFoam.plist")

    local tBlendFunc = ccBlendFunc:new()
	tBlendFunc.src = 1 --GL_ONE
	tBlendFunc.dst = 0x0303 --GL_ONE_MINUS_SRC_ALPHA
    emitter:setBlendFunc(tBlendFunc)

    --assert(emitter:getOpacityModifyRGB(), "Particle texture does not have premultiplied alpha, test is useless")

    emitter:setStartColor(ccc4f(1, 1, 1, 1))
    emitter:setEndColor(ccc4f(1, 1, 1, 0))
    emitter:setStartColorVar(ccc4f(0, 0, 0, 0))
    emitter:setEndColorVar(ccc4f(0, 0, 0, 0))

    layer:addChild(emitter, 10)

	titleLabel:setString("premultiplied alpha")
	subtitleLabel:setString("no black halo, particles should fade out")
	return layer
end

---------------------------------
--  PremultipliedAlphaTest2
---------------------------------
local function PremultipliedAlphaTest2()
	local layer = getBaseLayer()

	layer:setColor(ccc3(0, 0, 0))
    layer:removeChild(background, true)
    background = nil

    emitter = CCParticleSystemQuad:create("Particles/TestPremultipliedAlpha.plist")
    layer:addChild(emitter ,10)

	titleLabel:setString("premultiplied alpha 2")
	subtitleLabel:setString("Arrows should be faded")
	return layer
end

---------------------------------
--  Particle Test
---------------------------------
function CreateParticleLayer()
	if SceneIdx == 0 then return ParticleReorder()
	elseif SceneIdx == 1  then return ParticleBatchHybrid()
	elseif SceneIdx == 2  then return ParticleBatchMultipleEmitters()
	elseif SceneIdx == 3  then return DemoFlower()
	elseif SceneIdx == 4  then return DemoGalaxy()
	elseif SceneIdx == 5  then return DemoFirework()
	elseif SceneIdx == 6  then return DemoSpiral()
	elseif SceneIdx == 7  then return DemoSun()
	elseif SceneIdx == 8  then return DemoMeteor()
	elseif SceneIdx == 9  then return DemoFire()
	elseif SceneIdx == 10 then return DemoSmoke()
	elseif SceneIdx == 11 then return DemoExplosion()
	elseif SceneIdx == 12 then return DemoSnow()
	elseif SceneIdx == 13 then return DemoRain()
	elseif SceneIdx == 14 then return DemoBigFlower()
	elseif SceneIdx == 15 then return DemoRotFlower()
	elseif SceneIdx == 16 then return DemoModernArt()
	elseif SceneIdx == 17 then return DemoRing()
	elseif SceneIdx == 18 then return ParallaxParticle()
	elseif SceneIdx == 19 then return DemoParticleFromFile("BoilingFoam")
	elseif SceneIdx == 20 then return DemoParticleFromFile("BurstPipe")
	elseif SceneIdx == 21 then return DemoParticleFromFile("Comet")
	elseif SceneIdx == 22 then return DemoParticleFromFile("debian")
	elseif SceneIdx == 23 then return DemoParticleFromFile("ExplodingRing")
	elseif SceneIdx == 24 then return DemoParticleFromFile("LavaFlow")
	elseif SceneIdx == 25 then return DemoParticleFromFile("SpinningPeas")
	elseif SceneIdx == 26 then return DemoParticleFromFile("SpookyPeas")
	elseif SceneIdx == 27 then return DemoParticleFromFile("Upsidedown")
	elseif SceneIdx == 28 then return DemoParticleFromFile("Flower")
	elseif SceneIdx == 29 then return DemoParticleFromFile("Spiral")
	elseif SceneIdx == 30 then return DemoParticleFromFile("Galaxy")
	elseif SceneIdx == 31 then return DemoParticleFromFile("Phoenix")
    elseif SceneIdx == 32 then return DemoParticleFromFile("lines")
	elseif SceneIdx == 33 then return RadiusMode1()
	elseif SceneIdx == 34 then return RadiusMode2()
	elseif SceneIdx == 35 then return Issue704()
	elseif SceneIdx == 36 then return Issue870()
	--elseif SceneIdx == 36 then return Issue1201()
	-- v1.1 tests
	elseif SceneIdx == 37 then return MultipleParticleSystems()
	elseif SceneIdx == 38 then return MultipleParticleSystemsBatched()
	elseif SceneIdx == 39 then return AddAndDeleteParticleSystems()
	elseif SceneIdx == 40 then return ReorderParticleSystems()
	elseif SceneIdx == 41 then return PremultipliedAlphaTest()
	elseif SceneIdx == 42 then return PremultipliedAlphaTest2()
	end
end

function ParticleTest()
	cclog("ParticleTest")
	local scene = CCScene:create()

	SceneIdx = -1
	scene:addChild(nextAction())
	scene:addChild(CreateBackMenuItem())

	return scene
end
