1 /*
2 
3 Create an OpenGL context without creating an OpenGL Window. for Windows.
4 
5 For more info:
6 
7    http://www.nullterminator.net/opengl32.html by Blaine Hodge
8    http://msdn.microsoft.com/en-us/library/ee418815(v=vs.85).aspx
9    http://www.cprogramming.com/tutorial/wgl_wiggle_functions.html by RoD
10     ( which includes robot.cc by Steven Billington )
11    http://blogs.msdn.com/b/oldnewthing/archive/2006/12/04/1205831.aspx by Tom
12 */
13 
14 #undef NOGDI
15 #include <windows.h>
16 #include <vector>
17 
18 #include "OffscreenContext.h"
19 #include "printutils.h"
20 #include "imageutils.h"
21 #include "system-gl.h"
22 #include "fbo.h"
23 
24 #include <GL/gl.h> // must be included after glew.h
25 
26 #include <map>
27 #include <string>
28 #include <sstream>
29 
30 struct OffscreenContext
31 {
32   HWND window;
33   HDC dev_context;
34   HGLRC openGLContext;
35   int width;
36   int height;
37   fbo_t *fbo;
38 };
39 
40 #include "OffscreenContextAll.hpp"
41 
offscreen_context_init(OffscreenContext & ctx,int width,int height)42 void offscreen_context_init(OffscreenContext &ctx, int width, int height)
43 {
44   ctx.window = (HWND)nullptr;
45   ctx.dev_context = (HDC)nullptr;
46   ctx.openGLContext = (HGLRC)nullptr;
47   ctx.width = width;
48   ctx.height = height;
49   ctx.fbo = nullptr;
50 }
51 
get_os_info()52 std::string get_os_info()
53 {
54   OSVERSIONINFO osvi;
55 
56   ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
57   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
58   GetVersionEx(&osvi);
59 
60   SYSTEM_INFO si;
61   GetSystemInfo(&si);
62 	std::map<WORD,const char*> archs;
63   archs[PROCESSOR_ARCHITECTURE_AMD64] = "amd64";
64   archs[PROCESSOR_ARCHITECTURE_IA64] = "itanium";
65   archs[PROCESSOR_ARCHITECTURE_INTEL] = "x86";
66   archs[PROCESSOR_ARCHITECTURE_UNKNOWN] = "unknown";
67 
68 	std::ostringstream out;
69   out << "OS info: "
70       << "Microsoft(TM) Windows(TM) " << osvi.dwMajorVersion << " "
71       << osvi.dwMinorVersion << " " << osvi.dwBuildNumber << " "
72       << osvi.szCSDVersion;
73   if (archs.find(si.wProcessorArchitecture) != archs.end())
74     out << " " << archs[si.wProcessorArchitecture];
75   out << "\n";
76 
77   out << "Machine: " << si.dwProcessorType;
78 
79   return out.str();
80 }
81 
offscreen_context_getinfo(OffscreenContext *)82 std::string offscreen_context_getinfo(OffscreenContext * /*ctx*/)
83 {
84   // should probably get some info from WGL context here?
85   return STR("GL context creator: WGL\n" <<
86 						 "PNG generator: lodepng\n" <<
87 						 get_os_info());
88 }
89 
WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)90 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
91 {
92   return DefWindowProc( hwnd, message, wparam, lparam );
93 }
94 
create_wgl_dummy_context(OffscreenContext & ctx)95 bool create_wgl_dummy_context(OffscreenContext &ctx)
96 {
97   // this function alters ctx->window and ctx->openGLContext
98   //  and ctx->dev_context if successful
99 
100   // create window
101 
102   HINSTANCE inst = GetModuleHandleW(0);
103   WNDCLASSW wc;
104   ZeroMemory( &wc, sizeof( wc ) );
105   wc.style = CS_OWNDC;
106   wc.lpfnWndProc = WndProc;
107   wc.hInstance = inst;
108   wc.lpszClassName = L"OpenSCAD";
109   ATOM class_atom = RegisterClassW( &wc );
110 
111   if ( class_atom == 0 ) {
112 		std::cerr << "MS GDI - RegisterClass failed\n";
113     std::cerr << "last-error code: " << GetLastError() << "\n";
114     return false;
115   }
116 
117   LPCTSTR lpClassName = L"OpenSCAD";
118   LPCTSTR lpWindowName = L"OpenSCAD";
119   DWORD dwStyle = WS_CAPTION | WS_POPUPWINDOW; // | WS_VISIBLE
120   int x = 0;
121   int y = 0;
122   int nWidth = ctx.width;
123   int nHeight = ctx.height;
124   HWND hWndParent = nullptr;
125   HMENU hMenu = nullptr;
126   HINSTANCE hInstance = inst;
127   LPVOID lpParam = nullptr;
128 
129   HWND window = CreateWindowW( lpClassName, lpWindowName, dwStyle, x, y,
130     nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam );
131 
132   if ( window==nullptr ) {
133     std::cerr << "MS GDI - CreateWindow failed\n";
134     std::cerr << "last-error code: " << GetLastError() << "\n";
135     return false;
136   }
137 
138   // create WGL context, make current
139 
140   PIXELFORMATDESCRIPTOR pixformat;
141   int chosenformat;
142   HDC dev_context = GetDC( window );
143   if ( dev_context == nullptr ) {
144     std::cerr << "MS GDI - GetDC failed\n";
145     std::cerr << "last-error code: " << GetLastError() << "\n";
146     return false;
147   }
148 
149   ZeroMemory( &pixformat, sizeof( pixformat ) );
150   pixformat.nSize = sizeof( pixformat );
151   pixformat.nVersion = 1;
152   pixformat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
153   pixformat.iPixelType = PFD_TYPE_RGBA;
154   pixformat.cGreenBits = 8;
155   pixformat.cRedBits = 8;
156   pixformat.cBlueBits = 8;
157   pixformat.cAlphaBits = 8;
158   pixformat.cDepthBits = 24;
159   pixformat.cStencilBits = 8;
160 
161   chosenformat = ChoosePixelFormat( dev_context, &pixformat );
162   if (chosenformat==0) {
163     std::cerr << "MS GDI - ChoosePixelFormat failed\n";
164     std::cerr << "last-error code: " << GetLastError() << "\n";
165     return false;
166   }
167 
168   bool spfok = SetPixelFormat( dev_context, chosenformat, &pixformat );
169   if (!spfok) {
170     std::cerr << "MS GDI - SetPixelFormat failed\n";
171     std::cerr << "last-error code: " << GetLastError() << "\n";
172     return false;
173   }
174 
175   HGLRC gl_render_context = wglCreateContext( dev_context );
176   if ( gl_render_context == nullptr ) {
177       std::cerr << "MS WGL - wglCreateContext failed\n";
178 			std::cerr << "last-error code: " << GetLastError() << "\n";
179       ReleaseDC( ctx.window, ctx.dev_context );
180       return false;
181   }
182 
183   bool mcok = wglMakeCurrent( dev_context, gl_render_context );
184   if (!mcok) {
185     std::cerr << "MS WGL - wglMakeCurrent failed\n";
186     std::cerr << "last-error code: " << GetLastError() << "\n";
187     return false;
188   }
189 
190   ctx.window = window;
191   ctx.dev_context = dev_context;
192   ctx.openGLContext = gl_render_context;
193 
194   return true;
195 }
196 
197 
create_offscreen_context(int w,int h)198 OffscreenContext *create_offscreen_context(int w, int h)
199 {
200   OffscreenContext *ctx = new OffscreenContext;
201   offscreen_context_init( *ctx, w, h );
202 
203   // Before an FBO can be setup, a WGL context must be created.
204   // This call alters ctx->window and ctx->openGLContext
205   //  and ctx->dev_context if successful
206   if (!create_wgl_dummy_context( *ctx )) {
207     return nullptr;
208   }
209 
210   return create_offscreen_context_common( ctx );
211 }
212 
teardown_offscreen_context(OffscreenContext * ctx)213 bool teardown_offscreen_context(OffscreenContext *ctx)
214 {
215   if (ctx) {
216     fbo_unbind(ctx->fbo);
217     fbo_delete(ctx->fbo);
218 
219     wglMakeCurrent( nullptr, nullptr );
220     wglDeleteContext( ctx->openGLContext );
221     ReleaseDC( ctx->window, ctx->dev_context );
222 
223     return true;
224   }
225   return false;
226 }
227 
save_framebuffer(const OffscreenContext * ctx,std::ostream & output)228 bool save_framebuffer(const OffscreenContext *ctx, std::ostream &output)
229 {
230   if (!ctx) return false;
231   wglSwapLayerBuffers( ctx->dev_context, WGL_SWAP_MAIN_PLANE );
232   return save_framebuffer_common( ctx, output );
233 }
234 
235