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