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