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 * Constructor of cc.DrawNode for Canvas 100 */ 101 ctor: function () { 102 cc.Node.prototype.ctor.call(this); 103 this._buffer = []; 104 this._drawColor = cc.color(255, 255, 255, 255); 105 this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); 106 107 this.init(); 108 }, 109 110 // ----common function start ---- 111 getBlendFunc: function () { 112 return this._blendFunc; 113 }, 114 115 setBlendFunc: function (blendFunc, dst) { 116 if (dst === undefined) { 117 this._blendFunc.src = blendFunc.src; 118 this._blendFunc.dst = blendFunc.dst; 119 } else { 120 this._blendFunc.src = blendFunc; 121 this._blendFunc.dst = dst; 122 } 123 }, 124 125 /** 126 * line width setter 127 * @param {Number} width 128 */ 129 setLineWidth: function (width) { 130 this._lineWidth = width; 131 }, 132 133 /** 134 * line width getter 135 * @returns {Number} 136 */ 137 getLineWidth: function () { 138 return this._lineWidth; 139 }, 140 141 /** 142 * draw color setter 143 * @param {cc.Color} color 144 */ 145 setDrawColor: function (color) { 146 var locDrawColor = this._drawColor; 147 locDrawColor.r = color.r; 148 locDrawColor.g = color.g; 149 locDrawColor.b = color.b; 150 locDrawColor.a = (color.a == null) ? 255 : color.a; 151 }, 152 153 /** 154 * draw color getter 155 * @returns {cc.Color} 156 */ 157 getDrawColor: function () { 158 return cc.color(this._drawColor.r, this._drawColor.g, this._drawColor.b, this._drawColor.a); 159 }, 160 // ----common function end ---- 161 162 163 /** 164 * draws a rectangle given the origin and destination point measured in points. 165 * @param {cc.Point} origin 166 * @param {cc.Point} destination 167 * @param {cc.Color} fillColor 168 * @param {Number} lineWidth 169 * @param {cc.Color} lineColor 170 */ 171 drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { 172 lineWidth = lineWidth || this._lineWidth; 173 lineColor = lineColor || this.getDrawColor(); 174 if(lineColor.a == null) 175 lineColor.a = 255; 176 177 var vertices = [ 178 origin, 179 cc.p(destination.x, origin.y), 180 destination, 181 cc.p(origin.x, destination.y) 182 ]; 183 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 184 element.verts = vertices; 185 element.lineWidth = lineWidth; 186 element.lineColor = lineColor; 187 element.isClosePolygon = true; 188 element.isStroke = true; 189 element.lineCap = "butt"; 190 element.fillColor = fillColor; 191 if (fillColor) { 192 if(fillColor.a == null) 193 fillColor.a = 255; 194 element.isFill = true; 195 } 196 this._buffer.push(element); 197 }, 198 199 /** 200 * draws a circle given the center, radius and number of segments. 201 * @override 202 * @param {cc.Point} center center of circle 203 * @param {Number} radius 204 * @param {Number} angle angle in radians 205 * @param {Number} segments 206 * @param {Boolean} drawLineToCenter 207 * @param {Number} lineWidth 208 * @param {cc.Color} color 209 */ 210 drawCircle: function (center, radius, angle, segments, drawLineToCenter, lineWidth, color) { 211 lineWidth = lineWidth || this._lineWidth; 212 color = color || this.getDrawColor(); 213 if (color.a == null) 214 color.a = 255; 215 216 var coef = 2.0 * Math.PI / segments; 217 var vertices = []; 218 for (var i = 0; i <= segments; i++) { 219 var rads = i * coef; 220 var j = radius * Math.cos(rads + angle) + center.x; 221 var k = radius * Math.sin(rads + angle) + center.y; 222 vertices.push(cc.p(j, k)); 223 } 224 if (drawLineToCenter) { 225 vertices.push(cc.p(center.x, center.y)); 226 } 227 228 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 229 element.verts = vertices; 230 element.lineWidth = lineWidth; 231 element.lineColor = color; 232 element.isClosePolygon = true; 233 element.isStroke = true; 234 this._buffer.push(element); 235 }, 236 237 /** 238 * draws a quad bezier path 239 * @override 240 * @param {cc.Point} origin 241 * @param {cc.Point} control 242 * @param {cc.Point} destination 243 * @param {Number} segments 244 * @param {Number} lineWidth 245 * @param {cc.Color} color 246 */ 247 drawQuadBezier: function (origin, control, destination, segments, lineWidth, color) { 248 lineWidth = lineWidth || this._lineWidth; 249 color = color || this.getDrawColor(); 250 if (color.a == null) 251 color.a = 255; 252 253 var vertices = [], t = 0.0; 254 for (var i = 0; i < segments; i++) { 255 var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 256 var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 257 vertices.push(cc.p(x, y)); 258 t += 1.0 / segments; 259 } 260 vertices.push(cc.p(destination.x, destination.y)); 261 262 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 263 element.verts = vertices; 264 element.lineWidth = lineWidth; 265 element.lineColor = color; 266 element.isStroke = true; 267 element.lineCap = "round"; 268 this._buffer.push(element); 269 }, 270 271 /** 272 * draws a cubic bezier path 273 * @override 274 * @param {cc.Point} origin 275 * @param {cc.Point} control1 276 * @param {cc.Point} control2 277 * @param {cc.Point} destination 278 * @param {Number} segments 279 * @param {Number} lineWidth 280 * @param {cc.Color} color 281 */ 282 drawCubicBezier: function (origin, control1, control2, destination, segments, lineWidth, color) { 283 lineWidth = lineWidth || this._lineWidth; 284 color = color || this.getDrawColor(); 285 if (color.a == null) 286 color.a = 255; 287 288 var vertices = [], t = 0; 289 for (var i = 0; i < segments; i++) { 290 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; 291 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; 292 vertices.push(cc.p(x, y)); 293 t += 1.0 / segments; 294 } 295 vertices.push(cc.p(destination.x, destination.y)); 296 297 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 298 element.verts = vertices; 299 element.lineWidth = lineWidth; 300 element.lineColor = color; 301 element.isStroke = true; 302 element.lineCap = "round"; 303 this._buffer.push(element); 304 }, 305 306 /** 307 * draw a CatmullRom curve 308 * @override 309 * @param {Array} points 310 * @param {Number} segments 311 * @param {Number} lineWidth 312 * @param {cc.Color} color 313 */ 314 drawCatmullRom: function (points, segments, lineWidth, color) { 315 this.drawCardinalSpline(points, 0.5, segments, lineWidth, color); 316 }, 317 318 /** 319 * draw a cardinal spline path 320 * @override 321 * @param {Array} config 322 * @param {Number} tension 323 * @param {Number} segments 324 * @param {Number} lineWidth 325 * @param {cc.Color} color 326 */ 327 drawCardinalSpline: function (config, tension, segments, lineWidth, color) { 328 lineWidth = lineWidth || this._lineWidth; 329 color = color || this.getDrawColor(); 330 if(color.a == null) 331 color.a = 255; 332 333 var vertices = [], p, lt, deltaT = 1.0 / config.length; 334 for (var i = 0; i < segments + 1; i++) { 335 var dt = i / segments; 336 // border 337 if (dt == 1) { 338 p = config.length - 1; 339 lt = 1; 340 } else { 341 p = 0 | (dt / deltaT); 342 lt = (dt - deltaT * p) / deltaT; 343 } 344 345 // Interpolate 346 var newPos = cc.cardinalSplineAt( 347 cc.getControlPointAt(config, p - 1), 348 cc.getControlPointAt(config, p - 0), 349 cc.getControlPointAt(config, p + 1), 350 cc.getControlPointAt(config, p + 2), 351 tension, lt); 352 vertices.push(newPos); 353 } 354 355 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 356 element.verts = vertices; 357 element.lineWidth = lineWidth; 358 element.lineColor = color; 359 element.isStroke = true; 360 element.lineCap = "round"; 361 this._buffer.push(element); 362 }, 363 364 /** 365 * draw a dot at a position, with a given radius and color 366 * @param {cc.Point} pos 367 * @param {Number} radius 368 * @param {cc.Color} color 369 */ 370 drawDot: function (pos, radius, color) { 371 color = color || this.getDrawColor(); 372 if (color.a == null) 373 color.a = 255; 374 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_DOT); 375 element.verts = [pos]; 376 element.lineWidth = radius; 377 element.fillColor = color; 378 this._buffer.push(element); 379 }, 380 381 /** 382 * draws an array of points. 383 * @override 384 * @param {Array} points point of array 385 * @param {Number} radius 386 * @param {cc.Color} color 387 */ 388 drawDots: function(points, radius, color){ 389 if(!points || points.length == 0) 390 return; 391 color = color || this.getDrawColor(); 392 if (color.a == null) 393 color.a = 255; 394 for(var i = 0, len = points.length; i < len; i++) 395 this.drawDot(points[i], radius, color); 396 }, 397 398 /** 399 * draw a segment with a radius and color 400 * @param {cc.Point} from 401 * @param {cc.Point} to 402 * @param {Number} lineWidth 403 * @param {cc.Color} color 404 */ 405 drawSegment: function (from, to, lineWidth, color) { 406 lineWidth = lineWidth || this._lineWidth; 407 color = color || this.getDrawColor(); 408 if (color.a == null) 409 color.a = 255; 410 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 411 element.verts = [from, to]; 412 element.lineWidth = lineWidth * 2; 413 element.lineColor = color; 414 element.isStroke = true; 415 element.lineCap = "round"; 416 this._buffer.push(element); 417 }, 418 419 /** 420 * draw a polygon with a fill color and line color without copying the vertex list 421 * @param {Array} verts 422 * @param {cc.Color} fillColor 423 * @param {Number} lineWidth 424 * @param {cc.Color} color 425 */ 426 drawPoly_: function (verts, fillColor, lineWidth, color) { 427 lineWidth = lineWidth || this._lineWidth; 428 color = color || this.getDrawColor(); 429 if (color.a == null) 430 color.a = 255; 431 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 432 433 element.verts = verts; 434 element.fillColor = fillColor; 435 element.lineWidth = lineWidth; 436 element.lineColor = color; 437 element.isClosePolygon = true; 438 element.isStroke = true; 439 element.lineCap = "round"; 440 if (fillColor) 441 element.isFill = true; 442 this._buffer.push(element); 443 }, 444 445 /** 446 * draw a polygon with a fill color and line color, copying the vertex list 447 * @param {Array} verts 448 * @param {cc.Color} fillColor 449 * @param {Number} lineWidth 450 * @param {cc.Color} color 451 */ 452 drawPoly: function (verts, fillColor, lineWidth, color) { 453 var vertsCopy = []; 454 for (var i=0; i < verts.length; i++) { 455 vertsCopy.push(cc.p(verts[i].x, verts[i].y)); 456 } 457 return this.drawPoly_(vertsCopy, fillColor, lineWidth, color); 458 }, 459 460 draw: function (ctx) { 461 var context = ctx || cc._renderContext, _t = this; 462 if ((_t._blendFunc && (_t._blendFunc.src == cc.SRC_ALPHA) && (_t._blendFunc.dst == cc.ONE))) 463 context.globalCompositeOperation = 'lighter'; 464 465 for (var i = 0; i < _t._buffer.length; i++) { 466 var element = _t._buffer[i]; 467 switch (element.type) { 468 case cc.DrawNode.TYPE_DOT: 469 _t._drawDot(context, element); 470 break; 471 case cc.DrawNode.TYPE_SEGMENT: 472 _t._drawSegment(context, element); 473 break; 474 case cc.DrawNode.TYPE_POLY: 475 _t._drawPoly(context, element); 476 break; 477 } 478 } 479 }, 480 481 _drawDot: function (ctx, element) { 482 var locColor = element.fillColor, locPos = element.verts[0], locRadius = element.lineWidth; 483 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 484 485 ctx.fillStyle = "rgba(" + (0 | locColor.r) + "," + (0 | locColor.g) + "," + (0 | locColor.b) + "," + locColor.a / 255 + ")"; 486 ctx.beginPath(); 487 ctx.arc(locPos.x * locScaleX, -locPos.y * locScaleY, locRadius * locScaleX, 0, Math.PI * 2, false); 488 ctx.closePath(); 489 ctx.fill(); 490 }, 491 492 _drawSegment: function (ctx, element) { 493 var locColor = element.lineColor; 494 var locFrom = element.verts[0]; 495 var locTo = element.verts[1]; 496 var locLineWidth = element.lineWidth; 497 var locLineCap = element.lineCap; 498 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 499 500 ctx.strokeStyle = "rgba(" + (0 | locColor.r) + "," + (0 | locColor.g) + "," + (0 | locColor.b) + "," + locColor.a / 255 + ")"; 501 ctx.lineWidth = locLineWidth * locScaleX; 502 ctx.beginPath(); 503 ctx.lineCap = locLineCap; 504 ctx.moveTo(locFrom.x * locScaleX, -locFrom.y * locScaleY); 505 ctx.lineTo(locTo.x * locScaleX, -locTo.y * locScaleY); 506 ctx.stroke(); 507 }, 508 509 _drawPoly: function (ctx, element) { 510 var locVertices = element.verts; 511 var locLineCap = element.lineCap; 512 var locFillColor = element.fillColor; 513 var locLineWidth = element.lineWidth; 514 var locLineColor = element.lineColor; 515 var locIsClosePolygon = element.isClosePolygon; 516 var locIsFill = element.isFill; 517 var locIsStroke = element.isStroke; 518 if (locVertices == null) 519 return; 520 521 var firstPoint = locVertices[0]; 522 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 523 524 ctx.lineCap = locLineCap; 525 526 if (locFillColor) { 527 ctx.fillStyle = "rgba(" + (0 | locFillColor.r) + "," + (0 | locFillColor.g) + "," 528 + (0 | locFillColor.b) + "," + locFillColor.a / 255 + ")"; 529 } 530 531 if (locLineWidth) { 532 ctx.lineWidth = locLineWidth * locScaleX; 533 } 534 if (locLineColor) { 535 ctx.strokeStyle = "rgba(" + (0 | locLineColor.r) + "," + (0 | locLineColor.g) + "," 536 + (0 | locLineColor.b) + "," + locLineColor.a / 255 + ")"; 537 } 538 ctx.beginPath(); 539 ctx.moveTo(firstPoint.x * locScaleX, -firstPoint.y * locScaleY); 540 for (var i = 1, len = locVertices.length; i < len; i++) 541 ctx.lineTo(locVertices[i].x * locScaleX, -locVertices[i].y * locScaleY); 542 543 if (locIsClosePolygon) 544 ctx.closePath(); 545 546 if (locIsFill) 547 ctx.fill(); 548 if (locIsStroke) 549 ctx.stroke(); 550 }, 551 552 /** 553 * Clear the geometry in the node's buffer. 554 */ 555 clear: function () { 556 this._buffer.length = 0; 557 } 558 }); 559 560 cc.DrawNodeWebGL = cc.Node.extend({ 561 _bufferCapacity:0, 562 _buffer:null, 563 564 _trianglesArrayBuffer:null, 565 _trianglesWebBuffer:null, 566 _trianglesReader:null, 567 568 _lineWidth: 1, 569 _drawColor: null, 570 571 _blendFunc:null, 572 _dirty:false, 573 _className:"DrawNodeWebGL", 574 575 // ----common function start ---- 576 getBlendFunc:function () { 577 return this._blendFunc; 578 }, 579 580 setBlendFunc:function (blendFunc, dst) { 581 if (dst === undefined) { 582 this._blendFunc.src = blendFunc.src; 583 this._blendFunc.dst = blendFunc.dst; 584 } else { 585 this._blendFunc.src = blendFunc; 586 this._blendFunc.dst = dst; 587 } 588 }, 589 // ----common function end ---- 590 591 ctor:function () { 592 cc.Node.prototype.ctor.call(this); 593 this._buffer = []; 594 this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); 595 this._drawColor = cc.color(255,255,255,255); 596 597 this.init(); 598 }, 599 600 init:function () { 601 if (cc.Node.prototype.init.call(this)) { 602 this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_LENGTHTEXTURECOLOR); 603 this._ensureCapacity(64); 604 this._trianglesWebBuffer = cc._renderContext.createBuffer(); 605 this._dirty = true; 606 return true; 607 } 608 return false; 609 }, 610 611 /** 612 * line width setter 613 * @param {Number} width 614 */ 615 setLineWidth: function (width) { 616 this._lineWidth = width; 617 }, 618 619 /** 620 * line width getter 621 * @returns {Number} 622 */ 623 getLineWidth: function () { 624 return this._lineWidth; 625 }, 626 627 /** 628 * draw color setter 629 * @param {cc.Color} color 630 */ 631 setDrawColor: function (color) { 632 var locDrawColor = this._drawColor; 633 locDrawColor.r = color.r; 634 locDrawColor.g = color.g; 635 locDrawColor.b = color.b; 636 locDrawColor.a = color.a; 637 }, 638 639 /** 640 * draw color getter 641 * @returns {cc.Color} 642 */ 643 getDrawColor: function () { 644 return cc.color(this._drawColor.r, this._drawColor.g, this._drawColor.b, this._drawColor.a); 645 }, 646 647 /** 648 * draws a rectangle given the origin and destination point measured in points. 649 * @param {cc.Point} origin 650 * @param {cc.Point} destination 651 * @param {cc.Color} fillColor 652 * @param {Number} lineWidth 653 * @param {cc.Color} lineColor 654 */ 655 drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { 656 lineWidth = lineWidth || this._lineWidth; 657 lineColor = lineColor || this.getDrawColor(); 658 if (lineColor.a == null) 659 lineColor.a = 255; 660 var vertices = [origin, cc.p(destination.x, origin.y), destination, cc.p(origin.x, destination.y)]; 661 if(fillColor == null) 662 this._drawSegments(vertices, lineWidth, lineColor, true); 663 else 664 this.drawPoly(vertices, fillColor, lineWidth, lineColor); 665 }, 666 667 /** 668 * draws a circle given the center, radius and number of segments. 669 * @override 670 * @param {cc.Point} center center of circle 671 * @param {Number} radius 672 * @param {Number} angle angle in radians 673 * @param {Number} segments 674 * @param {Boolean} drawLineToCenter 675 * @param {Number} lineWidth 676 * @param {cc.Color} color 677 */ 678 drawCircle: function (center, radius, angle, segments, drawLineToCenter, lineWidth, color) { 679 lineWidth = lineWidth || this._lineWidth; 680 color = color || this.getDrawColor(); 681 if (color.a == null) 682 color.a = 255; 683 var coef = 2.0 * Math.PI / segments, vertices = [], i, len; 684 for (i = 0; i <= segments; i++) { 685 var rads = i * coef; 686 var j = radius * Math.cos(rads + angle) + center.x; 687 var k = radius * Math.sin(rads + angle) + center.y; 688 vertices.push(cc.p(j, k)); 689 } 690 if (drawLineToCenter) 691 vertices.push(cc.p(center.x, center.y)); 692 693 lineWidth *= 0.5; 694 for (i = 0, len = vertices.length; i < len - 1; i++) 695 this.drawSegment(vertices[i], vertices[i + 1], lineWidth, color); 696 }, 697 698 /** 699 * draws a quad bezier path 700 * @override 701 * @param {cc.Point} origin 702 * @param {cc.Point} control 703 * @param {cc.Point} destination 704 * @param {Number} segments 705 * @param {Number} lineWidth 706 * @param {cc.Color} color 707 */ 708 drawQuadBezier: function (origin, control, destination, segments, lineWidth, color) { 709 lineWidth = lineWidth || this._lineWidth; 710 color = color || this.getDrawColor(); 711 if (color.a == null) 712 color.a = 255; 713 var vertices = [], t = 0.0; 714 for (var i = 0; i < segments; i++) { 715 var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 716 var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 717 vertices.push(cc.p(x, y)); 718 t += 1.0 / segments; 719 } 720 vertices.push(cc.p(destination.x, destination.y)); 721 this._drawSegments(vertices, lineWidth, color, false); 722 }, 723 724 /** 725 * draws a cubic bezier path 726 * @override 727 * @param {cc.Point} origin 728 * @param {cc.Point} control1 729 * @param {cc.Point} control2 730 * @param {cc.Point} destination 731 * @param {Number} segments 732 * @param {Number} lineWidth 733 * @param {cc.Color} color 734 */ 735 drawCubicBezier: function (origin, control1, control2, destination, segments, lineWidth, color) { 736 lineWidth = lineWidth || this._lineWidth; 737 color = color || this.getDrawColor(); 738 if (color.a == null) 739 color.a = 255; 740 var vertices = [], t = 0; 741 for (var i = 0; i < segments; i++) { 742 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; 743 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; 744 vertices.push(cc.p(x, y)); 745 t += 1.0 / segments; 746 } 747 vertices.push(cc.p(destination.x, destination.y)); 748 this._drawSegments(vertices, lineWidth, color, false); 749 }, 750 751 /** 752 * draw a CatmullRom curve 753 * @override 754 * @param {Array} points 755 * @param {Number} segments 756 * @param {Number} lineWidth 757 * @param {cc.Color} color 758 */ 759 drawCatmullRom: function (points, segments, lineWidth, color) { 760 this.drawCardinalSpline(points, 0.5, segments, lineWidth, color); 761 }, 762 763 /** 764 * draw a cardinal spline path 765 * @override 766 * @param {Array} config 767 * @param {Number} tension 768 * @param {Number} segments 769 * @param {Number} lineWidth 770 * @param {cc.Color} color 771 */ 772 drawCardinalSpline: function (config, tension, segments, lineWidth, color) { 773 lineWidth = lineWidth || this._lineWidth; 774 color = color || this.getDrawColor(); 775 if (color.a == null) 776 color.a = 255; 777 var vertices = [], p, lt, deltaT = 1.0 / config.length; 778 779 for (var i = 0; i < segments + 1; i++) { 780 var dt = i / segments; 781 782 // border 783 if (dt == 1) { 784 p = config.length - 1; 785 lt = 1; 786 } else { 787 p = 0 | (dt / deltaT); 788 lt = (dt - deltaT * p) / deltaT; 789 } 790 791 // Interpolate 792 var newPos = cc.cardinalSplineAt( 793 cc.getControlPointAt(config, p - 1), 794 cc.getControlPointAt(config, p - 0), 795 cc.getControlPointAt(config, p + 1), 796 cc.getControlPointAt(config, p + 2), 797 tension, lt); 798 vertices.push(newPos); 799 } 800 801 lineWidth *= 0.5; 802 for (var j = 0, len = vertices.length; j < len - 1; j++) 803 this.drawSegment(vertices[j], vertices[j + 1], lineWidth, color); 804 }, 805 806 _render:function () { 807 var gl = cc._renderContext; 808 809 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); 810 gl.bindBuffer(gl.ARRAY_BUFFER, this._trianglesWebBuffer); 811 if (this._dirty) { 812 gl.bufferData(gl.ARRAY_BUFFER, this._trianglesArrayBuffer, gl.STREAM_DRAW); 813 this._dirty = false; 814 } 815 var triangleSize = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; 816 817 // vertex 818 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, gl.FLOAT, false, triangleSize, 0); 819 // color 820 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, triangleSize, 8); 821 // texcood 822 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, triangleSize, 12); 823 824 gl.drawArrays(gl.TRIANGLES, 0, this._buffer.length * 3); 825 cc.incrementGLDraws(1); 826 //cc.checkGLErrorDebug(); 827 }, 828 829 _ensureCapacity:function(count){ 830 var _t = this; 831 var locBuffer = _t._buffer; 832 if(locBuffer.length + count > _t._bufferCapacity){ 833 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT; 834 _t._bufferCapacity += Math.max(_t._bufferCapacity, count); 835 //re alloc 836 if((locBuffer == null) || (locBuffer.length === 0)){ 837 //init 838 _t._buffer = []; 839 _t._trianglesArrayBuffer = new ArrayBuffer(TriangleLength * _t._bufferCapacity); 840 _t._trianglesReader = new Uint8Array(_t._trianglesArrayBuffer); 841 } else { 842 var newTriangles = []; 843 var newArrayBuffer = new ArrayBuffer(TriangleLength * _t._bufferCapacity); 844 for(var i = 0; i < locBuffer.length;i++){ 845 newTriangles[i] = new cc.V2F_C4B_T2F_Triangle(locBuffer[i].a,locBuffer[i].b,locBuffer[i].c, 846 newArrayBuffer, i * TriangleLength); 847 } 848 _t._trianglesReader = new Uint8Array(newArrayBuffer); 849 _t._trianglesArrayBuffer = newArrayBuffer; 850 _t._buffer = newTriangles; 851 } 852 } 853 }, 854 855 draw:function () { 856 cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); 857 this._shaderProgram.use(); 858 this._shaderProgram.setUniformsForBuiltins(); 859 this._render(); 860 }, 861 862 drawDot:function (pos, radius, color) { 863 color = color || this.getDrawColor(); 864 if (color.a == null) 865 color.a = 255; 866 var c4bColor = {r: 0 | color.r, g: 0 | color.g, b: 0 | color.b, a: 0 | color.a}; 867 var a = {vertices: {x: pos.x - radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: -1.0, v: -1.0}}; 868 var b = {vertices: {x: pos.x - radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: -1.0, v: 1.0}}; 869 var c = {vertices: {x: pos.x + radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: 1.0, v: 1.0}}; 870 var d = {vertices: {x: pos.x + radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: 1.0, v: -1.0}}; 871 872 this._ensureCapacity(2*3); 873 874 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)); 875 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)); 876 this._dirty = true; 877 }, 878 879 drawDots: function(points, radius,color) { 880 if(!points || points.length == 0) 881 return; 882 color = color || this.getDrawColor(); 883 if (color.a == null) 884 color.a = 255; 885 for(var i = 0, len = points.length; i < len; i++) 886 this.drawDot(points[i], radius, color); 887 }, 888 889 drawSegment:function (from, to, radius, color) { 890 color = color || this.getDrawColor(); 891 if (color.a == null) 892 color.a = 255; 893 radius = radius || (this._lineWidth * 0.5); 894 var vertexCount = 6*3; 895 this._ensureCapacity(vertexCount); 896 897 var c4bColor = {r: 0 | color.r, g: 0 | color.g, b: 0 | color.b, a: 0 | color.a}; 898 var a = cc.__v2f(from), b = cc.__v2f(to); 899 var n = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(b, a))), t = cc.v2fperp(n); 900 var nw = cc.v2fmult(n, radius), tw = cc.v2fmult(t, radius); 901 902 var v0 = cc.v2fsub(b, cc.v2fadd(nw, tw)); 903 var v1 = cc.v2fadd(b, cc.v2fsub(nw, tw)); 904 var v2 = cc.v2fsub(b, nw); 905 var v3 = cc.v2fadd(b, nw); 906 var v4 = cc.v2fsub(a, nw); 907 var v5 = cc.v2fadd(a, nw); 908 var v6 = cc.v2fsub(a, cc.v2fsub(nw, tw)); 909 var v7 = cc.v2fadd(a, cc.v2fadd(nw, tw)); 910 911 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, triangleBuffer = this._trianglesArrayBuffer, locBuffer = this._buffer; 912 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(cc.v2fadd(n, t)))}, 913 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 914 triangleBuffer, locBuffer.length * TriangleLength)); 915 916 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 917 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 918 triangleBuffer, locBuffer.length * TriangleLength)); 919 920 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 921 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 922 triangleBuffer, locBuffer.length * TriangleLength)); 923 924 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 925 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 926 triangleBuffer, locBuffer.length * TriangleLength)); 927 928 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 929 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 930 triangleBuffer, locBuffer.length * TriangleLength)); 931 932 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 933 {vertices: v7, colors: c4bColor, texCoords: cc.__t(cc.v2fadd(n, t))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 934 triangleBuffer, locBuffer.length * TriangleLength)); 935 this._dirty = true; 936 }, 937 938 drawPoly:function (verts, fillColor, borderWidth, borderColor) { 939 if(fillColor == null){ 940 this._drawSegments(verts, borderWidth, borderColor, true); 941 return; 942 } 943 if (fillColor.a == null) 944 fillColor.a = 255; 945 if (borderColor.a == null) 946 borderColor.a = 255; 947 borderWidth = borderWidth || this._lineWidth; 948 borderWidth *= 0.5; 949 var c4bFillColor = {r: 0 | fillColor.r, g: 0 | fillColor.g, b: 0 | fillColor.b, a: 0 | fillColor.a}; 950 var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a}; 951 var extrude = [], i, v0, v1, v2, count = verts.length; 952 for (i = 0; i < count; i++) { 953 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 954 v1 = cc.__v2f(verts[i]); 955 v2 = cc.__v2f(verts[(i + 1) % count]); 956 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 957 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 958 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 959 extrude[i] = {offset: offset, n: n2}; 960 } 961 var outline = (borderWidth > 0.0), triangleCount = 3 * count - 2, vertexCount = 3 * triangleCount; 962 this._ensureCapacity(vertexCount); 963 964 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 965 var locBuffer = this._buffer; 966 var inset = (outline == false ? 0.5 : 0.0); 967 for (i = 0; i < count - 2; i++) { 968 v0 = cc.v2fsub(cc.__v2f(verts[0]), cc.v2fmult(extrude[0].offset, inset)); 969 v1 = cc.v2fsub(cc.__v2f(verts[i + 1]), cc.v2fmult(extrude[i + 1].offset, inset)); 970 v2 = cc.v2fsub(cc.__v2f(verts[i + 2]), cc.v2fmult(extrude[i + 2].offset, inset)); 971 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 972 {vertices: v1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: v2, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 973 trianglesBuffer, locBuffer.length * triangleBytesLen)); 974 } 975 976 for (i = 0; i < count; i++) { 977 var j = (i + 1) % count; 978 v0 = cc.__v2f(verts[i]); 979 v1 = cc.__v2f(verts[j]); 980 981 var n0 = extrude[i].n; 982 var offset0 = extrude[i].offset; 983 var offset1 = extrude[j].offset; 984 var inner0 = outline ? cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fsub(v0, cc.v2fmult(offset0, 0.5)); 985 var inner1 = outline ? cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fsub(v1, cc.v2fmult(offset1, 0.5)); 986 var outer0 = outline ? cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fadd(v0, cc.v2fmult(offset0, 0.5)); 987 var outer1 = outline ? cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fadd(v1, cc.v2fmult(offset1, 0.5)); 988 989 if (outline) { 990 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 991 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 992 trianglesBuffer, locBuffer.length * triangleBytesLen)); 993 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 994 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 995 trianglesBuffer, locBuffer.length * triangleBytesLen)); 996 } else { 997 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 998 {vertices: inner1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 999 trianglesBuffer, locBuffer.length * triangleBytesLen)); 1000 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 1001 {vertices: outer0, colors: c4bFillColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 1002 trianglesBuffer, locBuffer.length * triangleBytesLen)); 1003 } 1004 } 1005 extrude = null; 1006 this._dirty = true; 1007 }, 1008 1009 _drawSegments: function(verts, borderWidth, borderColor, closePoly){ 1010 borderWidth = borderWidth || this._lineWidth; 1011 borderColor = borderColor || this._drawColor; 1012 if(borderColor.a == null) 1013 borderColor.a = 255; 1014 borderWidth *= 0.5; 1015 if (borderWidth <= 0) 1016 return; 1017 1018 var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a }; 1019 var extrude = [], i, v0, v1, v2, count = verts.length; 1020 for (i = 0; i < count; i++) { 1021 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 1022 v1 = cc.__v2f(verts[i]); 1023 v2 = cc.__v2f(verts[(i + 1) % count]); 1024 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 1025 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 1026 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 1027 extrude[i] = {offset: offset, n: n2}; 1028 } 1029 1030 var triangleCount = 3 * count - 2, vertexCount = 3 * triangleCount; 1031 this._ensureCapacity(vertexCount); 1032 1033 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 1034 var locBuffer = this._buffer; 1035 var len = closePoly ? count : count - 1; 1036 for (i = 0; i < len; i++) { 1037 var j = (i + 1) % count; 1038 v0 = cc.__v2f(verts[i]); 1039 v1 = cc.__v2f(verts[j]); 1040 1041 var n0 = extrude[i].n; 1042 var offset0 = extrude[i].offset; 1043 var offset1 = extrude[j].offset; 1044 var inner0 = cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)); 1045 var inner1 = cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)); 1046 var outer0 = cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)); 1047 var outer1 = cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)); 1048 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 1049 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 1050 trianglesBuffer, locBuffer.length * triangleBytesLen)); 1051 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 1052 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 1053 trianglesBuffer, locBuffer.length * triangleBytesLen)); 1054 } 1055 extrude = null; 1056 this._dirty = true; 1057 }, 1058 1059 clear:function () { 1060 this._buffer.length = 0; 1061 this._dirty = true; 1062 } 1063 }); 1064 1065 cc.DrawNode = cc._renderType == cc._RENDER_TYPE_WEBGL ? cc.DrawNodeWebGL : cc.DrawNodeCanvas; 1066 1067 /** 1068 * Creates a DrawNode 1069 * @return {cc.DrawNode} 1070 */ 1071 cc.DrawNode.create = function () { 1072 return new cc.DrawNode(); 1073 }; 1074 1075 cc._DrawNodeElement = function (type, verts, fillColor, lineWidth, lineColor, lineCap, isClosePolygon, isFill, isStroke) { 1076 var _t = this; 1077 _t.type = type; 1078 _t.verts = verts || null; 1079 _t.fillColor = fillColor || null; 1080 _t.lineWidth = lineWidth || 0; 1081 _t.lineColor = lineColor || null; 1082 _t.lineCap = lineCap || "butt"; 1083 _t.isClosePolygon = isClosePolygon || false; 1084 _t.isFill = isFill || false; 1085 _t.isStroke = isStroke || false; 1086 }; 1087 1088 cc.DrawNode.TYPE_DOT = 0; 1089 cc.DrawNode.TYPE_SEGMENT = 1; 1090 cc.DrawNode.TYPE_POLY = 2; 1091