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 isScreenHidden = false;
244 
245     var hidden, visibilityChange;
246     if (typeof document.hidden !== "undefined") {
247         hidden = "hidden";
248         visibilityChange = "visibilitychange";
249     } else if (typeof document.mozHidden !== "undefined") {
250         hidden = "mozHidden";
251         visibilityChange = "mozvisibilitychange";
252     } else if (typeof document.msHidden !== "undefined") {
253         hidden = "msHidden";
254         visibilityChange = "msvisibilitychange";
255     } else if (typeof document.webkitHidden !== "undefined") {
256         hidden = "webkitHidden";
257         visibilityChange = "webkitvisibilitychange";
258     }
259 
260     function handleFocus() {
261         if (!cc.AudioEngine || !isScreenHidden) return;
262         isScreenHidden = false;
263         var audioEngine = cc.AudioEngine.getInstance();
264         audioEngine.resumeAllEffects();
265         audioEngine.resumeMusic();
266     }
267 
268     function handleBlur() {
269         if (!cc.AudioEngine || isScreenHidden) return;
270         isScreenHidden = true;
271         var audioEngine = cc.AudioEngine.getInstance();
272         audioEngine.pauseAllEffects();
273         audioEngine.pauseMusic();
274     }
275 
276     function handleVisibilityChange() {
277         if (!document[hidden])
278             handleFocus();
279         else
280             handleBlur();
281     }
282 
283     if (typeof document.addEventListener === "undefined" ||
284         typeof hidden === "undefined") {
285         cc.isAddedHiddenEvent = false;
286         window.addEventListener("focus", handleFocus, false);
287         window.addEventListener("blur", handleBlur, false);
288     } else {
289         cc.isAddedHiddenEvent = true;
290         document.addEventListener(visibilityChange, handleVisibilityChange, false);
291     }
292 
293     if ("onpageshow" in window && "onpagehide" in window) {
294         window.addEventListener("pageshow", handleFocus, false);
295         window.addEventListener("pagehide", handleBlur, false);
296     }
297     
298 };
299 
300 cc._addUserSelectStatus = function(){
301     var fontStyle = document.createElement("style");
302     fontStyle.type = "text/css";
303     document.body.appendChild(fontStyle);
304 
305     fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;"
306         +"-webkit-tap-highlight-color:rgba(0,0,0,0);}";
307 };
308 
309 cc._isContextMenuEnable = false;
310 /**
311  * enable/disable contextMenu for Canvas
312  * @param {Boolean} enabled
313  */
314 cc.setContextMenuEnable = function (enabled) {
315     cc._isContextMenuEnable = enabled;
316     if (!cc._isContextMenuEnable) {
317         cc.canvas.oncontextmenu = function () {
318             return false;
319         };
320     } else {
321         cc.canvas.oncontextmenu = function () {
322         };
323     }
324 };
325 
326 /**
327  * Run main loop of game engine
328  * @class
329  * @extends cc.Class
330  */
331 cc.Application = cc.Class.extend(/** @lends cc.Application# */{
332     _animationInterval:null,
333     /**
334      * Constructor
335      */
336     ctor:function () {
337         this._animationInterval = 0;
338         if(cc._sharedApplication)
339             throw "Application has been initialized";
340         cc._sharedApplication = this;
341     },
342 
343     /**
344      * Callback by cc.Director for limit FPS.
345      * @param {Number} interval The time, which expressed in second, between current frame and next.
346      */
347     setAnimationInterval:function (interval) {
348         this._animationInterval = interval;
349     },
350 
351     /**
352      *  Get status bar rectangle in EGLView window.
353      * @param {cc.Rect} rect
354      * @deprecated
355      */
356     statusBarFrame:function (rect) {
357         if (rect) {
358             // Windows doesn't have status bar.
359             rect = cc.rect(0, 0, 0, 0);
360         }
361     },
362 
363     getTargetPlatform:function(){
364         return cc.Browser.isMobile ? cc.TARGET_PLATFORM.MOBILE_BROWSER : cc.TARGET_PLATFORM.PC_BROWSER;
365     },
366 
367     /**
368      * Run the message loop.
369      * @return {Number}
370      */
371     run:function () {
372         // Initialize instance and cocos2d.
373         if (!this.applicationDidFinishLaunching())
374             return 0;
375 
376         var callback, director = cc.Director.getInstance(), w = window;
377         cc.director = director;
378         if (w.requestAnimFrame && this._animationInterval == 1 / 60) {
379             callback = function () {
380                 director.mainLoop();
381                 w.requestAnimFrame(callback);
382             };
383             //cc.log(window.requestAnimFrame);
384             w.requestAnimFrame(callback);
385         } else {
386             callback = function () {
387                 director.mainLoop();
388             };
389             setInterval(callback, this._animationInterval * 1000);
390         }
391         return 0;
392     }
393 });
394 
395 /**
396  * Get current application instance.
397  * @return {cc.Application}  Current application instance pointer.
398  */
399 cc.Application.getInstance = function () {
400     return cc._sharedApplication;
401 };
402 
403 /**
404  * Get current language config
405  * @return {Number} Current language config
406  */
407 cc.Application.getCurrentLanguage = function () {
408     var ret = cc.LANGUAGE_ENGLISH;
409 
410     var currentLang = navigator.language;
411     if(!currentLang){
412         currentLang = navigator.browserLanguage || navigator.userLanguage;
413     }
414     if(!currentLang){
415         return ret;
416     }
417 
418     currentLang = currentLang.substring(0,2).toLowerCase();
419     switch (currentLang) {
420         case "cn":
421         case "zh":
422             ret = cc.LANGUAGE_CHINESE;
423             break;
424         case "fr":
425             ret = cc.LANGUAGE_FRENCH;
426             break;
427         case "it":
428             ret = cc.LANGUAGE_ITALIAN;
429             break;
430         case "de":
431             ret = cc.LANGUAGE_GERMAN;
432             break;
433         case "es":
434             ret = cc.LANGUAGE_SPANISH;
435             break;
436         case "ru":
437             ret = cc.LANGUAGE_RUSSIAN;
438             break;
439         case "ko":
440             ret = cc.LANGUAGE_KOREAN;
441             break;
442         case "ja":
443             ret = cc.LANGUAGE_JAPANESE;
444             break;
445         case "hu":
446             ret = cc.LANGUAGE_HUNGARIAN;
447             break;
448         case "pt":
449             ret = cc.LANGUAGE_PORTUGUESE;
450             break;
451         case "ar":
452             ret = cc.LANGUAGE_ARABIC;
453             break;
454         case "no":
455             ret = cc.LANGUAGE_NORWEGIAN;
456             break;
457         case "pl":
458             ret = cc.LANGUAGE_POLISH;
459             break;
460     }
461 
462     return ret;
463 };
464 
465 cc._sharedApplication = null;
466