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 for Canvas <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 * @extends cc.Node 89 */ 90 cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNodeCanvas# */{ 91 _buffer: null, 92 _blendFunc: null, 93 _lineWidth: 0, 94 _drawColor: null, 95 96 ctor: function () { 97 cc.Node.prototype.ctor.call(this); 98 this._buffer = []; 99 this._lineWidth = 1; 100 this._drawColor = new cc.Color4F(255, 255, 255, 255); 101 this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); 102 }, 103 104 // ----common function start ---- 105 getBlendFunc: function () { 106 return this._blendFunc; 107 }, 108 109 setBlendFunc: function (blendFunc) { 110 this._blendFunc = blendFunc; 111 }, 112 113 /** 114 * line width setter 115 * @param {Number} width 116 */ 117 setLineWidth: function (width) { 118 this._lineWidth = width; 119 }, 120 121 /** 122 * line width getter 123 * @returns {Number} 124 */ 125 getLineWidth: function () { 126 return this._lineWidth; 127 }, 128 129 /** 130 * draw color setter 131 * @param {cc.Color4F} color 132 */ 133 setDrawColor: function (color) { 134 this._drawColor.r = color.r; 135 this._drawColor.g = color.g; 136 this._drawColor.b = color.b; 137 this._drawColor.a = color.a; 138 }, 139 140 /** 141 * draw color getter 142 * @returns {cc.Color4F} 143 */ 144 getDrawColor: function () { 145 return new cc.Color4F(this._drawColor.r, this._drawColor.g, this._drawColor.b, this._drawColor.a); 146 }, 147 // ----common function end ---- 148 149 150 /** 151 * draws a rectangle given the origin and destination point measured in points. 152 * @param {cc.Point} origin 153 * @param {cc.Point} destination 154 * @param {cc.Color4F} fillColor 155 * @param {Number} lineWidth 156 * @param {cc.Color4F} lineColor 157 */ 158 drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { 159 lineWidth = lineWidth || this._lineWidth; 160 lineColor = lineColor || this.getDrawColor(); 161 var vertices = [ 162 origin, 163 cc.p(destination.x, origin.y), 164 destination, 165 cc.p(origin.x, destination.y) 166 ]; 167 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 168 element.verts = vertices; 169 element.lineWidth = lineWidth; 170 element.lineColor = lineColor; 171 element.isClosePolygon = true; 172 element.isStroke = true; 173 element.lineCap = "butt"; 174 element.fillColor = fillColor; 175 if (fillColor) { 176 element.isFill = true; 177 } 178 this._buffer.push(element); 179 }, 180 181 /** 182 * draws a circle given the center, radius and number of segments. 183 * @override 184 * @param {cc.Point} center center of circle 185 * @param {Number} radius 186 * @param {Number} angle angle in radians 187 * @param {Number} segments 188 * @param {Boolean} drawLineToCenter 189 * @param {Number} lineWidth 190 * @param {cc.Color4F} color 191 */ 192 drawCircle: function (center, radius, angle, segments, drawLineToCenter, lineWidth, color) { 193 lineWidth = lineWidth || this._lineWidth; 194 color = color || this.getDrawColor(); 195 196 var coef = 2.0 * Math.PI / segments; 197 var vertices = []; 198 for (var i = 0; i <= segments; i++) { 199 var rads = i * coef; 200 var j = radius * Math.cos(rads + angle) + center.x; 201 var k = radius * Math.sin(rads + angle) + center.y; 202 vertices.push(cc.p(j, k)); 203 } 204 if (drawLineToCenter) { 205 vertices.push(cc.p(center.x, center.y)); 206 } 207 208 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 209 element.verts = vertices; 210 element.lineWidth = lineWidth; 211 element.lineColor = color; 212 element.isClosePolygon = true; 213 element.isStroke = true; 214 this._buffer.push(element); 215 }, 216 217 /** 218 * draws a quad bezier path 219 * @override 220 * @param {cc.Point} origin 221 * @param {cc.Point} control 222 * @param {cc.Point} destination 223 * @param {Number} segments 224 * @param {Number} lineWidth 225 * @param {cc.Color4F} color 226 */ 227 drawQuadBezier: function (origin, control, destination, segments, lineWidth, color) { 228 lineWidth = lineWidth || this._lineWidth; 229 color = color || this.getDrawColor(); 230 231 var vertices = []; 232 var t = 0.0; 233 for (var i = 0; i < segments; i++) { 234 var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 235 var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 236 vertices.push(cc.p(x, y)); 237 t += 1.0 / segments; 238 } 239 vertices.push(cc.p(destination.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 = color; 245 element.isStroke = true; 246 element.lineCap = "round"; 247 this._buffer.push(element); 248 }, 249 250 /** 251 * draws a cubic bezier path 252 * @override 253 * @param {cc.Point} origin 254 * @param {cc.Point} control1 255 * @param {cc.Point} control2 256 * @param {cc.Point} destination 257 * @param {Number} segments 258 * @param {Number} lineWidth 259 * @param {cc.Color4F} color 260 */ 261 drawCubicBezier: function (origin, control1, control2, destination, segments, lineWidth, color) { 262 lineWidth = lineWidth || this._lineWidth; 263 color = color || this.getDrawColor(); 264 265 var vertices = []; 266 var t = 0; 267 for (var i = 0; i < segments; i++) { 268 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; 269 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; 270 vertices.push(cc.p(x, y)); 271 t += 1.0 / segments; 272 } 273 vertices.push(cc.p(destination.x, destination.y)); 274 275 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 276 element.verts = vertices; 277 element.lineWidth = lineWidth; 278 element.lineColor = color; 279 element.isStroke = true; 280 element.lineCap = "round"; 281 this._buffer.push(element); 282 }, 283 284 /** 285 * draw a CatmullRom curve 286 * @override 287 * @param {Array} points 288 * @param {Number} segments 289 * @param {Number} lineWidth 290 * @param {cc.Color4F} color 291 */ 292 drawCatmullRom: function (points, segments, lineWidth, color) { 293 this.drawCardinalSpline(points, 0.5, segments, lineWidth, color); 294 }, 295 296 /** 297 * draw a cardinal spline path 298 * @override 299 * @param {Array} config 300 * @param {Number} tension 301 * @param {Number} segments 302 * @param {Number} lineWidth 303 * @param {cc.Color4F} color 304 */ 305 drawCardinalSpline: function (config, tension, segments, lineWidth, color) { 306 lineWidth = lineWidth || this._lineWidth; 307 color = color || this.getDrawColor(); 308 309 var vertices = []; 310 var p, lt; 311 var deltaT = 1.0 / config.length; 312 313 for (var i = 0; i < segments + 1; i++) { 314 var dt = i / segments; 315 316 // border 317 if (dt == 1) { 318 p = config.length - 1; 319 lt = 1; 320 } else { 321 p = 0 | (dt / deltaT); 322 lt = (dt - deltaT * p) / deltaT; 323 } 324 325 // Interpolate 326 var newPos = cc.CardinalSplineAt( 327 cc.getControlPointAt(config, p - 1), 328 cc.getControlPointAt(config, p - 0), 329 cc.getControlPointAt(config, p + 1), 330 cc.getControlPointAt(config, p + 2), 331 tension, lt); 332 vertices.push(newPos); 333 } 334 335 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 336 element.verts = vertices; 337 element.lineWidth = lineWidth; 338 element.lineColor = color; 339 element.isStroke = true; 340 element.lineCap = "round"; 341 this._buffer.push(element); 342 }, 343 344 /** 345 * draw a dot at a position, with a given radius and color 346 * @param {cc.Point} pos 347 * @param {Number} radius 348 * @param {cc.Color4F} color 349 */ 350 drawDot: function (pos, radius, color) { 351 color = color || this.getDrawColor(); 352 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_DOT); 353 element.verts = [pos]; 354 element.lineWidth = radius; 355 element.fillColor = color; 356 this._buffer.push(element); 357 }, 358 359 /** 360 * draw a segment with a radius and color 361 * @param {cc.Point} from 362 * @param {cc.Point} to 363 * @param {Number} lineWidth 364 * @param {cc.Color4F} color 365 */ 366 drawSegment: function (from, to, lineWidth, color) { 367 lineWidth = lineWidth || this._lineWidth; 368 color = color || this.getDrawColor(); 369 370 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 371 element.verts = [from, to]; 372 element.lineWidth = lineWidth; 373 element.lineColor = color; 374 element.isStroke = true; 375 element.lineCap = "round"; 376 this._buffer.push(element); 377 }, 378 379 /** 380 * draw a polygon with a fill color and line color without copying the vertex list 381 * @param {Array} verts 382 * @param {cc.Color4F} fillColor 383 * @param {Number} lineWidth 384 * @param {cc.Color4F} color 385 */ 386 drawPoly_: function (verts, fillColor, lineWidth, color) { 387 lineWidth = lineWidth || this._lineWidth; 388 color = color || this.getDrawColor(); 389 var element = new cc._DrawNodeElement(cc.DrawNode.TYPE_POLY); 390 391 element.verts = verts; 392 element.fillColor = fillColor; 393 element.lineWidth = lineWidth; 394 element.lineColor = color; 395 element.isClosePolygon = true; 396 element.isStroke = true; 397 element.lineCap = "round"; 398 if (fillColor) { 399 element.isFill = true; 400 } 401 this._buffer.push(element); 402 }, 403 404 /** 405 * draw a polygon with a fill color and line color, copying the vertex list 406 * @param {Array} verts 407 * @param {cc.Color4F} fillColor 408 * @param {Number} lineWidth 409 * @param {cc.Color4F} color 410 */ 411 drawPoly: function (verts, fillColor, lineWidth, color) { 412 var vertsCopy = []; 413 for (var i=0; i < verts.length; i++) { 414 vertsCopy.push(cc.p(verts[i].x, verts[i].y)); 415 } 416 return this.drawPoly_(vertsCopy, fillColor, lineWidth, color); 417 }, 418 419 draw: function (ctx) { 420 var context = ctx || cc.renderContext; 421 if ((this._blendFunc && (this._blendFunc.src == gl.SRC_ALPHA) && (this._blendFunc.dst == gl.ONE))) 422 context.globalCompositeOperation = 'lighter'; 423 424 for (var i = 0; i < this._buffer.length; i++) { 425 var element = this._buffer[i]; 426 switch (element.type) { 427 case cc.DrawNode.TYPE_DOT: 428 this._drawDot(context, element); 429 break; 430 case cc.DrawNode.TYPE_SEGMENT: 431 this._drawSegment(context, element); 432 break; 433 case cc.DrawNode.TYPE_POLY: 434 this._drawPoly(context, element); 435 break; 436 } 437 } 438 }, 439 440 _drawDot: function (ctx, element) { 441 var locColor = element.fillColor; 442 var locPos = element.verts[0]; 443 var locRadius = element.lineWidth; 444 var locScaleX = cc.EGLView.getInstance().getScaleX(), locScaleY = cc.EGLView.getInstance().getScaleY(); 445 446 ctx.fillStyle = "rgba(" + (0 | (locColor.r * 255)) + "," + (0 | (locColor.g * 255)) + "," + (0 | (locColor.b * 255)) + "," + locColor.a + ")"; 447 ctx.beginPath(); 448 ctx.arc(locPos.x * locScaleX, -locPos.y * locScaleY, locRadius * locScaleX, 0, Math.PI * 2, false); 449 ctx.closePath(); 450 ctx.fill(); 451 }, 452 453 _drawSegment: function (ctx, element) { 454 var locColor = element.lineColor; 455 var locFrom = element.verts[0]; 456 var locTo = element.verts[1]; 457 var locLineWidth = element.lineWidth; 458 var locLineCap = element.lineCap; 459 var locScaleX = cc.EGLView.getInstance().getScaleX(), locScaleY = cc.EGLView.getInstance().getScaleY(); 460 461 ctx.strokeStyle = "rgba(" + (0 | (locColor.r * 255)) + "," + (0 | (locColor.g * 255)) + "," + (0 | (locColor.b * 255)) + "," + locColor.a + ")"; 462 ctx.lineWidth = locLineWidth * locScaleX; 463 ctx.beginPath(); 464 ctx.lineCap = locLineCap; 465 ctx.moveTo(locFrom.x * locScaleX, -locFrom.y * locScaleY); 466 ctx.lineTo(locTo.x * locScaleX, -locTo.y * locScaleY); 467 ctx.stroke(); 468 }, 469 470 _drawPoly: function (ctx, element) { 471 var locVertices = element.verts; 472 var locLineCap = element.lineCap; 473 var locFillColor = element.fillColor; 474 var locLineWidth = element.lineWidth; 475 var locLineColor = element.lineColor; 476 var locIsClosePolygon = element.isClosePolygon; 477 var locIsFill = element.isFill; 478 var locIsStroke = element.isStroke; 479 if (locVertices == null) 480 return; 481 482 var firstPoint = locVertices[0]; 483 var locScaleX = cc.EGLView.getInstance().getScaleX(), locScaleY = cc.EGLView.getInstance().getScaleY(); 484 485 ctx.lineCap = locLineCap; 486 487 if (locFillColor) { 488 ctx.fillStyle = "rgba(" + (0 | (locFillColor.r * 255)) + "," + (0 | (locFillColor.g * 255)) + "," 489 + (0 | (locFillColor.b * 255)) + "," + locFillColor.a + ")"; 490 } 491 492 if (locLineWidth) { 493 ctx.lineWidth = locLineWidth * locScaleX; 494 } 495 if (locLineColor) { 496 ctx.strokeStyle = "rgba(" + (0 | (locLineColor.r * 255)) + "," + (0 | (locLineColor.g * 255)) + "," 497 + (0 | (locLineColor.b * 255)) + "," + locLineColor.a + ")"; 498 } 499 ctx.beginPath(); 500 ctx.moveTo(firstPoint.x * locScaleX, -firstPoint.y * locScaleY); 501 for (var i = 1, len = locVertices.length; i < len; i++) 502 ctx.lineTo(locVertices[i].x * locScaleX, -locVertices[i].y * locScaleY); 503 504 if (locIsClosePolygon) 505 ctx.closePath(); 506 507 if (locIsFill) 508 ctx.fill(); 509 if (locIsStroke) 510 ctx.stroke(); 511 }, 512 513 /** 514 * Clear the geometry in the node's buffer. 515 */ 516 clear: function () { 517 this._buffer.length = 0; 518 } 519 }); 520 521 /** 522 * <p>CCDrawNode for WebGL <br/> 523 * Node that draws dots, segments and polygons. <br/> 524 * Faster than the "drawing primitives" since they it draws everything in one single batch.</p> 525 * @class 526 * @extends cc.Node 527 */ 528 cc.DrawNodeWebGL = cc.Node.extend(/** @lends cc.DrawNodeWebGL# */{ 529 _bufferCapacity:0, 530 _buffer:null, 531 532 _trianglesArrayBuffer:null, 533 _trianglesWebBuffer:null, 534 _trianglesReader:null, 535 536 _blendFunc:null, 537 _dirty:false, 538 539 // ----common function start ---- 540 getBlendFunc:function () { 541 return this._blendFunc; 542 }, 543 544 setBlendFunc:function (blendFunc) { 545 this._blendFunc = blendFunc; 546 }, 547 // ----common function end ---- 548 549 ctor:function () { 550 cc.Node.prototype.ctor.call(this); 551 this._buffer = []; 552 this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); 553 }, 554 555 init:function () { 556 if (cc.Node.prototype.init.call(this)) { 557 this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_LENGTHTEXTURECOLOR)); 558 this._ensureCapacity(512); 559 this._trianglesWebBuffer = cc.renderContext.createBuffer(); 560 this._dirty = true; 561 return true; 562 } 563 return false; 564 }, 565 566 _render:function () { 567 var gl = cc.renderContext; 568 569 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); 570 gl.bindBuffer(gl.ARRAY_BUFFER, this._trianglesWebBuffer); 571 if (this._dirty) { 572 gl.bufferData(gl.ARRAY_BUFFER, this._trianglesArrayBuffer, gl.STREAM_DRAW); 573 this._dirty = false; 574 } 575 var triangleSize = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; 576 577 // vertex 578 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, gl.FLOAT, false, triangleSize, 0); 579 // color 580 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, triangleSize, 8); 581 // texcood 582 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, triangleSize, 12); 583 584 gl.drawArrays(gl.TRIANGLES, 0, this._buffer.length * 3); 585 cc.INCREMENT_GL_DRAWS(1); 586 //cc.CHECK_GL_ERROR_DEBUG(); 587 }, 588 589 _ensureCapacity:function(count){ 590 if(this._buffer.length + count > this._bufferCapacity){ 591 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT; 592 this._bufferCapacity += Math.max(this._bufferCapacity, count); 593 //re alloc 594 if((this._buffer == null) || (this._buffer.length === 0)){ 595 //init 596 this._buffer = []; 597 this._trianglesArrayBuffer = new ArrayBuffer(TriangleLength * this._bufferCapacity); 598 this._trianglesReader = new Uint8Array(this._trianglesArrayBuffer); 599 } else { 600 var newTriangles = this._buffer; 601 newTriangles.length = 0; 602 var newArrayBuffer = new ArrayBuffer(TriangleLength * this._bufferCapacity); 603 604 for(var i = 0; i < this._buffer.length;i++){ 605 newTriangles[i] = new cc.V2F_C4B_T2F_Triangle(this._buffer[i].a,this._buffer[i].b,this._buffer[i].c, 606 newArrayBuffer,i * TriangleLength); 607 } 608 this._trianglesReader = new Uint8Array(newArrayBuffer); 609 this._trianglesArrayBuffer = newArrayBuffer; 610 } 611 } 612 }, 613 614 draw:function () { 615 cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); 616 this._shaderProgram.use(); 617 this._shaderProgram.setUniformsForBuiltins(); 618 this._render(); 619 }, 620 621 /** 622 * draw a dot at a position, with a given radius and color 623 * @param {cc.Point} pos 624 * @param {Number} radius 625 * @param {cc.Color4F} color 626 */ 627 drawDot:function (pos, radius, color) { 628 var c4bColor = {r: 0 | (color.r * 255), g: 0 | (color.g * 255), b: 0 | (color.b * 255), a: 0 | (color.a * 255)}; 629 var a = {vertices: {x: pos.x - radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: -1.0, v: -1.0}}; 630 var b = {vertices: {x: pos.x - radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: -1.0, v: 1.0}}; 631 var c = {vertices: {x: pos.x + radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: 1.0, v: 1.0}}; 632 var d = {vertices: {x: pos.x + radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: 1.0, v: -1.0}}; 633 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)); 634 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)); 635 this._dirty = true; 636 }, 637 638 /** 639 * draw a segment with a radius and color 640 * @param {cc.Point} from 641 * @param {cc.Point} to 642 * @param {Number} radius 643 * @param {cc.Color4F} color 644 */ 645 drawSegment:function (from, to, radius, color) { 646 var vertexCount = 6*3; 647 this._ensureCapacity(vertexCount); 648 649 var c4bColor = {r: 0 | (color.r * 255), g: 0 | (color.g * 255), b: 0 | (color.b * 255), a: 0 | (color.a * 255)}; 650 var a = cc.__v2f(from); 651 var b = cc.__v2f(to); 652 653 var n = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(b, a))); 654 var t = cc.v2fperp(n); 655 656 var nw = cc.v2fmult(n, radius); 657 var tw = cc.v2fmult(t, radius); 658 var v0 = cc.v2fsub(b, cc.v2fadd(nw, tw)); 659 var v1 = cc.v2fadd(b, cc.v2fsub(nw, tw)); 660 var v2 = cc.v2fsub(b, nw); 661 var v3 = cc.v2fadd(b, nw); 662 var v4 = cc.v2fsub(a, nw); 663 var v5 = cc.v2fadd(a, nw); 664 var v6 = cc.v2fsub(a, cc.v2fsub(nw, tw)); 665 var v7 = cc.v2fadd(a, cc.v2fadd(nw, tw)); 666 667 var TriangleLength = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, triangleBuffer = this._trianglesArrayBuffer; 668 this._buffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(cc.v2fadd(n, t)))}, 669 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 670 triangleBuffer, this._buffer.length * TriangleLength)); 671 672 this._buffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 673 {vertices: v1, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(n, t))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 674 triangleBuffer, this._buffer.length * TriangleLength)); 675 676 this._buffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 677 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v2, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, 678 triangleBuffer, this._buffer.length * TriangleLength)); 679 680 this._buffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v3, colors: c4bColor, texCoords: cc.__t(n)}, 681 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 682 triangleBuffer, this._buffer.length * TriangleLength)); 683 684 this._buffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 685 {vertices: v4, colors: c4bColor, texCoords: cc.__t(cc.v2fneg(n))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 686 triangleBuffer, this._buffer.length * TriangleLength)); 687 688 this._buffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v6, colors: c4bColor, texCoords: cc.__t(cc.v2fsub(t, n))}, 689 {vertices: v7, colors: c4bColor, texCoords: cc.__t(cc.v2fadd(n, t))}, {vertices: v5, colors: c4bColor, texCoords: cc.__t(n)}, 690 triangleBuffer, this._buffer.length * TriangleLength)); 691 this._dirty = true; 692 }, 693 694 /** 695 * draw a polygon with a fill color and line color 696 * @param {Array} verts 697 * @param {cc.Color4F} fillColor 698 * @param {Number} borderWidth 699 * @param {cc.Color4F} borderColor 700 */ 701 drawPoly:function (verts, fillColor, borderWidth, borderColor) { 702 var c4bFillColor = {r: 0 | (fillColor.r * 255), g: 0 | (fillColor.g * 255), b: 0 | (fillColor.b * 255), a: 0 | (fillColor.a * 255)}; 703 var c4bBorderColor = {r: 0 | (borderColor.r * 255), g: 0 | (borderColor.g * 255), b: 0 | (borderColor.b * 255), a: 0 | (borderColor.a * 255)}; 704 var extrude = [], i; 705 var v0, v1, v2; 706 var count = verts.length; 707 for (i = 0; i < count; i++) { 708 v0 = cc.__v2f(verts[(i - 1 + count) % count]); 709 v1 = cc.__v2f(verts[i]); 710 v2 = cc.__v2f(verts[(i + 1) % count]); 711 var n1 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v1, v0))); 712 var n2 = cc.v2fnormalize(cc.v2fperp(cc.v2fsub(v2, v1))); 713 var offset = cc.v2fmult(cc.v2fadd(n1, n2), 1.0 / (cc.v2fdot(n1, n2) + 1.0)); 714 extrude[i] = {offset: offset, n: n2}; 715 } 716 var outline = (borderWidth > 0.0); 717 718 var triangleCount = 3 * count -2; 719 var vertexCount = 3 * triangleCount; 720 this._ensureCapacity(vertexCount); 721 722 var triangleBytesLen = cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT, trianglesBuffer = this._trianglesArrayBuffer; 723 var locBuffer = this._buffer; 724 var inset = (outline == false ? 0.5 : 0.0); 725 for (i = 0; i < count - 2; i++) { 726 v0 = cc.v2fsub(cc.__v2f(verts[0]), cc.v2fmult(extrude[0].offset, inset)); 727 v1 = cc.v2fsub(cc.__v2f(verts[i + 1]), cc.v2fmult(extrude[i + 1].offset, inset)); 728 v2 = cc.v2fsub(cc.__v2f(verts[i + 2]), cc.v2fmult(extrude[i + 2].offset, inset)); 729 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: v0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 730 {vertices: v1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: v2, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 731 trianglesBuffer, locBuffer.length * triangleBytesLen)); 732 } 733 734 for (i = 0; i < count; i++) { 735 var j = (i + 1) % count; 736 v0 = cc.__v2f(verts[i]); 737 v1 = cc.__v2f(verts[j]); 738 739 var n0 = extrude[i].n; 740 var offset0 = extrude[i].offset; 741 var offset1 = extrude[j].offset; 742 var inner0 = outline ? cc.v2fsub(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fsub(v0, cc.v2fmult(offset0, 0.5)); 743 var inner1 = outline ? cc.v2fsub(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fsub(v1, cc.v2fmult(offset1, 0.5)); 744 var outer0 = outline ? cc.v2fadd(v0, cc.v2fmult(offset0, borderWidth)) : cc.v2fadd(v0, cc.v2fmult(offset0, 0.5)); 745 var outer1 = outline ? cc.v2fadd(v1, cc.v2fmult(offset1, borderWidth)) : cc.v2fadd(v1, cc.v2fmult(offset1, 0.5)); 746 747 if (outline) { 748 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 749 {vertices: inner1, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 750 trianglesBuffer, locBuffer.length * triangleBytesLen)); 751 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bBorderColor, texCoords: cc.__t(cc.v2fneg(n0))}, 752 {vertices: outer0, colors: c4bBorderColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bBorderColor, texCoords: cc.__t(n0)}, 753 trianglesBuffer, locBuffer.length * triangleBytesLen)); 754 } else { 755 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 756 {vertices: inner1, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 757 trianglesBuffer, locBuffer.length * triangleBytesLen)); 758 locBuffer.push(new cc.V2F_C4B_T2F_Triangle({vertices: inner0, colors: c4bFillColor, texCoords: cc.__t(cc.v2fzero())}, 759 {vertices: outer0, colors: c4bFillColor, texCoords: cc.__t(n0)}, {vertices: outer1, colors: c4bFillColor, texCoords: cc.__t(n0)}, 760 trianglesBuffer, locBuffer.length * triangleBytesLen)); 761 } 762 } 763 extrude = null; 764 this._dirty = true; 765 }, 766 767 /** 768 * Clear the geometry in the node's buffer. 769 */ 770 clear:function () { 771 this._buffer.length = 0; 772 this._dirty = true; 773 } 774 }); 775 776 cc.DrawNode = cc.Browser.supportWebGL ? cc.DrawNodeWebGL : cc.DrawNodeCanvas; 777 778 /** 779 * Creates a DrawNode 780 * @return {cc.DrawNode} 781 */ 782 cc.DrawNode.create = function () { 783 var ret = new cc.DrawNode(); 784 if (ret && ret.init()) 785 return ret; 786 return null; 787 }; 788 789 cc._DrawNodeElement = function (type, verts, fillColor, lineWidth, lineColor, lineCap, isClosePolygon, isFill, isStroke) { 790 this.type = type; 791 this.verts = verts || null; 792 this.fillColor = fillColor || null; 793 this.lineWidth = lineWidth || 0; 794 this.lineColor = lineColor || null; 795 this.lineCap = lineCap || "butt"; 796 this.isClosePolygon = isClosePolygon || false; 797 this.isFill = isFill || false; 798 this.isStroke = isStroke || false; 799 }; 800 801 cc.DrawNode.TYPE_DOT = 0; 802 cc.DrawNode.TYPE_SEGMENT = 1; 803 cc.DrawNode.TYPE_POLY = 2; 804