/* ** ClanLib SDK ** Copyright (c) 1997-2005 The ClanLib Team ** ** This software is provided 'as-is', without any express or implied ** warranty. In no event will the authors be held liable for any damages ** arising from the use of this software. ** ** Permission is granted to anyone to use this software for any purpose, ** including commercial applications, and to alter it and redistribute it ** freely, subject to the following restrictions: ** ** 1. The origin of this software must not be misrepresented; you must not ** claim that you wrote the original software. If you use this software ** in a product, an acknowledgment in the product documentation would be ** appreciated but is not required. ** 2. Altered source versions must be plainly marked as such, and must not be ** misrepresented as being the original software. ** 3. This notice may not be removed or altered from any source distribution. ** ** Note: Some of the libraries ClanLib may link to may have additional ** requirements or restrictions. ** ** File Author(s): ** ** Magnus Norddahl ** (if your name is missing here, please add it) */ #include "Display/display_precomp.h" #include "canvas_opengl.h" #include "API/Core/System/error.h" #include "API/Display/pixel_buffer.h" #include "API/Display/display.h" #include "API/Display/display_window.h" #include "API/Display/graphic_context.h" #include "API/GL/opengl_state.h" #include "API/GL/opengl_wrap.h" #ifdef WIN32 #include "WGL/display_window_opengl.h" #else #ifdef __APPLE__ #include "AGL/display_window_opengl.h" #else #include "GLX/display_window_opengl.h" #endif #endif #include "graphic_context_opengl.h" #include "surface_target_opengl.h" ///////////////////////////////////////////////////////////////////////////// // CL_Canvas_OpenGL construction: CL_Canvas_OpenGL::CL_Canvas_OpenGL() { CL_OpenGLState state(CL_Display::get_current_window()->get_gc()); state.set_active(); selected_surface = 0; gc = 0; pbuffer = 0; pbuffer_context = 0; #ifdef WIN32 pbuffer_dc = 0; if (wglCreatePbufferARB == 0) { wglCreatePbufferARB = (ptr_wglCreatePbufferARB) wglGetProcAddress("wglCreatePbufferARB"); wglCreatePbufferARB = (ptr_wglCreatePbufferARB) wglGetProcAddress("wglCreatePbufferARB"); wglGetPbufferDCARB = (ptr_wglGetPbufferDCARB) wglGetProcAddress("wglGetPbufferDCARB"); wglReleasePbufferDCARB = (ptr_wglReleasePbufferDCARB) wglGetProcAddress("wglReleasePbufferDCARB"); wglDestroyPbufferARB = (ptr_wglDestroyPbufferARB) wglGetProcAddress("wglDestroyPbufferARB"); wglQueryPbufferARB = (ptr_wglQueryPbufferARB) wglGetProcAddress("wglQueryPbufferARB"); } #else #ifndef __APPLE__ if (glXCreateGLXPbufferSGIX == 0) { glXCreateGLXPbufferSGIX = (ptr_glXCreateGLXPbufferSGIX) CL_OpenGL::get_proc_address("glXCreateGLXPbufferSGIX"); glXDestroyGLXPbufferSGIX = (ptr_glXDestroyGLXPbufferSGIX) CL_OpenGL::get_proc_address("glXDestroyGLXPbufferSGIX"); glXQueryGLXPbufferSGIX = (ptr_glXQueryGLXPbufferSGIX) CL_OpenGL::get_proc_address("glXQueryGLXPbufferSGIX"); glXSelectEventSGIX = (ptr_glXSelectEventSGIX) CL_OpenGL::get_proc_address("glXSelectEventSGIX"); glXGetSelectedEventSGIX = (ptr_glXGetSelectedEventSGIX) CL_OpenGL::get_proc_address("glXGetSelectedEventSGIX"); glXChooseFBConfigSGIX = (ptr_glXChooseFBConfigSGIX) CL_OpenGL::get_proc_address("glXChooseFBConfigSGIX"); glXCreateContextWithConfigSGIX = (ptr_glXCreateContextWithConfigSGIX) CL_OpenGL::get_proc_address("glXCreateContextWithConfigSGIX"); } #endif #endif pbuffer_changed = false; texture_changed = true; } CL_Canvas_OpenGL::~CL_Canvas_OpenGL() { delete gc; CL_OpenGLState state(CL_Display::get_current_window()->get_gc()); state.set_active(); #ifdef WIN32 if (pbuffer_context) wglDeleteContext(pbuffer_context); if (pbuffer_dc) wglReleasePbufferDCARB(pbuffer, pbuffer_dc); if (pbuffer) wglDestroyPbufferARB(pbuffer); #else #ifdef __APPLE__ if (pbuffer) aglDestroyPBuffer(pbuffer); if (pbuffer_context) aglDestroyContext(pbuffer_context); #else if (pbuffer_context) glXDestroyContext(CL_DisplayWindow_OpenGL::get_display(), pbuffer_context); if (pbuffer) glXDestroyGLXPbufferSGIX(CL_DisplayWindow_OpenGL::get_display(), pbuffer); #endif #endif } ///////////////////////////////////////////////////////////////////////////// // CL_Canvas_OpenGL attributes: CL_GraphicContext *CL_Canvas_OpenGL::get_gc() { if (selected_surface == 0) return 0; if (gc == 0) { // Create working pbuffer: #ifdef WIN32 if (wglCreatePbufferARB == 0) { throw CL_Error("WGL_ARB_pbuffer OpenGL extension not supported by this card"); } int attribList[1] = { 0 }; PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, // version number // PFD_DRAW_TO_WINDOW | // support window PFD_SUPPORT_OPENGL //| // support OpenGL //PFD_DOUBLEBUFFER | // double buffered //PFD_DEPTH_DONTCARE , // do you care about a zbuffer? PFD_TYPE_RGBA, // RGBA type 24, // 24-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 8, // no alpha buffer 0, // shift bit ignored 0, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 0, // z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored }; int pixelformat = ChoosePixelFormat(wglGetCurrentDC(), &pfd); // int pixelformat = GetPixelFormat(wglGetCurrentDC()); pbuffer = wglCreatePbufferARB( wglGetCurrentDC(), pixelformat, selected_surface->surface_size.width, selected_surface->surface_size.height, attribList); pbuffer_dc = wglGetPbufferDCARB(pbuffer); pbuffer_context = wglCreateContext(pbuffer_dc); if (!CL_DisplayWindow_OpenGL::opengl_contexts.empty()) { wglShareLists(CL_DisplayWindow_OpenGL::opengl_contexts.back(), pbuffer_context); } #else #ifdef __APPLE__ GLint attrib[] = { AGL_RGBA, AGL_NO_RECOVERY, AGL_DEPTH_SIZE, 24, AGL_CLOSEST_POLICY, AGL_NONE }; AGLPixelFormat pixelformat = aglChoosePixelFormat(NULL, 0, attrib); if (AGL_NO_ERROR != aglGetError()) throw CL_Error("Could not choose canvas pixel format: " + std::string((const char*)aglErrorString(aglGetError()))); pbuffer_context = aglCreateContext(pixelformat, CL_DisplayWindow_OpenGL::share_context); if (AGL_NO_ERROR != aglGetError()) throw CL_Error("Could not create canvas gl context: " + std::string((const char*)aglErrorString(aglGetError()))); if (GL_FALSE==aglCreatePBuffer( selected_surface->surface_size.width, selected_surface->surface_size.height, GL_TEXTURE_RECTANGLE_EXT, //GL_TEXTURE_2D, GL_RGBA, 0, &pbuffer) ) throw CL_Error("Could not create canvas PBuffer: " + std::string((const char*)aglErrorString(aglGetError()))); aglSetPBuffer(pbuffer_context, pbuffer, 0, 0, aglGetVirtualScreen(CL_DisplayWindow_OpenGL::share_context)); if (AGL_NO_ERROR != aglGetError()) throw CL_Error("Could not set up canvas PBuffer: " + std::string((const char*)aglErrorString(aglGetError()))); #else int scrnum; GLXFBConfig *fbconfig; XVisualInfo *visinfo; int nitems; int attrib[] = { GLX_DOUBLEBUFFER, False, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 1, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT, None }; int pbufAttrib[] = { GLX_PBUFFER_WIDTH, selected_surface->surface_size.width, GLX_PBUFFER_HEIGHT, selected_surface->surface_size.height, GLX_LARGEST_PBUFFER, False, None }; scrnum = DefaultScreen( CL_DisplayWindow_OpenGL::get_display() ); fbconfig = glXChooseFBConfig(CL_DisplayWindow_OpenGL::get_display(), scrnum, attrib, &nitems); if (NULL == fbconfig) { fprintf(stderr,"Error: couldn't get fbconfig\n"); exit(1); } pbuffer = glXCreatePbuffer(CL_DisplayWindow_OpenGL::get_display(), fbconfig[0], pbufAttrib); visinfo = glXGetVisualFromFBConfig(CL_DisplayWindow_OpenGL::get_display(), fbconfig[0]); if (!visinfo) { fprintf(stderr, "Error: couldn't get an RGBA, double-buffered visual\n"); exit(1); } pbuffer_context = glXCreateContext( CL_DisplayWindow_OpenGL::get_display(), visinfo, dynamic_cast(CL_Display::get_current_window()->get_gc()->impl)->get_context(), GL_TRUE ); if (!pbuffer_context) { fprintf(stderr, "Error: glXCreateContext failed\n"); exit(1); } XFree(fbconfig); XFree(visinfo); #endif #endif // Create GC interface for it: gc = new CL_GraphicContext(new CL_GraphicContext_OpenGL(this)); gc->set_cliprect(CL_Rect(0, 0, selected_surface->surface_size.width, selected_surface->surface_size.height)); // Download surface to pbuffer: pbuffer_changed = false; texture_changed = true; sync_pbuffer(); } return gc; } CL_PixelBuffer CL_Canvas_OpenGL::get_pixeldata(const CL_Rect &area) { if (selected_surface) return selected_surface->get_pixeldata (); else return CL_PixelBuffer(); } int CL_Canvas_OpenGL::get_width() const { if (selected_surface) return selected_surface->get_width(); return 0; } int CL_Canvas_OpenGL::get_height() const { if (selected_surface) return selected_surface->get_height(); return 0; } ///////////////////////////////////////////////////////////////////////////// // CL_Canvas_OpenGL operations: void CL_Canvas_OpenGL::set_pixeldata(const CL_Point &dest, const CL_Rect &src, const CL_PixelBuffer &data) { } void CL_Canvas_OpenGL::select_surface(CL_Surface_Generic *surface) { if (selected_surface) { sync_texture(); selected_surface->selected_canvas = 0; } if (surface == 0) { selected_surface = 0; pbuffer_changed = false; texture_changed = false; } else { selected_surface = (CL_Surface_Target_OpenGL *) surface->target; selected_surface->selected_canvas = this; pbuffer_changed = false; texture_changed = true; // alloc_pbuffer(); } } void CL_Canvas_OpenGL::sync_surface() { sync_texture(); } void CL_Canvas_OpenGL::sync_pbuffer() { if (texture_changed && gc != 0) { CL_OpenGLState state(gc); state.set_active(); // Setup down/up 2d projection matrix: clMatrixMode(CL_PROJECTION); clLoadIdentity(); CLdouble viewport[4]; clGetDoublev(CL_VIEWPORT, viewport); CLdouble width = viewport[2]; CLdouble height = viewport[3]; gluOrtho2D(0.0, width, 0.0, height); clMatrixMode(CL_MODELVIEW); clLoadIdentity(); // Copy texture to pbuffer: clEnable(CL_TEXTURE_2D); clBindTexture(CL_TEXTURE_2D, selected_surface->handle); clMatrixMode(CL_TEXTURE); CLdouble scale_matrix[16]; memset(scale_matrix, 0, sizeof(CLdouble)*16); scale_matrix[0] = 1.0f/float(selected_surface->texture_size.width); scale_matrix[5] = 1.0f/float(selected_surface->texture_size.height); scale_matrix[10] = 1.0f; scale_matrix[15] = 1.0f; clLoadMatrixd(scale_matrix); clMatrixMode(CL_MODELVIEW); clBegin(CL_QUADS); clColor3f(1.0f, 1.0f, 1.0f); clTexCoord2f(float(selected_surface->surface_size.width), 0.0f); clVertex2f(float(selected_surface->surface_size.width), 0.0f); clTexCoord2f(float(selected_surface->surface_size.width), float(selected_surface->surface_size.height)); clVertex2f(float(selected_surface->surface_size.width), float(selected_surface->surface_size.height)); clTexCoord2f(0.0f, float(selected_surface->surface_size.height)); clVertex2f(0.0f, float(selected_surface->surface_size.height)); clTexCoord2f(0.0f, 0.0f); clVertex2f(0.0f, 0.0f); clEnd(); #ifdef __APPLE__ clFlush(); #endif } texture_changed = false; } void CL_Canvas_OpenGL::sync_texture() { if (pbuffer_changed && gc != 0) { CL_OpenGLState state(gc); state.set_active(); // Copy pbuffer to texture: clEnable(CL_TEXTURE_2D); clBindTexture(CL_TEXTURE_2D, selected_surface->handle); clCopyTexSubImage2D( CL_TEXTURE_2D, 0, 0, 0, 0, 0, selected_surface->surface_size.width, selected_surface->surface_size.height); #ifdef __APPLE__ clFlush(); #endif } pbuffer_changed = false; } void CL_Canvas_OpenGL::set_pbuffer_modified() { pbuffer_changed = true; } ///////////////////////////////////////////////////////////////////////////// // CL_Canvas_OpenGL implementation: #ifdef WIN32 CL_Canvas_OpenGL::ptr_wglCreatePbufferARB CL_Canvas_OpenGL::wglCreatePbufferARB = 0; CL_Canvas_OpenGL::ptr_wglGetPbufferDCARB CL_Canvas_OpenGL::wglGetPbufferDCARB = 0; CL_Canvas_OpenGL::ptr_wglReleasePbufferDCARB CL_Canvas_OpenGL::wglReleasePbufferDCARB = 0; CL_Canvas_OpenGL::ptr_wglDestroyPbufferARB CL_Canvas_OpenGL::wglDestroyPbufferARB = 0; CL_Canvas_OpenGL::ptr_wglQueryPbufferARB CL_Canvas_OpenGL::wglQueryPbufferARB = 0; #else #ifndef __APPLE__ CL_Canvas_OpenGL::ptr_glXCreateGLXPbufferSGIX CL_Canvas_OpenGL::glXCreateGLXPbufferSGIX = 0; CL_Canvas_OpenGL::ptr_glXDestroyGLXPbufferSGIX CL_Canvas_OpenGL::glXDestroyGLXPbufferSGIX = 0; CL_Canvas_OpenGL::ptr_glXQueryGLXPbufferSGIX CL_Canvas_OpenGL::glXQueryGLXPbufferSGIX = 0; CL_Canvas_OpenGL::ptr_glXSelectEventSGIX CL_Canvas_OpenGL::glXSelectEventSGIX = 0; CL_Canvas_OpenGL::ptr_glXGetSelectedEventSGIX CL_Canvas_OpenGL::glXGetSelectedEventSGIX = 0; CL_Canvas_OpenGL::ptr_glXChooseFBConfigSGIX CL_Canvas_OpenGL::glXChooseFBConfigSGIX = 0; CL_Canvas_OpenGL::ptr_glXCreateContextWithConfigSGIX CL_Canvas_OpenGL::glXCreateContextWithConfigSGIX = 0; #endif #endif