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