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