2017-02-12 16 views
-1

복잡한 다각형을 테셀레이션하기 위해 glu 테셀레이션을 사용합니다. 단순화 된 코드는 다음과 같습니다.gluTessEndPolygon()에서 항상 glutesselator가 충돌 함

그것은 항상 오류 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(); 
} 
+0

GLU 테셀레이터는 고대예요. 현대의 운전자가 철저히 테스트하지 않으면 놀라지 않을 것입니다. – 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 매개 변수의 호출 규칙은 동일하지 않으므로 문제가 발생합니다. 나는 호출 규칙에 많은주의를 기울이지 않았고 문제가 메모리 관리에 있다고 생각했다. –