Permalink
Browse files

halfway there... worked on sprite, path...

- tentative library name "vsprite" (vector sprites)
- renamed Skin to Sprite
- removed skeleton/triangulation stuff (not in this lib's scope!)
- included uthash-1.9.3 macro library to replace C++ STL map/vector/list
- most of path.c and sprite.c are now valid C

The big task remaining is to rewrite 'svgparser' in C, including
rolling our own XML parser.
  • Loading branch information...
tnovelli committed May 23, 2011
1 parent 20d7af7 commit 9182452d5af503777ba6a7cbcda78de2dc62d621
Showing with 2,584 additions and 524 deletions.
  1. +5 −0 .gitignore
  2. +24 −0 README.md
  3. 0 gradient.cc → gradient.c
  4. 0 matrix.cc → matrix.c
  5. +236 −0 path.c
  6. +0 −159 path.cc
  7. +37 −90 path.h
  8. +0 −184 skin.cc
  9. +0 −47 skin.h
  10. +74 −0 sprite.c
  11. +20 −0 sprite.h
  12. +10 −32 svgparser.cc → svgparser.c
  13. +5 −12 svgparser.h
  14. +124 −0 test/kzerza.svg
  15. +226 −0 test/nemesis-turret.svg
  16. 0 Test1.cc → test/stencil-test.c
  17. +224 −0 uthash/utarray.h
  18. +972 −0 uthash/uthash.h
  19. +490 −0 uthash/utlist.h
  20. +137 −0 uthash/utstring.h
View
@@ -0,0 +1,5 @@
+*.swp
+*~
+*.o
+*.a
+*.so
View
@@ -0,0 +1,24 @@
+
+A 2D OpenGL vector sprite animation engine, extracted from OpenMelee
+
+Loads and draws shapes from SVG files (created in Inkscape, for example).
+Designed to be simple and efficient, not robust or complete.
+It supports typically used SVG shapes, including curves and paths, with gradient color fills.
+It should 'play nice' with 2D physics engines like Chipmunk and Box2D.
+
+At some point, we may add support for other vector graphics formats, as SVG has a few shortcomings and is slow to evolve.
+
+
+## Dependencies:
+
+- Poly2tri-C
+
+
+## Status:
+
+May 2011 -- just started porting to plain C and decoupling from OpenMelee,
+Poly2tri, Box2D.
+
+
+
+
File renamed without changes.
View
File renamed without changes.
View
236 path.c
@@ -0,0 +1,236 @@
+#include "path.h"
+
+//------------------------------------------------------------------------
+// let's have 'curloop' be a utarray of Vec2's
+// we'll push points onto it as we parse them,
+// then push 'curloop' onto 'curpath'.
+// When we're all done, convert those to standard C arrays...
+//
+UT_array *curpath;
+UT_array *curloop;
+
+UT_icd ptr_icd = {sizeof(void*), NULL, NULL, NULL};
+
+void curpath_reset() { utarray_new(curpath, &ptr_icd); }
+void curloop_reset() { utarray_new(curloop, &ptr_icd); }
+
+//------------------------------------------------------------------------
+Path* path_new() {
+ Path *p = (Path*)malloc(sizeof(Path));
+ curpath_reset();
+ curloop_reset();
+ p->opacity=1;
+ p->fill[0]=0; p->fill[1]=0; p->fill[2]=0; p->fill[3]=0;
+ p->stroke[0]=0; p->stroke[1]=0; p->stroke[2]=0; p->stroke[3]=0;
+ //p->gradient=NULL;
+ //p->transform=NULL;
+ return p;
+}
+
+//------------------------------------------------------------------------
+void path_finish(Path *p) {
+ int n = utarray_len(curloop);
+ if(n) {
+ //TODO reduce vertices... see Squirtle .end_path()
+
+ utarray_push_back(curpath, curloop);
+
+ p->nloops = n;
+ // p->loops = TODO:convert curpath to standard C array
+ }
+}
+
+//------------------------------------------------------------------------
+void path_close(Path *p) {
+ utarray_push_back(curloop, utarray_front(curloop));
+ path_finish(p);
+}
+
+//------------------------------------------------------------------------
+void path_dump(Path *p) {
+ int n=0;
+ //Vec2lol::iterator i = loops.begin();
+ //while(i != loops.end()) {
+ // printf("LOOP%d= \n", ++n);
+ // Vec2list::iterator j = (*i)->begin();
+ // while(j != (*i)->end()) {
+ // printf(" %f,%f\n", j->x, j->y);
+ // ++j;
+ // }
+ // printf("\n");
+ // ++i;
+ //}
+}
+
+//------------------------------------------------------------------------
+void path_render(Path *p) {
+#if 0
+ //
+ // Simple version - just draw the outline
+ //
+ printf("Rendering");
+ Vec2lol::iterator i = loops.begin();
+ while(i != loops.end()) {
+ glBegin(GL_LINE_STRIP);
+ Vec2list::iterator j = (*i)->begin();
+ while(j != (*i)->end()) {
+ glVertex2f(j->x, j->y);
+ ++j;
+ printf(".");
+ }
+ glEnd();
+ ++i;
+ }
+ printf("\n");
+
+#else
+
+ //
+ // Fancy stencil buffer method
+ // Draws filled concave polygons without tesselation
+ //
+ // Incompatibilities with certain OpenGL features:
+ // - GL_CULL_FACE interferes with even-odd rule, causing incorrect shapes.
+ // - GL_DEPTH_TEST prevents (some/all) fills from rendering.
+ //
+ // References:
+ // "Drawing Filled, Concave Polygons Using the Stencil Buffer"
+ // OpenGL Red Book, Chapter 14
+ // http://glprogramming.com/red/chapter14.html#name13
+ //
+ // "Hardware accelerated polygon rendering", Zack Rusin, 2006.
+ // http://zrusin.blogspot.com/2006/07/hardware-accelerated-polygon-rendering.html
+ //
+
+ int l, i; // Loop#, Point#
+ Loop *loop = p->loops[0]; // current loop
+ Vec2 v; // current point
+
+ glPushAttrib(GL_ENABLE_BIT);
+
+ glEnable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+
+ // Compute a bounding box (for drawing a filled quad behind the stencil)
+ float x1,y1,x2,y2;
+ v = loop->points[0];
+ x1 = x2 = v.x;
+ y1 = y2 = v.y;
+ for(i=0; i < loop->npoints; i++) {
+ v = loop->points[i];
+ if(v.x < x1) x1=v.x;
+ if(v.y < y1) y1=v.y;
+ if(v.x > x2) x2=v.x;
+ if(v.y > y2) y2=v.y;
+ }
+
+ // Draw to stencil, using the even-odd rule for concave polygons
+ glDisable(GL_BLEND);
+ glStencilMask(0x01);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // INVERT = even-odd rule
+ glStencilFunc(GL_ALWAYS, 0, ~0);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ for(l=0; l < p->nloops; l++) {
+ loop = p->loops[l];
+ glBegin(GL_TRIANGLE_FAN);
+ for(i=0; i < loop->npoints; i++) {
+ v = loop->points[i];
+ glVertex2f(v.x, v.y);
+ }
+ glEnd ();
+ }
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ // Antialiasing: Draw aliased off-pixels to real
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glStencilFunc(GL_EQUAL, 0x00, 0x01);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ // Draw outline if necessary
+ if(p->stroke[3] != 0) {
+ glEnable(GL_LINE_SMOOTH);
+ glLineWidth(2);
+ for(l=0; l < p->nloops; l++) {
+ loop = p->loops[l];
+ glBegin(GL_LINE_LOOP);
+ glColor4ubv(p->stroke);
+ for(i=0; i < loop->npoints; i++) {
+ v = loop->points[i];
+ glVertex2f(v.x, v.y);
+ }
+ glEnd();
+ }
+ glDisable(GL_LINE_SMOOTH);
+ }
+
+ // Draw a filled quad behind the stencil
+ glStencilFunc(GL_EQUAL, 0x01, 0x01);
+ glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
+
+ glBegin(GL_QUADS);
+ GLubyte *color;
+ if(p->gradient) {
+ color = gradient_interp(p->gradient,x1,y1);
+ glColor4ubv(color);
+ glVertex2f(x1,y1);
+ color = gradient_interp(p->gradient,x2,y1);
+ glColor4ubv(color);
+ glVertex2f(x2,y1);
+ color = gradient_interp(p->gradient,x2,y2);
+ glColor4ubv(color);
+ glVertex2f(x2,y2);
+ color = gradient_interp(p->gradient,x1,y2);
+ glColor4ubv(color);
+ glVertex2f(x1,y2);
+ } else {
+ color = p->fill;
+ glColor4ubv(color);
+ glVertex2f(x1,y1);
+ glVertex2f(x2,y1);
+ glVertex2f(x2,y2);
+ glVertex2f(x1,y2);
+ }
+ glEnd();
+
+ glPopAttrib();
+#endif
+}
+
+//------------------------------------------------------------------------
+inline void path_apply_transform(Path *p) {
+ // Transform points if necessary
+ if(p->transform) {
+ int l, i;
+ Loop *loop;
+ Vec2 v;
+ for(l=0; l < p->nloops; l++) {
+ loop = p->loops[l];
+ for(i=0; i < loop->npoints; i++) {
+ loop->points[i] = transform_xform(loop->points[i]);
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+inline void path_translate(Path *p, Vec2 center) {
+ // Transform points if necessary
+ int l, i;
+ Loop *loop;
+ Vec2 v;
+ for(l=0; l < p->nloops; l++) {
+ loop = p->loops[l];
+ for(i=0; i < loop->npoints; i++) {
+ loop->points[i].x -= center.x;
+ loop->points[i].y -= center.y;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
Oops, something went wrong.

0 comments on commit 9182452

Please sign in to comment.