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