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 Copyright (c) 2012 Scott Lembcke and Howling Moon Software 6 7 http://www.cocos2d-x.org 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ****************************************************************************/ 27 28 /** 29 * Code copied & pasted from SpacePatrol game https://github.com/slembcke/SpacePatrol 30 * 31 * Renamed and added some changes for cocos2d 32 * 33 */ 34 cc.v2fzero = function () { 35 return {x: 0, y: 0}; 36 }; 37 38 cc.v2f = function (x, y) { 39 return {x: x, y: y}; 40 }; 41 42 cc.v2fadd = function (v0, v1) { 43 return cc.v2f(v0.x + v1.x, v0.y + v1.y); 44 }; 45 46 cc.v2fsub = function (v0, v1) { 47 return cc.v2f(v0.x - v1.x, v0.y - v1.y); 48 }; 49 50 cc.v2fmult = function (v, s) { 51 return cc.v2f(v.x * s, v.y * s); 52 }; 53 54 cc.v2fperp = function (p0) { 55 return cc.v2f(-p0.y, p0.x); 56 }; 57 58 cc.v2fneg = function (p0) { 59 return cc.v2f(-p0.x, -p0.y); 60 }; 61 62 cc.v2fdot = function (p0, p1) { 63 return p0.x * p1.x + p0.y * p1.y; 64 }; 65 66 cc.v2fforangle = function (_a_) { 67 return cc.v2f(Math.cos(_a_), Math.sin(_a_)); 68 }; 69 70 cc.v2fnormalize = function (p) { 71 var r = cc.pNormalize(cc.p(p.x, p.y)); 72 return cc.v2f(r.x, r.y); 73 }; 74 75 cc.__v2f = function (v) { 76 return cc.v2f(v.x, v.y); 77 }; 78 79 cc.__t = function (v) { 80 return {u: v.x, v: v.y}; 81 }; 82 83 /** 84 * <p>CCDrawNode <br/> 85 * Node that draws dots, segments and polygons. <br/> 86 * Faster than the "drawing primitives" since they it draws everything in one single batch.</p> 87 * @class 88 * @name cc.DrawNode 89 * @extends cc.Node 90 */ 91 cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNode# */{ 92 _buffer: null, 93 _blendFunc: null, 94 _lineWidth: 1, 95 _drawColor: null, 96 _className:"DrawNodeCanvas", 97 98 /** 99 * <p>The cc.DrawNodeCanvas's constructor. <br/> 100 * This function will automatically be invoked when you create a node using new construction: "var node = new cc.DrawNodeCanvas()".<br/> 101 * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.</p> 102 */ 103 ctor: function () { 104 cc.Node.prototype.ctor.call(this); 105 this._buffer = []; 106 this._drawColor = cc.color(255, 255, 255, 255); 107 this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); 108 109 this.init(); 110 }, 111 112 // ----common function start ---- 113 /** 114 * Gets the blend func 115 * @returns {Object} 116 */ 117 getBlendFunc: function () { 118 return this._blendFunc; 119 }, 120 121 /** 122 * Set the blend func 123 * @param blendFunc 124 * @param dst 125 */ 126 setBlendFunc: function (blendFunc, dst) { 127 if (dst === undefined) { 128 this._blendFunc.src = blendFunc.src; 129 this._blendFunc.dst = blendFunc.dst; 130 } else { 131 this._blendFunc.src = blendFunc; 132 this._blendFunc.dst = dst; 133 } 134 }, 135 136 /** 137 * line width setter 138 * @param {Number} width 139 */ 140 setLineWidth: function (width) { 141 this._lineWidth = width; 142 }, 143 144 /** 145 * line width getter 146 * @returns {Number} 147 */ 148 getLineWidth: function () { 149 return this._lineWidth; 150 }, 151 152 /** 153 * draw color setter 154 * @param {cc.Color} color 155 */ 156 setDrawColor: function (color) { 157 var locDrawColor = this._drawColor; 158 locDrawColor.r = color.r; 159 locDrawColor.g = color.g; 160 locDrawColor.b = color.b; 161 locDrawColor.a = (color.a == null) ? 255 : color.a; 162 }, 163 164 /** 165 * draw color getter 166 * @returns {cc.Color} 167 */ 168 getDrawColor: function () { 169 return cc.color(this._drawColor.r, this._drawColor.g, this._drawColor.b, this._drawColor.a); 170 }, 171 // ----common function end ---- 172 173 174 /** 175 * draws a rectangle given the origin and destination point measured in points. 176 * @param {cc.Point} origin 177 * @param {cc.Point} destination 178 * @param {cc.Color} fillColor 179 * @param {Number} lineWidth 180 * @param {cc.Color} lineColor 181 */ 182 drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { 183 lineWidth = lineWidth || this._lineWidth; 184 lineColor = lineColor || this.getDrawColor(); 185 if(lineColor.a == null) 186 lineColor.a = 255; 187 188 var vertices = [ 189 origin, 190 cc.p(destination.x, origin.y), 191 destination, 192 cc.p(origin.x, destination.y) 193 ]; 194 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 195 element.verts = vertices; 196 element.lineWidth = lineWidth; 197 element.lineColor = lineColor; 198 element.isClosePolygon = true; 199 element.isStroke = true; 200 element.lineCap = "butt"; 201 element.fillColor = fillColor; 202 if (fillColor) { 203 if(fillColor.a == null) 204 fillColor.a = 255; 205 element.isFill = true; 206 } 207 this._buffer.push(element); 208 }, 209 210 /** 211 * draws a circle given the center, radius and number of segments. 212 * @override 213 * @param {cc.Point} center center of circle 214 * @param {Number} radius 215 * @param {Number} angle angle in radians 216 * @param {Number} segments 217 * @param {Boolean} drawLineToCenter 218 * @param {Number} lineWidth 219 * @param {cc.Color} color 220 */ 221 drawCircle: function (center, radius, angle, segments, drawLineToCenter, lineWidth, color) { 222 lineWidth = lineWidth || this._lineWidth; 223 color = color || this.getDrawColor(); 224 if (color.a == null) 225 color.a = 255; 226 227 var coef = 2.0 * Math.PI / segments; 228 var vertices = []; 229 for (var i = 0; i <= segments; i++) { 230 var rads = i * coef; 231 var j = radius * Math.cos(rads + angle) + center.x; 232 var k = radius * Math.sin(rads + angle) + center.y; 233 vertices.push(cc.p(j, k)); 234 } 235 if (drawLineToCenter) { 236 vertices.push(cc.p(center.x, center.y)); 237 } 238 239 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 240 element.verts = vertices; 241 element.lineWidth = lineWidth; 242 element.lineColor = color; 243 element.isClosePolygon = true; 244 element.isStroke = true; 245 this._buffer.push(element); 246 }, 247 248 /** 249 * draws a quad bezier path 250 * @override 251 * @param {cc.Point} origin 252 * @param {cc.Point} control 253 * @param {cc.Point} destination 254 * @param {Number} segments 255 * @param {Number} lineWidth 256 * @param {cc.Color} color 257 */ 258 drawQuadBezier: function (origin, control, destination, segments, lineWidth, color) { 259 lineWidth = lineWidth || this._lineWidth; 260 color = color || this.getDrawColor(); 261 if (color.a == null) 262 color.a = 255; 263 264 var vertices = [], t = 0.0; 265 for (var i = 0; i < segments; i++) { 266 var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 267 var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 268 vertices.push(cc.p(x, y)); 269 t += 1.0 / segments; 270 } 271 vertices.push(cc.p(destination.x, destination.y)); 272 273 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 274 element.verts = vertices; 275 element.lineWidth = lineWidth; 276 element.lineColor = color; 277 element.isStroke = true; 278 element.lineCap = "round"; 279 this._buffer.push(element); 280 }, 281 282 /** 283 * draws a cubic bezier path 284 * @override 285 * @param {cc.Point} origin 286 * @param {cc.Point} control1 287 * @param {cc.Point} control2 288 * @param {cc.Point} destination 289 * @param {Number} segments 290 * @param {Number} lineWidth 291 * @param {cc.Color} color 292 */ 293 drawCubicBezier: function (origin, control1, control2, destination, segments, lineWidth, color) { 294 lineWidth = lineWidth || this._lineWidth; 295 color = color || this.getDrawColor(); 296 if (color.a == null) 297 color.a = 255; 298 299 var vertices = [], t = 0; 300 for (var i = 0; i < segments; i++) { 301 var x = Math.pow(1 - t, 3) * origin.x + 3.0 * Math.pow(1 - t, 2) * t * control1.x + 3.0 * (1 - t) * t * t * control2.x + t * t * t * destination.x; 302 var y = Math.pow(1 - t, 3) * origin.y + 3.0 * Math.pow(1 - t, 2) * t * control1.y + 3.0 * (1 - t) * t * t * control2.y + t * t * t * destination.y; 303 vertices.push(cc.p(x, y)); 304 t += 1.0 / segments; 305 } 306 vertices.push(cc.p(destination.x, destination.y)); 307 308 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 309 element.verts = vertices; 310 element.lineWidth = lineWidth; 311 element.lineColor = color; 312 element.isStroke = true; 313 element.lineCap = "round"; 314 this._buffer.push(element); 315 }, 316 317 /** 318 * draw a CatmullRom curve 319 * @override 320 * @param {Array} points 321 * @param {Number} segments 322 * @param {Number} lineWidth 323 * @param {cc.Color} color 324 */ 325 drawCatmullRom: function (points, segments, lineWidth, color) { 326 this.drawCardinalSpline(points, 0.5, segments, lineWidth, color); 327 }, 328 329 /** 330 * draw a cardinal spline path 331 * @override 332 * @param {Array} config 333 * @param {Number} tension 334 * @param {Number} segments 335 * @param {Number} lineWidth 336 * @param {cc.Color} color 337 */ 338 drawCardinalSpline: function (config, tension, segments, lineWidth, color) { 339 lineWidth = lineWidth || this._lineWidth; 340 color = color || this.getDrawColor(); 341 if(color.a == null) 342 color.a = 255; 343 344 var vertices = [], p, lt, deltaT = 1.0 / config.length; 345 for (var i = 0; i < segments + 1; i++) { 346 var dt = i / segments; 347 // border 348 if (dt == 1) { 349 p = config.length - 1; 350 lt = 1; 351 } else { 352 p = 0 | (dt / deltaT); 353 lt = (dt - deltaT * p) / deltaT; 354 } 355 356 // Interpolate 357 var newPos = cc.cardinalSplineAt( 358 cc.getControlPointAt(config, p - 1), 359 cc.getControlPointAt(config, p - 0), 360 cc.getControlPointAt(config, p + 1), 361 cc.getControlPointAt(config, p + 2), 362 tension, lt); 363 vertices.push(newPos); 364 } 365 366 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 367 element.verts = vertices; 368 element.lineWidth = lineWidth; 369 element.lineColor = color; 370 element.isStroke = true; 371 element.lineCap = "round"; 372 this._buffer.push(element); 373 }, 374 375 /** 376 * draw a dot at a position, with a given radius and color 377 * @param {cc.Point} pos 378 * @param {Number} radius 379 * @param {cc.Color} color 380 */ 381 drawDot: function (pos, radius, color) { 382 color = color || this.getDrawColor(); 383 if (color.a == null) 384 color.a = 255; 385 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_DOT); 386 element.verts = [pos]; 387 element.lineWidth = radius; 388 element.fillColor = color; 389 this._buffer.push(element); 390 }, 391 392 /** 393 * draws an array of points. 394 * @override 395 * @param {Array} points point of array 396 * @param {Number} radius 397 * @param {cc.Color} color 398 */ 399 drawDots: function(points, radius, color){ 400 if(!points || points.length == 0) 401 return; 402 color = color || this.getDrawColor(); 403 if (color.a == null) 404 color.a = 255; 405 for(var i = 0, len = points.length; i < len; i++) 406 this.drawDot(points[i], radius, color); 407 }, 408 409 /** 410 * draw a segment with a radius and color 411 * @param {cc.Point} from 412 * @param {cc.Point} to 413 * @param {Number} lineWidth 414 * @param {cc.Color} color 415 */ 416 drawSegment: function (from, to, lineWidth, color) { 417 lineWidth = lineWidth || this._lineWidth; 418 color = color || this.getDrawColor(); 419 if (color.a == null) 420 color.a = 255; 421 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 422 element.verts = [from, to]; 423 element.lineWidth = lineWidth * 2; 424 element.lineColor = color; 425 element.isStroke = true; 426 element.lineCap = "round"; 427 this._buffer.push(element); 428 }, 429 430 /** 431 * draw a polygon with a fill color and line color without copying the vertex list 432 * @param {Array} verts 433 * @param {cc.Color} fillColor 434 * @param {Number} lineWidth 435 * @param {cc.Color} color 436 */ 437 drawPoly_: function (verts, fillColor, lineWidth, color) { 438 lineWidth = lineWidth || this._lineWidth; 439 color = color || this.getDrawColor(); 440 if (color.a == null) 441 color.a = 255; 442 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 443 444 element.verts = verts; 445 element.fillColor = fillColor; 446 element.lineWidth = lineWidth; 447 element.lineColor = color; 448 element.isClosePolygon = true; 449 element.isStroke = true; 450 element.lineCap = "round"; 451 if (fillColor) 452 element.isFill = true; 453 this._buffer.push(element); 454 }, 455 456 /** 457 * draw a polygon with a fill color and line color, copying the vertex list 458 * @param {Array} verts 459 * @param {cc.Color} fillColor 460 * @param {Number} lineWidth 461 * @param {cc.Color} color 462 */ 463 drawPoly: function (verts, fillColor, lineWidth, color) { 464 var vertsCopy = []; 465 for (var i=0; i < verts.length; i++) { 466 vertsCopy.push(cc.p(verts[i].x, verts[i].y)); 467 } 468 return this.drawPoly_(vertsCopy, fillColor, lineWidth, color); 469 }, 470 471 /** 472 * Render function using the canvas 2d context or WebGL context, internal usage only, please do not call this function 473 * @param {CanvasRenderingContext2D | WebGLRenderingContext} ctx The render context 474 */ 475 draw: function (ctx) { 476 var context = ctx || cc._renderContext, _t = this; 477 if ((_t._blendFunc && (_t._blendFunc.src == cc.SRC_ALPHA) && (_t._blendFunc.dst == cc.ONE))) 478 context.globalCompositeOperation = 'lighter'; 479 480 for (var i = 0; i < _t._buffer.length; i++) { 481 var element = _t._buffer[i]; 482 switch (element.type) { 483 case cc.DrawNode.TYPE_DOT: 484 _t._drawDot(context, element); 485 break; 486 case cc.DrawNode.TYPE_SEGMENT: 487 _t._drawSegment(context, element); 488 break; 489 case cc.DrawNode.TYPE_POLY: 490 _t._drawPoly(context, element); 491 break; 492 } 493 } 494 }, 495 496 _drawDot: function (ctx, element) { 497 var locColor = element.fillColor, locPos = element.verts[0], locRadius = element.lineWidth; 498 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 499 500 ctx.fillStyle = "rgba(" + (0 | locColor.r) + "," + (0 | locColor.g) + "," + (0 | locColor.b) + "," + locColor.a / 255 + ")"; 501 ctx.beginPath(); 502 ctx.arc(locPos.x * locScaleX, -locPos.y * locScaleY, locRadius * locScaleX, 0, Math.PI * 2, false); 503 ctx.closePath(); 504 ctx.fill(); 505 }, 506 507 _drawSegment: function (ctx, element) { 508 var locColor = element.lineColor; 509 var locFrom = element.verts[0]; 510 var locTo = element.verts[1]; 511 var locLineWidth = element.lineWidth; 512 var locLineCap = element.lineCap; 513 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 514 515 ctx.strokeStyle = "rgba(" + (0 | locColor.r) + "," + (0 | locColor.g) + "," + (0 | locColor.b) + "," + locColor.a / 255 + ")"; 516 ctx.lineWidth = locLineWidth * locScaleX; 517 ctx.beginPath(); 518 ctx.lineCap = locLineCap; 519 ctx.moveTo(locFrom.x * locScaleX, -locFrom.y * locScaleY); 520 ctx.lineTo(locTo.x * locScaleX, -locTo.y * locScaleY); 521 ctx.stroke(); 522 }, 523 524 _drawPoly: function (ctx, element) { 525 var locVertices = element.verts; 526 var locLineCap = element.lineCap; 527 var locFillColor = element.fillColor; 528 var locLineWidth = element.lineWidth; 529 var locLineColor = element.lineColor; 530 var locIsClosePolygon = element.isClosePolygon; 531 var locIsFill = element.isFill; 532 var locIsStroke = element.isStroke; 533 if (locVertices == null) 534 return; 535 536 var firstPoint = locVertices[0]; 537 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 538 539 ctx.lineCap = locLineCap; 540 541 if (locFillColor) { 542 ctx.fillStyle = "rgba(" + (0 | locFillColor.r) + "," + (0 | locFillColor.g) + "," 543 + (0 | locFillColor.b) + "," + locFillColor.a / 255 + ")"; 544 } 545 546 if (locLineWidth) { 547 ctx.lineWidth = locLineWidth * locScaleX; 548 } 549 if (locLineColor) { 550 ctx.strokeStyle = "rgba(" + (0 | locLineColor.r) + "," + (0 | locLineColor.g) + "," 551 + (0 | locLineColor.b) + "," + locLineColor.a / 255 + ")"; 552 } 553 ctx.beginPath(); 554 ctx.moveTo(firstPoint.x * locScaleX, -firstPoint.y * locScaleY); 555 for (var i = 1, len = locVertices.length; i < len; i++) 556 ctx.lineTo(locVertices[i].x * locScaleX, -locVertices[i].y * locScaleY); 557 558 if (locIsClosePolygon) 559 ctx.closePath(); 560 561 if (locIsFill) 562 ctx.fill(); 563 if (locIsStroke) 564 ctx.stroke(); 565 }, 566 567 /** 568 * Clear the geometry in the node's buffer. 569 */ 570 clear: function () { 571 this._buffer.length = 0; 572 } 573 }); 574 575 //Just only a note 576 cc.DrawNodeWebGL = cc.Node.extend({ 577 _bufferCapacity:0, 578 _buffer:null, 579 580 _trianglesArrayBuffer:null, 581 _trianglesWebBuffer:null, 582 _trianglesReader:null, 583 584 _lineWidth: 1, 585 _drawColor: null, 586 587 _blendFunc:null, 588 _dirty:false, 589 _className:"DrawNodeWebGL", 590 591 // ----common function start ---- 592 getBlendFunc:function () { 593 return this._blendFunc; 594 }, 595 596 setBlendFunc:function (blendFunc, dst) { 597 if (dst === undefined) { 598 this._blendFunc.src = blendFunc.src; 599 this._blendFunc.dst = blendFunc.dst; 600 } else { 601 this._blendFunc.src = blendFunc; 602 this._blendFunc.dst = dst; 603 } 604 }, 605 // ----common function end ---- 606 607 ctor:function () { 608 cc.Node.prototype.ctor.call(this); 609 this._buffer = []; 610 this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); 611 this._drawColor = cc.color(255,255,255,255); 612 613 this.init(); 614 }, 615 616 init:function () { 617 if (cc.Node.prototype.init.call(this)) { 618 this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_LENGTHTEXTURECOLOR); 619 this._ensureCapacity(64); 620 this._trianglesWebBuffer = cc._renderContext.createBuffer(); 621 this._dirty = true; 622 return true; 623 } 624 return false; 625 }, 626 627 setLineWidth: function (width) { 628 this._lineWidth = width; 629 }, 630 631 getLineWidth: function () { 632 return this._lineWidth; 633 }, 634 635 setDrawColor: function (color) { 636 var locDrawColor = this._drawColor; 637 locDrawColor.r = color.r; 638 locDrawColor.g = color.g; 639 locDrawColor.b = color.b; 640 locDrawColor.a = color.a; 641 }, 642 643 getDrawColor: function () { 644 return cc.color(this._drawColor.r, this._drawColor.g, this._drawColor.b, this._drawColor.a); 645 }, 646 647 drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { 648 lineWidth = lineWidth || this._lineWidth; 649 lineColor = lineColor || this.getDrawColor(); 650 if (lineColor.a == null) 651 lineColor.a = 255; 652 var vertices = [origin, cc.p(destination.x, origin.y), destination, cc.p(origin.x, destination.y)]; 653 if(fillColor == null) 654 this._drawSegments(vertices, lineWidth, lineColor, true); 655 else 656 this.drawPoly(vertices, fillColor, lineWidth, lineColor); 657 }, 658 659 drawCircle: function (center, radius, angle, segments, drawLineToCenter, lineWidth, color) { 660 lineWidth = lineWidth || this._lineWidth; 661 color = color || this.getDrawColor(); 662 if (color.a == null) 663 color.a = 255; 664 var coef = 2.0 * Math.PI / segments, vertices = [], i, len; 665 for (i = 0; i <= segments; i++) { 666 var rads = i * coef; 667 var j = radius * Math.cos(rads + angle) + center.x; 668 var k = radius * Math.sin(rads + angle) + center.y; 669 vertices.push(cc.p(j, k)); 670 } 671 if (drawLineToCenter) 672 vertices.push(cc.p(center.x, center.y)); 673 674 lineWidth *= 0.5; 675 for (i = 0, len = vertices.length; i < len - 1; i++) 676 this.drawSegment(vertices[i], vertices[i + 1], lineWidth, color); 677 }, 678 679 drawQuadBezier: function (origin, control, destination, segments, lineWidth, color) { 680 lineWidth = lineWidth || this._lineWidth; 681 color = color || this.getDrawColor(); 682 if (color.a == null) 683 color.a = 255; 684 var vertices = [], t = 0.0; 685 for (var i = 0; i < segments; i++) { 686 var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 687 var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 688 vertices.push(cc.p(x, y)); 689 t += 1.0 / segments; 690 } 691 vertices.push(cc.p(destination.x, destination.y)); 692 this._drawSegments(vertices, lineWidth, color, false); 693 }, 694 695 drawCubicBezier: function (origin, control1, control2, destination, segments, lineWidth, color) { 696 lineWidth = lineWidth || this._lineWidth; 697 color = color || this.getDrawColor(); 698 if (color.a == null) 699 color.a = 255; 700 var vertices = [], t = 0; 701 for (var i = 0; i < segments; i++) { 702 var x = Math.pow(1 - t, 3) * origin.x + 3.0 * Math.pow(1 - t, 2) * t * control1.x + 3.0 * (1 - t) * t * t * control2.x + t * t * t * destination.x; 703 var y = Math.pow(1 - t, 3) * origin.y + 3.0 * Math.pow(1 - t, 2) * t * control1.y + 3.0 * (1 - t) * t * t * control2.y + t * t * t * destination.y; 704 vertices.push(cc.p(x, y)); 705 t += 1.0 / segments; 706 } 707 vertices.push(cc.p(destination.x, destination.y)); 708 this._drawSegments(vertices, lineWidth, color, false); 709 }, 710 711 drawCatmullRom: function (points, segments, lineWidth, color) { 712 this.drawCardinalSpline(points, 0.5, segments, lineWidth, color); 713 }, 714 715 drawCardinalSpline: function (config, tension, segments, lineWidth, color) { 716 lineWidth = lineWidth || this._lineWidth; 717 color = color || this.getDrawColor(); 718 if (color.a == null) 719 color.a = 255; 720 var vertices = [], p, lt, deltaT = 1.0 / config.length; 721 722 for (var i = 0; i < segments + 1; i++) { 723 var dt = i / segments; 724 725 // border 726 if (dt == 1) { 727 p = config.length - 1; 728 lt = 1; 729 } else { 730 p = 0 | (dt / deltaT); 731 lt = (dt - deltaT * p) / deltaT; 732 } 733 734 // Interpolate 735 var newPos = cc.cardinalSplineAt( 736 cc.getControlPointAt(config, p - 1), 737 cc.getControlPointAt(config, p - 0), 738 cc.getControlPointAt(config, p + 1), 739 cc.getControlPointAt(config, p + 2), 740 tension, lt); 741 vertices.push(newPos); 742 } 743 744 lineWidth *= 0.5; 745 for (var j = 0, len = vertices.length; j < len - 1; j++) 746 this.drawSegment(vertices[j], vertices[j + 1], lineWidth, color); 747 }, 748 749 _render:function () { 750 var gl = cc._renderContext; 751 752 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); 753 gl.bindBuffer(gl.ARRAY_BUFFER, this._trianglesWebBuffer); 754 if (this._dirty) { 755 gl.bufferData(gl.ARRAY_BUFFER, this._trianglesArrayBuffer, gl.STREAM_DRAW); 756 this._dirty = false; 757 } 758 var triangleSize = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; 759 760 // vertex 761 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, gl.FLOAT, false, triangleSize, 0); 762 // color 763 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, triangleSize, 8); 764 // texcood 765 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, triangleSize, 12); 766 767 gl.drawArrays(gl.TRIANGLES, 0, this._buffer.length * 3); 768 cc.incrementGLDraws(1); 769 //cc.checkGLErrorDebug(); 770 }, 771 772 _ensureCapacity:function(count){ 773 var _t = this; 774 var locBuffer = _t._buffer; 775 if(locBuffer.length + count > _t._bufferCapacity){ 776 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT; 777 _t._bufferCapacity += Math.max(_t._bufferCapacity, count); 778 //re alloc 779 if((locBuffer == null) || (locBuffer.length === 0)){ 780 //init 781 _t._buffer = []; 782 _t._trianglesArrayBuffer = new ArrayBuffer(TriangleLength * _t._bufferCapacity); 783 _t._trianglesReader = new Uint8Array(_t._trianglesArrayBuffer); 784 } else { 785 var newTriangles = []; 786 var newArrayBuffer = new ArrayBuffer(TriangleLength * _t._bufferCapacity); 787 for(var i = 0; i < locBuffer.length;i++){ 788 newTriangles[i] = new cc.V2F_C4B_T2F_Triangle(locBuffer[i].a,locBuffer[i].b,locBuffer[i].c, 789 newArrayBuffer, i * TriangleLength); 790 } 791 _t._trianglesReader = new Uint8Array(newArrayBuffer); 792 _t._trianglesArrayBuffer = newArrayBuffer; 793 _t._buffer = newTriangles; 794 } 795 } 796 }, 797 798 draw:function () { 799 cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); 800 this._shaderProgram.use(); 801 this._shaderProgram.setUniformsForBuiltins(); 802 this._render(); 803 }, 804 805 drawDot:function (pos, radius, color) { 806 color = color || this.getDrawColor(); 807 if (color.a == null) 808 color.a = 255; 809 var c4bColor = {r: 0 | color.r, g: 0 | color.g, b: 0 | color.b, a: 0 | color.a}; 810 var a = {vertices: {x: pos.x - radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: -1.0, v: -1.0}}; 811 var b = {vertices: {x: pos.x - radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: -1.0, v: 1.0}}; 812 var c = {vertices: {x: pos.x + radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: 1.0, v: 1.0}}; 813 var d = {vertices: {x: pos.x + radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: 1.0, v: -1.0}}; 814 815 this._ensureCapacity(2*3); 816 817 this._buffer.push(new cc.V2F_C4B_T2F_Triangle(a, b, c, this._trianglesArrayBuffer, this._buffer.length * cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT)); 818 this._buffer.push(new cc.V2F_C4B_T2F_Triangle(a, c, d, this._trianglesArrayBuffer, this._buffer.length * cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT)); 819 this._dirty = true; 820 }, 821 822 drawDots: function(points, radius,color) { 823 if(!points || points.length == 0) 824 return; 825 color = color || this.getDrawColor(); 826 if (color.a == null) 827 color.a = 255; 828 for(var i = 0, len = points.length; i < len; i++) 829 this.drawDot(points[i], radius, color); 830 }, 831 832 drawSegment:function (from, to, radius, color) { 833 color = color || this.getDrawColor(); 834 if (color.a == null) 835 color.a = 255; 836 radius = radius || (this._lineWidth * 0.5); 837 var vertexCount = 6*3; 838 this._ensureCapacity(vertexCount); 839 840 var c4bColor = {r: 0 | color.r, g: 0 | color.g, b: 0 | color.b, a: 0 | color.a}; 841 var a = cc.__v2f(from), b = cc.__v2f(to); 842 var n = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(b, a))), t = cc.v2fperp(n); 843 var nw = cc.v2fmult(n, radius), tw = cc.v2fmult(t, radius); 844 845 var v0 = cc.v2fsub(b, cc.v2fadd(nw, tw)); 846 var v1 = cc.v2fadd(b, cc.v2fsub(nw, tw)); 847 var v2 = cc.v2fsub(b, nw); 848 var v3 = cc.v2fadd(b, nw); 849 var v4 = cc.v2fsub(a, nw); 850 var v5 = cc.v2fadd(a, nw); 851 var v6 = cc.v2fsub(a, cc.v2fsub(nw, tw)); 852 var v7 = cc.v2fadd(a, cc.v2fadd(nw, tw)); 853 854 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, triangleBuffer = this._trianglesArrayBuffer, locBuffer = this._buffer; 855 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(cc.v2fadd(n, t)))}, 856 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 857 triangleBuffer, locBuffer.length * TriangleLength)); 858 859 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 860 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 861 triangleBuffer, locBuffer.length * TriangleLength)); 862 863 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 864 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 865 triangleBuffer, locBuffer.length * TriangleLength)); 866 867 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 868 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 869 triangleBuffer, locBuffer.length * TriangleLength)); 870 871 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 872 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 873 triangleBuffer, locBuffer.length * TriangleLength)); 874 875 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 876 {vertices: v7, colors: c4bColor, texCoords: cc.__t(cc.v2fadd(n, t))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 877 triangleBuffer, locBuffer.length * TriangleLength)); 878 this._dirty = true; 879 }, 880 881 drawPoly:function (verts, fillColor, borderWidth, borderColor) { 882 if(fillColor == null){ 883 this._drawSegments(verts, borderWidth, borderColor, true); 884 return; 885 } 886 if (fillColor.a == null) 887 fillColor.a = 255; 888 if (borderColor.a == null) 889 borderColor.a = 255; 890 borderWidth = borderWidth || this._lineWidth; 891 borderWidth *= 0.5; 892 var c4bFillColor = {r: 0 | fillColor.r, g: 0 | fillColor.g, b: 0 | fillColor.b, a: 0 | fillColor.a}; 893 var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a}; 894 var extrude = [], i, v0, v1, v2, count = verts.length; 895 for (i = 0; i < count; i++) { 896 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 897 v1 = cc.__v2f(verts[i]); 898 v2 = cc.__v2f(verts[(i + 1) % count]); 899 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 900 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 901 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 902 extrude[i] = {offset: offset, n: n2}; 903 } 904 var outline = (borderWidth > 0.0), triangleCount = 3 * count - 2, vertexCount = 3 * triangleCount; 905 this._ensureCapacity(vertexCount); 906 907 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 908 var locBuffer = this._buffer; 909 var inset = (outline == false ? 0.5 : 0.0); 910 for (i = 0; i < count - 2; i++) { 911 v0 = cc.v2fsub(cc.__v2f(verts[0]), cc.v2fmult(extrude[0].offset, inset)); 912 v1 = cc.v2fsub(cc.__v2f(verts[i + 1]), cc.v2fmult(extrude[i + 1].offset, inset)); 913 v2 = cc.v2fsub(cc.__v2f(verts[i + 2]), cc.v2fmult(extrude[i + 2].offset, inset)); 914 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 915 {vertices: v1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: v2, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 916 trianglesBuffer, locBuffer.length * triangleBytesLen)); 917 } 918 919 for (i = 0; i < count; i++) { 920 var j = (i + 1) % count; 921 v0 = cc.__v2f(verts[i]); 922 v1 = cc.__v2f(verts[j]); 923 924 var n0 = extrude[i].n; 925 var offset0 = extrude[i].offset; 926 var offset1 = extrude[j].offset; 927 var inner0 = outline ? cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fsub(v0, cc.v2fmult(offset0, 0.5)); 928 var inner1 = outline ? cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fsub(v1, cc.v2fmult(offset1, 0.5)); 929 var outer0 = outline ? cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fadd(v0, cc.v2fmult(offset0, 0.5)); 930 var outer1 = outline ? cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fadd(v1, cc.v2fmult(offset1, 0.5)); 931 932 if (outline) { 933 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 934 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 935 trianglesBuffer, locBuffer.length * triangleBytesLen)); 936 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 937 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 938 trianglesBuffer, locBuffer.length * triangleBytesLen)); 939 } else { 940 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 941 {vertices: inner1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 942 trianglesBuffer, locBuffer.length * triangleBytesLen)); 943 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 944 {vertices: outer0, colors: c4bFillColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 945 trianglesBuffer, locBuffer.length * triangleBytesLen)); 946 } 947 } 948 extrude = null; 949 this._dirty = true; 950 }, 951 952 _drawSegments: function(verts, borderWidth, borderColor, closePoly){ 953 borderWidth = borderWidth || this._lineWidth; 954 borderColor = borderColor || this._drawColor; 955 if(borderColor.a == null) 956 borderColor.a = 255; 957 borderWidth *= 0.5; 958 if (borderWidth <= 0) 959 return; 960 961 var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a }; 962 var extrude = [], i, v0, v1, v2, count = verts.length; 963 for (i = 0; i < count; i++) { 964 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 965 v1 = cc.__v2f(verts[i]); 966 v2 = cc.__v2f(verts[(i + 1) % count]); 967 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 968 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 969 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 970 extrude[i] = {offset: offset, n: n2}; 971 } 972 973 var triangleCount = 3 * count - 2, vertexCount = 3 * triangleCount; 974 this._ensureCapacity(vertexCount); 975 976 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 977 var locBuffer = this._buffer; 978 var len = closePoly ? count : count - 1; 979 for (i = 0; i < len; i++) { 980 var j = (i + 1) % count; 981 v0 = cc.__v2f(verts[i]); 982 v1 = cc.__v2f(verts[j]); 983 984 var n0 = extrude[i].n; 985 var offset0 = extrude[i].offset; 986 var offset1 = extrude[j].offset; 987 var inner0 = cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)); 988 var inner1 = cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)); 989 var outer0 = cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)); 990 var outer1 = cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)); 991 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 992 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 993 trianglesBuffer, locBuffer.length * triangleBytesLen)); 994 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 995 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 996 trianglesBuffer, locBuffer.length * triangleBytesLen)); 997 } 998 extrude = null; 999 this._dirty = true; 1000 }, 1001 1002 clear:function () { 1003 this._buffer.length = 0; 1004 this._dirty = true; 1005 } 1006 }); 1007 1008 cc.DrawNode = cc._renderType == cc._RENDER_TYPE_WEBGL ? cc.DrawNodeWebGL : cc.DrawNodeCanvas; 1009 1010 /** 1011 * Creates a DrawNode 1012 * @deprecated since v3.0 please use new cc.DrawNode() instead. 1013 * @return {cc.DrawNode} 1014 */ 1015 cc.DrawNode.create = function () { 1016 return new cc.DrawNode(); 1017 }; 1018 1019 cc._DrawNodeElement = function (type, verts, fillColor, lineWidth, lineColor, lineCap, isClosePolygon, isFill, isStroke) { 1020 var _t = this; 1021 _t.type = type; 1022 _t.verts = verts || null; 1023 _t.fillColor = fillColor || null; 1024 _t.lineWidth = lineWidth || 0; 1025 _t.lineColor = lineColor || null; 1026 _t.lineCap = lineCap || "butt"; 1027 _t.isClosePolygon = isClosePolygon || false; 1028 _t.isFill = isFill || false; 1029 _t.isStroke = isStroke || false; 1030 }; 1031 1032 cc.DrawNode.TYPE_DOT = 0; 1033 cc.DrawNode.TYPE_SEGMENT = 1; 1034 cc.DrawNode.TYPE_POLY = 2; 1035