2017-02-12 66 views
-1

我使用glu tessellation鑲嵌複雜的多邊形。下面列出了簡化的代碼。glutesselator總是崩潰在gluTessEndPolygon()

它總是在gluTessEndPolygon(GLUtessobj)崩潰,出現錯誤:

錯誤:0000005:訪問衝突讀取位置0x57783b39;

該代碼在多邊形的點數很少時起作用(< 100)。

我只是不明白爲什麼。

typedef boost::geometry::model::point<float, 2, boost::geometry::cs::cartesian> pt; 
typedef boost::geometry::model::polygon<pt> Polygon; 
typedef boost::geometry::model::ring<pt> Ring; 
vector<Polygon> g_myPolys; 


// ------Static variables used in glu tessellation------ 
static GLUtesselator *GLUtessobj; 
static unsigned int s_gltri_type; 
static int s_tess_orient; 
static int s_cur_pt_idx; 
// Create an array to hold pointers to allocated vertices created by "combine" callback, 
// so that they may be deleted after tessellation. 
static std::vector<GLdouble*>  s_combineVertexArray; 

// Store tessellated results 
static std::vector<double> s_vecTriVerts; // Store area objects' tessellated triangle(triangle fan, triangle strip and triangles) vertices. 
static std::vector<int> s_vecTriStripVertCnts; // Store every triangle strips' start indices in m_vecTriVerts. 
static std::vector<int> s_vecTriStripFirstIdx; // Store every triangle strips' vertex count start from its start index. 

static std::vector<int> s_vecTriFanVertCnts; // Store every triangle fans' start indices in m_vecTriVerts. 
static std::vector<int> s_vecTriFanFirstIdx; // Store every triangle fans' vertex count start from its start index. 

static std::vector<int> s_vecTrisVertCnts; // Store every triangles' start indices in m_vecTriVerts. 
static std::vector<int> s_vecTrisFirstIdx; // Store every triangles' vertex count start from its start index. 

static int s_cur_tri_fans_vert_cnt; 
static int s_cur_tri_strips_vert_cnt; 
static int s_cur_tris_vert_cnt; 

static std::vector<double*> s_vecTmp; 

void beginCallback(GLenum which) 
{ 
    s_gltri_type = which; 
    switch (s_gltri_type) 
    { 
    case GL_TRIANGLE_FAN: 
     s_vecTriFanFirstIdx.push_back(s_cur_pt_idx); 
     s_cur_tri_fans_vert_cnt = 0; 
     break; 
    case GL_TRIANGLE_STRIP: 
     s_vecTriStripFirstIdx.push_back(s_cur_pt_idx); 
     s_cur_tri_strips_vert_cnt = 0; 
     break; 
    case GL_TRIANGLES: 
     s_vecTrisFirstIdx.push_back(s_cur_pt_idx); 
     s_cur_tris_vert_cnt = 0; 
     break; 
    } 
} 


void vertexCallback(GLvoid *vertex) 
{ 
    GLdouble *pv = (GLdouble *) vertex; 
    s_vecTriVerts.push_back(pv[0]); 
    s_vecTriVerts.push_back(pv[1]); 

    s_cur_pt_idx ++; 

    switch (s_gltri_type) 
    { 
    case GL_TRIANGLE_FAN: 
     s_cur_tri_fans_vert_cnt ++; 
     break; 
    case GL_TRIANGLE_STRIP: 
     s_cur_tri_strips_vert_cnt ++; 
     break; 
    case GL_TRIANGLES: 
     s_cur_tris_vert_cnt ++; 
     break; 
    } 
} 

void combineCallback(GLdouble coords[3], 
    GLdouble *vertex_data[4], 
    GLfloat weight[4], GLdouble **dataOut) 
{ 
    GLdouble *vertex = (GLdouble *)malloc(6 * sizeof(GLdouble)); 

    vertex[0] = coords[0]; 
    vertex[1] = coords[1]; 
    vertex[2] = coords[2]; 
    vertex[3] = vertex[4] = vertex[5] = 0.0; 

    *dataOut = vertex; 

    s_combineVertexArray.push_back(vertex); 
} 

void endCallback() 
{ 
    switch (s_gltri_type) 
    { 
    case GL_TRIANGLE_FAN: 
     s_vecTriFanVertCnts.push_back(s_cur_tri_fans_vert_cnt); 
     break; 
    case GL_TRIANGLE_STRIP: 
     s_vecTriStripVertCnts.push_back(s_cur_tri_strips_vert_cnt); 
     break; 
    case GL_TRIANGLES: 
     s_vecTrisVertCnts.push_back(s_cur_tris_vert_cnt); 
     break; 
    } 
} 

void errorCallback(GLenum errorCode) 
{ 
    const GLubyte *estring; 
    estring = gluErrorString(errorCode); 
    printf ("Tessellation Error: %s\n", estring); 
} 

void Tessellate() 
{ 
    // Create tessellate object 
    GLUtessobj = gluNewTess(); 

    // Register the callbacks 
    gluTessCallback(GLUtessobj, GLU_TESS_BEGIN, (void (__stdcall*)())&beginCallback); 
    gluTessCallback(GLUtessobj, GLU_TESS_VERTEX, (void (__stdcall*)())&vertexCallback); 
    gluTessCallback(GLUtessobj, GLU_TESS_END,  (void (__stdcall*)())&endCallback); 
    gluTessCallback(GLUtessobj, GLU_TESS_COMBINE, (void (__stdcall*)())&combineCallback); 
    gluTessCallback(GLUtessobj, GLU_TESS_ERROR, (void (__stdcall*)())&errorCallback); 

    gluTessProperty(GLUtessobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE); 

    gluTessBeginPolygon(GLUtessobj, NULL); 
    gluTessBeginContour(GLUtessobj); 

    Polygon pp = g_myPolys[0]; 
    for (int i = 0; i < pp.outer().size(); i ++) 
    { 
     GLdouble *p = new GLdouble[3]; 
     s_vecTmp.push_back(p); 

     p[0] = pp.outer()[i].get<0>(); 
     p[1] = pp.outer()[i].get<1>(); 
     p[2] = 0.0; 

     gluTessVertex(GLUtessobj, p, p) ; 
    } 

    gluTessEndContour(GLUtessobj); 
    gluTessEndPolygon(GLUtessobj); 

    gluDeleteTess(GLUtessobj); 

    for (int i = 0; i < s_vecTmp.size(); i ++) 
     delete[] s_vecTmp[i]; 
    s_vecTmp.clear(); 

    // Free up any "Combine" vertices created 
    for(unsigned int i = 0; i < s_combineVertexArray.size(); i++) 
     free (s_combineVertexArray[i]); 
    s_combineVertexArray.clear(); 
} 
+0

只是提醒GLU Tessellator是古老的,如果現代司機不能徹底地測試它,我不會感到驚訝。 – SurvivalMachine

+0

@SurvivalMachine我必須修改舊版本的OpenGL。 OpenGL版本低於4.0有沒有更好的方法? –

+0

['libtess2'](https://github.com/memononen/libtess2)?另外,在[mcve]中進行編輯。 – genpfault

回答

1

有一件事立刻讓我覺得奇怪,那就是你在那裏做了演員__stdcall

gluTessCallback(GLUtessobj, GLU_TESS_BEGIN, (void (__stdcall*)())&beginCallback); 

你爲什麼這樣做?如果你的編譯器抱怨不兼容的調用約定,那麼你應該做的最後一件事就是拋出調用約定。如果您施行召集會議,只有絕望和恐懼等待。投射指針已經是個不錯的主意了(在C++中,從/到void*是可以的,但就是這樣)。

然後還有其他一些奇怪的事情,你用指針做。例如,您將std::vector與手動管理的內存(new GLdouble[3])混合在一起。真的,爲什麼?!

我強烈建議您簡化數據結構並清理指針雜耍。最有可能的是,你的代碼中有一些越界緩衝區寫入,但很難看到究竟在哪裏。

+0

回調和gluTessCallback 3rd參數的調用約定不完全相同,這會導致問題。我沒有十分注意調用約定,並認爲問題可能在於內存管理。 –