/* FIXME: JUST DRAWS THE FIRST PIECE.. TODO: SUPPORT FOR FULLPOLY POLYGONS */ void hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale) { int vertex_count = 0; PLINE *contour; struct do_hole_info info; int stencil_bit; info.scale = scale; global_scale = scale; if (poly->Clipped == NULL) { fprintf (stderr, "hidgl_fill_pcb_polygon: poly->Clipped == NULL\n"); return; } stencil_bit = hidgl_assign_clear_stencil_bit (); if (!stencil_bit) { printf ("hidgl_fill_pcb_polygon: No free stencil bits, aborting polygon\n"); return; } /* Flush out any existing geoemtry to be rendered */ hidgl_flush_triangles (&buffer); /* Walk the polygon structure, counting vertices */ /* This gives an upper bound on the amount of storage required */ for (contour = poly->Clipped->contours; contour != NULL; contour = contour->next) vertex_count = MAX (vertex_count, contour->Count); info.vertices = malloc (sizeof(GLdouble) * vertex_count * 3); info.tobj = gluNewTess (); gluTessCallback(info.tobj, GLU_TESS_BEGIN, (_GLUfuncptr)myBegin); gluTessCallback(info.tobj, GLU_TESS_VERTEX, (_GLUfuncptr)myVertex); gluTessCallback(info.tobj, GLU_TESS_COMBINE, (_GLUfuncptr)myCombine); gluTessCallback(info.tobj, GLU_TESS_ERROR, (_GLUfuncptr)myError); glPushAttrib (GL_STENCIL_BUFFER_BIT); /* Save the write mask etc.. for final restore */ glEnable (GL_STENCIL_TEST); glPushAttrib (GL_STENCIL_BUFFER_BIT | /* Resave the stencil write-mask etc.., and */ GL_COLOR_BUFFER_BIT); /* the colour buffer write mask etc.. for part way restore */ glStencilMask (stencil_bit); /* Only write to our stencil bit */ glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, ref value is our bit */ glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */ glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value */ /* Drawing operations now set our reference bit in the stencil buffer */ r_search (poly->Clipped->contour_tree, clip_box, NULL, do_hole, &info); hidgl_flush_triangles (&buffer); glPopAttrib (); /* Restore the colour and stencil buffer write-mask etc.. */ glStencilOp (GL_KEEP, GL_KEEP, GL_INVERT); /* This allows us to toggle the bit on any subcompositing bitplane */ /* If the stencil test has passed, we know that bit is 0, so we're */ /* effectively just setting it to 1. */ glStencilFunc (GL_GEQUAL, 0, assigned_bits); /* Pass stencil test if all assigned bits clear, */ /* reference is all assigned bits so we set */ /* any bits permitted by the stencil writemask */ /* Drawing operations as masked to areas where the stencil buffer is '0' */ /* Draw the polygon outer */ tesselate_contour (info.tobj, poly->Clipped->contours, info.vertices, scale); hidgl_flush_triangles (&buffer); /* Unassign our stencil buffer bit */ hidgl_return_stencil_bit (stencil_bit); glPopAttrib (); /* Restore the stencil buffer write-mask etc.. */ gluDeleteTess (info.tobj); myFreeCombined (); free (info.vertices); }
work(LLRegion &r) : region(r) { tobj = gluNewTess(); }
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); }
/* ARGSUSED4 */ static void draw_cut_style_cap_callback (int iloop, double cap[][3], float face_color[3], gleDouble cut_vector[3], gleDouble bisect_vector[3], double norms[][3], int frontwards) { int i; #ifdef OPENGL_10 GLUtriangulatorObj *tobj; tobj = gluNewTess (); gluTessCallback (tobj, GLU_BEGIN, (void (CALLBACK*)()) glBegin); gluTessCallback (tobj, GLU_VERTEX, (void (CALLBACK*)()) glVertex3dv); gluTessCallback (tobj, GLU_END, (void (CALLBACK*)()) glEnd); #endif /* OPENGL_10 */ if (face_color != NULL) C3F (face_color); if (frontwards) { /* if lighting is on, specify the endcap normal */ if (cut_vector != NULL) { /* if normal pointing in wrong direction, flip it. */ if (cut_vector[2] < 0.0) { VEC_SCALE (cut_vector, -1.0, cut_vector); } N3F_D (cut_vector); } #ifdef GL_32 BGNPOLYGON(); for (i=0; i<iloop; i++) { V3F_D (cap[i], i, FRONT_CAP); } ENDPOLYGON(); #endif /* GL_32 */ #ifdef OPENGL_10 gluBeginPolygon (tobj); for (i=0; i<iloop; i++) { gluTessVertex (tobj, cap[i], cap[i]); } gluEndPolygon (tobj); #endif /* OPENGL_10 */ } else { /* if lighting is on, specify the endcap normal */ if (cut_vector != NULL) { /* if normal pointing in wrong direction, flip it. */ if (cut_vector[2] > 0.0) { VEC_SCALE (cut_vector, -1.0, cut_vector); } N3F_D (cut_vector); } /* the sense of the loop is reversed for backfacing culling */ #ifdef GL_32 BGNPOLYGON(); for (i=iloop-1; i>-1; i--) { V3F_D (cap[i], i, BACK_CAP); } ENDPOLYGON(); #endif /* GL_32 */ #ifdef OPENGL_10 gluBeginPolygon (tobj); for (i=iloop-1; i>-1; i--) { gluTessVertex (tobj, cap[i], cap[i]); } gluEndPolygon (tobj); #endif /* OPENGL_10 */ } #ifdef OPENGL_10 gluDeleteTess (tobj); #endif /* OPENGL_10 */ }
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; }
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 extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize, GLdouble thickness, GLuint side, GLuint edge, GLuint whole) { static GLUtriangulatorObj *tobj = NULL; GLdouble vertex[3], dx, dy, len; int i; int count = dataSize / (2 * sizeof(GLfloat)); if (tobj == NULL) { tobj = gluNewTess(); /* create and initialize a GLU polygon * * tesselation object */ gluTessCallback(tobj, GLU_BEGIN, (void (CALLBACK*)()) glBegin); gluTessCallback(tobj, GLU_VERTEX, (void (CALLBACK*)()) glVertex2fv); /* semi-tricky */ gluTessCallback(tobj, GLU_END, (void (CALLBACK*)()) glEnd); } glNewList(side, GL_COMPILE); glShadeModel(GL_SMOOTH); /* smooth minimizes seeing tessellation */ gluBeginPolygon(tobj); for (i = 0; i < count; i++) { vertex[0] = data[i][0]; vertex[1] = data[i][1]; vertex[2] = 0; gluTessVertex(tobj, vertex, data[i]); } gluEndPolygon(tobj); glEndList(); glNewList(edge, GL_COMPILE); glShadeModel(GL_FLAT); /* flat shade keeps angular hands from being * * "smoothed" */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= count; i++) { /* mod function handles closing the edge */ glVertex3f(data[i % count][0], data[i % count][1], 0.0); glVertex3f(data[i % count][0], data[i % count][1], thickness); /* Calculate a unit normal by dividing by Euclidean distance. We * could be lazy and use glEnable(GL_NORMALIZE) so we could pass in * arbitrary normals for a very slight performance hit. */ dx = data[(i + 1) % count][1] - data[i % count][1]; dy = data[i % count][0] - data[(i + 1) % count][0]; len = sqrt(dx * dx + dy * dy); glNormal3f(dx / len, dy / len, 0.0); } glEnd(); glEndList(); glNewList(whole, GL_COMPILE); glFrontFace(GL_CW); glCallList(edge); glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */ glCallList(side); glPushMatrix(); glTranslatef(0.0, 0.0, thickness); glFrontFace(GL_CCW); glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */ glCallList(side); glPopMatrix(); glEndList(); }
/** 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); }
/** 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(); } }*/ }
int Tesselate (Tcl_Interp *interp, int argc, char* argv []) { int result = TCL_OK; int icoord = 0; int edgeflags = 1; int iarg; GLUtriangulatorObj* obj; int dlist = -1; GLdouble coord [3]; GLfloat* vtx; GLfloat* vtxptr; globalinterp = interp; globalresult = TCL_OK; for (iarg = 2; iarg < argc; iarg++) { int len = (int)strlen (argv [iarg]); if (strncmp (argv [iarg], "-displaylist", len) == 0) { iarg++; if (iarg == argc) { Tcl_AppendResult (interp, "not enough arguments", (char*)NULL); return TCL_ERROR; } if (strcmp (argv [iarg], "none") == 0) { dlist = 0; } else if (Tcl_GetInt (interp, argv [iarg], &dlist) != TCL_OK) { Tcl_AppendResult (interp, "\nError parsing display list number", (char*) NULL); return TCL_ERROR; } } else if (strncmp (argv [iarg], "-noedgeflags", len) == 0) { edgeflags = 0; } else break; } if (argc - iarg < 9) { Tcl_AppendResult (interp, "Not enough vertices", (char*) NULL); return TCL_ERROR; } obj = gluNewTess(); vtx = (GLfloat*) malloc (sizeof (GLfloat) * (argc - iarg)); vtxptr = vtx; assert (vtx != NULL); gluTessCallback(obj, GLU_BEGIN, glBegin); gluTessCallback(obj, GLU_VERTEX, glVertex3fv); gluTessCallback(obj, GLU_END, glEnd); gluTessCallback(obj, GLU_ERROR, (TessCallback) TessError); if (edgeflags) gluTessCallback (obj, GLU_EDGE_FLAG, (TessCallback) glEdgeFlag); if (dlist == -1) dlist = glGenLists (1); if (dlist != 0) glNewList (dlist, GL_COMPILE); gluBeginPolygon (obj); for (; iarg < argc; iarg++) { int len = (int)strlen (argv [iarg]); if (strncmp (argv [iarg], "-contour", len) == 0) { gluNextContour (obj, GLU_UNKNOWN); } else { if (Tcl_GetDouble (interp, argv [iarg], &coord[icoord]) != TCL_OK) { Tcl_AppendResult (interp, "\nError parsing tesselation vertex coord", (char*) NULL); result = TCL_ERROR; break; } else { icoord = (icoord+1)%3; if (icoord == 0) { *(vtxptr) = (GLfloat)coord [0]; *(vtxptr+1) = (GLfloat)coord [1]; *(vtxptr+2) = (GLfloat)coord [2]; gluTessVertex (obj, coord, vtxptr); vtxptr += 3; } } } } gluEndPolygon (obj); gluDeleteTess (obj); free (vtx); if (dlist != 0) glEndList(); if (result != TCL_OK || globalresult != TCL_OK) { if (dlist != 0) glDeleteLists (dlist, 1); return TCL_ERROR; } if (dlist != 0) { char tmp[128]; sprintf (tmp, "%d", dlist); Tcl_SetResult(interp, tmp, TCL_VOLATILE); } return TCL_OK; }
//---------------------------------------------------------- void ofBeginShape(){ if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing(); // just clear the vertices, just to make sure that // someone didn't do something improper, like : // a) ofBeginShape() // b) ofVertex(), ofVertex(), ofVertex() .... // c) ofBeginShape() // etc... clearTessVertices(); // now get the tesselator object up and ready: tobj = gluNewTess(); // -------------------------------------------------------- // note: you could write your own begin and end callbacks // if you wanted to... // for example, to count triangles or know which // type of object tess is giving back, etc... // -------------------------------------------------------- // #if defined( TARGET_WIN32) || defined( TARGET_LINUX ) || defined( MAC_OS_X_VERSION_10_5 ) // gluTessCallback( tobj, GLU_TESS_BEGIN, (void(CALLBACK*)())&glBegin); // gluTessCallback( tobj, GLU_TESS_VERTEX, (void(CALLBACK*)())&tessVertex); // gluTessCallback( tobj, GLU_TESS_COMBINE, (void(CALLBACK*)())&tessCombine); // gluTessCallback( tobj, GLU_TESS_END, (void(CALLBACK*)())&glEnd); // gluTessCallback( tobj, GLU_TESS_ERROR, (void(CALLBACK*)())&tessError); // #else // // xcode / osx complained, so we write it the way that makes it happy: // gluTessCallback( tobj, GLU_TESS_BEGIN, (void(CALLBACK*)(...))&glBegin); // gluTessCallback( tobj, GLU_TESS_VERTEX, (void(CALLBACK*)(...))&tessVertex); // gluTessCallback( tobj, GLU_TESS_COMBINE, (void(CALLBACK*)(...))&tessCombine); // gluTessCallback( tobj, GLU_TESS_END, (void(CALLBACK*)(...))&glEnd); // gluTessCallback( tobj, GLU_TESS_ERROR, (void(CALLBACK*)(...))&tessError); // #endif gluTessProperty( tobj, GLU_TESS_WINDING_RULE, polyMode); if (drawMode == OF_OUTLINE){ gluTessProperty( tobj, GLU_TESS_BOUNDARY_ONLY, true); } else { gluTessProperty( tobj, GLU_TESS_BOUNDARY_ONLY, false); } gluTessProperty( tobj, GLU_TESS_TOLERANCE, 0); /* ------------------------------------------ for 2d, this next call (normal) likely helps speed up .... quote : The computation of the normal represents about 10% of the computation time. For example, if all polygons lie in the x-y plane, you can provide the normal by using the ------------------------------------------- */ gluTessNormal(tobj, 0.0, 0.0, 1.0); gluTessBeginPolygon( tobj, NULL); }
/* 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; }
/* 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 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 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); }
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; }
GLUtriangulatorObj* gluauxNewTess (void) { GLUtriangulatorObj* tessobj = gluNewTess(); create(tessobj); return tessobj; }
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 GFXSystem::init() // that's the constructor of the system dependent // object used for the SDL port { unsigned char *keyboard; int size; Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif if(SDL_Init(SDL_INIT_EVERYTHING) < 0) { error("Couldn't initialize SDL: %s\n", SDL_GetError()); } //atexit(Sound_Quit); // atexit(SDL_Quit); /* if (TTF_Init() < 0) { fprintf(stderr, "Couldn't initialize TTF: %s\n", SDL_GetError()); exit(1); } atexit(TTF_Quit); int rendersolid = 0; int renderstyle = 0; int rendertype = 0; int ptsize = 11; font = TTF_OpenFont("verdana.ttf", ptsize); if (font == NULL) { fprintf(stderr, "Couldn't load %d pt font from %s: %s\n", ptsize, "verdana.ttf", SDL_GetError()); exit(2); } TTF_SetFontStyle(font, renderstyle);*/ SDL_WM_SetCaption("Alone in the dark \"GL\"", "AITD"); // SDL_ShowCursor (SDL_DISABLE); // SDL_EnableUNICODE (SDL_ENABLE); // not much used in fact SDL_PumpEvents(); keyboard = SDL_GetKeyState(&size); keyboard[SDLK_RETURN] = 0; sdl_screen = SDL_SetVideoMode(800, 600, 32, SDL_OPENGL/*|SDL_FULLSCREEN*/); if(sdl_screen == NULL) { error("Couldn't set 640x480x32 video mode: %s\n", SDL_GetError()); } _mouseLeft = 0; _mouseRight = 0; glEnable(GL_TEXTURE_2D); //glEnable(GL_CULL_FACE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glViewport(0, 0, 800, 600); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background glMatrixMode(GL_PROJECTION); // Select The Projection Matrix glLoadIdentity(); // Reset The Projection Matrix glOrtho(0, 320, 200, 0, 0.2, -100 * 1000); glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity(); // Reset The Modelview Matrix modelsDisplayList = glGenLists(1); // Create a new tessellation object tobj = gluNewTess(); // Set callback functions gluTessCallback(tobj, GLU_TESS_VERTEX, (GLvoid( *)())vertexCallback); gluTessCallback(tobj, GLU_TESS_BEGIN, (GLvoid( *)())glBegin); gluTessCallback(tobj, GLU_TESS_END, glEnd); gluTessCallback(tobj, GLU_TESS_COMBINE, (GLvoid( *)())combineCallback); gluTessCallback(tobj, GLU_TESS_VERTEX, (GLvoid( *)())vertexCallback); gluTessCallback(tobj, GLU_TESS_BEGIN, (GLvoid( *)())glBegin); gluTessCallback(tobj, GLU_TESS_END, glEnd); gluTessCallback(tobj, GLU_TESS_COMBINE, (GLvoid( *)())combineCallback); // init debug font #if 0 #ifdef INTERNAL_DEBUGGER glGenTextures(1, &debugFontTexture); glBindTexture(GL_TEXTURE_2D, debugFontTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, debugFont); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #endif #endif // SDL_mixer init if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 1, 2048) == -1) { error("Mix_OpenAudio: %s\n", Mix_GetError()); } Mix_HookMusic(OPL_musicPlayer, NULL); // configure offset mode glPolygonOffset(1, 2); // generate textures { int i; int j; unsigned char ditherMap[256*256*4]; unsigned char *tempPtr = ditherMap; for(i = 0; i < 256; i++) { for(j = 0; j < 256; j++) { unsigned char ditherValue = g_fitd->randRange(0, 0x50); *(tempPtr++) = ditherValue; *(tempPtr++) = ditherValue; *(tempPtr++) = ditherValue; *(tempPtr++) = 255; } } //glBlendFunc(GL_SRC_ALPHA,GL_ONE); glGenTextures(1, &ditherTexture); glBindTexture(GL_TEXTURE_2D, ditherTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, ditherMap); glBindTexture(GL_TEXTURE_2D, 0); glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_1D); } // quadrics init sphere = gluNewQuadric(); }
// 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); }
GLUTriangulator::GLUTriangulator() { tess = gluNewTess(); gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLUTessCallback)_faceBegin); gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLUTessCallback)_faceVertex); gluTessCallback(tess, GLU_TESS_END_DATA, (GLUTessCallback)_faceEnd); }
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); }
// Build PolyTessGeo Object from OGR Polygon // Using OpenGL/GLU tesselator int PolyTessGeo::PolyTessGeoGL(OGRPolygon *poly, bool bSENC_SM, double ref_lat, double ref_lon) { #ifdef ocpnUSE_GL int iir, ip; int *cntr; GLdouble *geoPt; wxString sout; wxString sout1; wxString stemp; // 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; #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 // PolyGeo BBox as lat/lon OGREnvelope Envelope; poly->getEnvelope(&Envelope); xmin = Envelope.MinX; ymin = Envelope.MinY; xmax = Envelope.MaxX; ymax = Envelope.MaxY; // Get total number of contours m_ncnt = 1; // always exterior ring int nint = poly->getNumInteriorRings(); // interior rings m_ncnt += nint; // Allocate cntr array cntr = (int *)malloc(m_ncnt * sizeof(int)); // Get total number of points(vertices) int npta = poly->getExteriorRing()->getNumPoints(); cntr[0] = npta; npta += 2; // fluff for( iir=0 ; iir < nint ; iir++) { int nptr = poly->getInteriorRing(iir)->getNumPoints(); cntr[iir+1] = nptr; npta += nptr + 2; } // printf("pPoly 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 = poly->getExteriorRing()->getNumPoints(); cntr[0] = npte; GLdouble *ppt = geoPt; // Check and account for winding direction of ring bool cw = !(poly->getExteriorRing()->isClockwise() == 0); double x0, y0, x, y; OGRPoint p; if(cw) { poly->getExteriorRing()->getPoint(0, &p); x0 = p.getX(); y0 = p.getY(); } else { poly->getExteriorRing()->getPoint(npte-1, &p); x0 = p.getX(); y0 = p.getY(); } // Transcribe contour to an array of doubles, with duplicates eliminated double *DPbuffer = (double *)malloc(npte * 2 * sizeof(double)); double *DPrun = DPbuffer; int nPoints = npte; for(ip = 0 ; ip < npte ; ip++) { int pidx; if(cw) pidx = npte - ip - 1; else pidx = ip; poly->getExteriorRing()->getPoint(pidx, &p); x = p.getX(); y = p.getY(); if( ((fabs(x-x0) > EQUAL_EPS) || (fabs(y-y0) > EQUAL_EPS))) { GLdouble *ppt_temp = ppt; if(tess_orient == TESS_VERT) { *DPrun++ = x; *DPrun++ = y; } else { *DPrun++ = y; *DPrun++ = x; } x0 = x; y0 = y; } else nPoints--; } if(nPoints > 5 && (m_LOD_meters > .01)){ index_keep.Clear(); index_keep.Add(0); index_keep.Add(nPoints-1); index_keep.Add(1); index_keep.Add(nPoints-2); DouglasPeucker(DPbuffer, 1, nPoints-2, m_LOD_meters/(1852 * 60), &index_keep); // printf("DP Reduction: %d/%d\n", index_keep.GetCount(), nPoints); g_keep += index_keep.GetCount(); g_orig += nPoints; // printf("...................Running: %g\n", (double)g_keep/g_orig); } else { index_keep.Clear(); for(int i = 0 ; i < nPoints ; i++) index_keep.Add(i); } cntr[0] = index_keep.GetCount(); // Mark the keepers by adding a simple constant to X for(unsigned int i=0 ; i < index_keep.GetCount() ; i++){ int k = index_keep.Item(i); DPbuffer[2*k] += 2000.; } // Declare the gluContour and copy the points gluTessBeginContour(GLUtessobj); DPrun = DPbuffer; for(ip = 0 ; ip < nPoints ; ip++) { x = *DPrun++; y = *DPrun++; if(x > 1000.){ GLdouble *ppt_top = ppt; *ppt++ = x-2000; *ppt++ = y; *ppt++ = 0; gluTessVertex( GLUtessobj, ppt_top, ppt_top ) ; } } gluTessEndContour(GLUtessobj); free(DPbuffer); // Now the interior contours for(iir=0 ; iir < nint ; iir++) { gluTessBeginContour(GLUtessobj); int npti = poly->getInteriorRing(iir)->getNumPoints(); // Check and account for winding direction of ring bool cw = !(poly->getInteriorRing(iir)->isClockwise() == 0); if(!cw) { poly->getInteriorRing(iir)->getPoint(0, &p); x0 = p.getX(); y0 = p.getY(); } else { poly->getInteriorRing(iir)->getPoint(npti-1, &p); x0 = p.getX(); y0 = p.getY(); } // 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; poly->getInteriorRing(iir)->getPoint(pidx, &p); x = p.getX(); y = p.getY(); 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 Poly, internal vertex %d %g %g\n", ip, x, y); } else cntr[iir+1]--; x0 = x; y0 = y; } gluTessEndContour(GLUtessobj); } // Store some SM conversion data in static store, // for callback access s_ref_lat = ref_lat; s_ref_lon = ref_lon; s_bSENC_SM = bSENC_SM; s_bmerc_transform = false; // 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 // Recalculate the size of the geometry buffer int nptfinal = 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 == tess_orient) { ty = *ppt++; tx = *ppt++; } else { tx = *ppt++; ty = *ppt++; } if(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) ); 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( s_pwork_buf ); s_pwork_buf = NULL; free (geoPt); // 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_bOK = true; #endif // #ifdef ocpnUSE_GL return 0; }
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 ; } } }
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 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); }
/* Mark Kilgard's tessellation code from the "dino" demos. */ void extrudeSolidFromPolygon(GLfloat data[][3], unsigned int dataSize, GLdouble thickness, GLuint side, GLuint edge, GLuint whole) { GLdouble vertex[3], dx, dy, len; int i, k; int flag = 0; int count = dataSize / (3 * sizeof(GLfloat)); static GLUtriangulatorObj *tobj = NULL; if (tobj == NULL) { tobj = gluNewTess(); gluTessCallback(tobj, GLU_BEGIN, glBegin); gluTessCallback(tobj, GLU_VERTEX, glVertex3fv); gluTessCallback(tobj, GLU_END, glEnd); } glNewList(side, GL_COMPILE); glShadeModel(GL_SMOOTH); gluBeginPolygon(tobj); for(i = 0; i < count; i++) { /* This detects a new contour from a large number placed in the unused z coordinate of the vertex where the new contour starts. See the coordinates for letterO, above. The coordinate must be reset below for additional calls. */ if (data[i][2] > 1000.0) { data[i][2] = 0.0; flag = 1; k = i; gluNextContour(tobj, GLU_INTERIOR); } vertex[0] = data[i][0]; vertex[1] = data[i][1]; vertex[2] = 0.0; gluTessVertex(tobj, vertex, data[i]); } gluEndPolygon(tobj); glEndList(); /* Reset coordinate for new calls. */ if (flag == 1) { data[k][2] = 10000.0; flag = 0; } glNewList(edge, GL_COMPILE); glBegin(GL_QUAD_STRIP); for(i = 0; i <= count; i++) { glVertex3f(data[i % count][0], data[i % count][1], 0.0); glVertex3f(data[i % count][0], data[i % count][1], thickness); /* Normals */ dx = data[(i+ 1) % count][1] - data[i % count][1]; dy = data[i % count][0] - data[(i + 1) % count][0]; len = sqrt(dx * dx + dy * dy); glNormal3f(dx / len, dy / len, 0.0); } glEnd(); glEndList(); glNewList(whole, GL_COMPILE); glFrontFace(GL_CW); glMaterialfv(GL_FRONT, GL_DIFFUSE, edgeColor); glMaterialfv(GL_FRONT, GL_SHININESS, shininess); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glCallList(edge); glNormal3f(0.0, 0.0, -1.0); glCallList(side); glPushMatrix(); glTranslatef(0.0, 0.0, thickness); glFrontFace(GL_CCW); glNormal3f(0.0, 0.0, 1.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, sideColor); glMaterialfv(GL_FRONT, GL_SHININESS, shininess); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glCallList(side); glPopMatrix(); glEndList(); }
gint gv_area_tessellate(GvArea *in_area) { typedef void (*f); static GLUtesselator *tess = NULL; GArray *ring; GvVertex *v; int i, j; GLdouble coords[3]; if (!tess) { tess = gluNewTess(); g_return_val_if_fail(tess, FALSE); gluTessCallback(tess, GLU_TESS_BEGIN, (f) tess_begin); gluTessCallback(tess, GLU_TESS_END, (f) tess_end); gluTessCallback(tess, GLU_TESS_VERTEX,(f) tess_vertex); gluTessCallback(tess, GLU_TESS_ERROR, (f) tess_error); } /* Global is available to all tess callbacks */ area = in_area; /* Check for short ring lengths */ if (!check_ring_lengths()) return FALSE; /* Fix ring winding before tesselation */ check_winding(); area->fill_objects = 0; if (area->fill) { g_array_set_size(area->fill, 0); g_array_set_size(area->mode_offset, 0); } else { area->fill = g_array_new(FALSE, FALSE, sizeof(GvVertex)); area->mode_offset = g_array_new(FALSE, FALSE, sizeof(gint)); } coords[2] = 0.0; gluTessBeginPolygon(tess, NULL); for (i=0; i < area->rings->len; ++i) { ring = gv_areas_get_ring(area, i); gluTessBeginContour(tess); for (j=0; j < ring->len; ++j) { v = &g_array_index(ring, GvVertex, j); coords[0] = (GLdouble)v->x; coords[1] = (GLdouble)v->y; gluTessVertex(tess, coords, v); } gluTessEndContour(tess); } gluTessEndPolygon(tess); return (area->fill_objects > 0 && g_array_index(area->mode_offset,gint,0) != GV_TESS_NONE); }