1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 /** 28 * Device type 29 * @constant 30 * @type {Object} 31 */ 32 cc.TARGET_PLATFORM = { 33 WINDOWS:0, 34 LINUX:1, 35 MACOS:2, 36 ANDROID:3, 37 IPHONE:4, 38 IPAD:5, 39 BLACKBERRY:6, 40 NACL:7, 41 EMSCRIPTEN:8, 42 MOBILE_BROWSER:100, 43 PC_BROWSER:101 44 }; 45 46 /** 47 * Device oriented vertically, home button on the bottom 48 * @constant 49 * @type Number 50 */ 51 cc.ORIENTATION_PORTRAIT = 0; 52 53 /** 54 * Device oriented vertically, home button on the top 55 * @constant 56 * @type Number 57 */ 58 cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1; 59 60 /** 61 * Device oriented horizontally, home button on the right 62 * @constant 63 * @type Number 64 */ 65 cc.ORIENTATION_LANDSCAPE_LEFT = 2; 66 67 /** 68 * Device oriented horizontally, home button on the left 69 * @constant 70 * @type Number 71 */ 72 cc.ORIENTATION_LANDSCAPE_RIGHT = 3; 73 74 //engine render type 75 76 /** 77 * Canvas of render type 78 * @constant 79 * @type Number 80 */ 81 cc.CANVAS = 0; 82 83 /** 84 * WebGL of render type 85 * @constant 86 * @type Number 87 */ 88 cc.WEBGL = 1; 89 90 /** 91 * drawing primitive of game engine 92 * @type cc.DrawingPrimitive 93 */ 94 cc.drawingUtil = null; 95 96 /** 97 * main Canvas 2D/3D Context of game engine 98 * @type CanvasRenderingContext2D|WebGLRenderingContext 99 */ 100 cc.renderContext = null; 101 102 /** 103 * main Canvas of game engine 104 * @type HTMLCanvasElement 105 */ 106 cc.canvas = null; 107 108 /** 109 * This Div element contain all game canvas 110 * @type HTMLDivElement 111 */ 112 cc.gameDiv = null; 113 114 /** 115 * current render type of game engine 116 * @type Number 117 */ 118 cc.renderContextType = cc.CANVAS; 119 120 /** 121 * save original size of canvas, use for resize canvas 122 * @type cc.Size 123 */ 124 cc.originalCanvasSize = cc.size(0, 0); 125 126 window.requestAnimFrame = (function () { 127 return window.requestAnimationFrame || 128 window.webkitRequestAnimationFrame || 129 window.mozRequestAnimationFrame || 130 window.oRequestAnimationFrame || 131 window.msRequestAnimationFrame 132 })(); 133 134 135 if (!window.console) { 136 window.console = {}; 137 window.console.log = function () { 138 }; 139 window.console.assert = function () { 140 }; 141 } 142 143 cc.isAddedHiddenEvent = false; 144 145 /** 146 * <p> 147 * setup game main canvas,renderContext,gameDiv and drawingUtil with argument <br/> 148 * <br/> 149 * can receive follow type of arguemnt: <br/> 150 * - empty: create a canvas append to document's body, and setup other option <br/> 151 * - string: search the element by document.getElementById(), <br/> 152 * if this element is HTMLCanvasElement, set this element as main canvas of engine, and set it's ParentNode as cc.gameDiv.<br/> 153 * if this element is HTMLDivElement, set it's ParentNode to cc.gameDiv, and create a canvas as main canvas of engine. <br/> 154 * </p> 155 * @function 156 * @example 157 * //setup with null 158 * cc.setup(); 159 * 160 * // setup with HTMLCanvasElement, gameCanvas is Canvas element 161 * // declare like this: <canvas id="gameCanvas" width="800" height="450"></canvas> 162 * cc.setup("gameCanvas"); 163 * 164 * //setup with HTMLDivElement, gameDiv is Div element 165 * // declare like this: <div id="Cocos2dGameContainer" width="800" height="450"></div> 166 * cc.setup("Cocos2dGameContainer"); 167 */ 168 cc.setup = function (el, width, height) { 169 var element = cc.$(el) || cc.$('#' + el); 170 var localCanvas, localContainer, localConStyle; 171 if (element.tagName == "CANVAS") { 172 width = width || element.width; 173 height = height || element.height; 174 175 //it is already a canvas, we wrap it around with a div 176 localContainer = cc.container = cc.$new("DIV"); 177 localConStyle = localContainer.style; 178 localCanvas = cc.canvas = element; 179 localCanvas.parentNode.insertBefore(localContainer, localCanvas); 180 localCanvas.appendTo(localContainer); 181 localConStyle.width = (width || 480) + "px"; 182 localConStyle.height = (height || 320) + "px"; 183 localContainer.setAttribute('id', 'Cocos2dGameContainer'); 184 localConStyle.margin = "0 auto"; 185 localCanvas.setAttribute("width", width || 480); 186 localCanvas.setAttribute("height", height || 320); 187 } else {//we must make a new canvas and place into this element 188 if (element.tagName != "DIV") { 189 cc.log("Warning: target element is not a DIV or CANVAS"); 190 } 191 width = width || element.clientWidth; 192 height = height || element.clientHeight; 193 194 localCanvas = cc.canvas = cc.$new("CANVAS"); 195 localCanvas.addClass("gameCanvas"); 196 localCanvas.setAttribute("width", width || 480); 197 localCanvas.setAttribute("height", height || 320); 198 localContainer = cc.container = element; 199 localConStyle = localContainer.style; 200 element.appendChild(localCanvas); 201 localConStyle.width = (width || 480) + "px"; 202 localConStyle.height = (height || 320) + "px"; 203 localConStyle.margin = "0 auto"; 204 } 205 localConStyle.position = 'relative'; 206 localConStyle.overflow = 'hidden'; 207 localContainer.top = '100%'; 208 209 if(cc.__renderDoesnotSupport) 210 return; 211 212 if (cc.Browser.supportWebGL) 213 cc.renderContext = cc.webglContext = cc.create3DContext(localCanvas,{ 214 'stencil': true, 215 'preserveDrawingBuffer': true, 216 'antialias': !cc.Browser.isMobile, 217 'alpha': false}); 218 if(cc.renderContext){ 219 cc.renderContextType = cc.WEBGL; 220 window.gl = cc.renderContext; // global variable declared in CCMacro.js 221 cc.drawingUtil = new cc.DrawingPrimitiveWebGL(cc.renderContext); 222 cc.TextureCache.getInstance()._initializingRenderer(); 223 } else { 224 cc.renderContext = localCanvas.getContext("2d"); 225 cc.mainRenderContextBackup = cc.renderContext; 226 cc.renderContextType = cc.CANVAS; 227 cc.renderContext.translate(0, localCanvas.height); 228 cc.drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc.renderContext) : null; 229 } 230 231 cc.originalCanvasSize = cc.size(localCanvas.width, localCanvas.height); 232 cc.gameDiv = localContainer; 233 234 cc.log(cc.ENGINE_VERSION); 235 cc.Configuration.getInstance(); 236 237 cc.setContextMenuEnable(false); 238 239 if(cc.Browser.isMobile){ 240 cc._addUserSelectStatus(); 241 } 242 243 var hidden, visibilityChange; 244 if (typeof document.hidden !== "undefined") { 245 hidden = "hidden"; 246 visibilityChange = "visibilitychange"; 247 } else if (typeof document.mozHidden !== "undefined") { 248 hidden = "mozHidden"; 249 visibilityChange = "mozvisibilitychange"; 250 } else if (typeof document.msHidden !== "undefined") { 251 hidden = "msHidden"; 252 visibilityChange = "msvisibilitychange"; 253 } else if (typeof document.webkitHidden !== "undefined") { 254 hidden = "webkitHidden"; 255 visibilityChange = "webkitvisibilitychange"; 256 } 257 258 function handleVisibilityChange() { 259 if(!cc.AudioEngine) return; 260 var audioEngine = cc.AudioEngine.getInstance(); 261 if (!document[hidden]){ 262 cc.Director.getInstance()._resetLastUpdate(); 263 audioEngine.resumeAllEffects(); 264 audioEngine.resumeMusic(); 265 } else{ 266 audioEngine.pauseAllEffects(); 267 audioEngine.pauseMusic(); 268 } 269 } 270 271 if (typeof document.addEventListener === "undefined" || 272 typeof hidden === "undefined") { 273 cc.isAddedHiddenEvent = false; 274 window.addEventListener("focus", function () { 275 if(!cc.AudioEngine) return; 276 var audioEngine = cc.AudioEngine.getInstance(); 277 audioEngine.resumeAllEffects(); 278 audioEngine.resumeMusic(); 279 }, false); 280 window.addEventListener("blur", function () { 281 if(!cc.AudioEngine) return; 282 var audioEngine = cc.AudioEngine.getInstance(); 283 audioEngine.pauseAllEffects(); 284 audioEngine.pauseMusic(); 285 }, false); 286 } else { 287 cc.isAddedHiddenEvent = true; 288 document.addEventListener(visibilityChange, handleVisibilityChange, false); 289 } 290 }; 291 292 cc._addUserSelectStatus = function(){ 293 var fontStyle = document.createElement("style"); 294 fontStyle.type = "text/css"; 295 document.body.appendChild(fontStyle); 296 297 fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;" 298 +"-webkit-tap-highlight-color:rgba(0,0,0,0);}"; 299 }; 300 301 cc._isContextMenuEnable = false; 302 /** 303 * enable/disable contextMenu for Canvas 304 * @param {Boolean} enabled 305 */ 306 cc.setContextMenuEnable = function (enabled) { 307 cc._isContextMenuEnable = enabled; 308 if (!cc._isContextMenuEnable) { 309 cc.canvas.oncontextmenu = function () { 310 return false; 311 }; 312 } else { 313 cc.canvas.oncontextmenu = function () { 314 }; 315 } 316 }; 317 318 /** 319 * Run main loop of game engine 320 * @class 321 * @extends cc.Class 322 */ 323 cc.Application = cc.Class.extend(/** @lends cc.Application# */{ 324 _animationInterval:null, 325 /** 326 * Constructor 327 */ 328 ctor:function () { 329 this._animationInterval = 0; 330 if(cc._sharedApplication) 331 throw "Application has been initialized"; 332 cc._sharedApplication = this; 333 }, 334 335 /** 336 * Callback by cc.Director for limit FPS. 337 * @param {Number} interval The time, which expressed in second, between current frame and next. 338 */ 339 setAnimationInterval:function (interval) { 340 this._animationInterval = interval; 341 }, 342 343 /** 344 * Get status bar rectangle in EGLView window. 345 * @param {cc.Rect} rect 346 * @deprecated 347 */ 348 statusBarFrame:function (rect) { 349 if (rect) { 350 // Windows doesn't have status bar. 351 rect = cc.rect(0, 0, 0, 0); 352 } 353 }, 354 355 getTargetPlatform:function(){ 356 return cc.Browser.isMobile ? cc.TARGET_PLATFORM.MOBILE_BROWSER : cc.TARGET_PLATFORM.PC_BROWSER; 357 }, 358 359 /** 360 * Run the message loop. 361 * @return {Number} 362 */ 363 run:function () { 364 // Initialize instance and cocos2d. 365 if (!this.applicationDidFinishLaunching()) 366 return 0; 367 368 var callback, director = cc.Director.getInstance(), w = window; 369 cc.director = director; 370 if (w.requestAnimFrame && this._animationInterval == 1 / 60) { 371 callback = function () { 372 director.mainLoop(); 373 w.requestAnimFrame(callback); 374 }; 375 //cc.log(window.requestAnimFrame); 376 w.requestAnimFrame(callback); 377 } else { 378 callback = function () { 379 director.mainLoop(); 380 }; 381 setInterval(callback, this._animationInterval * 1000); 382 } 383 return 0; 384 } 385 }); 386 387 /** 388 * Get current application instance. 389 * @return {cc.Application} Current application instance pointer. 390 */ 391 cc.Application.getInstance = function () { 392 return cc._sharedApplication; 393 }; 394 395 /** 396 * Get current language config 397 * @return {Number} Current language config 398 */ 399 cc.Application.getCurrentLanguage = function () { 400 var ret = cc.LANGUAGE_ENGLISH; 401 402 var currentLang = navigator.language; 403 if(!currentLang) 404 currentLang = navigator.browserLanguage || navigator.userLanguage; 405 if(!currentLang) 406 return ret; 407 408 currentLang = currentLang.toLowerCase(); 409 switch (currentLang) { 410 case "zh-cn": 411 ret = cc.LANGUAGE_CHINESE; 412 break; 413 case "fr": 414 ret = cc.LANGUAGE_FRENCH; 415 break; 416 case "it": 417 ret = cc.LANGUAGE_ITALIAN; 418 break; 419 case "de": 420 ret = cc.LANGUAGE_GERMAN; 421 break; 422 case "es": 423 ret = cc.LANGUAGE_SPANISH; 424 break; 425 case "ru": 426 ret = cc.LANGUAGE_RUSSIAN; 427 break; 428 case "ko": 429 ret = cc.LANGUAGE_KOREAN; 430 break; 431 case "ja": 432 ret = cc.LANGUAGE_JAPANESE; 433 break; 434 case "hu": 435 ret = cc.LANGUAGE_HUNGARIAN; 436 break; 437 case "pt": 438 ret = cc.LANGUAGE_PORTUGUESE; 439 break; 440 case "ar": 441 ret = cc.LANGUAGE_ARABIC; 442 break; 443 case "no": 444 ret = cc.LANGUAGE_NORWEGIAN; 445 break; 446 case "pl": 447 ret = cc.LANGUAGE_POLISH; 448 break; 449 } 450 451 return ret; 452 }; 453 454 cc._sharedApplication = null; 455