OpenGL - konkave Polygone zeichnen
-
Ich versuche gerade konkave Polygone mit OpenGL zu zeichnen. Ich orientiere mich an folgendem Beispiel: http://www.opengl.org/resources/code/samples/redbook/tess.c
Nach ein paar Sekunden stürzt mein Programm allerdings ab. Ich habe mal ein Minimalbeispiel geschrieben, dieses stürzt nach 20 Frames mit folgendem Backtrace ab:
#0 68FC2FC5 gluTessEndPolygon() (C:\WINDOWS\system32\glu32.dll:??) #1 F4457658 ??() (??:??) #2 01C914F9 ??() (??:??) #3 0022FE48 ??() (??:??) #4 004015B1 EndPolygon() (C:/.../main.c:83)Wichtig sind eigentlich nur die Funktionen am Anfang, die Funktion combineCallback habe ich komplett aus dem Beispiel übernommen.
Kann mir jemand irgendeinen Tipp geben, woran das liegen könnte? Ich bin total hilflos.
#include <windows.h> #include <GL/gl.h> #include <GL/glu.h> #include <stdlib.h> #include <stdio.h> GLUtesselator* tess; void beginCallback(GLenum which) { glBegin(which); } void vertexCallback(void *data) { glVertex3dv((GLdouble *)data); } void endCallback() { glEnd(); } void combineCallback(GLdouble coords[3], GLdouble *vertex_data[4], GLfloat weight[4], GLdouble **dataOut ) { GLdouble *vertex; int i; vertex = (GLdouble *) malloc(6 * sizeof(GLdouble)); vertex[0] = coords[0]; vertex[1] = coords[1]; vertex[2] = coords[2]; for (i = 3; i < 7; i++) vertex[i] = weight[0] * vertex_data[0][i] + weight[1] * vertex_data[1][i] + weight[2] * vertex_data[2][i] + weight[3] * vertex_data[3][i]; *dataOut = vertex; } void errorCallback(GLenum errorCode) { const GLubyte *estring; estring = gluErrorString(errorCode); fprintf(stderr, "Tessellation Error: %s\n", estring); exit(0); } void InitCallbacks() { tess = gluNewTess(); gluTessCallback(tess, GLU_TESS_BEGIN, beginCallback); gluTessCallback(tess, GLU_TESS_VERTEX, vertexCallback); gluTessCallback(tess, GLU_TESS_END, endCallback); gluTessCallback(tess, GLU_TESS_ERROR, errorCallback); gluTessCallback(tess, GLU_TESS_COMBINE, combineCallback); } void BeginPolygon() { gluTessBeginPolygon(tess, NULL); gluTessBeginContour(tess); } void Vertex(const double xposition, const double yposition) { double* temp = malloc(sizeof(double)*3); // Die müssen natürlich noch freigegeben werden, aber darum wollte ich mich später kümmern temp[0] = xposition; temp[1] = yposition; temp[2] = 0.0; gluTessVertex(tess, temp, temp); } void EndPolygon() { gluTessEndContour(tess); gluTessEndPolygon(tess); } LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); void EnableOpenGL(HWND hwnd, HDC*, HGLRC*); void DisableOpenGL(HWND, HDC, HGLRC); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex; HWND hwnd; HDC hDC; HGLRC hRC; MSG msg; BOOL bQuit = FALSE; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_OWNDC; wcex.lpfnWndProc = WindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wcex.lpszMenuName = NULL; wcex.lpszClassName = "GLSample"; wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);; if (!RegisterClassEx(&wcex)) return 0; hwnd = CreateWindowEx(0, "GLSample", "OpenGL Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 256, 256, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); EnableOpenGL(hwnd, &hDC, &hRC); InitCallbacks(); while (!bQuit) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { bQuit = TRUE; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); BeginPolygon(); Vertex(-1, -1); Vertex(1, 1); Vertex(-0.5, 0.5); Vertex(-1, 1); EndPolygon(); static int frameCnt = 0; printf("Frame %d\n", frameCnt++); SwapBuffers(hDC); } } DisableOpenGL(hwnd, hDC, hRC); DestroyWindow(hwnd); return msg.wParam; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); break; case WM_DESTROY: return 0; case WM_KEYDOWN: { switch (wParam) { case VK_ESCAPE: PostQuitMessage(0); break; } } break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC) { PIXELFORMATDESCRIPTOR pfd; int iFormat; *hDC = GetDC(hwnd); ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cDepthBits = 16; pfd.iLayerType = PFD_MAIN_PLANE; iFormat = ChoosePixelFormat(*hDC, &pfd); SetPixelFormat(*hDC, iFormat, &pfd); *hRC = wglCreateContext(*hDC); wglMakeCurrent(*hDC, *hRC); } void DisableOpenGL (HWND hwnd, HDC hDC, HGLRC hRC) { wglMakeCurrent(NULL, NULL); wglDeleteContext(hRC); ReleaseDC(hwnd, hDC); }
-
ok, ich hab jetz nicht dein Quelltext gelesen, aber warum nimmst du nicht einfas GL_TRIANGLE_FAN ?
-
Krux schrieb:
ok, ich hab jetz nicht dein Quelltext gelesen, aber warum nimmst du nicht einfas GL_TRIANGLE_FAN ?
Ich hab gehört, dass es in den meisten Implementierungen das gleiche ist wie GL_POLYGON. Hatte es auch schon ausprobiert, kam das selbe wie bei GL_POLYGON heraus. Kann damit zwar konkave Polygone machen, aber nur in einem gewissen Maße (alle Dreicke müssen einen gemeinsamen Punkt haben).
-
also, wenn du hilfe haben möchtest, dann bitte ich dich um einen kleineren Quelltext, der sich auf das Problem reduziert. Sonst kann und werde ich dir nicht helfen.
-
Krux schrieb:
also, wenn du hilfe haben möchtest, dann bitte ich dich um einen kleineren Quelltext, der sich auf das Problem reduziert. Sonst kann und werde ich dir nicht helfen.
Ok:
GLUtesselator* tess; void beginCallback(GLenum which) { glBegin(which); } void vertexCallback(void *data) { // Diese Funktion hab ich vereinfacht glVertex3dv((GLdouble *)data); } void endCallback() { glEnd(); } void combineCallback(GLdouble coords[3], GLdouble *vertex_data[4], GLfloat weight[4], GLdouble **dataOut ) { // Diese direkt aus dem Beispiel übernommen. GLdouble *vertex; int i; vertex = (GLdouble *) malloc(6 * sizeof(GLdouble)); vertex[0] = coords[0]; vertex[1] = coords[1]; vertex[2] = coords[2]; for (i = 3; i < 7; i++) vertex[i] = weight[0] * vertex_data[0][i] + weight[1] * vertex_data[1][i] + weight[2] * vertex_data[2][i] + weight[3] * vertex_data[3][i]; *dataOut = vertex; } void errorCallback(GLenum errorCode) { const GLubyte *estring; estring = gluErrorString(errorCode); fprintf(stderr, "Tessellation Error: %s\n", estring); exit(0); } void InitCallbacks() { // wird einmal am Anfang aufgerufen tess = gluNewTess(); gluTessCallback(tess, GLU_TESS_BEGIN, beginCallback); gluTessCallback(tess, GLU_TESS_VERTEX, vertexCallback); gluTessCallback(tess, GLU_TESS_END, endCallback); gluTessCallback(tess, GLU_TESS_ERROR, errorCallback); gluTessCallback(tess, GLU_TESS_COMBINE, combineCallback); } void BeginPolygon() { gluTessBeginPolygon(tess, NULL); gluTessBeginContour(tess); } void Vertex(const double xposition, const double yposition) { double* temp = malloc(sizeof(double)*3); // Die müssen natürlich noch freigegeben werden, aber darum wollte ich mich später kümmern temp[0] = xposition; temp[1] = yposition; temp[2] = 0.0; gluTessVertex(tess, temp, temp); } void EndPolygon() { gluTessEndContour(tess); gluTessEndPolygon(tess); // Hier stürzt es ab }
-
Ich hab das ganze mal unter Linux getestet und dort funktioniert es komischerweise. Es muss wohl irgendwas Windows spezifisches sein, dass zum Absturz führt. Vllt. liegts an den Callbacks?
-
ich glaube bei der mesa lib (die es ja als source gibt) gibt es auch eine implementierung fuer diese tesselierung und du koenntest unabhaengig von windows usw. tesselieren... vielleicht. ich hab die tesselierung noch nie benutzt, aber da noch niemand den tipp sagte

-
joomoo schrieb:
Ich hab das ganze mal unter Linux getestet und dort funktioniert es komischerweise. Es muss wohl irgendwas Windows spezifisches sein, dass zum Absturz führt. Vllt. liegts an den Callbacks?
Deine Vermutung ist richtig. Die Callbacks müssen die Aufrufkonvention stdcall haben! WEnn du glBegin und glEnd direkt benutzt, kannst du das folgender Maßen machen:
typedef void (__stdcall *TessFn)(); GLUtesselator* pTess = gluNewTess(); gluTessCallback(pTess,GLU_TESS_BEGIN,reinterpret_cast<TessFn>(glBegin)); gluTessCallback(pTess,GLU_TESS_END,glEnd); gluTessCallback(pTess,GLU_TESS_VERTEX,reinterpret_cast<TessFn>(glVertex3dv));Deine Combine-Funktion musst du dann in der Deklaration/Definition auch auf stdcall umstellen (standard in C++ ist ja cdecl).
MfG Pellaeon
-
Tausend Dank! Jetzt funktioniert's.