/* Create an OpenGL context without creating an OpenGL Window. for Windows. For more info: http://www.nullterminator.net/opengl32.html by Blaine Hodge http://msdn.microsoft.com/en-us/library/ee418815(v=vs.85).aspx http://www.cprogramming.com/tutorial/wgl_wiggle_functions.html by RoD ( which includes robot.cc by Steven Billington ) http://blogs.msdn.com/b/oldnewthing/archive/2006/12/04/1205831.aspx by Tom */ #undef NOGDI #include #include #include "OffscreenContext.h" #include "printutils.h" #include "imageutils.h" #include "system-gl.h" #include "fbo.h" #include // must be included after glew.h #include #include #include using namespace std; struct OffscreenContext { HWND window; HDC dev_context; HGLRC openGLContext; int width; int height; fbo_t *fbo; }; #include "OffscreenContextAll.hpp" void offscreen_context_init(OffscreenContext &ctx, int width, int height) { ctx.window = (HWND)NULL; ctx.dev_context = (HDC)NULL; ctx.openGLContext = (HGLRC)NULL; ctx.width = width; ctx.height = height; ctx.fbo = NULL; } string get_os_info() { OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); SYSTEM_INFO si; GetSystemInfo(&si); map archs; archs[PROCESSOR_ARCHITECTURE_AMD64] = "amd64"; archs[PROCESSOR_ARCHITECTURE_IA64] = "itanium"; archs[PROCESSOR_ARCHITECTURE_INTEL] = "x86"; archs[PROCESSOR_ARCHITECTURE_UNKNOWN] = "unknown"; stringstream out; out << "OS info: " << "Microsoft(TM) Windows(TM) " << osvi.dwMajorVersion << " " << osvi.dwMinorVersion << " " << osvi.dwBuildNumber << " " << osvi.szCSDVersion; if (archs.find(si.wProcessorArchitecture) != archs.end()) out << " " << archs[si.wProcessorArchitecture]; out << "\n"; out << "Machine: " << si.dwProcessorType; return out.str(); } string offscreen_context_getinfo(OffscreenContext *ctx) { // should probably get some info from WGL context here? stringstream out; out << "GL context creator: WGL\n" << "PNG generator: lodepng\n" << get_os_info(); return out.str(); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { return DefWindowProc( hwnd, message, wparam, lparam ); } bool create_wgl_dummy_context(OffscreenContext &ctx) { // this function alters ctx->window and ctx->openGLContext // and ctx->dev_context if successfull // create window HINSTANCE inst = GetModuleHandle(0); WNDCLASS wc; ZeroMemory( &wc, sizeof( wc ) ); wc.style = CS_OWNDC; wc.lpfnWndProc = WndProc; wc.hInstance = inst; wc.lpszClassName = L"OpenSCAD"; ATOM class_atom = RegisterClassW( &wc ); if ( class_atom == 0 ) { cerr << "MS GDI - RegisterClass failed\n"; cerr << "last-error code: " << GetLastError() << "\n"; return false; } LPCTSTR lpClassName = L"OpenSCAD"; LPCTSTR lpWindowName = L"OpenSCAD"; DWORD dwStyle = WS_CAPTION | WS_POPUPWINDOW; // | WS_VISIBLE int x = 0; int y = 0; int nWidth = ctx.width; int nHeight = ctx.height; HWND hWndParent = NULL; HMENU hMenu = NULL; HINSTANCE hInstance = inst; LPVOID lpParam = NULL; HWND window = CreateWindowW( lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam ); if ( window==NULL ) { cerr << "MS GDI - CreateWindow failed\n"; cerr << "last-error code: " << GetLastError() << "\n"; return false; } // create WGL context, make current PIXELFORMATDESCRIPTOR pixformat; int chosenformat; HDC dev_context = GetDC( window ); if ( dev_context == NULL ) { cerr << "MS GDI - GetDC failed\n"; cerr << "last-error code: " << GetLastError() << "\n"; return false; } ZeroMemory( &pixformat, sizeof( pixformat ) ); pixformat.nSize = sizeof( pixformat ); pixformat.nVersion = 1; pixformat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pixformat.iPixelType = PFD_TYPE_RGBA; pixformat.cGreenBits = 8; pixformat.cRedBits = 8; pixformat.cBlueBits = 8; pixformat.cAlphaBits = 8; pixformat.cDepthBits = 24; pixformat.cStencilBits = 8; chosenformat = ChoosePixelFormat( dev_context, &pixformat ); if (chosenformat==0) { cerr << "MS GDI - ChoosePixelFormat failed\n"; cerr << "last-error code: " << GetLastError() << "\n"; return false; } bool spfok = SetPixelFormat( dev_context, chosenformat, &pixformat ); if (!spfok) { cerr << "MS GDI - SetPixelFormat failed\n"; cerr << "last-error code: " << GetLastError() << "\n"; return false; } HGLRC gl_render_context = wglCreateContext( dev_context ); if ( gl_render_context == NULL ) { cerr << "MS WGL - wglCreateContext failed\n"; cerr << "last-error code: " << GetLastError() << "\n"; ReleaseDC( ctx.window, ctx.dev_context ); return false; } bool mcok = wglMakeCurrent( dev_context, gl_render_context ); if (!mcok) { cerr << "MS WGL - wglMakeCurrent failed\n"; cerr << "last-error code: " << GetLastError() << "\n"; return false; } ctx.window = window; ctx.dev_context = dev_context; ctx.openGLContext = gl_render_context; return true; } OffscreenContext *create_offscreen_context(int w, int h) { OffscreenContext *ctx = new OffscreenContext; offscreen_context_init( *ctx, w, h ); // Before an FBO can be setup, a WGL context must be created. // This call alters ctx->window and ctx->openGLContext // and ctx->dev_context if successfull if (!create_wgl_dummy_context( *ctx )) { return NULL; } return create_offscreen_context_common( ctx ); } bool teardown_offscreen_context(OffscreenContext *ctx) { if (ctx) { fbo_unbind(ctx->fbo); fbo_delete(ctx->fbo); wglMakeCurrent( NULL, NULL ); wglDeleteContext( ctx->openGLContext ); ReleaseDC( ctx->window, ctx->dev_context ); return true; } return false; } bool save_framebuffer(OffscreenContext *ctx, std::ostream &output) { if (!ctx) return false; wglSwapLayerBuffers( ctx->dev_context, WGL_SWAP_MAIN_PLANE ); return save_framebuffer_common( ctx, output ); }