Das Leid mit OpenGL und XPlatform
-
SFML und alle SDL haben beide das gleiche Problem:
Sie sind nicht dafür gemacht als reine WindowManager missbraucht zu werden. Sie kommen mit overhead und auch mit Funktionen die ich nicht brauche. Sie brauchen Platz, haben haufenweise Header usw.Mag jetzt pingelig sein, aber beide Libraries sind mir, naja ein Dorn im Auge ist jetzt zu harsch gesagt, ich meine das nicht böse. Sie passen einfach nicht zu meinen Anforderungen.
SDL weils mir zu C-Like ist und 1.3 nicht wirklich stabil atm und ums zu bauen muss man sich das ganze DirectX SDK installieren was mich schon per se ankotzt.
SFML hat das Problem, dass wenn man einen 3.3 Context erzeugt, es haufenweise Warnungen gibt, über veraltete Funktionen. Bzw seit ich nicht mehr GLew sondern gl3w verwende, eben crashes weil diese veralteten Funktionen mit gl3w nicht mehr geladen werden. Klar, ich kann die auskommentieren und mein privat-build machen, aber das ist störend und umständlich.
GLUT ist eigentlich genau das was ich brauche und möchte:
Es unterstützt ordentlich OpenGL in allen Versionen, es wird aktualisiert und ich brauch keine dreckigen Hacks implementieren um das zu erreichen was ich möchte. Ich hab sonst keine Library gefunden die als Window Manager für OpenGL3 dienen kann.
Nur, was nutzt mir das wenn ich nur Pointer auf Funktionen übergeben kann, aber nichtmal wenigstens nen UserPointer, der dann auf die Callbacks übergeben wird.Jetzt müsste man eigentlich mal eine C++-Library schreiben, die genau das anbietet. Ich traus mir nicht zu, da ich keine Kentnisse aufm Mac oder Linux für KDE/X/GNOME habe.
Irgendwelche Ideen? Ausser wieder mit Singletons um ich zu werfen? Ich bin grade ausgebrannt und würde am liebsten OpenGL.org anzünden. Nein Spaß, aber ich glaube ihr versteht mich :D.
-
Nur, was nutzt mir das wenn ich nur Pointer auf Funktionen übergeben kann, aber nichtmal wenigstens nen UserPointer, der dann auf die Callbacks übergeben wird.
Was meinst du damit?
-
Gnarpf schrieb:
Nur, was nutzt mir das wenn ich nur Pointer auf Funktionen übergeben kann, aber nichtmal wenigstens nen UserPointer, der dann auf die Callbacks übergeben wird.
Was meinst du damit?
Mmh, ganz einfach:
void reshape(int w, int h) {} glutReshapeFunc(reshape);
Soweit ist das kein Problem.
class myWindow { public: void reshape(int w, int h); };
Schon haste nen Problem.^^ GLUT und GLFW erlauben nicht das setzen von Userpointern damit man eben nen this-zeiger mitgeben könnte und die richtige Instanz deiner Klasse aufgerufen wird.
boost::bind habe ich bereits probiert, da ist keine Lösung dabei leider:glfwSetKeyCallback(boost::bind(&NLWindowGL::GLFWKeyPressCallback, boost::ref(*this), _1, _2)); glfwSetKeyCallback(boost::bind(&NLWindowGL::GLFWKeyPressCallback, this, _1, _2));
Error 1 error C2664: 'glfwSetKeyCallback' : cannot convert parameter 1 from 'boost::_bi::bind_t<R,F,L>' to 'GLFWkeyfun'
edit:
Würde GLUT oder GLFW einen Userpointer erlauben, wäre sowas möglich:class myWindow { public: myWindow() { glfwSetReshapeFunc(myWindow::sReshapeCallback, this); } static void sReshapeCallback(void* userptr, int w, int h) { myWindow* w = static_cast<myWindow*>(userptr); w->reshape(w, h); } void reshape(int w, int h) {} };
Schon könnte man auch mit C++ halbwegs sauber damit umgehen ohne auf ein Singleton zurückzugreifen.
Mit so einer Methode kann man ja auch die WinAPI sauber kapseln mit SetWindowsLong.
-
GLUT ist ja uralt, dass GLFW nichts dergleichen bietet wundert mich. Aber naja, mach das was diese Libraries machen einach selbst, so kompliziert ist das eigentlich gar nicht und du bekommst maximale Kontrolle.
-
dot schrieb:
GLUT ist ja uralt, dass GLFW nichts dergleichen bietet wundert mich. Aber naja, mach das was diese Libraries machen einach selbst, so kompliziert ist das eigentlich gar nicht und du bekommst maximale Kontrolle.
Ich hab jetzt folgende Lösung:
class myWindow { static myWindow* m_instance; static sGLFWReshapeCallback(int w, int h){ m_instance->reshape(int w, int h); } void reshape(int w, int h); void createWindow() { m_instance = this; /* ... */ } };
Nicht schön, aber selten.
Es gibt nur ein Fenster, daher kein Problem. Aber trotzdem bleibt halt der Beigeschmack des dreckigen Hacks. Leider.Selber machen.. ja, das ist halt wieder ne Tonne Arbeit, die ich mir ungern mache. Ich denke auf der anderen Seite käme so ein Wrapper eventuell gut an. Bin aber leider kein Profi der WinAPI.
-
Scorcher24 schrieb:
Ich hab jetzt folgende Lösung:
Also ein Singleton...
-
Ja, im Prinzip schon.
Aber ich setz mich jetzt hin und mach mir meinen eigenen Context. Den mach ich auch gleich kompatibel zu wxWidgets, dann brauch ich nicht den veralteten Context von wxWidgets nehmen. Wird halt wieder nen Stück Arbyte.
Aber damit opfer ich halt meine Crossplatform Fähigkeit. Und jetzt find mal wen der dir das auf X oder Mac portiert^^.
-
Wenn du das Ganze in ein GUI Toolkit integriert brauchst dann verwend doch einfach Qt, das hat afaik schon ein QGLWidget das alle Stücke spielt.
-
dot schrieb:
Wenn du das Ganze in ein GUI Toolkit integriert brauchst dann verwend doch einfach Qt, das hat afaik schon ein QGLWidget das alle Stücke spielt.
Jein, das ganze ist innerhalb meiner Library. Dort brauche ich keine Kompatibilität zu wxWidgets. Aber für mein Tools brauche ich die und wxWidgets hat für OpenGL leider keine Versionsauswahl wie das bei modernem OpenGL möglich ist. Ich kann aber die Schnittstellen so bauen, dass ich damit auf einen wxWidgets Panel zeichnen kann indem ich einfach das HWND des Panels nehme und darauf meinen Context erzeuge. Macht SFML im Prinzip genauso. Aber ich will meine Lib (die .dll direkt) nicht von QT abhängig machen. Auch nicht von wxWidgets. Und bei den Tools verwende ich bereits wie gesagt wxWidgets (persönliche Präferenz, kein Flamewar nötig welches besser ist :D).
-
Ah ok.
Scorcher24 schrieb:
(persönliche Präferenz, kein Flamewar nötig welches besser ist :D).
Keine Sorge ich find beide doof :p . Für Tools würd ich eher zu sowas wie C# greifen weil man damit viel schneller ans Ziel kommt
-
Ja, nur dann müsste ich wieder die komplette Engine dann später mit CLI C# tauglich machen. Neee danke dot.
-
Nicht wirklich, du müsstest nur eine Schnittstelle für exakt die Funktionalität des Editors anbieten. D.h. die lowlevel Editorlogik (die du sowieso schreiben musst) in C++/CLI mit deiner Engine schreiben und dann ein C# GUI draufsetzen. So hab ich zumindest vor das in Zukunft zu machen. Und meinen Erfahrungen nach erwart ich dass das ziemlich gut funktionieren sollte
Ich hab zumindest gelernt dass es keine gute Idee ist 1:1 zu wrappen und dann alles in C# zu machen. Wenn schon dann besser nicht einfach nur wrappen sondern gleich auch die Abstraktionsebene erhöhen. Das ist nicht nur evtl. besser für die Performance sondern sorgt eben wie gesagt vor allem dafür dass die Mehrarbeit des Wrapperschreibens wegfällt und sinnvolle Arbeit die sowieso gemacht werden müsste an ihre Stelle tritt.
-
Irrlicht unterstützt Win32, Mac und Linux ohne externe Abhängigkeiten und ist open source. Die Engine kannst du zwar nicht gebrauchen, die erstellt ja auch nur einen OpenGL 1.x Kontext, aber vielleicht kannst du dir da ja mal angucken wie die das machen.
-
cooky451 schrieb:
Irrlicht unterstützt Win32, Mac und Linux ohne externe Abhängigkeiten und ist open source. Die Engine kannst du zwar nicht gebrauchen, die erstellt ja auch nur einen OpenGL 1.x Kontext, aber vielleicht kannst du dir da ja mal angucken wie die das machen.
Ich weiss wie man nen Context erstellt. Nur ich wollte es mir ersparen das ganze selbst zu implementieren für versch. Platformen.
Mir gings aber hauptsächlich darum, dass OpenGL zwar von der spezifikation her XPlatform ist, aber die Erzeugung des Context ist nicht standardisiert und die vorhanden Tools wie GLUT sind nur rein auf C ausgelegt.
Es nervt einfach. Wie gesagt, ein userpointer würde alles einfacher machen. Vieeel einfacher.
-
Ich meinte ja nur, wo "selber machen" ja schon im Raum stand, es aber deiner Aussage nach am Know-How für Linux und Mac scheitern würde, könnte man sich ja mal angucken wie die das machen.
-
Du kannst dir doch von SFML einfach nur die Window-Klasse klauen. DIe ist ziemlich minimal. Sind glaub ich nur 2-3 Header und die Sources dazu. Und das gnaze sollte auch ohne Warnings durchlaufen. Im Gegensatz natürlich zu "RenderWindow" was wirklich veraltet Funktionen einsetzt.
Das anzupassen sollte dir auf jeden Fall weniger Arbeit machen, als da jetzt komplett selber was aus demn Boden zu stampfen.
//edit seh grad, die ist doch etwas mehr. Trotzdem verwenden.
-
otze schrieb:
Du kannst dir doch von SFML einfach nur die Window-Klasse klauen. DIe ist ziemlich minimal. Sind glaub ich nur 2-3 Header und die Sources dazu. Und das gnaze sollte auch ohne Warnings durchlaufen. Im Gegensatz natürlich zu "RenderWindow" was wirklich veraltet Funktionen einsetzt.
Das anzupassen sollte dir auf jeden Fall weniger Arbeit machen, als da jetzt komplett selber was aus demn Boden zu stampfen.
//edit seh grad, die ist doch etwas mehr. Trotzdem verwenden.
Naja, ich brauch eben das RenderWindow.
Ich habs jetzt in Klassen aufgeteilt:NLWindowWin32::NLWindowWin32() : NLIPlatformWindow(), m_isActive(true) { m_hInstance = GetModuleHandle(NULL); } NLWindowWin32::~NLWindowWin32() { // Destroy the Window ::DestroyWindow((HWND)m_hwnd); // Change Display back ::ChangeDisplaySettings(NULL, 0); // Unregister ::UnregisterClass(getWindowClassName(), m_hInstance); } bool NLWindowWin32::createWindow( const NLWindowSettings& settings ) { m_settings = settings; WNDCLASSEX wc; DWORD dwStyle = WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; // Different Style for Fullscreen if ( m_settings.fullscreen ) { dwStyle = WS_POPUP; } if ( m_settings.resizable && !m_settings.fullscreen ) { dwStyle = WS_OVERLAPPEDWINDOW; } // Fill WindowClass Structure with needed options wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)NLWindowWin32::sWinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = m_hInstance; wc.hIcon = ::LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = ::LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = 0; wc.lpszMenuName = NULL; wc.lpszClassName = getWindowClassName(); wc.hIconSm = ::LoadIcon(NULL, IDI_APPLICATION); // Register it if ( !::RegisterClassEx(&wc) ) { ::MessageBox(HWND_DESKTOP, L"RegisterClass() failed!", L"DXWindow", MB_ICONERROR|MB_OK); return false; } // Let Windows(TM) calculate the window size so our canvas is as big as we want it to have. m_wnd_rect.left = 0; m_wnd_rect.right = static_cast<long>(settings.width); m_wnd_rect.bottom = static_cast<long>(settings.height); m_wnd_rect.top = 0; ::AdjustWindowRectEx(&m_wnd_rect, dwStyle, FALSE, WS_EX_APPWINDOW); // Create Window m_hwnd = ::CreateWindowEx(WS_EX_APPWINDOW, getWindowClassName(), L"", dwStyle|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 50, 50, m_wnd_rect.right-m_wnd_rect.left, m_wnd_rect.bottom-m_wnd_rect.top, NULL, NULL, m_hInstance, NULL); // Window creation failed for some reason. if ( m_hwnd == NULL ) { ::MessageBox(HWND_DESKTOP, L"CreateWindowEx() failed!", L"NightLight2D", MB_ICONERROR|MB_OK); ::UnregisterClass(getWindowClassName(), m_hInstance); ChangeDisplaySettings(NULL, 0); return false; } // Go fullscreen // TODO: This code fails. if ( m_settings.fullscreen ) { DEVMODE dmVideoMode; memset(&dmVideoMode,0,sizeof(dmVideoMode)); dmVideoMode.dmSize = sizeof(dmVideoMode); dmVideoMode.dmPelsWidth = static_cast<DWORD>(m_settings.width); dmVideoMode.dmPelsHeight = static_cast<DWORD>(m_settings.height); dmVideoMode.dmBitsPerPel = m_settings.bpp; dmVideoMode.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; if (ChangeDisplaySettings(&dmVideoMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL ) { ::MessageBox(HWND_DESKTOP, L"ChangeDisplaySettings() failed!", L"NightLight2D", MB_ICONERROR|MB_OK); return false; } } // Set the userpointer ::SetWindowLongPtr((HWND)m_hwnd, GWL_USERDATA, reinterpret_cast<long>(this)); //Set caption ::SetWindowTextA((HWND)m_hwnd, m_settings.caption.c_str()); // Show Window and bring to the foreground, so it is topmost for now. ::ShowWindow((HWND)m_hwnd, true); ::SetForegroundWindow((HWND)m_hwnd); return true; } //------------------------------------------------------ // Event Pump //------------------------------------------------------ bool NLWindowWin32::pumpEvents() { // Main Loop MSG msg; while ( ::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) ) { if (msg.message == WM_QUIT) break; ::TranslateMessage(&msg); ::DispatchMessage(&msg); } if ( isRunning() ) return true; return false; } //------------------------------------------------------ // Real WinProc, gets called by sWinProc //------------------------------------------------------ LRESULT NLWindowWin32::WinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch(msg) { case WM_CLOSE: { // Leave loop m_isRunning = false; return 0; } case WM_KEYDOWN: { //return 0; break; } case WM_KEYUP: { //return 0; break; } case WM_MOUSEMOVE: { //return 0; break; } case WM_ACTIVATE: { m_isActive = (LOWORD(wParam) == 1); break; // return 0; } } return ::DefWindowProc(hwnd, msg, wParam, lParam); } //------------------------------------------------------ // Static member function which gets the user pointer // from the window and calls the correct object //------------------------------------------------------ LRESULT NLWindowWin32::sWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { NLWindowWin32* ptr = reinterpret_cast<NLWindowWin32*>(GetWindowLong(hwnd, GWL_USERDATA)); return ptr->WinProc(hwnd, msg, wParam, lParam); } //------------------------------------------------------ // Gets size of the desktop and calculates how the // window has to be positioned to be in the center. //------------------------------------------------------ void NLWindowWin32::center() { u32 screenWidth = GetSystemMetrics(SM_CXSCREEN); u32 screenHeight = GetSystemMetrics(SM_CYSCREEN); u32 left = (screenWidth / 2) - static_cast<u32>( m_settings.width / 2); u32 top = (screenHeight / 2) - static_cast<u32>( m_settings.height / 2); MoveWindow((HWND)m_hwnd, left, top, static_cast<int>(m_settings.width), static_cast<int>(m_settings.height), TRUE); } //////////////////////////////////////////////////////////////// NLContextWin32::NLContextWin32( NLWindowHandle hwnd, NLOpenGLSettings settings ) : NLIPlatformContext(hwnd, settings) { int pf = 0; PIXELFORMATDESCRIPTOR pfd = {0}; OSVERSIONINFO osvi = {0}; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); // Obtain HDC for this window. if (!(m_hdc = GetDC((HWND)m_hwnd))){ NLError("[NLContextWin32] GetDC() failed."); throw NLException("GetDC() failed.", true); } // Create and set a pixel format for the window. 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 = settings.BPP; pfd.cDepthBits = settings.BPP; pfd.iLayerType = PFD_MAIN_PLANE; // Obtain Windows Version if (!GetVersionEx(&osvi)) { NLError("[NLContextWin32] GetVersionEx() failed."); throw NLException("GetVersionEx() failed."); } // Get a pixelformat, based on our settings pf = ChoosePixelFormat(m_hdc, &pfd); // Set the pixelformat if (!SetPixelFormat(m_hdc, pf, &pfd)) { NLError("[NLContextWin32] GetVersionEx() failed."); throw NLException("SetPixelFormat() failed."); } // When running under Windows Vista or later support desktop composition. // This doesn't really apply when running in full screen mode. if (osvi.dwMajorVersion > 6 || (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 0)) pfd.dwFlags |= PFD_SUPPORT_COMPOSITION; // Verify that this OpenGL implementation supports the required extensions. std::string extensions = wglGetExtensionsStringARB(m_hdc); if (extensions.find("WGL_ARB_create_context") == std::string::npos){ NLError("[NLContextWin32] Required extension WGL_ARB_create_context is not supported."); throw NLException("[NLContextWin32] Required extension WGL_ARB_create_context is not supported."); } // Creates an OpenGL forward compatible rendering context. int attribList[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, settings.MAJOR, WGL_CONTEXT_MINOR_VERSION_ARB, settings.MINOR, WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, 0, 0 }; // First try creating an OpenGL context. if (!(m_hglrc = wglCreateContextAttribsARB(m_hdc, 0, attribList))) { // Fall back to an OpenGL 3.0 context. attribList[3] = 0; if (!(m_hglrc = wglCreateContextAttribsARB(m_hdc, 0, attribList))){ NLError("[NLContextWin32] wglCreateContextAttribsARB() failed for OpenGL 3 context."); throw NLException("wglCreateContextAttribsARB() failed for OpenGL 3 context.", true); } } if (!wglMakeCurrent(m_hdc, m_hglrc)){ NLError("[NLContextWin32] wglMakeCurrent() failed for OpenGL 3 context."); throw NLException("wglMakeCurrent() failed for OpenGL 3 context."); } // Init gl3w if ( gl3wInit() ){ std::stringstream ss; ss << std::string("[NLWindow] gl3wInit failed."); NLError(ss.str()); } // OpenGL Error Check { if ( !NLGLCheck(__FILE__, __LINE__) ){ NLError("[NLWindow] GLerror after gl3wInit() while gl3wInit() returned OK"); } } } NLContextWin32::~NLContextWin32() { if (m_hdc) { if (m_hglrc) { SystemController().getResourceManager().unload(); wglMakeCurrent(m_hdc, 0); wglDeleteContext(m_hglrc); } ReleaseDC((HWND)m_hwnd, m_hdc); } } void NLContextWin32::endRender() { #ifdef _DEBUG NLGLCheck(__FILE__, __LINE__); #endif ::SwapBuffers(m_hdc); } void NLContextWin32::beginRender() { wglMakeCurrent(m_hdc, m_hglrc); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); } // Basisklasse: struct NLOpenGLSettings { NLOpenGLSettings() : MAJOR(3), MINOR(0), BPP(24) {} int MAJOR; int MINOR; int BPP; }; class NLIPlatformContext { public: NLIPlatformContext(NLWindowHandle hwnd, NLOpenGLSettings settings) : m_settings(settings), m_hwnd(hwnd) {} virtual ~NLIPlatformContext() {} virtual void endRender() = 0; virtual void beginRender() = 0; inline void dumpOpenGLInfos(bool extensions) { // OpenGL char* gl_ven = (char*)glGetString(GL_VENDOR); char* gl_ver = (char*)glGetString(GL_VERSION); char* gl_render = (char*)glGetString(GL_RENDERER); char* gl_glslang= (char*)glGetString(GL_SHADING_LANGUAGE_VERSION); if ( gl_ven ) { NLMessage(std::string("[NLIPlatformContext] OpenGL Vendor String: ") + gl_ven); } if ( gl_ver ) { NLMessage(std::string("[NLIPlatformContext] OpenGL Version: ") + gl_ver); } if ( gl_render ) { NLMessage(std::string("[NLIPlatformContext] OpenGL Renderer: ") + gl_render); } if ( gl_glslang ) { NLMessage(std::string("[NLIPlatformContext] OpenGL Shader Version: ") + gl_glslang); } if ( extensions ) { // Get all Extensions NLStringVector v; GLint num_extensions; GLubyte* p = NULL; glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions); for ( int i=0; i < num_extensions; i++ ) { p = (GLubyte*) glGetStringi (GL_EXTENSIONS, i); if ( p ) v.push_back((char*)p); } SystemController().getLog().printExtensions(v); } } // Implemented inline to ensure it is always the same. inline void initOpenGL(f32 w, f32 h) { // Set Viewport glViewport(0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h)); // Clear Color glClearColor(m_clearcolor.r, m_clearcolor.g, m_clearcolor.b, m_clearcolor.a); // Misc. Options glEnable(GL_DEPTH_TEST); // Blend Func glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } inline void setClearColor(const NLColor4f& color) { m_clearcolor = color; glClearColor(m_clearcolor.r, m_clearcolor.g, m_clearcolor.b, m_clearcolor.a); } const NLColor4f& getClearColor() const { return m_clearcolor; } protected: NLWindowHandle m_hwnd; NLOpenGLSettings m_settings; NLColor4f m_clearcolor; };
Was jetzt noch fehlt ist das Key-Handling und mit so tieferen WinAPI Dingen wie Systemkeys abfragen, habe ich halt immer a bissl Probleme^^.
Egal ich krieg das schon hin, ich beiss mich durch :).
Ändert aber nix an meiner Kritik an GLUT. Dass SFML das nicht anbietet, dafür können die auch nix, die haben ja die Anforderung nicht an sich selbst OGL3 Konform zu sein.
SDL1.3 hat das, aber die Abhängigkeit zu DirectX macht das ganze zu komplex für evtl. Anwender der Lib.
-
GFWL wird mit Version 3 Userpointer akzeptieren für die Callbacks. So am rande :). Hab das vorhin erfahren. Ist aber noch instabil, daher keine Wahl momentan.
-
Scorcher24 schrieb:
GLUT ist eigentlich genau das was ich brauche und möchte:
Es unterstützt ordentlich OpenGL in allen Versionen, es wird aktualisiert und ich brauch keine dreckigen Hacks implementieren um das zu erreichen was ich möchte.Du meinst wohl FreeGlut und nicht das Original GLUT.
GLUT ist nämlich nicht nur total veraltet, sondern es wird seit AFAIK ca. > 10 Jahren nicht mehr weiterentwickelt.