topical media & game development

talk show tell print

lib-of-vs-libs-openFrameworks-graphics-ofGraphics.cpp / cpp



  include <ofGraphics.h>
  include <ofAppRunner.h>
  include <ofBitmapFont.h>
  
  ifdef TARGET_OSX
          #include <OpenGL/glu.h>
  endif
  
  ifdef TARGET_OPENGLES
          #include <glu.h>
  endif
  
  ifdef TARGET_LINUX
          #include "GL/glu.h"
  endif
  
  ifdef TARGET_WIN32
          #include <glu.h>
  endif
  
  ifndef TARGET_WIN32
      #define CALLBACK
  endif
  
  include <vector>
  
  //----------------------------------------------------------
  // static
  static float        drawMode                        = OF_FILLED;
  static bool         bSetupCircle                = false;
  static int                numCirclePts                = 0;
  float                         bgColor[4]                        = {0,0,0,0};
  void                         setupCircle();
  bool                         bSmoothHinted                = false;
  bool                        bUsingArbTex                = true;
  bool                         bBakgroundAuto                = true;
  int                         cornerMode                        = OF_RECTMODE_CORNER;
  int                         polyMode                        = OF_POLY_WINDING_ODD;
  
  //style stuff - new in 006
  ofStyle                        currentStyle;
  vector <ofStyle> styleHistory;
  
  static float circlePts[OF_MAX_CIRCLE_PTS*2];
  static float circlePtsScaled[OF_MAX_CIRCLE_PTS*2];
  static float trianglePoints[6];
  static float linePoints[4];
  static float rectPoints[8];
  
  //----------------------------------------------------------
  void  ofSetRectMode(int mode){
          if (mode == OF_RECTMODE_CORNER)                 cornerMode = OF_RECTMODE_CORNER;
          else if (mode == OF_RECTMODE_CENTER)         cornerMode = OF_RECTMODE_CENTER;
  
          currentStyle.rectMode = cornerMode;
  }
  
  //----------------------------------------------------------
  int ofGetRectMode(){
          return         cornerMode;
  }
  
  //----------------------------------------------------------
  bool ofGetUsingArbTex(){
          return bUsingArbTex;
  }
  
  //----------------------------------------------------------
  void ofEnableArbTex(){
          bUsingArbTex = true;
  }
  
  //----------------------------------------------------------
  void ofDisableArbTex(){
          bUsingArbTex = false;
  }
  
  //----------------------------------------------------------
  void ofSetBackgroundAuto(bool bAuto){
          bBakgroundAuto = bAuto;
  }
  
  //----------------------------------------------------------
  bool ofbClearBg(){
          return bBakgroundAuto;
  }
  
  //----------------------------------------------------------
  float * ofBgColorPtr(){
          return bgColor;
  }
  
  //----------------------------------------------------------
  void ofBackground(int r, int g, int b){
          bgColor[0] = (float)r / (float)255.0f;
          bgColor[1] = (float)g / (float)255.0f;
          bgColor[2] = (float)b / (float)255.0f;
          bgColor[3] = 1.0f;
          // if we are in not-auto mode, then clear with a bg call...
          if (ofbClearBg() == false){
                  glClearColor(bgColor[0],bgColor[1],bgColor[2], bgColor[3]);
                  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
          }
  }
  
  //----------------------------------------------------------
  void ofNoFill(){
          drawMode = OF_OUTLINE;
          currentStyle.bFill = false;
  }
  
  //----------------------------------------------------------
  void ofFill(){
          drawMode = OF_FILLED;
          currentStyle.bFill = true;
  }
  
  //----------------------------------------------------------
  void ofSetLineWidth(float lineWidth){
          glLineWidth(lineWidth);
          currentStyle.lineWidth = lineWidth;
  }
  
  //----------------------------------------------------------
  void startSmoothing();
  void startSmoothing(){
          #ifndef TARGET_OPENGLES
                  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT);
          #endif
  
          glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
          glEnable(GL_LINE_SMOOTH);
  
          //why do we need this?
          glEnable(GL_BLEND);
          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  }
  
  //----------------------------------------------------------
  void endSmoothing();
  void endSmoothing(){
          #ifndef TARGET_OPENGLES
                  glPopAttrib();
          #endif
  }
  
  //----------------------------------------------------------
  void setupCircle(){
          ofSetCircleResolution(CIRC_RESOLUTION);
  }
  
  //----------------------------------------------------------
  void ofSetCircleResolution(int res){
          res = MIN( MAX(1, res), OF_MAX_CIRCLE_PTS);
  
          if (res > 1 && res != numCirclePts){
                  numCirclePts = res;
                  currentStyle.circleResolution = numCirclePts;
  
                  float angle = 0.0f;
                  float angleAdder = M_TWO_PI / (float)res;
                  int k = 0;
                  for (int i = 0; i < numCirclePts; i++){
                          circlePts[k] = cos(angle);
                          circlePts[k+1] = sin(angle);
                          angle += angleAdder;
                          k+=2;
                  }
                  bSetupCircle = true;
          }
  }
  
  //----------------------------------------------------------
  void ofTriangle(float x1,float y1,float x2,float y2,float x3, float y3){
  
          // use smoothness, if requested:
          if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();
  
          // draw:
          trianglePoints[0] = x1;
          trianglePoints[1] = y1;
          trianglePoints[2] = x2;
          trianglePoints[3] = y2;
          trianglePoints[4] = x3;
          trianglePoints[5] = y3;
  
          glEnableClientState(GL_VERTEX_ARRAY);
          glVertexPointer(2, GL_FLOAT, 0, &trianglePoints[0]);
          glDrawArrays((drawMode == OF_FILLED) ? GL_TRIANGLES : GL_LINE_LOOP, 0, 3);
  
          // back to normal, if smoothness is on
          if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();
  }
  
  //----------------------------------------------------------
  void ofCircle(float x,float y, float radius){
  
          if (!bSetupCircle) setupCircle();
  
          // use smoothness, if requested:
          if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();
  
          int k = 0;
          for(int i = 0; i < numCirclePts; i++){
                  circlePtsScaled[k]   = x + circlePts[k] * radius;
                  circlePtsScaled[k+1] = y + circlePts[k+1] * radius;
                  k+=2;
          }
  
          glEnableClientState(GL_VERTEX_ARRAY);
          glVertexPointer(2, GL_FLOAT, 0, &circlePtsScaled[0]);
          glDrawArrays( (drawMode == OF_FILLED) ? GL_TRIANGLE_FAN : GL_LINE_LOOP, 0, numCirclePts);
  
          // back to normal, if smoothness is on
          if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();
  
  }
  
  //----------------------------------------------------------
  void ofEllipse(float x, float y, float width, float height){
  
          if (!bSetupCircle) setupCircle();
  
          // use smoothness, if requested:
          if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();
  
          int k = 0;
          for(int i = 0; i < numCirclePts; i++){
                  circlePtsScaled[k]   = x + circlePts[k] * width  * 0.5;
                  circlePtsScaled[k+1] = y + circlePts[k+1] * height * 0.5;
                  k+=2;
          }
  
          glEnableClientState(GL_VERTEX_ARRAY);
          glVertexPointer(2, GL_FLOAT, 0, &circlePtsScaled[0]);
          glDrawArrays( (drawMode == OF_FILLED) ? GL_TRIANGLE_FAN : GL_LINE_LOOP, 0, numCirclePts);
  
          // back to normal, if smoothness is on
          if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();
  }
  
  //----------------------------------------------------------
  void ofLine(float x1,float y1,float x2,float y2){
  
          // use smoothness, if requested:
          if (bSmoothHinted) startSmoothing();
  
          linePoints[0] = x1;
          linePoints[1] = y1;
          linePoints[2] = x2;
          linePoints[3] = y2;
  
          glEnableClientState(GL_VERTEX_ARRAY);
          glVertexPointer(2, GL_FLOAT, 0, &linePoints[0]);
          glDrawArrays(GL_LINES, 0, 2);
  
          // back to normal, if smoothness is on
          if (bSmoothHinted) endSmoothing();
  
  }
  
  //----------------------------------------------------------
  void ofRect(float x,float y,float w,float h){
  
          // use smoothness, if requested:
          if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();
  
          if (cornerMode == OF_RECTMODE_CORNER){
                  rectPoints[0] = x;
                  rectPoints[1] = y;
  
                  rectPoints[2] = x+w;
                  rectPoints[3] = y;
  
                  rectPoints[4] = x+w;
                  rectPoints[5] = y+h;
  
                  rectPoints[6] = x;
                  rectPoints[7] = y+h;
          }else{
                  rectPoints[0] = x-w/2;
                  rectPoints[1] = y-h/2;
  
                  rectPoints[2] = x+w/2;
                  rectPoints[3] = y-h/2;
  
                  rectPoints[4] = x+w/2;
                  rectPoints[5] = y+h/2;
  
                  rectPoints[6] = x-w/2;
                  rectPoints[7] = y+h/2;
          }
  
          glEnableClientState(GL_VERTEX_ARRAY);
          glVertexPointer(2, GL_FLOAT, 0, &rectPoints[0]);
          glDrawArrays((drawMode == OF_FILLED) ? GL_TRIANGLE_FAN : GL_LINE_LOOP, 0, 4);
  
          // use smoothness, if requested:
          if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();
  }
  
  //----------------------------------------------------------
  void ofCurve(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3){
  
          int resolution = 20;
  
          float t,t2,t3;
          float x,y;
  
          ofBeginShape();
  
          for (int i = 0; i < resolution; i++){
  
                  t         =  (float)i / (float)(resolution-1);
                  t2         = t * t;
                  t3         = t2 * t;
  
                  x = 0.5f * ( ( 2.0f * x1 ) +
                  ( -x0 + x2 ) * t +
                  ( 2.0f * x0 - 5.0f * x1 + 4 * x2 - x3 ) * t2 +
                  ( -x0 + 3.0f * x1 - 3.0f * x2 + x3 ) * t3 );
  
                  y = 0.5f * ( ( 2.0f * y1 ) +
                  ( -y0 + y2 ) * t +
                  ( 2.0f * y0 - 5.0f * y1 + 4 * y2 - y3 ) * t2 +
                  ( -y0 + 3.0f * y1 - 3.0f * y2 + y3 ) * t3 );
  
                  ofVertex(x,y);
          }
  
          ofEndShape();
  }
  
  //----------------------------------------------------------
  void ofBezier(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3){
  
          float   ax, bx, cx;
      float   ay, by, cy;
      float   t, t2, t3;
      float   x, y;
  
      // polynomial coefficients
      cx = 3.0f * (x1 - x0);
      bx = 3.0f * (x2 - x1) - cx;
      ax = x3 - x0 - cx - bx;
  
      cy = 3.0f * (y1 - y0);
      by = 3.0f * (y2 - y1) - cy;
      ay = y3 - y0 - cy - by;
  
      int resolution = 20;
  
      ofBeginShape();
      for (int i = 0; i < resolution; i++){
              t         =  (float)i / (float)(resolution-1);
              t2 = t * t;
              t3 = t2 * t;
                  x = (ax * t3) + (bx * t2) + (cx * t) + x0;
              y = (ay * t3) + (by * t2) + (cy * t) + y0;
              ofVertex(x,y);
      }
      ofEndShape();
  }
  
  //----------------------------------------------------------
  void ofSetColor(int _r, int _g, int _b){
          float r = (float)_r / 255.0f; r = MAX(0,MIN(r,1.0f));
          float g = (float)_g / 255.0f; g = MAX(0,MIN(g,1.0f));
          float b = (float)_b / 255.0f; b = MAX(0,MIN(b,1.0f));
  
          currentStyle.color.r = r * 255.0;
          currentStyle.color.g = g * 255.0;
          currentStyle.color.b = b * 255.0;
          currentStyle.color.a = 255;
  
          glColor4f(r,g,b,1);
  }
  
  //----------------------------------------------------------
  void ofSetColor(int _r, int _g, int _b, int _a){
          float r = (float)_r / 255.0f; r = MAX(0,MIN(r,1.0f));
          float g = (float)_g / 255.0f; g = MAX(0,MIN(g,1.0f));
          float b = (float)_b / 255.0f; b = MAX(0,MIN(b,1.0f));
          float a = (float)_a / 255.0f; a = MAX(0,MIN(a,1.0f));
  
          currentStyle.color.r = r * 255.0;
          currentStyle.color.g = g * 255.0;
          currentStyle.color.b = b * 255.0;
          currentStyle.color.a = a * 255.0;
  
          glColor4f(r,g,b,a);
  }
  
  //----------------------------------------------------------
  void ofSetColor(int hexColor){
          int r = (hexColor >> 16) & 0xff;
          int g = (hexColor >> 8) & 0xff;
          int b = (hexColor >> 0) & 0xff;
          ofSetColor(r,g,b);
  }
  
  //----------------------------------------------------------
  void ofEnableAlphaBlending(){
          glEnable(GL_BLEND);
          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
          currentStyle.blending = 1;
  }
  
  //----------------------------------------------------------
  void ofDisableAlphaBlending(){
          glDisable(GL_BLEND);
          currentStyle.blending = 0;
  }
  
  //----------------------------------------------------------
  void ofEnableSmoothing(){
          // please see:
          // http://www.opengl.org/resources/faq/technical/rasterization.htm
  	bSmoothHinted = true;
          currentStyle.smoothing = 1;
  }
  
  //----------------------------------------------------------
  void ofDisableSmoothing(){
          bSmoothHinted = false;
          currentStyle.smoothing = 0;
  }
  
  //----------------------------------------------------------
  void ofSetStyle(ofStyle style){
          //color
          ofSetColor((int)style.color.r, (int)style.color.g, (int)style.color.b, (int)style.color.a);
  
          //circle resolution - don't worry it only recalculates the display list if the res has changed
          ofSetCircleResolution(style.circleResolution);
  
          //line width - finally!
          ofSetLineWidth(style.lineWidth);
  
          //rect mode: corner/center
          ofSetRectMode(style.rectMode);
  
          //poly mode: winding type
          ofSetPolyMode(style.polyMode);
  
          //fill
          if(style.bFill ){
                  ofFill();
          }else{
                  ofNoFill();
          }
  
          //smoothing
          if(style.smoothing ){
                  ofEnableSmoothing();
          }else{
                  ofDisableSmoothing();
          }
  
          //blending
          if(style.blending ){
                  ofEnableAlphaBlending();
          }else{
                  ofDisableAlphaBlending();
          }
  }
  
  //----------------------------------------------------------
  ofStyle ofGetStyle(){
          return currentStyle;
  }
  
  //----------------------------------------------------------
  void ofPushStyle(){
          styleHistory.insert(styleHistory.begin(), currentStyle);
  
          //if we are over the max number of styles we have set, then delete the oldest styles.
          if( styleHistory.size() > OF_MAX_STYLE_HISTORY ){
                  styleHistory.erase(styleHistory.begin() + OF_MAX_STYLE_HISTORY, styleHistory.end());
                  //should we warn here?
                  //ofLog(OF_LOG_WARNING, "ofPushStyle - warning: you have used ofPushStyle more than \%i times without calling ofPopStyle - check your code!", OF_MAX_STYLE_HISTORY);
          }
  }
  
  //----------------------------------------------------------
  void ofPopStyle(){
          if( styleHistory.size() ){
                  ofSetStyle(styleHistory[0]);
                  styleHistory.erase(styleHistory.begin(), styleHistory.begin()+1);
          }
  }
  
  //our openGL wrappers
  //----------------------------------------------------------
  void ofPushMatrix(){
          glPushMatrix();
  }
  
  //----------------------------------------------------------
  void ofPopMatrix(){
          glPopMatrix();
  }
  
  //----------------------------------------------------------
  void ofTranslate(float x, float y, float z){
          glTranslatef(x, y, z);
  }
  
  //----------------------------------------------------------
  void ofScale(float xAmnt, float yAmnt, float zAmnt){
          glScalef(xAmnt, yAmnt, zAmnt);
  }
  
  //----------------------------------------------------------
  void ofRotate(float degrees, float vecX, float vecY, float vecZ){
          glRotatef(degrees, vecX, vecY, vecZ);
  }
  
  //----------------------------------------------------------
  void ofRotateX(float degrees){
          glRotatef(degrees, 1, 0, 0);
  }
  
  //----------------------------------------------------------
  void ofRotateY(float degrees){
          glRotatef(degrees, 0, 1, 0);
  }
  
  //----------------------------------------------------------
  void ofRotateZ(float degrees){
          glRotatef(degrees, 0, 0, 1);
  }
  
  //same as ofRotateZ
  //----------------------------------------------------------
  void ofRotate(float degrees){
          glRotatef(degrees, 0, 0, 1);
  }
  
  //--------------------------------------------------
  void ofDrawBitmapString(string textString, float x, float y){
  ifndef TARGET_OPENGLES        // temp for now, until is ported from existing iphone implementations
  
      glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT );
      glPixelStorei( GL_UNPACK_SWAP_BYTES,  GL_FALSE );
      glPixelStorei( GL_UNPACK_LSB_FIRST,   GL_FALSE );
      glPixelStorei( GL_UNPACK_ROW_LENGTH,  0        );
      glPixelStorei( GL_UNPACK_SKIP_ROWS,   0        );
      glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0        );
      glPixelStorei( GL_UNPACK_ALIGNMENT,   1        );
  
          int len = (int)textString.length();
          float yOffset = 0;
          float fontSize = 8.0f;
          glRasterPos2f(x,y);
          bool bOrigin = false;
          for(int c = 0; c < len; c++)
          {
                  if(textString[c] == '\n')
                  {
  
                          yOffset += bOrigin ? -1 : 1 * (fontSize*1.7);
                          glRasterPos2f(x,y + (int)yOffset);
                  } else if (textString[c] >= 32){
                          // < 32 = control characters - don't draw
                          // solves a bug with control characters
                          // getting drawn when they ought to not be
                          ofDrawBitmapCharacter(textString[c]);
                  }
          }
  
          glPopClientAttrib( );
  endif
  }
  
  //----------------------------------------------------------
  //Resets openGL parameters back to OF defaults
  void ofSetupGraphicDefaults(){
  
          glEnableClientState(GL_VERTEX_ARRAY);
          glDisableClientState(GL_NORMAL_ARRAY);
          glDisableClientState(GL_COLOR_ARRAY);
          glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  
          ofDisableSmoothing();
          ofDisableAlphaBlending();
          ofBackground(200, 200, 200);
          ofSetColor(255, 255, 255, 255);
  }
  
  //----------------------------------------------------------
  void ofSetupScreen(){
          int w, h;
  
          w = ofGetWidth();
          h = ofGetHeight();
  
          float halfFov, theTan, screenFov, aspect;
          screenFov                 = 60.0f;
  
          float eyeX                 = (float)w / 2.0;
          float eyeY                 = (float)h / 2.0;
          halfFov                 = PI * screenFov / 360.0;
          theTan                         = tanf(halfFov);
          float dist                 = eyeY / theTan;
          float nearDist         = dist / 10.0;        // near / far clip plane
          float farDist         = dist * 10.0;
          aspect                         = (float)w/(float)h;
  
          glMatrixMode(GL_PROJECTION);
          glLoadIdentity();
          gluPerspective(screenFov, aspect, nearDist, farDist);
  
          glMatrixMode(GL_MODELVIEW);
          glLoadIdentity();
          gluLookAt(eyeX, eyeY, dist, eyeX, eyeY, 0.0, 0.0, 1.0, 0.0);
  
          glScalef(1, -1, 1);           // invert Y axis so increasing Y goes down.
            glTranslatef(0, -h, 0);       // shift origin up to upper-left corner.
  }
  
  //-------------- polygons ----------------------------------
  //
  // to do polygons, we need tesselation
  // to do tesselation, we need glu and callbacks....
  // ------------------------------------
  // one of the callbacks creates new vertices (on intersections, etc),
  // and there is a potential for memory leaks
  // if we don't clean up properly
  // ------------------------------------
  // also the easiest system, using beginShape
  // vertex(), endShape, will also use dynamically
  // allocated memory
  // ------------------------------------
  // so, therefore, we will be using a static vector here
  // for two things:
  //
  // a) collecting vertices
  // b) new vertices on combine callback
  //
  // important note!
  //
  // this assumes single threaded polygon creation
  // you can have big problems if creating polygons in
  // multiple threads... please be careful
  //
  // (but also be aware that alot of opengl code
  // is single threaded anyway, so you will have problems
  // with many things opengl related across threads)
  //
  // ------------------------------------
  // (note: this implementation is based on code from ftgl)
  // ------------------------------------
  
  //---------------------------- for combine callback:
  std::vector <double*> newVectrices;
  std::vector <float> tessVertices;
  
  //---------------------------- store all the polygon vertices:
  std::vector <double*> polyVertices;
  //---------------------------- and for curve vertexes, since we need 4 to make a curve
  std::vector <double*> curveVertices;
  
  static int currentStartVertex = 0;
  
  // what is the starting vertex of the shape we are drawing
  // this allows multi contour polygons;
  
  static GLUtesselator * tobj = NULL;
  //static bool tessInited = false;
  //static GLdouble point[3];
  static GLint shapeType;
  
  void CALLBACK tessError(GLenum);
  void CALLBACK tessVertex( void* data);
  void CALLBACK tessCombine( GLdouble coords[3], void* vertex_data[4], GLfloat weight[4], void** outData);
  void clearTessVertices();
  void clearCurveVertices();
  
  //----------------------------------------------------------
  void CALLBACK tessError(GLenum errCode){
          const GLubyte* estring;
          estring = gluErrorString( errCode);
          ofLog(OF_LOG_ERROR, "tessError: \%s", estring);
  }
  
  //----------------------------------------------------------
  void CALLBACK tessBegin(GLint type){
          shapeType = type;
          tessVertices.clear();
  }
  
  //----------------------------------------------------------
  void CALLBACK tessEnd(){
          //we draw as 3d not 2d: change 3s bellow to 2 and comment the 3rd push_back in tessVertex to do 2D
  
          glEnableClientState(GL_VERTEX_ARRAY);
          glVertexPointer(3, GL_FLOAT, 0, &tessVertices[0]);
          glDrawArrays(shapeType, 0, tessVertices.size()/3);
          tessVertices.clear();
  }
  
  //----------------------------------------------------------
  void CALLBACK tessVertex( void* data){
  
          tessVertices.push_back( ( (double *)data)[0] );
          tessVertices.push_back( ( (double *)data)[1] );
          tessVertices.push_back( ( (double *)data)[2] );        //No need for z for now?
  }
  
  //----------------------------------------------------------
  void CALLBACK tessCombine( GLdouble coords[3], void* vertex_data[4], GLfloat weight[4], void** outData){
      double* vertex = new double[3];
      newVectrices.push_back(vertex);
      vertex[0] = coords[0];
      vertex[1] = coords[1];
      vertex[2] = coords[2];
      *outData = vertex;
  }
  
  //----------------------------------------------------------
  void clearTessVertices(){
          // -------------------------------------------------
      // ---------------- delete newly created vertices !
       for(vector<double*>::iterator itr=polyVertices.begin();
          itr!=polyVertices.end();
          ++itr){
          delete [] (*itr);
      }
      polyVertices.clear();
  
      // combine callback also makes new vertices, let's clear them:
      for(vector<double*>::iterator itr=newVectrices.begin();
          itr!=newVectrices.end();
          ++itr){
          delete [] (*itr);
      }
      newVectrices.clear();
      // -------------------------------------------------
  
      clearCurveVertices();
      currentStartVertex = 0;
  }
  
  //----------------------------------------------------------
  void clearCurveVertices(){
          // combine callback also makes new vertices, let's clear them:
      for(vector<double*>::iterator itr=curveVertices.begin();
          itr!=curveVertices.end();
          ++itr){
          delete [] (*itr);
      }
      curveVertices.clear();
  }
  
  //----------------------------------------------------------
  void ofSetPolyMode(int mode){
          switch (mode){
                  case OF_POLY_WINDING_ODD:
                          polyMode = OF_POLY_WINDING_ODD;
                          break;
                  case OF_POLY_WINDING_NONZERO:
                          polyMode = OF_POLY_WINDING_NONZERO;
                          break;
                  case OF_POLY_WINDING_POSITIVE:
                          polyMode = OF_POLY_WINDING_POSITIVE;
                          break;
                  case OF_POLY_WINDING_NEGATIVE:
                          polyMode = OF_POLY_WINDING_NEGATIVE;
                          break;
                  case OF_POLY_WINDING_ABS_GEQ_TWO:
                          polyMode = OF_POLY_WINDING_ABS_GEQ_TWO;
                          break;
                  default:
                          ofLog(OF_LOG_ERROR," error in ofSetPolyMode");
  
          }
  
          currentStyle.polyMode = polyMode;
  }
  
  //----------------------------------------------------------
  void ofBeginShape(){
  
          if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();
  
          // just clear the vertices, just to make sure that
          // someone didn't do something improper, like :
          // a) ofBeginShape()
          // b) ofVertex(), ofVertex(), ofVertex() ....
          // c) ofBeginShape()
          // etc...
  
          clearTessVertices();
  
          // now get the tesselator object up and ready:
  
          tobj = gluNewTess();
  
          // --------------------------------------------------------
          // note:         you could write your own begin and end callbacks
          //                         if you wanted to...
          //                         for example, to count triangles or know which
          //                         type of object tess is giving back, etc...
          // --------------------------------------------------------
  
          #if defined( TARGET_OSX)
                  #ifndef MAC_OS_X_VERSION_10_5
                          #define OF_NEED_GLU_FIX
                  #endif
          #endif
  
          // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
          // MAC - XCODE USERS PLEASE NOTE - some machines will not be able to compile the code below
          // if this happens uncomment the "OF_NEED_GLU_FIX" line below and it
          // should compile also please post to the forums with the error message, you OS X version,
          // Xcode verison and the CPU type - PPC or Intel. Thanks!
          // (note: this is known problem based on different version of glu.h, we are working on a fix)
          // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  
          //#define OF_NEED_GLU_FIX
  
          #ifdef OF_NEED_GLU_FIX
                  #define OF_GLU_CALLBACK_HACK (void(CALLBACK*)(...)
          #else
                  #define OF_GLU_CALLBACK_HACK (void(CALLBACK*)()
          #endif
  
          gluTessCallback( tobj, GLU_TESS_BEGIN, OF_GLU_CALLBACK_HACK)&tessBegin);
          gluTessCallback( tobj, GLU_TESS_VERTEX, OF_GLU_CALLBACK_HACK)&tessVertex);
          gluTessCallback( tobj, GLU_TESS_COMBINE, OF_GLU_CALLBACK_HACK)&tessCombine);
          gluTessCallback( tobj, GLU_TESS_END, OF_GLU_CALLBACK_HACK)&tessEnd);
          gluTessCallback( tobj, GLU_TESS_ERROR, OF_GLU_CALLBACK_HACK)&tessError);
  
          gluTessProperty( tobj, GLU_TESS_WINDING_RULE, polyMode);
          if (drawMode == OF_OUTLINE){
                  gluTessProperty( tobj, GLU_TESS_BOUNDARY_ONLY, true);
          } else {
                  gluTessProperty( tobj, GLU_TESS_BOUNDARY_ONLY, false);
          }
          gluTessProperty( tobj, GLU_TESS_TOLERANCE, 0);
  
          /* ------------------------------------------
          for 2d, this next call (normal) likely helps speed up ....
          quote : The computation of the normal represents about 10% of
          the computation time. For example, if all polygons lie in
          the x-y plane, you can provide the normal by using the
          -------------------------------------------  */
  
          gluTessNormal(tobj, 0.0, 0.0, 1.0);
          gluTessBeginPolygon( tobj, NULL);
  
  }
  
  //----------------------------------------------------------
  void ofVertex(float x, float y){
           double* point = new double[3];
           point[0] = x;
          point[1] = y;
          point[2] = 0;
           polyVertices.push_back(point);
  
           clearCurveVertices();        // we drop any "curve calls"
                                                           // once a vertex call has been made
                                                           // ie,
                                                           // you can't mix
                                                           // ofCurveVertex();
                                                           // ofCurveVertex();
                                                           // ofVertex();
                                                           // etc...
                                                           // and you need 4 calls
                                                           // to curve to see something...
  
  }
  
  //---------------------------------------------------
  void ofCurveVertex(float x, float y){
  
          double* point = new double[3];
           point[0] = x;
          point[1] = y;
          point[2] = 0;
           curveVertices.push_back(point);
  
           if (curveVertices.size() >= 4){
  
                   int startPos = (int)curveVertices.size() - 4;
  
                   float x0 = curveVertices[startPos + 0][0];
                     float y0 = curveVertices[startPos + 0][1];
                   float x1 = curveVertices[startPos + 1][0];
                     float y1 = curveVertices[startPos + 1][1];
                   float x2 = curveVertices[startPos + 2][0];
                     float y2 = curveVertices[startPos + 2][1];
                   float x3 = curveVertices[startPos + 3][0];
                     float y3 = curveVertices[startPos + 3][1];
  
                   int resolution = 20;
  
                  float t,t2,t3;
                  float x,y;
  
                  for (int i = 0; i < resolution; i++){
  
                          t         =  (float)i / (float)(resolution-1);
                          t2         = t * t;
                          t3         = t2 * t;
  
                          x = 0.5f * ( ( 2.0f * x1 ) +
                          ( -x0 + x2 ) * t +
                          ( 2.0f * x0 - 5.0f * x1 + 4 * x2 - x3 ) * t2 +
                          ( -x0 + 3.0f * x1 - 3.0f * x2 + x3 ) * t3 );
  
                          y = 0.5f * ( ( 2.0f * y1 ) +
                          ( -y0 + y2 ) * t +
                          ( 2.0f * y0 - 5.0f * y1 + 4 * y2 - y3 ) * t2 +
                          ( -y0 + 3.0f * y1 - 3.0f * y2 + y3 ) * t3 );
  
                          double* newPoint = new double[3];
                          newPoint[0] = x;
                          newPoint[1] = y;
                          newPoint[2] = 0;
                          polyVertices.push_back(newPoint);
                  }
           }
  
  }
  
  void ofBezierVertex(float x1, float y1, float x2, float y2, float x3, float y3){
  
          clearCurveVertices();        // we drop any stored "curve calls"
  
          // if, and only if poly vertices has points, we can make a bezier
          // from the last point
  
          // the resolultion with which we computer this bezier
          // is arbitrary, can we possibly make it dynamic?
  
          if (polyVertices.size() > 0){
  
                  float x0 = polyVertices[polyVertices.size()-1][0];
                  float y0 = polyVertices[polyVertices.size()-1][1];
  
                  float   ax, bx, cx;
                  float   ay, by, cy;
                  float   t, t2, t3;
                  float   x, y;
  
                  // polynomial coefficients
                  cx = 3.0f * (x1 - x0);
                  bx = 3.0f * (x2 - x1) - cx;
                  ax = x3 - x0 - cx - bx;
  
                  cy = 3.0f * (y1 - y0);
                  by = 3.0f * (y2 - y1) - cy;
                  ay = y3 - y0 - cy - by;
  
                  // arbitrary ! can we fix??
                  int resolution = 20;
  
                  for (int i = 0; i < resolution; i++){
                          t         =  (float)i / (float)(resolution-1);
                          t2 = t * t;
                          t3 = t2 * t;
                          x = (ax * t3) + (bx * t2) + (cx * t) + x0;
                          y = (ay * t3) + (by * t2) + (cy * t) + y0;
                          ofVertex(x,y);
                  }
  
          }
  
  }
  
  //----------------------------------------------------------
  void ofNextContour(bool bClose){
  
          if ((bClose == true)){
                  //---------------------------
                  if ((int)polyVertices.size() > currentStartVertex){
  
                          double* point = new double[3];
                           point[0] = polyVertices[currentStartVertex][0];
                          point[1] = polyVertices[currentStartVertex][1];
                          point[2] = 0;
                           polyVertices.push_back(point);
                   }
          }
  
          if ((polyMode == OF_POLY_WINDING_ODD) && (drawMode == OF_OUTLINE)){
                  // let's just draw via another method, like glLineLoop
                  // much, much faster, and *no* tess / computation necessary
  
                  int numToDraw = polyVertices.size()-currentStartVertex;
                  if( numToDraw > 0){
  
                          // GLfloat points[numToDraw * 2];        // zach, we can't do this on VS 2008
                          GLfloat * points = new GLfloat[numToDraw * 2];
                          int k = 0;
  
                          for (int i=currentStartVertex; i< (int)polyVertices.size(); i++) {
                                  points[k] = polyVertices[i][0];
                                  points[k+1] = polyVertices[i][1];
                                  k+=2;
                          }
  
                          glEnableClientState(GL_VERTEX_ARRAY);
                          glVertexPointer(2, GL_FLOAT, 0, &points[0]);
                          glDrawArrays(GL_LINE_STRIP, 0, numToDraw);
  
                          delete [] points;
                  }
  
          } else {
  
                  if ( tobj != NULL){
                gluTessBeginContour( tobj);
                          for (int i=currentStartVertex; i<(int)polyVertices.size(); i++) {
                                     gluTessVertex( tobj, polyVertices[i],polyVertices[i]);
                          }
                          gluTessEndContour( tobj);
                  }
             }
  
             currentStartVertex = (int)polyVertices.size();
  
  }
  
  //----------------------------------------------------------
  void ofEndShape(bool bClose){
  
          // (close -> add the first point to the end)
          // -----------------------------------------------
  
          if ((bClose == true)){
                  //---------------------------
                  if ((int)polyVertices.size() > currentStartVertex){
  
                          double* point = new double[3];
                           point[0] = polyVertices[currentStartVertex][0];
                          point[1] = polyVertices[currentStartVertex][1];
                          point[2] = 0;
                           polyVertices.push_back(point);
  
                   }
          }
          //------------------------------------------------
  
          if ((polyMode == OF_POLY_WINDING_ODD) && (drawMode == OF_OUTLINE)){
  
                  // let's just draw via another method, like glLineLoop
                  // much, much faster, and *no* tess / computation necessary
  
                  int numToDraw = polyVertices.size()-currentStartVertex;
                  if( numToDraw > 0){
  
                          // GLfloat points[numToDraw * 2]; // zach, needed for VS 2008
  
                          GLfloat * points = new GLfloat[numToDraw * 2];
  
                          int k = 0;
  
                          for (int i=currentStartVertex; i< (int)polyVertices.size(); i++) {
                                  points[k] = polyVertices[i][0];
                                  points[k+1] = polyVertices[i][1];
  
                                  k+=2;
                          }
  
                          glEnableClientState(GL_VERTEX_ARRAY);
                          glVertexPointer(2, GL_FLOAT, 0, &points[0]);
                          glDrawArrays(GL_LINE_STRIP, 0, numToDraw);
  
                          delete [] points;
                  }
  
          } else {
  
                  if ( tobj != NULL){
                      gluTessBeginContour( tobj);
                          for (int i=currentStartVertex; i<(int)polyVertices.size(); i++) {
                                     gluTessVertex( tobj, polyVertices[i],polyVertices[i]);
                          }
  
                          gluTessEndContour( tobj);
  
                  }
             }
  
          if ( tobj != NULL){
                  // no matter what we did / do, we need to delete the tesselator object
                  gluTessEndPolygon( tobj);
                  gluDeleteTess( tobj);
                  tobj = NULL;
          }
  
             // now clear the vertices on the dynamically allocated data
             clearTessVertices();
  
             if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();
  
  }
  
  


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.