1 /** 2 * The Render Engine 3 * AccumulatorParticleEngine 4 * 5 * @fileoverview An extension to the standard particle engine which accumulates and 6 * fades out particles for a more dramatic effect. 7 * 8 * @author: Brett Fattori (brettf@renderengine.com) 9 * 10 * @author: $Author: bfattori@gmail.com $ 11 * @version: $Revision: 1571 $ 12 * 13 * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com) 14 * 15 * Permission is hereby granted, free of charge, to any person obtaining a copy 16 * of this software and associated documentation files (the "Software"), to deal 17 * in the Software without restriction, including without limitation the rights 18 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 * copies of the Software, and to permit persons to whom the Software is 20 * furnished to do so, subject to the following conditions: 21 * 22 * The above copyright notice and this permission notice shall be included in 23 * all copies or substantial portions of the Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 * THE SOFTWARE. 32 * 33 */ 34 35 // The class this file defines and its required classes 36 R.Engine.define({ 37 "class":"R.particles.AccumulatorParticleEngine", 38 "requires":[ 39 "R.particles.ParticleEngine", 40 "R.struct.Container", 41 "R.rendercontexts.CanvasContext", 42 "R.util.RenderUtil" 43 ] 44 }); 45 46 /** 47 * @class An updated particle engine with an accumulator buffer so that 48 * effects such as bloom, glow, and tail can be achieved. A note 49 * of caution, using the accumulator particle engine <em>will be 50 * slower</em> compared with the basic particle engine. 51 * <p/> 52 * Because of the effect used by the accumulator particle engine, 53 * background imagery will be darkened slightly. 54 * 55 * @extends R.particles.ParticleEngine 56 * @constructor 57 * @description Create a particle engine 58 */ 59 R.particles.AccumulatorParticleEngine = function () { 60 return R.particles.ParticleEngine.extend(/** @scope R.particles.AccumulatorParticleEngine.prototype */{ 61 62 accumulator:null, // The accumulated frame 63 fadeRate:0, // The rate at which particles fade out 64 blur:false, 65 radius:1, 66 hasBackground:false, 67 68 /** @private */ 69 constructor:function (fadeRate) { 70 this.base("AccumulatorParticleEngine"); 71 this.accumulator = null; 72 this.fadeRate = fadeRate || 0.5; 73 this.blur = false; 74 this.radius = 1; 75 this.hasBackground = false; 76 }, 77 78 /** 79 * Destroy the particle engine 80 */ 81 destroy:function () { 82 this.accumulator.destroy(); 83 this.base(); 84 }, 85 86 /** 87 * Releases the particle engine back into the pool. 88 */ 89 release:function () { 90 this.base(); 91 this.accumulator = null; 92 this.fadeRate = 0; 93 this.blur = false; 94 this.radius = 1; 95 this.hasBackground = false; 96 }, 97 98 /** 99 * Set the rate at which the particles fade out 100 * @param fadeRate {Number} A value between 0 and 1 101 */ 102 setFadeRate:function (fadeRate) { 103 this.fadeRate = fadeRate; 104 this.accumulator = null; 105 }, 106 107 /** 108 * Enable blurring of the particles in the accumulator 109 * @param state {Boolean} <code>true</code> to enable (default: false) 110 */ 111 setBlur:function (state) { 112 this.blur = state; 113 }, 114 115 /** 116 * Set the blurring radius around the pixel. Higher numbers result in lower frame rates. 117 * @param radius {Number} The radius of the blur (default: 1) 118 */ 119 setBlurRadius:function (radius) { 120 this.radius = radius; 121 }, 122 123 /** 124 * Set this value to <code>true</code> if the particle engine is atop a background image. 125 * This will have the effect of slightly darkening the background image. If the background 126 * is solid black, you can set this to <code>false</code>. 127 * @param state {Boolean} The background state 128 */ 129 setBackgroundState:function (state) { 130 this.hasBackground = state; 131 }, 132 133 /** 134 * Clear the accumulator 135 */ 136 reset:function () { 137 if (this.accumulator) { 138 this.accumulator.reset(); 139 } 140 this.base(); 141 }, 142 143 /** 144 * Update the particles within the render context. 145 * 146 * @param renderContext {R.rendercontexts.AbstractRenderContext} The context the particles will be rendered within. 147 * @param time {Number} The global time within the engine. 148 * @param dt {Number} The delta between the world time and the last time the world was updated 149 * in milliseconds. 150 */ 151 update:function (renderContext, time, dt) { 152 if (R.Engine.options.disableParticleEngine) { 153 return; 154 } 155 156 // Is there an accumulator already? 157 if (!this.accumulator) { 158 // Create the accumulator buffer, at the size of the renderContext 159 this.accumulator = R.rendercontexts.CanvasContext.create("APEContext", 160 renderContext.getViewport().w, renderContext.getViewport().h); 161 } 162 163 if (!this.blur) { 164 // Fade the accumulator at a set rate 165 this.accumulator.get2DContext().globalAlpha = this.fadeRate; 166 this.accumulator.get2DContext().globalCompositeOperation = this.hasBackground ? "xor" : "source-atop"; 167 this.accumulator.setFillStyle("rgb(0,0,0)"); 168 this.accumulator.drawFilledRectangle(renderContext.getViewport()); 169 this.accumulator.get2DContext().globalCompositeOperation = "source-over"; 170 } else { 171 var vp = R.math.Rectangle2D.create(renderContext.getViewport()), 172 ox = vp.x, oy = vp.y; 173 this.accumulator.get2DContext().globalAlpha = 0.5; 174 for (var y = -this.radius; y <= this.radius; y++) { 175 for (var x = -this.radius; x <= this.radius; x++) { 176 vp.y = oy + y; 177 vp.x = ox + x; 178 this.accumulator.drawImage(vp, this.accumulator.getSurface()); 179 } 180 } 181 vp.destroy(); 182 } 183 184 this.accumulator.get2DContext().globalAlpha = 1.0; 185 186 // Render particles to the accumulator 187 this.base(this.accumulator, time, dt); 188 189 // Render the contents of the accumulator to the render context 190 renderContext.drawImage(renderContext.getViewport(), this.accumulator.getSurface()); 191 }, 192 193 /** 194 * Get the properties object for the particle engine 195 * @return {Object} 196 */ 197 getProperties:function () { 198 var self = this; 199 var prop = this.base(self); 200 return $.extend(prop, { 201 "FadeRate":[function () { 202 return self.fadeRate; 203 }, 204 null, false] 205 }); 206 } 207 208 209 }, /** @scope R.particles.AccumulatorParticleEngine.prototype */{ 210 /** 211 * Get the class name of this object 212 * 213 * @return {String} "R.particles.AccumulatorParticleEngine" 214 */ 215 getClassName:function () { 216 return "R.particles.AccumulatorParticleEngine"; 217 } 218 }); 219 };