1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga 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 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 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)); 872 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)); 873 this._dirty = true; 874 }, 875 876 drawDots: function(points, radius,color) { 877 if(!points || points.length == 0) 878 return; 879 color = color || this.getDrawColor(); 880 if (color.a == null) 881 color.a = 255; 882 for(var i = 0, len = points.length; i < len; i++) 883 this.drawDot(points[i], radius, color); 884 }, 885 886 drawSegment:function (from, to, radius, color) { 887 color = color || this.getDrawColor(); 888 if (color.a == null) 889 color.a = 255; 890 radius = radius || (this._lineWidth * 0.5); 891 var vertexCount = 6*3; 892 this._ensureCapacity(vertexCount); 893 894 var c4bColor = {r: 0 | color.r, g: 0 | color.g, b: 0 | color.b, a: 0 | color.a}; 895 var a = cc.__v2f(from), b = cc.__v2f(to); 896 var n = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(b, a))), t = cc.v2fperp(n); 897 var nw = cc.v2fmult(n, radius), tw = cc.v2fmult(t, radius); 898 899 var v0 = cc.v2fsub(b, cc.v2fadd(nw, tw)); 900 var v1 = cc.v2fadd(b, cc.v2fsub(nw, tw)); 901 var v2 = cc.v2fsub(b, nw); 902 var v3 = cc.v2fadd(b, nw); 903 var v4 = cc.v2fsub(a, nw); 904 var v5 = cc.v2fadd(a, nw); 905 var v6 = cc.v2fsub(a, cc.v2fsub(nw, tw)); 906 var v7 = cc.v2fadd(a, cc.v2fadd(nw, tw)); 907 908 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, triangleBuffer = this._trianglesArrayBuffer, locBuffer = this._buffer; 909 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(cc.v2fadd(n, t)))}, 910 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 911 triangleBuffer, locBuffer.length * TriangleLength)); 912 913 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 914 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 915 triangleBuffer, locBuffer.length * TriangleLength)); 916 917 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 918 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 919 triangleBuffer, locBuffer.length * TriangleLength)); 920 921 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 922 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 923 triangleBuffer, locBuffer.length * TriangleLength)); 924 925 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 926 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 927 triangleBuffer, locBuffer.length * TriangleLength)); 928 929 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 930 {vertices: v7, colors: c4bColor, texCoords: cc.__t(cc.v2fadd(n, t))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 931 triangleBuffer, locBuffer.length * TriangleLength)); 932 this._dirty = true; 933 }, 934 935 drawPoly:function (verts, fillColor, borderWidth, borderColor) { 936 if(fillColor == null){ 937 this._drawSegments(verts, borderWidth, borderColor, true); 938 return; 939 } 940 if (fillColor.a == null) 941 fillColor.a = 255; 942 if (borderColor.a == null) 943 borderColor.a = 255; 944 borderWidth = borderWidth || this._lineWidth; 945 borderWidth *= 0.5; 946 var c4bFillColor = {r: 0 | fillColor.r, g: 0 | fillColor.g, b: 0 | fillColor.b, a: 0 | fillColor.a}; 947 var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a}; 948 var extrude = [], i, v0, v1, v2, count = verts.length; 949 for (i = 0; i < count; i++) { 950 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 951 v1 = cc.__v2f(verts[i]); 952 v2 = cc.__v2f(verts[(i + 1) % count]); 953 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 954 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 955 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 956 extrude[i] = {offset: offset, n: n2}; 957 } 958 var outline = (borderWidth > 0.0), triangleCount = 3 * count - 2, vertexCount = 3 * triangleCount; 959 this._ensureCapacity(vertexCount); 960 961 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 962 var locBuffer = this._buffer; 963 var inset = (outline == false ? 0.5 : 0.0); 964 for (i = 0; i < count - 2; i++) { 965 v0 = cc.v2fsub(cc.__v2f(verts[0]), cc.v2fmult(extrude[0].offset, inset)); 966 v1 = cc.v2fsub(cc.__v2f(verts[i + 1]), cc.v2fmult(extrude[i + 1].offset, inset)); 967 v2 = cc.v2fsub(cc.__v2f(verts[i + 2]), cc.v2fmult(extrude[i + 2].offset, inset)); 968 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 969 {vertices: v1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: v2, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 970 trianglesBuffer, locBuffer.length * triangleBytesLen)); 971 } 972 973 for (i = 0; i < count; i++) { 974 var j = (i + 1) % count; 975 v0 = cc.__v2f(verts[i]); 976 v1 = cc.__v2f(verts[j]); 977 978 var n0 = extrude[i].n; 979 var offset0 = extrude[i].offset; 980 var offset1 = extrude[j].offset; 981 var inner0 = outline ? cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fsub(v0, cc.v2fmult(offset0, 0.5)); 982 var inner1 = outline ? cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fsub(v1, cc.v2fmult(offset1, 0.5)); 983 var outer0 = outline ? cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fadd(v0, cc.v2fmult(offset0, 0.5)); 984 var outer1 = outline ? cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fadd(v1, cc.v2fmult(offset1, 0.5)); 985 986 if (outline) { 987 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 988 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 989 trianglesBuffer, locBuffer.length * triangleBytesLen)); 990 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 991 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 992 trianglesBuffer, locBuffer.length * triangleBytesLen)); 993 } else { 994 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 995 {vertices: inner1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 996 trianglesBuffer, locBuffer.length * triangleBytesLen)); 997 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 998 {vertices: outer0, colors: c4bFillColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 999 trianglesBuffer, locBuffer.length * triangleBytesLen)); 1000 } 1001 } 1002 extrude = null; 1003 this._dirty = true; 1004 }, 1005 1006 _drawSegments: function(verts, borderWidth, borderColor, closePoly){ 1007 borderWidth = borderWidth || this._lineWidth; 1008 borderColor = borderColor || this._drawColor; 1009 if(borderColor.a == null) 1010 borderColor.a = 255; 1011 borderWidth *= 0.5; 1012 if (borderWidth <= 0) 1013 return; 1014 1015 var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a }; 1016 var extrude = [], i, v0, v1, v2, count = verts.length; 1017 for (i = 0; i < count; i++) { 1018 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 1019 v1 = cc.__v2f(verts[i]); 1020 v2 = cc.__v2f(verts[(i + 1) % count]); 1021 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 1022 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 1023 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 1024 extrude[i] = {offset: offset, n: n2}; 1025 } 1026 1027 var triangleCount = 3 * count - 2, vertexCount = 3 * triangleCount; 1028 this._ensureCapacity(vertexCount); 1029 1030 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 1031 var locBuffer = this._buffer; 1032 var len = closePoly ? count : count - 1; 1033 for (i = 0; i < len; i++) { 1034 var j = (i + 1) % count; 1035 v0 = cc.__v2f(verts[i]); 1036 v1 = cc.__v2f(verts[j]); 1037 1038 var n0 = extrude[i].n; 1039 var offset0 = extrude[i].offset; 1040 var offset1 = extrude[j].offset; 1041 var inner0 = cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)); 1042 var inner1 = cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)); 1043 var outer0 = cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)); 1044 var outer1 = cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)); 1045 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 1046 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 1047 trianglesBuffer, locBuffer.length * triangleBytesLen)); 1048 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 1049 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 1050 trianglesBuffer, locBuffer.length * triangleBytesLen)); 1051 } 1052 extrude = null; 1053 this._dirty = true; 1054 }, 1055 1056 clear:function () { 1057 this._buffer.length = 0; 1058 this._dirty = true; 1059 } 1060 }); 1061 1062 cc.DrawNode = cc._renderType == cc._RENDER_TYPE_WEBGL ? cc.DrawNodeWebGL : cc.DrawNodeCanvas; 1063 1064 /** 1065 * Creates a DrawNode 1066 * @return {cc.DrawNode} 1067 */ 1068 cc.DrawNode.create = function () { 1069 return new cc.DrawNode(); 1070 }; 1071 1072 cc._DrawNodeElement = function (type, verts, fillColor, lineWidth, lineColor, lineCap, isClosePolygon, isFill, isStroke) { 1073 var _t = this; 1074 _t.type = type; 1075 _t.verts = verts || null; 1076 _t.fillColor = fillColor || null; 1077 _t.lineWidth = lineWidth || 0; 1078 _t.lineColor = lineColor || null; 1079 _t.lineCap = lineCap || "butt"; 1080 _t.isClosePolygon = isClosePolygon || false; 1081 _t.isFill = isFill || false; 1082 _t.isStroke = isStroke || false; 1083 }; 1084 1085 cc.DrawNode.TYPE_DOT = 0; 1086 cc.DrawNode.TYPE_SEGMENT = 1; 1087 cc.DrawNode.TYPE_POLY = 2; 1088