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     if (element.tagName == "CANVAS") {
171         width = width || element.width;
172         height = height || element.height;
173 
174         //it is already a canvas, we wrap it around with a div
175         cc.container = cc.$new("DIV");
176         cc.canvas = element;
177         cc.canvas.parentNode.insertBefore(cc.container, cc.canvas);
178         cc.canvas.appendTo(cc.container);
179         cc.container.style.width = (width || 480) + "px";
180         cc.container.style.height = (height || 320) + "px";
181         cc.container.setAttribute('id', 'Cocos2dGameContainer');
182         cc.container.style.margin = "0 auto";
183         cc.canvas.setAttribute("width", width || 480);
184         cc.canvas.setAttribute("height", height || 320);
185     } else {//we must make a new canvas and place into this element
186         if (element.tagName != "DIV") {
187             cc.log("Warning: target element is not a DIV or CANVAS");
188         }
189         width = width || element.clientWidth;
190         height = height || element.clientHeight;
191 
192         cc.canvas = cc.$new("CANVAS");
193         cc.canvas.addClass("gameCanvas");
194         cc.canvas.setAttribute("width", width || 480);
195         cc.canvas.setAttribute("height", height || 320);
196         cc.container = element;
197         element.appendChild(cc.canvas);
198         cc.container.style.width = (width || 480) + "px";
199         cc.container.style.height = (height || 320) + "px";
200         cc.container.style.margin = "0 auto";
201     }
202     cc.container.style.position = 'relative';
203     cc.container.style.overflow = 'hidden';
204     cc.container.top = '100%';
205 
206     if(cc.__renderDoesnotSupport)
207         return;
208 
209     if (cc.Browser.supportWebGL)
210         cc.renderContext = cc.webglContext = cc.create3DContext(cc.canvas,{'stencil': true, 'preserveDrawingBuffer': true, 'alpha': false });
211     if(cc.renderContext){
212         cc.renderContextType = cc.WEBGL;
213         window.gl = cc.renderContext; // global variable declared in CCMacro.js
214         cc.drawingUtil = new cc.DrawingPrimitiveWebGL(cc.renderContext);
215         cc.TextureCache.getInstance()._initializingRenderer();
216     } else {
217         cc.renderContext = cc.canvas.getContext("2d");
218         cc.mainRenderContextBackup = cc.renderContext;
219         cc.renderContextType = cc.CANVAS;
220         cc.renderContext.translate(0, cc.canvas.height);
221         cc.drawingUtil = new cc.DrawingPrimitiveCanvas(cc.renderContext);
222     }
223 
224     cc.originalCanvasSize = cc.size(cc.canvas.width, cc.canvas.height);
225     cc.gameDiv = cc.container;
226 
227     cc.log(cc.ENGINE_VERSION);
228     cc.Configuration.getInstance();
229 
230     cc.setContextMenuEnable(false);
231 
232     if(cc.Browser.isMobile){
233         cc._addUserSelectStatus();
234         cc._addBottomTag();
235     }
236 
237     var hidden, visibilityChange;
238     if (typeof document.hidden !== "undefined") {
239         hidden = "hidden";
240         visibilityChange = "visibilitychange";
241     } else if (typeof document.mozHidden !== "undefined") {
242         hidden = "mozHidden";
243         visibilityChange = "mozvisibilitychange";
244     } else if (typeof document.msHidden !== "undefined") {
245         hidden = "msHidden";
246         visibilityChange = "msvisibilitychange";
247     } else if (typeof document.webkitHidden !== "undefined") {
248         hidden = "webkitHidden";
249         visibilityChange = "webkitvisibilitychange";
250     }
251 
252     function handleVisibilityChange() {
253         if (!document[hidden])
254             cc.Director.getInstance()._resetLastUpdate();
255     }
256 
257     if (typeof document.addEventListener === "undefined" ||
258         typeof hidden === "undefined") {
259         cc.isAddedHiddenEvent = false;
260     } else {
261         cc.isAddedHiddenEvent = true;
262         document.addEventListener(visibilityChange, handleVisibilityChange, false);
263     }
264 };
265 
266 cc._addUserSelectStatus = function(){
267     var fontStyle = document.createElement("style");
268     fontStyle.type = "text/css";
269     document.body.appendChild(fontStyle);
270 
271     fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;"
272         +"-webkit-tap-highlight-color:rgba(0,0,0,0);}";
273 };
274 
275 cc._addBottomTag = function () {
276     var bottom = document.createElement("div");
277     bottom.id = "bottom";
278     bottom.style.border = bottom.style.margin = bottom.style.padding = bottom.style.height = bottom.style.lineHeight = bottom.style.fontSize = "0px";
279     document.body.appendChild(bottom);
280     window.location.href="#bottom";
281 };
282 
283 cc._isContextMenuEnable = false;
284 /**
285  * enable/disable contextMenu for Canvas
286  * @param {Boolean} enabled
287  */
288 cc.setContextMenuEnable = function (enabled) {
289     cc._isContextMenuEnable = enabled;
290     if (!cc._isContextMenuEnable) {
291         cc.canvas.oncontextmenu = function () {
292             return false;
293         };
294     } else {
295         cc.canvas.oncontextmenu = function () {
296         };
297     }
298 };
299 
300 /**
301  * Run main loop of game engine
302  * @class
303  * @extends cc.Class
304  */
305 cc.Application = cc.Class.extend(/** @lends cc.Application# */{
306     _animationInterval:null,
307     /**
308      * Constructor
309      */
310     ctor:function () {
311         this._animationInterval = 0;
312         if(cc._sharedApplication)
313             throw "Application has been initialized";
314         cc._sharedApplication = this;
315     },
316 
317     /**
318      * Callback by cc.Director for limit FPS.
319      * @param {Number} interval The time, which expressed in second, between current frame and next.
320      */
321     setAnimationInterval:function (interval) {
322         this._animationInterval = interval;
323     },
324 
325     /**
326      *  Get status bar rectangle in EGLView window.
327      * @param {cc.Rect} rect
328      * @deprecated
329      */
330     statusBarFrame:function (rect) {
331         if (rect) {
332             // Windows doesn't have status bar.
333             rect = cc.rect(0, 0, 0, 0);
334         }
335     },
336 
337     getTargetPlatform:function(){
338         return cc.Browser.isMobile ? cc.TARGET_PLATFORM.MOBILE_BROWSER : cc.TARGET_PLATFORM.PC_BROWSER;
339     },
340 
341     /**
342      * Run the message loop.
343      * @return {Number}
344      */
345     run:function () {
346         // Initialize instance and cocos2d.
347         if (!this.applicationDidFinishLaunching())
348             return 0;
349 
350         var callback, director = cc.Director.getInstance(), w = window;
351         if (w.requestAnimFrame && this._animationInterval == 1 / 60) {
352             callback = function () {
353                 director.mainLoop();
354                 w.requestAnimFrame(callback);
355             };
356             //cc.log(window.requestAnimFrame);
357             w.requestAnimFrame(callback);
358         } else {
359             callback = function () {
360                 director.mainLoop();
361             };
362             setInterval(callback, this._animationInterval * 1000);
363         }
364         return 0;
365     }
366 });
367 
368 /**
369  * Get current application instance.
370  * @return {cc.Application}  Current application instance pointer.
371  */
372 cc.Application.getInstance = function () {
373     return cc._sharedApplication;
374 };
375 
376 /**
377  * Get current language config
378  * @return {Number} Current language config
379  */
380 cc.Application.getCurrentLanguage = function () {
381     var ret = cc.LANGUAGE_ENGLISH;
382 
383     var currentLang = navigator.language;
384     if(!currentLang)
385         currentLang = navigator.browserLanguage || navigator.userLanguage;
386     if(!currentLang)
387         return ret;
388 
389     currentLang = currentLang.toLowerCase();
390     switch (currentLang) {
391         case "zh-cn":
392             ret = cc.LANGUAGE_CHINESE;
393             break;
394         case "fr":
395             ret = cc.LANGUAGE_FRENCH;
396             break;
397         case "it":
398             ret = cc.LANGUAGE_ITALIAN;
399             break;
400         case "de":
401             ret = cc.LANGUAGE_GERMAN;
402             break;
403         case "es":
404             ret = cc.LANGUAGE_SPANISH;
405             break;
406         case "ru":
407             ret = cc.LANGUAGE_RUSSIAN;
408             break;
409         case "ko":
410             ret = cc.LANGUAGE_KOREAN;
411             break;
412         case "ja":
413             ret = cc.LANGUAGE_JAPANESE;
414             break;
415         case "hu":
416             ret = cc.LANGUAGE_HUNGARIAN;
417             break;
418         case "pt":
419             ret = cc.LANGUAGE_PORTUGUESE;
420             break;
421         case "ar":
422             ret = cc.LANGUAGE_ARABIC;
423             break;
424         case "no":
425             ret = cc.LANGUAGE_NORWEGIAN;
426             break;
427         case "pl":
428             ret = cc.LANGUAGE_POLISH;
429             break;
430     }
431 
432     return ret;
433 };
434 
435 cc._sharedApplication = null;
436