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 cc.RESOLUTION_POLICY = { 28 // The entire application is visible in the specified area without trying to preserve the original aspect ratio. 29 // Distortion can occur, and the application may appear stretched or compressed. 30 EXACT_FIT: 0, 31 // The entire application fills the specified area, without distortion but possibly with some cropping, 32 // while maintaining the original aspect ratio of the application. 33 NO_BORDER: 1, 34 // The entire application is visible in the specified area without distortion while maintaining the original 35 // aspect ratio of the application. Borders can appear on two sides of the application. 36 SHOW_ALL: 2, 37 // The application takes the height of the design resolution size and modifies the width of the internal 38 // canvas so that it fits the aspect ratio of the device 39 // no distortion will occur however you must make sure your application works on different 40 // aspect ratios 41 FIXED_HEIGHT: 3, 42 // The application takes the width of the design resolution size and modifies the height of the internal 43 // canvas so that it fits the aspect ratio of the device 44 // no distortion will occur however you must make sure your application works on different 45 // aspect ratios 46 FIXED_WIDTH: 4, 47 48 UNKNOWN: 5 49 }; 50 51 cc.Touches = []; 52 cc.TouchesIntergerDict = {}; 53 54 /** 55 * @class 56 * @extends cc.Class 57 */ 58 cc.EGLView = cc.Class.extend(/** @lends cc.EGLView# */{ 59 _delegate: null, 60 // Size of parent node that contains cc.container and cc.canvas 61 _frameSize: null, 62 // resolution size, it is the size appropriate for the app resources. 63 _designResolutionSize: null, 64 _originalDesignResolutionSize: null, 65 // Viewport is the container's rect related to content's coordinates in pixel 66 _viewPortRect: null, 67 // The visible rect in content's coordinate in point 68 _visibleRect: null, 69 // the view name 70 _viewName: "", 71 // Custom callback for resize event 72 _resizeCallback: null, 73 _scaleX: 1, 74 _originalScaleX: 1, 75 _scaleY: 1, 76 _originalScaleY: 1, 77 _indexBitsUsed: 0, 78 _maxTouches: 5, 79 _resolutionPolicy: null, 80 _rpExactFit: null, 81 _rpShowAll: null, 82 _rpNoBorder: null, 83 _rpFixedHeight: null, 84 _rpFixedWidth: null, 85 _initialized: false, 86 87 _captured: false, 88 _wnd: null, 89 _hDC: null, 90 _hRC: null, 91 _accelerometerKeyHook: null, 92 _supportTouch: false, 93 _contentTranslateLeftTop: null, 94 95 _menu: null, 96 // Parent node that contains cc.container and cc.canvas 97 _frame: null, 98 _frameZoomFactor: 1.0, 99 __resizeWithBrowserSize: false, 100 _isAdjustViewPort: false, 101 102 ctor: function () { 103 this._frame = (cc.container.parentNode === document.body) ? document.documentElement : cc.container.parentNode; 104 this._frameSize = cc.size(0, 0); 105 this._initFrameSize(); 106 107 var w = cc.canvas.width, h = cc.canvas.height; 108 this._designResolutionSize = cc.size(w, h); 109 this._originalDesignResolutionSize = cc.size(w, h); 110 this._viewPortRect = cc.rect(0, 0, w, h); 111 this._visibleRect = cc.rect(0, 0, w, h); 112 this._delegate = cc.Director.getInstance().getTouchDispatcher(); 113 this._contentTranslateLeftTop = {left: 0, top: 0}; 114 this._viewName = "Cocos2dHTML5"; 115 116 cc.VisibleRect.init(this._designResolutionSize); 117 118 // Setup system default resolution policies 119 this._rpExactFit = new cc.ResolutionPolicy(cc.ContainerStrategy.EQUAL_TO_FRAME, cc.ContentStrategy.EXACT_FIT); 120 this._rpShowAll = new cc.ResolutionPolicy(cc.ContainerStrategy.PROPORTION_TO_FRAME, cc.ContentStrategy.SHOW_ALL); 121 this._rpNoBorder = new cc.ResolutionPolicy(cc.ContainerStrategy.EQUAL_TO_FRAME, cc.ContentStrategy.NO_BORDER); 122 this._rpFixedHeight = new cc.ResolutionPolicy(cc.ContainerStrategy.EQUAL_TO_FRAME, cc.ContentStrategy.FIXED_HEIGHT); 123 this._rpFixedWidth = new cc.ResolutionPolicy(cc.ContainerStrategy.EQUAL_TO_FRAME, cc.ContentStrategy.FIXED_WIDTH); 124 125 this._hDC = cc.canvas; 126 this._hRC = cc.renderContext; 127 }, 128 129 // Resize helper functions 130 _resizeEvent: function () { 131 var width = this._originalDesignResolutionSize.width; 132 var height = this._originalDesignResolutionSize.height; 133 if (this._resizeCallback) { 134 this._initFrameSize(); 135 this._resizeCallback.call(); 136 } 137 if (width > 0) 138 this.setDesignResolutionSize(width, height, this._resolutionPolicy); 139 }, 140 141 resizeWithBrowserSize: function (enabled) { 142 var adjustSize; 143 if (enabled) { 144 //enable 145 if (!this.__resizeWithBrowserSize) { 146 this.__resizeWithBrowserSize = true; 147 adjustSize = this._resizeEvent.bind(this); 148 window.addEventListener('resize', adjustSize, false); 149 } 150 } else { 151 //disable 152 if (this.__resizeWithBrowserSize) { 153 this.__resizeWithBrowserSize = true; 154 adjustSize = this._resizeEvent.bind(this); 155 window.removeEventListener('resize', adjustSize, false); 156 } 157 } 158 }, 159 160 setResizeCallback: function (callback) { 161 if (typeof callback == "function" || callback == null) { 162 this._resizeCallback = callback; 163 } 164 }, 165 166 _initFrameSize: function () { 167 var locFrameSize = this._frameSize; 168 locFrameSize.width = this._frame.clientWidth; 169 locFrameSize.height = this._frame.clientHeight; 170 }, 171 172 // hack 173 _adjustSizeKeepCanvasSize: function (width, height) { 174 var designWidth = this._originalDesignResolutionSize.width; 175 var designHeight = this._originalDesignResolutionSize.height; 176 if (designWidth > 0) 177 this.setDesignResolutionSize(designWidth, designHeight, this._resolutionPolicy); 178 }, 179 180 _setViewPortMeta: function (width, height) { 181 if (this._isAdjustViewPort) { 182 var viewportMetas = {"user-scalable": "no", "maximum-scale": "1.0", "initial-scale": "1.0"}, elems = document.getElementsByName("viewport"), vp, content; 183 if (elems.length == 0) { 184 vp = document.createElement("meta"); 185 vp.name = "viewport"; 186 vp.content = ""; 187 document.head.appendChild(vp); 188 } 189 else vp = elems[0]; 190 content = vp.content; 191 for (var key in viewportMetas) { 192 var pattern = new RegExp(key); 193 if (!pattern.test(content)) { 194 content += (content == "" ? "" : ",") + key + "=" + viewportMetas[key]; 195 } 196 } 197 /* 198 if(width<=320){ 199 width = 321; 200 } 201 if(height) 202 content ="height="+height+","+content; 203 if(width) 204 content ="width="+width+","+content; 205 */ 206 vp.content = content; 207 } 208 }, 209 210 // RenderTexture hacker 211 _setScaleXYForRenderTexture: function () { 212 //hack for RenderTexture on canvas mode when adapting multiple resolution resources 213 var scaleFactor = cc.CONTENT_SCALE_FACTOR(); 214 this._scaleX = scaleFactor; 215 this._scaleY = scaleFactor; 216 }, 217 218 // Other helper functions 219 _resetScale: function () { 220 this._scaleX = this._originalScaleX; 221 this._scaleY = this._originalScaleY; 222 }, 223 224 _getUnUsedIndex: function () { 225 var i; 226 var temp = this._indexBitsUsed; 227 228 for (i = 0; i < this._maxTouches; i++) { 229 if (!(temp & 0x00000001)) { 230 this._indexBitsUsed |= (1 << i); 231 return i; 232 } 233 234 temp >>= 1; 235 } 236 237 // all bits are used 238 return -1; 239 }, 240 241 _removeUsedIndexBit: function (index) { 242 if (index < 0 || index >= this._maxTouches) { 243 return; 244 } 245 246 var temp = 1 << index; 247 temp = ~temp; 248 this._indexBitsUsed &= temp; 249 }, 250 251 // Useless, just make sure the compatibility temporarily, should be removed 252 _adjustSizeToBrowser: function () { 253 }, 254 255 /** 256 * init 257 */ 258 initialize: function () { 259 this._initialized = true; 260 }, 261 262 adjustViewPort: function (enabled) { 263 this._isAdjustViewPort = enabled; 264 }, 265 266 /** 267 * Force destroying EGL view, subclass must implement this method. 268 */ 269 end: function () { 270 }, 271 272 /** 273 * Get whether render system is ready(no matter opengl or canvas), 274 * this name is for the compatibility with cocos2d-x, subclass must implement this method. 275 * @return {Boolean} 276 */ 277 isOpenGLReady: function () { 278 return (this._hDC != null && this._hRC != null); 279 }, 280 281 /* 282 * Set zoom factor for frame. This method is for debugging big resolution (e.g.new ipad) app on desktop. 283 * @param {Number} zoomFactor 284 */ 285 setFrameZoomFactor: function (zoomFactor) { 286 this._frameZoomFactor = zoomFactor; 287 this.centerWindow(); 288 cc.Director.getInstance().setProjection(cc.Director.getInstance().getProjection()); 289 }, 290 291 /** 292 * Exchanges the front and back buffers, subclass must implement this method. 293 */ 294 swapBuffers: function () { 295 }, 296 297 /** 298 * Open or close IME keyboard , subclass must implement this method. 299 */ 300 setIMEKeyboardState: function (isOpen) { 301 if (isOpen) { 302 // [EAGLView sharedEGLView] becomeFirstResponder 303 } else { 304 // [EAGLView sharedEGLView] resignFirstResponder 305 } 306 }, 307 308 /** 309 * <p> 310 * The resolution translate on EGLView 311 * </p> 312 * @param {Number} offsetLeft 313 * @param {Number} offsetTop 314 */ 315 setContentTranslateLeftTop: function (offsetLeft, offsetTop) { 316 this._contentTranslateLeftTop = {left: offsetLeft, top: offsetTop}; 317 }, 318 319 /** 320 * <p> 321 * get the resolution translate on EGLView 322 * </p> 323 * @return {cc.Size|Object} 324 */ 325 getContentTranslateLeftTop: function () { 326 return this._contentTranslateLeftTop; 327 }, 328 329 /** 330 * Get the frame size of EGL view. 331 * In general, it returns the screen size since the EGL view is a fullscreen view. 332 * @return {cc.Size} 333 */ 334 getFrameSize: function () { 335 return cc.size(this._frameSize.width, this._frameSize.height); 336 }, 337 338 /** 339 * Set the frame size of EGL view. 340 * @param {Number} width 341 * @param {Number} height 342 */ 343 setFrameSize: function (width, height) { 344 this._frameSize.width = width; 345 this._frameSize.height = height; 346 this._frame.style.width = width + "px"; 347 this._frame.style.height = height + "px"; 348 //this.centerWindow(); 349 this._resizeEvent(); 350 cc.Director.getInstance().setProjection(cc.Director.getInstance().getProjection()); 351 }, 352 353 centerWindow: function () { 354 }, 355 356 setAccelerometerKeyHook: function (accelerometerKeyHook) { 357 this._accelerometerKeyHook = accelerometerKeyHook; 358 }, 359 360 /** 361 * Get the visible area size of opengl viewport. 362 * @return {cc.Size} 363 */ 364 getVisibleSize: function () { 365 return this._visibleRect._size; 366 }, 367 368 /** 369 * Get the visible origin povar of opengl viewport. 370 * @return {cc.Point} 371 */ 372 getVisibleOrigin: function () { 373 return this._visibleRect._origin; 374 }, 375 376 canSetContentScaleFactor: function () { 377 return true; 378 }, 379 380 /** 381 * Get the current resolution policy 382 * @return {cc.ResolutionPolicy} 383 */ 384 getResolutionPolicy: function () { 385 return this._resolutionPolicy; 386 }, 387 388 /** 389 * Set the current resolution policy 390 * @param {cc.ResolutionPolicy|Number} resolutionPolicy 391 */ 392 setResolutionPolicy: function (resolutionPolicy) { 393 if (resolutionPolicy instanceof cc.ResolutionPolicy) { 394 this._resolutionPolicy = resolutionPolicy; 395 } 396 // Ensure compatibility with JSB 397 else { 398 switch (resolutionPolicy) { 399 case cc.RESOLUTION_POLICY.EXACT_FIT: 400 this._resolutionPolicy = this._rpExactFit; 401 break; 402 case cc.RESOLUTION_POLICY.SHOW_ALL: 403 this._resolutionPolicy = this._rpShowAll; 404 break; 405 case cc.RESOLUTION_POLICY.NO_BORDER: 406 this._resolutionPolicy = this._rpNoBorder; 407 break; 408 case cc.RESOLUTION_POLICY.FIXED_HEIGHT: 409 this._resolutionPolicy = this._rpFixedHeight; 410 break; 411 case cc.RESOLUTION_POLICY.FIXED_WIDTH: 412 this._resolutionPolicy = this._rpFixedWidth; 413 break; 414 } 415 } 416 }, 417 418 /** 419 * Set the design resolution size. 420 * @param {Number} width Design resolution width. 421 * @param {Number} height Design resolution height. 422 * @param {cc.ResolutionPolicy|Number} resolutionPolicy The resolution policy desired, you may choose: 423 * [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. 424 * [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. 425 * [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. 426 * [4] ResolutionFixedHeight Scale the content's height to screen's height and proportionally scale its width 427 * [5] ResolutionFixedWidth Scale the content's width to screen's width and proportionally scale its height 428 * [cc.ResolutionPolicy] Custom resolution policy, constructed by cc.ResolutionPolicy 429 */ 430 setDesignResolutionSize: function (width, height, resolutionPolicy) { 431 // Defensive code 432 if (isNaN(width) || width == 0 || isNaN(height) || height == 0) { 433 cc.log("Resolution not valid"); 434 return; 435 } 436 this.setResolutionPolicy(resolutionPolicy); 437 var policy; 438 if (policy = this._resolutionPolicy) 439 policy.preApply(this); 440 else { 441 cc.log("should set resolutionPolicy"); 442 return; 443 } 444 445 // Reinit frame size 446 var frameW = this._frameSize.width, frameH = this._frameSize.height; 447 if (cc.Browser.isMobile) 448 this._setViewPortMeta(this._frameSize.width, this._frameSize.height); 449 this._initFrameSize(); 450 // No change 451 if (resolutionPolicy == this._resolutionPolicy 452 && width == this._originalDesignResolutionSize.width && height == this._originalDesignResolutionSize.height 453 && frameW == this._frameSize.width && frameH == this._frameSize.height) 454 return; 455 this._designResolutionSize = cc.size(width, height); 456 this._originalDesignResolutionSize = cc.size(width, height); 457 458 var result = policy.apply(this, this._designResolutionSize); 459 if (result.scale && result.scale.length == 2) { 460 this._scaleX = result.scale[0]; 461 this._scaleY = result.scale[1]; 462 } 463 if (result.viewport instanceof cc.Rect) { 464 var vp = this._viewPortRect = result.viewport, visible = this._visibleRect; 465 visible._size.width = cc.canvas.width / this._scaleX; 466 visible._size.height = cc.canvas.height / this._scaleY; 467 visible._origin.x = -vp.x / this._scaleX; 468 visible._origin.y = -vp.y / this._scaleY; 469 } 470 471 // reset director's member variables to fit visible rect 472 var director = cc.Director.getInstance(); 473 director._winSizeInPoints = this.getDesignResolutionSize(); 474 475 if (cc.renderContextType == cc.WEBGL) { 476 // reset director's member variables to fit visible rect 477 director._createStatsLabel(); 478 director.setGLDefaultValues(); 479 } 480 481 this._originalScaleX = this._scaleX; 482 this._originalScaleY = this._scaleY; 483 // For editbox 484 if (cc.DOM) { 485 cc.DOM._resetEGLViewDiv(); 486 } 487 488 cc.VisibleRect.init(this.getVisibleSize()); 489 490 policy.postApply(this); 491 }, 492 493 /** 494 * Get design resolution size. 495 * Default resolution size is the same as 'getFrameSize'. 496 * @return {cc.Size} 497 */ 498 getDesignResolutionSize: function () { 499 return cc.size(this._designResolutionSize.width, this._designResolutionSize.height); 500 }, 501 502 /** 503 * set touch delegate 504 * @param {cc.TouchDispatcher} delegate 505 */ 506 setTouchDelegate: function (delegate) { 507 this._delegate = delegate; 508 }, 509 510 /** 511 * Set opengl view port rectangle with points. 512 * @param {Number} x 513 * @param {Number} y 514 * @param {Number} w width 515 * @param {Number} h height 516 */ 517 setViewPortInPoints: function (x, y, w, h) { 518 var locFrameZoomFactor = this._frameZoomFactor, locScaleX = this._scaleX, locScaleY = this._scaleY; 519 cc.renderContext.viewport((x * locScaleX * locFrameZoomFactor + this._viewPortRect.x * locFrameZoomFactor), 520 (y * locScaleY * locFrameZoomFactor + this._viewPortRect.y * locFrameZoomFactor), 521 (w * locScaleX * locFrameZoomFactor), 522 (h * locScaleY * locFrameZoomFactor)); 523 }, 524 525 /** 526 * Set Scissor rectangle with points. 527 * @param {Number} x 528 * @param {Number} y 529 * @param {Number} w 530 * @param {Number} h 531 */ 532 setScissorInPoints: function (x, y, w, h) { 533 var locFrameZoomFactor = this._frameZoomFactor, locScaleX = this._scaleX, locScaleY = this._scaleY; 534 cc.renderContext.scissor((x * locScaleX * locFrameZoomFactor + this._viewPortRect.x * locFrameZoomFactor), 535 (y * locScaleY * locFrameZoomFactor + this._viewPortRect.y * locFrameZoomFactor), 536 (w * locScaleX * locFrameZoomFactor), 537 (h * locScaleY * locFrameZoomFactor)); 538 }, 539 540 /** 541 * Get whether GL_SCISSOR_TEST is enable 542 */ 543 isScissorEnabled: function () { 544 var gl = cc.renderContext; 545 return gl.isEnabled(gl.SCISSOR_TEST); 546 }, 547 548 /** 549 * Get the current scissor rectangle 550 * @return {cc.Rect} 551 */ 552 getScissorRect: function () { 553 var gl = cc.renderContext, scaleX = this._scaleX, scaleY = this._scaleY; 554 var boxArr = gl.getParameter(gl.SCISSOR_BOX); 555 return cc.rect((boxArr[0] - this._viewPortRect.x) / scaleX, (boxArr[1] - this._viewPortRect.y) / scaleY, 556 boxArr[2] / scaleX, boxArr[3] / scaleY); 557 }, 558 559 /** 560 * @param {String} viewName 561 */ 562 setViewName: function (viewName) { 563 if (viewName != null && viewName.length > 0) { 564 this._viewName = viewName; 565 } 566 }, 567 568 /** 569 * get view name 570 * @return {String} 571 */ 572 getViewName: function () { 573 return this._viewName; 574 }, 575 576 /** 577 * Get the opengl view port rectangle. 578 */ 579 getViewPortRect: function () { 580 return this._viewPortRect; 581 }, 582 583 /** 584 * Get scale factor of the horizontal direction. 585 */ 586 getScaleX: function () { 587 return this._scaleX; 588 }, 589 590 /** 591 * Get scale factor of the vertical direction. 592 */ 593 getScaleY: function () { 594 return this._scaleY; 595 }, 596 597 /** 598 * Get the real location in view 599 */ 600 convertToLocationInView: function (tx, ty, relatedPos) { 601 return {x: tx - relatedPos.left, y: relatedPos.top + relatedPos.height - ty}; 602 }, 603 604 /** 605 * Touch events are handled by default; if you want to customize your handlers, please override these functions: 606 * @param {Number} num 607 * @param {Array} ids 608 * @param {Array} xs 609 * @param {Array} ys 610 */ 611 handleTouchesBegin: function (num, ids, xs, ys) { 612 var arr = [], locViewPortRect = this._viewPortRect, locScaleX = this._scaleX, locScaleY = this._scaleY; 613 for (var i = 0; i < num; ++i) { 614 var id = ids[i]; 615 var x = xs[i]; 616 var y = ys[i]; 617 618 var index = cc.TouchesIntergerDict[id]; 619 var unusedIndex = 0; 620 621 // it is a new touch 622 if (index == null) { 623 unusedIndex = this._getUnUsedIndex(); 624 625 // The touches is more than MAX_TOUCHES ? 626 if (unusedIndex == -1) { 627 cc.log("The touches is more than MAX_TOUCHES, nUnusedIndex = " + unusedIndex); 628 continue; 629 } 630 631 var touch = cc.Touches[unusedIndex] = new cc.Touch(); 632 touch.setTouchInfo(unusedIndex, (x - locViewPortRect.x) / locScaleX, 633 (y - locViewPortRect.y) / locScaleY); 634 635 cc.TouchesIntergerDict[id] = 0 | unusedIndex; 636 arr.push(touch); 637 } 638 } 639 640 if (arr.length !== 0) 641 this._delegate.touchesBegan(arr, null); 642 }, 643 644 /** 645 * @param {Number} num 646 * @param {Number} ids 647 * @param {Number} xs 648 * @param {Number} ys 649 */ 650 handleTouchesMove: function (num, ids, xs, ys) { 651 var arr = []; 652 var locScaleX = this._scaleX, locScaleY = this._scaleY, locViewPortX = this._viewPortRect.x, locViewPortY = this._viewPortRect.y; 653 for (var i = 0; i < num; ++i) { 654 var id = ids[i]; 655 var x = xs[i]; 656 var y = ys[i]; 657 658 var index = cc.TouchesIntergerDict[id]; 659 if (index == null) { 660 //cc.log("if the index doesn't exist, it is an error"); 661 continue; 662 } 663 664 var touch = cc.Touches[index]; 665 if (touch) { 666 touch.setTouchInfo(index, (x - locViewPortX) / locScaleX, 667 (y - locViewPortY) / locScaleY); 668 arr.push(touch); 669 } 670 else { 671 // It is error, should return. 672 //cc.log("Moving touches with id: " + id + " error"); 673 return; 674 } 675 } 676 677 if (arr.length == 0) { 678 //cc.log("touchesMoved: count = 0"); 679 return; 680 } 681 682 this._delegate.touchesMoved(arr, null); 683 }, 684 685 /** 686 * @param {Number} num 687 * @param {Number} ids 688 * @param {Number} xs 689 * @param {Number} ys 690 */ 691 handleTouchesEnd: function (num, ids, xs, ys) { 692 var arr = []; 693 this.getSetOfTouchesEndOrCancel(arr, num, ids, xs, ys); 694 this._delegate.touchesEnded(arr, null); 695 }, 696 697 /** 698 * @param {Number} num 699 * @param {Number} ids 700 * @param {Number} xs 701 * @param {Number} ys 702 */ 703 handleTouchesCancel: function (num, ids, xs, ys) { 704 var arr = []; 705 this.getSetOfTouchesEndOrCancel(arr, num, ids, xs, ys); 706 this._delegate.touchesCancelled(arr, null); 707 }, 708 709 /** 710 * @param {Array} arr 711 * @param {Number} num 712 * @param {Number} ids 713 * @param {Number} xs 714 * @param {Number} ys 715 */ 716 getSetOfTouchesEndOrCancel: function (arr, num, ids, xs, ys) { 717 var locScaleX = this._scaleX, locScaleY = this._scaleY, locViewPortRect = this._viewPortRect; 718 for (var i = 0; i < num; ++i) { 719 var id = ids[i]; 720 var x = xs[i]; 721 var y = ys[i]; 722 723 var index = cc.TouchesIntergerDict[id]; 724 if (index == null) { 725 //cc.log("if the index doesn't exist, it is an error"); 726 continue; 727 } 728 /* Add to the set to send to the director */ 729 var touch = cc.Touches[index]; 730 if (touch) { 731 //cc.log("Ending touches with id: " + id + ", x=" + x + ", y=" + y); 732 touch.setTouchInfo(index, (x - locViewPortRect.x) / locScaleX, 733 (y - locViewPortRect.y) / locScaleY); 734 735 arr.push(touch); 736 737 // release the object 738 cc.Touches[index] = null; 739 this._removeUsedIndexBit(index); 740 741 delete cc.TouchesIntergerDict[id]; 742 } else { 743 //cc.log("Ending touches with id: " + id + " error"); 744 return; 745 } 746 } 747 }, 748 749 // Pass the touches to the superview 750 touchesBegan: function (touches, event) { 751 var ids = []; 752 var xs = []; 753 var ys = []; 754 755 var i = 0; 756 var touch; 757 for (var j = 0; j < touches.length; j++) { 758 touch = touches[j]; 759 ids[i] = touch.getId() || j; 760 xs[i] = touch.getLocation().x; 761 ys[i] = touch.getLocation().y; 762 ++i; 763 } 764 this.handleTouchesBegin(i, ids, xs, ys); 765 }, 766 767 touchesMoved: function (touches, event) { 768 var ids = []; 769 var xs = []; 770 var ys = []; 771 772 var i = 0; 773 var touch; 774 for (var j = 0; j < touches.length; j++) { 775 touch = touches[j]; 776 ids[i] = touch.getId() || j; 777 xs[i] = touch.getLocation().x; 778 ys[i] = touch.getLocation().y; 779 ++i; 780 } 781 this.handleTouchesMove(i, ids, xs, ys); 782 }, 783 784 touchesEnded: function (touches, event) { 785 var ids = []; 786 var xs = []; 787 var ys = []; 788 789 var i = 0; 790 var touch; 791 for (var j = 0; j < touches.length; j++) { 792 touch = touches[j]; 793 ids[i] = touch.getId() || j; 794 xs[i] = touch.getLocation().x; 795 ys[i] = touch.getLocation().y; 796 ++i; 797 } 798 this.handleTouchesEnd(i, ids, xs, ys); 799 }, 800 801 touchesCancelled: function (touches, event) { 802 var ids = []; 803 var xs = []; 804 var ys = []; 805 806 var i = 0; 807 var touch; 808 for (var j = 0; j < touches.length; j++) { 809 touch = touches[j]; 810 ids[i] = touch.getId() || j; 811 xs[i] = touch.getLocation().x; 812 ys[i] = touch.getLocation().y; 813 ++i; 814 } 815 this.handleTouchesCancel(i, ids, xs, ys); 816 } 817 }); 818 819 820 cc.EGLView.getInstance = function () { 821 if (!this._instance) { 822 this._instance = new cc.EGLView(); 823 this._instance.initialize(); 824 } 825 return this._instance; 826 }; 827 828 829 /** 830 * <p>cc.ContainerStrategy class is the root strategy class of container's scale strategy, 831 * it controls the behavior of how to scale the cc.container and cc.canvas object</p> 832 * 833 * @class 834 * @extends cc.Class 835 */ 836 837 cc.ContainerStrategy = cc.Class.extend({ 838 /** 839 * Manipulation before applying the strategy 840 * @param {cc.EGLView} view The target view 841 */ 842 preApply: function (view) { 843 }, 844 845 /** 846 * Function to apply this strategy 847 * @param {cc.EGLView} view 848 * @param {cc.Size} designedResolution 849 */ 850 apply: function (view, designedResolution) { 851 }, 852 853 /** 854 * Manipulation after applying the strategy 855 * @param {cc.EGLView} view The target view 856 */ 857 postApply: function (view) { 858 }, 859 860 _setupContainer: function (frame, w, h) { 861 if (cc.Browser.isMobile && frame == document.documentElement) { 862 // Automatically full screen when user touches on mobile version 863 cc.Screen.getInstance().autoFullScreen(cc.canvas); 864 } 865 866 var locCanvasElement = cc.canvas, locContainer = cc.container; 867 // Setup canvas 868 locCanvasElement.width = w; 869 locCanvasElement.height = h; 870 // Setup container 871 locContainer.style.width = w + "px"; 872 locContainer.style.height = h + "px"; 873 874 var body = document.body, style; 875 if (body && (style = body.style)) { 876 style.paddingTop = style.paddingTop || "0px"; 877 style.paddingRight = style.paddingRight || "0px"; 878 style.paddingBottom = style.paddingBottom || "0px"; 879 style.paddingLeft = style.paddingLeft || "0px"; 880 style.borderTop = style.borderTop || "0px"; 881 style.borderRight = style.borderRight || "0px"; 882 style.borderBottom = style.borderBottom || "0px"; 883 style.borderLeft = style.borderLeft || "0px"; 884 style.marginTop = style.marginTop || "0px"; 885 style.marginRight = style.marginRight || "0px"; 886 style.marginBottom = style.marginBottom || "0px"; 887 style.marginLeft = style.marginLeft || "0px"; 888 } 889 }, 890 891 _fixContainer: function () { 892 // Add container to document body 893 document.body.insertBefore(cc.container, document.body.firstChild); 894 // Set body's width height to window's size, and forbid overflow, so that game will be centered 895 var bs = document.body.style; 896 bs.width = window.innerWidth + "px"; 897 bs.height = window.innerHeight + "px"; 898 bs.overflow = "hidden"; 899 // Body size solution doesn't work on all mobile browser so this is the aleternative: fixed container 900 var contStyle = cc.container.style; 901 contStyle.position = "fixed"; 902 contStyle.left = contStyle.top = "0px"; 903 // Reposition body 904 document.body.scrollTop = 0; 905 } 906 }); 907 908 /** 909 * <p>cc.ContentStrategy class is the root strategy class of content's scale strategy, 910 * it controls the behavior of how to scale the scene and setup the viewport for the game</p> 911 * 912 * @class 913 * @extends cc.Class 914 */ 915 916 cc.ContentStrategy = cc.Class.extend({ 917 918 _result: { 919 scale: [1, 1], 920 viewport: null 921 }, 922 923 _buildResult: function (containerW, containerH, contentW, contentH, scaleX, scaleY) { 924 var viewport = cc.rect(Math.round((containerW - contentW) / 2), 925 Math.round((containerH - contentH) / 2), 926 contentW, contentH); 927 928 // Translate the content 929 if (cc.renderContextType == cc.CANVAS) 930 cc.renderContext.translate(viewport.x, viewport.y + contentH); 931 932 this._result.scale = [scaleX, scaleY]; 933 this._result.viewport = viewport; 934 return this._result; 935 }, 936 937 /** 938 * Manipulation before appling the strategy 939 * @param {cc.EGLView} The target view 940 */ 941 preApply: function (view) { 942 }, 943 944 /** 945 * Function to apply this strategy 946 * The return value is {scale: [scaleX, scaleY], viewport: {cc.Rect}}, 947 * The target view can then apply these value to itself, it's prefered not to modify directly its private variables 948 * @param {cc.EGLView} view 949 * @param {cc.Size} designedResolution 950 * @return {object} scaleAndViewportRect 951 */ 952 apply: function (view, designedResolution) { 953 return {"scale": [1, 1]}; 954 }, 955 956 /** 957 * Manipulation after appling the strategy 958 * @param {cc.EGLView} The target view 959 */ 960 postApply: function (view) { 961 } 962 }); 963 964 (function () { 965 966 // Container scale strategys 967 var EqualToFrame = cc.ContainerStrategy.extend({ 968 apply: function (view) { 969 this._setupContainer(view._frame, view._frameSize.width, view._frameSize.height); 970 } 971 }); 972 973 var ProportionalToFrame = cc.ContainerStrategy.extend({ 974 apply: function (view, designedResolution) { 975 var frameW = view._frameSize.width, frameH = view._frameSize.height, containerStyle = cc.container.style, 976 designW = designedResolution.width, designH = designedResolution.height, 977 scaleX = frameW / designW, scaleY = frameH / designH, 978 containerW, containerH; 979 980 scaleX < scaleY ? (containerW = frameW, containerH = designH * scaleX) : (containerW = designW * scaleY, containerH = frameH); 981 982 // Adjust container size with integer value 983 var offx = Math.round((frameW - containerW) / 2); 984 var offy = Math.round((frameH - containerH) / 2); 985 containerW = frameW - 2 * offx; 986 containerH = frameH - 2 * offy; 987 988 this._setupContainer(view._frame, containerW, containerH); 989 // Setup container's margin 990 containerStyle.marginLeft = offx + "px"; 991 containerStyle.marginRight = offx + "px"; 992 containerStyle.marginTop = offy + "px"; 993 containerStyle.marginBottom = offy + "px"; 994 } 995 }); 996 997 var EqualToWindow = EqualToFrame.extend({ 998 preApply: function (view) { 999 view._frame = document.documentElement; 1000 }, 1001 1002 apply: function (view) { 1003 this._super(view); 1004 1005 this._fixContainer(); 1006 } 1007 }); 1008 1009 var ProportionalToWindow = ProportionalToFrame.extend({ 1010 preApply: function (view) { 1011 view._frame = document.documentElement; 1012 }, 1013 1014 apply: function (view, designedResolution) { 1015 this._super(view, designedResolution); 1016 1017 this._fixContainer(); 1018 } 1019 }); 1020 1021 var OriginalContainer = cc.ContainerStrategy.extend({}); 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, 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.getInstance()._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.getInstance()._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 */ 1120 cc.ResolutionPolicy = cc.Class.extend({ 1121 _containerStrategy: null, 1122 _contentStrategy: null, 1123 1124 ctor: function (containerStg, contentStg) { 1125 this.setContainerStrategy(containerStg); 1126 this.setContentStrategy(contentStg); 1127 }, 1128 1129 /** 1130 * Manipulation before appling the resolution policy 1131 * @param {cc.EGLView} The target view 1132 */ 1133 preApply: function (view) { 1134 this._containerStrategy.preApply(view); 1135 this._contentStrategy.preApply(view); 1136 }, 1137 1138 /** 1139 * Function to apply this resolution policy 1140 * The return value is {scale: [scaleX, scaleY], viewport: {cc.Rect}}, 1141 * The target view can then apply these value to itself, it's prefered not to modify directly its private variables 1142 * @param {cc.EGLView} The target view 1143 * @param {cc.Size} The user defined design resolution 1144 * @return {object} An object contains the scale X/Y values and the viewport rect 1145 */ 1146 apply: function (view, designedResolution) { 1147 this._containerStrategy.apply(view, designedResolution); 1148 return this._contentStrategy.apply(view, designedResolution); 1149 }, 1150 1151 /** 1152 * Manipulation after appling the strategy 1153 * @param {cc.EGLView} The target view 1154 */ 1155 postApply: function (view) { 1156 this._containerStrategy.postApply(view); 1157 this._contentStrategy.postApply(view); 1158 }, 1159 1160 /** 1161 * Setup the container's scale strategy 1162 * @param {cc.ContainerStrategy} containerStg 1163 */ 1164 setContainerStrategy: function (containerStg) { 1165 if (containerStg instanceof cc.ContainerStrategy) 1166 this._containerStrategy = containerStg; 1167 }, 1168 1169 /** 1170 * Setup the content's scale strategy 1171 * @param {cc.ContentStrategy} contentStg 1172 */ 1173 setContentStrategy: function (contentStg) { 1174 if (contentStg instanceof cc.ContentStrategy) 1175 this._contentStrategy = contentStg; 1176 } 1177 });