1 // TODO: RENDERING NEEDS CLEANING!! // 2 3 /** 4 * The Render Engine 5 * BitmapText 6 * 7 * @fileoverview A bitmap font renderer for render contexts that don't 8 * support fonts natively. 9 * 10 * @author: Brett Fattori (brettf@renderengine.com) 11 * @author: $Author: bfattori $ 12 * @version: $Revision: 1555 $ 13 * 14 * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com) 15 * 16 * Permission is hereby granted, free of charge, to any person obtaining a copy 17 * of this software and associated documentation files (the "Software"), to deal 18 * in the Software without restriction, including without limitation the rights 19 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 * copies of the Software, and to permit persons to whom the Software is 21 * furnished to do so, subject to the following conditions: 22 * 23 * The above copyright notice and this permission notice shall be included in 24 * all copies or substantial portions of the Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 * THE SOFTWARE. 33 * 34 */ 35 36 // The class this file defines and its required classes 37 R.Engine.define({ 38 "class":"R.text.BitmapText", 39 "requires":[ 40 "R.math.Math2D", 41 "R.util.RenderUtil", 42 "R.text.AbstractTextRenderer" 43 ] 44 }); 45 46 /** 47 * @class A text renderer which draws text from a bitmap font file. This type of text 48 * renderer is only supported by the {@link R.rendercontexts.CanvasContext}. For an {@link R.rendercontexts.HTMLElementContext} 49 * or a derivative, use the {@link R.text.ContextText} renderer. 50 * 51 * @constructor 52 * @param font {Font} A resource obtained by calling {@link FontResourceLoader#get} 53 * @extends R.text.AbstractTextRenderer 54 * @see R.resources.loaders.BitmapFontLoader 55 */ 56 R.text.BitmapText = function () { 57 return R.text.AbstractTextRenderer.extend(/** @scope R.text.BitmapText.prototype */{ 58 59 font:null, 60 spacing:0, 61 62 /** @private */ 63 constructor:function (font) { 64 this.base(); 65 this.font = font; 66 }, 67 68 /** 69 * Release the text renderer back into the pool for reuse 70 */ 71 release:function () { 72 this.base(); 73 this.font = null; 74 this.spacing = 0; 75 }, 76 77 /** 78 * Calculate the bounding box for the text and set it on the host object. 79 * @private 80 */ 81 calculateBoundingBox:function () { 82 var text = this.getText(), lCount = text.length, align = this.getTextAlignment(), 83 letter = (align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? text.length - 1 : 0), 84 kern = (align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? -this.font.info.kerning : this.font.info.kerning), 85 space = R.math.Point2D.create((align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? -this.font.info.space : this.font.info.space), 0), 86 cW, cH = this.font.info.height, cS = 0, y = 0, pc = R.math.Point2D.create(0, 0); 87 88 // Run the text to get its bounding box 89 var weight = this.getTextWeight(); 90 for (var wT = 0; wT < weight; wT++) { 91 92 pc.set(wT * 0.5, 0); 93 94 // 1st pass: The text 95 letter = (align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? text.length - 1 : 0); 96 lCount = text.length; 97 98 while (lCount-- > 0) { 99 var chr = text.charCodeAt(letter); 100 if (chr == 10) { 101 y += (cH * this.getSize()) + this.getLineSpacing(); 102 pc.set(0, y); 103 } 104 else { 105 var glyph = chr - 32; 106 if (glyph == 0) { 107 // A space 108 pc.add(space); 109 } 110 else { 111 // Draw the text 112 cS = this.font.info.letters[glyph - 1]; 113 cW = this.font.info.letters[glyph] - cS; 114 pc.add(R.math.Point2D.create(cW, 0).mul(kern)); 115 } 116 } 117 118 letter += (align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? -1 : 1); 119 } 120 } 121 122 // Set the bounding box 123 this.getGameObject().getBoundingBox().set(0, 0, pc.x * this.getSize(), cH * this.getSize()); 124 pc.destroy(); 125 }, 126 127 /** 128 * Set the scaling of the text 129 * @param size {Number} 130 */ 131 setSize:function (size) { 132 this.base(size); 133 this.generated = false; 134 this.calculateBoundingBox(); 135 }, 136 137 /** 138 * Set the text to render. 139 * 140 * @param text {String} The text to render 141 */ 142 setText:function (text) { 143 // If the font only supports uppercase letters 144 text = (this.font.upperCaseOnly ? String(text).toUpperCase() : text); 145 146 // Replace special chars 147 this.base(text); 148 this.generated = false; 149 this.calculateBoundingBox(); 150 }, 151 152 /** 153 * @private 154 */ 155 execute:function (renderContext, time, dt) { 156 157 if (this.getText().length == 0) { 158 return; 159 } 160 161 renderContext.pushTransform(); 162 renderContext.setScale(this.getSize()); 163 164 var text = this.getText(), lCount = text.length, align = this.getTextAlignment(), 165 letter = (align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? text.length - 1 : 0), 166 kern = (align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? -this.font.info.kerning : this.font.info.kerning), 167 space = R.math.Point2D.create((align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? -this.font.info.space : this.font.info.space), 0), 168 cW, cH = this.font.info.height, cS = 0, y = 0, lineCount = 1; 169 170 // Render the text 171 var weight = this.getTextWeight(); 172 for (var wT = 0; wT < weight; wT++) { 173 174 var pc = R.math.Point2D.create(wT * 0.5, 0); 175 176 // 1st pass: The text 177 letter = (align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? text.length - 1 : 0); 178 lCount = text.length; 179 180 if (renderContext.get2DContext) { 181 renderContext.get2DContext().globalCompositeOperation = "source-over"; 182 } 183 184 while (lCount-- > 0) { 185 var chr = text.charCodeAt(letter); 186 if (chr == 10) { 187 y += (cH * this.getSize()) + this.getLineSpacing(); 188 pc.set(0, y); 189 lineCount++; 190 } 191 else { 192 var glyph = chr - 32; 193 if (glyph == 0) { 194 // A space 195 pc.add(space); 196 } 197 else { 198 // Draw the text 199 cS = this.font.info.letters[glyph - 1]; 200 cW = this.font.info.letters[glyph] - cS; 201 var sRect = R.math.Rectangle2D.create(cS, 0, cW, cH); 202 var rect = R.math.Rectangle2D.create(pc.x, pc.y, cW, cH); 203 renderContext.drawImage(rect, this.font.image, sRect, this.getGameObject()); 204 pc.add(R.math.Point2D.create(cW, 0).mul(kern)); 205 } 206 } 207 208 letter += (align == R.text.AbstractTextRenderer.ALIGN_RIGHT ? -1 : 1); 209 } 210 } 211 212 // 2nd pass: The color 213 if (renderContext.get2DContext) { 214 renderContext.get2DContext().globalCompositeOperation = "source-atop"; 215 var r = R.math.Rectangle2D.create(0, 0, pc.x, cH * (lineCount + this.getLineSpacing())); 216 renderContext.setFillStyle(this.getColor()); 217 renderContext.drawFilledRectangle(r); 218 // Reset the composition operation 219 renderContext.get2DContext().globalCompositeOperation = "source-over"; 220 r.destroy(); 221 } 222 223 pc.destroy(); 224 space.destroy(); 225 226 renderContext.popTransform(); 227 } 228 }, /** @scope R.text.BitmapText.prototype */ { 229 /** 230 * Get the class name of this object 231 * @return {String} The string "R.text.BitmapText" 232 */ 233 getClassName:function () { 234 return "R.text.BitmapText"; 235 } 236 }); 237 238 };