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