1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga Inc. 5 Copyright (c) 2012 Scott Lembcke and Howling Moon Software 6 7 http://www.cocos2d-x.org 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ****************************************************************************/ 27 28 /* 29 * Code copied & pasted from SpacePatrol game https://github.com/slembcke/SpacePatrol 30 * 31 * Renamed and added some changes for cocos2d 32 * 33 */ 34 35 cc.v2f = function (x, y) { 36 return new cc.Vertex2F(x, y); 37 }; 38 39 cc.v2fadd = function (v0, v1) { 40 return cc.v2f(v0.x + v1.x, v0.y + v1.y); 41 }; 42 43 cc.v2fsub = function (v0, v1) { 44 return cc.v2f(v0.x - v1.x, v0.y - v1.y); 45 }; 46 47 cc.v2fmult = function (v, s) { 48 return cc.v2f(v.x * s, v.y * s); 49 }; 50 51 cc.v2fperp = function (p0) { 52 return cc.v2f(-p0.y, p0.x); 53 }; 54 55 cc.v2fneg = function (p0) { 56 return cc.v2f(-p0.x, -p0.y); 57 }; 58 59 cc.v2fdot = function (p0, p1) { 60 return p0.x * p1.x + p0.y * p1.y; 61 }; 62 63 cc.v2fforangle = function (_a_) { 64 return cc.v2f(Math.cos(_a_), Math.sin(_a_)); 65 }; 66 67 cc.v2fnormalize = function (p) { 68 var r = cc.pNormalize(cc.p(p.x, p.y)); 69 return cc.v2f(r.x, r.y); 70 }; 71 72 cc.__v2f = function (v) { 73 return cc.v2f(v.x, v.y); 74 }; 75 76 cc.__t = function (v) { 77 return new cc.Tex2F(v.x, v.y); 78 }; 79 80 /** CCDrawNode 81 Node that draws dots, segments and polygons. 82 Faster than the "drawing primitives" since they it draws everything in one single batch. 83 */ 84 cc.DrawNode = cc.Node.extend({ 85 _vao:0, 86 _vbo:0, 87 88 _bufferCapacity:0, 89 _bufferCount:0, 90 _buffer:null, 91 92 _blendFunc:null, 93 94 _dirty:false, 95 96 ctor:function () { 97 this._buffer = []; 98 }, 99 100 ensureCapacity:function (count) { 101 }, 102 103 init:function () { 104 if (this._super()) { 105 this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); 106 //this.ensureCapacity(512); 107 this._dirty = true; 108 return true; 109 } 110 return false; 111 }, 112 113 render:function () { 114 /*if( this._dirty ) { 115 glBindBuffer(GL_ARRAY_BUFFER, _vbo); 116 glBufferData(GL_ARRAY_BUFFER, sizeof(ccV2F_C4B_T2F)*_bufferCapacity, _buffer, GL_STREAM_DRAW); 117 glBindBuffer(GL_ARRAY_BUFFER, 0); 118 this._dirty = false; 119 } 120 121 ccGLBindVAO(_vao); 122 glDrawArrays(GL_TRIANGLES, 0, _bufferCount); 123 124 CC_INCREMENT_GL_DRAWS(1); 125 126 CHECK_GL_ERROR();*/ 127 }, 128 129 draw:function (ctx) { 130 131 var context = ctx || cc.renderContext; 132 133 if ((this._blendFunc && (this._blendFunc.src == gl.SRC_ALPHA) && (this._blendFunc.dst == gl.ONE))) 134 context.globalCompositeOperation = 'lighter'; 135 136 for (var i = 0; i < this._buffer.length; i++) { 137 var element = this._buffer[i]; 138 if (element.type === cc.DRAWNODE_TYPE_DOT) { 139 context.fillStyle = "rgba(" + (0|(element.color.r * 255)) + "," + (0|(element.color.g * 255)) + "," + (0|(element.color.b * 255)) + "," + element.color.a + ")"; 140 cc.drawingUtil.drawPoint(element.position, element.radius); 141 } 142 143 if (element.type === cc.DRAWNODE_TYPE_SEGMENT) { 144 context.strokeStyle = "rgba(" + (0|(element.color.r * 255)) + "," + (0|(element.color.g * 255)) + "," + (0|(element.color.b * 255)) + "," + element.color.a + ")"; 145 context.lineWidth = element.radius; 146 context.lineCap = "round"; 147 cc.drawingUtil.drawLine(element.from, element.to); 148 } 149 150 if (element.type === cc.DRAWNODE_TYPE_POLY) { 151 context.fillStyle = "rgba(" + (0|(element.fillColor.r * 255)) + "," + (0|(element.fillColor.g * 255)) + "," 152 + (0|(element.fillColor.b * 255)) + "," + element.fillColor.a + ")"; 153 cc.drawingUtil.drawPoly(element.verts, element.count, false, true); 154 context.lineWidth = element.borderWidth; 155 context.lineCap = "round"; 156 context.strokeStyle = "rgba(" + (0|(element.borderColor.r * 255)) + "," + (0|(element.borderColor.g * 255)) + "," 157 + (0|(element.borderColor.b * 255)) + "," + element.borderColor.a + ")"; 158 cc.drawingUtil.drawPoly(element.verts, element.count, false, false); 159 } 160 } 161 162 //TODO WEBGL 163 /*this.render(); 164 ccGLBlendFunc(_blendFunc.src, _blendFunc.dst); 165 166 [shaderProgram_ use]; 167 [shaderProgram_ setUniformsForBuiltins]; 168 169 [self render];*/ 170 }, 171 172 getBlendFunc:function () { 173 return this._blendFunc; 174 }, 175 176 setBlendFunc:function (blendFunc) { 177 this._blendFunc = blendFunc; 178 }, 179 180 /** draw a dot at a position, with a given radius and color */ 181 drawDot:function (pos, radius, color) { 182 var element = new cc._DrawNodeElement(cc.DRAWNODE_TYPE_DOT); 183 element.position = pos; 184 element.radius = radius; 185 element.color = color; 186 this._buffer.push(element); 187 188 //TODO WEBGL 189 /* var vertex_count = 2*3; 190 this.ensureCapacity(vertex_count); 191 192 ccV2F_C4B_T2F a = {{pos.x - radius, pos.y - radius}, ccc4BFromccc4F(color), {-1.0, -1.0} }; 193 ccV2F_C4B_T2F b = {{pos.x - radius, pos.y + radius}, ccc4BFromccc4F(color), {-1.0, 1.0} }; 194 ccV2F_C4B_T2F c = {{pos.x + radius, pos.y + radius}, ccc4BFromccc4F(color), { 1.0, 1.0} }; 195 ccV2F_C4B_T2F d = {{pos.x + radius, pos.y - radius}, ccc4BFromccc4F(color), { 1.0, -1.0} }; 196 197 ccV2F_C4B_T2F_Triangle *triangles = (ccV2F_C4B_T2F_Triangle *)(_buffer + _bufferCount); 198 triangles[0] = (ccV2F_C4B_T2F_Triangle){a, b, c}; 199 triangles[1] = (ccV2F_C4B_T2F_Triangle){a, c, d}; 200 201 202 this._bufferCount += vertex_count;*/ 203 }, 204 205 /** draw a segment with a radius and color */ 206 drawSegment:function (a, b, radius, color) { 207 var element = new cc._DrawNodeElement(cc.DRAWNODE_TYPE_SEGMENT); 208 element.from = a; 209 element.to = b; 210 element.radius = radius; 211 element.color = color; 212 this._buffer.push(element); 213 214 //TODO WEBGL 215 /* 216 var vertex_count = 6*3; 217 this.ensureCapacity(vertex_count); 218 219 ccVertex2F a = __v2f(_a); 220 ccVertex2F b = __v2f(_b); 221 222 223 ccVertex2F n = v2fnormalize(v2fperp(v2fsub(b, a))); 224 ccVertex2F t = v2fperp(n); 225 226 ccVertex2F nw = v2fmult(n, radius); 227 ccVertex2F tw = v2fmult(t, radius); 228 ccVertex2F v0 = v2fsub(b, v2fadd(nw, tw)); 229 ccVertex2F v1 = v2fadd(b, v2fsub(nw, tw)); 230 ccVertex2F v2 = v2fsub(b, nw); 231 ccVertex2F v3 = v2fadd(b, nw); 232 ccVertex2F v4 = v2fsub(a, nw); 233 ccVertex2F v5 = v2fadd(a, nw); 234 ccVertex2F v6 = v2fsub(a, v2fsub(nw, tw)); 235 ccVertex2F v7 = v2fadd(a, v2fadd(nw, tw)); 236 237 238 ccV2F_C4B_T2F_Triangle *triangles = (ccV2F_C4B_T2F_Triangle *)(_buffer + _bufferCount); 239 240 triangles[0] = (ccV2F_C4B_T2F_Triangle) { 241 {v0, ccc4BFromccc4F(color), __t(v2fneg(v2fadd(n, t))) }, 242 {v1, ccc4BFromccc4F(color), __t(v2fsub(n, t)) }, 243 {v2, ccc4BFromccc4F(color), __t(v2fneg(n)) }, 244 }; 245 246 triangles[1] = (ccV2F_C4B_T2F_Triangle){ 247 {v3, ccc4BFromccc4F(color), __t(n)}, 248 {v1, ccc4BFromccc4F(color), __t(v2fsub(n, t)) }, 249 {v2, ccc4BFromccc4F(color), __t(v2fneg(n)) }, 250 }; 251 252 triangles[2] = (ccV2F_C4B_T2F_Triangle){ 253 {v3, ccc4BFromccc4F(color), __t(n)}, 254 {v4, ccc4BFromccc4F(color), __t(v2fneg(n)) }, 255 {v2, ccc4BFromccc4F(color), __t(v2fneg(n)) }, 256 }; 257 triangles[3] = (ccV2F_C4B_T2F_Triangle){ 258 {v3, ccc4BFromccc4F(color), __t(n) }, 259 {v4, ccc4BFromccc4F(color), __t(v2fneg(n)) }, 260 {v5, ccc4BFromccc4F(color), __t(n) }, 261 }; 262 triangles[4] = (ccV2F_C4B_T2F_Triangle){ 263 {v6, ccc4BFromccc4F(color), __t(v2fsub(t, n))}, 264 {v4, ccc4BFromccc4F(color), __t(v2fneg(n)) }, 265 {v5, ccc4BFromccc4F(color), __t(n)}, 266 }; 267 triangles[5] = (ccV2F_C4B_T2F_Triangle){ 268 {v6, ccc4BFromccc4F(color), __t(v2fsub(t, n)) }, 269 {v7, ccc4BFromccc4F(color), __t(v2fadd(n, t)) }, 270 {v5, ccc4BFromccc4F(color), __t(n)}, 271 }; 272 273 this._bufferCount += vertex_count; 274 this._dirty = true; */ 275 }, 276 277 /** draw a polygon with a fill color and line color */ 278 drawPoly:function (verts, fillColor, width, borderColor) { 279 var element = new cc._DrawNodeElement(cc.DRAWNODE_TYPE_POLY); 280 element.verts = verts; 281 element.count = verts.length; 282 element.fillColor = fillColor; 283 element.borderWidth = width; 284 element.borderColor = borderColor; 285 this._buffer.push(element); 286 287 //TODO WEBGL 288 /* struct ExtrudeVerts {ccVertex2F offset, n;}; 289 struct ExtrudeVerts extrude[count]; 290 bzero(extrude, sizeof(extrude) ); 291 292 for(int i=0; i<count; i++){ 293 ccVertex2F v0 = __v2f( verts[(i-1+count)%count] ); 294 ccVertex2F v1 = __v2f( verts[i] ); 295 ccVertex2F v2 = __v2f( verts[(i+1)%count] ); 296 297 ccVertex2F n1 = v2fnormalize(v2fperp(v2fsub(v1, v0))); 298 ccVertex2F n2 = v2fnormalize(v2fperp(v2fsub(v2, v1))); 299 300 ccVertex2F offset = v2fmult(v2fadd(n1, n2), 1.0/(v2fdot(n1, n2) + 1.0)); 301 extrude[i] = (struct ExtrudeVerts){offset, n2}; 302 } 303 304 var outline = (line.a > 0.0 && width > 0.0); 305 306 var triangle_count = 3*count - 2; 307 var vertex_count = 3*triangle_count; 308 309 this.ensureCapacity(vertex_count); 310 311 ccV2F_C4B_T2F_Triangle *triangles = (ccV2F_C4B_T2F_Triangle *)(_buffer + _bufferCount); 312 ccV2F_C4B_T2F_Triangle *cursor = triangles; 313 314 var inset = (outline == 0.0 ? 0.5 : 0.0); 315 for(int i=0; i<count-2; i++){ 316 ccVertex2F v0 = v2fsub( __v2f(verts[0 ]), v2fmult(extrude[0 ].offset, inset)); 317 ccVertex2F v1 = v2fsub( __v2f(verts[i+1]), v2fmult(extrude[i+1].offset, inset)); 318 ccVertex2F v2 = v2fsub( __v2f(verts[i+2]), v2fmult(extrude[i+2].offset, inset)); 319 320 *cursor++ = (ccV2F_C4B_T2F_Triangle){ 321 {v0, ccc4BFromccc4F(fill), __t(v2fzero) }, 322 {v1, ccc4BFromccc4F(fill), __t(v2fzero) }, 323 {v2, ccc4BFromccc4F(fill), __t(v2fzero) }, 324 }; 325 } 326 327 for(int i=0; i<count; i++){ 328 int j = (i+1)%count; 329 ccVertex2F v0 = __v2f( verts[i] ); 330 ccVertex2F v1 = __v2f( verts[j] ); 331 332 ccVertex2F n0 = extrude[i].n; 333 334 ccVertex2F offset0 = extrude[i].offset; 335 ccVertex2F offset1 = extrude[j].offset; 336 337 if(outline){ 338 ccVertex2F inner0 = v2fsub(v0, v2fmult(offset0, width)); 339 ccVertex2F inner1 = v2fsub(v1, v2fmult(offset1, width)); 340 ccVertex2F outer0 = v2fadd(v0, v2fmult(offset0, width)); 341 ccVertex2F outer1 = v2fadd(v1, v2fmult(offset1, width)); 342 343 *cursor++ = (ccV2F_C4B_T2F_Triangle){ 344 {inner0, ccc4BFromccc4F(line), __t(v2fneg(n0))}, 345 {inner1, ccc4BFromccc4F(line), __t(v2fneg(n0))}, 346 {outer1, ccc4BFromccc4F(line), __t(n0)} 347 }; 348 *cursor++ = (ccV2F_C4B_T2F_Triangle){ 349 {inner0, ccc4BFromccc4F(line), __t(v2fneg(n0))}, 350 {outer0, ccc4BFromccc4F(line), __t(n0)}, 351 {outer1, ccc4BFromccc4F(line), __t(n0)} 352 }; 353 } else { 354 ccVertex2F inner0 = v2fsub(v0, v2fmult(offset0, 0.5)); 355 ccVertex2F inner1 = v2fsub(v1, v2fmult(offset1, 0.5)); 356 ccVertex2F outer0 = v2fadd(v0, v2fmult(offset0, 0.5)); 357 ccVertex2F outer1 = v2fadd(v1, v2fmult(offset1, 0.5)); 358 359 *cursor++ = (ccV2F_C4B_T2F_Triangle){ 360 {inner0, ccc4BFromccc4F(fill), __t(v2fzero)}, 361 {inner1, ccc4BFromccc4F(fill), __t(v2fzero)}, 362 {outer1, ccc4BFromccc4F(fill), __t(n0)} 363 }; 364 *cursor++ = (ccV2F_C4B_T2F_Triangle){ 365 {inner0, ccc4BFromccc4F(fill), __t(v2fzero)}, 366 {outer0, ccc4BFromccc4F(fill), __t(n0)}, 367 {outer1, ccc4BFromccc4F(fill), __t(n0)} 368 }; 369 } 370 } 371 372 this._bufferCount += vertex_count; 373 this._dirty = true; */ 374 }, 375 376 /** Clear the geometry in the node's buffer. */ 377 clear:function () { 378 this._buffer.length = 0; 379 this._bufferCount = 0; 380 this._dirty = true; 381 } 382 }); 383 384 cc.DrawNode.create = function(){ 385 var ret = new cc.DrawNode(); 386 if(ret && ret.init()) 387 return ret; 388 return null; 389 }; 390 391 cc._DrawNodeElement = function (type) { 392 this.type = type; 393 }; 394 395 cc.DRAWNODE_TYPE_DOT = 0; 396 cc.DRAWNODE_TYPE_SEGMENT = 1; 397 cc.DRAWNODE_TYPE_POLY = 2; 398