1 /**
  2  * The Render Engine
  3  * VirtualCanvasContext
  4  *
  5  * @fileoverview An extension of the canvas context used to represent a game world larger than
  6  *    the viewport.
  7  *
  8  * @author: Brett Fattori (brettf@renderengine.com)
  9  *
 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.VirtualCanvasContext",
 38     "requires":[
 39         "R.rendercontexts.CanvasContext",
 40         "R.math.Math2D"
 41     ]
 42 });
 43 
 44 /**
 45  * @class A canvas render context whose world boundary is larger than the actual
 46  *        viewport.  This allows the world to be rendered as if viewed through a
 47  *        window into a larger world.  You can set the world position with simple
 48  *        scroll methods, or cause the world to transition to a specific point over
 49  *        a given duration.
 50  *
 51  * @constructor
 52  * @param name {String} The name of the object
 53  * @param windowWidth {Number} The width of the viewable window, in pixels
 54  * @param windowHeight {Number} The height of the viewable window, in pixels
 55  * @param worldWidth {Number} The width of the world, in pixels
 56  * @param worldHeight {Number} The height of the world, in pixels
 57  * @extends R.rendercontexts.CanvasContext
 58  */
 59 R.rendercontexts.VirtualCanvasContext = function () {
 60     return R.rendercontexts.CanvasContext.extend(/** @scope R.rendercontexts.VirtualCanvasContext.prototype */{
 61 
 62         scrollFromPt:null,
 63         scrollToPt:null,
 64         moving:false,
 65         expireTime:0,
 66         duration:0,
 67 
 68         /** @private */
 69         constructor:function (name, windowWidth, windowHeight, worldWidth, worldHeight) {
 70             // Create an element for us to use as our window
 71             this.base(name || "VirtualCanvasContext", windowWidth, windowHeight);
 72             this.setWorldBoundary(R.math.Rectangle2D.create(0, 0, worldWidth, worldHeight));
 73             this.scrollToPt = R.math.Point2D.create(0, 0);
 74             this.scrollFromPt = R.math.Point2D.create(0, 0);
 75             this.moving = false;
 76             this.expireTime = 0;
 77             this.duration = 0;
 78         },
 79 
 80         /**
 81          * Set the horizontal world position in pixels.
 82          *
 83          * @param x {Number} The horizontal scroll in pixels
 84          */
 85         setHorizontalScroll:function (x) {
 86             var maxX = this.getWorldBoundary().w - this.getViewport().w;
 87             x = (x < 0 ? 0 : (x > maxX ? maxX : x));
 88             this.getWorldPosition().setX(x);
 89             this.getViewport().getTopLeft().setX(x);
 90         },
 91 
 92         /**
 93          * Set the vertical world position in pixels.
 94          *
 95          * @param y {Number} The vertical scroll in pixels
 96          */
 97         setVerticalScroll:function (y) {
 98             var maxY = this.getWorldBoundary().h - this.getViewport().h;
 99             y = (y < 0 ? 0 : (y > maxY ? maxY : y));
100             this.getWorldPosition().setY(y);
101             this.getViewport().getTopLeft().setY(y);
102         },
103 
104         /**
105          * Set the current world position to a specific point.
106          * @param pt {R.math.Point2D} The point to set the scroll to.
107          */
108         setScroll:function (pt) {
109             this.setHorizontalScroll(pt.x);
110             this.setVerticalScroll(pt.y);
111         },
112 
113         /**
114          * Scroll to the given point, or location, over the given duration.
115          * @param duration {Number} The number of milliseconds for the transition to occur
116          * @param ptOrX {Number|R.math.Point2D} The X coordinate, or point, to scroll to
117          * @param [y] {Number} The Y coordinate, if <tt>ptOrX</tt> is a number
118          */
119         scrollTo:function (duration, ptOrX, y) {
120             this.scrollFromPt.set(this.getWorldPosition());
121             this.scrollToPt.set(ptOrX, y);
122             this.moving = true;
123             this.expireTime = R.Engine.worldTime + duration;
124             this.duration = duration;
125         },
126 
127         /**
128          * Get the horizontal scroll amount in pixels.
129          * @return {Number} The horizontal scroll
130          */
131         getHorizontalScroll:function () {
132             return this.getWorldPosition().x;
133         },
134 
135         /**
136          * Get the vertical scroll amount in pixels.
137          * @return {Number} The vertical scroll
138          */
139         getVerticalScroll:function () {
140             return this.getWorldPosition().y;
141         },
142 
143         /**
144          * If a transition was initiated with {@link #scrollTo},
145          * this will update the viewport accordingly.
146          *
147          * @param worldTime {Number} The current world time
148          * @param dt {Number} The delta between the world time and the last time the world was updated
149          *          in milliseconds.
150          */
151         setupWorld:function (worldTime, dt) {
152             if (this.moving) {
153                 if (worldTime < this.expireTime) {
154                     // Moving
155                     var sc = R.math.Point2D.create(this.scrollToPt).sub(this.scrollFromPt)
156                             .mul((this.duration - (this.expireTime - worldTime)) / this.duration),
157                         sp = R.math.Point2D.create(this.scrollFromPt).add(sc);
158                     this.setScroll(sp);
159                     sc.destroy();
160                     sp.destroy();
161                 } else {
162                     // Arrived
163                     this.moving = false;
164                     this.expireTime = 0;
165                     this.setScroll(this.scrollToPt);
166                 }
167             }
168             this.base(worldTime, dt);
169         }
170 
171     }, /** @scope R.rendercontexts.VirtualCanvasContext.prototype */ {
172 
173         /**
174          * Get the class name of this object
175          * @return {String} The string "R.rendercontexts.VirtualCanvasContext"
176          */
177         getClassName:function () {
178             return "R.rendercontexts.VirtualCanvasContext";
179         }
180     });
181 
182 };
183