glutesselator总是在gluTessEndPolygon()

时间:2017-02-12 14:36:00

标签: c++ opengl glu tessellation

我使用glu镶嵌来镶嵌复杂的多边形。下面列出了简化的代码。

它始终在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: %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();
}

1 个答案:

答案 0 :(得分:1)

有一件事让我感到奇怪的是,你在那里进行了__stdcall

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

你为什么这样做?如果你的编译器抱怨不兼容的调用约定,那么你应该做的最后一件事就是强制转换调用约定。如果你施行召唤大会,只有绝望和恐怖等待。编译指针已经是一个坏主意(在C ++中从/向void*转换是好的,但那就是它。)

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

我强烈建议您简化数据结构并清理指针杂乱。很可能你的代码中有一些超出范围的缓冲区写入,但很难确切地看到。