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