1 /*!
  2  * The Render Engine is a cross-browser, open source game engine written entirely
  3  * in JavaScript. Designed from the ground up to be extremely flexible, it boasts
  4  * an extensive API and uses the newest features of today's modern browsers.  
  5  * 
  6  * Visit
  7  * http://www.renderengine.com for more information.
  8  *
  9  * author: Brett Fattori (brettf@renderengine.com)
 10  * version: @BUILD_VERSION
 11  * date: @BUILD_DATE
 12  *
 13  * Copyright (c) 2011 Brett Fattori
 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 "use strict";
 36 
 37 /**
 38  * @namespace
 39  * The Render Engine namespace
 40  */
 41 var R = R || {};
 42 
 43 /**
 44  * List of namespaces declared in R
 45  * @private
 46  */
 47 R._namespaces = {};
 48 
 49 /**
 50  * The global namespace, typically the window object
 51  * @memberOf R
 52  * @type {Object}
 53  */
 54 R.global = this;
 55 
 56 // Mimic the jQuery.browser object
 57 R.browser = {
 58     userAgent:navigator.userAgent.toLowerCase()
 59 };
 60 
 61 var uAMatcher = {
 62     webkit:/(webkit)[ \/]([\w.]+)/,
 63     opera:/(opera)(?:.*version)?[ \/]([\w.]+)/,
 64     msie:/(msie) ([\w.]+)/,
 65     mozilla:/(mozilla)(?:.*? rv:([\w.]+))?/,
 66     chrome:/(chrome)/,
 67     firefox:/(firefox)/,
 68     Wii:/nintendo (wii)/,
 69     android:/(android).*AppleWebKit/,
 70     safariMobile:/(iphone|ipad|ipod)/
 71 };
 72 
 73 for (var ua in uAMatcher)
 74     if (uAMatcher.hasOwnProperty(ua)) {
 75         var matcher = uAMatcher[ua].exec(R.browser.userAgent), version = matcher ? matcher[2] : null;
 76         R.browser[ua] = (matcher && matcher[1] ? true : false);
 77         R.browser.version = (version != null);
 78     }
 79 
 80 R.browser.WiiMote = ((window.opera && window.opera.wiiremote) ? window.opera.wiiremote : null);
 81 R.browser.WiiScreenWidth = 800;
 82 R.browser.WiiScreenHeight = 460;
 83 
 84 
 85 // Chrome version
 86 if (R.browser.chrome) {
 87     R.browser.version = /chrome\/([\d\.]*)\b/.exec(R.browser.userAgent)[1];
 88 }
 89 
 90 // Firefox version
 91 if (R.browser.firefox) {
 92     R.browser.version = /firefox\/([\d\.]*)\b/.exec(R.browser.userAgent)[1];
 93 }
 94 
 95 /**
 96  * Declare a new namespace in R.
 97  * @param ns {String} The namespace to declare
 98  * @exception Throws an exception if the namespace is already declared
 99  * @memberOf R
100  */
101 R.namespace = function (ns) {
102     if (R._namespaces[ns]) {
103         throw new Error("Namespace '" + ns + "' already defined!");
104     }
105     R._namespaces[ns] = 1;
106 
107     var path = ns.split("."), cur = R;
108     for (var p; path.length && (p = path.shift());) {
109         if (cur[p]) {
110             cur = cur[p];
111         } else {
112             cur = cur[p] = {};
113         }
114     }
115 };
116 
117 /**
118  * Throw an "unsupported" exception for the given method in the class.
119  * @param method {String} The method name
120  * @param clazz {Class} The class object
121  * @memberOf R
122  * @exception Throws a "[method] is unsupported in [Class]" error
123  */
124 R._unsupported = function (method, clazz) {
125     throw new Error(method + " is unsupported in " + clazz.getClassName());
126 };
127 
128 /** @private **/
129 R.str = Object.prototype.toString;
130 
131 /**
132  * Check if the given object is a function
133  * @param obj {Object} The object to test
134  * @return {Boolean}
135  * @memberOf R
136  */
137 R.isFunction = function (obj) {
138     return (R.str.call(obj) === "[object Function]");
139 };
140 
141 /**
142  * Check if the given object is an array
143  * @param obj {Object} The object to test
144  * @return {Boolean}
145  * @memberOf R
146  */
147 R.isArray = function (obj) {
148     return (R.str.call(obj) === "[object Array]");
149 };
150 
151 /**
152  * Check if the given object is a string
153  * @param obj {Object} The object to test
154  * @return {Boolean}
155  * @memberOf R
156  */
157 R.isString = function (obj) {
158     return (R.str.call(obj) === "[object String]");
159 };
160 
161 /**
162  * Check if the given object is a number
163  * @param obj {Object} The object to test
164  * @return {Boolean}
165  * @memberOf R
166  */
167 R.isNumber = function (obj) {
168     return (R.str.call(obj) === "[object Number]");
169 };
170 
171 /**
172  * Check if the given object is undefined.  Cannot check properties
173  * of an object unless the object is known to be defined.
174  * @param obj {Object} The object to test
175  * @returns {boolean}
176  * @memberOf R
177  */
178 R.isUndefined = function(obj) {
179     return typeof obj === "undefined";
180 };
181 
182 /**
183  * Check if the given object is null.
184  * @param obj {Object} The object to test
185  * @returns {boolean}
186  * @memberOf R
187  */
188 R.isNull = function(obj) {
189     return obj === null;
190 };
191 
192 /**
193  * Test if the object is undefined, null, or a string and is empty
194  * @param obj {Object} The object to test
195  * @return {Boolean}
196  * @memberOf R
197  */
198 R.isEmpty = function (obj) {
199     return R.isUndefined(obj) || R.isNull(obj) || (R.isString(obj) && $.trim(obj) === "");
200 };
201 
202 /**
203  * Make a simplified class object.
204  * @param clazz {Object} Methods and fields to assign to the class prototype.  A special method, "<tt>constructor</tt>"
205  *        will be used as the constructor function for the class, or an empty constructor will be assigned.
206  * @param props {Object} Properties which are available on the object class.  The format is [getterFn, setterFn].  If
207  *        either is null, the corresponding property accessor method will not be assigned.
208  * @return {Function} A new
209  * @memberOf R
210  */
211 R.make = function (clazz, props) {
212     // Get the constructor (if it exists)
213     var c = clazz["constructor"] || function () {
214     };
215     if (clazz["constructor"]) {
216         delete clazz["constructor"];
217     }
218 
219     // Assign prototype fields and methods
220     for (var fm in clazz) {
221         c.prototype[fm] = clazz[fm];
222     }
223 
224     // Set up properties
225     if (props) {
226         for (var p in props) {
227             if (props[p][0]) {
228                 c.prototype.__defineGetter__(p, props[p][0]);
229             }
230             if (props[p][1]) {
231                 c.prototype.__defineSetter__(p, props[p][1]);
232             }
233         }
234     }
235 
236     return c;
237 };
238 
239 /**
240  * Method for cloning objects which extend from {@link R.engine.PooledObject}.
241  * Other objects will return a clone of the object, but not classes.
242  * @param obj {Object} The object to clone
243  * @return {Object} A clone of the object
244  */
245 R.clone = function (obj) {
246     if (obj instanceof R.engine.PooledObject) {
247         var ctor = obj.constructor;
248         if (ctor.clone) {
249             return ctor.clone(obj);
250         } else {
251             return ctor.create(obj);
252         }
253     } else {
254         return $.extend({}, obj);
255     }
256 };
257 
258 /**
259  * Cache of classes located by name
260  * @private
261  */
262 R.classCache = {};
263 
264 /**
265  * Get the class for the given class name string.
266  * @param className {String} The class name string
267  * @return {Class} The class object for the given name
268  * @throws ReferenceError if the class is invalid or unknown
269  */
270 R.getClassForName = function (className) {
271     if (R.classCache[className] !== undefined) {
272         return R.classCache[className];
273     }
274 
275     var cn = className.split("."), c = R.global;
276     try {
277         while (cn.length > 0) {
278             c = c[cn.shift()];
279         }
280 
281         // Cache it, if resolved
282         if (R.engine.Linker.resolvedClasses[className]) {
283             R.classCache[className] = c;
284         }
285         return c;
286     } catch (ex) {
287         return undefined;
288     }
289 };
290 
291 /**
292  * Method to request an animation frame for timing (alternate loop)
293  * framerate fixed at 60fps
294  */
295 R.global.nativeFrame = (function () {
296     return  R.global.requestAnimationFrame ||
297         R.global.webkitRequestAnimationFrame ||
298         R.global.mozRequestAnimationFrame ||
299         R.global.oRequestAnimationFrame ||
300         R.global.msRequestAnimationFrame ||
301         function (/* function */ callback, /* DOMElement */ element) {
302             R.global.setTimeout(callback, 1000 / 60);
303         };
304 })();
305 
306 // Instead of arguments.callee
307 R.bind = function (obj, fn) {
308     return function () {
309         return fn.apply(obj, arguments);
310     }
311 };
312 
313 // Define the engine's default namespaces
314 R.namespace("debug");
315 R.namespace("lang");
316 R.namespace("struct");
317 R.namespace("math");
318 R.namespace("engine");
319 R.namespace("collision");
320 R.namespace("collision.broadphase");
321 R.namespace("components");
322 R.namespace("components.input");
323 R.namespace("components.transform");
324 R.namespace("components.logic");
325 R.namespace("components.logic.behaviors");
326 R.namespace("components.collision");
327 R.namespace("components.render");
328 R.namespace("components.physics");
329 R.namespace("objects");
330 R.namespace("particles");
331 R.namespace("particles.effects");
332 R.namespace("physics");
333 R.namespace("rendercontexts");
334 R.namespace("resources");
335 R.namespace("resources.loaders");
336 R.namespace("resources.types");
337 R.namespace("sound");
338 R.namespace("storage");
339 R.namespace("text");
340 R.namespace("ui");
341 R.namespace("util");
342 R.namespace("util.console");
343 
344 /**
345  * Return the current time in milliseconds.
346  * @return {Number}
347  */
348 R.now = (function () {
349     return Date.now ? Date.now : function () {
350         return new Date().getTime();
351     };
352 })();
353 
354 R.loadGame = function (fileName, className, description) {
355     var gameLoader = {}, cb;
356 
357     gameLoader.fileName = fileName;
358     gameLoader.className = className;
359     gameLoader.description = description;
360 
361     cb = R.bind(gameLoader, function () {
362         if (typeof R.Engine !== "undefined" && typeof R.Engine.loadGame !== "undefined") {
363             R.Engine.loadGame(this.fileName, this.className, this.description);
364         } else {
365             setTimeout(cb, 250);
366         }
367     });
368 
369 
370     setTimeout(cb, 250);
371 };
372 
373 
374