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