1 /** 2 * The Render Engine 3 * RenderContext2D 4 * 5 * @fileoverview The base 2D render context. This context implements a number of 6 * methods which are then standard on all contexts which extend from 7 * it. 8 * 9 * @author: Brett Fattori (brettf@renderengine.com) 10 * @author: $Author: bfattori $ 11 * @version: $Revision: 1555 $ 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.rendercontexts.RenderContext2D", 38 "requires":[ 39 "R.rendercontexts.AbstractRenderContext", 40 "R.math.Math2D", 41 "R.struct.Container" 42 ] 43 }); 44 45 /** 46 * @class All 2D contexts should extend from this to inherit the 47 * methods which abstract the drawing methods. 48 * @extends R.rendercontexts.AbstractRenderContext 49 * @constructor 50 * @description Create a new instance of a 2d render context. 51 * @param name {String} The name of the context 52 * @param surface {HTMLElement} The element which represents the surface of the context 53 */ 54 R.rendercontexts.RenderContext2D = function () { 55 return R.rendercontexts.AbstractRenderContext.extend(/** @scope R.rendercontexts.RenderContext2D.prototype */{ 56 57 width:0, 58 height:0, 59 lineStyle:null, 60 fillStyle:null, 61 lineWidth:1, 62 position:null, 63 rotation:0, 64 scaleX:1, 65 scaleY:1, 66 wPosition:null, 67 wRotation:0, 68 wScale:null, 69 bBox:null, 70 backgroundColor:null, 71 font:null, 72 fontWeight:null, 73 fontSize:null, 74 fontAlign:null, 75 fontBaseline:null, 76 fontStyle:null, 77 zBins:null, 78 postRenderList:null, 79 _xformStack:null, 80 81 /** @private */ 82 constructor:function (name, surface) { 83 this.base(name || "RenderContext2D", surface); 84 this.wPosition = R.math.Point2D.create(0, 0); 85 this.wRotation = 0; 86 this.wScale = 1; 87 this.zBins = { 88 "0":{ 89 all:R.struct.Container.create(), 90 vis:[] 91 } 92 }; 93 this.zBins.activeBins = [0]; 94 this.postRenderList = []; 95 96 // Default font settings 97 this.font = "sans-serif"; 98 this.fontWeight = "normal"; 99 this.fontSize = "12px"; 100 this.fontAlign = "left"; 101 this.fontBaseline = "alphabetic"; 102 this.fontStyle = "normal"; 103 this._xformStack = []; 104 this.position = R.math.Point2D.create(0, 0); 105 this.rotation = 0; 106 this.scaleX = 1; 107 this.scaleY = 1; 108 }, 109 110 /** 111 * Releases the object back into the object pool. See {@link R.engine.PooledObject#release} 112 * for more information. 113 */ 114 release:function () { 115 this.base(); 116 this.width = 0; 117 this.height = 0; 118 this.lineStyle = null; 119 this.fillStyle = null; 120 this.lineWidth = 1; 121 this.position = null; 122 this.rotation = 0; 123 this.scaleX = 1; 124 this.scaleY = 1; 125 this.bBox = null; 126 this.backgroundColor = null; 127 this.wPosition = null; 128 this.wRotation = 0; 129 this.wScale = null; 130 this.font = null; 131 this.fontWeight = null; 132 this.fontSize = null; 133 this.fontAlign = null; 134 this.fontBaseline = null; 135 this.fontStyle = null; 136 this.zBins = null; 137 this._xformStack = null; 138 }, 139 140 /** 141 * Clean up the render bins after cleaning up the contained objects. 142 */ 143 cleanUp:function () { 144 this.base(); 145 for (var b in this.zBins.activeBins) { 146 this.zBins[this.zBins.activeBins[b]].all.destroy(); 147 this.zBins[this.zBins.activeBins[b]].all = null; 148 this.zBins[this.zBins.activeBins[b]].vis = null; 149 } 150 this.zBins = { 151 "0":{ 152 all:R.struct.Container.create(), 153 vis:[] 154 } 155 }; 156 this.zBins.activeBins = [0]; 157 }, 158 159 /** 160 * Sorts objects by their {@link R.objects.Object2D#getZIndex z-index}. Objects 161 * that don't have a z-index are untouched. 162 */ 163 sort:function () { 164 this.base(R.rendercontexts.RenderContext2D.sortFn); 165 }, 166 167 /** 168 * Add an object to the context. Only objects 169 * within the context will be rendered. If an object declared 170 * an <tt>afterAdd()</tt> method, it will be called after the object 171 * has been added to the context. 172 * 173 * @param obj {R.engine.BaseObject} The object to add to the render list 174 */ 175 add:function (obj) { 176 this.base(obj); 177 178 // Organize objects into bins by their zIndex so we can 179 // determine dirty rectangles 180 if (obj.getZIndex) { 181 this.swapBins(obj, R.rendercontexts.RenderContext2D.NO_ZBIN, obj.getZIndex()); 182 } else { 183 // If they don't have a zIndex, put them in the zeroth bin 184 this.swapBins(obj, R.rendercontexts.RenderContext2D.NO_ZBIN, 0); 185 } 186 }, 187 188 /** 189 * Remove an object from the render context. The object is 190 * not destroyed when it is removed from the container. The removal 191 * occurs after each update to avoid disrupting the flow of object 192 * traversal. 193 * 194 * @param obj {Object} The object to remove from the container. 195 * @return {Object} The object that was removed 196 */ 197 remove:function (obj) { 198 this.base(obj); 199 200 if (obj.getZIndex) { 201 // Remove the object from the zBins 202 var zBin = this.zBins[obj.getZIndex()]; 203 zBin.all.remove(obj); 204 R.engine.Support.arrayRemove(zBin.vis, obj); 205 } else { 206 this.zBins["0"].all.remove(obj); 207 R.engine.Support.arrayRemove(this.zBins["0"].vis, obj); 208 } 209 }, 210 211 /** 212 * Swap the zBin that the object is contained within. 213 * @param obj {R.objects.Object2D} The object to swap 214 * @param oldBin {Number} The old bin number, or <tt>RenderContext2D.NO_ZBIN</tt> to just 215 * insert into a new bin. 216 * @param newBin {Number} The new bin to put the object into 217 */ 218 swapBins:function (obj, oldBin, newBin) { 219 var zBin; 220 if (oldBin != R.rendercontexts.RenderContext2D.NO_ZBIN) { 221 // Remove the object from the old zBin 222 zBin = this.zBins[oldBin]; 223 zBin.remove(obj); 224 } 225 226 // We'll need to know the sorted order of bin numbers since there may be gaps 227 if (!this.zBins[newBin]) { 228 this.zBins.activeBins.push(newBin); 229 this.zBins.activeBins.sort(); 230 } 231 232 // Add to a bin 233 zBin = this.zBins[newBin]; 234 if (!zBin) { 235 this.zBins[newBin] = { 236 all:R.struct.Container.create(), // List of all objects in the bin 237 vis:[] // Optimized list of only visible objects 238 }; 239 240 zBin = this.zBins[newBin]; 241 } 242 243 // Start objects out as "not visible" 244 this.getContextData(obj).isVisible = false; 245 246 // Add the object to the "all objects" container 247 zBin.all.add(obj); 248 }, 249 250 /** 251 * Called to render all of the objects to the context. 252 * 253 * @param time {Number} The current render time in milliseconds from the engine. 254 * @param dt {Number} The delta between the world time and the last time the world was updated 255 * in milliseconds. 256 */ 257 render:function (time, dt) { 258 // Push the world transform 259 this.pushTransform(); 260 261 this.setupWorld(time, dt); 262 263 // Run the objects in each bin 264 for (var zbin in this.zBins.activeBins) { 265 var bin = this.zBins[this.zBins.activeBins[zbin]]; 266 267 // Don't want to push the entire bin onto the stack 268 this.processBin(this.zBins.activeBins[zbin]); 269 R.Engine.rObjs += bin.vis.length; 270 271 var objs = bin.vis; 272 this.renderBin(zbin, objs, time, dt); 273 } 274 275 // Restore the world transform 276 this.popTransform(); 277 278 while (this.postRenderList.length > 0) { 279 var fn = this.postRenderList.shift(); 280 fn.call(this); 281 } 282 283 // Safely remove any objects that were removed from 284 // the context while it was rendering 285 if (this.safeRemoveList.length > 0) { 286 this._safeRemove(); 287 } 288 }, 289 290 /** 291 * A rendering function to perform in world coordinates. After the world has 292 * been rendered, and all transformations have been reset to world coordinates, 293 * the list of post-render functions are executed. 294 * @param fn {Function} A function to execute 295 */ 296 postRender:function (fn) { 297 this.postRenderList.push(fn); 298 }, 299 300 /** 301 * Process all objects in a bin, optimizing the list down to only those that are visible. 302 * TODO: Hoping to put this in a Worker thead at some point for speed 303 * @param binId {String} The bin Id 304 * @private 305 */ 306 processBin:function (binId) { 307 var bin = this.zBins[binId]; 308 309 // Spin through "all" objects to determine visibility. 310 var itr = bin.all.iterator(); 311 while (itr.hasNext()) { 312 // Check if the object is visible, so it'll be processed. 313 var obj = itr.next(), contextModel = this.getContextData(obj); 314 if (!obj.getWorldBox || (obj.isKeepAlive && obj.isKeepAlive()) || 315 (this.getExpandedViewport().isIntersecting(obj.getWorldBox()))) { 316 // If the object isn't visible, push it into the "visibility" list 317 if (!contextModel.isVisible) { 318 contextModel.isVisible = true; 319 bin.vis.push(obj); 320 } 321 } else if (contextModel.isVisible) { 322 // The object isn't in the viewport and is marked visible, unmark it and 323 // remove from "visibility" list 324 contextModel.isVisible = false; 325 R.engine.Support.arrayRemove(bin.vis, obj); 326 } 327 } 328 itr.destroy(); 329 }, 330 331 /** 332 * Render all of the objects in a single bin, grouped by z-index. 333 * @param bin {Number} The bin number being rendered 334 * @param objs {Array} Array of objects 335 * @param time {Number} The current render time in milliseconds from the engine. 336 * @param dt {Number} The delta between the world time and the last time the world was updated 337 * in milliseconds. 338 */ 339 renderBin:function (bin, objs, time, dt) { 340 R.engine.Support.forEach(objs, function (e) { 341 this.renderObject(e, time, dt); 342 }, this); 343 }, 344 345 //------------------------------------------------------------------------ 346 347 /** 348 * Set the background color of the context. 349 * 350 * @param color {String} An HTML color 351 */ 352 setBackgroundColor:function (color) { 353 this.backgroundColor = color; 354 }, 355 356 /** 357 * Get the color assigned to the context background. 358 * @return {String} 359 */ 360 getBackgroundColor:function () { 361 return this.backgroundColor; 362 }, 363 364 /** 365 * Set the width of the context drawing area. 366 * 367 * @param width {Number} The width in pixels 368 */ 369 setWidth:function (width) { 370 this.width = width; 371 }, 372 373 /** 374 * Get the width of the context drawing area. 375 * @return {Number} 376 */ 377 getWidth:function () { 378 return this.width; 379 }, 380 381 /** 382 * Set the height of the context drawing area 383 * 384 * @param height {Number} The height in pixels 385 */ 386 setHeight:function (height) { 387 this.height = height; 388 }, 389 390 /** 391 * Get the height of the context drawing area. 392 * @render {Number} 393 */ 394 getHeight:function () { 395 return this.height; 396 }, 397 398 /** 399 * Get the bounding box for the rendering context. 400 * @return {R.math.Rectangle2D} 401 */ 402 getBoundingBox:function () { 403 if (!this.bBox) { 404 this.bBox = R.math.Rectangle2D.create(0, 0, this.getWidth(), this.getHeight()); 405 } 406 return this.bBox; 407 }, 408 409 /** 410 * Set the current transform position (translation) relative to the viewport. 411 * 412 * @param point {R.math.Point2D} The translation 413 */ 414 setPosition:function (point) { 415 this.position.add(point); 416 }, 417 418 /** 419 * Get the current transform position (translation) relative to the viewport. 420 * 421 * @return {R.math.Point2D} 422 */ 423 getPosition:function () { 424 return this.position; 425 }, 426 427 /** 428 * Set the rotation angle of the current transform. 429 * 430 * @param angle {Number} An angle in degrees 431 */ 432 setRotation:function (angle) { 433 this.rotation = angle; 434 }, 435 436 /** 437 * Get the current transform rotation. 438 * @return {Number} 439 */ 440 getRotation:function () { 441 return this.rotation; 442 }, 443 444 /** 445 * Set the scale of the current transform. Specifying 446 * only the first parameter implies a uniform scale. 447 * 448 * @param scaleX {Number} The X scaling factor, with 1 being 100% 449 * @param scaleY {Number} The Y scaling factor 450 */ 451 setScale:function (scaleX, scaleY) { 452 this.scaleX = scaleX; 453 this.scaleY = scaleY || scaleX; 454 }, 455 456 /** 457 * Get the X scaling factor of the current transform. 458 * @return {Number} 459 */ 460 getScaleX:function () { 461 return this.scaleX; 462 }, 463 464 /** 465 * Get the Y scaling factor of the current transform. 466 * @return {Number} 467 */ 468 getScaleY:function () { 469 return this.scaleY; 470 }, 471 472 /** 473 * Push the current transformation matrix. 474 */ 475 pushTransform:function () { 476 // Translation 477 var p = R.clone(this.getWorldPosition()).add(this.getPosition()); 478 var tMtx = $M([ 479 [1, 0, p.x], 480 [0, 1, p.y], 481 [0, 0, 1] 482 ]); 483 484 // Rotation 485 var a = this.getWorldRotation() + this.getRotation(); 486 var rMtx; 487 if (a != 0) { 488 // Rotate 489 rMtx = Matrix.Rotation(R.math.Math2D.degToRad(a), R.rendercontexts.RenderContext2D.ROTATION_AXIS); 490 } 491 else { 492 // Set to identity 493 rMtx = R.math.Math2D.identityMatrix(); 494 } 495 496 // Scale 497 var sX = this.getWorldScale() * this.getScaleX(), sY = this.getWorldScale() * this.getScaleY(), 498 sMtx = $M([ 499 [sX, 0, 0], 500 [0, sY, 0], 501 [0, 0, 1] 502 ]), txfmMtx = tMtx.multiply(rMtx).multiply(sMtx); 503 504 rMtx = null; 505 sMtx = null; 506 this._xformStack.push(txfmMtx); 507 508 this.base(); 509 }, 510 511 /** 512 * Pop the current transformation matrix. 513 */ 514 popTransform:function () { 515 // Restore the last position, (TODO: angle, and scale) 516 var xform = this._xformStack.pop().col(3); 517 this.position.set(xform.e(1), xform.e(2)); 518 519 this.base(); 520 }, 521 522 /** 523 * Set the font to use when rendering text to the context. 524 * @param font {String} A font string similar to CSS 525 */ 526 setFont:function (font) { 527 this.font = font; 528 }, 529 530 /** 531 * Get the font currently being used to render text 532 * @return {String} 533 */ 534 getFont:function () { 535 return this.font; 536 }, 537 538 /** 539 * Get the normalized font string used to describe the style. The 540 * value includes style, weight, size, and font. 541 * @return {String} 542 */ 543 getNormalizedFont:function () { 544 return this.getFontStyle() + " " + this.getFontWeight() + " " + this.getFontSize() + " " + this.getFont(); 545 }, 546 547 /** 548 * Set the size of the font being used to render text 549 * @param size {String} The font size string 550 */ 551 setFontSize:function (size) { 552 this.fontSize = size + "px"; 553 }, 554 555 /** 556 * Get the font size 557 * @return {String} 558 */ 559 getFontSize:function () { 560 return this.fontSize; 561 }, 562 563 /** 564 * Set the rendering weight of the font 565 * @param weight {String} 566 */ 567 setFontWeight:function (weight) { 568 this.fontWeight = weight; 569 }, 570 571 /** 572 * Get the weight of the font to be rendered to the context 573 * @return {String} 574 */ 575 getFontWeight:function () { 576 return this.fontWeight; 577 }, 578 579 /** 580 * Set the font alignment for the context 581 * @param align {String} The font alignment 582 */ 583 setFontAlign:function (align) { 584 this.fontAlign = align; 585 }, 586 587 /** 588 * Get the alignment of the font 589 * @return {String} 590 */ 591 getFontAlign:function () { 592 return this.fontAlign; 593 }, 594 595 /** 596 * Set the baseline of the renderable font 597 * @param baseline {String} The render baseline 598 */ 599 setFontBaseline:function (baseline) { 600 this.fontBaseline = baseline; 601 }, 602 603 /** 604 * Get the font baseline 605 * @return {String} 606 */ 607 getFontBaseline:function () { 608 return this.fontBaseline; 609 }, 610 611 /** 612 * Set the style of the renderable font 613 * @param style {String} The font style 614 */ 615 setFontStyle:function (style) { 616 this.fontStyle = style; 617 }, 618 619 /** 620 * Get a rectangle that will approximately enclose the text drawn by the render context. 621 * @param text {String} The text to measure 622 * @return {R.math.Rectangle2D} 623 */ 624 getTextMetrics:function (text) { 625 return R.math.Rectangle2D.create(0, 0, 1, 1); 626 }, 627 628 /** 629 * Get the renderable style of the font 630 * @return {String} 631 */ 632 getFontStyle:function () { 633 return this.fontStyle; 634 }, 635 636 /** 637 * Set the current transformation using a matrix. Replaces the 638 * current transformation at the top of the stack. 639 * @param matrix {Matrix} The transformation matrix 640 */ 641 setTransform:function (matrix) { 642 this._xformStack[this._xformStack.length - 1] = matrix; 643 }, 644 645 /** 646 * Get the current transformation matrix. 647 * @return {Matrix} 648 */ 649 getTransform:function () { 650 return this._xformStack[this._xformStack.length - 1]; 651 }, 652 653 /** 654 * Set the transformation of the world. 655 * 656 * @param position {R.math.Point2D} 657 * @param rotation {Number} 658 * @param scale {Number} 659 */ 660 setRenderTransform:function (mtx3) { 661 }, 662 663 /** 664 * Get the render position relative to the world 665 * @return {R.math.Point2D} 666 */ 667 getRenderPosition:function () { 668 return R.math.Point2D.ZERO; 669 }, 670 671 /** 672 * Get the render rotation relative to the world 673 * @return {Number} 674 */ 675 getRenderRotation:function () { 676 return 0; 677 }, 678 679 /** 680 * Get the render scale relative to the world 681 * @return {Number} 682 */ 683 getRenderScale:function () { 684 return 1.0; 685 }, 686 687 /** 688 * Set the line style for the context. 689 * 690 * @param lineStyle {String} An HTML color or <tt>null</tt> 691 */ 692 setLineStyle:function (lineStyle) { 693 this.lineStyle = lineStyle; 694 }, 695 696 /** 697 * Get the current line style for the context. <tt>null</tt> if 698 * not set. 699 * @return {String} 700 */ 701 getLineStyle:function () { 702 return this.lineStyle; 703 }, 704 705 /** 706 * Set the line width for drawing paths. 707 * 708 * @param [width=1] {Number} The width of lines in pixels 709 */ 710 setLineWidth:function (width) { 711 this.lineWidth = width; 712 }, 713 714 /** 715 * Get the current line width for drawing paths. 716 * @return {Number} 717 */ 718 getLineWidth:function () { 719 return this.lineWidth; 720 }, 721 722 /** 723 * Set the fill style of the context. 724 * 725 * @param fillStyle {String} An HTML color, or <tt>null</tt>. 726 */ 727 setFillStyle:function (fillStyle) { 728 this.fillStyle = fillStyle; 729 }, 730 731 /** 732 * Get the current fill style of the context. 733 * @return {String} 734 */ 735 getFillStyle:function () { 736 return this.fillStyle; 737 }, 738 739 /** 740 * Draw an un-filled rectangle on the context. 741 * 742 * @param rect {R.math.Rectangle2D} The rectangle to draw 743 * @param [ref] {R.engine.GameObject} A reference game object 744 */ 745 drawRectangle:function (rect /*, ref */) { 746 }, 747 748 /** 749 * Draw a filled rectangle on the context. 750 * 751 * @param rect {R.math.Rectangle2D} The rectangle to draw 752 * @param [ref] {R.engine.GameObject} A reference game object 753 */ 754 drawFilledRectangle:function (rect /*, ref */) { 755 }, 756 757 /** 758 * Draw an un-filled arc on the context. Arcs are drawn in clockwise 759 * order. 760 * 761 * @param point {R.math.Point2D} The point around which the arc will be drawn 762 * @param radius {Number} The radius of the arc in pixels 763 * @param startAngle {Number} The starting angle of the arc in degrees 764 * @param endAngle {Number} The end angle of the arc in degrees 765 * @param [ref] {R.engine.GameObject} A reference game object 766 */ 767 drawArc:function (point, radius, startAngle, endAngle /*, ref */) { 768 }, 769 770 /** 771 * Draw a filled arc on the context. Arcs are drawn in clockwise 772 * order. 773 * 774 * @param point {R.math.Point2D} The point around which the arc will be drawn 775 * @param radius {Number} The radius of the arc in pixels 776 * @param startAngle {Number} The starting angle of the arc in degrees 777 * @param endAngle {Number} The end angle of the arc in degrees 778 * @param [ref] {R.engine.GameObject} A reference game object 779 */ 780 drawFilledArc:function (point, radius, startAngle, endAngle /*, ref */) { 781 }, 782 783 /** 784 * Helper method to draw a circle by calling the {@link #drawArc} method 785 * with predefined start and end angle of zero and 6.28 radians. 786 * 787 * @param point {R.math.Point2D} The point around which the circle will be drawn 788 * @param radius {Number} The radius of the circle in pixels 789 * @param [ref] {R.engine.GameObject} A reference game object 790 */ 791 drawCircle:function (point, radius /*, ref */) { 792 this.drawArc(point, radius, 0, R.math.Math2D.TWO_PI); 793 }, 794 795 /** 796 * Helper method to draw a filled circle by calling the {@link #drawFilledArc} method 797 * with predefined start and end angle of zero and 6.28 radians. 798 * 799 * @param point {R.math.Point2D} The point around which the circle will be drawn 800 * @param radius {Number} The radius of the circle in pixels 801 * @param [ref] {R.engine.GameObject} A reference game object 802 */ 803 drawFilledCircle:function (point, radius /*, ref */) { 804 this.drawFilledArc(point, radius, 0, R.math.Math2D.TWO_PI); 805 }, 806 807 /** 808 * Draw a polygon or polyline using a Duff's device for 809 * efficiency and loop unrolling with inversion for speed. 810 * 811 * @param pointArray {Array} An array of <tt>R.math.Point2D</tt> objects 812 * @param closedLoop {Boolean} <tt>true</tt> to close the polygon 813 * @private 814 */ 815 _poly:function (pointArray, closedLoop) { 816 this.startPath(); 817 this.moveTo(pointArray[0]); 818 var p = 1; 819 820 // Using Duff's device with loop inversion 821 switch ((pointArray.length - 1) & 0x3) { 822 case 3: 823 this.lineSeg(pointArray[p++]); 824 case 2: 825 this.lineSeg(pointArray[p++]); 826 case 1: 827 this.lineSeg(pointArray[p++]); 828 } 829 830 if (p < pointArray.length) { 831 do 832 { 833 this.lineSeg(pointArray[p++]); 834 this.lineSeg(pointArray[p++]); 835 this.lineSeg(pointArray[p++]); 836 this.lineSeg(pointArray[p++]); 837 } while (p < pointArray.length); 838 } 839 840 if (closedLoop) { 841 this.endPath(); 842 } 843 }, 844 845 /** 846 * Draw an un-filled regular polygon with N sides. 847 * 848 * @param sides {Number} The number of sides, must be more than 2 849 * @param center {R.math.Point2D} The center of the polygon 850 * @param [radius] {Number} The radius of the polygon. Default: 100 851 */ 852 drawRegularPolygon:function (sides, center, radius) { 853 var poly = R.math.Math2D.regularPolygon(sides, radius); 854 for (var p = 0; p < poly.length; p++) { 855 poly[p].add(center); 856 } 857 this.drawPolygon(poly); 858 }, 859 860 /** 861 * Draw an un-filled polygon on the context. 862 * 863 * @param pointArray {Array} An array of {@link R.math.Point2D} objects 864 * @param [ref] {R.engine.GameObject} A reference game object 865 */ 866 drawPolygon:function (pointArray /*, ref */) { 867 this._poly(pointArray, true); 868 this.strokePath(); 869 this.lineSeg.moveTo = false; 870 }, 871 872 /** 873 * Draw a non-closed poly line on the context. 874 * 875 * @param pointArray {Array} An array of {@link Point2D} objects 876 * @param [ref] {R.engine.GameObject} A reference game object 877 */ 878 drawPolyline:function (pointArray /*, ref */) { 879 this._poly(pointArray, false); 880 this.strokePath(); 881 this.lineSeg.moveTo = false; 882 }, 883 884 /** 885 * Draw an filled polygon on the context. 886 * 887 * @param pointArray {Array} An array of {@link R.math.Point2D} objects 888 * @param [ref] {R.engine.GameObject} A reference game object 889 */ 890 drawFilledPolygon:function (pointArray /*, ref */) { 891 this._poly(pointArray, true); 892 this.fillPath(); 893 this.lineSeg.moveTo = false; 894 }, 895 896 /** 897 * Draw an un-filled regular polygon with N sides. 898 * 899 * @param sides {Number} The number of sides, must be more than 2 900 * @param center {R.math.Point2D} The center of the polygon 901 * @param [radius] {Number} The radius of the polygon. Default: 100 902 */ 903 drawFilledRegularPolygon:function (sides, center, radius) { 904 var poly = R.math.Math2D.regularPolygon(sides, radius); 905 for (var p = 0; p < poly.length; p++) { 906 poly[p].add(center); 907 } 908 this.drawFilledPolygon(poly); 909 }, 910 911 /** 912 * Draw a line on the context. 913 * 914 * @param point1 {R.math.Point2D} The start of the line 915 * @param point2 {R.math.Point2D} The end of the line 916 * @param [ref] {R.engine.GameObject} A reference game object 917 */ 918 drawLine:function (point1, point2 /*, ref */) { 919 }, 920 921 /** 922 * Draw a point on the context. 923 * 924 * @param point {R.math.Point2D} The position to draw the point 925 * @param [ref] {R.engine.GameObject} A reference game object 926 */ 927 drawPoint:function (point /*, ref */) { 928 }, 929 930 /** 931 * Draw a sprite on the context. 932 * 933 * @param sprite {R.resources.types.Sprite} The sprite to draw 934 * @param time {Number} The current world time 935 * @param dt {Number} The delta between the world time and the last time the world was updated 936 * in milliseconds. 937 * @param [ref] {R.engine.GameObject} A reference game object 938 */ 939 drawSprite:function (sprite, time, dt /*, ref */) { 940 }, 941 942 /** 943 * Draw an image on the context. 944 * 945 * @param rect {R.math.Rectangle2D} The rectangle that specifies the position and 946 * dimensions of the image rectangle. 947 * @param image {Object} The image to draw onto the context 948 * @param [srcRect] {R.math.Rectangle2D} <i>[optional]</i> The source rectangle within the image, if 949 * <tt>null</tt> the entire image is used 950 * @param [ref] {R.engine.GameObject} A reference game object 951 */ 952 drawImage:function (rect, image, srcRect /*, ref */) { 953 }, 954 955 /** 956 * Capture an image from the context. 957 * 958 * @param rect {R.math.Rectangle2D} The area to capture 959 * @return {ImageData} Image data capture 960 */ 961 getImage:function (rect) { 962 }, 963 964 /** 965 * Draw an image, captured with {@link #getImage}, to 966 * the context. 967 * 968 * @param imageData {ImageData} Image data captured 969 * @param point {R.math.Point2D} The poisition at which to draw the image 970 * @param [ref] {R.engine.GameObject} A reference game object 971 */ 972 putImage:function (imageData, point /*, ref */) { 973 }, 974 975 /** 976 * Draw text on the context. 977 * 978 * @param point {R.math.Point2D} The top-left position to draw the image. 979 * @param text {String} The text to draw 980 * @param [ref] {R.engine.GameObject} A reference game object 981 */ 982 drawText:function (point, text /*, ref */) { 983 }, 984 985 /** 986 * Start a path. 987 */ 988 startPath:function () { 989 }, 990 991 /** 992 * End a path. 993 */ 994 endPath:function () { 995 }, 996 997 /** 998 * Stroke a path using the current line style and width. 999 */ 1000 strokePath:function () { 1001 }, 1002 1003 /** 1004 * Fill a path using the current fill style. 1005 */ 1006 fillPath:function () { 1007 }, 1008 1009 /** 1010 * Move the current path to the point sepcified. 1011 * 1012 * @param point {R.math.Point2D} The point to move to 1013 */ 1014 moveTo:function (point) { 1015 }, 1016 1017 /** 1018 * Draw a line from the current point to the point specified. 1019 * 1020 * @param point {R.math.Point2D} The point to draw a line to 1021 */ 1022 lineTo:function (point) { 1023 }, 1024 1025 /** 1026 * Used to draw line segments for polylines. If <tt>point</tt> 1027 * is <tt>null</tt>, the context will move to the next point. Otherwise, 1028 * it will draw a line to the point. 1029 * 1030 * @param point {R.math.Point2D} The point to draw a line to, or null. 1031 */ 1032 lineSeg:function (point) { 1033 if (point == null) { 1034 this.lineSeg.moveTo = true; 1035 return; 1036 } 1037 1038 if (this.lineSeg.moveTo) { 1039 // Cannot have two subsequent nulls 1040 Assert((point != null), "LineSeg repeated null!", this); 1041 this.moveTo(point); 1042 this.lineSeg.moveTo = false; 1043 } 1044 else { 1045 this.lineTo(point); 1046 } 1047 }, 1048 1049 /** 1050 * Draw a quadratic curve from the current point to the specified point. 1051 * 1052 * @param cPoint {R.math.Point2D} The control point 1053 * @param point {R.math.Point2D} The point to draw to 1054 */ 1055 quadraticCurveTo:function (cPoint, point) { 1056 }, 1057 1058 /** 1059 * Draw a bezier curve from the current point to the specified point. 1060 * 1061 * @param cPoint1 {R.math.Point2D} Control point 1 1062 * @param cPoint2 {R.math.Point2D} Control point 2 1063 * @param point {R.math.Point2D} The point to draw to 1064 */ 1065 bezierCurveTo:function (cPoint1, cPoint2, point) { 1066 }, 1067 1068 /** 1069 * Draw an arc from the current point to the specified point. 1070 * 1071 * @param point1 {R.math.Point2D} Arc point 1 1072 * @param point2 {R.math.Point2D} Arc point 2 1073 * @param radius {Number} The radius of the arc 1074 */ 1075 arcTo:function (point1, point2, radius) { 1076 }, 1077 1078 /** 1079 * Draw an element on the context 1080 * @param ref {R.engine.GameObject} A reference game object 1081 */ 1082 drawElement:function (ref) { 1083 } 1084 1085 }, /** @scope R.rendercontexts.RenderContext2D.prototype */{ 1086 /** 1087 * Get the class name of this object 1088 * 1089 * @return {String} "R.rendercontexts.RenderContext2D" 1090 */ 1091 getClassName:function () { 1092 return "R.rendercontexts.RenderContext2D"; 1093 }, 1094 1095 /** 1096 * Sort the objects to draw from objects with the lowest 1097 * z-index to the highest z-index. 1098 * @static 1099 */ 1100 sortFn:function (obj1, obj2) { 1101 if (obj1.getZIndex && obj2.getZIndex) { 1102 return obj1.getZIndex() - obj2.getZIndex(); 1103 } 1104 return 0 1105 }, 1106 1107 /** 1108 * Bold text weight 1109 * @type {String} 1110 */ 1111 FONT_WEIGHT_BOLD:"bold", 1112 1113 /** 1114 * Normal text weight 1115 * @type {String} 1116 */ 1117 FONT_WEIGHT_NORMAL:"normal", 1118 1119 /** 1120 * Light text weight 1121 * @type {String} 1122 */ 1123 FONT_WEIGHT_LIGHT:"light", 1124 1125 /** 1126 * Text align left 1127 * @type {String} 1128 */ 1129 FONT_ALIGN_LEFT:"left", 1130 1131 /** 1132 * Text align right 1133 * @type {String} 1134 */ 1135 FONT_ALIGN_RIGHT:"right", 1136 1137 /** 1138 * Text align center 1139 * @type {String} 1140 */ 1141 FONT_ALIGN_CENTER:"center", 1142 1143 /** 1144 * Text align start of stroke 1145 * @type {String} 1146 */ 1147 FONT_ALIGN_START:"start", 1148 1149 /** 1150 * Text align end of stroke 1151 * @type {String} 1152 */ 1153 FONT_ALIGN_END:"end", 1154 1155 /** 1156 * Text baseline alphabetic 1157 * @type {String} 1158 */ 1159 FONT_BASELINE_ALPHABETIC:"alphabetic", 1160 1161 /** 1162 * Text baseline top of em box 1163 * @type {String} 1164 */ 1165 FONT_BASELINE_TOP:"top", 1166 1167 /** 1168 * Text baseline hanging ideograph 1169 * @type {String} 1170 */ 1171 FONT_BASELINE_HANGING:"hanging", 1172 1173 /** 1174 * Text baseline middle of em square 1175 * @type {String} 1176 */ 1177 FONT_BASELINE_MIDDLE:"middle", 1178 1179 /** 1180 * Text baseline ideographic bottom 1181 * @type {String} 1182 */ 1183 FONT_BASELINE_IDEOGRAPHIC:"ideographic", 1184 1185 /** 1186 * Text baseline bottom of em square 1187 * @type {String} 1188 */ 1189 FONT_BASELINE_BOTTOM:"bottom", 1190 1191 /** 1192 * Text style italic 1193 * @type {String} 1194 */ 1195 FONT_STYLE_ITALIC:"italic", 1196 1197 /** 1198 * Text style normal 1199 * @type {String} 1200 */ 1201 FONT_STYLE_NORMAL:"normal", 1202 1203 /** 1204 * Text style oblique 1205 * @type {String} 1206 */ 1207 FONT_STYLE_OBLIQUE:"oblique", 1208 1209 /** 1210 * @private 1211 */ 1212 NO_ZBIN:0xDEADBEEF, 1213 1214 /** 1215 * @private 1216 */ 1217 ROTATION_AXIS:$V([0, 0, 1]) 1218 }); 1219 1220 }; 1221