1 /** 2 * The Render Engine 3 * BillboardComponent 4 * 5 * @fileoverview A render component which will render the contents of 6 * a generated image until the contents are updated. 7 * 8 * @author: Brett Fattori (brettf@renderengine.com) 9 * @author: $Author: bfattori $ 10 * @version: $Revision: 1556 $ 11 * 12 * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com) 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a copy 15 * of this software and associated documentation files (the "Software"), to deal 16 * in the Software without restriction, including without limitation the rights 17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 * copies of the Software, and to permit persons to whom the Software is 19 * furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be included in 22 * all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 * THE SOFTWARE. 31 * 32 */ 33 34 // The class this file defines and its required classes 35 R.Engine.define({ 36 "class":"R.components.render.Billboard2D", 37 "requires":[ 38 "R.components.Render", 39 "R.util.RenderUtil", 40 "R.text.AbstractTextRenderer", 41 "R.math.Point2D" 42 ] 43 }); 44 45 /** 46 * @class The billboard component renders the contents of an image which 47 * was generated by a linked render component. When the contents 48 * of the linked component are re-rendered, the contents of the 49 * image are updated. The best usage of this component is for infrequently 50 * changing vector drawn objects. For example: 51 * <pre> 52 * // Add component to draw the object 53 * this.add(R.components.Billboard2D.create("draw", R.components.Vector2D.create("vector"))); 54 * </pre> 55 * Accessing the <tt>R.components.Vector2D</tt> within the <tt>R.components.Billboard2D</tt> 56 * is as simple as calling {@link #getComponent}. If the contents of the linked 57 * component are updated, you will need to call {@link #regenerate} to recreate the 58 * billboard image. 59 * 60 * 61 * @param name {String} The name of the component 62 * @param renderComponent {R.components.Render} A render component to create the billboard from 63 * @param priority {Number} The priority of the component between 0.0 and 1.0 64 * @constructor 65 * @extends R.components.Render 66 * @description Creates a 2d billboard component. 67 */ 68 R.components.render.Billboard2D = function () { 69 "use strict"; 70 return R.components.Render.extend(/** @scope R.components.render.Billboard2D.prototype */{ 71 72 billboard:null, 73 mode:null, 74 renderComponent:null, 75 hostRect:null, 76 77 /** 78 * @private 79 */ 80 constructor:function (name, renderComponent, priority) { 81 Assert(renderComponent instanceof R.components.Render || 82 renderComponent instanceof R.text.AbstractTextRenderer, "Attempt to assign a non-render component to a billboard component"); 83 this.base(name, priority || 0.1); 84 this.mode = R.components.render.Billboard2D.REDRAW; 85 this.renderComponent = renderComponent; 86 87 }, 88 89 /** 90 * Destroy the object 91 */ 92 destroy:function () { 93 this.renderComponent.destroy(); 94 this.base(); 95 }, 96 97 /** 98 * Releases the component back into the object pool. See {@link R.engine.PooledObject#release} 99 * for more information. 100 */ 101 release:function () { 102 this.base(); 103 this.mode = null; 104 this.renderComponent = null; 105 }, 106 107 /** 108 * Deprecated in favor of {@link #setGameObject}. 109 * @deprecated 110 */ 111 setHostObject:function (hostObject) { 112 this.setGameObject(hostObject); 113 }, 114 115 /** 116 * Establishes the link between this component and its game object. 117 * When you assign components to a game object, it will call this method 118 * so that each component can refer to its game object, the same way 119 * a game object can refer to a component with {@link R.engine.GameObject#getComponent}. 120 * 121 * @param hostObject {R.engine.GameObject} The object which hosts this component 122 */ 123 setGameObject:function (gameObject) { 124 this.renderComponent.setGameObject(gameObject); 125 this.base(gameObject); 126 }, 127 128 /** 129 * Call this method when the linked render component has been updated 130 * to force the billboard to be redrawn. 131 */ 132 regenerate:function () { 133 this.mode = R.components.render.Billboard2D.REDRAW; 134 this.hostRect = null; 135 this.getGameObject().markDirty(); 136 }, 137 138 /** 139 * Get the linked render component. 140 * @return {R.components.Render} 141 */ 142 getComponent:function () { 143 return this.renderComponent; 144 }, 145 146 /** 147 * Draws the contents of the billboard to the render context. This 148 * component operates in one of two modes. When the contents of the 149 * subclassed component are redrawing, a temporary render context is created 150 * to which the component renders. The second mode is where the contents 151 * of the context from the first mode are rendered instead of performing 152 * all of the operations required to render the component. This component 153 * is only good if the contents don't change often. 154 * 155 * @param renderContext {R.rendercontexts.AbstractRenderContext} The rendering context 156 * @param time {Number} The engine time in milliseconds 157 * @param dt {Number} The delta between the world time and the last time the world was updated 158 * in milliseconds. 159 */ 160 execute:function (renderContext, time, dt) { 161 if (!this.base(renderContext, time, dt)) { 162 return; 163 } 164 165 // Get the host object's bounding box 166 var hostBox = this.getGameObject().getBoundingBox(); 167 var o = R.math.Point2D.create(this.getGameObject().getOrigin()); 168 169 if (this.mode == R.components.render.Billboard2D.REDRAW) { 170 // We'll match the type of context the component is rendering to 171 //var ctx = this.getGameObject().getRenderContext().constructor; 172 173 if (!this.billboard) { 174 // Due to pooling, we don't need to recreate this each time 175 this.billboard = $("<img/>"); 176 } 177 178 this.billboard.attr({ 179 "src":R.util.RenderUtil.renderComponentToImage(R.rendercontexts.CanvasContext, this.renderComponent, 180 hostBox.w, hostBox.h, null, o), 181 "width":hostBox.w, 182 "height":hostBox.h 183 }); 184 185 this.mode = R.components.render.Billboard2D.NORMAL; 186 } 187 188 // Render the billboard. If the bounding box's origin is negative in 189 // either X or Y, we'll need to move the transformation there before rendering the object 190 this.transformOrigin(renderContext, true); 191 try { 192 renderContext.drawImage(this.getGameObject().getBoundingBox(), this.billboard[0], this.getGameObject()); 193 } 194 catch (ex) { 195 // TODO: Find a better way to perform this operation since try/catch is SLOW 196 // It appears that Firefox might not have a full image rendered, so calling 197 // drawImage fails with a component exception. To abate this possible issue, 198 // we try the call and catch the failure... 199 } 200 201 /* pragma:DEBUG_START */ 202 // Debug the billboard image box 203 if (R.Engine.getDebugMode()) { 204 renderContext.setLineStyle("green"); 205 renderContext.drawRectangle(this.getGameObject().getBoundingBox(), this.getGameObject()); 206 } 207 /* pragma:DEBUG_END */ 208 209 this.transformOrigin(renderContext, false); 210 o.destroy(); 211 } 212 213 }, /** @scope R.components.render.Billboard2D.prototype */{ 214 215 /** 216 * Get the class name of this object 217 * 218 * @return {String} "R.components.render.Billboard2D" 219 */ 220 getClassName:function () { 221 return "R.components.render.Billboard2D"; 222 }, 223 224 /** 225 * The component will render to a temporary context from which the 226 * actual content will be rendered. 227 * @type {Number} 228 */ 229 REDRAW:0, 230 231 /** 232 * The component will render the contents of the billboard. 233 * @type {Number} 234 */ 235 NORMAL:1, 236 237 /** 238 * A temporary context to which all billboards will render their 239 * bitmaps. 240 * @private 241 */ 242 tempContext:null 243 244 }); 245 };