1 /**************************************************************************** 2 Copyright (c) 2008-2010 Ricardo Quesada 3 Copyright (c) 2011-2012 cocos2d-x.org 4 Copyright (c) 2013-2014 Chukong Technologies 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 * @ignore 29 */ 30 cc.Touches = []; 31 cc.TouchesIntergerDict = {}; 32 33 cc.DENSITYDPI_DEVICE = "device-dpi"; 34 cc.DENSITYDPI_HIGH = "high-dpi"; 35 cc.DENSITYDPI_MEDIUM = "medium-dpi"; 36 cc.DENSITYDPI_LOW = "low-dpi"; 37 38 cc.__BrowserGetter = { 39 init: function(){ 40 this.html = document.getElementsByTagName("html")[0]; 41 }, 42 availWidth: function(frame){ 43 if(!frame || frame === this.html) 44 return window.innerWidth; 45 else 46 return frame.clientWidth; 47 }, 48 availHeight: function(frame){ 49 if(!frame || frame === this.html) 50 return window.innerHeight; 51 else 52 return frame.clientHeight; 53 }, 54 meta: { 55 "width": "device-width", 56 "user-scalable": "no" 57 }, 58 adaptationType: cc.sys.browserType 59 }; 60 61 if(window.navigator.userAgent.indexOf("OS 8_1_") > -1) //this mistake like MIUI, so use of MIUI treatment method 62 cc.__BrowserGetter.adaptationType = cc.sys.BROWSER_TYPE_MIUI; 63 64 if(cc.sys.os === cc.sys.OS_IOS) // All browsers are WebView 65 cc.__BrowserGetter.adaptationType = cc.sys.BROWSER_TYPE_SAFARI; 66 67 switch(cc.__BrowserGetter.adaptationType){ 68 case cc.sys.BROWSER_TYPE_SAFARI: 69 cc.__BrowserGetter.meta["minimal-ui"] = "true"; 70 cc.__BrowserGetter.availWidth = function(frame){ 71 return frame.clientWidth; 72 }; 73 cc.__BrowserGetter.availHeight = function(frame){ 74 return frame.clientHeight; 75 }; 76 break; 77 case cc.sys.BROWSER_TYPE_CHROME: 78 cc.__BrowserGetter.__defineGetter__("target-densitydpi", function(){ 79 return cc.view._targetDensityDPI; 80 }); 81 case cc.sys.BROWSER_TYPE_SOUGOU: 82 case cc.sys.BROWSER_TYPE_UC: 83 cc.__BrowserGetter.availWidth = function(frame){ 84 return frame.clientWidth; 85 }; 86 cc.__BrowserGetter.availHeight = function(frame){ 87 return frame.clientHeight; 88 }; 89 break; 90 case cc.sys.BROWSER_TYPE_MIUI: 91 cc.__BrowserGetter.init = function(view){ 92 if(view.__resizeWithBrowserSize) return; 93 var resize = function(){ 94 view.setDesignResolutionSize( 95 view._designResolutionSize.width, 96 view._designResolutionSize.height, 97 view._resolutionPolicy 98 ); 99 window.removeEventListener("resize", resize, false); 100 }; 101 window.addEventListener("resize", resize, false); 102 }; 103 break; 104 } 105 106 /** 107 * cc.view is the singleton object which represents the game window.<br/> 108 * It's main task include: <br/> 109 * - Apply the design resolution policy<br/> 110 * - Provide interaction with the window, like resize event on web, retina display support, etc...<br/> 111 * - Manage the game view port which can be different with the window<br/> 112 * - Manage the content scale and translation<br/> 113 * <br/> 114 * Since the cc.view is a singleton, you don't need to call any constructor or create functions,<br/> 115 * the standard way to use it is by calling:<br/> 116 * - cc.view.methodName(); <br/> 117 * @class 118 * @name cc.view 119 * @extend cc.Class 120 */ 121 cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ 122 _delegate: null, 123 // Size of parent node that contains cc.container and cc._canvas 124 _frameSize: null, 125 // resolution size, it is the size appropriate for the app resources. 126 _designResolutionSize: null, 127 _originalDesignResolutionSize: null, 128 // Viewport is the container's rect related to content's coordinates in pixel 129 _viewPortRect: null, 130 // The visible rect in content's coordinate in point 131 _visibleRect: null, 132 _retinaEnabled: false, 133 _autoFullScreen: true, 134 // The device's pixel ratio (for retina displays) 135 _devicePixelRatio: 1, 136 // the view name 137 _viewName: "", 138 // Custom callback for resize event 139 _resizeCallback: null, 140 _scaleX: 1, 141 _originalScaleX: 1, 142 _scaleY: 1, 143 _originalScaleY: 1, 144 _indexBitsUsed: 0, 145 _maxTouches: 5, 146 _resolutionPolicy: null, 147 _rpExactFit: null, 148 _rpShowAll: null, 149 _rpNoBorder: null, 150 _rpFixedHeight: null, 151 _rpFixedWidth: null, 152 _initialized: false, 153 154 _captured: false, 155 _wnd: null, 156 _hDC: null, 157 _hRC: null, 158 _supportTouch: false, 159 _contentTranslateLeftTop: null, 160 161 // Parent node that contains cc.container and cc._canvas 162 _frame: null, 163 _frameZoomFactor: 1.0, 164 __resizeWithBrowserSize: false, 165 _isAdjustViewPort: true, 166 _targetDensityDPI: null, 167 168 /** 169 * Constructor of cc.EGLView 170 */ 171 ctor: function () { 172 var _t = this, d = document, _strategyer = cc.ContainerStrategy, _strategy = cc.ContentStrategy; 173 174 cc.__BrowserGetter.init(this); 175 176 _t._frame = (cc.container.parentNode === d.body) ? d.documentElement : cc.container.parentNode; 177 _t._frameSize = cc.size(0, 0); 178 _t._initFrameSize(); 179 180 var w = cc._canvas.width, h = cc._canvas.height; 181 _t._designResolutionSize = cc.size(w, h); 182 _t._originalDesignResolutionSize = cc.size(w, h); 183 _t._viewPortRect = cc.rect(0, 0, w, h); 184 _t._visibleRect = cc.rect(0, 0, w, h); 185 _t._contentTranslateLeftTop = {left: 0, top: 0}; 186 _t._viewName = "Cocos2dHTML5"; 187 188 var sys = cc.sys; 189 _t.enableRetina(sys.os === sys.OS_IOS || sys.os === sys.OS_OSX); 190 cc.visibleRect && cc.visibleRect.init(_t._visibleRect); 191 192 // Setup system default resolution policies 193 _t._rpExactFit = new cc.ResolutionPolicy(_strategyer.EQUAL_TO_FRAME, _strategy.EXACT_FIT); 194 _t._rpShowAll = new cc.ResolutionPolicy(_strategyer.PROPORTION_TO_FRAME, _strategy.SHOW_ALL); 195 _t._rpNoBorder = new cc.ResolutionPolicy(_strategyer.EQUAL_TO_FRAME, _strategy.NO_BORDER); 196 _t._rpFixedHeight = new cc.ResolutionPolicy(_strategyer.EQUAL_TO_FRAME, _strategy.FIXED_HEIGHT); 197 _t._rpFixedWidth = new cc.ResolutionPolicy(_strategyer.EQUAL_TO_FRAME, _strategy.FIXED_WIDTH); 198 199 _t._hDC = cc._canvas; 200 _t._hRC = cc._renderContext; 201 _t._targetDensityDPI = cc.DENSITYDPI_HIGH; 202 }, 203 204 // Resize helper functions 205 _resizeEvent: function () { 206 var view; 207 if(this.setDesignResolutionSize){ 208 view = this; 209 }else{ 210 view = cc.view; 211 } 212 213 // Check frame size changed or not 214 var prevFrameW = view._frameSize.width, prevFrameH = view._frameSize.height; 215 view._initFrameSize(); 216 if (view._frameSize.width === prevFrameW && view._frameSize.height === prevFrameH) 217 return; 218 219 // Frame size changed, do resize works 220 if (view._resizeCallback) { 221 view._resizeCallback.call(); 222 } 223 var width = view._originalDesignResolutionSize.width; 224 var height = view._originalDesignResolutionSize.height; 225 if (width > 0) 226 view.setDesignResolutionSize(width, height, view._resolutionPolicy); 227 }, 228 229 /** 230 * <p> 231 * Sets view's target-densitydpi for android mobile browser. it can be set to: <br/> 232 * 1. cc.DENSITYDPI_DEVICE, value is "device-dpi" <br/> 233 * 2. cc.DENSITYDPI_HIGH, value is "high-dpi" (default value) <br/> 234 * 3. cc.DENSITYDPI_MEDIUM, value is "medium-dpi" (browser's default value) <br/> 235 * 4. cc.DENSITYDPI_LOW, value is "low-dpi" <br/> 236 * 5. Custom value, e.g: "480" <br/> 237 * </p> 238 * @param {String} densityDPI 239 */ 240 setTargetDensityDPI: function(densityDPI){ 241 this._targetDensityDPI = densityDPI; 242 this._setViewPortMeta(); 243 }, 244 245 /** 246 * Returns the current target-densitydpi value of cc.view. 247 * @returns {String} 248 */ 249 getTargetDensityDPI: function(){ 250 return this._targetDensityDPI; 251 }, 252 253 /** 254 * Sets whether resize canvas automatically when browser's size changed.<br/> 255 * Useful only on web. 256 * @param {Boolean} enabled Whether enable automatic resize with browser's resize event 257 */ 258 resizeWithBrowserSize: function (enabled) { 259 if (enabled) { 260 //enable 261 if (!this.__resizeWithBrowserSize) { 262 this.__resizeWithBrowserSize = true; 263 cc._addEventListener(window, 'resize', this._resizeEvent); 264 cc._addEventListener(window, 'orientationchange', this._resizeEvent); 265 } 266 } else { 267 //disable 268 if (this.__resizeWithBrowserSize) { 269 this.__resizeWithBrowserSize = false; 270 window.removeEventListener('resize', this._resizeEvent); 271 window.removeEventListener('orientationchange', this._resizeEvent); 272 } 273 } 274 }, 275 276 /** 277 * Sets the callback function for cc.view's resize action,<br/> 278 * this callback will be invoked before applying resolution policy, <br/> 279 * so you can do any additional modifications within the callback.<br/> 280 * Useful only on web. 281 * @param {Function|null} callback The callback function 282 */ 283 setResizeCallback: function (callback) { 284 if (cc.isFunction(callback) || callback == null) { 285 this._resizeCallback = callback; 286 } 287 }, 288 289 _initFrameSize: function () { 290 var locFrameSize = this._frameSize; 291 locFrameSize.width = cc.__BrowserGetter.availWidth(this._frame); 292 locFrameSize.height = cc.__BrowserGetter.availHeight(this._frame); 293 }, 294 295 // hack 296 _adjustSizeKeepCanvasSize: function () { 297 var designWidth = this._originalDesignResolutionSize.width; 298 var designHeight = this._originalDesignResolutionSize.height; 299 if (designWidth > 0) 300 this.setDesignResolutionSize(designWidth, designHeight, this._resolutionPolicy); 301 }, 302 303 _setViewPortMeta: function () { 304 if (this._isAdjustViewPort) { 305 var vp = document.getElementById("cocosMetaElement"); 306 if(vp){ 307 document.head.removeChild(vp); 308 } 309 310 var viewportMetas, 311 elems = document.getElementsByName("viewport"), 312 currentVP = elems ? elems[0] : null, 313 content; 314 315 vp = cc.newElement("meta"); 316 vp.id = "cocosMetaElement"; 317 vp.name = "viewport"; 318 vp.content = ""; 319 320 viewportMetas = cc.__BrowserGetter.meta; 321 322 content = currentVP ? currentVP.content : ""; 323 for (var key in viewportMetas) { 324 var pattern = new RegExp(key); 325 if (!pattern.test(content)) { 326 content += "," + key + "=" + viewportMetas[key]; 327 } 328 } 329 if(/^,/.test(content)) 330 content = content.substr(1); 331 332 vp.content = content; 333 // For adopting certain android devices which don't support second viewport 334 if (currentVP) 335 currentVP.content = content; 336 337 document.head.appendChild(vp); 338 } 339 }, 340 341 // RenderTexture hacker 342 _setScaleXYForRenderTexture: function () { 343 //hack for RenderTexture on canvas mode when adapting multiple resolution resources 344 var scaleFactor = cc.contentScaleFactor(); 345 this._scaleX = scaleFactor; 346 this._scaleY = scaleFactor; 347 }, 348 349 // Other helper functions 350 _resetScale: function () { 351 this._scaleX = this._originalScaleX; 352 this._scaleY = this._originalScaleY; 353 }, 354 355 // Useless, just make sure the compatibility temporarily, should be removed 356 _adjustSizeToBrowser: function () { 357 }, 358 359 initialize: function () { 360 this._initialized = true; 361 }, 362 363 /** 364 * Sets whether the engine modify the "viewport" meta in your web page.<br/> 365 * It's enabled by default, we strongly suggest you not to disable it.<br/> 366 * And even when it's enabled, you can still set your own "viewport" meta, it won't be overridden<br/> 367 * Only useful on web 368 * @param {Boolean} enabled Enable automatic modification to "viewport" meta 369 */ 370 adjustViewPort: function (enabled) { 371 this._isAdjustViewPort = enabled; 372 }, 373 374 /** 375 * Retina support is enabled by default for Apple device but disabled for other devices,<br/> 376 * it takes effect only when you called setDesignResolutionPolicy<br/> 377 * Only useful on web 378 * @param {Boolean} enabled Enable or disable retina display 379 */ 380 enableRetina: function(enabled) { 381 this._retinaEnabled = enabled ? true : false; 382 }, 383 384 /** 385 * Check whether retina display is enabled.<br/> 386 * Only useful on web 387 * @return {Boolean} 388 */ 389 isRetinaEnabled: function() { 390 return this._retinaEnabled; 391 }, 392 393 /** 394 * If enabled, the application will try automatically to enter full screen mode on mobile devices<br/> 395 * You can pass true as parameter to enable it and disable it by passing false.<br/> 396 * Only useful on web 397 * @param {Boolean} enabled Enable or disable auto full screen on mobile devices 398 */ 399 enableAutoFullScreen: function(enabled) { 400 this._autoFullScreen = enabled ? true : false; 401 }, 402 403 /** 404 * Check whether auto full screen is enabled.<br/> 405 * Only useful on web 406 * @return {Boolean} Auto full screen enabled or not 407 */ 408 isAutoFullScreenEnabled: function() { 409 return this._autoFullScreen; 410 }, 411 412 /** 413 * Force destroying EGL view, subclass must implement this method. 414 */ 415 end: function () { 416 }, 417 418 /** 419 * Get whether render system is ready(no matter opengl or canvas),<br/> 420 * this name is for the compatibility with cocos2d-x, subclass must implement this method. 421 * @return {Boolean} 422 */ 423 isOpenGLReady: function () { 424 return (this._hDC !== null && this._hRC !== null); 425 }, 426 427 /* 428 * Set zoom factor for frame. This method is for debugging big resolution (e.g.new ipad) app on desktop. 429 * @param {Number} zoomFactor 430 */ 431 setFrameZoomFactor: function (zoomFactor) { 432 this._frameZoomFactor = zoomFactor; 433 this.centerWindow(); 434 cc.director.setProjection(cc.director.getProjection()); 435 }, 436 437 /** 438 * Exchanges the front and back buffers, subclass must implement this method. 439 */ 440 swapBuffers: function () { 441 }, 442 443 /** 444 * Open or close IME keyboard , subclass must implement this method. 445 * @param {Boolean} isOpen 446 */ 447 setIMEKeyboardState: function (isOpen) { 448 }, 449 450 /** 451 * Sets the resolution translate on EGLView 452 * @param {Number} offsetLeft 453 * @param {Number} offsetTop 454 */ 455 setContentTranslateLeftTop: function (offsetLeft, offsetTop) { 456 this._contentTranslateLeftTop = {left: offsetLeft, top: offsetTop}; 457 }, 458 459 /** 460 * Returns the resolution translate on EGLView 461 * @return {cc.Size|Object} 462 */ 463 getContentTranslateLeftTop: function () { 464 return this._contentTranslateLeftTop; 465 }, 466 467 /** 468 * Returns the frame size of the view.<br/> 469 * On native platforms, it returns the screen size since the view is a fullscreen view.<br/> 470 * On web, it returns the size of the canvas's outer DOM element. 471 * @return {cc.Size} 472 */ 473 getFrameSize: function () { 474 return cc.size(this._frameSize.width, this._frameSize.height); 475 }, 476 477 /** 478 * On native, it sets the frame size of view.<br/> 479 * On web, it sets the size of the canvas's outer DOM element. 480 * @param {Number} width 481 * @param {Number} height 482 */ 483 setFrameSize: function (width, height) { 484 this._frameSize.width = width; 485 this._frameSize.height = height; 486 this._frame.style.width = width + "px"; 487 this._frame.style.height = height + "px"; 488 //this.centerWindow(); 489 this._resizeEvent(); 490 cc.director.setProjection(cc.director.getProjection()); 491 }, 492 493 /** 494 * Empty function 495 */ 496 centerWindow: function () { 497 }, 498 499 /** 500 * Returns the visible area size of the view port. 501 * @return {cc.Size} 502 */ 503 getVisibleSize: function () { 504 return cc.size(this._visibleRect.width,this._visibleRect.height); 505 }, 506 507 /** 508 * Returns the visible origin of the view port. 509 * @return {cc.Point} 510 */ 511 getVisibleOrigin: function () { 512 return cc.p(this._visibleRect.x,this._visibleRect.y); 513 }, 514 515 /** 516 * Returns whether developer can set content's scale factor. 517 * @return {Boolean} 518 */ 519 canSetContentScaleFactor: function () { 520 return true; 521 }, 522 523 /** 524 * Returns the current resolution policy 525 * @see cc.ResolutionPolicy 526 * @return {cc.ResolutionPolicy} 527 */ 528 getResolutionPolicy: function () { 529 return this._resolutionPolicy; 530 }, 531 532 /** 533 * Sets the current resolution policy 534 * @see cc.ResolutionPolicy 535 * @param {cc.ResolutionPolicy|Number} resolutionPolicy 536 */ 537 setResolutionPolicy: function (resolutionPolicy) { 538 var _t = this; 539 if (resolutionPolicy instanceof cc.ResolutionPolicy) { 540 _t._resolutionPolicy = resolutionPolicy; 541 } 542 // Ensure compatibility with JSB 543 else { 544 var _locPolicy = cc.ResolutionPolicy; 545 if(resolutionPolicy === _locPolicy.EXACT_FIT) 546 _t._resolutionPolicy = _t._rpExactFit; 547 if(resolutionPolicy === _locPolicy.SHOW_ALL) 548 _t._resolutionPolicy = _t._rpShowAll; 549 if(resolutionPolicy === _locPolicy.NO_BORDER) 550 _t._resolutionPolicy = _t._rpNoBorder; 551 if(resolutionPolicy === _locPolicy.FIXED_HEIGHT) 552 _t._resolutionPolicy = _t._rpFixedHeight; 553 if(resolutionPolicy === _locPolicy.FIXED_WIDTH) 554 _t._resolutionPolicy = _t._rpFixedWidth; 555 } 556 }, 557 558 /** 559 * Sets the resolution policy with designed view size in points.<br/> 560 * The resolution policy include: <br/> 561 * [1] ResolutionExactFit Fill screen by stretch-to-fit: if the design resolution ratio of width to height is different from the screen resolution ratio, your game view will be stretched.<br/> 562 * [2] ResolutionNoBorder Full screen without black border: if the design resolution ratio of width to height is different from the screen resolution ratio, two areas of your game view will be cut.<br/> 563 * [3] ResolutionShowAll Full screen with black border: if the design resolution ratio of width to height is different from the screen resolution ratio, two black borders will be shown.<br/> 564 * [4] ResolutionFixedHeight Scale the content's height to screen's height and proportionally scale its width<br/> 565 * [5] ResolutionFixedWidth Scale the content's width to screen's width and proportionally scale its height<br/> 566 * [cc.ResolutionPolicy] [Web only feature] Custom resolution policy, constructed by cc.ResolutionPolicy<br/> 567 * @param {Number} width Design resolution width. 568 * @param {Number} height Design resolution height. 569 * @param {cc.ResolutionPolicy|Number} resolutionPolicy The resolution policy desired 570 */ 571 setDesignResolutionSize: function (width, height, resolutionPolicy) { 572 // Defensive code 573 if( !(width > 0 || height > 0) ){ 574 cc.log(cc._LogInfos.EGLView_setDesignResolutionSize); 575 return; 576 } 577 578 this.setResolutionPolicy(resolutionPolicy); 579 var policy = this._resolutionPolicy; 580 if (!policy){ 581 cc.log(cc._LogInfos.EGLView_setDesignResolutionSize_2); 582 return; 583 } 584 policy.preApply(this); 585 586 // Reinit frame size 587 if(cc.sys.isMobile) 588 this._setViewPortMeta(); 589 590 this._initFrameSize(); 591 592 this._originalDesignResolutionSize.width = this._designResolutionSize.width = width; 593 this._originalDesignResolutionSize.height = this._designResolutionSize.height = height; 594 595 var result = policy.apply(this, this._designResolutionSize); 596 597 if(result.scale && result.scale.length === 2){ 598 this._scaleX = result.scale[0]; 599 this._scaleY = result.scale[1]; 600 } 601 602 if(result.viewport){ 603 var vp = this._viewPortRect, 604 vb = this._visibleRect, 605 rv = result.viewport; 606 607 vp.x = rv.x; 608 vp.y = rv.y; 609 vp.width = rv.width; 610 vp.height = rv.height; 611 612 vb.x = -vp.x / this._scaleX; 613 vb.y = -vp.y / this._scaleY; 614 vb.width = cc._canvas.width / this._scaleX; 615 vb.height = cc._canvas.height / this._scaleY; 616 cc._renderContext.setOffset && cc._renderContext.setOffset(vp.x, -vp.y) 617 } 618 619 // reset director's member variables to fit visible rect 620 var director = cc.director; 621 director._winSizeInPoints.width = this._designResolutionSize.width; 622 director._winSizeInPoints.height = this._designResolutionSize.height; 623 policy.postApply(this); 624 cc.winSize.width = director._winSizeInPoints.width; 625 cc.winSize.height = director._winSizeInPoints.height; 626 627 if (cc._renderType === cc._RENDER_TYPE_WEBGL) { 628 // reset director's member variables to fit visible rect 629 director._createStatsLabel(); 630 director.setGLDefaultValues(); 631 } 632 633 this._originalScaleX = this._scaleX; 634 this._originalScaleY = this._scaleY; 635 // For editbox 636 if (cc.DOM) 637 cc.DOM._resetEGLViewDiv(); 638 cc.visibleRect && cc.visibleRect.init(this._visibleRect); 639 }, 640 641 /** 642 * Returns the designed size for the view. 643 * Default resolution size is the same as 'getFrameSize'. 644 * @return {cc.Size} 645 */ 646 getDesignResolutionSize: function () { 647 return cc.size(this._designResolutionSize.width, this._designResolutionSize.height); 648 }, 649 650 /** 651 * Sets view port rectangle with points. 652 * @param {Number} x 653 * @param {Number} y 654 * @param {Number} w width 655 * @param {Number} h height 656 */ 657 setViewPortInPoints: function (x, y, w, h) { 658 var locFrameZoomFactor = this._frameZoomFactor, locScaleX = this._scaleX, locScaleY = this._scaleY; 659 cc._renderContext.viewport((x * locScaleX * locFrameZoomFactor + this._viewPortRect.x * locFrameZoomFactor), 660 (y * locScaleY * locFrameZoomFactor + this._viewPortRect.y * locFrameZoomFactor), 661 (w * locScaleX * locFrameZoomFactor), 662 (h * locScaleY * locFrameZoomFactor)); 663 }, 664 665 /** 666 * Sets Scissor rectangle with points. 667 * @param {Number} x 668 * @param {Number} y 669 * @param {Number} w 670 * @param {Number} h 671 */ 672 setScissorInPoints: function (x, y, w, h) { 673 var locFrameZoomFactor = this._frameZoomFactor, locScaleX = this._scaleX, locScaleY = this._scaleY; 674 cc._renderContext.scissor((x * locScaleX * locFrameZoomFactor + this._viewPortRect.x * locFrameZoomFactor), 675 (y * locScaleY * locFrameZoomFactor + this._viewPortRect.y * locFrameZoomFactor), 676 (w * locScaleX * locFrameZoomFactor), 677 (h * locScaleY * locFrameZoomFactor)); 678 }, 679 680 /** 681 * Returns whether GL_SCISSOR_TEST is enable 682 * @return {Boolean} 683 */ 684 isScissorEnabled: function () { 685 var gl = cc._renderContext; 686 return gl.isEnabled(gl.SCISSOR_TEST); 687 }, 688 689 /** 690 * Returns the current scissor rectangle 691 * @return {cc.Rect} 692 */ 693 getScissorRect: function () { 694 var gl = cc._renderContext, scaleX = this._scaleX, scaleY = this._scaleY; 695 var boxArr = gl.getParameter(gl.SCISSOR_BOX); 696 return cc.rect((boxArr[0] - this._viewPortRect.x) / scaleX, (boxArr[1] - this._viewPortRect.y) / scaleY, 697 boxArr[2] / scaleX, boxArr[3] / scaleY); 698 }, 699 700 /** 701 * Sets the name of the view 702 * @param {String} viewName 703 */ 704 setViewName: function (viewName) { 705 if (viewName != null && viewName.length > 0) { 706 this._viewName = viewName; 707 } 708 }, 709 710 /** 711 * Returns the name of the view 712 * @return {String} 713 */ 714 getViewName: function () { 715 return this._viewName; 716 }, 717 718 /** 719 * Returns the view port rectangle. 720 * @return {cc.Rect} 721 */ 722 getViewPortRect: function () { 723 return this._viewPortRect; 724 }, 725 726 /** 727 * Returns scale factor of the horizontal direction (X axis). 728 * @return {Number} 729 */ 730 getScaleX: function () { 731 return this._scaleX; 732 }, 733 734 /** 735 * Returns scale factor of the vertical direction (Y axis). 736 * @return {Number} 737 */ 738 getScaleY: function () { 739 return this._scaleY; 740 }, 741 742 /** 743 * Returns device pixel ratio for retina display. 744 * @return {Number} 745 */ 746 getDevicePixelRatio: function() { 747 return this._devicePixelRatio; 748 }, 749 750 /** 751 * Returns the real location in view for a translation based on a related position 752 * @param {Number} tx The X axis translation 753 * @param {Number} ty The Y axis translation 754 * @param {Object} relatedPos The related position object including "left", "top", "width", "height" informations 755 * @return {cc.Point} 756 */ 757 convertToLocationInView: function (tx, ty, relatedPos) { 758 return {x: this._devicePixelRatio * (tx - relatedPos.left), y: this._devicePixelRatio * (relatedPos.top + relatedPos.height - ty)}; 759 }, 760 761 _convertMouseToLocationInView: function(point, relatedPos) { 762 var locViewPortRect = this._viewPortRect, _t = this; 763 point.x = ((_t._devicePixelRatio * (point.x - relatedPos.left)) - locViewPortRect.x) / _t._scaleX; 764 point.y = (_t._devicePixelRatio * (relatedPos.top + relatedPos.height - point.y) - locViewPortRect.y) / _t._scaleY; 765 }, 766 767 _convertTouchesWithScale: function(touches){ 768 var locViewPortRect = this._viewPortRect, locScaleX = this._scaleX, locScaleY = this._scaleY, selTouch, selPoint, selPrePoint; 769 for( var i = 0; i < touches.length; i ++){ 770 selTouch = touches[i]; 771 selPoint = selTouch._point; 772 selPrePoint = selTouch._prevPoint; 773 selTouch._setPoint((selPoint.x - locViewPortRect.x) / locScaleX, 774 (selPoint.y - locViewPortRect.y) / locScaleY); 775 selTouch._setPrevPoint((selPrePoint.x - locViewPortRect.x) / locScaleX, 776 (selPrePoint.y - locViewPortRect.y) / locScaleY); 777 } 778 } 779 }); 780 781 /** 782 * @function 783 * @return {cc.EGLView} 784 * @private 785 */ 786 cc.EGLView._getInstance = function () { 787 if (!this._instance) { 788 this._instance = this._instance || new cc.EGLView(); 789 this._instance.initialize(); 790 } 791 return this._instance; 792 }; 793 794 /** 795 * <p>cc.ContainerStrategy class is the root strategy class of container's scale strategy, 796 * it controls the behavior of how to scale the cc.container and cc._canvas object</p> 797 * 798 * @class 799 * @extends cc.Class 800 */ 801 cc.ContainerStrategy = cc.Class.extend(/** @lends cc.ContainerStrategy# */{ 802 /** 803 * Manipulation before appling the strategy 804 * @param {cc.view} The target view 805 */ 806 preApply: function (view) { 807 }, 808 809 /** 810 * Function to apply this strategy 811 * @param {cc.view} view 812 * @param {cc.Size} designedResolution 813 */ 814 apply: function (view, designedResolution) { 815 }, 816 817 /** 818 * Manipulation after applying the strategy 819 * @param {cc.view} view The target view 820 */ 821 postApply: function (view) { 822 823 }, 824 825 _setupContainer: function (view, w, h) { 826 var frame = view._frame; 827 if (cc.view._autoFullScreen && cc.sys.isMobile && frame === document.documentElement) { 828 // Automatically full screen when user touches on mobile version 829 cc.screen.autoFullScreen(frame); 830 } 831 832 var locCanvasElement = cc._canvas, locContainer = cc.container; 833 // Setup container 834 locContainer.style.width = locCanvasElement.style.width = w + "px"; 835 locContainer.style.height = locCanvasElement.style.height = h + "px"; 836 // Setup pixel ratio for retina display 837 var devicePixelRatio = view._devicePixelRatio = 1; 838 if (view.isRetinaEnabled()) 839 devicePixelRatio = view._devicePixelRatio = window.devicePixelRatio || 1; 840 // Setup canvas 841 locCanvasElement.width = w * devicePixelRatio; 842 locCanvasElement.height = h * devicePixelRatio; 843 cc._renderContext.resetCache && cc._renderContext.resetCache(); 844 845 var body = document.body, style; 846 if (body && (style = body.style)) { 847 style.paddingTop = style.paddingTop || "0px"; 848 style.paddingRight = style.paddingRight || "0px"; 849 style.paddingBottom = style.paddingBottom || "0px"; 850 style.paddingLeft = style.paddingLeft || "0px"; 851 style.borderTop = style.borderTop || "0px"; 852 style.borderRight = style.borderRight || "0px"; 853 style.borderBottom = style.borderBottom || "0px"; 854 style.borderLeft = style.borderLeft || "0px"; 855 style.marginTop = style.marginTop || "0px"; 856 style.marginRight = style.marginRight || "0px"; 857 style.marginBottom = style.marginBottom || "0px"; 858 style.marginLeft = style.marginLeft || "0px"; 859 } 860 }, 861 862 _fixContainer: function () { 863 // Add container to document body 864 document.body.insertBefore(cc.container, document.body.firstChild); 865 // Set body's width height to window's size, and forbid overflow, so that game will be centered 866 var bs = document.body.style; 867 bs.width = window.innerWidth + "px"; 868 bs.height = window.innerHeight + "px"; 869 bs.overflow = "hidden"; 870 // Body size solution doesn't work on all mobile browser so this is the aleternative: fixed container 871 var contStyle = cc.container.style; 872 contStyle.position = "fixed"; 873 contStyle.left = contStyle.top = "0px"; 874 // Reposition body 875 document.body.scrollTop = 0; 876 } 877 }); 878 879 /** 880 * <p>cc.ContentStrategy class is the root strategy class of content's scale strategy, 881 * it controls the behavior of how to scale the scene and setup the viewport for the game</p> 882 * 883 * @class 884 * @extends cc.Class 885 */ 886 cc.ContentStrategy = cc.Class.extend(/** @lends cc.ContentStrategy# */{ 887 888 _result: { 889 scale: [1, 1], 890 viewport: null 891 }, 892 893 _buildResult: function (containerW, containerH, contentW, contentH, scaleX, scaleY) { 894 // Makes content fit better the canvas 895 Math.abs(containerW - contentW) < 2 && (contentW = containerW); 896 Math.abs(containerH - contentH) < 2 && (contentH = containerH); 897 898 var viewport = cc.rect(Math.round((containerW - contentW) / 2), 899 Math.round((containerH - contentH) / 2), 900 contentW, contentH); 901 902 // Translate the content 903 if (cc._renderType === cc._RENDER_TYPE_CANVAS){ 904 //TODO: modify something for setTransform 905 //cc._renderContext.translate(viewport.x, viewport.y + contentH); 906 } 907 908 this._result.scale = [scaleX, scaleY]; 909 this._result.viewport = viewport; 910 return this._result; 911 }, 912 913 /** 914 * Manipulation before applying the strategy 915 * @param {cc.view} view The target view 916 */ 917 preApply: function (view) { 918 }, 919 920 /** 921 * Function to apply this strategy 922 * The return value is {scale: [scaleX, scaleY], viewport: {cc.Rect}}, 923 * The target view can then apply these value to itself, it's preferred not to modify directly its private variables 924 * @param {cc.view} view 925 * @param {cc.Size} designedResolution 926 * @return {object} scaleAndViewportRect 927 */ 928 apply: function (view, designedResolution) { 929 return {"scale": [1, 1]}; 930 }, 931 932 /** 933 * Manipulation after applying the strategy 934 * @param {cc.view} view The target view 935 */ 936 postApply: function (view) { 937 } 938 }); 939 940 (function () { 941 942 // Container scale strategys 943 /** 944 * @class 945 * @extends cc.ContainerStrategy 946 */ 947 var EqualToFrame = cc.ContainerStrategy.extend({ 948 apply: function (view) { 949 this._setupContainer(view, view._frameSize.width, view._frameSize.height); 950 } 951 }); 952 953 /** 954 * @class 955 * @extends cc.ContainerStrategy 956 */ 957 var ProportionalToFrame = cc.ContainerStrategy.extend({ 958 apply: function (view, designedResolution) { 959 var frameW = view._frameSize.width, frameH = view._frameSize.height, containerStyle = cc.container.style, 960 designW = designedResolution.width, designH = designedResolution.height, 961 scaleX = frameW / designW, scaleY = frameH / designH, 962 containerW, containerH; 963 964 scaleX < scaleY ? (containerW = frameW, containerH = designH * scaleX) : (containerW = designW * scaleY, containerH = frameH); 965 966 // Adjust container size with integer value 967 var offx = Math.round((frameW - containerW) / 2); 968 var offy = Math.round((frameH - containerH) / 2); 969 containerW = frameW - 2 * offx; 970 containerH = frameH - 2 * offy; 971 972 this._setupContainer(view, containerW, containerH); 973 // Setup container's margin 974 containerStyle.marginLeft = offx + "px"; 975 containerStyle.marginRight = offx + "px"; 976 containerStyle.marginTop = offy + "px"; 977 containerStyle.marginBottom = offy + "px"; 978 } 979 }); 980 981 /** 982 * @class 983 * @extends EqualToFrame 984 */ 985 var EqualToWindow = EqualToFrame.extend({ 986 preApply: function (view) { 987 this._super(view); 988 view._frame = document.documentElement; 989 }, 990 991 apply: function (view) { 992 this._super(view); 993 this._fixContainer(); 994 } 995 }); 996 997 /** 998 * @class 999 * @extends ProportionalToFrame 1000 */ 1001 var ProportionalToWindow = ProportionalToFrame.extend({ 1002 preApply: function (view) { 1003 this._super(view); 1004 view._frame = document.documentElement; 1005 }, 1006 1007 apply: function (view, designedResolution) { 1008 this._super(view, designedResolution); 1009 this._fixContainer(); 1010 } 1011 }); 1012 1013 /** 1014 * @class 1015 * @extends cc.ContainerStrategy 1016 */ 1017 var OriginalContainer = cc.ContainerStrategy.extend({ 1018 apply: function (view) { 1019 this._setupContainer(view, cc._canvas.width, cc._canvas.height); 1020 } 1021 }); 1022 1023 // #NOT STABLE on Android# Alias: Strategy that makes the container's size equals to the window's size 1024 // cc.ContainerStrategy.EQUAL_TO_WINDOW = new EqualToWindow(); 1025 // #NOT STABLE on Android# Alias: Strategy that scale proportionally the container's size to window's size 1026 // cc.ContainerStrategy.PROPORTION_TO_WINDOW = new ProportionalToWindow(); 1027 // Alias: Strategy that makes the container's size equals to the frame's size 1028 cc.ContainerStrategy.EQUAL_TO_FRAME = new EqualToFrame(); 1029 // Alias: Strategy that scale proportionally the container's size to frame's size 1030 cc.ContainerStrategy.PROPORTION_TO_FRAME = new ProportionalToFrame(); 1031 // Alias: Strategy that keeps the original container's size 1032 cc.ContainerStrategy.ORIGINAL_CONTAINER = new OriginalContainer(); 1033 1034 // Content scale strategys 1035 var ExactFit = cc.ContentStrategy.extend({ 1036 apply: function (view, designedResolution) { 1037 var containerW = cc._canvas.width, containerH = cc._canvas.height, 1038 scaleX = containerW / designedResolution.width, scaleY = containerH / designedResolution.height; 1039 1040 return this._buildResult(containerW, containerH, containerW, containerH, scaleX, scaleY); 1041 } 1042 }); 1043 1044 var ShowAll = cc.ContentStrategy.extend({ 1045 apply: function (view, designedResolution) { 1046 var containerW = cc._canvas.width, containerH = cc._canvas.height, 1047 designW = designedResolution.width, designH = designedResolution.height, 1048 scaleX = containerW / designW, scaleY = containerH / designH, scale = 0, 1049 contentW, contentH; 1050 1051 scaleX < scaleY ? (scale = scaleX, contentW = containerW, contentH = designH * scale) 1052 : (scale = scaleY, contentW = designW * scale, contentH = containerH); 1053 1054 return this._buildResult(containerW, containerH, contentW, contentH, scale, scale); 1055 } 1056 }); 1057 1058 var NoBorder = cc.ContentStrategy.extend({ 1059 apply: function (view, designedResolution) { 1060 var containerW = cc._canvas.width, containerH = cc._canvas.height, 1061 designW = designedResolution.width, designH = designedResolution.height, 1062 scaleX = containerW / designW, scaleY = containerH / designH, scale, 1063 contentW, contentH; 1064 1065 scaleX < scaleY ? (scale = scaleY, contentW = designW * scale, contentH = containerH) 1066 : (scale = scaleX, contentW = containerW, contentH = designH * scale); 1067 1068 return this._buildResult(containerW, containerH, contentW, contentH, scale, scale); 1069 } 1070 }); 1071 1072 var FixedHeight = cc.ContentStrategy.extend({ 1073 apply: function (view, designedResolution) { 1074 var containerW = cc._canvas.width, containerH = cc._canvas.height, 1075 designH = designedResolution.height, scale = containerH / designH, 1076 contentW = containerW, contentH = containerH; 1077 1078 return this._buildResult(containerW, containerH, contentW, contentH, scale, scale); 1079 }, 1080 1081 postApply: function (view) { 1082 cc.director._winSizeInPoints = view.getVisibleSize(); 1083 } 1084 }); 1085 1086 var FixedWidth = cc.ContentStrategy.extend({ 1087 apply: function (view, designedResolution) { 1088 var containerW = cc._canvas.width, containerH = cc._canvas.height, 1089 designW = designedResolution.width, scale = containerW / designW, 1090 contentW = containerW, contentH = containerH; 1091 1092 return this._buildResult(containerW, containerH, contentW, contentH, scale, scale); 1093 }, 1094 1095 postApply: function (view) { 1096 cc.director._winSizeInPoints = view.getVisibleSize(); 1097 } 1098 }); 1099 1100 // Alias: Strategy to scale the content's size to container's size, non proportional 1101 cc.ContentStrategy.EXACT_FIT = new ExactFit(); 1102 // Alias: Strategy to scale the content's size proportionally to maximum size and keeps the whole content area to be visible 1103 cc.ContentStrategy.SHOW_ALL = new ShowAll(); 1104 // Alias: Strategy to scale the content's size proportionally to fill the whole container area 1105 cc.ContentStrategy.NO_BORDER = new NoBorder(); 1106 // Alias: Strategy to scale the content's height to container's height and proportionally scale its width 1107 cc.ContentStrategy.FIXED_HEIGHT = new FixedHeight(); 1108 // Alias: Strategy to scale the content's width to container's width and proportionally scale its height 1109 cc.ContentStrategy.FIXED_WIDTH = new FixedWidth(); 1110 1111 })(); 1112 1113 /** 1114 * <p>cc.ResolutionPolicy class is the root strategy class of scale strategy, 1115 * its main task is to maintain the compatibility with Cocos2d-x</p> 1116 * 1117 * @class 1118 * @extends cc.Class 1119 * @param {cc.ContainerStrategy} containerStg The container strategy 1120 * @param {cc.ContentStrategy} contentStg The content strategy 1121 */ 1122 cc.ResolutionPolicy = cc.Class.extend(/** @lends cc.ResolutionPolicy# */{ 1123 _containerStrategy: null, 1124 _contentStrategy: null, 1125 1126 /** 1127 * Constructor of cc.ResolutionPolicy 1128 * @param {cc.ContainerStrategy} containerStg 1129 * @param {cc.ContentStrategy} contentStg 1130 */ 1131 ctor: function (containerStg, contentStg) { 1132 this.setContainerStrategy(containerStg); 1133 this.setContentStrategy(contentStg); 1134 }, 1135 1136 /** 1137 * Manipulation before applying the resolution policy 1138 * @param {cc.view} view The target view 1139 */ 1140 preApply: function (view) { 1141 this._containerStrategy.preApply(view); 1142 this._contentStrategy.preApply(view); 1143 }, 1144 1145 /** 1146 * Function to apply this resolution policy 1147 * The return value is {scale: [scaleX, scaleY], viewport: {cc.Rect}}, 1148 * The target view can then apply these value to itself, it's preferred not to modify directly its private variables 1149 * @param {cc.view} view The target view 1150 * @param {cc.Size} designedResolution The user defined design resolution 1151 * @return {object} An object contains the scale X/Y values and the viewport rect 1152 */ 1153 apply: function (view, designedResolution) { 1154 this._containerStrategy.apply(view, designedResolution); 1155 return this._contentStrategy.apply(view, designedResolution); 1156 }, 1157 1158 /** 1159 * Manipulation after appyling the strategy 1160 * @param {cc.view} view The target view 1161 */ 1162 postApply: function (view) { 1163 this._containerStrategy.postApply(view); 1164 this._contentStrategy.postApply(view); 1165 }, 1166 1167 /** 1168 * Setup the container's scale strategy 1169 * @param {cc.ContainerStrategy} containerStg 1170 */ 1171 setContainerStrategy: function (containerStg) { 1172 if (containerStg instanceof cc.ContainerStrategy) 1173 this._containerStrategy = containerStg; 1174 }, 1175 1176 /** 1177 * Setup the content's scale strategy 1178 * @param {cc.ContentStrategy} contentStg 1179 */ 1180 setContentStrategy: function (contentStg) { 1181 if (contentStg instanceof cc.ContentStrategy) 1182 this._contentStrategy = contentStg; 1183 } 1184 }); 1185 1186 /** 1187 * @memberOf cc.ResolutionPolicy# 1188 * @name EXACT_FIT 1189 * @constant 1190 * @type Number 1191 * @static 1192 * The entire application is visible in the specified area without trying to preserve the original aspect ratio.<br/> 1193 * Distortion can occur, and the application may appear stretched or compressed. 1194 */ 1195 cc.ResolutionPolicy.EXACT_FIT = 0; 1196 1197 /** 1198 * @memberOf cc.ResolutionPolicy# 1199 * @name NO_BORDER 1200 * @constant 1201 * @type Number 1202 * @static 1203 * The entire application fills the specified area, without distortion but possibly with some cropping,<br/> 1204 * while maintaining the original aspect ratio of the application. 1205 */ 1206 cc.ResolutionPolicy.NO_BORDER = 1; 1207 1208 /** 1209 * @memberOf cc.ResolutionPolicy# 1210 * @name SHOW_ALL 1211 * @constant 1212 * @type Number 1213 * @static 1214 * The entire application is visible in the specified area without distortion while maintaining the original<br/> 1215 * aspect ratio of the application. Borders can appear on two sides of the application. 1216 */ 1217 cc.ResolutionPolicy.SHOW_ALL = 2; 1218 1219 /** 1220 * @memberOf cc.ResolutionPolicy# 1221 * @name FIXED_HEIGHT 1222 * @constant 1223 * @type Number 1224 * @static 1225 * The application takes the height of the design resolution size and modifies the width of the internal<br/> 1226 * canvas so that it fits the aspect ratio of the device<br/> 1227 * no distortion will occur however you must make sure your application works on different<br/> 1228 * aspect ratios 1229 */ 1230 cc.ResolutionPolicy.FIXED_HEIGHT = 3; 1231 1232 /** 1233 * @memberOf cc.ResolutionPolicy# 1234 * @name FIXED_WIDTH 1235 * @constant 1236 * @type Number 1237 * @static 1238 * The application takes the width of the design resolution size and modifies the height of the internal<br/> 1239 * canvas so that it fits the aspect ratio of the device<br/> 1240 * no distortion will occur however you must make sure your application works on different<br/> 1241 * aspect ratios 1242 */ 1243 cc.ResolutionPolicy.FIXED_WIDTH = 4; 1244 1245 /** 1246 * @memberOf cc.ResolutionPolicy# 1247 * @name UNKNOWN 1248 * @constant 1249 * @type Number 1250 * @static 1251 * Unknow policy 1252 */ 1253 cc.ResolutionPolicy.UNKNOWN = 5;