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 it draws everything in one single batch.</p> 87 * @class 88 * @name cc.DrawNode 89 * @extends cc.Node 90 */ 91 cc.DrawNode = cc.Node.extend(/** @lends cc.DrawNode# */{ 92 //TODO need refactor 93 94 _buffer:null, 95 _blendFunc:null, 96 _lineWidth: 1, 97 _drawColor: null, 98 99 /** 100 * Gets the blend func 101 * @returns {Object} 102 */ 103 getBlendFunc: function () { 104 return this._blendFunc; 105 }, 106 107 /** 108 * Set the blend func 109 * @param blendFunc 110 * @param dst 111 */ 112 setBlendFunc: function (blendFunc, dst) { 113 if (dst === undefined) { 114 this._blendFunc.src = blendFunc.src; 115 this._blendFunc.dst = blendFunc.dst; 116 } else { 117 this._blendFunc.src = blendFunc; 118 this._blendFunc.dst = dst; 119 } 120 }, 121 122 /** 123 * line width setter 124 * @param {Number} width 125 */ 126 setLineWidth: function (width) { 127 this._lineWidth = width; 128 }, 129 130 /** 131 * line width getter 132 * @returns {Number} 133 */ 134 getLineWidth: function () { 135 return this._lineWidth; 136 }, 137 138 /** 139 * draw color setter 140 * @param {cc.Color} color 141 */ 142 setDrawColor: function (color) { 143 var locDrawColor = this._drawColor; 144 locDrawColor.r = color.r; 145 locDrawColor.g = color.g; 146 locDrawColor.b = color.b; 147 locDrawColor.a = (color.a == null) ? 255 : color.a; 148 }, 149 150 /** 151 * draw color getter 152 * @returns {cc.Color} 153 */ 154 getDrawColor: function () { 155 return cc.color(this._drawColor.r, this._drawColor.g, this._drawColor.b, this._drawColor.a); 156 } 157 }); 158 159 /** 160 * Creates a DrawNode 161 * @deprecated since v3.0 please use `new cc.DrawNode()` instead. 162 * @return {cc.DrawNode} 163 */ 164 cc.DrawNode.create = function () { 165 return new cc.DrawNode(); 166 }; 167 168 cc.DrawNode.TYPE_DOT = 0; 169 cc.DrawNode.TYPE_SEGMENT = 1; 170 cc.DrawNode.TYPE_POLY = 2; 171 172 cc.game.addEventListener(cc.game.EVENT_RENDERER_INITED, function () { 173 if (cc._renderType === cc.game.RENDER_TYPE_CANVAS) { 174 175 cc._DrawNodeElement = function (type, verts, fillColor, lineWidth, lineColor, lineCap, isClosePolygon, isFill, isStroke) { 176 var _t = this; 177 _t.type = type; 178 _t.verts = verts || null; 179 _t.fillColor = fillColor || null; 180 _t.lineWidth = lineWidth || 0; 181 _t.lineColor = lineColor || null; 182 _t.lineCap = lineCap || "butt"; 183 _t.isClosePolygon = isClosePolygon || false; 184 _t.isFill = isFill || false; 185 _t.isStroke = isStroke || false; 186 }; 187 188 cc.extend(cc.DrawNode.prototype, /** @lends cc.DrawNode# */{ 189 _className:"DrawNodeCanvas", 190 191 /** 192 * <p>The cc.DrawNodeCanvas's constructor. <br/> 193 * This function will automatically be invoked when you create a node using new construction: "var node = new cc.DrawNodeCanvas()".<br/> 194 * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.</p> 195 */ 196 ctor: function () { 197 cc.Node.prototype.ctor.call(this); 198 var locCmd = this._renderCmd; 199 locCmd._buffer = this._buffer = []; 200 locCmd._drawColor = this._drawColor = cc.color(255, 255, 255, 255); 201 locCmd._blendFunc = this._blendFunc = new cc.BlendFunc(cc.SRC_ALPHA, cc.ONE_MINUS_SRC_ALPHA); 202 203 this.init(); 204 this._localBB = new cc.Rect(); 205 }, 206 207 setLocalBB: function(rectorX, y, width, height) { 208 var localBB = this._localBB; 209 if(y === undefined) { 210 localBB.x = rectorX.x; 211 localBB.y = rectorX.y; 212 localBB.width = rectorX.width; 213 localBB.height = rectorX.height; 214 } else { 215 localBB.x = rectorX; 216 localBB.y = y; 217 localBB.width = width; 218 localBB.height = height; 219 } 220 }, 221 /** 222 * draws a rectangle given the origin and destination point measured in points. 223 * @param {cc.Point} origin 224 * @param {cc.Point} destination 225 * @param {cc.Color} fillColor 226 * @param {Number} lineWidth 227 * @param {cc.Color} lineColor 228 */ 229 drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { 230 lineWidth = (lineWidth == null) ? this._lineWidth : lineWidth; 231 lineColor = lineColor || this.getDrawColor(); 232 if(lineColor.a == null) 233 lineColor.a = 255; 234 235 var vertices = [ 236 origin, 237 cc.p(destination.x, origin.y), 238 destination, 239 cc.p(origin.x, destination.y) 240 ]; 241 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 242 element.verts = vertices; 243 element.lineWidth = lineWidth; 244 element.lineColor = lineColor; 245 element.isClosePolygon = true; 246 element.isStroke = true; 247 element.lineCap = "butt"; 248 element.fillColor = fillColor; 249 if (fillColor) { 250 if(fillColor.a == null) 251 fillColor.a = 255; 252 element.isFill = true; 253 } 254 this._buffer.push(element); 255 }, 256 257 /** 258 * draws a circle given the center, radius and number of segments. 259 * @override 260 * @param {cc.Point} center center of circle 261 * @param {Number} radius 262 * @param {Number} angle angle in radians 263 * @param {Number} segments 264 * @param {Boolean} drawLineToCenter 265 * @param {Number} lineWidth 266 * @param {cc.Color} color 267 */ 268 drawCircle: function (center, radius, angle, segments, drawLineToCenter, lineWidth, color) { 269 lineWidth = lineWidth || this._lineWidth; 270 color = color || this.getDrawColor(); 271 if (color.a == null) 272 color.a = 255; 273 274 var coef = 2.0 * Math.PI / segments; 275 var vertices = []; 276 for (var i = 0; i <= segments; i++) { 277 var rads = i * coef; 278 var j = radius * Math.cos(rads + angle) + center.x; 279 var k = radius * Math.sin(rads + angle) + center.y; 280 vertices.push(cc.p(j, k)); 281 } 282 if (drawLineToCenter) { 283 vertices.push(cc.p(center.x, center.y)); 284 } 285 286 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 287 element.verts = vertices; 288 element.lineWidth = lineWidth; 289 element.lineColor = color; 290 element.isClosePolygon = true; 291 element.isStroke = true; 292 this._buffer.push(element); 293 }, 294 295 /** 296 * draws a quad bezier path 297 * @override 298 * @param {cc.Point} origin 299 * @param {cc.Point} control 300 * @param {cc.Point} destination 301 * @param {Number} segments 302 * @param {Number} lineWidth 303 * @param {cc.Color} color 304 */ 305 drawQuadBezier: function (origin, control, destination, segments, lineWidth, color) { 306 lineWidth = lineWidth || this._lineWidth; 307 color = color || this.getDrawColor(); 308 if (color.a == null) 309 color.a = 255; 310 311 var vertices = [], t = 0.0; 312 for (var i = 0; i < segments; i++) { 313 var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 314 var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 315 vertices.push(cc.p(x, y)); 316 t += 1.0 / segments; 317 } 318 vertices.push(cc.p(destination.x, destination.y)); 319 320 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 321 element.verts = vertices; 322 element.lineWidth = lineWidth; 323 element.lineColor = color; 324 element.isStroke = true; 325 element.lineCap = "round"; 326 this._buffer.push(element); 327 }, 328 329 /** 330 * draws a cubic bezier path 331 * @override 332 * @param {cc.Point} origin 333 * @param {cc.Point} control1 334 * @param {cc.Point} control2 335 * @param {cc.Point} destination 336 * @param {Number} segments 337 * @param {Number} lineWidth 338 * @param {cc.Color} color 339 */ 340 drawCubicBezier: function (origin, control1, control2, destination, segments, lineWidth, color) { 341 lineWidth = lineWidth || this._lineWidth; 342 color = color || this.getDrawColor(); 343 if (color.a == null) 344 color.a = 255; 345 346 var vertices = [], t = 0; 347 for (var i = 0; i < segments; i++) { 348 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; 349 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; 350 vertices.push(cc.p(x, y)); 351 t += 1.0 / segments; 352 } 353 vertices.push(cc.p(destination.x, destination.y)); 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 CatmullRom curve 366 * @override 367 * @param {Array} points 368 * @param {Number} segments 369 * @param {Number} [lineWidth] 370 * @param {cc.Color} [color] 371 */ 372 drawCatmullRom: function (points, segments, lineWidth, color) { 373 this.drawCardinalSpline(points, 0.5, segments, lineWidth, color); 374 }, 375 376 /** 377 * draw a cardinal spline path 378 * @override 379 * @param {Array} config 380 * @param {Number} tension 381 * @param {Number} segments 382 * @param {Number} [lineWidth] 383 * @param {cc.Color} [color] 384 */ 385 drawCardinalSpline: function (config, tension, segments, lineWidth, color) { 386 lineWidth = lineWidth || this._lineWidth; 387 color = color || this.getDrawColor(); 388 if(color.a == null) 389 color.a = 255; 390 391 var vertices = [], p, lt, deltaT = 1.0 / config.length; 392 for (var i = 0; i < segments + 1; i++) { 393 var dt = i / segments; 394 // border 395 if (dt === 1) { 396 p = config.length - 1; 397 lt = 1; 398 } else { 399 p = 0 | (dt / deltaT); 400 lt = (dt - deltaT * p) / deltaT; 401 } 402 403 // Interpolate 404 var newPos = cc.cardinalSplineAt( 405 cc.getControlPointAt(config, p - 1), 406 cc.getControlPointAt(config, p - 0), 407 cc.getControlPointAt(config, p + 1), 408 cc.getControlPointAt(config, p + 2), 409 tension, lt); 410 vertices.push(newPos); 411 } 412 413 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 414 element.verts = vertices; 415 element.lineWidth = lineWidth; 416 element.lineColor = color; 417 element.isStroke = true; 418 element.lineCap = "round"; 419 this._buffer.push(element); 420 }, 421 422 /** 423 * draw a dot at a position, with a given radius and color 424 * @param {cc.Point} pos 425 * @param {Number} radius 426 * @param {cc.Color} [color] 427 */ 428 drawDot: function (pos, radius, color) { 429 color = color || this.getDrawColor(); 430 if (color.a == null) 431 color.a = 255; 432 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_DOT); 433 element.verts = [pos]; 434 element.lineWidth = radius; 435 element.fillColor = color; 436 this._buffer.push(element); 437 }, 438 439 /** 440 * draws an array of points. 441 * @override 442 * @param {Array} points point of array 443 * @param {Number} radius 444 * @param {cc.Color} [color] 445 */ 446 drawDots: function(points, radius, color){ 447 if(!points || points.length == 0) 448 return; 449 color = color || this.getDrawColor(); 450 if (color.a == null) 451 color.a = 255; 452 for(var i = 0, len = points.length; i < len; i++) 453 this.drawDot(points[i], radius, color); 454 }, 455 456 /** 457 * draw a segment with a radius and color 458 * @param {cc.Point} from 459 * @param {cc.Point} to 460 * @param {Number} [lineWidth] 461 * @param {cc.Color} [color] 462 */ 463 drawSegment: function (from, to, lineWidth, color) { 464 lineWidth = lineWidth || this._lineWidth; 465 color = color || this.getDrawColor(); 466 if (color.a == null) 467 color.a = 255; 468 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 469 element.verts = [from, to]; 470 element.lineWidth = lineWidth * 2; 471 element.lineColor = color; 472 element.isStroke = true; 473 element.lineCap = "round"; 474 this._buffer.push(element); 475 }, 476 477 /** 478 * draw a polygon with a fill color and line color without copying the vertex list 479 * @param {Array} verts 480 * @param {cc.Color|null} fillColor Fill color or `null` for a hollow polygon. 481 * @param {Number} [lineWidth] 482 * @param {cc.Color} [color] 483 */ 484 drawPoly_: function (verts, fillColor, lineWidth, color) { 485 lineWidth = (lineWidth == null ) ? this._lineWidth : lineWidth; 486 color = color || this.getDrawColor(); 487 if (color.a == null) 488 color.a = 255; 489 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 490 491 element.verts = verts; 492 element.fillColor = fillColor; 493 element.lineWidth = lineWidth; 494 element.lineColor = color; 495 element.isClosePolygon = true; 496 element.isStroke = true; 497 element.lineCap = "round"; 498 if (fillColor) 499 element.isFill = true; 500 this._buffer.push(element); 501 }, 502 503 /** 504 * draw a polygon with a fill color and line color, copying the vertex list 505 * @param {Array} verts 506 * @param {cc.Color|null} fillColor Fill color or `null` for a hollow polygon. 507 * @param {Number} [lineWidth] 508 * @param {cc.Color} [lineColor] 509 */ 510 drawPoly: function (verts, fillColor, lineWidth, lineColor) { 511 var vertsCopy = []; 512 for (var i=0; i < verts.length; i++) { 513 vertsCopy.push(cc.p(verts[i].x, verts[i].y)); 514 } 515 return this.drawPoly_(vertsCopy, fillColor, lineWidth, lineColor); 516 }, 517 518 /** 519 * Clear the geometry in the node's buffer. 520 */ 521 clear: function () { 522 this._buffer.length = 0; 523 }, 524 525 _createRenderCmd: function(){ 526 return new cc.DrawNode.CanvasRenderCmd(this); 527 } 528 }); 529 } 530 else if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) { 531 532 cc.extend(cc.DrawNode.prototype, { 533 _bufferCapacity:0, 534 535 _trianglesArrayBuffer:null, 536 _trianglesWebBuffer:null, 537 _trianglesReader:null, 538 539 _dirty:false, 540 _className:"DrawNodeWebGL", 541 542 ctor:function () { 543 cc.Node.prototype.ctor.call(this); 544 this._buffer = []; 545 this._blendFunc = new cc.BlendFunc(cc.SRC_ALPHA, cc.ONE_MINUS_SRC_ALPHA); 546 this._drawColor = cc.color(255,255,255,255); 547 548 this.init(); 549 }, 550 551 init:function () { 552 if (cc.Node.prototype.init.call(this)) { 553 this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_LENGTHTEXTURECOLOR); 554 this._ensureCapacity(64); 555 this._trianglesWebBuffer = cc._renderContext.createBuffer(); 556 this._dirty = true; 557 return true; 558 } 559 return false; 560 }, 561 562 drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { 563 lineWidth = (lineWidth == null) ? this._lineWidth : lineWidth; 564 lineColor = lineColor || this.getDrawColor(); 565 if (lineColor.a == null) 566 lineColor.a = 255; 567 var vertices = [origin, cc.p(destination.x, origin.y), destination, cc.p(origin.x, destination.y)]; 568 if(fillColor == null) 569 this._drawSegments(vertices, lineWidth, lineColor, true); 570 else 571 this.drawPoly(vertices, fillColor, lineWidth, lineColor); 572 }, 573 574 drawCircle: function (center, radius, angle, segments, drawLineToCenter, lineWidth, color) { 575 lineWidth = lineWidth || this._lineWidth; 576 color = color || this.getDrawColor(); 577 if (color.a == null) 578 color.a = 255; 579 var coef = 2.0 * Math.PI / segments, vertices = [], i, len; 580 for (i = 0; i <= segments; i++) { 581 var rads = i * coef; 582 var j = radius * Math.cos(rads + angle) + center.x; 583 var k = radius * Math.sin(rads + angle) + center.y; 584 vertices.push(cc.p(j, k)); 585 } 586 if (drawLineToCenter) 587 vertices.push(cc.p(center.x, center.y)); 588 589 lineWidth *= 0.5; 590 for (i = 0, len = vertices.length; i < len - 1; i++) 591 this.drawSegment(vertices[i], vertices[i + 1], lineWidth, color); 592 }, 593 594 drawQuadBezier: function (origin, control, destination, segments, lineWidth, color) { 595 lineWidth = lineWidth || this._lineWidth; 596 color = color || this.getDrawColor(); 597 if (color.a == null) 598 color.a = 255; 599 var vertices = [], t = 0.0; 600 for (var i = 0; i < segments; i++) { 601 var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 602 var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 603 vertices.push(cc.p(x, y)); 604 t += 1.0 / segments; 605 } 606 vertices.push(cc.p(destination.x, destination.y)); 607 this._drawSegments(vertices, lineWidth, color, false); 608 }, 609 610 drawCubicBezier: function (origin, control1, control2, destination, segments, lineWidth, color) { 611 lineWidth = lineWidth || this._lineWidth; 612 color = color || this.getDrawColor(); 613 if (color.a == null) 614 color.a = 255; 615 var vertices = [], t = 0; 616 for (var i = 0; i < segments; i++) { 617 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; 618 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; 619 vertices.push(cc.p(x, y)); 620 t += 1.0 / segments; 621 } 622 vertices.push(cc.p(destination.x, destination.y)); 623 this._drawSegments(vertices, lineWidth, color, false); 624 }, 625 626 drawCatmullRom: function (points, segments, lineWidth, color) { 627 this.drawCardinalSpline(points, 0.5, segments, lineWidth, color); 628 }, 629 630 drawCardinalSpline: function (config, tension, segments, lineWidth, color) { 631 lineWidth = lineWidth || this._lineWidth; 632 color = color || this.getDrawColor(); 633 if (color.a == null) 634 color.a = 255; 635 var vertices = [], p, lt, deltaT = 1.0 / config.length; 636 637 for (var i = 0; i < segments + 1; i++) { 638 var dt = i / segments; 639 640 // border 641 if (dt === 1) { 642 p = config.length - 1; 643 lt = 1; 644 } else { 645 p = 0 | (dt / deltaT); 646 lt = (dt - deltaT * p) / deltaT; 647 } 648 649 // Interpolate 650 var newPos = cc.cardinalSplineAt( 651 cc.getControlPointAt(config, p - 1), 652 cc.getControlPointAt(config, p - 0), 653 cc.getControlPointAt(config, p + 1), 654 cc.getControlPointAt(config, p + 2), 655 tension, lt); 656 vertices.push(newPos); 657 } 658 659 lineWidth *= 0.5; 660 for (var j = 0, len = vertices.length; j < len - 1; j++) 661 this.drawSegment(vertices[j], vertices[j + 1], lineWidth, color); 662 }, 663 664 _render:function () { 665 var gl = cc._renderContext; 666 667 gl.bindBuffer(gl.ARRAY_BUFFER, this._trianglesWebBuffer); 668 if (this._dirty) { 669 gl.bufferData(gl.ARRAY_BUFFER, this._trianglesArrayBuffer, gl.STREAM_DRAW); 670 this._dirty = false; 671 } 672 var triangleSize = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; 673 674 gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_POSITION); 675 gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_COLOR); 676 gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_TEX_COORDS); 677 678 // vertex 679 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, gl.FLOAT, false, triangleSize, 0); 680 // color 681 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, triangleSize, 8); 682 // texcood 683 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, triangleSize, 12); 684 685 gl.drawArrays(gl.TRIANGLES, 0, this._buffer.length * 3); 686 cc.incrementGLDraws(1); 687 //cc.checkGLErrorDebug(); 688 }, 689 690 _ensureCapacity:function(count){ 691 var _t = this; 692 var locBuffer = _t._buffer; 693 if(locBuffer.length + count > _t._bufferCapacity){ 694 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT; 695 _t._bufferCapacity += Math.max(_t._bufferCapacity, count); 696 //re alloc 697 if((locBuffer == null) || (locBuffer.length === 0)){ 698 //init 699 _t._buffer = []; 700 _t._trianglesArrayBuffer = new ArrayBuffer(TriangleLength * _t._bufferCapacity); 701 _t._trianglesReader = new Uint8Array(_t._trianglesArrayBuffer); 702 } else { 703 var newTriangles = []; 704 var newArrayBuffer = new ArrayBuffer(TriangleLength * _t._bufferCapacity); 705 for(var i = 0; i < locBuffer.length;i++){ 706 newTriangles[i] = new cc.V2F_C4B_T2F_Triangle(locBuffer[i].a,locBuffer[i].b,locBuffer[i].c, 707 newArrayBuffer, i * TriangleLength); 708 } 709 _t._trianglesReader = new Uint8Array(newArrayBuffer); 710 _t._trianglesArrayBuffer = newArrayBuffer; 711 _t._buffer = newTriangles; 712 } 713 } 714 }, 715 716 drawDot:function (pos, radius, color) { 717 color = color || this.getDrawColor(); 718 if (color.a == null) 719 color.a = 255; 720 var c4bColor = {r: 0 | color.r, g: 0 | color.g, b: 0 | color.b, a: 0 | color.a}; 721 var a = {vertices: {x: pos.x - radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: -1.0, v: -1.0}}; 722 var b = {vertices: {x: pos.x - radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: -1.0, v: 1.0}}; 723 var c = {vertices: {x: pos.x + radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: 1.0, v: 1.0}}; 724 var d = {vertices: {x: pos.x + radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: 1.0, v: -1.0}}; 725 726 this._ensureCapacity(2*3); 727 728 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)); 729 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)); 730 this._dirty = true; 731 }, 732 733 drawDots: function(points, radius,color) { 734 if(!points || points.length === 0) 735 return; 736 color = color || this.getDrawColor(); 737 if (color.a == null) 738 color.a = 255; 739 for(var i = 0, len = points.length; i < len; i++) 740 this.drawDot(points[i], radius, color); 741 }, 742 743 drawSegment:function (from, to, radius, color) { 744 color = color || this.getDrawColor(); 745 if (color.a == null) 746 color.a = 255; 747 radius = radius || (this._lineWidth * 0.5); 748 var vertexCount = 6*3; 749 this._ensureCapacity(vertexCount); 750 751 var c4bColor = {r: 0 | color.r, g: 0 | color.g, b: 0 | color.b, a: 0 | color.a}; 752 var a = cc.__v2f(from), b = cc.__v2f(to); 753 var n = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(b, a))), t = cc.v2fperp(n); 754 var nw = cc.v2fmult(n, radius), tw = cc.v2fmult(t, radius); 755 756 var v0 = cc.v2fsub(b, cc.v2fadd(nw, tw)); 757 var v1 = cc.v2fadd(b, cc.v2fsub(nw, tw)); 758 var v2 = cc.v2fsub(b, nw); 759 var v3 = cc.v2fadd(b, nw); 760 var v4 = cc.v2fsub(a, nw); 761 var v5 = cc.v2fadd(a, nw); 762 var v6 = cc.v2fsub(a, cc.v2fsub(nw, tw)); 763 var v7 = cc.v2fadd(a, cc.v2fadd(nw, tw)); 764 765 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, triangleBuffer = this._trianglesArrayBuffer, locBuffer = this._buffer; 766 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(cc.v2fadd(n, t)))}, 767 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 768 triangleBuffer, locBuffer.length * TriangleLength)); 769 770 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 771 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 772 triangleBuffer, locBuffer.length * TriangleLength)); 773 774 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 775 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 776 triangleBuffer, locBuffer.length * TriangleLength)); 777 778 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 779 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 780 triangleBuffer, locBuffer.length * TriangleLength)); 781 782 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 783 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 784 triangleBuffer, locBuffer.length * TriangleLength)); 785 786 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 787 {vertices: v7, colors: c4bColor, texCoords: cc.__t(cc.v2fadd(n, t))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 788 triangleBuffer, locBuffer.length * TriangleLength)); 789 this._dirty = true; 790 }, 791 792 drawPoly:function (verts, fillColor, borderWidth, borderColor) { 793 if(fillColor == null){ 794 this._drawSegments(verts, borderWidth, borderColor, true); 795 return; 796 } 797 if (fillColor.a == null) 798 fillColor.a = 255; 799 if (borderColor.a == null) 800 borderColor.a = 255; 801 borderWidth = (borderWidth == null)? this._lineWidth : borderWidth; 802 borderWidth *= 0.5; 803 var c4bFillColor = {r: 0 | fillColor.r, g: 0 | fillColor.g, b: 0 | fillColor.b, a: 0 | fillColor.a}; 804 var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a}; 805 var extrude = [], i, v0, v1, v2, count = verts.length; 806 for (i = 0; i < count; i++) { 807 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 808 v1 = cc.__v2f(verts[i]); 809 v2 = cc.__v2f(verts[(i + 1) % count]); 810 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 811 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 812 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 813 extrude[i] = {offset: offset, n: n2}; 814 } 815 var outline = (borderWidth > 0.0), triangleCount = 3 * count - 2, vertexCount = 3 * triangleCount; 816 this._ensureCapacity(vertexCount); 817 818 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 819 var locBuffer = this._buffer; 820 var inset = (outline == false ? 0.5 : 0.0); 821 for (i = 0; i < count - 2; i++) { 822 v0 = cc.v2fsub(cc.__v2f(verts[0]), cc.v2fmult(extrude[0].offset, inset)); 823 v1 = cc.v2fsub(cc.__v2f(verts[i + 1]), cc.v2fmult(extrude[i + 1].offset, inset)); 824 v2 = cc.v2fsub(cc.__v2f(verts[i + 2]), cc.v2fmult(extrude[i + 2].offset, inset)); 825 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 826 {vertices: v1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: v2, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 827 trianglesBuffer, locBuffer.length * triangleBytesLen)); 828 } 829 830 for (i = 0; i < count; i++) { 831 var j = (i + 1) % count; 832 v0 = cc.__v2f(verts[i]); 833 v1 = cc.__v2f(verts[j]); 834 835 var n0 = extrude[i].n; 836 var offset0 = extrude[i].offset; 837 var offset1 = extrude[j].offset; 838 var inner0 = outline ? cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fsub(v0, cc.v2fmult(offset0, 0.5)); 839 var inner1 = outline ? cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fsub(v1, cc.v2fmult(offset1, 0.5)); 840 var outer0 = outline ? cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fadd(v0, cc.v2fmult(offset0, 0.5)); 841 var outer1 = outline ? cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fadd(v1, cc.v2fmult(offset1, 0.5)); 842 843 if (outline) { 844 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 845 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 846 trianglesBuffer, locBuffer.length * triangleBytesLen)); 847 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 848 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 849 trianglesBuffer, locBuffer.length * triangleBytesLen)); 850 } else { 851 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 852 {vertices: inner1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 853 trianglesBuffer, locBuffer.length * triangleBytesLen)); 854 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 855 {vertices: outer0, colors: c4bFillColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 856 trianglesBuffer, locBuffer.length * triangleBytesLen)); 857 } 858 } 859 extrude = null; 860 this._dirty = true; 861 }, 862 863 _drawSegments: function(verts, borderWidth, borderColor, closePoly){ 864 borderWidth = (borderWidth == null) ? this._lineWidth : borderWidth; 865 borderColor = borderColor || this._drawColor; 866 if(borderColor.a == null) 867 borderColor.a = 255; 868 borderWidth *= 0.5; 869 if (borderWidth <= 0) 870 return; 871 872 var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a }; 873 var extrude = [], i, v0, v1, v2, count = verts.length; 874 for (i = 0; i < count; i++) { 875 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 876 v1 = cc.__v2f(verts[i]); 877 v2 = cc.__v2f(verts[(i + 1) % count]); 878 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 879 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 880 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 881 extrude[i] = {offset: offset, n: n2}; 882 } 883 884 var triangleCount = 3 * count - 2, vertexCount = 3 * triangleCount; 885 this._ensureCapacity(vertexCount); 886 887 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 888 var locBuffer = this._buffer; 889 var len = closePoly ? count : count - 1; 890 for (i = 0; i < len; i++) { 891 var j = (i + 1) % count; 892 v0 = cc.__v2f(verts[i]); 893 v1 = cc.__v2f(verts[j]); 894 895 var n0 = extrude[i].n; 896 var offset0 = extrude[i].offset; 897 var offset1 = extrude[j].offset; 898 var inner0 = cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)); 899 var inner1 = cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)); 900 var outer0 = cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)); 901 var outer1 = cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)); 902 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 903 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 904 trianglesBuffer, locBuffer.length * triangleBytesLen)); 905 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 906 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 907 trianglesBuffer, locBuffer.length * triangleBytesLen)); 908 } 909 extrude = null; 910 this._dirty = true; 911 }, 912 913 clear:function () { 914 this._buffer.length = 0; 915 this._dirty = true; 916 }, 917 918 _createRenderCmd: function () { 919 return new cc.DrawNode.WebGLRenderCmd(this); 920 } 921 }); 922 } 923 }); 924