2017-02-12 67 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参数的调用约定不完全相同,这会导致问题。我没有十分注意调用约定,并认为问题可能在于内存管理。 –