1 module graphics.adapters.win32; 2 3 version( Windows ): 4 5 import core.dgame, core.gameobject, core.properties; 6 import graphics.graphics, graphics.adapters.adapter; 7 import utility.input, utility.output; 8 9 import win32.windef, win32.winuser, win32.winbase; 10 import win32.wingdi : PIXELFORMATDESCRIPTOR, SetPixelFormat, SwapBuffers; 11 import derelict.opengl3.gl3, derelict.opengl3.wgl, derelict.opengl3.wglext; 12 13 enum DWS_FULLSCREEN = WS_POPUP | WS_SYSMENU; 14 enum DWS_WINDOWED = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; 15 16 extern( Windows ) 17 LRESULT WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) 18 { 19 switch( message ) 20 { 21 case WM_CLOSE: 22 case WM_DESTROY: 23 case WM_QUIT: 24 PostQuitMessage( 0 ); 25 break; 26 // If key down, send it to input 27 case WM_KEYDOWN: 28 Input.setKeyState( cast(uint)wParam, true ); 29 break; 30 // If key up, send it to input 31 case WM_KEYUP: 32 Input.setKeyState( cast(uint)wParam, false ); 33 break; 34 // On Mouse Event 35 case WM_RBUTTONDOWN: 36 Input.setKeyState( VK_RBUTTON, true ); 37 break; 38 // On Mouse Event 39 case WM_RBUTTONUP: 40 Input.setKeyState( VK_RBUTTON, false ); 41 break; 42 // On Mouse Event 43 case WM_LBUTTONDOWN: 44 Input.setKeyState( VK_LBUTTON, true ); 45 break; 46 // On Mouse Event 47 case WM_LBUTTONUP: 48 Input.setKeyState( VK_LBUTTON, false ); 49 break; 50 // If no change, send to default windows handler 51 default: 52 return DefWindowProc( hWnd, message, wParam, lParam ); 53 } 54 return 0; 55 } 56 57 final class Win32 : Adapter 58 { 59 public: 60 static @property Win32 get() { return cast(Win32)Graphics.adapter; } 61 62 mixin Property!( "HWND", "hWnd" ); 63 mixin Property!( "HINSTANCE", "hInstance" ); 64 65 override void initialize() 66 { 67 // Load opengl functions 68 DerelictGL3.load(); 69 70 // Setup the window 71 screenWidth = GetSystemMetrics( SM_CXSCREEN ); 72 screenHeight = GetSystemMetrics( SM_CYSCREEN ); 73 74 hInstance = GetModuleHandle( null ); 75 76 WNDCLASSEX wcex = { 77 WNDCLASSEX.sizeof, 78 CS_HREDRAW | CS_VREDRAW,// | CS_OWNDC, 79 &WndProc, 80 0, 81 0, 82 hInstance, 83 null, 84 LoadCursor( null, IDC_ARROW ), 85 cast(HBRUSH)( COLOR_WINDOW + 1 ), 86 null, 87 DGame.instance.title.ptr, 88 null 89 }; 90 91 RegisterClassEx( &wcex ); 92 openWindow( false ); 93 94 // Setup opengl 95 uint formatCount; 96 int pixelFormat; 97 PIXELFORMATDESCRIPTOR pfd; 98 99 HGLRC handle; 100 101 deviceContext = GetDC( hWnd ); 102 SetPixelFormat( deviceContext, 1, &pfd ); 103 renderContext = wglCreateContext( deviceContext ); 104 wglMakeCurrent( deviceContext, renderContext ); 105 106 DerelictGL3.reload(); 107 108 if( DerelictGL3.loadedVersion < GLVersion.GL40 ) 109 { 110 log( OutputType.Error, "Your version of OpenGL is unsupported. Required: GL40 Yours: ", DerelictGL3.loadedVersion ); 111 //throw new Exception( "Unsupported version of OpenGL." ); 112 return; 113 } 114 115 closeWindow(); 116 openWindow(); 117 118 // Set attributes list 119 const(int)[ 19 ] attributeList = [ 120 WGL_SUPPORT_OPENGL_ARB, TRUE, // Support for OpenGL rendering 121 WGL_DRAW_TO_WINDOW_ARB, TRUE, // Support for rendering window 122 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, // Support for hardware acceleration 123 WGL_COLOR_BITS_ARB, 24, // Support for 24bit color 124 WGL_DEPTH_BITS_ARB, 24, // Support for 24bit depth buffer 125 WGL_DOUBLE_BUFFER_ARB, TRUE, // Support for double buffer 126 WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB, // Support for swapping buffers 127 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, // Support for RGBA pixel type 128 WGL_STENCIL_BITS_ARB, 8, // Support for 8 bit stencil buffer 129 0 // Null terminate 130 ]; 131 132 // Set version to 4.0 133 const(int)[ 5 ] versionInfo = [ 134 WGL_CONTEXT_MAJOR_VERSION_ARB, 4, 135 WGL_CONTEXT_MINOR_VERSION_ARB, 0, 136 0 137 ]; 138 139 // Get new Device Context 140 deviceContext = GetDC( hWnd ); 141 142 // Query pixel format 143 wglChoosePixelFormatARB( deviceContext, attributeList.ptr, null, 1, &pixelFormat, &formatCount ); 144 145 // Set the pixel format 146 SetPixelFormat( deviceContext, pixelFormat, &pfd ); 147 148 // Create OpenGL rendering context 149 renderContext = wglCreateContextAttribsARB( deviceContext, null, versionInfo.ptr ); 150 151 // Set current context 152 wglMakeCurrent( deviceContext, renderContext ); 153 154 // Set depth buffer 155 glClearDepth( 1.0f ); 156 157 // Enable depth testing 158 glEnable( GL_DEPTH_TEST ); 159 160 // Enable transparency 161 glEnable( GL_BLEND ); 162 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 163 164 // Set front face 165 //glFrontFace( GL_CW ); 166 167 reload(); 168 169 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); 170 } 171 172 override void shutdown() 173 { 174 wglMakeCurrent( null, null ); 175 wglDeleteContext( renderContext ); 176 renderContext = null; 177 ReleaseDC( hWnd, deviceContext ); 178 deviceContext = null; 179 closeWindow(); 180 } 181 182 override void resize() 183 { 184 LONG style = GetWindowLong( hWnd, GWL_STYLE ) & ~( DWS_FULLSCREEN | DWS_WINDOWED ); 185 186 loadProperties(); 187 188 if( fullscreen ) 189 { 190 width = screenWidth; 191 height = screenHeight; 192 style |= DWS_FULLSCREEN; 193 } 194 else 195 { 196 style |= DWS_WINDOWED; 197 } 198 199 SetWindowLong( hWnd, GWL_STYLE, style ); 200 SetWindowPos( hWnd, null, ( screenWidth - width ) / 2, ( screenHeight - height ) / 2, 201 width + ( 2 * GetSystemMetrics( SM_CYBORDER ) ), 202 height + GetSystemMetrics( SM_CYCAPTION ) + GetSystemMetrics( SM_CYBORDER ), 203 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED ); 204 205 glViewport( 0, 0, width, height ); 206 // update matricies 207 } 208 209 override void reload() 210 { 211 resize(); 212 213 // Enable back face culling 214 if( backfaceCulling ) 215 { 216 glEnable( GL_CULL_FACE ); 217 glCullFace( GL_BACK ); 218 } 219 220 // Turn on of off the v sync 221 wglSwapIntervalEXT( vsync ); 222 } 223 224 override void swapBuffers() 225 { 226 SwapBuffers( deviceContext ); 227 } 228 229 override void openWindow() 230 { 231 openWindow( true ); 232 } 233 234 final void openWindow( bool showWindow ) 235 { 236 hWnd = CreateWindowEx( 0, DGame.instance.title.ptr, DGame.instance.title.ptr, fullscreen ? DWS_FULLSCREEN : DWS_WINDOWED, 237 ( screenWidth - width ) / 2, ( screenHeight - height ) / 2, width, height, 238 null, null, hInstance, null ); 239 240 assert( hWnd ); 241 242 resize(); 243 244 ShowWindow( hWnd, showWindow ? SW_NORMAL : SW_HIDE ); 245 } 246 247 override void closeWindow() 248 { 249 DestroyWindow( hWnd ); 250 hWnd = null; 251 } 252 253 override void messageLoop() 254 { 255 MSG msg; 256 257 // Initialize the message structure. 258 ( cast(byte*)&msg )[ 0 .. msg.sizeof ] = 0; 259 260 // Handle the windows messages. 261 while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) 262 { 263 TranslateMessage( &msg ); 264 DispatchMessage( &msg ); 265 } 266 } 267 }