added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / src / fxwt / init_win32.cpp
1 /*
2 This file is part of the 3dengfx, realtime visualization system.
3
4 Copyright (C) 2005 John Tsiombikas <nuclear@siggraph.org>
5
6 3dengfx is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 3dengfx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with 3dengfx; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 /* OpenGL through Win32
22  *
23  * Author: John Tsiombikas 2005
24  * modified: Mihalis Georgoulopoulos 2006
25  */
26
27 #include "3dengfx_config.h"
28
29 #if GFX_LIBRARY == NATIVE && NATIVE_LIB == NATIVE_WIN32
30
31 #include <stdlib.h>
32 #include "init.hpp"
33 #include "gfx_library.h"
34 #include "3dengfx/3denginefx.hpp"
35 #include "common/err_msg.h"
36
37 long CALLBACK fxwt_win32_handle_event(HWND__ *win, unsigned int msg, unsigned int wparam, long lparam);
38
39 HWND__ *fxwt_win32_win;
40 HDC__ *fxwt_win32_dc;
41 static HGLRC__ *wgl_ctx;
42
43 static bool win32_video_mode_switch(int width, int height, int bpp, bool dontcare_bpp);
44 static void win32_reset_video_mode();
45
46 bool fxwt::init_graphics(GraphicsInitParameters *gparams) {
47         HWND__ *win;
48         HDC__ *dc;
49
50         info("Initializing WGL");
51         HINSTANCE pid = GetModuleHandle(0);
52
53         WNDCLASSEX wc;
54         memset(&wc, 0, sizeof wc);
55         wc.cbSize = sizeof wc;
56         wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
57         wc.hCursor = LoadCursor(0, IDC_ARROW);
58         wc.hIcon = wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
59         wc.hInstance = pid;
60         wc.lpfnWndProc = fxwt_win32_handle_event;
61         wc.lpszClassName = "win32_sucks_big_time";
62         wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
63         RegisterClassEx(&wc);
64
65         //unsigned long style = WS_OVERLAPPEDWINDOW /*| WS_VISIBLE*/ | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
66         
67         unsigned long desktop_w = GetSystemMetrics(SM_CXSCREEN);
68         unsigned long desktop_h = GetSystemMetrics(SM_CYSCREEN);
69         
70         unsigned long style, width, height;
71         width = gparams->x;
72         height = gparams->y;
73         if (gparams->fullscreen)
74         {       
75                 style = WS_POPUP;
76                 if (!win32_video_mode_switch(gparams->x, gparams->y, 32, (gparams->dont_care_flags & DONT_CARE_BPP)))
77                         return false;
78         }
79         else
80         {
81                 style = WS_OVERLAPPED | WS_SYSMENU;
82         }
83         
84         
85         win = CreateWindow("win32_sucks_big_time", "3dengfx/win32", 
86                         style, 
87                         0, 0, 
88                         width, height, 
89                         0, 0, pid, 0);
90         dc = GetDC(win);
91
92         // decide window placement
93         // if the window is smaller than the desktop, center 
94         // the window in the desktop
95         unsigned long placement_x = 0;
96         unsigned long placement_y = 0;
97         
98         if (gparams->x < desktop_w)
99                 placement_x = (desktop_w - gparams->x) / 2;
100         if (gparams->y < desktop_h)
101                 placement_y = (desktop_h - gparams->y) / 2;
102
103         // adjust window size to make the client area big enough
104         // to fit the framebuffer
105         RECT client_rect;
106         GetClientRect(win, &client_rect);
107
108         unsigned long new_width = gparams->x + (gparams->x - client_rect.right);
109         unsigned long new_height = gparams->y + (gparams->y - client_rect.bottom);
110         
111         if (!gparams->fullscreen)
112         {
113                 MoveWindow(win, placement_x, placement_y,
114                                         new_width, new_height, false);
115         }
116
117         // show the window
118         ShowWindow(win, SW_SHOW);
119         UpdateWindow(win);
120         SetFocus(win);
121         
122         // determine color bits
123         int color_bits;
124         if(gparams->dont_care_flags & DONT_CARE_BPP) {
125                 color_bits = 1;
126         } else {
127                 switch(gparams->bpp) {
128                 case 32:
129                 case 24:
130                         color_bits = 8;
131                         break;
132
133                 case 16:
134                 case 15:
135                         color_bits = 5;
136                         break;
137
138                 case 12:
139                         color_bits = 4;
140                         break;
141
142                 default:
143                         error("%s: Tried to set unsupported pixel format: %d bpp", __func__, gparams->bpp);
144                 }
145         }
146
147         // determine stencil bits
148         int stencil_bits = gparams->stencil_bits;
149         if(gparams->dont_care_flags & DONT_CARE_STENCIL) {
150                 stencil_bits = 1;
151         }
152
153         // determine zbuffer bits
154         int zbits = gparams->depth_bits == 32 ? 24 : gparams->depth_bits;
155
156         PIXELFORMATDESCRIPTOR pfd;
157         memset(&pfd, 0, sizeof pfd);
158         pfd.nSize = sizeof pfd;
159         pfd.nVersion = 1;
160         pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;
161         pfd.iPixelType = PFD_TYPE_RGBA;
162         pfd.cColorBits = gparams->bpp;
163         pfd.cDepthBits = zbits;
164         pfd.cStencilBits = stencil_bits;
165         pfd.iLayerType = PFD_MAIN_PLANE;
166
167         info("Trying to set video mode %dx%dx%d, d:%d s:%d %s", gparams->x, gparams->y, gparams->bpp, gparams->depth_bits, gparams->stencil_bits, gparams->fullscreen ? "fullscreen" : "windowed");
168
169         int pix_format = ChoosePixelFormat(dc, &pfd);
170         if(!pix_format) {
171                 error("ChoosePixelFormat() failed: %d", GetLastError());
172                 ReleaseDC(win, dc);
173                 DestroyWindow(win);
174                 return false;
175         }
176
177         //TODO: examine if the pixelformat is correct
178
179         if(!SetPixelFormat(dc, pix_format, &pfd)) {
180                 error("SetPixelFormat() failed");
181                 ReleaseDC(win, dc);
182                 DestroyWindow(win);
183                 return false;
184         }
185
186         if(!(wgl_ctx = wglCreateContext(dc))) {
187                 error("wglCreateContext() failed");
188                 ReleaseDC(win, dc);
189                 DestroyWindow(win);
190                 return false;
191         }
192
193         if(wglMakeCurrent(dc, wgl_ctx) == FALSE) {
194         error("wglMakeCurrent() failed");
195                 wglDeleteContext(wgl_ctx);
196                 ReleaseDC(win, dc);
197                 DestroyWindow(win);
198                 return false;
199         }
200
201         fxwt_win32_dc = dc;
202         fxwt_win32_win = win;
203
204         if (gparams->fullscreen)
205                 ShowCursor(0);
206
207         return true;
208 }
209
210 void fxwt::destroy_graphics() {
211         info("Shutting down WGL");
212         wglMakeCurrent(0, 0);
213         wglDeleteContext(wgl_ctx);
214         ReleaseDC(fxwt_win32_win, fxwt_win32_dc);
215         DestroyWindow(fxwt_win32_win);
216
217         info("Resetting video mode");
218         win32_reset_video_mode();
219
220         ShowCursor(1);
221 }
222
223 static bool win32_video_mode_switch(int width, int height, int bpp, bool dontcare_bpp)
224 {
225         // enumerate display modes
226         std::vector<DEVMODE> modes;
227         DEVMODE curr_mode;
228         curr_mode.dmSize = sizeof(DEVMODE);
229                 
230         for (int i=0; ; i++)
231         {
232                 if (! EnumDisplaySettings(0, i, &curr_mode))
233                         break;
234                 modes.push_back(curr_mode);
235         }
236         
237         int best_mode = -1;
238         unsigned int best_bpp = 1;
239         if (!dontcare_bpp) best_bpp = bpp;
240         
241         for (int i=0; i<modes.size(); i++)
242         {
243                 if (modes[i].dmPelsWidth == width &&
244                         modes[i].dmPelsHeight == height)
245                 {
246                         if (modes[i].dmBitsPerPel >= best_bpp)
247                         {
248                                 best_bpp = modes[i].dmBitsPerPel;
249                                 best_mode = i;
250                         }
251                 }
252         }
253
254         if (best_mode == -1) return false;
255         
256         if (ChangeDisplaySettings(&modes[best_mode], CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)
257                 return true;
258
259         return false;
260 }
261
262 // resets the video mode to the default mode in the registry
263 static void win32_reset_video_mode()
264 {
265         ChangeDisplaySettings(0, 0);
266 }
267
268 #endif  // GFX_LIBRARY == NATIVE && NATIVE_LIB == NATIVE_WIN32