1 /** 2 * TODO 3 */ 4 module dash.graphics.adapters.win32gl; 5 6 version( Windows ): 7 8 import dash.core, dash.graphics, dash.utility; 9 10 import win32.windef, win32.winuser, win32.winbase; 11 import win32.wingdi : PIXELFORMATDESCRIPTOR, SetPixelFormat, SwapBuffers; 12 import derelict.opengl3.gl3, derelict.opengl3.wgl, derelict.opengl3.wglext; 13 14 enum DWS_FULLSCREEN = WS_POPUP | WS_SYSMENU; 15 enum DWS_WINDOWED = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; 16 17 extern( Windows ) 18 private LRESULT WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) 19 { 20 switch( message ) 21 { 22 // On close 23 case WM_CLOSE: 24 DGame.instance.currentState = EngineState.Quit; 25 break; 26 // If key down, send it to input 27 case WM_KEYDOWN: 28 Keyboard.setButtonState( cast(Keyboard.Buttons)wParam, true ); 29 break; 30 // If key up, send it to input 31 case WM_KEYUP: 32 Keyboard.setButtonState( cast(Keyboard.Buttons)wParam, false ); 33 break; 34 // On right mouse down 35 case WM_RBUTTONDOWN: 36 Mouse.setButtonState( Mouse.Buttons.Right, true ); 37 break; 38 // On right mouse up 39 case WM_RBUTTONUP: 40 Mouse.setButtonState( Mouse.Buttons.Right, false ); 41 break; 42 // On left mouse down 43 case WM_LBUTTONDOWN: 44 Mouse.setButtonState( Mouse.Buttons.Left, true ); 45 break; 46 // On left mouse up 47 case WM_LBUTTONUP: 48 Mouse.setButtonState( Mouse.Buttons.Left, false ); 49 break; 50 // On mouse scroll 51 case WM_MOUSEWHEEL: 52 Mouse.setAxisState( Mouse.Axes.ScrollWheel, Mouse.getAxisState( Mouse.Axes.ScrollWheel ) + ( ( cast(int)wParam >> 16 ) / 120 ) ); 53 break; 54 // If no change, send to default windows handler 55 default: 56 return DefWindowProc( hWnd, message, wParam, lParam ); 57 } 58 return 0; 59 } 60 61 /** 62 * TODO 63 */ 64 final class Win32GL : OpenGL 65 { 66 private: 67 HWND _hWnd; 68 HINSTANCE _hInstance; 69 bool _wasFullscreen; 70 HDC deviceContext; 71 HGLRC renderContext; 72 73 public: 74 /// TODO 75 mixin( Property!_hWnd ); 76 /// TODO 77 mixin( Property!_hInstance ); 78 /// TODO 79 static @property Win32GL get() { return cast(Win32GL)Graphics.adapter; } 80 81 /** 82 * TODO 83 */ 84 override void initialize() 85 { 86 // Load opengl functions 87 DerelictGL3.load(); 88 89 // Setup the window 90 screenWidth = GetSystemMetrics( SM_CXSCREEN ); 91 screenHeight = GetSystemMetrics( SM_CYSCREEN ); 92 93 hInstance = GetModuleHandle( null ); 94 95 WNDCLASSEX wcex = { 96 WNDCLASSEX.sizeof, 97 CS_HREDRAW | CS_VREDRAW,// | CS_OWNDC, 98 &WndProc, 99 0, 100 0, 101 cast(void*)hInstance, 102 null, 103 LoadCursor( null, IDC_ARROW ), 104 cast(HBRUSH)( COLOR_WINDOW + 1 ), 105 null, 106 DGame.instance.title.ptr, 107 null 108 }; 109 110 RegisterClassEx( &wcex ); 111 112 // Setup opengl 113 uint formatCount; 114 int pixelFormat; 115 PIXELFORMATDESCRIPTOR pfd; 116 117 // Check for OpenGL version 118 openWindow( false ); 119 120 deviceContext = GetDC( hWnd ); 121 SetPixelFormat( deviceContext, 1, &pfd ); 122 renderContext = wglCreateContext( deviceContext ); 123 wglMakeCurrent( deviceContext, renderContext ); 124 125 DerelictGL3.reload(); 126 127 if( DerelictGL3.loadedVersion < GLVersion.GL40 ) 128 { 129 fatalf( "Your version of OpenGL is unsupported. Required: GL40 Yours: %s", DerelictGL3.loadedVersion ); 130 //throw new Exception( "Unsupported version of OpenGL." ); 131 return; 132 } 133 134 shutdown(); 135 openWindow(); 136 137 // Set attributes list 138 const(int)[ 19 ] attributeList = [ 139 WGL_SUPPORT_OPENGL_ARB, TRUE, // Support for OpenGL rendering 140 WGL_DRAW_TO_WINDOW_ARB, TRUE, // Support for rendering window 141 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, // Support for hardware acceleration 142 WGL_COLOR_BITS_ARB, 24, // Support for 24bit color 143 WGL_DEPTH_BITS_ARB, 24, // Support for 24bit depth buffer 144 WGL_DOUBLE_BUFFER_ARB, TRUE, // Support for double buffer 145 WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB, // Support for swapping buffers 146 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, // Support for RGBA pixel type 147 WGL_STENCIL_BITS_ARB, 8, // Support for 8 bit stencil buffer 148 0 // Null terminate 149 ]; 150 151 // Set version to 4.0 152 const(int)[ 5 ] versionInfo = [ 153 WGL_CONTEXT_MAJOR_VERSION_ARB, 4, 154 WGL_CONTEXT_MINOR_VERSION_ARB, 0, 155 0 156 ]; 157 158 // Get new Device Context 159 deviceContext = GetDC( hWnd ); 160 161 // Query pixel format 162 wglChoosePixelFormatARB( deviceContext, attributeList.ptr, null, 1, &pixelFormat, &formatCount ); 163 164 // Set the pixel format 165 SetPixelFormat( deviceContext, pixelFormat, &pfd ); 166 167 // Create OpenGL rendering context 168 renderContext = wglCreateContextAttribsARB( deviceContext, null, versionInfo.ptr ); 169 170 // Set current context 171 wglMakeCurrent( deviceContext, renderContext ); 172 173 refresh(); 174 175 HANDLE hIcon = LoadImage( null, ( Resources.Textures ~ "/icon.ico" ).ptr, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); 176 if( hIcon ) 177 { 178 //Change both icons to the same icon handle. 179 SendMessage( hWnd, WM_SETICON, ICON_SMALL, cast(int)hIcon ); 180 SendMessage( hWnd, WM_SETICON, ICON_BIG, cast(int)hIcon ); 181 182 //This will ensure that the application icon gets changed too. 183 SendMessage( GetWindow( hWnd, GW_OWNER ), WM_SETICON, ICON_SMALL, cast(int)hIcon ); 184 SendMessage( GetWindow( hWnd, GW_OWNER ), WM_SETICON, ICON_BIG, cast(int)hIcon ); 185 } 186 } 187 188 /** 189 * TODO 190 */ 191 override void shutdown() 192 { 193 wglMakeCurrent( null, null ); 194 wglDeleteContext( renderContext ); 195 renderContext = null; 196 ReleaseDC( hWnd, deviceContext ); 197 deviceContext = null; 198 closeWindow(); 199 } 200 201 /** 202 * TODO 203 */ 204 override void resize() 205 { 206 LONG style = GetWindowLong( hWnd, GWL_STYLE ) & ~( DWS_FULLSCREEN | DWS_WINDOWED ); 207 208 loadProperties(); 209 210 if( fullscreen ) 211 { 212 width = screenWidth; 213 height = screenHeight; 214 style |= DWS_FULLSCREEN; 215 } 216 else 217 { 218 style |= DWS_WINDOWED; 219 } 220 221 if( _wasFullscreen != fullscreen ) 222 { 223 SetWindowLong( hWnd, GWL_STYLE, style ); 224 SetWindowPos( hWnd, null, ( screenWidth - width ) / 2, ( screenHeight - height ) / 2, 225 width + ( 2 * GetSystemMetrics( SM_CYBORDER ) ), 226 height + GetSystemMetrics( SM_CYCAPTION ) + GetSystemMetrics( SM_CYBORDER ), 227 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED ); 228 } 229 230 _wasFullscreen = fullscreen; 231 232 resizeDefferedRenderBuffer(); 233 234 glViewport( 0, 0, width, height ); 235 } 236 237 /** 238 * TODO 239 */ 240 override void refresh() 241 { 242 resize(); 243 244 // Enable back face culling 245 if( backfaceCulling ) 246 { 247 glEnable( GL_CULL_FACE ); 248 glCullFace( GL_BACK ); 249 } 250 251 // Turn on of off the v sync 252 wglSwapIntervalEXT( vsync ); 253 } 254 255 /** 256 * TODO 257 */ 258 override void swapBuffers() 259 { 260 SwapBuffers( deviceContext ); 261 } 262 263 /** 264 * TODO 265 */ 266 override void openWindow() 267 { 268 openWindow( true ); 269 } 270 271 /** 272 * TODO 273 */ 274 final void openWindow( bool showWindow ) 275 { 276 hWnd = CreateWindowEx( 0, DGame.instance.title.ptr, DGame.instance.title.ptr, fullscreen ? DWS_FULLSCREEN : DWS_WINDOWED, 277 ( screenWidth - width ) / 2, ( screenHeight - height ) / 2, width, height, 278 null, null, hInstance, null ); 279 280 assert( hWnd ); 281 282 resize(); 283 284 ShowWindow( hWnd, showWindow ? SW_NORMAL : SW_HIDE ); 285 } 286 287 /** 288 * TODO 289 */ 290 override void closeWindow() 291 { 292 DestroyWindow( hWnd ); 293 hWnd = null; 294 } 295 296 /** 297 * TODO 298 */ 299 override void messageLoop() 300 { 301 MSG msg; 302 303 // Initialize the message structure. 304 ( cast(byte*)&msg )[ 0 .. msg.sizeof ] = 0; 305 306 // Handle the windows messages. 307 while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) 308 { 309 TranslateMessage( &msg ); 310 DispatchMessage( &msg ); 311 } 312 } 313 }