1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * <p>
 29  *   Drawing primitives Utility Class. this class is base class, it contain some render type version: Canvas, WebGL, DOM.<br/>
 30  *   this class contain some primitive Drawing Method: <br/>
 31  *     - drawPoint<br/>
 32  *     - drawLine<br/>
 33  *     - drawPoly<br/>
 34  *     - drawCircle<br/>
 35  *     - drawQuadBezier<br/>
 36  *     - drawCubicBezier<br/>
 37  *     You can change the color, width and other property by calling these WebGL API:<br/>
 38  *     glColor4ub(), glLineWidth(), glPointSize().<br/>
 39  * </p>
 40  * @class
 41  * @extends cc.Class
 42  * @warning These functions draws the Line, Point, Polygon, immediately. They aren't batched. <br/>
 43  *   If you are going to make a game that depends on these primitives, I suggest creating a batch.
 44  */
 45 cc.DrawingPrimitive = cc.Class.extend(/** @lends cc.DrawingPrimitive# */{
 46     _renderContext:null,
 47 
 48     /**
 49      * set render context of drawing primitive
 50      * @param context
 51      */
 52     setRenderContext:function (context) {
 53         this._renderContext = context;
 54     },
 55 
 56     /**
 57      * returns render context of drawing primitive
 58      * @return {CanvasRenderingContext2D}
 59      */
 60     getRenderContext:function () {
 61         return this._renderContext;
 62     },
 63 
 64     /**
 65      * Constructor
 66      * @param {CanvasRenderingContext2D} renderContext
 67      */
 68     ctor:function (renderContext) {
 69         this._renderContext = renderContext;
 70     },
 71 
 72     /**
 73      * draws a point given x and y coordinate measured in points
 74      * @param {cc.Point} point
 75      */
 76     drawPoint:function (point) {
 77         cc.log("DrawingPrimitive.drawPoint() not implement!");
 78     },
 79 
 80     /**
 81      * draws an array of points.
 82      * @param {Array} points point of array
 83      * @param {Number} numberOfPoints
 84      */
 85     drawPoints:function (points, numberOfPoints) {
 86         cc.log("DrawingPrimitive.drawPoints() not implement!");
 87     },
 88 
 89     /**
 90      * draws a line given the origin and destination point measured in points
 91      * @param {cc.Point} origin
 92      * @param {cc.Point} destination
 93      */
 94     drawLine:function (origin, destination) {
 95         cc.log("DrawingPrimitive.drawLine() not implement!");
 96     },
 97 
 98     /**
 99      * draws a rectangle given the origin and destination point measured in points.
100      * @param {cc.Point} origin
101      * @param {cc.Point} destination
102      */
103     drawRect:function (origin, destination) {
104         cc.log("DrawingPrimitive.drawRect() not implement!");
105     },
106 
107     /**
108      * draws a solid rectangle given the origin and destination point measured in points.
109      * @param {cc.Point} origin
110      * @param {cc.Point} destination
111      * @param {cc.Color4F} color
112      */
113     drawSolidRect:function (origin, destination, color) {
114         cc.log("DrawingPrimitive.drawSolidRect() not implement!");
115     },
116 
117     /**
118      * draws a poligon given a pointer to cc.Point coordiantes and the number of vertices measured in points.
119      * @param {Array} vertices a pointer to cc.Point coordiantes
120      * @param {Number} numOfVertices the number of vertices measured in points
121      * @param {Boolean} closePolygon The polygon can be closed or open
122      * @param {Boolean} fill The polygon can be closed or open and optionally filled with current color
123      */
124     drawPoly:function (vertices, numOfVertices, closePolygon, fill) {
125         cc.log("DrawingPrimitive.drawPoly() not implement!");
126     },
127 
128     /**
129      * draws a solid polygon given a pointer to CGPoint coordiantes, the number of vertices measured in points, and a color.
130      * @param {Array} poli
131      * @param {Number} numberOfPoints
132      * @param {cc.Color4F} color
133      */
134     drawSolidPoly:function (poli, numberOfPoints, color) {
135         cc.log("DrawingPrimitive.drawSolidPoly() not implement!");
136     },
137 
138     /**
139      * draws a circle given the center, radius and number of segments.
140      * @param {cc.Point} center center of circle
141      * @param {Number} radius
142      * @param {Number} angle angle in radians
143      * @param {Number} segments
144      * @param {Boolean} drawLineToCenter
145      */
146     drawCircle:function (center, radius, angle, segments, drawLineToCenter) {
147         cc.log("DrawingPrimitive.drawCircle() not implement!");
148     },
149 
150     /**
151      * draws a quad bezier path
152      * @param {cc.Point} origin
153      * @param {cc.Point} control
154      * @param {cc.Point} destination
155      * @param {Number} segments
156      */
157     drawQuadBezier:function (origin, control, destination, segments) {
158         cc.log("DrawingPrimitive.drawQuadBezier() not implement!");
159     },
160 
161     /**
162      * draws a cubic bezier path
163      * @param {cc.Point} origin
164      * @param {cc.Point} control1
165      * @param {cc.Point} control2
166      * @param {cc.Point} destination
167      * @param {Number} segments
168      */
169     drawCubicBezier:function (origin, control1, control2, destination, segments) {
170         cc.log("DrawingPrimitive.drawCubicBezier() not implement!");
171     },
172 
173     /**
174      * draw a catmull rom line
175      * @param {Array} points
176      * @param {Number} segments
177      */
178     drawCatmullRom:function (points, segments) {
179         cc.log("DrawingPrimitive.drawCardinalSpline() not implement!");
180     },
181 
182     /**
183      * draw a cardinal spline path
184      * @param {Array} config
185      * @param {Number} tension
186      * @param {Number} segments
187      */
188     drawCardinalSpline:function (config, tension, segments) {
189         cc.log("DrawingPrimitive.drawCardinalSpline() not implement!");
190     }
191 });
192 
193 /**
194  * Canvas of DrawingPrimitive implement version
195  * @class
196  * @extends cc.DrawingPrimitive
197  */
198 cc.DrawingPrimitiveCanvas = cc.DrawingPrimitive.extend(/** @lends cc.DrawingPrimitiveCanvas# */{
199     /**
200      * draws a point given x and y coordinate measured in points
201      * @override
202      * @param {cc.Point} point
203      * @param {Number} size
204      */
205     drawPoint:function (point, size) {
206         if (!size) {
207             size = 1;
208         }
209         var newPoint = cc.p(point.x * cc.CONTENT_SCALE_FACTOR(), point.y * cc.CONTENT_SCALE_FACTOR());
210         this._renderContext.beginPath();
211         this._renderContext.arc(newPoint.x, -newPoint.y, size * cc.CONTENT_SCALE_FACTOR(), 0, Math.PI * 2, false);
212         this._renderContext.closePath();
213         this._renderContext.fill();
214     },
215 
216     /**
217      * draws an array of points.
218      * @override
219      * @param {Array} points point of array
220      * @param {Number} numberOfPoints
221      * @param {Number} size
222      */
223     drawPoints:function (points, numberOfPoints, size) {
224         if (points == null) {
225             return;
226         }
227         if (!size) {
228             size = 1;
229         }
230 
231         this._renderContext.beginPath();
232         for (var i = 0; i < points.length; i++) {
233             this._renderContext.arc(points[i].x * cc.CONTENT_SCALE_FACTOR(), -points[i].y * cc.CONTENT_SCALE_FACTOR(),
234                 size * cc.CONTENT_SCALE_FACTOR(), 0, Math.PI * 2, false);
235         }
236         this._renderContext.closePath();
237         this._renderContext.fill();
238     },
239 
240     /**
241      * draws a line given the origin and destination point measured in points
242      * @override
243      * @param {cc.Point} origin
244      * @param {cc.Point} destination
245      */
246     drawLine:function (origin, destination) {
247         this._renderContext.beginPath();
248         this._renderContext.moveTo(origin.x * cc.CONTENT_SCALE_FACTOR(), -origin.y * cc.CONTENT_SCALE_FACTOR());
249         this._renderContext.lineTo(destination.x * cc.CONTENT_SCALE_FACTOR(), -destination.y * cc.CONTENT_SCALE_FACTOR());
250         this._renderContext.closePath();
251         this._renderContext.stroke();
252     },
253 
254     /**
255      * draws a rectangle given the origin and destination point measured in points.
256      * @param {cc.Point} origin
257      * @param {cc.Point} destination
258      */
259     drawRect:function (origin, destination) {
260         this.drawLine(cc.p(origin.x, origin.y), cc.p(destination.x, origin.y));
261         this.drawLine(cc.p(destination.x, origin.y), cc.p(destination.x, destination.y));
262         this.drawLine(cc.p(destination.x, destination.y), cc.p(origin.x, destination.y));
263         this.drawLine(cc.p(origin.x, destination.y), cc.p(origin.x, origin.y));
264     },
265 
266     /**
267      * draws a solid rectangle given the origin and destination point measured in points.
268      * @param {cc.Point} origin
269      * @param {cc.Point} destination
270      * @param {cc.Color4F} color
271      */
272     drawSolidRect:function (origin, destination, color) {
273         var vertices = [
274             origin,
275             cc.p(destination.x, origin.y),
276             destination,
277             cc.p(origin.x, destination.y)
278         ];
279 
280         this.drawSolidPoly(vertices, 4, color);
281     },
282 
283     /**
284      * draws a poligon given a pointer to cc.Point coordiantes and the number of vertices measured in points.
285      * @override
286      * @param {Array} vertices a pointer to cc.Point coordiantes
287      * @param {Number} numOfVertices the number of vertices measured in points
288      * @param {Boolean} closePolygon The polygon can be closed or open
289      * @param {Boolean} fill The polygon can be closed or open and optionally filled with current color
290      */
291     drawPoly:function (vertices, numOfVertices, closePolygon, fill) {
292         if (fill == 'undefined') {
293             fill = false;
294         }
295 
296         if (vertices == null) {
297             return;
298         }
299         if (vertices.length < 3) {
300             throw new Error("Polygon's point must greater than 2");
301         }
302 
303         var firstPoint = vertices[0];
304         this._renderContext.beginPath();
305         this._renderContext.moveTo(firstPoint.x * cc.CONTENT_SCALE_FACTOR(), -firstPoint.y * cc.CONTENT_SCALE_FACTOR());
306         for (var i = 1; i < vertices.length; i++) {
307             this._renderContext.lineTo(vertices[i].x * cc.CONTENT_SCALE_FACTOR(), -vertices[i].y * cc.CONTENT_SCALE_FACTOR());
308         }
309         if (closePolygon) {
310             this._renderContext.closePath();
311         }
312 
313         if (fill) {
314             this._renderContext.fill();
315         } else {
316             this._renderContext.stroke();
317         }
318     },
319 
320     /**
321      * draws a solid polygon given a pointer to CGPoint coordiantes, the number of vertices measured in points, and a color.
322      * @param {Array} poli
323      * @param {Number} numberOfPoints
324      * @param {cc.Color4F} color
325      */
326     drawSolidPoly:function (poli, numberOfPoints, color) {
327         this.setDrawColor4F(color.r, color.g, color.b, color.a);
328         this.drawPoly(poli, numberOfPoints, true, true);
329     },
330 
331     /**
332      * draws a circle given the center, radius and number of segments.
333      * @override
334      * @param {cc.Point} center center of circle
335      * @param {Number} radius
336      * @param {Number} angle angle in radians
337      * @param {Number} segments
338      * @param {Boolean} drawLineToCenter
339      */
340     drawCircle:function (center, radius, angle, segments, drawLineToCenter) {
341         this._renderContext.beginPath();
342         var endAngle = angle - Math.PI * 2;
343         this._renderContext.arc(0 | center.x, 0 | -(center.y), radius, -angle, -endAngle, false);
344         if (drawLineToCenter) {
345             this._renderContext.lineTo(0 | center.x, 0 | -(center.y));
346         }
347         this._renderContext.stroke();
348     },
349 
350     /**
351      * draws a quad bezier path
352      * @override
353      * @param {cc.Point} origin
354      * @param {cc.Point} control
355      * @param {cc.Point} destination
356      * @param {Number} segments
357      */
358     drawQuadBezier:function (origin, control, destination, segments) {
359         //this is OpenGL Algorithm
360         var vertices = [];
361 
362         var t = 0.0;
363         for (var i = 0; i < segments; i++) {
364             var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x;
365             var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y;
366             vertices.push(cc.p(x * cc.CONTENT_SCALE_FACTOR(), y * cc.CONTENT_SCALE_FACTOR()));
367             t += 1.0 / segments;
368         }
369         vertices.push(cc.p(destination.x * cc.CONTENT_SCALE_FACTOR(), destination.y * cc.CONTENT_SCALE_FACTOR()));
370 
371         this.drawPoly(vertices, segments + 1, false, false);
372     },
373 
374     /**
375      * draws a cubic bezier path
376      * @override
377      * @param {cc.Point} origin
378      * @param {cc.Point} control1
379      * @param {cc.Point} control2
380      * @param {cc.Point} destination
381      * @param {Number} segments
382      */
383     drawCubicBezier:function (origin, control1, control2, destination, segments) {
384         //this is OpenGL Algorithm
385         var vertices = [];
386 
387         var t = 0;
388         for (var i = 0; i < segments; i++) {
389             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;
390             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;
391             vertices.push(cc.p(x * cc.CONTENT_SCALE_FACTOR(), y * cc.CONTENT_SCALE_FACTOR()));
392             t += 1.0 / segments;
393         }
394         vertices.push(cc.p(destination.x * cc.CONTENT_SCALE_FACTOR(), destination.y * cc.CONTENT_SCALE_FACTOR()));
395 
396         this.drawPoly(vertices, segments + 1, false, false);
397     },
398 
399     /**
400      * draw a CatmullRom curve
401      * @override
402      * @param {Array} points
403      * @param {Number} segments
404      */
405     drawCatmullRom:function (points, segments) {
406         this.drawCardinalSpline(points, 0.5, segments);
407     },
408 
409     /**
410      * draw a cardinal spline path
411      * @override
412      * @param {Array} config
413      * @param {Number} tension
414      * @param {Number} segments
415      */
416     drawCardinalSpline:function (config, tension, segments) {
417         //lazy_init();
418         cc.renderContext.strokeStyle = "rgba(255,255,255,1)";
419         var points = [];
420         var p, lt;
421         var deltaT = 1.0 / config.length;
422 
423         for (var i = 0; i < segments + 1; i++) {
424             var dt = i / segments;
425 
426             // border
427             if (dt == 1) {
428                 p = config.length - 1;
429                 lt = 1;
430             } else {
431                 p = 0 | (dt / deltaT);
432                 lt = (dt - deltaT * p) / deltaT;
433             }
434 
435             // Interpolate
436             var newPos = cc.CardinalSplineAt(
437                 cc.getControlPointAt(config, p - 1),
438                 cc.getControlPointAt(config, p - 0),
439                 cc.getControlPointAt(config, p + 1),
440                 cc.getControlPointAt(config, p + 2),
441                 tension, lt);
442             points.push(newPos);
443         }
444         this.drawPoly(points, segments + 1, false, false);
445     },
446 
447     /**
448      * draw an image
449      * @override
450      * @param {HTMLImageElement|HTMLCanvasElement} image
451      * @param {cc.Point} sourcePoint
452      * @param {cc.Size} sourceSize
453      * @param {cc.Point} destPoint
454      * @param {cc.Size} destSize
455      */
456     drawImage:function (image, sourcePoint, sourceSize, destPoint, destSize) {
457         var len = arguments.length;
458         switch (len) {
459             case 2:
460                 var height = image.height;
461                 this._renderContext.drawImage(image, sourcePoint.x, -(sourcePoint.y + height));
462                 break;
463             case 3:
464                 this._renderContext.drawImage(image, sourcePoint.x, -(sourcePoint.y + sourceSize.height), sourceSize.width, sourceSize.height);
465                 break;
466             case 5:
467                 this._renderContext.drawImage(image, sourcePoint.x, sourcePoint.y, sourceSize.width, sourceSize.height, destPoint.x, -(destPoint.y + destSize.height),
468                     destSize.width, destSize.height);
469                 break;
470             default:
471                 throw new Error("Argument must be non-nil");
472                 break;
473         }
474     },
475 
476     /**
477      * draw a star
478      * @param {CanvasRenderingContext2D} ctx canvas context
479      * @param {Number} radius
480      * @param {cc.Color3B|cc.Color4B|cc.Color4F} color
481      */
482     drawStar:function (ctx, radius, color) {
483         var context = ctx || this._renderContext;
484         if (color instanceof cc.Color4F)
485             color = new cc.Color3B(0 | (color.r * 255), 0 | (color.g * 255), 0 | (color.b * 255));
486         var colorStr = "rgba(" + color.r + "," + color.g + "," + color.b;
487         context.fillStyle = colorStr + ",1)";
488         var subRadius = radius / 10;
489 
490         context.beginPath();
491         context.moveTo(-radius, radius);
492         context.lineTo(0, subRadius);
493         context.lineTo(radius, radius);
494         context.lineTo(subRadius, 0);
495         context.lineTo(radius, -radius);
496         context.lineTo(0, -subRadius);
497         context.lineTo(-radius, -radius);
498         context.lineTo(-subRadius, 0);
499         context.lineTo(-radius, radius);
500         context.closePath();
501         context.fill();
502 
503         var g1 = context.createRadialGradient(0, 0, subRadius, 0, 0, radius);
504         g1.addColorStop(0, colorStr + ", 1)");
505         g1.addColorStop(0.3, colorStr + ", 0.8)");
506         g1.addColorStop(1.0, colorStr + ", 0.0)");
507         context.fillStyle = g1;
508         context.beginPath();
509         var startAngle_1 = 0;
510         var endAngle_1 = cc.PI2;
511         context.arc(0, 0, radius - subRadius, startAngle_1, endAngle_1, false);
512         context.closePath();
513         context.fill();
514     },
515 
516     /**
517      * draw a color ball
518      * @param {CanvasRenderingContext2D} ctx canvas context
519      * @param {Number} radius
520      * @param {cc.Color3B|cc.Color4B|cc.Color4F} color
521      */
522     drawColorBall:function (ctx, radius, color) {
523         var context = ctx || this._renderContext;
524         if (color instanceof cc.Color4F)
525             color = new cc.Color3B(0 | (color.r * 255), 0 | (color.g * 255), 0 | (color.b * 255));
526         var colorStr = "rgba(" + color.r + "," + color.g + "," + color.b;
527         var subRadius = radius / 10;
528 
529         var g1 = context.createRadialGradient(0, 0, subRadius, 0, 0, radius);
530         g1.addColorStop(0, colorStr + ", 1)");
531         g1.addColorStop(0.3, colorStr + ", 0.8)");
532         g1.addColorStop(0.6, colorStr + ", 0.4)");
533         g1.addColorStop(1.0, colorStr + ", 0.0)");
534         context.fillStyle = g1;
535         context.beginPath();
536         var startAngle_1 = 0;
537         var endAngle_1 = cc.PI2;
538         context.arc(0, 0, radius, startAngle_1, endAngle_1, false);
539         context.closePath();
540         context.fill();
541     },
542 
543     /**
544      * fill text
545      * @param {String} strText
546      * @param {Number} x
547      * @param {Number} y
548      */
549     fillText:function (strText, x, y) {
550         this._renderContext.fillText(strText, x, -y);
551     },
552 
553     /**
554      * set the drawing color with 4 unsigned bytes
555      * @param {Number} r red value (0 to 255)
556      * @param {Number} g green value (0 to 255)
557      * @param {Number} b blue value (0 to 255)
558      * @param {Number} a Alpha value (0 to 255)
559      */
560     setDrawColor4B:function (r, g, b, a) {
561         this._renderContext.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a / 255 + ")";
562         this._renderContext.strokeStyle = "rgba(" + r + "," + g + "," + b + "," + a / 255 + ")";
563     },
564 
565     /**
566      * set the drawing color with 4 floats
567      * @param {Number} r red value (0 to 1)
568      * @param {Number} g green value (0 to 1)
569      * @param {Number} b blue value (0 to 1)
570      * @param {Number} a Alpha value (0 to 1)
571      */
572     setDrawColor4F:function (r, g, b, a) {
573         this._renderContext.fillStyle = "rgba(" + (0 | (r * 255)) + "," + (0 | (g * 255)) + "," + (0 | (b * 255)) + "," + a + ")";
574         this._renderContext.strokeStyle = "rgba(" + (0 | (r * 255)) + "," + (0 | (g * 255)) + "," + (0 | (b * 255)) + "," + a + ")";
575     },
576 
577     /**
578      * set the point size in points. Default 1.
579      * @param {Number} pointSize
580      */
581     setPointSize:function (pointSize) {
582     },
583 
584     /**
585      * set the line width. Default 1.
586      * @param {Number} width
587      */
588     setLineWidth:function (width) {
589         this._renderContext.lineWidth = width;
590     }
591 });
592 
593 /**
594  * Canvas of DrawingPrimitive implement version
595  * @class
596  * @extends cc.DrawingPrimitive
597  */
598 cc.DrawingPrimitiveWebGL = cc.DrawingPrimitive.extend({
599     _initialized:false,
600     _shader: null,
601     _colorLocation:-1,
602     _color: null,
603     _pointSizeLocation:-1,
604     _pointSize:-1,
605 
606     ctor:function (ctx) {
607         if (ctx == null)
608             ctx = cc.renderContext;
609 
610         if (!ctx instanceof  WebGLRenderingContext)
611             throw "Can't initialise DrawingPrimitiveWebGL. context need is WebGLRenderingContext";
612 
613         cc.DrawingPrimitive.prototype.ctor.call(this, ctx);
614         this._color = new cc.Color4F(1.0, 1.0, 1.0, 1.0);
615     },
616 
617     lazy_init:function () {
618         if (!this._initialized) {
619             //
620             // Position and 1 color passed as a uniform (to similate glColor4ub )
621             //
622             this._shader = cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_UCOLOR);
623             this._colorLocation = this._renderContext.getUniformLocation(this._shader.getProgram(), "u_color");
624             this._pointSizeLocation = this._renderContext.getUniformLocation(this._shader.getProgram(), "u_pointSize");
625             //cc.CHECK_GL_ERROR_DEBUG();
626 
627             this._initialized = true;
628         }
629     },
630 
631     /**
632      * initlialize context
633      */
634     drawInit:function () {
635         this._initialized = false;
636     },
637 
638     /**
639      * draws a point given x and y coordinate measured in points
640      * @param {cc.Point} point
641      */
642     drawPoint:function (point) {
643         this.lazy_init();
644 
645         this._shader.use();
646         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
647         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
648         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(this._color._arrayBuffer,0,4), 1);
649         this._shader.setUniformLocationWith1f(this._pointSizeLocation, this._pointSize);
650 
651         var glContext = this._renderContext;
652         var pointBuffer = glContext.createBuffer();
653         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
654         glContext.bufferData(glContext.ARRAY_BUFFER, new Float32Array([point.x, point.y]), glContext.STATIC_DRAW);
655         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
656 
657         glContext.drawArrays(glContext.POINTS, 0, 1);
658         glContext.deleteBuffer(pointBuffer);
659 
660         cc.INCREMENT_GL_DRAWS(1);
661     },
662 
663     /**
664      * draws an array of points.
665      * @param {Array} points point of array
666      * @param {Number} numberOfPoints
667      */
668     drawPoints:function (points, numberOfPoints) {
669         if (!points || points.length == 0)
670             return;
671 
672         this.lazy_init();
673 
674         this._shader.use();
675         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
676         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
677         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(this._color._arrayBuffer,0,4), 1);
678         this._shader.setUniformLocationWith1f(this._pointSizeLocation, this._pointSize);
679 
680         var glContext = this._renderContext;
681         var pointBuffer = glContext.createBuffer();
682         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
683         glContext.bufferData(glContext.ARRAY_BUFFER, this._pointsToTypeArray(points), glContext.STATIC_DRAW);
684         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
685 
686         glContext.drawArrays(glContext.POINTS, 0, points.length);
687         glContext.deleteBuffer(pointBuffer);
688 
689         cc.INCREMENT_GL_DRAWS(1);
690     },
691 
692     _pointsToTypeArray:function (points) {
693         var typeArr = new Float32Array(points.length * 2);
694         for (var i = 0; i < points.length; i++) {
695             typeArr[i * 2] = points[i].x;
696             typeArr[i * 2 + 1] = points[i].y;
697         }
698         return typeArr;
699     },
700 
701     /**
702      * draws a line given the origin and destination point measured in points
703      * @param {cc.Point} origin
704      * @param {cc.Point} destination
705      */
706     drawLine:function (origin, destination) {
707         this.lazy_init();
708 
709         this._shader.use();
710         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
711         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
712         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(this._color._arrayBuffer,0,4), 1);
713 
714         var glContext = this._renderContext;
715         var pointBuffer = glContext.createBuffer();
716         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
717         glContext.bufferData(glContext.ARRAY_BUFFER, this._pointsToTypeArray([origin, destination]), glContext.STATIC_DRAW);
718         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
719 
720         glContext.drawArrays(glContext.LINES, 0, 2);
721         glContext.deleteBuffer(pointBuffer);
722 
723         cc.INCREMENT_GL_DRAWS(1);
724     },
725 
726     /**
727      * draws a rectangle given the origin and destination point measured in points.
728      * @param {cc.Point} origin
729      * @param {cc.Point} destination
730      */
731     drawRect:function (origin, destination) {
732         this.drawLine(cc.p(origin.x, origin.y), cc.p(destination.x, origin.y));
733         this.drawLine(cc.p(destination.x, origin.y), cc.p(destination.x, destination.y));
734         this.drawLine(cc.p(destination.x, destination.y), cc.p(origin.x, destination.y));
735         this.drawLine(cc.p(origin.x, destination.y), cc.p(origin.x, origin.y));
736     },
737 
738     /**
739      * draws a solid rectangle given the origin and destination point measured in points.
740      * @param {cc.Point} origin
741      * @param {cc.Point} destination
742      * @param {cc.Color4F} color
743      */
744     drawSolidRect:function (origin, destination, color) {
745         var vertices = [
746             origin,
747             cc.p(destination.x, origin.y),
748             destination,
749             cc.p(origin.x, destination.y)
750         ];
751 
752         this.drawSolidPoly(vertices, 4, color);
753     },
754 
755     /**
756      * draws a polygon given a pointer to cc.Point coordiantes and the number of vertices measured in points.
757      * @param {Array} vertices a pointer to cc.Point coordiantes
758      * @param {Number} numOfVertices the number of vertices measured in points
759      * @param {Boolean} closePolygon The polygon can be closed or open
760      */
761     drawPoly:function (vertices, numOfVertices, closePolygon) {
762         this.lazy_init();
763 
764         this._shader.use();
765         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
766         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
767         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(this._color._arrayBuffer,0,4), 1);
768 
769         var glContext = this._renderContext;
770         var pointBuffer = glContext.createBuffer();
771         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
772         glContext.bufferData(glContext.ARRAY_BUFFER, this._pointsToTypeArray(vertices), glContext.STATIC_DRAW);
773         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
774 
775         if (closePolygon)
776             glContext.drawArrays(glContext.LINE_LOOP, 0, vertices.length);
777         else
778             glContext.drawArrays(glContext.LINE_STRIP, 0, vertices.length);
779         glContext.deleteBuffer(pointBuffer);
780 
781         cc.INCREMENT_GL_DRAWS(1);
782     },
783 
784     /**
785      * draws a solid polygon given a pointer to CGPoint coordiantes, the number of vertices measured in points, and a color.
786      * @param {Array} poli
787      * @param {Number} numberOfPoints
788      * @param {cc.Color4F} color
789      */
790     drawSolidPoly:function (poli, numberOfPoints, color) {
791         this.lazy_init();
792         if (!color)
793             color = this._color;
794 
795         this._shader.use();
796         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
797         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
798         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(color._arrayBuffer,0,4), 1);
799 
800         var glContext = this._renderContext;
801         var pointBuffer = glContext.createBuffer();
802         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
803         glContext.bufferData(glContext.ARRAY_BUFFER, this._pointsToTypeArray(poli), glContext.STATIC_DRAW);
804         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
805         glContext.drawArrays(glContext.TRIANGLE_FAN, 0, poli.length);
806         glContext.deleteBuffer(pointBuffer);
807 
808         cc.INCREMENT_GL_DRAWS(1);
809     },
810 
811     /**
812      * draws a circle given the center, radius and number of segments.
813      * @param {cc.Point} center center of circle
814      * @param {Number} radius
815      * @param {Number} angle angle in radians
816      * @param {Number} segments
817      * @param {Boolean} drawLineToCenter
818      */
819     drawCircle:function (center, radius, angle, segments, drawLineToCenter) {
820         this.lazy_init();
821 
822         var additionalSegment = 1;
823         if (drawLineToCenter)
824             additionalSegment++;
825 
826         var coef = 2.0 * Math.PI / segments;
827 
828         var vertices = new Float32Array((segments + 2) * 2);
829         if (!vertices)
830             return;
831 
832         for (var i = 0; i <= segments; i++) {
833             var rads = i * coef;
834             var j = radius * Math.cos(rads + angle) + center.x;
835             var k = radius * Math.sin(rads + angle) + center.y;
836 
837             vertices[i * 2] = j;
838             vertices[i * 2 + 1] = k;
839         }
840         vertices[(segments + 1) * 2] = center.x;
841         vertices[(segments + 1) * 2 + 1] = center.y;
842 
843         this._shader.use();
844         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
845         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
846         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(this._color._arrayBuffer,0,4), 1);
847 
848         var glContext = this._renderContext;
849         var pointBuffer = glContext.createBuffer();
850         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
851         glContext.bufferData(glContext.ARRAY_BUFFER, vertices, glContext.STATIC_DRAW);
852         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
853 
854         glContext.drawArrays(glContext.LINE_STRIP, 0, segments + additionalSegment);
855         glContext.deleteBuffer(pointBuffer);
856 
857         cc.INCREMENT_GL_DRAWS(1);
858     },
859 
860     /**
861      * draws a quad bezier path
862      * @param {cc.Point} origin
863      * @param {cc.Point} control
864      * @param {cc.Point} destination
865      * @param {Number} segments
866      */
867     drawQuadBezier:function (origin, control, destination, segments) {
868         this.lazy_init();
869 
870         var vertices = new Float32Array((segments + 1) * 2);
871 
872         var t = 0.0;
873         for (var i = 0; i < segments; i++) {
874             vertices[i * 2] = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x;
875             vertices[i * 2 + 1] = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y;
876             t += 1.0 / segments;
877         }
878         vertices[segments * 2] = destination.x;
879         vertices[segments * 2 + 1] = destination.y;
880 
881         this._shader.use();
882         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
883         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
884         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(this._color._arrayBuffer,0,4), 1);
885 
886         var glContext = this._renderContext;
887         var pointBuffer = glContext.createBuffer();
888         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
889         glContext.bufferData(glContext.ARRAY_BUFFER, vertices, glContext.STATIC_DRAW);
890         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
891 
892         glContext.drawArrays(glContext.LINE_STRIP, 0, segments + 1);
893         glContext.deleteBuffer(pointBuffer);
894 
895         cc.INCREMENT_GL_DRAWS(1);
896     },
897 
898     /**
899      * draws a cubic bezier path
900      * @param {cc.Point} origin
901      * @param {cc.Point} control1
902      * @param {cc.Point} control2
903      * @param {cc.Point} destination
904      * @param {Number} segments
905      */
906     drawCubicBezier:function (origin, control1, control2, destination, segments) {
907         this.lazy_init();
908 
909         var vertices = new Float32Array((segments + 1) * 2);
910 
911         var t = 0;
912         for (var i = 0; i < segments; i++) {
913             vertices[i * 2] = 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;
914             vertices[i * 2 + 1] = 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;
915             t += 1.0 / segments;
916         }
917         vertices[segments * 2] = destination.x;
918         vertices[segments * 2 + 1] = destination.y;
919 
920         this._shader.use();
921         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
922         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
923         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(this._color._arrayBuffer,0,4), 1);
924 
925         var glContext = this._renderContext;
926         var pointBuffer = glContext.createBuffer();
927         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
928         glContext.bufferData(glContext.ARRAY_BUFFER, vertices, glContext.STATIC_DRAW);
929         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
930         glContext.drawArrays(glContext.LINE_STRIP, 0, segments + 1);
931         glContext.deleteBuffer(pointBuffer);
932 
933         cc.INCREMENT_GL_DRAWS(1);
934     },
935 
936     /**
937      * draw a catmull rom line
938      * @param {Array} points
939      * @param {Number} segments
940      */
941     drawCatmullRom:function (points, segments) {
942         this.drawCardinalSpline(points, 0.5, segments);
943     },
944 
945     /**
946      * draw a cardinal spline path
947      * @param {Array} config
948      * @param {Number} tension
949      * @param {Number} segments
950      */
951     drawCardinalSpline:function (config, tension, segments) {
952         this.lazy_init();
953 
954         var vertices = new Float32Array((segments + 1) * 2);
955         var p, lt, deltaT = 1.0 / config.length;
956         for (var i = 0; i < segments + 1; i++) {
957             var dt = i / segments;
958 
959             // border
960             if (dt == 1) {
961                 p = config.length - 1;
962                 lt = 1;
963             } else {
964                 p = 0 | (dt / deltaT);
965                 lt = (dt - deltaT * p) / deltaT;
966             }
967 
968             var newPos = cc.CardinalSplineAt(
969                 cc.getControlPointAt(config, p - 1),
970                 cc.getControlPointAt(config, p),
971                 cc.getControlPointAt(config, p + 1),
972                 cc.getControlPointAt(config, p + 2),
973                 tension, lt);
974             // Interpolate
975 
976             vertices[i * 2] = newPos.x;
977             vertices[i * 2 + 1] = newPos.y;
978         }
979 
980         this._shader.use();
981         this._shader.setUniformForModelViewAndProjectionMatrixWithMat4();
982         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION);
983         this._shader.setUniformLocationWith4fv(this._colorLocation, new Float32Array(this._color._arrayBuffer,0,4), 1);
984 
985         var glContext = this._renderContext;
986         var pointBuffer = glContext.createBuffer();
987         glContext.bindBuffer(glContext.ARRAY_BUFFER, pointBuffer);
988         glContext.bufferData(glContext.ARRAY_BUFFER, vertices, glContext.STATIC_DRAW);
989         glContext.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, glContext.FLOAT, false, 0, 0);
990         glContext.drawArrays(glContext.LINE_STRIP, 0, segments + 1);
991         glContext.deleteBuffer(pointBuffer);
992 
993         cc.INCREMENT_GL_DRAWS(1);
994     },
995 
996     /**
997      * set the drawing color with 4 unsigned bytes
998      * @param {Number} r red value (0 to 255)
999      * @param {Number} g green value (0 to 255)
1000      * @param {Number} b blue value (0 to 255)
1001      * @param {Number} a Alpha value (0 to 255)
1002      */
1003     setDrawColor4B:function (r, g, b, a) {
1004         this._color.r = r / 255.0;
1005         this._color.g = g / 255.0;
1006         this._color.b = b / 255.0;
1007         this._color.a = a / 255.0;
1008     },
1009 
1010     /**
1011      * set the drawing color with 4 floats
1012      * @param {Number} r red value (0 to 1)
1013      * @param {Number} g green value (0 to 1)
1014      * @param {Number} b blue value (0 to 1)
1015      * @param {Number} a Alpha value (0 to 1)
1016      */
1017     setDrawColor4F:function (r, g, b, a) {
1018         this._color.r = r;
1019         this._color.g = g;
1020         this._color.b = b;
1021         this._color.a = a;
1022     },
1023 
1024     /**
1025      * set the point size in points. Default 1.
1026      * @param {Number} pointSize
1027      */
1028     setPointSize:function (pointSize) {
1029         this._pointSize = pointSize * cc.CONTENT_SCALE_FACTOR();
1030     },
1031 
1032     /**
1033      * set the line width. Default 1.
1034      * @param {Number} width
1035      */
1036     setLineWidth:function (width) {
1037         if(this._renderContext.lineWidth)
1038             this._renderContext.lineWidth(width);
1039     }
1040 });
1041 
1042 cc.PI2 = Math.PI * 2;
1043