void EngineTessellator::Run(double windingRule, bool ccw) { //make sure the last polygon is inserted if (current.size()) { polygons.push_back(current); current.clear(); } tessellate_t* t=new tessellate_t; t->ccw = ccw; t->tess = gluNewTess(); DebugAssert(t->tess); gluTessCallback( t->tess, GLU_TESS_ERROR ,(void (CALLBACK*)())callback_error); gluTessCallback( t->tess, GLU_TESS_VERTEX_DATA ,(void (CALLBACK*)())callback_vertex); gluTessCallback( t->tess, GLU_TESS_BEGIN_DATA ,(void (CALLBACK*)())callback_begin); gluTessCallback( t->tess, GLU_TESS_END_DATA ,(void (CALLBACK*)())callback_end); gluTessCallback( t->tess, GLU_TESS_COMBINE_DATA,(void (CALLBACK*)())callback_combine); gluTessProperty( t->tess, GLU_TESS_WINDING_RULE, windingRule ); gluTessProperty( t->tess, GLU_TESS_BOUNDARY_ONLY,GL_FALSE); for (polygon_set_t::const_iterator IT=polygons.begin();IT!=polygons.end();IT++) { const polygon_t& polygon=*IT; gluTessBeginPolygon(t->tess,t); for (polygon_t::const_iterator JT=polygon.begin();JT!=polygon.end();JT++) { const contour_t& contour=*JT; gluTessBeginContour(t->tess); for (int V=0;V<(int)contour.size();V++) { double* v=new double[3]; t->to_dealloc.push_back(v); v[0]=contour[V].x; v[1]=contour[V].y; v[2]=contour[V].z; gluTessVertex(t->tess,v,v); } gluTessEndContour(t->tess); } gluTessEndPolygon(t->tess); } this->m_raw_triangles=std::vector<Vec3f>(); for (int I=0;I<(int)t->result.size();I+=3) { Vec3f& v0=t->result[I+0];this->m_raw_triangles.push_back(Vec3f(v0.x,v0.y,v0.z)); Vec3f& v1=t->result[I+1];this->m_raw_triangles.push_back(Vec3f(v1.x,v1.y,v1.z)); Vec3f& v2=t->result[I+2];this->m_raw_triangles.push_back(Vec3f(v2.x,v2.y,v2.z)); } //the projection matrix Mat4f T=Mat4f::getProjectionMatrix(t->result); Mat4f Ti=T.invert(); this->m_matrix=Mat4f(Ti); //the graph m_g.reset(new Graph(2)); for (int I=0;I<(int)t->result.size();I+=3) { Vec3f _v0=T * t->result[I+0]; Vec3f _v1=T * t->result[I+1]; Vec3f _v2=T * t->result[I+2]; //after the projection they should have one less coordinate (which should be v.z) Vecf v0=Vecf(1.0f,_v0.x,_v0.y); Vecf v1=Vecf(1.0f,_v1.x,_v1.y); Vecf v2=Vecf(1.0f,_v2.x,_v2.y); //*** vertices *** unsigned int N0=m_g->findVertex(v0); unsigned int N1=m_g->findVertex(v1); unsigned int N2=m_g->findVertex(v2); if (!N0) N0=m_g->addVertex(v0); if (!N1) N1=m_g->addVertex(v1); if (!N2) N2=m_g->addVertex(v2); //*** edges *** unsigned int E01=0,E12=0,E20=0; E01=m_g->findFirstCommonNode(N0,N1,Graph::DIRECTION_UP); E12=m_g->findFirstCommonNode(N1,N2,Graph::DIRECTION_UP); E20=m_g->findFirstCommonNode(N2,N0,Graph::DIRECTION_UP); if (!E01) {E01=m_g->addEdge(N0,N1);memcpy(m_g->getGeometry(E01,true),m_g->getFittingPlane(E01).mem,sizeof(float)*3);} if (!E12) {E12=m_g->addEdge(N1,N2);memcpy(m_g->getGeometry(E12,true),m_g->getFittingPlane(E12).mem,sizeof(float)*3);} if (!E20) {E20=m_g->addEdge(N2,N0);memcpy(m_g->getGeometry(E20,true),m_g->getFittingPlane(E20).mem,sizeof(float)*3);} //*** triangle *** unsigned int T=0; if (!T) {T=m_g->findFirstCommonNode(E01,E12,Graph::DIRECTION_UP);DebugAssert(!T || m_g->findArch(E20,T,Graph::DIRECTION_UP)!=0);} if (!T) {T=m_g->findFirstCommonNode(E12,E20,Graph::DIRECTION_UP);DebugAssert(!T || m_g->findArch(E01,T,Graph::DIRECTION_UP)!=0);} if (!T) {T=m_g->findFirstCommonNode(E20,E01,Graph::DIRECTION_UP);DebugAssert(!T || m_g->findArch(E12,T,Graph::DIRECTION_UP)!=0);} //if the triangle does not exists if (!T) { unsigned int T=m_g->addNode(2); m_g->addArch(E01,T); m_g->addArch(E12,T); m_g->addArch(E20,T); m_g->addArch(T,N0);//double connectivity m_g->addArch(T,N1); m_g->addArch(T,N2); } } //deallocate tessellator gluDeleteTess(t->tess); for (int i=0;i<(int)t->to_dealloc.size();i++) delete [] t->to_dealloc[i]; delete t; }
void GLAPIENTRY gluEndPolygon( GLUtesselator *tess ) { gluTessEndContour( tess ); gluTessEndPolygon( tess ); }
void ProtoTessellator::endPolygon() { gluTessEndPolygon(tesselator); }
void init (void) { int i; GLUtesselator *tobj; GLdouble rect[4][3] = {50.0, 50.0, 0.0, 200.0, 50.0, 0.0, 200.0, 200.0, 0.0, 50.0, 200.0, 0.0}; GLdouble tri[3][3] = {75.0, 75.0, 0.0, 125.0, 175.0, 0.0, 175.0, 75.0, 0.0}; GLdouble star[5][6] = {250.0, 50.0, 0.0, 1.0, 0.0, 1.0, 325.0, 200.0, 0.0, 1.0, 1.0, 0.0, 400.0, 50.0, 0.0, 0.0, 1.0, 1.0, 250.0, 150.0, 0.0, 1.0, 0.0, 0.0, 400.0, 150.0, 0.0, 0.0, 1.0, 0.0}; glClearColor(0.0, 0.0, 0.0, 0.0); startList = glGenLists(2); tobj = gluNewTess(); gluTessCallback(tobj, GLU_TESS_VERTEX, glVertex3dv); gluTessCallback(tobj, GLU_TESS_BEGIN, beginCallback); gluTessCallback(tobj, GLU_TESS_END, endCallback); gluTessCallback(tobj, GLU_TESS_ERROR, errorCallback); /* rectangle with triangular hole inside */ glNewList(startList, GL_COMPILE); glShadeModel(GL_FLAT); printf("a"); gluTessBeginPolygon(tobj, NULL); printf("b"); gluTessBeginContour(tobj); printf("c"); gluTessVertex(tobj, rect[0], rect[0]); gluTessVertex(tobj, rect[1], rect[1]); gluTessVertex(tobj, rect[2], rect[2]); gluTessVertex(tobj, rect[3], rect[3]); gluTessEndContour(tobj); printf(" d"); gluTessBeginContour(tobj); printf("e"); gluTessVertex(tobj, tri[0], tri[0]); gluTessVertex(tobj, tri[1], tri[1]); gluTessVertex(tobj, tri[2], tri[2]); printf("f"); gluTessEndContour(tobj); printf("g"); gluTessEndPolygon(tobj); printf(" h"); glEndList(); gluTessCallback(tobj, GLU_TESS_VERTEX, vertexCallback); gluTessCallback(tobj, GLU_TESS_BEGIN, beginCallback); gluTessCallback(tobj, GLU_TESS_END, endCallback); gluTessCallback(tobj, GLU_TESS_ERROR, errorCallback); gluTessCallback(tobj, GLU_TESS_COMBINE, combineCallback); /* smooth shaded, self-intersecting star */ glNewList(startList + 1, GL_COMPILE); glShadeModel(GL_SMOOTH); gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE); gluTessBeginPolygon(tobj, NULL); gluTessBeginContour(tobj); gluTessVertex(tobj, star[0], star[0]); gluTessVertex(tobj, star[1], star[1]); gluTessVertex(tobj, star[2], star[2]); gluTessVertex(tobj, star[3], star[3]); gluTessVertex(tobj, star[4], star[4]); gluTessEndContour(tobj); gluTessEndPolygon(tobj); glPushMatrix(); glTranslatef(-100.0, 200.0, 0.0); glBegin(GL_POLYGON); for (i=0; i<5; i++) { glColor3f(star[i][3], star[i][4], star[i][5]); glVertex3f(star[i][0], star[i][1], star[i][2]); } glEnd(); glColor3f(1,1,1); glBegin(GL_LINE_STRIP); glVertex3f(100, 100, 0); glVertex3f(100, -100, 0); glVertex3f(-100, 0, 0); glVertex3f(100, 0, 0); glEnd(); glPopMatrix(); glEndList(); gluDeleteTess(tobj); }
PsychError SCREENFillPoly(void) { PsychColorType color; PsychWindowRecordType *windowRecord; double whiteValue; int i, mSize, nSize, pSize; psych_bool isArgThere; double *pointList; double isConvex; int j,k; int flag; double z; combinerCacheSlot = 0; combinerCacheSize = 0; combinerCache = NULL; //all sub functions should have these two lines PsychPushHelp(useString, synopsisString,seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; //check for superfluous arguments PsychErrorExit(PsychCapNumInputArgs(4)); //The maximum number of inputs PsychErrorExit(PsychCapNumOutputArgs(0)); //The maximum number of outputs //get the window record from the window record argument and get info from the window record PsychAllocInWindowRecordArg(1, kPsychArgRequired, &windowRecord); //Get the color argument or use the default, then coerce to the form determened by the window depth. isArgThere=PsychCopyInColorArg(2, FALSE, &color); if(!isArgThere){ whiteValue=PsychGetWhiteValueFromWindow(windowRecord); PsychLoadColorStruct(&color, kPsychIndexColor, whiteValue ); //index mode will coerce to any other. } PsychCoerceColorMode( &color); //get the list of pairs and validate. PsychAllocInDoubleMatArg(3, kPsychArgRequired, &mSize, &nSize, &pSize, &pointList); if(nSize!=2) PsychErrorExitMsg(PsychError_user, "Width of pointList must be 2"); if(mSize<3) PsychErrorExitMsg(PsychError_user, "Polygons must consist of at least 3 points; M dimension of pointList was < 3!"); if(pSize>1) PsychErrorExitMsg(PsychError_user, "pointList must be a 2D matrix, not a 3D matrix!"); isConvex = -1; PsychCopyInDoubleArg(4, kPsychArgOptional, &isConvex); // On non-OpenGL1/2 we always force isConvex to zero, so the GLU tesselator is // always used. This because the tesselator only emits GL_TRIANGLES and GL_TRIANGLE_STRIP // and GL_TRIANGLE_FANS primitives which are supported on all current OpenGL API's, whereas // or "classic" fast-path needs GL_POLYGONS, which are only supported on classic OpenGL1/2: if (!PsychIsGLClassic(windowRecord)) isConvex = 0; // Enable this windowRecords framebuffer as current drawingtarget: PsychSetDrawingTarget(windowRecord); // Set default drawshader: PsychSetShader(windowRecord, -1); PsychUpdateAlphaBlendingFactorLazily(windowRecord); PsychSetGLColor(&color, windowRecord); ///////// Test for convexity //////// // This algorithm checks, if the polygon is definitely convex, or not. // We take the slow-path, if polygon is non-convex or if we can't prove // that it is convex. // // Algorithm adapted from: http://astronomy.swin.edu.au/~pbourke/geometry/clockwise/ // Which was written by Paul Bourke, 1998. // // -> This webpage explains the mathematical principle behind the test and provides // a C-Source file which has been adapted for use here. // if (isConvex == -1) { flag = 0; for (i=0; i < mSize; i++) { j = (i + 1) % mSize; k = (i + 2) % mSize; z = (pointList[j] - pointList[i]) * (pointList[k+mSize] - pointList[j+mSize]); z -= (pointList[j+mSize] - pointList[i+mSize]) * (pointList[k] - pointList[j]); if (z < 0) { flag |= 1; } else if (z > 0) { flag |= 2; } if (flag == 3) { // This is definitely a CONCAVE polygon --> not Convex --> Take slow but safe path. break; } } if (flag!=0 && flag!=3) { // This is a convex polygon --> Take fast path. isConvex = 1; } else { // This is a complex polygon --> can't determine if it is convex or not --> Take slow but safe path. isConvex = 0; } } ////// Switch between fast path and slow path, depending on convexity of polygon: if (isConvex > 0) { // Convex, non-self-intersecting polygon - Take the fast-path: glBegin(GL_POLYGON); for(i=0;i<mSize;i++) glVertex2d((GLdouble)pointList[i], (GLdouble)pointList[i+mSize]); glEnd(); } else { // Possibly concave and/or self-intersecting polygon - At least we couldn't prove it is convex. // Take the slow, but safe, path using GLU-Tesselators to break it up into a couple of convex, simple // polygons: // Create and initialize a new GLU-Tesselator object, if needed: if (NULL == tess) { // Create tesselator: tess = gluNewTess(); if (NULL == tess) PsychErrorExitMsg(PsychError_outofMemory, "Out of memory condition in Screen('FillPoly')! Not enough space."); // Assign our callback-functions: gluTessCallback(tess, GLU_TESS_BEGIN, GLUTESSCBCASTER PsychtcbBegin); gluTessCallback(tess, GLU_TESS_VERTEX, GLUTESSCBCASTER PsychtcbVertex); gluTessCallback(tess, GLU_TESS_END, GLUTESSCBCASTER PsychtcbEnd); gluTessCallback(tess, GLU_TESS_COMBINE, GLUTESSCBCASTER PsychtcbCombine); // Define all tesselated polygons to lie in the x-y plane: gluTessNormal(tess, 0, 0, 1); } // We need to hold the values in a temporary array: if (tempvsize < mSize) { tempvsize = ((mSize / 1000) + 1) * 1000; tempv = (double*) realloc((void*) tempv, sizeof(double) * 3 * tempvsize); if (NULL == tempv) PsychErrorExitMsg(PsychError_outofMemory, "Out of memory condition in Screen('FillPoly')! Not enough space."); } // Now submit our Polygon for tesselation: gluTessBeginPolygon(tess, NULL); gluTessBeginContour(tess); for(i=0; i < mSize; i++) { tempv[i*3]=(GLdouble) pointList[i]; tempv[i*3+1]=(GLdouble) pointList[i+mSize]; tempv[i*3+2]=0; gluTessVertex(tess, (GLdouble*) &(tempv[i*3]), (void*) &(tempv[i*3])); } // Process, finalize and render it by calling our callback-functions: gluTessEndContour(tess); gluTessEndPolygon (tess); // Done with drawing the filled polygon. (Slow-Path) } // Mark end of drawing op. This is needed for single buffered drawing: PsychFlushGL(windowRecord); // printf("CombinerCalls %i out of %i allocated.\n", combinerCacheSlot, combinerCacheSize); return(PsychError_none); }
void XMGPolygon::SetCoordArray ( const XMGVector2X* src_arr_coord, XMGTexUnit unit, GLuint src_idx_shape, GLuint src_idx_facet ) { XMGPolygonImpl* impl = (XMGPolygonImpl *) m_impl; XMGRenderImpl* impl_parent = (XMGRenderImpl *) XMGRender::m_impl; XMGTess* data; XMGShape* shape; XMGFacet* facet; GLuint idx_tess; GLuint idx_shape; GLuint idx_facet; GLuint idx_vertex; GLuint num_shape; GLuint num_facet; GLuint num_vertex; GLuint off_src; XMGVector2F* farr_coord; XMGVector2X* xarr_coord; XMGRender::SetCoordArray ( src_arr_coord, unit, src_idx_shape, src_idx_facet ); if ( impl_parent->m_has_face[ 0 ] == XMG_FALSE && impl_parent->m_has_face[ 1 ] ) { return; } if ( src_idx_facet != XMG_FACET_ALL ) { shape = impl_parent->m_vec_shape[ src_idx_facet ]; facet = shape->m_vec_facet[ src_idx_facet ]; if ( facet->m_vec_contour.size ( ) == 0 ) { return; } } off_src = 0; for ( impl_parent->RangeArray ( src_idx_shape, impl_parent->m_vec_shape.size ( ), idx_shape, num_shape ); idx_shape < num_shape; idx_shape++ ) { shape = impl_parent->m_vec_shape[ idx_shape ]; for ( impl_parent->RangeArray ( src_idx_facet, shape->m_vec_facet.size ( ), idx_facet, num_facet ); idx_facet < num_facet; idx_facet++ ) { facet = shape->m_vec_facet[ idx_facet ]; if ( idx_facet < 2 ) { switch ( impl_parent->m_geo_type ) { case XMG_GEO_CONE : case XMG_GEO_CWALL : idx_tess = 1; break; default : idx_tess = idx_facet; break; } if ( impl->m_tess[ idx_tess ] ) { data = impl->m_data[ idx_tess ][ idx_shape ]; data->Init ( XMG_TESS_COORD ); gluTessBeginPolygon ( impl->m_tess[ idx_tess ], (GLvoid *) data ); gluTessBeginContour ( impl->m_tess[ idx_tess ] ); for ( idx_vertex = 0, num_vertex = shape->m_num_basic; idx_vertex < num_vertex; idx_vertex++ ) { data->m_arr_vertex[ idx_vertex * 8 + 6 ] = XMG_X2F ( src_arr_coord[ off_src + idx_vertex ].m_x ); data->m_arr_vertex[ idx_vertex * 8 + 7 ] = XMG_X2F ( src_arr_coord[ off_src + idx_vertex ].m_y ); if ( shape->m_idx_hole != 0 && shape->m_idx_hole == idx_vertex ) { gluNextContour ( impl->m_tess[ idx_tess ], GLU_INTERIOR ); } gluTessVertex ( impl->m_tess[ idx_tess ], &data->m_arr_vertex[ idx_vertex * 8 ], &data->m_arr_vertex[ idx_vertex * 8 ] ); } gluTessEndContour ( impl->m_tess[ idx_tess ] ); gluTessEndPolygon ( impl->m_tess[ idx_tess ] ); if ( impl_parent->m_type_coords[ unit ] == XMG_TYPE_FLOAT ) { XMGAssert ( farr_coord = (XMGVector2F *) kdMalloc ( sizeof ( XMGVector2F ) * facet->m_num_ext ) ); for ( idx_vertex = 0, num_vertex = facet->m_num_ext; idx_vertex < num_vertex; idx_vertex++ ) { farr_coord[ idx_vertex ] = data->m_vec_coord[ idx_vertex ]; } impl_parent->SetBuffer ( impl_parent->m_id_coords[ unit ], farr_coord, sizeof ( XMGVector2F ) * facet->m_off_ext, sizeof ( XMGVector2F ) * facet->m_num_ext ); kdFree ( farr_coord ); } else { XMGAssert ( xarr_coord = (XMGVector2X *) kdMalloc ( sizeof ( XMGVector2X ) * facet->m_num_ext ) ); for ( idx_vertex = 0, num_vertex = facet->m_num_ext; idx_vertex < num_vertex; idx_vertex++ ) { xarr_coord[ idx_vertex ] = data->m_vec_coord[ idx_vertex ]; } impl_parent->SetBuffer ( impl_parent->m_id_coords[ unit ], xarr_coord, sizeof ( XMGVector2X ) * facet->m_off_ext, sizeof ( XMGVector2X ) * facet->m_num_ext ); kdFree ( xarr_coord ); } } } off_src += facet->m_num_vertex; } } }
void tesselateComplexPolygon(Array<Vector3>& input, Array<Triangle>& output) { // Use the GLU triangulator to do the hard work. static GLUtriangulatorObj* tobj = NULL; if (tobj == NULL) { tobj = gluNewTess(); #if defined(G3D_OSX) #define CAST(x) reinterpret_cast<void (*)(...)>(x) #elif defined(G3D_LINUX) #define CAST(x) reinterpret_cast<void (*)()>(x) #else #define CAST(x) reinterpret_cast<void (__stdcall *)(void)>(x) #endif gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, CAST(_tesselateBegin)); gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, CAST(_tesselateVertex)); gluTessCallback(tobj, GLU_TESS_END_DATA, CAST(_tesselateEnd)); gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, CAST(_tesselateCombine)); gluTessCallback(tobj, GLU_TESS_ERROR, CAST(_tesselateError)); gluTessProperty(tobj, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); #undef CAST } double v[3]; int i; TessData data; gluTessBeginPolygon(tobj, &data); gluTessBeginContour(tobj); for (i = 0; i < input.size(); ++i) { // Expand the input to double precision v[0] = input[i].x; v[1] = input[i].y; v[2] = input[i].z; gluTessVertex(tobj, v, &(input[i])); } gluTessEndContour(tobj); gluTessEndPolygon(tobj); for (int p = 0; p < data.primitive.size(); ++p) { const TessData::Primitive& primitive = data.primitive[p]; // Turn the tesselated primitive into triangles switch (primitive.primitiveType) { case GL_TRIANGLES: // This is easy, just walk through them in order. for (i = 0; i < primitive.vertex.size(); i += 3) { output.append(Triangle(primitive.vertex[i], primitive.vertex[i + 1], primitive.vertex[i + 2])); } break; case GL_TRIANGLE_FAN: { // Make a triangle between every pair of vertices and the 1st vertex for (i = 1; i < primitive.vertex.size() - 1; ++i) { output.append(Triangle(primitive.vertex[0], primitive.vertex[i], primitive.vertex[i + 1])); } } break; case GL_TRIANGLE_STRIP: for (i = 0; i < primitive.vertex.size() - 3; i += 2) { output.append(Triangle(primitive.vertex[i], primitive.vertex[i + 1], primitive.vertex[i + 2])); output.append(Triangle(primitive.vertex[i + 2], primitive.vertex[i + 1], primitive.vertex[i + 3])); } if (i < primitive.vertex.size() - 2) { output.append(Triangle(primitive.vertex[i], primitive.vertex[i + 1], primitive.vertex[i + 2])); } break; default: //debugAssertM(false, GLenumToString(primitive.primitiveType)); // Ignore other primitives ; } } }
/* * endPolygon */ void TessellatePolygon::endPolygon(void) { gluTessEndPolygon(tessellationObject); } // end endPolygon()
/* draw all solid polygons found in aPolysList * aZpos = z position in board internal units * aThickness = thickness in board internal units * If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos. * If aThickness > 0, a solid object is drawn. * The top side is located at aZpos + aThickness / 2 * The bottom side is located at aZpos - aThickness / 2 */ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList, int aZpos, int aThickness, double aBiuTo3DUnits, bool aUseTextures ) { // for Tess callback functions: s_biuTo3Dunits = aBiuTo3DUnits; s_useTextures = aUseTextures; GLUtesselator* tess = gluNewTess(); gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )tessBeginCB ); gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )tessEndCB ); gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )tessErrorCB ); gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )tessCPolyPt2Vertex ); GLdouble v_data[3]; double zpos = ( aZpos + (aThickness / 2.0) ) * aBiuTo3DUnits; s_currentZpos = zpos; // for Tess callback functions v_data[2] = aZpos + (aThickness / 2.0); // Set normal toward positive Z axis, for a solid object on the top side if( aThickness ) SetNormalZpos(); // gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); // Draw solid areas contained in this list CPOLYGONS_LIST polylist = aPolysList; // temporary copy for gluTessVertex int startContour; for( int side = 0; side < 2; side++ ) { startContour = 1; for( unsigned ii = 0; ii < polylist.GetCornersCount(); ii++ ) { if( startContour == 1 ) { gluTessBeginPolygon( tess, NULL ); gluTessBeginContour( tess ); startContour = 0; } // https://www.opengl.org/sdk/docs/man2/xhtml/gluTessNormal.xml gluTessNormal( tess, 0.0, 0.0, 0.0 ); v_data[0] = polylist.GetX( ii ) * aBiuTo3DUnits; v_data[1] = -polylist.GetY( ii ) * aBiuTo3DUnits; // gluTessVertex store pointers on data, not data, so do not store // different corners values in a temporary variable // but send pointer on each CPolyPt value in polylist // before calling gluDeleteTess gluTessVertex( tess, v_data, &polylist[ii] ); if( polylist.IsEndContour( ii ) ) { gluTessEndContour( tess ); gluTessEndPolygon( tess ); startContour = 1; } } if( aThickness == 0 ) break; // Prepare the bottom side of solid areas zpos = ( aZpos - (aThickness / 2.0) ) * aBiuTo3DUnits; s_currentZpos = zpos; // for Tess callback functions v_data[2] = zpos; // Set normal toward negative Z axis, for a solid object on bottom side SetNormalZneg(); } if( startContour == 0 ) { gluTessEndContour( tess ); gluTessEndPolygon( tess ); } gluDeleteTess( tess ); if( aThickness == 0 ) { return; } // Build the 3D data : vertical side Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2.0), false, aBiuTo3DUnits ); }
void Tessel::EndPolygon() { gluTessEndContour(obj); gluTessEndPolygon(obj); }
void DVRClipper::clipSlice( DVRVolume *volume, DVRSlice &unclippedSlice, const Vec3f &slicingNormal, Real32 dist2RefPlane, DVRRenderSlice &clippedSlice) { const Vec3f &texScale = unclippedSlice.getTextureScale (); const Vec3f &texTranslate = unclippedSlice.getTextureTranslate(); // get clip objects DVRClipObjectsPtr clipObjects = DVRVOLUME_PARAMETER(volume, DVRClipObjects); // nothing to clip with? if(clipObjects == NullFC) { DVRRenderSlicePrimitive *newPrimitive = new DVRRenderSlicePrimitive(); newPrimitive->type = GL_TRIANGLE_FAN; for(UInt32 i = 0; i < unclippedSlice.getVertexCount(); i++) { UInt32 idx = (6+numAddPerVertexAttr)*i; sliceVertexData[idx ] = unclippedSlice.getVertex(i).getValues()[0]; sliceVertexData[idx + 1] = unclippedSlice.getVertex(i).getValues()[1]; sliceVertexData[idx + 2] = unclippedSlice.getVertex(i).getValues()[2]; // set (standard) texture coordinates sliceVertexData[idx + 3] = texScale[0] * unclippedSlice.getVertex(i).getValues()[0] + texTranslate[0]; sliceVertexData[idx + 4] = texScale[1] * unclippedSlice.getVertex(i).getValues()[1] + texTranslate[1]; sliceVertexData[idx + 5] = texScale[2] * unclippedSlice.getVertex(i).getValues()[2] + texTranslate[2]; newPrimitive->vertices.push_back(&sliceVertexData[idx]); } clippedSlice.push_back(newPrimitive); return; } if(!hasTesselatorSupport) return; // render colored contours only (usefull for debugging) if(clipObjects->getDoContours()) { glDisable(GL_TEXTURE ); glDisable(GL_LIGHTING ); glBegin (GL_LINE_STRIP); { int col = 0; for(UInt32 i = 0; i < unclippedSlice.getVertexCount(); i++) { glColor3f(col % 3 == 0 ? 1.0f : 0.0f, col % 3 == 1 ? 1.0f : 0.0f, col % 3 == 2 ? 1.0f : 0.0f); col++; glVertex3fv(unclippedSlice.getVertex(i).getValues()); } } glEnd(); bool clipAwayOutside = clipObjects->getClipMode() == DVRClipObjects::Difference; for(UInt32 i = 0; i < clipObjects->count(); i++) { // get i-th clip object DVRClipGeometryPtr clipObject = clipObjects->get(i); // compute the contours of the triangles intersecting the // current slice const DVRTriangleList &contours = clipObject->getContours(dist2RefPlane, !clipAwayOutside, slicingNormal); if(!contours.empty()) { DVRTriangle *current; DVRTriangle *contourStart; // iterate over all contours DVRTriangleList::const_iterator contoursIt; for(contoursIt = contours.begin(); contoursIt != contours.end (); contoursIt++) { contourStart = current = *contoursIt; glBegin(GL_LINE_STRIP); { int col = 0; // iterate over all triangles in the current contour do { glColor3f(col % 3 == 0 ? 1.0f : 0.0f, col % 3 == 1 ? 1.0f : 0.0f, col % 3 == 2 ? 1.0f : 0.0f); col++; glVertex3dv(current->cutPoint); current = current->contourNeighbour; } while(current!= contourStart); } glEnd(); } } } glEnable(GL_TEXTURE ); glEnable(GL_LIGHTING); } else { // tesselate and render the clipped slices // set the slice normal for tesselation gluTessNormal(myTess, slicingNormal[0], slicingNormal[1], slicingNormal[2]); clippedSlice.clear(); gluTessBeginPolygon(myTess, &clippedSlice); // set the slice's base contour gluTessBeginContour(myTess); for(UInt32 i = 0; i < unclippedSlice.getVertexCount(); i++) { UInt32 idx = (6 + numAddPerVertexAttr) * i; sliceVertexData[idx ] = unclippedSlice.getVertex(i).getValues()[0]; sliceVertexData[idx + 1] = unclippedSlice.getVertex(i).getValues()[1]; sliceVertexData[idx + 2] = unclippedSlice.getVertex(i).getValues()[2]; // set (standard) texture coordinates sliceVertexData[idx + 3] = texScale[0] * unclippedSlice.getVertex(i).getValues()[0] + texTranslate[0]; sliceVertexData[idx + 4] = texScale[1] * unclippedSlice.getVertex(i).getValues()[1] + texTranslate[1]; sliceVertexData[idx + 5] = texScale[2] * unclippedSlice.getVertex(i).getValues()[2] + texTranslate[2]; gluTessVertex(myTess, &sliceVertexData[idx], &sliceVertexData[idx]); } gluTessEndContour(myTess); // set contours of clip objects if(clipObjects->getClipMode() != DVRClipObjects::Off) { // get clip mode bool clipAwayOutside = clipObjects->getClipMode() == DVRClipObjects::Difference; // add the contours of the intersections of the clip geometries // with the slice for(UInt32 i = 0; i < clipObjects->count(); i++) { // get i-th clip object DVRClipGeometryPtr clipObject = clipObjects->get(i); // compute the contours of the triangles intersecting // the current slice const DVRTriangleList &contours = clipObject->getContours( dist2RefPlane, !clipAwayOutside, slicingNormal); if(!contours.empty()) { DVRTriangle *current; DVRTriangle *contourStart; // iterate over all contours DVRTriangleList::const_iterator contoursIt; for(contoursIt = contours.begin(); contoursIt != contours.end (); contoursIt++) { contourStart = current = *contoursIt; // start new contour gluTessBeginContour(myTess); // iterate over all triangles in the current contour do { // set (standard) texture coordinates current->cutPoint[3] = texScale[0] * current->cutPoint[0] + texTranslate[0]; current->cutPoint[4] = texScale[1] * current->cutPoint[1] + texTranslate[1]; current->cutPoint[5] = texScale[2] * current->cutPoint[2] + texTranslate[2]; if(!current->cutPoint) std::cerr << "WTF: cutPoint is NULL" << std::endl; gluTessVertex(myTess, current->cutPoint, current->cutPoint); current = current->contourNeighbour; } while(current != contourStart); gluTessEndContour(myTess); } } } } gluTessEndPolygon(myTess); } }
void Tesselator::compute() { gluTessEndPolygon( _tobj ); }
int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller) { ErlDrvBinary* bin; int i; GLdouble* new_vertices; int *vertices; int num_vertices; GLdouble *n; int n_pos, AP, res; num_vertices = * (int *) buff; buff += 8; /* Align */ n = (double *) buff; buff += 8*3; bin = driver_alloc_binary(num_vertices*6*sizeof(GLdouble)); new_vertices = tess_coords = (double *) bin->orig_bytes; memcpy(tess_coords,buff,num_vertices*3*sizeof(GLdouble)); tess_alloc_vertex = tess_coords + num_vertices*3; #if 0 fprintf(stderr, "n=%d\r\n", num_vertices); #endif vertices = (int *) driver_alloc(sizeof(int) * 16*num_vertices); tess_vertices = vertices; gluTessNormal(tess, n[0], n[1], n[2]); gluTessBeginPolygon(tess, 0); gluTessBeginContour(tess); for (i = 0; i < num_vertices; i++) { gluTessVertex(tess, tess_coords+3*i, tess_coords+3*i); } gluTessEndContour(tess); gluTessEndPolygon(tess); n_pos = (tess_vertices - vertices); AP = 0; ErlDrvTermData *rt; rt = (ErlDrvTermData *) driver_alloc(sizeof(ErlDrvTermData) * (13+n_pos*2)); rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_"); for(i=0; i < n_pos; i++) { rt[AP++] = ERL_DRV_INT; rt[AP++] = (int) vertices[i]; }; rt[AP++] = ERL_DRV_NIL; rt[AP++] = ERL_DRV_LIST; rt[AP++] = n_pos+1; rt[AP++] = ERL_DRV_BINARY; rt[AP++] = (ErlDrvTermData) bin; rt[AP++] = (tess_alloc_vertex-new_vertices)*sizeof(GLdouble); rt[AP++] = 0; rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Return tuple {list, Bin} rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Result tuple res = driver_send_term(port,caller,rt,AP); /* fprintf(stderr, "List %d: %d %d %d \r\n", */ /* res, */ /* n_pos, */ /* (tess_alloc_vertex-new_vertices)*sizeof(GLdouble), */ /* num_vertices*6*sizeof(GLdouble)); */ driver_free_binary(bin); driver_free(vertices); driver_free(rt); return 0; }
void __stdcall gluEndPolygon( GLUtesselator *tess ) { gluTessEndContour( tess ); gluTessEndPolygon( tess ); }
void init_scene(int width, int height) { GLubyte* tex; GLUtesselator* tobj; GLfloat rect[4][3]={ {50.0f, 50.0f, 0.0f}, {200.0f, 50.0f, 0.0f}, {200.0f, 200.0f, 0.0f}, {50.0f, 200.0f, 0.0f} }; GLfloat tri[3][3]={ {75.0f, 75.0f, 0.0f}, {125.0f, 175.0f, 0.0f}, {175.0f, 75.0f, 0.0f} }; GLfloat star[5][6]={ {250.0f, 50.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {325.0f, 200.0f, 0.0f, 1.0f, 1.0f, 0.0f}, {400.0f, 50.0f, 0.0f, 0.0f, 1.0f, 1.0f}, {250.0f, 150.0f, 0.0f, 1.0f, 0.0f, 0.0f}, {400.0f, 150.0f, 0.0f, 0.0f, 1.0f, 0.0f} }; GLfloat triangle[9][8]={ {450.0f, 50.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {525.0f, 200.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f}, {600.0f, 50.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f}, {500.0f, 50.0f, 0.0f, 0.666f, 0.000f, 0.333f, 0.333f, 0.000f}, {550.0f, 150.0f, 0.0f, 0.666f, 0.666f, 1.000f, 0.666f, 0.666f}, {500.0f, 150.0f, 0.0f, 1.000f, 0.666f, 0.666f, 0.333f, 0.666f}, {550.0f, 50.0f, 0.0f, 0.333f, 0.000f, 0.666f, 0.666f, 0.000f}, {575.0f, 100.0f, 0.0f, 0.333f, 0.333f, 1.000f, 0.825f, 0.333f}, {475.0f, 100.0f, 0.0f, 1.000f, 0.333f, 0.333f, 0.175f, 0.333f} }; glViewport(0, 0, (GLsizei)width, (GLsizei)height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0f, (GLfloat)width, 0.0f, (GLfloat)height); glClearColor(0.0, 0.0, 0.0, 0.0); /* Create new triangulator */ tobj=gluNewTess(); /* Set triangulator's callbacks */ gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (GLvoid (*)())&vertexCallback); gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (GLvoid (*)())&beginCallback); gluTessCallback(tobj, GLU_TESS_END_DATA, (GLvoid (*)())&endCallback); gluTessCallback(tobj, GLU_TESS_ERROR, (GLvoid (*)())&errorCallback); /* reset object */ object1.sequences=0; /* rectangle with triangular hole inside */ gluTessBeginPolygon(tobj, (void*)&object1); gluTessBeginContour(tobj); gluTessVertex(tobj, rect[0], rect[0]); gluTessVertex(tobj, rect[1], rect[1]); gluTessVertex(tobj, rect[2], rect[2]); gluTessVertex(tobj, rect[3], rect[3]); gluTessEndContour(tobj); gluTessBeginContour(tobj); gluTessVertex(tobj, tri[0], tri[0]); gluTessVertex(tobj, tri[1], tri[1]); gluTessVertex(tobj, tri[2], tri[2]); gluTessEndContour(tobj); gluTessEndPolygon(tobj); /* Set triangulator's callbacks */ gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (GLvoid (*)())&vertexColorCallback); gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (GLvoid (*)())&beginCallback); gluTessCallback(tobj, GLU_TESS_END_DATA, (GLvoid (*)())&endCallback); gluTessCallback(tobj, GLU_TESS_ERROR, (GLvoid (*)())&errorCallback); gluTessCallback(tobj, GLU_TESS_COMBINE, (GLvoid (*)())&combineColorCallback); /* reset object */ object2.sequences=0; /* self-intersecting star */ gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE); gluTessBeginPolygon(tobj, (void*)&object2); gluTessBeginContour(tobj); gluTessVertex(tobj, star[0], star[0]); gluTessVertex(tobj, star[1], star[1]); gluTessVertex(tobj, star[2], star[2]); gluTessVertex(tobj, star[3], star[3]); gluTessVertex(tobj, star[4], star[4]); gluTessEndContour(tobj); gluTessEndPolygon(tobj); /* Set triangulator's callbacks */ gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (GLvoid (*)())&vertexTexColorCallback); gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (GLvoid (*)())&beginCallback); gluTessCallback(tobj, GLU_TESS_END_DATA, (GLvoid (*)())&endCallback); gluTessCallback(tobj, GLU_TESS_ERROR, (GLvoid (*)())&errorCallback); gluTessCallback(tobj, GLU_TESS_COMBINE, (GLvoid (*)())&combineTexColorCallback); /* reset object */ object3.sequences=0; /* self-intersecting star */ gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE); gluTessBeginPolygon(tobj, (void*)&object3); gluTessBeginContour(tobj); gluTessVertex(tobj, triangle[0], triangle[0]); gluTessVertex(tobj, triangle[1], triangle[1]); gluTessVertex(tobj, triangle[2], triangle[2]); gluTessEndContour(tobj); gluTessBeginContour(tobj); gluTessVertex(tobj, triangle[3], triangle[3]); gluTessVertex(tobj, triangle[4], triangle[4]); gluTessVertex(tobj, triangle[5], triangle[5]); gluTessVertex(tobj, triangle[6], triangle[6]); gluTessVertex(tobj, triangle[7], triangle[7]); gluTessVertex(tobj, triangle[8], triangle[8]); gluTessEndContour(tobj); gluTessEndPolygon(tobj); /* Destroy triangulator object */ gluDeleteTess(tobj); /* enable filtering */ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); tex=make_texture(256, 256); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 256, 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, tex); free(tex); }
/* convert a PolyList into a linked list of PolyListNodes, subdivide * non-flat or concave polgons */ static PolyListNode * PolyListToLinkedPoyList(Transform T, Transform Tdual, Transform TxT, const void **tagged_app, PolyListNode **plistp, PolyList *pl, struct obstack *scratch) { PolyListNode *plist = NULL; int pnr; if (!plistp) { plistp = &plist; } PolyListComputeNormals(pl, PL_HASVN|PL_HASPN|PL_HASPFL); for (pnr = 0; pnr < pl->n_polys; pnr++) { PolyListNode *new_pn; Poly *poly; if (pl->p[pnr].flags & POLY_NOPOLY) { /* degenerated, just skip it */ continue; } poly = &pl->p[pnr]; poly->flags |= pl->geomflags; if (T && T != TM_IDENTITY) { poly = transform_poly(T, Tdual, TxT, poly, scratch); } switch (pl->p[pnr].n_vertices) { case 3: /* ok */ new_pn = new_poly_list_node(tagged_app, scratch); new_pn->poly = poly; ListPush(*plistp, new_pn); break; #if !HAVE_LIBGLU case 4: /* supported */ if (pl->p[pnr].flags & (POLY_NONFLAT|POLY_CONCAVE)) { /* split this polygon along a diagonal, if the polygon is * concave: split across the unique concave vertex. */ int concave; if (pl->p[pnr].flags & POLY_CONCAVE) { Point3 nu; /* We need to determine the concave vertex */ PolyNormal(poly, &nu, pl->geomflags & VERT_4D, false, NULL, &concave); } else { concave= 0; } split_quad_poly(concave, poly, plistp, tagged_app, scratch); } else { new_pn = new_poly_list_node(tagged_app, scratch); new_pn->poly = poly; ListPush(*plistp, new_pn); } break; default: if (pl->p[pnr].flags & (POLY_NONFLAT|POLY_CONCAVE)) { static int was_here; if (!was_here ) { GeomError(1, "Non-flat or concave polygons not supported yet.\n"); was_here = 1; } } new_pn = new_poly_list_node(tagged_app, scratch); new_pn->poly = poly; ListPush(*plistp, new_pn); break; #else case 4: /* if we want to be able to render polygons with * self-intersections "correctly", then we always have to use * the GLU tesselater for polygons with more than 4 vertices and * for non-convex quadrilaterals. We can handle non-flat * quadrilaterals ourselves. */ if ((pl->p[pnr].flags & (POLY_NONFLAT|POLY_CONCAVE)) == POLY_NONFLAT) { /* Split this polygon along a diagonal. Leave concave * quadrilaterals to the GLU tesselator; they could have * self-intersections. */ split_quad_poly(0, poly, plistp, tagged_app, scratch); } else if ((pl->p[pnr].flags & POLY_CONCAVE) == 0) { new_pn = new_poly_list_node(tagged_app, scratch); new_pn->poly = poly; ListPush(*plistp, new_pn); } break; /* otherwise fall into the > 4 vertices case and leave * everything to the GLU tesselator. */ default: { /* We use the GLU tesselator here, if available. It is not * necessary to reinvent the wheel; also, the OpenGL MG backend * also uses the tesselator (so we will get comparable shapes * w/o translucency). */ static GLUtesselator *glutess; struct tess_data tessdata[1]; VARARRAY2(dv, GLdouble, poly->n_vertices, 3); Vertex **vp; int i; if (glutess == NULL) { glutess = gluNewTess(); gluTessProperty(glutess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); gluTessCallback(glutess, GLU_TESS_BEGIN_DATA, (GLvoid (*)())tess_begin_data); gluTessCallback(glutess, GLU_TESS_VERTEX_DATA, (GLvoid (*)())tess_vertex_data); gluTessCallback(glutess, GLU_TESS_COMBINE_DATA, (GLvoid (*)())tess_combine_data); } tessdata->trickyp = poly; tessdata->polyflags = poly->flags; tessdata->pn = &poly->pn; tessdata->scratch = scratch; tessdata->plistp = plistp; tessdata->tagged_app = tagged_app; /* tell GLU what we think is a good approximation for the normal */ gluTessNormal(glutess, poly->pn.x, poly->pn.y, poly->pn.z); /* rest is done in the callback functions */ gluTessBeginPolygon(glutess, tessdata); gluTessBeginContour(glutess); for (i = 0, vp = poly->v; i < poly->n_vertices; i++, vp++) { HPt3Coord w = (*vp)->pt.w ? (*vp)->pt.w : 1e20; if (w == 1.0) { dv[i][0] = (*vp)->pt.x; dv[i][1] = (*vp)->pt.y; dv[i][2] = (*vp)->pt.z; } else { dv[i][0] = (*vp)->pt.x / w; dv[i][1] = (*vp)->pt.y / w; dv[i][2] = (*vp)->pt.z / w; } gluTessVertex(glutess, dv[i], *vp); } gluTessEndContour(glutess); gluTessEndPolygon(glutess); break; /* out of switch */ } /* default */ #endif } /* switch */ } /* for */ return *plistp; }
void XMGPolygon::SetVertexArray ( const XMGVector3X* src_arr_vertex, const GLuint* arr_idx_hole ) { XMGPolygonImpl* impl = (XMGPolygonImpl *) m_impl; XMGRenderImpl* impl_parent = (XMGRenderImpl *) XMGRender::m_impl; XMGTess* data[2]; XMGShape* shape; XMGFacet* facet; XMGContour* contour; GLuint idx_tess; GLuint idx_shape; GLuint idx_facet; GLuint idx_vertex; GLuint idx_vec; GLuint num_shape; GLuint num_vertex; GLuint num_vec; GLuint off_vertex; GLuint off_ext; XMGVector3X src_vertex; XMGVector3X* arr_vertex; off_vertex = 0; off_ext = impl_parent->m_num_vertex; impl_parent->m_ext_vertex = 0; for ( idx_shape = 0, num_shape = impl_parent->m_vec_shape.size ( ); idx_shape < num_shape; idx_shape++ ) { shape = impl_parent->m_vec_shape[ idx_shape ]; shape->m_idx_hole = arr_idx_hole ? arr_idx_hole[ idx_shape ] : XMG_HOLE_NULL; // Set tess vertices if ( impl->m_tess[ 0 ] || impl->m_tess[ 1 ] ) { for ( idx_tess = 0; idx_tess < 2; idx_tess++ ) { if ( impl->m_tess[ idx_tess ] ) { data[ idx_tess ] = impl->m_data[ idx_tess ][ idx_shape ]; data[ idx_tess ]->Init ( XMG_TESS_VERTEX ); gluTessBeginPolygon ( impl->m_tess[ idx_tess ], (GLvoid *) data[ idx_tess ] ); gluTessBeginContour ( impl->m_tess[ idx_tess ] ); } } for ( idx_vertex = 0, num_vertex = shape->m_num_basic; idx_vertex < num_vertex; idx_vertex++ ) { for ( idx_tess = 0; idx_tess < 2; idx_tess++ ) { if ( idx_tess == 0 ) { if ( impl->m_tess[ idx_tess ] ) { src_vertex = src_arr_vertex[ off_vertex + idx_vertex ]; } else { continue; } } else if ( idx_tess == 1 ) { if ( impl->m_tess[ idx_tess ] ) { switch ( impl_parent->m_geo_type ) { case XMG_GEO_SOLID : src_vertex = src_arr_vertex[ off_vertex + num_vertex + idx_vertex ]; break; case XMG_GEO_BSOLID : if ( shape->m_idx_hole ) { src_vertex = src_arr_vertex[ idx_vertex < shape->m_idx_hole ? shape->m_idx_hole - idx_vertex - 1 : num_vertex + shape->m_idx_hole - idx_vertex - 1 ]; } else { src_vertex = src_arr_vertex[ num_vertex - idx_vertex - 1 ]; } src_vertex.m_z = 0; break; } } else { continue; } } data[ idx_tess ]->m_arr_vertex[ idx_vertex * 8 + 0 ] = XMG_X2F ( src_vertex.m_x ); data[ idx_tess ]->m_arr_vertex[ idx_vertex * 8 + 1 ] = XMG_X2F ( src_vertex.m_y ); data[ idx_tess ]->m_arr_vertex[ idx_vertex * 8 + 2 ] = XMG_X2F ( src_vertex.m_z ); if ( shape->m_idx_hole != 0 && shape->m_idx_hole == idx_vertex ) { gluNextContour ( impl->m_tess[ idx_tess ], GLU_INTERIOR ); } gluTessVertex ( impl->m_tess[ idx_tess ], &data[ idx_tess ]->m_arr_vertex[ idx_vertex * 8 ], &data[ idx_tess ]->m_arr_vertex[ idx_vertex * 8 ] ); } } idx_facet = 0; for ( idx_tess = 0; idx_tess < 2; idx_tess++ ) { if ( impl->m_tess[ idx_tess ] ) { gluTessEndContour ( impl->m_tess[ idx_tess ] ); gluTessEndPolygon ( impl->m_tess[ idx_tess ] ); // Set contours with original facet = shape->m_vec_facet[ idx_facet ]; facet->ClearContour ( ); if ( shape->m_idx_hole == XMG_HOLE_NULL ) { XMGAssert ( contour = new XMGContour ( ) ); contour->m_draw_limit = XMG_LIMIT_LINE; contour->m_off_vertex = facet->m_off_vertex; contour->m_num_vertex = facet->m_num_vertex; facet->m_vec_contour.push_back ( contour ); } else { XMGAssert ( contour = new XMGContour ( ) ); contour->m_draw_limit = XMG_LIMIT_LINE; contour->m_off_vertex = facet->m_off_vertex; contour->m_num_vertex = shape->m_idx_hole; facet->m_vec_contour.push_back ( contour ); XMGAssert ( contour = new XMGContour ( ) ); contour->m_draw_limit = XMG_LIMIT_LINE; contour->m_off_vertex = facet->m_off_vertex + shape->m_idx_hole; contour->m_num_vertex = facet->m_num_vertex - shape->m_idx_hole; facet->m_vec_contour.push_back ( contour ); } // Set contours with tessed facet->m_off_ext = off_ext; for ( idx_vec = 0, num_vec = data[ idx_tess ]->m_vec_num_vertex.size ( ); idx_vec < num_vec; idx_vec++ ) { XMGAssert ( contour = new XMGContour ( ) ); contour->m_draw_limit = XMG_LIMIT_TRI; contour->m_disp_mode = data[ idx_tess ]->m_vec_mode[ idx_vec ]; contour->m_off_vertex = off_ext; contour->m_num_vertex = data[ idx_tess ]->m_vec_num_vertex[ idx_vec ]; facet->m_vec_contour.push_back ( contour ); off_ext += contour->m_num_vertex; } idx_facet++; facet->m_num_ext = data[ idx_tess ]->m_vec_vertex.size ( ); impl_parent->m_ext_vertex += facet->m_num_ext; } } } off_vertex += shape->m_num_input; } XMGRender::SetVertexArray ( src_arr_vertex, XMG_SHAPE_ALL ); if ( impl->m_tess[ 0 ] || impl->m_tess[ 1 ] ) { off_vertex = 0; num_vertex = impl_parent->m_ext_vertex; XMGAssert ( arr_vertex = (XMGVector3X *) kdMalloc ( sizeof ( XMGVector3X ) * num_vertex ) ); for ( idx_shape = 0, num_shape = impl_parent->m_vec_shape.size ( ); idx_shape < num_shape; idx_shape++ ) { for ( idx_tess = 0; idx_tess < 2; idx_tess++ ) { if ( impl->m_tess[ idx_tess ] ) { data[ idx_tess ] = impl->m_data[ idx_tess ][ idx_shape ]; for ( idx_vertex = 0, num_vertex = data[ idx_tess ]->m_vec_vertex.size ( ); idx_vertex < num_vertex; idx_vertex++ ) { arr_vertex[ off_vertex ] = data[ idx_tess ]->m_vec_vertex[ idx_vertex ]; off_vertex++; } data[ idx_tess ]->ClearVector ( ); } } } impl_parent->SetBuffer ( impl_parent->m_id_vertex, arr_vertex, sizeof ( XMGVector3X ) * impl_parent->m_num_vertex, sizeof ( XMGVector3X ) * impl_parent->m_ext_vertex ); kdFree ( arr_vertex ); } }
/** Convert to TriMesh */ void PolyhedronGeom::convert(GeomObject* target) { TriMeshGeom* tm = dynamic_cast<TriMeshGeom*>(target); vec3d* vertsptr = verts.dataPtr(); // Index of the corresponding facevarying (or facevertex) variable int facevarindex = 0; int i, j; // Check if the target geom is really a TriMesh if (tm==0) { throw ENotImplementedError("Conversion not supported by the PolyhedronGeom"); } // No tesselation object allocated yet? Then do so once and for all... if (tess==0) { tess = gluNewTess(); if (tess==0) return; } PolyTriangulation polyTriangulation(*this); // Remove any existing variable in the trimesh... tm->deleteAllVariables(); dataMemManager.setDataSize(3*sizeof(GLdouble)+2*sizeof(int)); gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (TessCallback)(&onTessBegin_triangulation)); gluTessCallback(tess, GLU_TESS_END_DATA, (TessCallback)(&onTessEnd_triangulation)); gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (TessCallback)(&onTessVertex_triangulation)); gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); gluTessProperty(tess, GLU_TESS_TOLERANCE, 0); gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); // Iterate over all polygons... for(i=0; i<getNumPolys(); i++) { dataMemManager.reset(); gluTessBeginPolygon(tess, &polyTriangulation); // Iterate over all loops of polygon i... for(j=0; j<getNumLoops(i); j++) { gluTessBeginContour(tess); LoopIterator it = loopBegin(i, j); LoopIterator itend = loopEnd(i, j); vec3d* v; for( ; it!=itend; it++) { int vidx = (*it); v = vertsptr + vidx; GLdouble* loc = (GLdouble*)dataMemManager.newDataPtr(); loc[0] = v->x; loc[1] = v->y; loc[2] = v->z; int* data = (int*)(loc+3); data[0] = vidx; // Vertex index data[1] = facevarindex; // facevarying variable index gluTessVertex(tess, loc, data); facevarindex++; } gluTessEndContour(tess); } gluTessEndPolygon(tess); polyTriangulation.polyFinished(); } polyTriangulation.initTriMesh(*tm); }
void Boundary::render(bool invert) { // Calculate the geometry of the border calculate(); //glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); // Render the border glBegin(GL_QUADS); for (int i = 0; i < outerEdges.size(); i++) { Edge out = outerEdges[i]; Edge in = innerEdges[i]; if (!invert) { glColor4f(0.0, 0.0, 0.0, 0.0); } else { glColor4f(1.0, 1.0, 1.0, 1.0); } glVertex3f(out.a.x, out.a.y, 0.0); glVertex3f(out.b.x, out.b.y, 0.0); if (!invert) { glColor4f(1.0, 1.0, 1.0, 1.0); } else { glColor4f(0.0, 0.0, 0.0, 0.0); } glVertex3f(in.b.x, in.b.y, 0.0); glVertex3f(in.a.x, in.a.y, 0.0); } glEnd(); // Fill the border if (!invert) { glColor3f(1.0, 1.0, 1.0); } else { glColor3f(0.0, 0.0, 0.0); } GLUtesselator *tess = gluNewTess(); gluTessCallback(tess, GLU_TESS_BEGIN, (GLvoid (*) ()) &glBegin); gluTessCallback(tess, GLU_TESS_END, (GLvoid (*) ()) &glEnd); gluTessCallback(tess, GLU_TESS_VERTEX, (GLvoid (*) ()) &glVertex3dv); gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); gluTessNormal(tess, 0, 0, 1); gluTessBeginPolygon(tess, NULL); gluTessBeginContour(tess); GLdouble *vertices = new GLdouble[innerEdges.size() * 3]; for (int i = 0; i < innerEdges.size(); i++) { vertices[(i * 3) + 0] = innerEdges[i].a.x; vertices[(i * 3) + 1] = innerEdges[i].a.y; vertices[(i * 3) + 2] = 0.0; gluTessVertex(tess, vertices + (i * 3), vertices + (i * 3)); } gluTessEndContour(tess); gluTessEndPolygon(tess); delete [] vertices; gluDeleteTess(tess); }
/** Draw the polyhedron. */ void PolyhedronGeom::drawGL() { // No tesselation object allocated yet? Then do so once and for all... if (tess==0) { tess = gluNewTess(); if (tess==0) return; } // Set flag to 0 (i.e. no variables are present so far) tess_data_flag = 0; PrimVarAccess<vec3d> normals(*this, std::string("N"), NORMAL, 1, std::string("Nfaces")); PrimVarAccess<double> texcoords(*this, std::string("st"), FLOAT, 2, std::string("stfaces")); PrimVarAccess<vec3d> colors(*this, std::string("Cs"), COLOR, 1, std::string("Csfaces")); vec3d* N; vec3d* Cs; GLfloat glcol[4] = {0,0,0,1}; double* st; vec3d* vertsptr = verts.dataPtr(); int i,j; int nfloats=3; // Check which variables has to be passed to the vertex callback // (this is the case when mode is > 2) if (normals.mode>2) { tess_data_flag |= 0x01; nfloats += 3; } if (texcoords.mode>2) { tess_data_flag |= 0x02; nfloats += 2; } if (colors.mode>2) { tess_data_flag |= 0x04; nfloats += 3; } dataMemManager.setDataSize(nfloats*sizeof(GLdouble)); gluTessCallback(tess, GLU_TESS_BEGIN, (TessCallback)(&onTessBegin)); gluTessCallback(tess, GLU_TESS_END, (TessCallback)(&onTessEnd)); gluTessCallback(tess, GLU_TESS_VERTEX, (TessCallback)(&onTessVertex)); gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); gluTessProperty(tess, GLU_TESS_TOLERANCE, 0); gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); // Iterate over all polygons... for(i=0; i<getNumPolys(); i++) { dataMemManager.reset(); // No normals? Then a face normal has to be calculated... if (normals.mode==0) { vec3d Ng; computeNormal(i, Ng); glNormal3d(Ng.x, Ng.y, Ng.z); } // Process uniform variables... if (normals.onFace(N)) glNormal3d(N->x, N->y, N->z); if (texcoords.onFace(st)) glTexCoord2dv(st); if (colors.onFace(Cs)) { glcol[0] = GLfloat(Cs->x); glcol[1] = GLfloat(Cs->y); glcol[2] = GLfloat(Cs->z); glMaterialfv(GL_FRONT, GL_DIFFUSE, glcol); } gluTessBeginPolygon(tess, 0); // Iterate over all loops of polygon i... for(j=0; j<getNumLoops(i); j++) { gluTessBeginContour(tess); LoopIterator it = loopBegin(i, j); LoopIterator itend = loopEnd(i, j); vec3d* v; for( ; it!=itend; it++) { int vidx = (*it); v = vertsptr + vidx; GLdouble* data = (GLdouble*)dataMemManager.newDataPtr(); GLdouble* p = data+3; data[0] = v->x; data[1] = v->y; data[2] = v->z; if (normals.onVertex(vidx, N)) { p[0] = N->x; p[1] = N->y; p[2] = N->z; p += 3; } if (texcoords.onVertex(vidx, st)) { p[0] = st[0]; p[1] = st[1]; p += 2; } if (colors.onVertex(vidx, Cs)) { p[0] = Cs->x; p[1] = Cs->y; p[2] = Cs->z; } gluTessVertex(tess, data, data); } gluTessEndContour(tess); } gluTessEndPolygon(tess); } /* for(i=0; i<getNumPolys(); i++) { for(j=0; j<getNumLoops(i); j++) { LoopIterator it = loopBegin(i, j); LoopIterator itend = loopEnd(i, j); vec3d* v; glBegin(GL_LINE_LOOP); for( ; it!=itend; it++) { v = vertsptr + (*it); glVertex3d(v->x, v->y, v->z); } glEnd(); } }*/ }
void FTVectoriser::MakeMesh(FTGL_DOUBLE zNormal, int outsetType, float outsetSize) { if(mesh) { delete mesh; } mesh = new FTMesh; GLUtesselator* tobj = gluNewTess(); gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (GLUTesselatorFunction)ftglBegin); gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (GLUTesselatorFunction)ftglVertex); gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (GLUTesselatorFunction)ftglCombine); gluTessCallback(tobj, GLU_TESS_END_DATA, (GLUTesselatorFunction)ftglEnd); gluTessCallback(tobj, GLU_TESS_ERROR_DATA, (GLUTesselatorFunction)ftglError); if(contourFlag & ft_outline_even_odd_fill) // ft_outline_reverse_fill { gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); } else { gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); } gluTessProperty(tobj, GLU_TESS_TOLERANCE, 0); gluTessNormal(tobj, 0.0f, 0.0f, zNormal); gluTessBeginPolygon(tobj, mesh); for(size_t c = 0; c < ContourCount(); ++c) { /* Build the */ switch(outsetType) { case 1 : contourList[c]->buildFrontOutset(outsetSize); break; case 2 : contourList[c]->buildBackOutset(outsetSize); break; } const FTContour* contour = contourList[c]; gluTessBeginContour(tobj); for(size_t p = 0; p < contour->PointCount(); ++p) { const FTGL_DOUBLE* d; switch(outsetType) { case 1: d = contour->FrontPoint(p); break; case 2: d = contour->BackPoint(p); break; case 0: default: d = contour->Point(p); break; } // XXX: gluTessVertex doesn't modify the data but does not // specify "const" in its prototype, so we cannot cast to // a const type. gluTessVertex(tobj, (GLdouble *)d, (GLvoid *)d); } gluTessEndContour(tobj); } gluTessEndPolygon(tobj); gluDeleteTess(tobj); }
void Playback3D::do_mask_sync(Playback3DCommand *command) { #ifdef HAVE_GL command->canvas->lock_canvas("Playback3D::do_mask_sync"); if(command->canvas->get_canvas()) { BC_WindowBase *window = command->canvas->get_canvas(); window->lock_window("Playback3D::do_mask_sync"); window->enable_opengl(); switch(command->frame->get_opengl_state()) { case VFrame::RAM: // Time to upload to the texture command->frame->to_texture(); break; case VFrame::SCREEN: // Read back from PBuffer // Bind context to pbuffer command->frame->enable_opengl(); command->frame->screen_to_texture(); break; } // Create PBuffer and draw the mask on it command->frame->enable_opengl(); // Initialize coordinate system int w = command->frame->get_w(); int h = command->frame->get_h(); command->frame->init_screen(); int value = command->keyframe_set->get_value(command->start_position_project, PLAY_FORWARD); float feather = command->keyframe_set->get_feather(command->start_position_project, PLAY_FORWARD); // Clear screen glDisable(GL_TEXTURE_2D); if(command->default_auto->mode == MASK_MULTIPLY_ALPHA) { glClearColor(0.0, 0.0, 0.0, 0.0); glColor4f((float)value / 100, (float)value / 100, (float)value / 100, 1.0); } else { glClearColor(1.0, 1.0, 1.0, 1.0); glColor4f((float)1.0 - (float)value / 100, (float)1.0 - (float)value / 100, (float)1.0 - (float)value / 100, 1.0); } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Draw mask with scaling to simulate feathering GLUtesselator *tesselator = gluNewTess(); gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv); gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin); gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd); gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback); // Draw every submask as a new polygon int total_submasks = command->keyframe_set->total_submasks( command->start_position_project, PLAY_FORWARD); float scale = feather + 1; int display_list = glGenLists(1); glNewList(display_list, GL_COMPILE); for(int k = 0; k < total_submasks; k++) { gluTessBeginPolygon(tesselator, NULL); gluTessBeginContour(tesselator); ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>; command->keyframe_set->get_points(points, k, command->start_position_project, PLAY_FORWARD); int first_point = 0; // Need to tabulate every vertex in persistent memory because // gluTessVertex doesn't copy them. ArrayList<GLdouble*> coords; for(int i = 0; i < points->total; i++) { MaskPoint *point1 = points->values[i]; MaskPoint *point2 = (i >= points->total - 1) ? points->values[0] : points->values[i + 1]; // This is very slow. float x, y; int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y))); if(point1->control_x2 == 0 && point1->control_y2 == 0 && point2->control_x1 == 0 && point2->control_y1 == 0) segments = 1; float x0 = point1->x; float y0 = point1->y; float x1 = point1->x + point1->control_x2; float y1 = point1->y + point1->control_y2; float x2 = point2->x + point2->control_x1; float y2 = point2->y + point2->control_y1; float x3 = point2->x; float y3 = point2->y; for(int j = 0; j <= segments; j++) { float t = (float)j / segments; float tpow2 = t * t; float tpow3 = t * t * t; float invt = 1 - t; float invtpow2 = invt * invt; float invtpow3 = invt * invt * invt; x = ( invtpow3 * x0 + 3 * t * invtpow2 * x1 + 3 * tpow2 * invt * x2 + tpow3 * x3); y = ( invtpow3 * y0 + 3 * t * invtpow2 * y1 + 3 * tpow2 * invt * y2 + tpow3 * y3); if(j > 0 || first_point) { GLdouble *coord = new GLdouble[3]; coord[0] = x / scale; coord[1] = -h + y / scale; coord[2] = 0; coords.append(coord); first_point = 0; } } } // Now that we know the total vertices, send them to GLU for(int i = 0; i < coords.total; i++) gluTessVertex(tesselator, coords.values[i], coords.values[i]); gluTessEndContour(tesselator); gluTessEndPolygon(tesselator); points->remove_all_objects(); delete points; coords.remove_all_objects(); } glEndList(); glCallList(display_list); glDeleteLists(display_list, 1); glColor4f(1, 1, 1, 1); // Read mask into temporary texture. // For feathering, just read the part of the screen after the downscaling. float w_scaled = w / scale; float h_scaled = h / scale; // Don't vary the texture size according to scaling because that // would waste memory. // This enables and binds the temporary texture. glActiveTexture(GL_TEXTURE1); BC_Texture::new_texture(&temp_texture, w, h, command->frame->get_color_model()); temp_texture->bind(1); glReadBuffer(GL_BACK); // Need to add extra size to fill in the bottom right glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, (int)MIN(w_scaled + 2, w), (int)MIN(h_scaled + 2, h)); command->frame->bind_texture(0); // For feathered masks, use a shader to multiply. // For unfeathered masks, we could use a stencil buffer // for further optimization but we also need a YUV algorithm. unsigned int frag_shader = 0; switch(temp_texture->get_texture_components()) { case 3: if(command->frame->get_color_model() == BC_YUV888) frag_shader = VFrame::make_shader(0, multiply_yuvmask3_frag, 0); else frag_shader = VFrame::make_shader(0, multiply_mask3_frag, 0); break; case 4: frag_shader = VFrame::make_shader(0, multiply_mask4_frag, 0); break; } if(frag_shader) { int variable; glUseProgram(frag_shader); if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0) glUniform1i(variable, 0); if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0) glUniform1i(variable, 1); if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0) glUniform1f(variable, scale); } // Write texture to PBuffer with multiply and scaling for feather. command->frame->draw_texture(0, 0, w, h, 0, 0, w, h); command->frame->set_opengl_state(VFrame::SCREEN); // Disable temp texture glUseProgram(0); glActiveTexture(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); delete temp_texture; temp_texture = 0; glActiveTexture(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); // Default drawable window->enable_opengl(); window->unlock_window(); } command->canvas->unlock_canvas(); #endif }
//---------------------------------------------------------- ofVboMesh ofTessellator::tessellate( const ofPolyline& polyline, bool bIs2D ){ mutex.lock(); clear(); resultMesh = ofVboMesh(); // resultMesh.clear(); // now get the tesselator object up and ready: GLUtesselator * ofShapeTobj = gluNewTess(); #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( ofShapeTobj, GLU_TESS_BEGIN, OF_GLU_CALLBACK_HACK &ofTessellator::begin); gluTessCallback( ofShapeTobj, GLU_TESS_VERTEX, OF_GLU_CALLBACK_HACK &ofTessellator::vertex); gluTessCallback( ofShapeTobj, GLU_TESS_COMBINE, OF_GLU_CALLBACK_HACK &ofTessellator::combine); gluTessCallback( ofShapeTobj, GLU_TESS_END, OF_GLU_CALLBACK_HACK &ofTessellator::end); gluTessCallback( ofShapeTobj, GLU_TESS_ERROR, OF_GLU_CALLBACK_HACK &ofTessellator::error); gluTessProperty( ofShapeTobj, GLU_TESS_WINDING_RULE, ofGetStyle().polyMode); if (!ofGetStyle().bFill){ gluTessProperty( ofShapeTobj, GLU_TESS_BOUNDARY_ONLY, true); } else { gluTessProperty( ofShapeTobj, GLU_TESS_BOUNDARY_ONLY, false); } gluTessProperty( ofShapeTobj, 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 ------------------------------------------- */ if( bIs2D) gluTessNormal(ofShapeTobj, 0.0, 0.0, 1.0); gluTessBeginPolygon( ofShapeTobj, NULL); for ( int i=0; i<polyline.size(); i++ ) { double* point = new double[3]; point[0] = polyline[i].x; point[1] = polyline[i].y; point[2] = polyline[i].z; ofShapePolyVertexs.push_back(point); } gluTessBeginContour( ofShapeTobj ); for (int i=0; i<(int)ofShapePolyVertexs.size(); i++) { gluTessVertex( ofShapeTobj, ofShapePolyVertexs[i], ofShapePolyVertexs[i]); } gluTessEndContour( ofShapeTobj ); // no matter what we did / do, we need to delete the tesselator object gluTessEndPolygon( ofShapeTobj); gluDeleteTess( ofShapeTobj); ofShapeTobj = NULL; // now clear the vertices on the dynamically allocated data clear(); mutex.unlock(); return resultMesh; }
static void _cogl_path_build_fill_attribute_buffer (CoglPath *path) { CoglPathTesselator tess; unsigned int path_start = 0; CoglPathData *data = path->data; int i; /* If we've already got a vbo then we don't need to do anything */ if (data->fill_attribute_buffer) return; tess.primitive_type = FALSE; /* Generate a vertex for each point on the path */ tess.vertices = g_array_new (FALSE, FALSE, sizeof (CoglPathTesselatorVertex)); g_array_set_size (tess.vertices, data->path_nodes->len); for (i = 0; i < data->path_nodes->len; i++) { CoglPathNode *node = &g_array_index (data->path_nodes, CoglPathNode, i); CoglPathTesselatorVertex *vertex = &g_array_index (tess.vertices, CoglPathTesselatorVertex, i); vertex->x = node->x; vertex->y = node->y; /* Add texture coordinates so that a texture would be drawn to fit the bounding box of the path and then cropped by the path */ if (data->path_nodes_min.x == data->path_nodes_max.x) vertex->s = 0.0f; else vertex->s = ((node->x - data->path_nodes_min.x) / (data->path_nodes_max.x - data->path_nodes_min.x)); if (data->path_nodes_min.y == data->path_nodes_max.y) vertex->t = 0.0f; else vertex->t = ((node->y - data->path_nodes_min.y) / (data->path_nodes_max.y - data->path_nodes_min.y)); } tess.indices_type = _cogl_path_tesselator_get_indices_type_for_size (data->path_nodes->len); _cogl_path_tesselator_allocate_indices_array (&tess); tess.glu_tess = gluNewTess (); if (data->fill_rule == COGL_PATH_FILL_RULE_EVEN_ODD) gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); else gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); /* All vertices are on the xy-plane */ gluTessNormal (tess.glu_tess, 0.0, 0.0, 1.0); gluTessCallback (tess.glu_tess, GLU_TESS_BEGIN_DATA, _cogl_path_tesselator_begin); gluTessCallback (tess.glu_tess, GLU_TESS_VERTEX_DATA, _cogl_path_tesselator_vertex); gluTessCallback (tess.glu_tess, GLU_TESS_END_DATA, _cogl_path_tesselator_end); gluTessCallback (tess.glu_tess, GLU_TESS_COMBINE_DATA, _cogl_path_tesselator_combine); gluTessBeginPolygon (tess.glu_tess, &tess); while (path_start < data->path_nodes->len) { CoglPathNode *node = &g_array_index (data->path_nodes, CoglPathNode, path_start); gluTessBeginContour (tess.glu_tess); for (i = 0; i < node->path_size; i++) { double vertex[3] = { node[i].x, node[i].y, 0.0 }; gluTessVertex (tess.glu_tess, vertex, GINT_TO_POINTER (i + path_start)); } gluTessEndContour (tess.glu_tess); path_start += node->path_size; } gluTessEndPolygon (tess.glu_tess); gluDeleteTess (tess.glu_tess); data->fill_attribute_buffer = cogl_attribute_buffer_new (data->context, sizeof (CoglPathTesselatorVertex) * tess.vertices->len, tess.vertices->data); g_array_free (tess.vertices, TRUE); data->fill_attributes[0] = cogl_attribute_new (data->fill_attribute_buffer, "cogl_position_in", sizeof (CoglPathTesselatorVertex), G_STRUCT_OFFSET (CoglPathTesselatorVertex, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); data->fill_attributes[1] = cogl_attribute_new (data->fill_attribute_buffer, "cogl_tex_coord0_in", sizeof (CoglPathTesselatorVertex), G_STRUCT_OFFSET (CoglPathTesselatorVertex, s), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); data->fill_vbo_indices = cogl_indices_new (data->context, tess.indices_type, tess.indices->data, tess.indices->len); data->fill_vbo_n_indices = tess.indices->len; g_array_free (tess.indices, TRUE); }
void CMFCTessView::OnDraw(CDC* pDC) { CMFCTessDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here //some per-drawing init stuff glLoadIdentity(); //setup drawing dimensions, etc CPoint vptorg = m_pDC->GetViewportOrg() ; //note m_pDC, NOT pDC CRect rect ; GetWindowRect( &rect ) ; int dx = rect.Width() ; int dy = rect.Height() ; glViewport( 0, 0, dx, dy ); glMatrixMode( GL_MODELVIEW ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // create bitmaps for the device context font's first 256 glyphs HDC hdc = m_pDC->GetSafeHdc() ; wglUseFontBitmaps(hdc, 0, 256, 1000); glListBase(1000); float R ; if( pDoc->m_ContourList.GetCount() > 0 ) { CalculateExtents() ; // Collect overall figure extents (in meters) R = Radius ; //11/29/03 experiment to eliminate probs w/non-square windows float glleft = -R ; float gltop = +R ; float nearplane = -R ; //rev 07/25/03 float farplane = R ; //rev 07/25/03 float glleft2 = glleft ; float gltop2 = gltop ; float glright2 = ( glleft + 2*R ) ; float glbottom2 = ( gltop - 2*R ) ; //adjust for non-square viewing window float dxdy = (float)dx/(float)dy ; //=1.00 for square window if( dxdy > 1 ) { glOrtho( glleft2*dxdy , glright2*dxdy, glbottom2, gltop2, nearplane, farplane ) ; } else { glOrtho( glleft2 , glright2, glbottom2/dxdy, gltop2/dxdy, nearplane, farplane ) ; } glTranslatef( -m_Center.x, -m_Center.y, -m_Center.z ) ; } else { CString txtstr ; glOrtho( -1.f , 1.f, -1.f, 1.f, -1.f, 1.f ) ; glTranslatef( 0.f, 0.f, 0.f ) ; txtstr = "Nothing to draw" ; glColor3f( 0.f, 0.f, 0.f ) ; glRasterPos3f(0.0F, 0.0F, 0.0F ); glCallLists(txtstr.GetLength(), GL_UNSIGNED_BYTE, txtstr); //clean up & exit glFlush(); glDeleteLists(1000, 256) ; SwapBuffers( m_pDC->GetSafeHdc() ); return ; } glPushMatrix() ; //01/09/05 implement tessellation GLUtesselator *tobj; tobj = gluNewTess(); //added 02/09/05 as part of mem leak fix while( gm_VertexPtrList.GetCount() > 0 ) { GLdouble* pV = (GLdouble*)gm_VertexPtrList.RemoveHead() ; delete[] pV ; pV = NULL ; } gluTessCallback(tobj, GLU_TESS_BEGIN, (void (CALLBACK *) ())beginCallback); gluTessCallback(tobj, GLU_TESS_VERTEX, (void (CALLBACK *) ()) vertexCallback); gluTessCallback(tobj, GLU_TESS_END, (void (CALLBACK *) ())endCallback); gluTessCallback(tobj, GLU_TESS_ERROR,(void (CALLBACK *) ())errorCallback); gluTessCallback(tobj, GLU_TESS_COMBINE, (void (CALLBACK *) ())combineCallback); glShadeModel(GL_SMOOTH); gluTessProperty(tobj, GLU_TESS_WINDING_RULE, m_WindingRule ); //only one polygon, but multiple contours gluTessBeginPolygon(tobj, NULL); POSITION pos = pDoc->m_ContourList.GetHeadPosition() ; while ( pos ) { CContour* pCtr = (CContour*)pDoc->m_ContourList.GetNext( pos ) ; ASSERT( pCtr != NULL && pCtr->m_NumVertex > 0 && pCtr->m_ppVertexArray != NULL ) ; int numcorners = pCtr->m_NumVertex ; gluTessBeginContour(tobj); for( int cnridx = 0; cnridx < numcorners; cnridx++ ) { GLdouble* glvert = pCtr->m_ppVertexArray[cnridx]; gluTessVertex( tobj, glvert, glvert ) ; TRACE( "Draw: Sent vertex(%f,%f,%f,%f,%f,%f)\n", glvert[0],glvert[1],glvert[2],glvert[3],glvert[4],glvert[5] ) ; } gluTessEndContour(tobj); } //end of all contour definitions gluTessEndPolygon(tobj); //clean up & exit glFlush(); glDeleteLists(1000, 256) ; // delete our 256 glyph display lists SwapBuffers( m_pDC->GetSafeHdc() ); gluDeleteTess( tobj ) ; //added 02/09/05 as part of mem leak fix while( gm_VertexPtrList.GetCount() > 0 ) { GLdouble* pV = (GLdouble*)gm_VertexPtrList.RemoveHead() ; delete[] pV ; pV = NULL ; } }
void MapPainterOpenGL::DrawArea(const Projection& projection, const MapParameter& /*parameter*/, const MapPainter::AreaData& area) { if (area.fillStyle->GetFillColor().IsVisible()) { glColor4d(area.fillStyle->GetFillColor().GetR(), area.fillStyle->GetFillColor().GetG(), area.fillStyle->GetFillColor().GetB(), area.fillStyle->GetFillColor().GetA()); gluTessProperty(tesselator, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); gluTessBeginPolygon(tesselator, NULL); gluTessBeginContour(tesselator); for (size_t i=area.transStart; i<=area.transEnd; i++) { gluTessVertex(tesselator, (GLdouble*)&coordBuffer->buffer[i], (GLdouble*)&coordBuffer->buffer[i]); } gluTessEndContour(tesselator); if (!area.clippings.empty()) { // Clip areas within the area by using CAIRO_FILL_RULE_EVEN_ODD for (std::list<PolyData>::const_iterator c=area.clippings.begin(); c!=area.clippings.end(); c++) { const PolyData& data=*c; gluTessBeginContour(tesselator); for (size_t i=data.transStart; i<=data.transEnd; i++) { gluTessVertex(tesselator, (GLdouble*)&coordBuffer->buffer[i], (GLdouble*)&coordBuffer->buffer[i]); } gluTessEndContour(tesselator); } } gluTessEndPolygon(tesselator); } if (area.fillStyle->GetBorderWidth()>0 && area.fillStyle->GetBorderColor().IsVisible()) { double borderWidth=projection.ConvertWidthToPixel(area.fillStyle->GetBorderWidth()); glColor4d(area.fillStyle->GetBorderColor().GetR(), area.fillStyle->GetBorderColor().GetG(), area.fillStyle->GetBorderColor().GetB(), area.fillStyle->GetBorderColor().GetA()); glLineWidth(borderWidth); glBegin(GL_LINE_LOOP); for (size_t i=area.transStart; i<=area.transEnd; i++) { glVertex3d(coordBuffer->buffer[i].GetX(), coordBuffer->buffer[i].GetY(), 0.0); } glEnd(); } }
// Build PolyTessGeo Object from OGR Polygon // Using OpenGL/GLU tesselator int PolyTessGeo::BuildTessGLU() { unsigned int iir, ip; GLdouble *geoPt; #if 0 // Make a quick sanity check of the polygon coherence bool b_ok = true; OGRLineString *tls = poly->getExteriorRing(); if(!tls) { b_ok = false; } else { int tnpta = poly->getExteriorRing()->getNumPoints(); if(tnpta < 3 ) b_ok = false; } for( iir=0 ; iir < poly->getNumInteriorRings() ; iir++) { int tnptr = poly->getInteriorRing(iir)->getNumPoints(); if( tnptr < 3 ) b_ok = false; } if( !b_ok ) return ERROR_BAD_OGRPOLY; #endif // Allocate a work buffer, which will be grown as needed #define NINIT_BUFFER_LEN 10000 m_pwork_buf = (GLdouble *)malloc(NINIT_BUFFER_LEN * 2 * sizeof(GLdouble)); m_buf_len = NINIT_BUFFER_LEN * 2; m_buf_idx = 0; // Create an array to hold pointers to allocated vertices created by "combine" callback, // so that they may be deleted after tesselation. m_pCombineVertexArray = new wxArrayPtrVoid; // Create tesselator GLUtessobj = gluNewTess(); // Register the callbacks gluTessCallback(GLUtessobj, GLU_TESS_BEGIN_DATA, (GLvoid (*) ())&beginCallback); gluTessCallback(GLUtessobj, GLU_TESS_BEGIN_DATA, (GLvoid (*) ())&beginCallback); gluTessCallback(GLUtessobj, GLU_TESS_VERTEX_DATA, (GLvoid (*) ())&vertexCallback); gluTessCallback(GLUtessobj, GLU_TESS_END_DATA, (GLvoid (*) ())&endCallback); gluTessCallback(GLUtessobj, GLU_TESS_COMBINE_DATA, (GLvoid (*) ())&combineCallback); gluTessCallback(GLUtessobj, GLU_TESS_ERROR_DATA, (GLvoid (*) ())&errorCallback); gluTessProperty(GLUtessobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); gluTessNormal(GLUtessobj, 0, 0, 1); // Get total number of points(vertices) to build a buffer int npta = 0; for( int i=0 ; i < m_ncnt ; i++) npta += m_cntr[i]; geoPt = (GLdouble *)malloc((npta + 6) * 3 * sizeof(GLdouble)); // vertex array // Grow the work buffer if necessary if((npta * 4) > m_buf_len) { m_pwork_buf = (GLdouble *)realloc(m_pwork_buf, npta * 4 * sizeof(GLdouble)); m_buf_len = npta * 4; } // Define the polygon gluTessBeginPolygon(GLUtessobj, this); // 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[m_cntr[0]-1].m_x; y0 = pp[m_cntr[0]-1].m_y; } unsigned int ptValid = m_cntr[0]; // Transcribe points to vertex array, in proper order with no duplicates // also, accounting for tess_orient GLdouble *ppt = geoPt; for(ip = 0 ; ip < (unsigned int)m_cntr[0] ; ip++) { int pidx; if(cw) pidx = m_cntr[0] - 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; *ppt++ = 0; } else { *ppt++ = y; *ppt++ = x; *ppt++ = 0; } } else ptValid--; x0 = x; y0 = y; } // Apply LOD reduction int beforeLOD = ptValid; int afterLOD = beforeLOD; if(ptValid > 20 && (m_LOD_meters > .01)) { std::vector<bool> bool_keep(ptValid, false); // Keep a few key points bool_keep[0] = true; bool_keep[1] = true; bool_keep[ptValid-1] = true; bool_keep[ptValid-2] = true; DouglasPeuckerDI(geoPt, 1, ptValid-2, m_LOD_meters, bool_keep); // Create a new buffer double *LOD_result = (double *)malloc((m_cntr[0]) * 3 * sizeof(double)); double *plod = LOD_result; int kept_LOD =0; for(unsigned int i=0 ; i < ptValid ; i++){ if(bool_keep[i]){ double x = geoPt[i*3]; double y = geoPt[(i*3) + 1]; *plod++ = x; *plod++ = y; *plod++ = 0; kept_LOD++; } } beforeLOD = ptValid; afterLOD = kept_LOD; // Copy the lod points back into the vertex buffer memcpy(geoPt, LOD_result, kept_LOD * 3 * sizeof(double)); free(LOD_result); ptValid = kept_LOD; } // Declare the gluContour and copy the points gluTessBeginContour(GLUtessobj); double *DPrun = geoPt; for(ip = 0 ; ip < ptValid ; ip++) { gluTessVertex( GLUtessobj, DPrun, DPrun ) ; DPrun += 3; } gluTessEndContour(GLUtessobj); // Now the interior contours #if 1 int gpIndex = m_cntr[0]; for(iir=0; iir < (unsigned int)m_ncnt-1; iir++){ wxPoint2DDouble *pp = (wxPoint2DDouble *)m_vertexPtrArray[iir + 1]; int npti = m_cntr[iir+1]; ptValid = npti; double *ppt = &geoPt[gpIndex * 3]; // next available location in geoPT double *DPStart = ppt; // 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++) { 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; *ppt++ = 0; } else { *ppt++ = y; *ppt++ = x; *ppt++ = 0; } } else ptValid--; x0 = x; y0 = y; } // Declare the gluContour and reference the points gluTessBeginContour(GLUtessobj); double *DPruni = DPStart; for(ip = 0 ; ip < ptValid ; ip++) { gluTessVertex( GLUtessobj, DPruni, DPruni ) ; DPruni += 3; } gluTessEndContour(GLUtessobj); gpIndex += m_cntr[iir+1]; } #endif m_pTPG_Last = NULL; m_pTPG_Head = NULL; m_nvmax = 0; // Ready to kick off the tesselator gluTessEndPolygon(GLUtessobj); // here it goes m_nvertex_max = m_nvmax; // record largest vertex count, updates in callback // Tesselation all done, so... // Create the data structures 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->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 // Recalculate the size of the geometry buffer unsigned int nptfinal = m_cntr[0] + 2; // for(int i=0 ; i < nint ; i++) // nptfinal += cntr[i+1] + 2; // No longer need the full geometry in the SENC, nptfinal = 1; m_nwkb = (nptfinal + 1) * 2 * sizeof(float); m_ppg_head->pgroup_geom = (float *)calloc(sizeof(float), (nptfinal + 1) * 2); 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, m_ref_lat, m_ref_lon, &easting, &northing); *vro++ = easting; // x *vro++ = northing; // y } else { *vro++ = tx; // lon *vro++ = ty; // lat } ppt++; // skip z } m_ppg_head->tri_prim_head = m_pTPG_Head; // head of linked list of TriPrims // Convert the Triangle vertex arrays into a single memory allocation of floats // to reduce SENC size and enable efficient access later // First calculate the total byte size int total_byte_size = 2 * sizeof(float); TriPrim *p_tp = m_ppg_head->tri_prim_head; while( p_tp ) { total_byte_size += p_tp->nVert * 2 * sizeof(float); p_tp = p_tp->p_next; // pick up the next in chain } float *vbuf = (float *)malloc(total_byte_size); p_tp = m_ppg_head->tri_prim_head; float *p_run = vbuf; while( p_tp ) { float *pfbuf = p_run; GLdouble *pdouble_buf = (GLdouble *)p_tp->p_vertex; for( int i=0 ; i < p_tp->nVert * 2 ; ++i){ float x = (float)( *((GLdouble *)pdouble_buf) ); pdouble_buf++; *p_run++ = x; } free(p_tp->p_vertex); p_tp->p_vertex = (double *)pfbuf; p_tp = p_tp->p_next; // pick up the next in chain } m_ppg_head->bsingle_alloc = true; m_ppg_head->single_buffer = (unsigned char *)vbuf; m_ppg_head->single_buffer_size = total_byte_size; m_ppg_head->data_type = DATA_TYPE_FLOAT; gluDeleteTess(GLUtessobj); free( m_pwork_buf ); m_pwork_buf = NULL; free (geoPt); // Free up any "Combine" vertices created for(unsigned int i = 0; i < m_pCombineVertexArray->GetCount() ; i++) free (m_pCombineVertexArray->Item(i)); delete m_pCombineVertexArray; m_bOK = true; return 0; }
void init (void) { GLUtesselator *tobj; GLdouble rect[4][3] = {50.0, 50.0, 0.0, 200.0, 50.0, 0.0, 200.0, 200.0, 0.0, 50.0, 200.0, 0.0}; GLdouble tri[3][3] = {75.0, 75.0, 0.0, 125.0, 175.0, 0.0, 175.0, 75.0, 0.0}; GLdouble star[5][6] = {250.0, 50.0, 0.0, 1.0, 0.0, 1.0, 325.0, 200.0, 0.0, 1.0, 1.0, 0.0, 400.0, 50.0, 0.0, 0.0, 1.0, 1.0, 250.0, 150.0, 0.0, 1.0, 0.0, 0.0, 400.0, 150.0, 0.0, 0.0, 1.0, 0.0}; glClearColor(0.0, 0.0, 0.0, 0.0); startList = glGenLists(2); tobj = gluNewTess(); gluTessCallback(tobj, GLU_TESS_VERTEX, glVertex3dv); gluTessCallback(tobj, GLU_TESS_BEGIN, beginCallback); gluTessCallback(tobj, GLU_TESS_END, endCallback); gluTessCallback(tobj, GLU_TESS_ERROR, errorCallback); /* rectangle with triangular hole inside */ glNewList(startList, GL_COMPILE); glShadeModel(GL_FLAT); gluTessBeginPolygon(tobj, NULL); gluTessBeginContour(tobj); gluTessVertex(tobj, rect[0], rect[0]); gluTessVertex(tobj, rect[1], rect[1]); gluTessVertex(tobj, rect[2], rect[2]); gluTessVertex(tobj, rect[3], rect[3]); gluTessEndContour(tobj); gluTessBeginContour(tobj); gluTessVertex(tobj, tri[0], tri[0]); gluTessVertex(tobj, tri[1], tri[1]); gluTessVertex(tobj, tri[2], tri[2]); gluTessEndContour(tobj); gluTessEndPolygon(tobj); glEndList(); gluTessCallback(tobj, GLU_TESS_VERTEX, vertexCallback); gluTessCallback(tobj, GLU_TESS_BEGIN, beginCallback); gluTessCallback(tobj, GLU_TESS_END, endCallback); gluTessCallback(tobj, GLU_TESS_ERROR, errorCallback); gluTessCallback(tobj, GLU_TESS_COMBINE, combineCallback); /* smooth shaded, self-intersecting star */ glNewList(startList + 1, GL_COMPILE); glShadeModel(GL_SMOOTH); gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE); gluTessBeginPolygon(tobj, NULL); gluTessBeginContour(tobj); gluTessVertex(tobj, star[0], star[0]); gluTessVertex(tobj, star[1], star[1]); gluTessVertex(tobj, star[2], star[2]); gluTessVertex(tobj, star[3], star[3]); gluTessVertex(tobj, star[4], star[4]); gluTessEndContour(tobj); gluTessEndPolygon(tobj); glEndList(); gluDeleteTess(tobj); }
int PolyTessGeo::BuildTessGL(void) { #ifdef ocpnUSE_GL int iir, ip; int *cntr; GLdouble *geoPt; wxString sout; wxString sout1; wxString stemp; #ifdef __WXMSW__ // If using the OpenGL dlls provided with Windows, // load the dll and establish addresses of the entry points needed #ifdef USE_GLU_DLL if(!s_glu_dll_ready) { s_hGLU_DLL = LoadLibrary("glu32.dll"); if (s_hGLU_DLL != NULL) { s_lpfnTessProperty = (LPFNDLLTESSPROPERTY)GetProcAddress(s_hGLU_DLL,"gluTessProperty"); s_lpfnNewTess = (LPFNDLLNEWTESS)GetProcAddress(s_hGLU_DLL, "gluNewTess"); s_lpfnTessBeginContour = (LPFNDLLTESSBEGINCONTOUR)GetProcAddress(s_hGLU_DLL, "gluTessBeginContour"); s_lpfnTessEndContour = (LPFNDLLTESSENDCONTOUR)GetProcAddress(s_hGLU_DLL, "gluTessEndContour"); s_lpfnTessBeginPolygon = (LPFNDLLTESSBEGINPOLYGON)GetProcAddress(s_hGLU_DLL, "gluTessBeginPolygon"); s_lpfnTessEndPolygon = (LPFNDLLTESSENDPOLYGON)GetProcAddress(s_hGLU_DLL, "gluTessEndPolygon"); s_lpfnDeleteTess = (LPFNDLLDELETETESS)GetProcAddress(s_hGLU_DLL, "gluDeleteTess"); s_lpfnTessVertex = (LPFNDLLTESSVERTEX)GetProcAddress(s_hGLU_DLL, "gluTessVertex"); s_lpfnTessCallback = (LPFNDLLTESSCALLBACK)GetProcAddress(s_hGLU_DLL, "gluTessCallback"); s_glu_dll_ready = true; } else { return ERROR_NO_DLL; } } #endif #endif // Allocate a work buffer, which will be grown as needed #define NINIT_BUFFER_LEN 10000 s_pwork_buf = (GLdouble *)malloc(NINIT_BUFFER_LEN * 2 * sizeof(GLdouble)); s_buf_len = NINIT_BUFFER_LEN * 2; s_buf_idx = 0; // Create an array to hold pointers to allocated vertices created by "combine" callback, // so that they may be deleted after tesselation. s_pCombineVertexArray = new wxArrayPtrVoid; // Create tesselator GLUtessobj = gluNewTess(); // Register the callbacks gluTessCallback(GLUtessobj, GLU_TESS_BEGIN, (GLvoid (__CALL_CONVENTION *) ())&beginCallback); gluTessCallback(GLUtessobj, GLU_TESS_BEGIN, (GLvoid (__CALL_CONVENTION *) ())&beginCallback); gluTessCallback(GLUtessobj, GLU_TESS_VERTEX, (GLvoid (__CALL_CONVENTION *) ())&vertexCallback); gluTessCallback(GLUtessobj, GLU_TESS_END, (GLvoid (__CALL_CONVENTION *) ())&endCallback); gluTessCallback(GLUtessobj, GLU_TESS_COMBINE, (GLvoid (__CALL_CONVENTION *) ())&combineCallback); // gluTessCallback(GLUtessobj, GLU_TESS_ERROR, (GLvoid (__CALL_CONVENTION *) ())&errorCallback); // glShadeModel(GL_SMOOTH); gluTessProperty(GLUtessobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); // gluTess algorithm internally selects vertically oriented triangle strips and fans. // This orientation is not optimal for conventional memory-mapped raster display shape filling. // We can "fool" the algorithm by interchanging the x and y vertex values passed to gluTessVertex // and then reverting x and y on the resulting vertexCallbacks. // In this implementation, we will explicitely set the preferred orientation. //Set the preferred orientation tess_orient = TESS_HORZ; // prefer horizontal tristrips // Get total number of contours m_ncnt = m_pxgeom->n_contours; // Allocate cntr array cntr = (int *)malloc(m_ncnt * sizeof(int)); // Get total number of points(vertices) int npta = m_pxgeom->contour_array[0]; cntr[0] = npta; npta += 2; // fluff for( iir=0 ; iir < m_ncnt-1 ; iir++) { int nptr = m_pxgeom->contour_array[iir+1]; cntr[iir+1] = nptr; npta += nptr + 2; // fluff } // printf("xgeom npta: %d\n", npta); geoPt = (GLdouble *)malloc((npta) * 3 * sizeof(GLdouble)); // vertex array // Grow the work buffer if necessary if((npta * 4) > s_buf_len) { s_pwork_buf = (GLdouble *)realloc(s_pwork_buf, npta * 4 * sizeof(GLdouble)); s_buf_len = npta * 4; } // Define the polygon gluTessBeginPolygon(GLUtessobj, NULL); // Create input structures // Exterior Ring int npte = m_pxgeom->contour_array[0]; cntr[0] = npte; GLdouble *ppt = geoPt; // Check and account for winding direction of ring bool cw = true; double x0, y0, x, y; OGRPoint p; wxPoint2DDouble *pp = m_pxgeom->vertex_array; pp++; // skip 0? if(cw) { // poly->getExteriorRing()->getPoint(0, &p); x0 = pp->m_x; y0 = pp->m_y; } else { // poly->getExteriorRing()->getPoint(npte-1, &p); x0 = pp[npte-1].m_x; y0 = pp[npte-1].m_y; // x0 = p.getX(); // y0 = p.getY(); } // pp++; gluTessBeginContour(GLUtessobj); // 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; // poly->getExteriorRing()->getPoint(pidx, &p); x = pp[pidx].m_x; y = pp[pidx].m_y; // pp++; if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS)) { GLdouble *ppt_temp = ppt; if(tess_orient == TESS_VERT) { *ppt++ = x; *ppt++ = y; } else { *ppt++ = y; *ppt++ = x; } *ppt++ = 0.0; gluTessVertex( GLUtessobj, ppt_temp, ppt_temp ) ; //printf("tess from xgeom, external vertex %g %g\n", x, y); } else cntr[0]--; x0 = x; y0 = y; } gluTessEndContour(GLUtessobj); int index_offset = npte; #if 1 // Now the interior contours for(iir=0; iir < m_ncnt-1; iir++) { gluTessBeginContour(GLUtessobj); // int npti = cntr[iir]; int npti = m_pxgeom->contour_array[iir+1]; // Check and account for winding direction of ring bool cw = false; //!(poly->getInteriorRing(iir)->isClockwise() == 0); if(!cw) { x0 = pp[index_offset].m_x; y0 = pp[index_offset].m_y; } else { x0 = pp[index_offset + npti-1].m_x; y0 = pp[index_offset + 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 + index_offset].m_x; y = pp[pidx + index_offset].m_y; if((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS)) { GLdouble *ppt_temp = ppt; if(tess_orient == TESS_VERT) { *ppt++ = x; *ppt++ = y; } else { *ppt++ = y; *ppt++ = x; } *ppt++ = 0.0; gluTessVertex( GLUtessobj, ppt_temp, ppt_temp ) ; // printf("tess from xgeom, internal vertex %d %g %g\n", ip, x, y); } else cntr[iir+1]--; x0 = x; y0 = y; } gluTessEndContour(GLUtessobj); index_offset += npti; } #endif // Store some SM conversion data in static store, // for callback access s_bSENC_SM = false; s_bmerc_transform = true; s_transform_x_rate = m_pxgeom->x_rate; s_transform_x_origin = m_pxgeom->x_offset; s_transform_y_rate = m_pxgeom->y_rate; s_transform_y_origin = m_pxgeom->y_offset; // Ready to kick off the tesselator s_pTPG_Last = NULL; s_pTPG_Head = NULL; s_nvmax = 0; gluTessEndPolygon(GLUtessobj); // here it goes m_nvertex_max = s_nvmax; // record largest vertex count, updates in callback // Tesselation all done, so... // Create the data structures m_ppg_head = new PolyTriGroup; m_ppg_head->m_bSMSENC = s_bSENC_SM; m_ppg_head->nContours = m_ncnt; m_ppg_head->pn_vertex = cntr; // pointer to array of poly vertex counts 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 == tess_orient) { ty = *ppt++; tx = *ppt++; } else { tx = *ppt++; ty = *ppt++; } if(0/*bSENC_SM*/) { // Calculate SM from chart common reference point double easting, northing; // toSM(ty, tx, ref_lat, ref_lon, &easting, &northing); *vro++ = easting; // x *vro++ = northing; // y } else { *vro++ = tx; // lon *vro++ = ty; // lat } ppt++; // skip z } m_ppg_head->tri_prim_head = s_pTPG_Head; // head of linked list of TriPrims // Convert the Triangle vertex arrays into a single memory allocation of floats // to reduce SENC size and enable efficient access later // First calculate the total byte size int total_byte_size = 2 * sizeof(float); TriPrim *p_tp = m_ppg_head->tri_prim_head; while( p_tp ) { total_byte_size += p_tp->nVert * 2 * sizeof(float); p_tp = p_tp->p_next; // pick up the next in chain } float *vbuf = (float *)malloc(total_byte_size); p_tp = m_ppg_head->tri_prim_head; float *p_run = vbuf; while( p_tp ) { float *pfbuf = p_run; GLdouble *pdouble_buf = (GLdouble *)p_tp->p_vertex; for( int i=0 ; i < p_tp->nVert * 2 ; ++i){ float x = (float)( *((GLdouble *)pdouble_buf) ); *p_run++ = x; pdouble_buf++; } free(p_tp->p_vertex); p_tp->p_vertex = (double *)pfbuf; p_tp = p_tp->p_next; // pick up the next in chain } m_ppg_head->bsingle_alloc = true; m_ppg_head->single_buffer = (unsigned char *)vbuf; m_ppg_head->single_buffer_size = total_byte_size; m_ppg_head->data_type = DATA_TYPE_FLOAT; gluDeleteTess(GLUtessobj); free( s_pwork_buf ); s_pwork_buf = NULL; free (geoPt); // All allocated buffers are owned now by the m_ppg_head // And will be freed on dtor of this object delete m_pxgeom; // Free up any "Combine" vertices created for(unsigned int i = 0; i < s_pCombineVertexArray->GetCount() ; i++) free (s_pCombineVertexArray->Item(i)); delete s_pCombineVertexArray; m_pxgeom = NULL; m_bOK = true; #endif //#ifdef ocpnUSE_GL return 0; }
nuiRenderObject* nuiTessellator::GenerateFromPath(float Quality) { nuiPath Points; mpPath->Tessellate(Points, Quality); uint count = Points.GetCount(); if (!count) return nullptr; gluTessNormal(mpTess, 0,0,1); gluTessProperty(mpTess,GLU_TESS_TOLERANCE, 0); gluTessCallback(mpTess, GLU_TESS_BEGIN_DATA, NUI_GLU_CALLBACK &nuiTessellator::StaticInternalTessBegin); gluTessCallback(mpTess, GLU_TESS_EDGE_FLAG_DATA,NUI_GLU_CALLBACK &nuiTessellator::StaticInternalTessEdgeFlag); gluTessCallback(mpTess, GLU_TESS_VERTEX_DATA, NUI_GLU_CALLBACK &nuiTessellator::StaticInternalTessVertex); gluTessCallback(mpTess, GLU_TESS_END_DATA, NUI_GLU_CALLBACK &nuiTessellator::StaticInternalTessEnd); gluTessCallback(mpTess, GLU_TESS_COMBINE_DATA, NUI_GLU_CALLBACK &nuiTessellator::StaticInternalTessCombine); gluTessCallback(mpTess, GLU_TESS_ERROR_DATA, NUI_GLU_CALLBACK &nuiTessellator::StaticInternalTessError); gluTessProperty(mpTess,GLU_TESS_BOUNDARY_ONLY, mOutline?GL_TRUE:GL_FALSE); gluTessProperty(mpTess,GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); mpObject = new nuiRenderObject(); mEdgeFlag = true; gluTessBeginPolygon(mpTess, this); bool beginNext = true; //printf("Start tesselation\n"); for (uint i = 0; i < count; i++) { nuiPoint& rPoint = Points[i]; if (rPoint.GetType() != nuiPointTypeStop) { if (beginNext) { gluTessBeginContour(mpTess); beginNext = false; } double vec[4] = { rPoint[0], rPoint[1], rPoint[2], 0 }; //printf("%d input %f %f\n", i, vec[0], vec[1]); gluTessVertex(mpTess, vec, (void*)mTempPoints.AddVertex(rPoint)); } else { //printf("End Contour\n"); gluTessEndContour(mpTess); beginNext = true; } } if (Points.Back().GetType() != nuiPointTypeStop) gluTessEndContour(mpTess); gluTessEndPolygon(mpTess); nuiRenderObject* pObject = mpObject; mpObject = NULL; mTempPoints.Clear(); return pObject; }