glutesselator 总是在 gluTessEndPolygon() 处崩溃

glutesselator always crashes at gluTessEndPolygon()

本文关键字:崩溃 gluTessEndPolygon glutesselator      更新时间:2023-10-16

>我使用glu tessellation来细分复杂的多边形。下面列出了简化的代码。

它总是在gluTessEndPolygon(GLUtessobj)时崩溃并显示错误:

错误:0xC0000005:访问违规读取位置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: %sn", 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();
}

有一件事立即让我感到奇怪,那就是你在那里__stdcall演员表。

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

你为什么要这样做?如果您的编译器抱怨不兼容的调用约定,那么您应该做的最后一件事就是强制转换调用约定。只有绝望和恐惧在等待着你,如果你投下了一个召唤公约。投射指针已经是一个坏主意(C++投射从/到void*是可以的,但仅此而已(。

然后你用指针做了一些其他奇怪的事情。例如,您将std::vector与手动管理的内存 (new GLdouble[3] ( 混合在一起。说真的,为什么?!

我强烈建议您简化数据结构并清理指针杂耍。很可能你在代码的某处有一些越界缓冲区写入,但很难看出确切的位置。