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 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 cc.PI2 = Math.PI * 2; 28 29 /** 30 * Canvas of DrawingPrimitive implement version 31 * @class 32 * @extends cc.Class 33 */ 34 cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas# */{ 35 _cacheArray:[], 36 _renderContext:null, 37 /** 38 * Constructor 39 * @param {CanvasRenderingContext2D} renderContext 40 */ 41 ctor:function (renderContext) { 42 this._renderContext = renderContext; 43 }, 44 45 /** 46 * draws a point given x and y coordinate measured in points 47 * @override 48 * @param {cc.Point} point 49 * @param {Number} size 50 */ 51 drawPoint:function (point, size) { 52 if (!size) { 53 size = 1; 54 } 55 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 56 var newPoint = cc.p(point.x * locScaleX, point.y * locScaleY); 57 this._renderContext.beginPath(); 58 this._renderContext.arc(newPoint.x, -newPoint.y, size * locScaleX, 0, Math.PI * 2, false); 59 this._renderContext.closePath(); 60 this._renderContext.fill(); 61 }, 62 63 /** 64 * draws an array of points. 65 * @override 66 * @param {Array} points point of array 67 * @param {Number} numberOfPoints 68 * @param {Number} size 69 */ 70 drawPoints:function (points, numberOfPoints, size) { 71 if (points == null) { 72 return; 73 } 74 if (!size) { 75 size = 1; 76 } 77 var locContext = this._renderContext,locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 78 79 locContext.beginPath(); 80 for (var i = 0, len = points.length; i < len; i++) 81 locContext.arc(points[i].x * locScaleX, -points[i].y * locScaleY, size * locScaleX, 0, Math.PI * 2, false); 82 locContext.closePath(); 83 locContext.fill(); 84 }, 85 86 /** 87 * draws a line given the origin and destination point measured in points 88 * @override 89 * @param {cc.Point} origin 90 * @param {cc.Point} destination 91 */ 92 drawLine:function (origin, destination) { 93 var locContext = this._renderContext, locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 94 locContext.beginPath(); 95 locContext.moveTo(origin.x * locScaleX, -origin.y * locScaleY); 96 locContext.lineTo(destination.x * locScaleX, -destination.y * locScaleY); 97 locContext.closePath(); 98 locContext.stroke(); 99 }, 100 101 /** 102 * draws a rectangle given the origin and destination point measured in points. 103 * @param {cc.Point} origin 104 * @param {cc.Point} destination 105 */ 106 drawRect:function (origin, destination) { 107 this.drawLine(cc.p(origin.x, origin.y), cc.p(destination.x, origin.y)); 108 this.drawLine(cc.p(destination.x, origin.y), cc.p(destination.x, destination.y)); 109 this.drawLine(cc.p(destination.x, destination.y), cc.p(origin.x, destination.y)); 110 this.drawLine(cc.p(origin.x, destination.y), cc.p(origin.x, origin.y)); 111 }, 112 113 /** 114 * draws a solid rectangle given the origin and destination point measured in points. 115 * @param {cc.Point} origin 116 * @param {cc.Point} destination 117 * @param {cc.Color} color 118 */ 119 drawSolidRect:function (origin, destination, color) { 120 var vertices = [ 121 origin, 122 cc.p(destination.x, origin.y), 123 destination, 124 cc.p(origin.x, destination.y) 125 ]; 126 127 this.drawSolidPoly(vertices, 4, color); 128 }, 129 130 /** 131 * draws a polygon given a pointer to cc.Point coordinates and the number of vertices measured in points. 132 * @override 133 * @param {Array} vertices a pointer to cc.Point coordinates 134 * @param {Number} numOfVertices the number of vertices measured in points 135 * @param {Boolean} closePolygon The polygon can be closed or open 136 * @param {Boolean} [fill=] The polygon can be closed or open and optionally filled with current color 137 */ 138 drawPoly:function (vertices, numOfVertices, closePolygon, fill) { 139 fill = fill || false; 140 141 if (vertices == null) 142 return; 143 144 if (vertices.length < 3) 145 throw new Error("Polygon's point must greater than 2"); 146 147 var firstPoint = vertices[0], locContext = this._renderContext; 148 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 149 locContext.beginPath(); 150 locContext.moveTo(firstPoint.x * locScaleX, -firstPoint.y * locScaleY); 151 for (var i = 1, len = vertices.length; i < len; i++) 152 locContext.lineTo(vertices[i].x * locScaleX, -vertices[i].y * locScaleY); 153 154 if (closePolygon) 155 locContext.closePath(); 156 157 if (fill) 158 locContext.fill(); 159 else 160 locContext.stroke(); 161 }, 162 163 /** 164 * draws a solid polygon given a pointer to CGPoint coordinates, the number of vertices measured in points, and a color. 165 * @param {Array} polygons 166 * @param {Number} numberOfPoints 167 * @param {cc.Color} color 168 */ 169 drawSolidPoly:function (polygons, numberOfPoints, color) { 170 this.setDrawColor(color.r, color.g, color.b, color.a); 171 this.drawPoly(polygons, numberOfPoints, true, true); 172 }, 173 174 /** 175 * draws a circle given the center, radius and number of segments. 176 * @override 177 * @param {cc.Point} center center of circle 178 * @param {Number} radius 179 * @param {Number} angle angle in radians 180 * @param {Number} segments 181 * @param {Boolean} [drawLineToCenter=] 182 */ 183 drawCircle: function (center, radius, angle, segments, drawLineToCenter) { 184 drawLineToCenter = drawLineToCenter || false; 185 var locContext = this._renderContext; 186 var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); 187 locContext.beginPath(); 188 var endAngle = angle - Math.PI * 2; 189 locContext.arc(0 | (center.x * locScaleX), 0 | -(center.y * locScaleY), radius * locScaleX, -angle, -endAngle, false); 190 if (drawLineToCenter) { 191 locContext.lineTo(0 | (center.x * locScaleX), 0 | -(center.y * locScaleY)); 192 } 193 locContext.stroke(); 194 }, 195 196 /** 197 * draws a quad bezier path 198 * @override 199 * @param {cc.Point} origin 200 * @param {cc.Point} control 201 * @param {cc.Point} destination 202 * @param {Number} segments 203 */ 204 drawQuadBezier:function (origin, control, destination, segments) { 205 //this is OpenGL Algorithm 206 var vertices = this._cacheArray; 207 vertices.length =0; 208 209 var t = 0.0; 210 for (var i = 0; i < segments; i++) { 211 var x = Math.pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 212 var y = Math.pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 213 vertices.push(cc.p(x, y)); 214 t += 1.0 / segments; 215 } 216 vertices.push(cc.p(destination.x, destination.y)); 217 218 this.drawPoly(vertices, segments + 1, false, false); 219 }, 220 221 /** 222 * draws a cubic bezier path 223 * @override 224 * @param {cc.Point} origin 225 * @param {cc.Point} control1 226 * @param {cc.Point} control2 227 * @param {cc.Point} destination 228 * @param {Number} segments 229 */ 230 drawCubicBezier:function (origin, control1, control2, destination, segments) { 231 //this is OpenGL Algorithm 232 var vertices = this._cacheArray; 233 vertices.length =0; 234 235 var t = 0; 236 for (var i = 0; i < segments; i++) { 237 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; 238 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; 239 vertices.push(cc.p(x , y )); 240 t += 1.0 / segments; 241 } 242 vertices.push(cc.p(destination.x , destination.y)); 243 244 this.drawPoly(vertices, segments + 1, false, false); 245 }, 246 247 /** 248 * draw a CatmullRom curve 249 * @override 250 * @param {Array} points 251 * @param {Number} segments 252 */ 253 drawCatmullRom:function (points, segments) { 254 this.drawCardinalSpline(points, 0.5, segments); 255 }, 256 257 /** 258 * draw a cardinal spline path 259 * @override 260 * @param {Array} config 261 * @param {Number} tension 262 * @param {Number} segments 263 */ 264 drawCardinalSpline:function (config, tension, segments) { 265 //lazy_init(); 266 cc._renderContext.strokeStyle = "rgba(255,255,255,1)"; 267 var points = this._cacheArray; 268 points.length = 0; 269 var p, lt; 270 var deltaT = 1.0 / config.length; 271 272 for (var i = 0; i < segments + 1; i++) { 273 var dt = i / segments; 274 275 // border 276 if (dt == 1) { 277 p = config.length - 1; 278 lt = 1; 279 } else { 280 p = 0 | (dt / deltaT); 281 lt = (dt - deltaT * p) / deltaT; 282 } 283 284 // Interpolate 285 var newPos = cc.CardinalSplineAt( 286 cc.getControlPointAt(config, p - 1), 287 cc.getControlPointAt(config, p - 0), 288 cc.getControlPointAt(config, p + 1), 289 cc.getControlPointAt(config, p + 2), 290 tension, lt); 291 points.push(newPos); 292 } 293 this.drawPoly(points, segments + 1, false, false); 294 }, 295 296 /** 297 * draw an image 298 * @override 299 * @param {HTMLImageElement|HTMLCanvasElement} image 300 * @param {cc.Point} sourcePoint 301 * @param {cc.Size} sourceSize 302 * @param {cc.Point} destPoint 303 * @param {cc.Size} destSize 304 */ 305 drawImage:function (image, sourcePoint, sourceSize, destPoint, destSize) { 306 var len = arguments.length; 307 switch (len) { 308 case 2: 309 var height = image.height; 310 this._renderContext.drawImage(image, sourcePoint.x, -(sourcePoint.y + height)); 311 break; 312 case 3: 313 this._renderContext.drawImage(image, sourcePoint.x, -(sourcePoint.y + sourceSize.height), sourceSize.width, sourceSize.height); 314 break; 315 case 5: 316 this._renderContext.drawImage(image, sourcePoint.x, sourcePoint.y, sourceSize.width, sourceSize.height, destPoint.x, -(destPoint.y + destSize.height), 317 destSize.width, destSize.height); 318 break; 319 default: 320 throw new Error("Argument must be non-nil"); 321 break; 322 } 323 }, 324 325 /** 326 * draw a star 327 * @param {CanvasRenderingContext2D} ctx canvas context 328 * @param {Number} radius 329 * @param {cc.Color} color 330 */ 331 drawStar:function (ctx, radius, color) { 332 var context = ctx || this._renderContext; 333 radius *= cc.view.getScaleX(); 334 var colorStr = "rgba(" + (0 | color.r) + "," + (0 | color.g) + "," + (0 | color.b); 335 context.fillStyle = colorStr + ",1)"; 336 var subRadius = radius / 10; 337 338 context.beginPath(); 339 context.moveTo(-radius, radius); 340 context.lineTo(0, subRadius); 341 context.lineTo(radius, radius); 342 context.lineTo(subRadius, 0); 343 context.lineTo(radius, -radius); 344 context.lineTo(0, -subRadius); 345 context.lineTo(-radius, -radius); 346 context.lineTo(-subRadius, 0); 347 context.lineTo(-radius, radius); 348 context.closePath(); 349 context.fill(); 350 351 var g1 = context.createRadialGradient(0, 0, subRadius, 0, 0, radius); 352 g1.addColorStop(0, colorStr + ", 1)"); 353 g1.addColorStop(0.3, colorStr + ", 0.8)"); 354 g1.addColorStop(1.0, colorStr + ", 0.0)"); 355 context.fillStyle = g1; 356 context.beginPath(); 357 var startAngle_1 = 0; 358 var endAngle_1 = cc.PI2; 359 context.arc(0, 0, radius - subRadius, startAngle_1, endAngle_1, false); 360 context.closePath(); 361 context.fill(); 362 }, 363 364 /** 365 * draw a color ball 366 * @param {CanvasRenderingContext2D} ctx canvas context 367 * @param {Number} radius 368 * @param {cc.Color} color 369 */ 370 drawColorBall:function (ctx, radius, color) { 371 var context = ctx || this._renderContext; 372 radius *= cc.view.getScaleX(); 373 var colorStr = "rgba(" +(0|color.r) + "," + (0|color.g) + "," + (0|color.b); 374 var subRadius = radius / 10; 375 376 var g1 = context.createRadialGradient(0, 0, subRadius, 0, 0, radius); 377 g1.addColorStop(0, colorStr + ", 1)"); 378 g1.addColorStop(0.3, colorStr + ", 0.8)"); 379 g1.addColorStop(0.6, colorStr + ", 0.4)"); 380 g1.addColorStop(1.0, colorStr + ", 0.0)"); 381 context.fillStyle = g1; 382 context.beginPath(); 383 var startAngle_1 = 0; 384 var endAngle_1 = cc.PI2; 385 context.arc(0, 0, radius, startAngle_1, endAngle_1, false); 386 context.closePath(); 387 context.fill(); 388 }, 389 390 /** 391 * fill text 392 * @param {String} strText 393 * @param {Number} x 394 * @param {Number} y 395 */ 396 fillText:function (strText, x, y) { 397 this._renderContext.fillText(strText, x, -y); 398 }, 399 400 /** 401 * set the drawing color with 4 unsigned bytes 402 * @param {Number} r red value (0 to 255) 403 * @param {Number} g green value (0 to 255) 404 * @param {Number} b blue value (0 to 255) 405 * @param {Number} a Alpha value (0 to 255) 406 */ 407 setDrawColor:function (r, g, b, a) { 408 this._renderContext.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a / 255 + ")"; 409 this._renderContext.strokeStyle = "rgba(" + r + "," + g + "," + b + "," + a / 255 + ")"; 410 }, 411 412 /** 413 * set the point size in points. Default 1. 414 * @param {Number} pointSize 415 */ 416 setPointSize:function (pointSize) { 417 }, 418 419 /** 420 * set the line width. Default 1. 421 * @param {Number} width 422 */ 423 setLineWidth:function (width) { 424 this._renderContext.lineWidth = width * cc.view.getScaleX(); 425 } 426 });