2 This file is part of the 3dengfx, realtime visualization system.
4 Copyright (C) 2005 John Tsiombikas <nuclear@siggraph.org>
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.
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.
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
21 /* OpenGL through Win32
23 * Author: John Tsiombikas 2005
24 * modified: Mihalis Georgoulopoulos 2006
27 #include "3dengfx_config.h"
29 #if GFX_LIBRARY == NATIVE && NATIVE_LIB == NATIVE_WIN32
33 #include "gfx_library.h"
34 #include "3dengfx/3denginefx.hpp"
35 #include "common/err_msg.h"
37 long CALLBACK fxwt_win32_handle_event(HWND__ *win, unsigned int msg, unsigned int wparam, long lparam);
39 HWND__ *fxwt_win32_win;
41 static HGLRC__ *wgl_ctx;
43 static bool win32_video_mode_switch(int width, int height, int bpp, bool dontcare_bpp);
44 static void win32_reset_video_mode();
46 bool fxwt::init_graphics(GraphicsInitParameters *gparams) {
50 info("Initializing WGL");
51 HINSTANCE pid = GetModuleHandle(0);
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);
60 wc.lpfnWndProc = fxwt_win32_handle_event;
61 wc.lpszClassName = "win32_sucks_big_time";
62 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
65 //unsigned long style = WS_OVERLAPPEDWINDOW /*| WS_VISIBLE*/ | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
67 unsigned long desktop_w = GetSystemMetrics(SM_CXSCREEN);
68 unsigned long desktop_h = GetSystemMetrics(SM_CYSCREEN);
70 unsigned long style, width, height;
73 if (gparams->fullscreen)
76 if (!win32_video_mode_switch(gparams->x, gparams->y, 32, (gparams->dont_care_flags & DONT_CARE_BPP)))
81 style = WS_OVERLAPPED | WS_SYSMENU;
85 win = CreateWindow("win32_sucks_big_time", "3dengfx/win32",
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;
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;
103 // adjust window size to make the client area big enough
104 // to fit the framebuffer
106 GetClientRect(win, &client_rect);
108 unsigned long new_width = gparams->x + (gparams->x - client_rect.right);
109 unsigned long new_height = gparams->y + (gparams->y - client_rect.bottom);
111 if (!gparams->fullscreen)
113 MoveWindow(win, placement_x, placement_y,
114 new_width, new_height, false);
118 ShowWindow(win, SW_SHOW);
122 // determine color bits
124 if(gparams->dont_care_flags & DONT_CARE_BPP) {
127 switch(gparams->bpp) {
143 error("%s: Tried to set unsupported pixel format: %d bpp", __func__, gparams->bpp);
147 // determine stencil bits
148 int stencil_bits = gparams->stencil_bits;
149 if(gparams->dont_care_flags & DONT_CARE_STENCIL) {
153 // determine zbuffer bits
154 int zbits = gparams->depth_bits == 32 ? 24 : gparams->depth_bits;
156 PIXELFORMATDESCRIPTOR pfd;
157 memset(&pfd, 0, sizeof pfd);
158 pfd.nSize = sizeof pfd;
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;
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");
169 int pix_format = ChoosePixelFormat(dc, &pfd);
171 error("ChoosePixelFormat() failed: %d", GetLastError());
177 //TODO: examine if the pixelformat is correct
179 if(!SetPixelFormat(dc, pix_format, &pfd)) {
180 error("SetPixelFormat() failed");
186 if(!(wgl_ctx = wglCreateContext(dc))) {
187 error("wglCreateContext() failed");
193 if(wglMakeCurrent(dc, wgl_ctx) == FALSE) {
194 error("wglMakeCurrent() failed");
195 wglDeleteContext(wgl_ctx);
202 fxwt_win32_win = win;
204 if (gparams->fullscreen)
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);
217 info("Resetting video mode");
218 win32_reset_video_mode();
223 static bool win32_video_mode_switch(int width, int height, int bpp, bool dontcare_bpp)
225 // enumerate display modes
226 std::vector<DEVMODE> modes;
228 curr_mode.dmSize = sizeof(DEVMODE);
232 if (! EnumDisplaySettings(0, i, &curr_mode))
234 modes.push_back(curr_mode);
238 unsigned int best_bpp = 1;
239 if (!dontcare_bpp) best_bpp = bpp;
241 for (int i=0; i<modes.size(); i++)
243 if (modes[i].dmPelsWidth == width &&
244 modes[i].dmPelsHeight == height)
246 if (modes[i].dmBitsPerPel >= best_bpp)
248 best_bpp = modes[i].dmBitsPerPel;
254 if (best_mode == -1) return false;
256 if (ChangeDisplaySettings(&modes[best_mode], CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)
262 // resets the video mode to the default mode in the registry
263 static void win32_reset_video_mode()
265 ChangeDisplaySettings(0, 0);
268 #endif // GFX_LIBRARY == NATIVE && NATIVE_LIB == NATIVE_WIN32