ShapeMesh* ShapeTesselator::createMesh(int windingRule)
 {
     tessTesselate(tess, windingRule, TESS_POLYGONS, 3, 2, 0);
     
     ShapeMesh *mesh = new ShapeMesh;
     mesh->appendVertices((Vec2f*)tessGetVertices(tess), tessGetVertexCount(tess));
     mesh->appendIndices((uint32_t*)tessGetElements(tess), tessGetElementCount(tess) * 3);
     
     return mesh;
 }
Example #2
0
TriMeshRef Triangulator::createMesh( Winding winding )
{
	TriMeshRef result = make_shared<TriMesh>( TriMesh::Format().positions( 2 ) );
	
	tessTesselate( mTess.get(), (int)winding, TESS_POLYGONS, 3, 2, 0 );
	result->appendVertices( (vec2*)tessGetVertices( mTess.get() ), tessGetVertexCount( mTess.get() ) );
	result->appendIndices( (uint32_t*)( tessGetElements( mTess.get() ) ), tessGetElementCount( mTess.get() ) * 3 );
	
	return result;
}
Example #3
0
TriMesh Triangulator::calcMesh( Winding winding )
{
	TriMesh result( TriMesh::Format().positions( 2 ) );
	
	tessTesselate( mTess.get(), (int)winding, TESS_POLYGONS, 3, 2, 0 );
	result.appendVertices( (vec2*)tessGetVertices( mTess.get() ), tessGetVertexCount( mTess.get() ) );
	result.appendIndices( (uint32_t*)( tessGetElements( mTess.get() ) ), tessGetElementCount( mTess.get() ) * 3 );
	
	return result;
}
Example #4
0
//----------------------------------------------------------
void ofTessellator::performTessellation(ofPolyWindingMode polyWindingMode, ofMesh& dstmesh, bool bIs2D ) {

	if (!tessTesselate(cacheTess, polyWindingMode, TESS_POLYGONS, 3, 3, 0)){
		ofLogError("ofTessellator") << "performTessellation(): mesh polygon tessellation failed, winding mode " << polyWindingMode;
		return;
	}

	int numVertices = tessGetVertexCount( cacheTess );
	int numIndices = tessGetElementCount( cacheTess )*3;

	dstmesh.clear();
	dstmesh.addVertices((ofDefaultVertexType*)tessGetVertices(cacheTess),numVertices);
	dstmesh.addIndices((ofIndexType*)tessGetElements(cacheTess),numIndices);
	/*ofIndexType * tessElements = (ofIndexType *)tessGetElements(cacheTess);
	for(int i=0;i<numIndices;i++){
		if(tessElements[i]!=TESS_UNDEF)
			dstmesh.addIndex(tessElements[i]);
	}*/
	dstmesh.setMode(OF_PRIMITIVE_TRIANGLES);

}
//----------------------------------------------------------------//
void SafeTesselator::GetTriangles ( MOAIVertexBuffer& vtxBuffer, MOAIIndexBuffer& idxBuffer ) {

	ZLMemStream idxStream;
	ZLMemStream vtxStream;

	const int* elems = tessGetElements ( this->mTess );
	const int nelems = tessGetElementCount ( this->mTess );
	
	for ( int i = 0; i < nelems; ++i ) {
		const int* tri = &elems [ i * 3 ];
		
		idxStream.Write < u32 >( tri [ 0 ]);
		idxStream.Write < u32 >( tri [ 1 ]);
		idxStream.Write < u32 >( tri [ 2 ]);
	}

	const float* verts = tessGetVertices ( this->mTess );
	const int nverts = tessGetVertexCount ( this->mTess );
	
	for ( int i = 0; i < nverts; ++i ) {
		const ZLVec2D& vert = (( const ZLVec2D* )verts )[ i ];
		
		vtxStream.Write < float >( vert.mX );
		vtxStream.Write < float >( vert.mY );
		vtxStream.Write < float >( 0.0f );
		vtxStream.Write < u32 >( 0xffffffff );
	}
	
	idxStream.Seek ( 0, SEEK_SET );
	vtxStream.Seek ( 0, SEEK_SET );
	
	idxBuffer.CopyFromStream ( idxStream, 4 );
	
	vtxBuffer.Clear ();
	vtxBuffer.Reserve ( vtxStream.GetLength ());
	vtxBuffer.WriteStream ( vtxStream );
}
Example #6
0
int PolyTessGeo::BuildTess(void)
{
    //  Setup the tesselator
    
    TESSalloc ma;
    TESStesselator* tess = 0;
    const int nvp = 3;
//    unsigned char* vflags = 0;
#ifdef USE_POOL
    struct MemPool pool;
    unsigned char mem[4024*1024];
//    int nvflags = 0;
#else
    int allocated = 0;
    double t0 = 0, t1 = 0;
#endif

#ifdef USE_POOL

    pool.size = 0;
    pool.cap = sizeof(mem);
    pool.buf = mem;
    memset(&ma, 0, sizeof(ma));
    ma.memalloc = poolAlloc;
    ma.memfree = poolFree;
    ma.userData = (void*)&pool;
    ma.extraVertices = 256; // realloc not provided, allow 256 extra vertices.

#else
 
    memset(&ma, 0, sizeof(ma));
    ma.memalloc = stdAlloc;
    ma.memfree = stdFree;
    ma.userData = (void*)&allocated;
    ma.extraVertices = 256; // realloc not provided, allow 256 extra vertices.
#endif

    tess = tessNewTess(&ma);
    if (!tess)
        return -1;

    //tessSetOption(tess, TESS_CONSTRAINED_DELAUNAY_TRIANGULATION, 1);

    
    //  Create the contour vertex arrays
    
      int iir, ip;

//      Get max number number of points(vertices) in any contour
      int npta  = m_cntr[0];
      npta += 2;                            // fluff

      for( iir=0 ; iir < m_ncnt-1 ; iir++){
            int nptr = m_cntr[iir+1];
            npta = wxMax(npta, nptr); 
      }


      TESSreal *geoPt = (TESSreal *)malloc((npta) * 2 * sizeof(TESSreal));     // tess input vertex array
      TESSreal *ppt = geoPt;


//      Create input structures

//    Exterior Ring
      int npte = m_cntr[0];
      unsigned int ptValid = npte;

//  Check and account for winding direction of ring


      double x0, y0, x, y;
      OGRPoint p;

      wxPoint2DDouble *pp = (wxPoint2DDouble *)m_vertexPtrArray[0];
      bool cw = isRingClockwise(pp, m_cntr[0]);
      
      //pp++;       // skip 0?

      if(cw)
      {
            x0 = pp->m_x;
            y0 = pp->m_y;
      }
      else
      {
            x0 = pp[npte-1].m_x;
            y0 = pp[npte-1].m_y;
      }



//  Transcribe points to vertex array, in proper order with no duplicates
//   also, accounting for tess_orient
      for(ip = 0 ; ip < npte ; ip++)
      {
            int pidx;
            if(cw)
                  pidx = npte - ip - 1;

            else
                  pidx = ip;

            x = pp[pidx].m_x;
            y = pp[pidx].m_y;

            if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS))
            {
                  if(m_tess_orient == TESS_VERT)
                  {
                        *ppt++ = x;
                        *ppt++ = y;
                  }
                  else
                  {
                        *ppt++ = y;
                        *ppt++ = x;
                  }
            }
            else
                  ptValid--;

            x0 = x;
            y0 = y;
      }

      
      //  Apply LOD reduction
    int beforeLOD = ptValid;
    int afterLOD = beforeLOD;
   
    std::vector<bool> bool_keep;
    if(ptValid > 5 && (m_LOD_meters > .01)){
        
        for(unsigned int i = 0 ; i < ptValid ; i++)
            bool_keep.push_back(false);

        // Keep a few key points
        bool_keep[0] = true;
        bool_keep[1] = true;
        bool_keep[ptValid-1] = true;
        bool_keep[ptValid-2] = true;
        
        DouglasPeuckerFI(geoPt, 1, ptValid-2, m_LOD_meters, bool_keep);
            
        // Create a new buffer
        float *LOD_result = (float *)malloc((npte) * 2 * sizeof(float));     
        float *plod = LOD_result;
        int kept_LOD =0;
        
        for(unsigned int i=0 ; i < ptValid ; i++){
            if(bool_keep[i]){
                float x = geoPt[i*2];
                float y = geoPt[(i*2) + 1];
                *plod++ = x;
                *plod++ = y;
                kept_LOD++;
            }
        }

        beforeLOD = ptValid;
        afterLOD = kept_LOD;
    
        tessAddContour(tess, 2, LOD_result, sizeof(float)*2, kept_LOD);
        
        free(LOD_result);
    }
    else {
        tessAddContour(tess, 2, geoPt, sizeof(float)*2, ptValid);
    }
    
    

#if 1
//  Now the interior contours
      for(iir=0; iir < m_ncnt-1; iir++)
      {
            ppt = geoPt;
            wxPoint2DDouble *pp = (wxPoint2DDouble *)m_vertexPtrArray[iir + 1];

            int npti  = m_cntr[iir+1];
            ptValid = npti;
            
      //  Check and account for winding direction of ring
            bool cw = isRingClockwise(pp, m_cntr[iir+1]);

            if(!cw)
            {
                  x0 = pp[0].m_x;
                  y0 = pp[0].m_y;
            }
            else
            {
                  x0 = pp[npti-1].m_x;
                  y0 = pp[npti-1].m_y;
            }

//  Transcribe points to vertex array, in proper order with no duplicates
//   also, accounting for tess_orient
            for(int ip = 0 ; ip < npti ; ip++)
            {
                  OGRPoint p;
                  int pidx;
                  if(!cw)                               // interior contours must be cw
                        pidx = npti - ip - 1;
                  else
                        pidx = ip;


                  x = pp[pidx].m_x;
                  y = pp[pidx].m_y;

                  if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS))
                  {
                        if(m_tess_orient == TESS_VERT)
                        {
                              *ppt++ = x;
                              *ppt++ = y;
                        }
                        else
                        {
                              *ppt++ = y;
                              *ppt++ = x;
                        }
                  }
                  else
                        ptValid--;

                  x0 = x;
                  y0 = y;

            }
            
            tessAddContour(tess, 2, geoPt, sizeof(float)*2, ptValid);

      }
#endif


      //      Ready to kick off the tesselator

      TriPrim *pTPG_Last = NULL;
      TriPrim *pTPG_Head = NULL;

      //s_nvmax = 0;

      //OCPNStopWatchTess tt0;
      
      if (!tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, nvp, 2, 0))
        return -1;
      double tessTime = 0; //tt0.GetTime();


    //  Tesselation all done, so...
    //  Create the data structures
    
    //  Make a linked list of TriPrims from tess output arrays

    const TESSreal* verts = tessGetVertices(tess);
    const int* vinds = tessGetVertexIndices(tess);
    const int* elems = tessGetElements(tess);
    const int nverts = tessGetVertexCount(tess);
    int nelems = tessGetElementCount(tess);

      
    bool skip = false;
    //skip = true;
    
    double stripTime = 0;
    //tt0.Reset();

    int bytes_needed_vbo = 0;
    float *vbo = 0;
    
    if(m_bstripify && nelems && !skip){
        
         
        STRIPERCREATE sc;
        sc.DFaces                       = (udword *)elems;
        sc.NbFaces                      = nelems;
        sc.AskForWords          = false;
        sc.ConnectAllStrips     = false;
        sc.OneSided             = false;
        sc.SGIAlgorithm         = false;

       
        Striper Strip;
        Strip.Init(sc);
        
        STRIPERRESULT sr;
        Strip.Compute(sr);

        stripTime = 0; //tt0.GetTime();

/*        
        fprintf(stdout, "Number of strips: %d\n", sr.NbStrips);
        fprintf(stdout, "Number of points: %d\n", nelems);
        uword* Refs = (uword*)sr.StripRuns;
        for(udword i=0;i<sr.NbStrips;i++)
        {
                fprintf(stdout, "Strip %d:   ", i);
                udword NbRefs = sr.StripLengths[i];
                for(udword j=0;j<NbRefs;j++)
                {
                        fprintf(stdout, "%d ", *Refs++);
                }
                fprintf(stdout, "\n");
        }
*/
        // calculate and allocate the final (float) VBO-like buffer for this entire feature
        
        int *Refs = (int *)sr.StripRuns;
        for(unsigned int i=0;i<sr.NbStrips;i++){
            unsigned int NbRefs = sr.StripLengths[i];         //  vertices per strip
            bytes_needed_vbo += NbRefs * 2 * sizeof(float);
        }
        
        vbo = (float *)malloc(bytes_needed_vbo);
        float *vbo_run = vbo;
        
        for(unsigned int i=0;i<sr.NbStrips;i++){
            unsigned int NbRefs = sr.StripLengths[i];         //  vertices per strip
 
            if(NbRefs >= 3){                              // this is a valid primitive

                TriPrim *pTPG = new TriPrim;
                if(NULL == pTPG_Last){
                    pTPG_Head = pTPG;
                    pTPG_Last = pTPG;
                }
                else{
                    pTPG_Last->p_next = pTPG;
                    pTPG_Last = pTPG;
                }

                pTPG->p_next = NULL;
                pTPG->nVert = NbRefs;
            
//                pTPG->p_vertex = (double *)malloc(NbRefs * 2 * sizeof(double));
//                GLdouble *pdd = (GLdouble*)pTPG->p_vertex;

                pTPG->p_vertex = (double *)vbo_run;

            //  Preset LLBox bounding box limits
                double sxmax = -1e8;
                double sxmin = 1e8;
                double symax = -1e8;
                double symin = 1e8;

                if(NbRefs >3)
                    pTPG->type = GL_TRIANGLE_STRIP;
                else
                    pTPG->type = GL_TRIANGLES;

                // Add the first two points
                int vindex[3];
                vindex[0] = *Refs++;
                vindex[1] = *Refs++;
                unsigned int np = 2;         // for the first triangle
                    
                for(unsigned int i = 2; i < NbRefs ; i++){    
                    vindex[np] = *Refs++;
                    np++;
                    
                    for (unsigned int j = 0; j < np; ++j){
                        double yd = verts[vindex[j]*2];
                        double xd = verts[vindex[j]*2+1];
                    
                    // Calculate LLBox bounding box for each Tri-prim
                        if(m_bmerc_transform){
                            double valx = ( xd * mx_rate ) + mx_offset;
                            double valy = ( yd * my_rate ) + my_offset;
            
                                //    quickly convert to lat/lon
                            double lat = ( 2.0 * atan ( exp ( valy/CM93_semimajor_axis_meters ) ) - PI/2. ) / DEGREE;
                            double lon= ( valx / ( DEGREE * CM93_semimajor_axis_meters ) );


                            sxmax = wxMax(lon, sxmax);
                            sxmin = wxMin(lon, sxmin);
                            symax = wxMax(lat, symax);
                            symin = wxMin(lat, symin);
                        }
                        else{
                            sxmax = wxMax(xd, sxmax);
                            sxmin = wxMin(xd, sxmin);
                            symax = wxMax(yd, symax);
                            symin = wxMin(yd, symin);
                        }
                        
                    //  Append this point to TriPrim vbo

                        *vbo_run++ = (xd) + m_feature_easting;    // adjust to chart ref coordinates
                        *vbo_run++ = (yd) + m_feature_northing;
                    }               // For

                    // Compute the final LLbbox for this TriPrim chain
                    double minlat, minlon, maxlat, maxlon;
                    fromSM(sxmin, symin, m_feature_ref_lat, m_feature_ref_lon, &minlat, &minlon);
                    fromSM(sxmax, symax, m_feature_ref_lat, m_feature_ref_lon, &maxlat, &maxlon);

                    pTPG->tri_box.Set(minlat, minlon, maxlat, maxlon);

                    // set for next single point
                    np = 0;

                }
            }
            else
                Refs += sr.StripLengths[i];
           
        }                       // for strips
    }
    else{       // not stripified
        
        m_nvertex_max = nverts;               // record largest vertex count
        
        bytes_needed_vbo = nelems * nvp * 2 * sizeof(float);
        vbo = (float *)malloc(bytes_needed_vbo);
        float *vbo_run = vbo;

        for (int i = 0; i < nelems; ++i){
            const int* p = &elems[i*nvp];

            TriPrim *pTPG = new TriPrim;
            if(NULL == pTPG_Last){
                    pTPG_Head = pTPG;
                    pTPG_Last = pTPG;
            }
            else{
                    pTPG_Last->p_next = pTPG;
                    pTPG_Last = pTPG;
            }

            pTPG->p_next = NULL;
            pTPG->type = GL_TRIANGLES;
            pTPG->nVert = nvp;
            
//            pTPG->p_vertex = (double *)malloc(nvp * 2 * sizeof(double));
//            GLdouble *pdd = (GLdouble*)pTPG->p_vertex;

            pTPG->p_vertex = (double *)vbo_run;

            //  Preset LLBox bounding box limits
            double sxmax = -1e8;
            double sxmin = 1e8;
            double symax = -1e8;
            double symin = 1e8;

            for (size_t j = 0; j < nvp && p[j] != TESS_UNDEF; ++j){
                double yd = verts[p[j]*2];
                double xd = verts[p[j]*2+1];
                
                // Calculate LLBox bounding box for each Tri-prim
                if(m_bmerc_transform){
                    double valx = ( xd * mx_rate ) + mx_offset;
                    double valy = ( yd * my_rate ) + my_offset;
    
                        //    quickly convert to lat/lon
                    double lat = ( 2.0 * atan ( exp ( valy/CM93_semimajor_axis_meters ) ) - PI/2. ) / DEGREE;
                    double lon= ( valx / ( DEGREE * CM93_semimajor_axis_meters ) );


                    sxmax = wxMax(lon, sxmax);
                    sxmin = wxMin(lon, sxmin);
                    symax = wxMax(lat, symax);
                    symin = wxMin(lat, symin);
                }
                else{
                    sxmax = wxMax(xd, sxmax);
                    sxmin = wxMin(xd, sxmin);
                    symax = wxMax(yd, symax);
                    symin = wxMin(yd, symin);
                }
                
                //  Append this point to TriPrim, converting to SM if called for

                if(m_b_senc_sm){
                    double easting, northing;
                    toSM(yd, xd, m_ref_lat, m_ref_lon, &easting, &northing);
                    *vbo_run++ = easting;
                    *vbo_run++ = northing;
                }
                else{
                    *vbo_run++ = xd;
                    *vbo_run++ = yd;
                }
            }
        
        pTPG->tri_box.Set(symin, sxmin, symax, sxmax);
        }
    }           // stripify

    if(m_printStats){
        int nTri = 0;
        int nStrip = 0;
        
        TriPrim *p_tp = pTPG_Head;
        while( p_tp ) {
            if(p_tp->type == GL_TRIANGLES)
                nTri++;
            if(p_tp->type == GL_TRIANGLE_STRIP)
                nStrip++;
            
          p_tp = p_tp->p_next; // pick up the next in chain
        }
        
        if((nTri + nStrip) > 10000){
            printf("LOD:  %d/%d\n", afterLOD, beforeLOD);

            printf("Tess time(ms): %f\n", tessTime);
            printf("Strip time(ms): %f\n", stripTime);

            printf("Primitives:   Tri: %5d  Strip: %5d  Total: %5d\n", nTri, nStrip, nTri + nStrip);
            printf("\n");
        }
    }
 
   
    
      m_ppg_head = new PolyTriGroup;
      m_ppg_head->m_bSMSENC = m_b_senc_sm;

      m_ppg_head->nContours = m_ncnt;
      m_ppg_head->pn_vertex = m_cntr;             // pointer to array of poly vertex counts
      m_ppg_head->tri_prim_head = pTPG_Head;         // head of linked list of TriPrims
      //m_ppg_head->data_type = DATA_TYPE_DOUBLE;
      

//  Transcribe the raw geometry buffer
//  Converting to float as we go, and
//  allowing for tess_orient
//  Also, convert to SM if requested

      int nptfinal = npta;
      
      //  No longer need the full geometry in the SENC,
      nptfinal = 1;
      
      m_nwkb = (nptfinal +1) * 2 * sizeof(float);
      m_ppg_head->pgroup_geom = (float *)malloc(m_nwkb);
      float *vro = m_ppg_head->pgroup_geom;
      ppt = geoPt;
      float tx,ty;

      for(ip = 0 ; ip < nptfinal ; ip++)
      {
            if(TESS_HORZ == m_tess_orient)
            {
                  ty = *ppt++;
                  tx = *ppt++;
            }
            else
            {
                  tx = *ppt++;
                  ty = *ppt++;
            }

            if(m_b_senc_sm)
            {
            //  Calculate SM from chart common reference point
                  double easting, northing;
                  toSM(ty, tx, 0/*ref_lat*/, 0/*ref_lon*/, &easting, &northing);
                  *vro++ = easting;              // x
                  *vro++ = northing;             // y
            }
            else
            {
                  *vro++ = tx;                  // lon
                  *vro++ = ty;                  // lat
            }

            ppt++;                      // skip z
      }


      m_ppg_head->bsingle_alloc = true;
      m_ppg_head->single_buffer = (unsigned char *)vbo;
      m_ppg_head->single_buffer_size = bytes_needed_vbo;
      m_ppg_head->data_type = DATA_TYPE_FLOAT;
      

      free (geoPt);

      //    All allocated buffers are owned now by the m_ppg_head
      //    And will be freed on dtor of this object
 
      if (tess) tessDeleteTess(tess);

      m_bOK = true;
      

      return 0;
      

}
Example #7
0
int main(int argc, char *argv[])
{
	GLFWwindow* window;
	const GLFWvidmode* mode;
	int width,height,i,j;
	struct SVGPath* bg;
	struct SVGPath* fg;
	struct SVGPath* it;
	float bounds[4],view[4],cx,cy,w,offx,offy;
	float t = 0.0f, pt = 0.0f;
	TESSalloc ma;
	TESStesselator* tess = 0;
	const int nvp = 6;
	unsigned char* vflags = 0;
	int nvflags = 0;
#ifdef USE_POOL
	struct MemPool pool;
	unsigned char mem[1024*1024];
#else
	int allocated = 0;
#endif
	TESS_NOTUSED(argc);
	TESS_NOTUSED(argv);

	if (!glfwInit()) {
		printf("Failed to init GLFW.");
		return -1;
	}

	printf("loading...\n");
	// Load assets
	bg = svgParseFromFile("../Bin/bg.svg");
	if (!bg) return -1;
	fg = svgParseFromFile("../Bin/fg.svg");
	if (!fg) return -1;

	printf("go...\n");
	
	// Flip y
	for (it = bg; it != NULL; it = it->next)
		for (i = 0; i < it->npts; ++i)
			it->pts[i*2+1] = -it->pts[i*2+1];
	for (it = fg; it != NULL; it = it->next)
		for (i = 0; i < it->npts; ++i)
			it->pts[i*2+1] = -it->pts[i*2+1];

	// Find FG bounds and center.
	bounds[0] = bounds[2] = fg->pts[0];
	bounds[1] = bounds[3] = fg->pts[1];
	for (it = fg; it != NULL; it = it->next)
	{
		for (i = 0; i < it->npts; ++i)
		{
			const float x = it->pts[i*2];
			const float y = it->pts[i*2+1];
			if (x < bounds[0]) bounds[0] = x;
			if (y < bounds[1]) bounds[1] = y;
			if (x > bounds[2]) bounds[2] = x;
			if (y > bounds[3]) bounds[3] = y;
		}
	}
	cx = (bounds[0]+bounds[2])/2;
	cy = (bounds[1]+bounds[3])/2;
	for (it = fg; it != NULL; it = it->next)
	{
		for (i = 0; i < it->npts; ++i)
		{
			it->pts[i*2] -= cx;
			it->pts[i*2+1] -= cy;
		}
	}
			
	// Find BG bounds.
	bounds[0] = bounds[2] = bg->pts[0];
	bounds[1] = bounds[3] = bg->pts[1];
	for (it = bg; it != NULL; it = it->next)
	{
		for (i = 0; i < it->npts; ++i)
		{
			const float x = it->pts[i*2];
			const float y = it->pts[i*2+1];
			if (x < bounds[0]) bounds[0] = x;
			if (y < bounds[1]) bounds[1] = y;
			if (x > bounds[2]) bounds[2] = x;
			if (y > bounds[3]) bounds[3] = y;
		}
	}
		
#ifdef USE_POOL

	pool.size = 0;
	pool.cap = sizeof(mem);
	pool.buf = mem;
	memset(&ma, 0, sizeof(ma));
	ma.memalloc = poolAlloc;
	ma.memfree = poolFree;
	ma.userData = (void*)&pool;
	ma.extraVertices = 256; // realloc not provided, allow 256 extra vertices.

#else

	memset(&ma, 0, sizeof(ma));
	ma.memalloc = stdAlloc;
	ma.memfree = stdFree;
	ma.userData = (void*)&allocated;
	ma.extraVertices = 256; // realloc not provided, allow 256 extra vertices.

	tess = tessNewTess(&ma);
	if (!tess)
		return -1;

	// Offset the foreground shape to center of the bg.
	offx = (bounds[2]+bounds[0])/2;
	offy = (bounds[3]+bounds[1])/2;
	for (it = fg; it != NULL; it = it->next)
	{
		for (i = 0; i < it->npts; ++i)
		{
			it->pts[i*2] += offx;
			it->pts[i*2+1] += offy;
		}
	}
	
	// Add contours.
	for (it = bg; it != NULL; it = it->next)
		tessAddContour(tess, 2, it->pts, sizeof(float)*2, it->npts);
	for (it = fg; it != NULL; it = it->next)
		tessAddContour(tess, 2, it->pts, sizeof(float)*2, it->npts);
	if (!tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, nvp, 2, 0))
		return -1;
	printf("Memory used: %.1f kB\n", allocated/1024.0f);
	
#endif
	
	mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
	width = mode->width - 40;
	height = mode->height - 80;
    window = glfwCreateWindow(width, height, "Libtess2 Demo", NULL, NULL);
	if (!window) {
		glfwTerminate();
		return -1;
	}

	glfwSetKeyCallback(window, key);
	glfwMakeContextCurrent(window);

	// Adjust bounds so that we get nice view of the bg.
	cx = (bounds[0]+bounds[2])/2;
	cy = (bounds[3]+bounds[1])/2;
	w = (bounds[2]-bounds[0])/2;
	view[0] = cx - w*1.2f;
	view[2] = cx + w*1.2f;
	view[1] = cy - w*1.2f*(float)height/(float)width;
	view[3] = cy + w*1.2f*(float)height/(float)width;
		
	glfwSetTime(0);

	while (!glfwWindowShouldClose(window))
	{
		float ct = (float)glfwGetTime();
		if (run) t += ct - pt;
		pt = ct;
		
		// Update and render
		glViewport(0, 0, width, height);
		glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glDisable(GL_TEXTURE_2D);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(view[0],view[2],view[1],view[3],-1,1);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glDisable(GL_DEPTH_TEST);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

#ifdef USE_POOL
		pool.size = 0; // reset pool
		tess = tessNewTess(&ma);
		if (tess)
		{
			offx = (view[2]+view[0])/2 + sinf(t) * (view[2]-view[0])/2;
			offy = (view[3]+view[1])/2 + cosf(t*3.13f) * (view[3]-view[1])/6;
			
			for (it = fg; it != NULL; it = it->next)
			{
				for (i = 0; i < it->npts; ++i)
				{
					it->pts[i*2] += offx;
					it->pts[i*2+1] += offy;
				}
			}

			for (it = bg; it != NULL; it = it->next)
				tessAddContour(tess, 2, it->pts, sizeof(float)*2, it->npts);
			for (it = fg; it != NULL; it = it->next)
				tessAddContour(tess, 2, it->pts, sizeof(float)*2, it->npts);

			for (it = fg; it != NULL; it = it->next)
			{
				for (i = 0; i < it->npts; ++i)
				{
					it->pts[i*2] -= offx;
					it->pts[i*2+1] -= offy;
				}
			}

			// First combine contours and then triangulate, this removes unnecessary inner vertices.
			if (tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_BOUNDARY_CONTOURS, 0, 0, 0))
			{
				const float* verts = tessGetVertices(tess);
				const int* vinds = tessGetVertexIndices(tess);
				const int nverts = tessGetVertexCount(tess);
				const int* elems = tessGetElements(tess);
				const int nelems = tessGetElementCount(tess);

				if (nverts > nvflags)
				{
					if (vflags)
						free(vflags);
					nvflags = nverts;
					vflags = (unsigned char*)malloc(sizeof(unsigned char)*nvflags);
				}
				
				if (vflags)
				{
					// Vertex indices describe the order the indices were added and can be used
					// to map the tesselator output to input. Vertices marked as TESS_UNDEF
					// are the ones that were created at the intersection of segments.
					// That is, if vflags is set it means that the vertex comes from intersegment.
					for (i = 0; i < nverts; ++i)
						vflags[i] = vinds[i] == TESS_UNDEF ? 1 : 0;
				}
				
				for (i = 0; i < nelems; ++i)
				{
					int b = elems[i*2];
					int n = elems[i*2+1];
					tessAddContour(tess, 2, &verts[b*2], sizeof(float)*2, n);
				}
				if (!tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, nvp, 2, 0))
					tess = 0;
			}
			else
				tess = 0;				
		}
#endif		

		// Draw tesselated pieces.
		if (tess)
		{
			const float* verts = tessGetVertices(tess);
			const int* vinds = tessGetVertexIndices(tess);
			const int* elems = tessGetElements(tess);
			const int nverts = tessGetVertexCount(tess);
			const int nelems = tessGetElementCount(tess);
			
			// Draw polygons.
			glColor4ub(255,255,255,128);
			for (i = 0; i < nelems; ++i)
			{
				const int* p = &elems[i*nvp];
				glBegin(GL_TRIANGLE_FAN);
				for (j = 0; j < nvp && p[j] != TESS_UNDEF; ++j)
					glVertex2f(verts[p[j]*2], verts[p[j]*2+1]);
				glEnd();
			}
			
			glColor4ub(0,0,0,16);
			for (i = 0; i < nelems; ++i)
			{
				const int* p = &elems[i*nvp];
				glBegin(GL_LINE_LOOP);
				for (j = 0; j < nvp && p[j] != TESS_UNDEF; ++j)
					glVertex2f(verts[p[j]*2], verts[p[j]*2+1]);
				glEnd();
			}
			
			glColor4ub(0,0,0,128);
			glPointSize(3.0f);
			glBegin(GL_POINTS);
			for (i = 0; i < nverts; ++i)
			{
				if (vflags && vflags[vinds[i]])
					glColor4ub(255,0,0,192);
				else
					glColor4ub(0,0,0,128);
				glVertex2f(verts[i*2], verts[i*2+1]);
			}
			glEnd();
			glPointSize(1.0f);
		}
		
		glEnable(GL_DEPTH_TEST);
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	
	if (tess) tessDeleteTess(tess);
	
	if (vflags)
		free(vflags);
	
	svgDelete(bg);	
	svgDelete(fg);	

	glfwTerminate();
	return 0;
}
Example #8
0
int getVertexCount(TESStess* t) {
	return tessGetVertexCount(t->tess);
}