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;
}
 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;
 }
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;
}
//----------------------------------------------------------
void ofTessellator::performTessellation(ofPolyWindingMode polyWindingMode, vector<ofPolyline>& dstpoly, bool bIs2D ) {
	if (!tessTesselate(cacheTess, polyWindingMode, TESS_BOUNDARY_CONTOURS, 0, 3, 0)){
		ofLogError("ofTessellator") << "performTesselation(): polyline boundary contours tessellation failed, winding mode " << polyWindingMode;
		return;
	}

	const ofDefaultVertexType* verts = (ofDefaultVertexType*)tessGetVertices(cacheTess);
	const TESSindex* elems = tessGetElements(cacheTess);
	const int nelems = tessGetElementCount(cacheTess);
	dstpoly.resize(nelems);
	for (int i = 0; i < nelems; ++i)
	{
			int b = elems[i*2];
			int n = elems[i*2+1];
			dstpoly[i].clear();
			dstpoly[i].addVertices(&verts[b],n);
			dstpoly[i].setClosed(true);
	}
}
//----------------------------------------------------------
void ofTessellator::performTessellation(ofPolyWindingMode polyWindingMode, vector<ofPolyline>& dstpoly, bool bIs2D ) {
	if (!tessTesselate(cacheTess, polyWindingMode, TESS_BOUNDARY_CONTOURS, 0, 3, 0)){
		ofLog(OF_LOG_ERROR,"ofTessellator: tessellation failed");
		return;
	}

	const ofPoint* verts = (ofPoint*)tessGetVertices(cacheTess);
	const TESSindex* elems = tessGetElements(cacheTess);
	const int nelems = tessGetElementCount(cacheTess);
	dstpoly.resize(nelems);
	for (int i = 0; i < nelems; ++i)
	{
			int b = elems[i*2];
			int n = elems[i*2+1];
			dstpoly[i].clear();
			dstpoly[i].addVertexes(&verts[b],n);
			dstpoly[i].setClosed(true);
	}
}
//----------------------------------------------------------
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 );
}
Exemple #8
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;
      

}
Exemple #9
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;
}
Exemple #10
0
const TESSreal* getVertices(TESStess* t) {
	return tessGetVertices(t->tess);
}
void BoatDialog::OnPaintCrossOverChart(wxPaintEvent& event)
{
    wxWindow *window = dynamic_cast<wxWindow*>(event.GetEventObject());
    if(!window)
        return;

    wxGCDC dc(window);
    dc.SetBackgroundMode(wxTRANSPARENT);

    long index = SelectedPolar();
    bool polar = !m_cPlotType->GetSelection();

    int w, h;
    m_CrossOverChart->GetSize( &w, &h);

    dc.SetPen(wxPen(wxColor(0, 0, 0)));
    dc.SetBrush(*wxTRANSPARENT_BRUSH);
    dc.SetTextForeground(wxColour(0, 55, 75));

    bool full = m_cbFullPlot->GetValue();
    double scale;
    int xc = full ? w / 2 : 0;
    if(polar) {
        scale = wxMin(full ? w/2 : w, h/2) / 40.0;
    }
    
    for(double VW = 0; VW < 40; VW += 10) {
        if(polar) {
            dc.DrawCircle(xc, h/2, VW * scale);
            dc.DrawText(wxString::Format(_T("%.0f"), VW), xc, h/2+(int)VW*scale);
        } else {
            int y = h - VW * h / 40;
            dc.DrawLine(0, y, w, y);
            dc.DrawText(wxString::Format(_T("%.0f"), VW), 0, y);
        }
    }

    for(double H = 0; H < 180; H += 10) {
        if(polar) {
            double x = scale*sin(deg2rad(H));
            double y = scale*cos(deg2rad(H));
            if(H < 180)
                dc.DrawLine(xc - x, h/2 + y, xc + x, h/2 - y);

            wxString str = wxString::Format(_T("%.0f"), H);
            int sw, sh;
            dc.GetTextExtent(str, &sw, &sh);
            dc.DrawText(str, xc + .9*x - sw/2, h/2 - .9*y - sh/2);
        } else {
            int x = H * w / 180;
            dc.DrawLine(x, 0, x, h);
            dc.DrawText(wxString::Format(_T("%.0f"), H), x, 0);
        }
    }
    
    wxColour colors[] = {*wxRED, *wxGREEN, *wxBLUE, *wxCYAN, *wxYELLOW,
                         wxColour(255, 0, 255)};
    int c = 0;
    for(unsigned int i=0; i<m_Boat.Polars.size(); i++) {
        bool bold = i == index;

//        dc.SetPen(wxPen(colors[c], bold ? 1 : 3));
        dc.SetPen(*wxTRANSPARENT_PEN);
        dc.SetBrush(wxColour(colors[c].Red(),
                             colors[c].Green(),
                             colors[c].Blue(),
                             bold ? 230 : 60));
        if(++c == (sizeof colors) / (sizeof *colors))
            c = 0;

        bool tri = true;
        TESStesselator *tess = m_Boat.Polars[i].CrossOverRegion.Tesselate(tri);

        if(!tess)
            continue;
          
        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.
        for (int i = 0; i < nelems; ++i)
        {
            if(tri) {
                const int* p = &elems[i*3];
                wxPoint points[3];
                for (unsigned j = 0; j < 3 && p[j] != TESS_UNDEF; ++j) {
                    double H = verts[p[j]*2+0];
                    double VW = verts[p[j]*2+1];
                    points[j] = wxPoint(H * w / 180, h - VW * h / 40);
                }
                if(polar) {
                    int count[3] = {CalcPolarPoints(points[0], points[1]),
                                    CalcPolarPoints(points[1], points[2]),
                                    CalcPolarPoints(points[2], points[0])};
                    wxPoint *pts = new wxPoint[count[0] + count[1] + count[2]];
                    int c = 0;
                    for(int j = 0; j<3; j++) {
                        int jp1 = j+1 == 3 ? 0 : j+1;
                        for(int k=0; k<count[j]; k++) {
                            double d = (double)k / count[j];
                            double px = points[j].x * (1-d) + points[jp1].x * d;
                            double py = points[j].y * (1-d) + points[jp1].y * d;
                            double H = px / w * 180;
                            double VW = (h - py) / h * 40;
                            pts[c++] = wxPoint(xc + scale*VW*sin(deg2rad(H)),
                                               h/2 - scale*VW*cos(deg2rad(H)));
                        }
                    }
                    dc.DrawPolygon(c, pts);
                    if(full) {
                        for(int j = 0; j<c; j++)
                            pts[j].x = 2*xc - pts[j].x;
                        dc.DrawPolygon(c, pts);
                    }
                    delete [] pts;
                } else {
                    dc.DrawPolygon(3, points);
                }
            } else {
                int b = elems[i*2];
                int n = elems[i*2+1];

                wxPoint pl;
                for(int j = 0; j<=n; j++) {
                    int k = j < n ? j : 0;
                    float H = verts[2*(b + k)+0], VW = verts[2*(b + k)+1];
                    wxPoint p0;
                    if(polar)
                        p0 = wxPoint(xc + scale*VW*sin(deg2rad(H)),
                                            h/2 - scale*VW*cos(deg2rad(H)));
                    else
                        p0 = wxPoint(H * w / 180, h - VW * h / 40);

                    if(j > 0)
                        dc.DrawLine(pl, p0);
                    pl = p0;
                }
            }
        }

        tessDeleteTess(tess);
    }
}