//---------------------------------------------------------- void ofTessellator::tessellateToPolylines( const ofPolyline& src, ofPolyWindingMode polyWindingMode, vector<ofPolyline>& dstpoly, bool bIs2D){ ofPolyline& polyline = const_cast<ofPolyline&>(src); tessAddContour( cacheTess, bIs2D?2:3, &polyline.getVertices()[0], sizeof(ofPoint), polyline.size()); performTessellation( polyWindingMode, dstpoly, bIs2D ); }
//---------------------------------------------------------- void ofTessellator::tessellateToMesh( const ofPolyline& src, ofPolyWindingMode polyWindingMode, ofMesh& dstmesh, bool bIs2D){ ofPolyline& polyline = const_cast<ofPolyline&>(src); tessAddContour( cacheTess, bIs2D?2:3, &polyline.getVertices()[0], sizeof(glm::vec3), polyline.size()); performTessellation( polyWindingMode, dstmesh, bIs2D ); }
//---------------------------------------------------------- void ofTessellator::tessellateToPolylines( const vector<ofPolyline>& src, ofPolyWindingMode polyWindingMode, vector<ofPolyline>& dstpoly, bool bIs2D ) { // pass vertex pointers to GLU tessellator for ( int i=0; i<(int)src.size(); ++i ) { ofPolyline& polyline = const_cast<ofPolyline&>(src[i]); tessAddContour( cacheTess, bIs2D?2:3, &polyline.getVertices()[0].x, sizeof(ofPoint), polyline.size()); } performTessellation( polyWindingMode, dstpoly, bIs2D ); }
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; }
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; }
void ShapeTesselator::add(const std::vector<ci::Vec2f> &polygon) { tessAddContour(tess, 2, polygon.data(), sizeof(float) * 2, polygon.size()); }
void addContour(TESStess* t, int size, const void* pointer, int stride, int count) { tessAddContour(t->tess, size, pointer, stride, count); }
void Triangulator::addPolyLine( const PolyLine2f &polyLine ) { if( polyLine.size() > 0 ) tessAddContour( mTess.get(), 2, &polyLine.getPoints()[0], sizeof(float) * 2, (int)polyLine.size() ); }
void Triangulator::addPath( const Path2d &path, float approximationScale ) { vector<vec2> subdivided = path.subdivide( approximationScale ); tessAddContour( mTess.get(), 2, &subdivided[0], sizeof(float) * 2, (int)subdivided.size() ); }
void Triangulator::addPolyLine( const vec2 *points, size_t numPoints ) { if( numPoints > 0 ) tessAddContour( mTess.get(), 2, &points, sizeof(vec2), (int)numPoints ); }