From b38c84c55cc20f02f8eea959c440dde9a5794205 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 9 Jan 2003 20:35:32 +0000 Subject: [PATCH] add .old --- panda/src/dxgsg8/wdxGraphicsPipe8.cxx.old | 110 + panda/src/dxgsg8/wdxGraphicsPipe8.h.old | 72 + panda/src/dxgsg8/wdxGraphicsWindow8.cxx.old | 3458 +++++++++++++++++++ panda/src/dxgsg8/wdxGraphicsWindow8.h.old | 195 ++ 4 files changed, 3835 insertions(+) create mode 100644 panda/src/dxgsg8/wdxGraphicsPipe8.cxx.old create mode 100644 panda/src/dxgsg8/wdxGraphicsPipe8.h.old create mode 100644 panda/src/dxgsg8/wdxGraphicsWindow8.cxx.old create mode 100644 panda/src/dxgsg8/wdxGraphicsWindow8.h.old diff --git a/panda/src/dxgsg8/wdxGraphicsPipe8.cxx.old b/panda/src/dxgsg8/wdxGraphicsPipe8.cxx.old new file mode 100644 index 0000000000..a51f030604 --- /dev/null +++ b/panda/src/dxgsg8/wdxGraphicsPipe8.cxx.old @@ -0,0 +1,110 @@ +// Filename: wdxGraphicsPipe.cxx +// Created by: mike (09Jan97) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "wdxGraphicsPipe8.h" +#include "config_wdxdisplay8.h" +#include +#include +#include + +//////////////////////////////////////////////////////////////////// +// Static variables +//////////////////////////////////////////////////////////////////// +TypeHandle wdxGraphicsPipe::_type_handle; + +//wdxGraphicsPipe *global_pipe; + +wdxGraphicsPipe::wdxGraphicsPipe(const PipeSpecifier& spec) +: InteractiveGraphicsPipe(spec) { +// _width = GetSystemMetrics(SM_CXSCREEN); +// _height = GetSystemMetrics(SM_CYSCREEN); + _shift = false; +// global_pipe = this; +} + +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsPipe::get_window_type +// Access: Public, Virtual +// Description: Returns the TypeHandle of the kind of window +// preferred by this kind of pipe. +//////////////////////////////////////////////////////////////////// +TypeHandle wdxGraphicsPipe:: +get_window_type() const { + return wdxGraphicsWindow::get_class_type(); +} + +GraphicsPipe *wdxGraphicsPipe:: +make_wdxGraphicsPipe(const FactoryParams ¶ms) { + GraphicsPipe::PipeSpec *pipe_param; + if(!get_param_into(pipe_param, params)) { + return new wdxGraphicsPipe(PipeSpecifier()); + } else { + return new wdxGraphicsPipe(pipe_param->get_specifier()); + } +} + +TypeHandle wdxGraphicsPipe::get_class_type(void) { + return _type_handle; +} + +const char *pipe_type_name="wdxGraphicsPipe8"; + +void wdxGraphicsPipe::init_type(void) { + InteractiveGraphicsPipe::init_type(); + register_type(_type_handle, pipe_type_name, + InteractiveGraphicsPipe::get_class_type()); +} + +TypeHandle wdxGraphicsPipe::get_type(void) const { + return get_class_type(); +} + +wdxGraphicsPipe::wdxGraphicsPipe(void) { + wdxdisplay_cat.error() + << pipe_type_name <<"s should not be created with the default constructor" << endl; +} + +wdxGraphicsPipe::wdxGraphicsPipe(const wdxGraphicsPipe&) { + wdxdisplay_cat.error() + << pipe_type_name << "s should not be copied" << endl; +} + +wdxGraphicsPipe& wdxGraphicsPipe::operator=(const wdxGraphicsPipe&) { + wdxdisplay_cat.error() + << pipe_type_name << "s should not be assigned" << endl; + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: find_window +// Access: +// Description: Find the window that has the xwindow "win" in the +// window list for the pipe (if it exists) +//////////////////////////////////////////////////////////////////// +wdxGraphicsWindow *wdxGraphicsPipe:: +find_window(HWND win) { + int num_windows = get_num_windows(); + for(int w = 0; w < num_windows; w++) { + wdxGraphicsWindow *window = DCAST(wdxGraphicsWindow, get_window(w)); + if((window->_dxgsg!=NULL) && (window->_dxgsg->scrn.hWnd == win)) + return window; + } + return NULL; +} + + diff --git a/panda/src/dxgsg8/wdxGraphicsPipe8.h.old b/panda/src/dxgsg8/wdxGraphicsPipe8.h.old new file mode 100644 index 0000000000..872fc160b8 --- /dev/null +++ b/panda/src/dxgsg8/wdxGraphicsPipe8.h.old @@ -0,0 +1,72 @@ +// Filename: wdxGraphicsPipe.h +// Created by: mike (09Jan97) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// +#ifndef WDXGRAPHICSPIPE8_H +#define WDXGRAPHICSPIPE8_H +// +//////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////// +#include + +#include +#include +#include "wdxGraphicsWindow8.h" + +//////////////////////////////////////////////////////////////////// +// Defines +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Class : wdxGraphicsPipe +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX wdxGraphicsPipe : public InteractiveGraphicsPipe { +public: + wdxGraphicsPipe(const PipeSpecifier&); + + wdxGraphicsWindow* find_window(HWND win); +// ButtonHandle lookup_key(WPARAM wparam) const; + + virtual TypeHandle get_window_type() const; + +public: + + static GraphicsPipe* make_wdxGraphicsPipe(const FactoryParams ¶ms); + + static TypeHandle get_class_type(void); + static void init_type(void); + virtual TypeHandle get_type(void) const; + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + + static TypeHandle _type_handle; + +// int _width; +// int _height; + bool _shift; + +protected: + + wdxGraphicsPipe(void); + wdxGraphicsPipe(const wdxGraphicsPipe&); + wdxGraphicsPipe& operator=(const wdxGraphicsPipe&); + +}; + +#endif diff --git a/panda/src/dxgsg8/wdxGraphicsWindow8.cxx.old b/panda/src/dxgsg8/wdxGraphicsWindow8.cxx.old new file mode 100644 index 0000000000..f0ca2bb1e8 --- /dev/null +++ b/panda/src/dxgsg8/wdxGraphicsWindow8.cxx.old @@ -0,0 +1,3458 @@ +// Filename: wdxGraphicsWindow.cxx +// Created by: mike (09Jan00) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "wdxGraphicsWindow8.h" +#include "wdxGraphicsPipe8.h" +#include "config_wdxdisplay8.h" + +#include +#include +#include + +#ifdef DO_PSTATS +#include +#endif + +#include +#include + +//////////////////////////////////////////////////////////////////// +// Static variables +//////////////////////////////////////////////////////////////////// +TypeHandle wdxGraphicsWindow::_type_handle; + +#define LAST_ERROR 0 +#define ERRORBOX_TITLE "Panda3D Error" +#define WDX_WINDOWCLASSNAME "wdxDisplay" +#define WDX_WINDOWCLASSNAME_NOCURSOR WDX_WINDOWCLASSNAME "_NoCursor" +#define DEFAULT_CURSOR IDC_ARROW + +// define this to enable debug testing of dinput joystick +//#define DINPUT_DEBUG_POLL + +typedef map HWND_PANDAWIN_MAP; + +// CardIDVec is used in DX7 lowmem card-classification pass so DX8 can +// establish correspondence b/w DX7 mem info & DX8 device +typedef struct { + HMONITOR hMon; + DWORD MaxAvailVidMem; + bool bIsLowVidMemCard; + GUID DX7_DeviceGUID; + DWORD VendorID,DeviceID; +// char szDriver[MAX_DEVICE_IDENTIFIER_STRING]; +} CardID; + +typedef vector CardIDVec; +static CardIDVec *g_pCardIDVec=NULL; + +HWND_PANDAWIN_MAP hwnd_pandawin_map; +wdxGraphicsWindow* global_wdxwinptr = NULL; // need this for temporary windproc + +#define MAX_DISPLAYS 20 + +#define PAUSED_TIMER_ID 7 // completely arbitrary choice +#define JOYSTICK_POLL_TIMER_ID 8 +#define DX_IS_READY ((_dxgsg!=NULL)&&(_dxgsg->GetDXReady())) + +LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam,LPARAM lparam); + +// imperfect method to ID NVid? could also scan desc str, but that isnt fullproof either +#define IS_NVIDIA(DDDEVICEID) ((DDDEVICEID.VendorId==0x10DE) || (DDDEVICEID.VendorId==0x12D2)) +#define IS_ATI(DDDEVICEID) (DDDEVICEID.VendorId==0x1002) +#define IS_MATROX(DDDEVICEID) (DDDEVICEID.VendorId==0x102B) + +// because we dont have access to ModifierButtons, as a hack just synchronize state of these +// keys on get/lose keybd focus +#define NUM_MODIFIER_KEYS 16 +unsigned int hardcoded_modifier_buttons[NUM_MODIFIER_KEYS]={VK_SHIFT,VK_MENU,VK_CONTROL,VK_SPACE,VK_TAB, + VK_UP,VK_DOWN,VK_LEFT,VK_RIGHT,VK_PRIOR,VK_NEXT,VK_HOME,VK_END, + VK_INSERT,VK_DELETE,VK_ESCAPE}; + +#define UNKNOWN_VIDMEM_SIZE 0xFFFFFFFF +/* +static DWORD BitDepth_2_DDBDMask(DWORD iBitDepth) { + switch(iBitDepth) { + case 16: return DDBD_16; + case 32: return DDBD_32; + case 24: return DDBD_24; + case 8: return DDBD_8; + case 1: return DDBD_1; + case 2: return DDBD_2; + case 4: return DDBD_4; + } + return 0x0; +} + +typedef enum {DBGLEV_FATAL,DBGLEV_ERROR,DBGLEV_WARNING,DBGLEV_INFO,DBGLEV_DEBUG,DBGLEV_SPAM + } DebugLevels; + +void PrintDBGStr(DebugLevels level,HRESULT hr,const char *msgstr) { + ostream *pstrm; + static ostream dbg_strms[DBGLEV_SPAM+1]={wdxdisplay_cat.fatal,wdxdisplay_cat.error, + wdxdisplay_cat.warning,wdxdisplay_cat.info,wdxdisplay_cat.debug,wdxdisplay_cat.spam}; + assert(level<=DBGLEV_SPAM); + + pstrm=dbg_strms[level]; + (*pstrm)->fatal() << "GetDisplayMode failed, hr = " << ConvD3DErrorToString(hr) << endl; +} +*/ + +// pops up MsgBox w/system error msg +#define LAST_ERROR 0 +void PrintErrorMessage(DWORD msgID) { + LPTSTR pMessageBuffer; + + if(msgID==LAST_ERROR) + msgID=GetLastError(); + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL,msgID, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language + (LPTSTR) &pMessageBuffer, // the weird ptrptr->ptr cast is intentional, see FORMAT_MESSAGE_ALLOCATE_BUFFER + 1024, NULL); + MessageBox(GetDesktopWindow(),pMessageBuffer,_T(ERRORBOX_TITLE),MB_OK); + wdxdisplay_cat.fatal() << "System error msg: " << pMessageBuffer << endl; + LocalFree( pMessageBuffer ); +} + +//#if defined(NOTIFY_DEBUG) || defined(DO_PSTATS) +//#ifdef _DEBUG +#if 0 +extern void dbgPrintVidMem(LPDIRECTDRAW7 pDD, LPDDSCAPS2 lpddsCaps,const char *pMsg) { + DWORD dwTotal,dwFree; + HRESULT hr; + + // These Caps bits arent allowed to be specified when calling GetAvailVidMem. + // They don't affect surface allocation in a vram heap. + +#define AVAILVIDMEM_BADCAPS (DDSCAPS_BACKBUFFER | \ + DDSCAPS_FRONTBUFFER | \ + DDSCAPS_COMPLEX | \ + DDSCAPS_FLIP | \ + DDSCAPS_OWNDC | \ + DDSCAPS_PALETTE | \ + DDSCAPS_SYSTEMMEMORY | \ + DDSCAPS_VISIBLE | \ + DDSCAPS_WRITEONLY) + + DDSCAPS2 ddsCaps = *lpddsCaps; + ddsCaps.dwCaps &= ~(AVAILVIDMEM_BADCAPS); // turn off the bad caps +// ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; done internally by DX anyway + + if(FAILED( hr = pDD->GetAvailableVidMem(&ddsCaps,&dwTotal,&dwFree))) { + wdxdisplay_cat.debug() << "GetAvailableVidMem failed : hr = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Write a debug message to the console reporting the texture memory. + char tmpstr[100],tmpstr2[100]; + sprintf(tmpstr,"%.4g",dwTotal/1000000.0); + sprintf(tmpstr2,"%.4g",dwFree/1000000.0); + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "AvailableVidMem before creating "<< pMsg << ",(megs) total: " << tmpstr << " free:" << tmpstr2 <scrn.hWnd = hwnd; + + // Determine the initial open status of the IME. + _ime_open = false; + _ime_active = false; + HIMC hIMC = ImmGetContext(hwnd); + if (hIMC != 0) { + _ime_open = (ImmGetOpenStatus(hIMC) != 0); + ImmReleaseContext(hwnd, hIMC); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: static_window_proc +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + HWND_PANDAWIN_MAP::iterator pwin; + pwin=hwnd_pandawin_map.find(hwnd); + + if(pwin!=hwnd_pandawin_map.end()) { + wdxGraphicsWindow *wdxwinptr=(*pwin).second; + return wdxwinptr->window_proc(hwnd, msg, wparam, lparam); + } else if(global_wdxwinptr!=NULL){ + // this stuff should only be used during CreateWindow() + return global_wdxwinptr->window_proc(hwnd, msg, wparam, lparam); + } else { + // should never need this?? (maybe at shutdwn?) + return DefWindowProc(hwnd, msg, wparam, lparam); + } +} + +// Note: could use _TrackMouseEvent in comctrl32.dll (part of IE 3.0+) which emulates +// TrackMouseEvent on w95, but that requires another 500K of memory to hold that DLL, +// which is lame just to support w95, which probably has other issues anyway +INLINE void wdxGraphicsWindow:: +track_mouse_leaving(HWND hwnd) { + TRACKMOUSEEVENT tme = {sizeof(TRACKMOUSEEVENT),TME_LEAVE,hwnd,0}; + BOOL bSucceeded = TrackMouseEvent(&tme); // tell win32 to post WM_MOUSELEAVE msgs + + if((!bSucceeded) && wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "TrackMouseEvent failed!, LastError=" << GetLastError() << endl; + + _tracking_mouse_leaving=true; +} + +//////////////////////////////////////////////////////////////////// +// Function: window_proc +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +LONG wdxGraphicsWindow:: +window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + int button = -1; + int x, y, width, height; + + switch(msg) { + case WM_PAINT: { + if((_WindowAdjustingType != NotAdjusting) || (!DX_IS_READY)) { + // let DefWndProc do WM_ERASEBKGND & just draw black, + // rather than forcing Present to stretchblt the old window contents + // into the new size + break; + } + + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + if(DX_IS_READY) { + _dxgsg->show_frame(true); // 'true' since just want to show the last rendered backbuf, if any + } + EndPaint(hwnd, &ps); + return 0; + } + + case WM_MOUSEMOVE: { + if(!DX_IS_READY) + break; + + // Win32 doesn't return the same numbers as X does when the mouse + // goes beyond the upper or left side of the window + #define SET_MOUSE_COORD(iVal,VAL) { \ + iVal = VAL; \ + if(iVal & 0x8000) \ + iVal -= 0x10000; \ + } + + if(!_tracking_mouse_leaving) { + // need to re-call TrackMouseEvent every time mouse re-enters window + track_mouse_leaving(hwnd); + } + + WORD newX=LOWORD(lparam); + WORD newY=HIWORD(lparam); + + SET_MOUSE_COORD(x,newX); + SET_MOUSE_COORD(y,newY); + + handle_mouse_motion(x, y); + if(_props._fullscreen && (_dxgsg!=NULL) && (_dxgsg->scrn.pD3DDevice!=NULL)) + _dxgsg->scrn.pD3DDevice->SetCursorPosition(newX,newY,D3DCURSOR_IMMEDIATE_UPDATE); + return 0; + } + + // if cursor is invisible, make it visible when moving in the window bars,etc + case WM_NCMOUSEMOVE: { + if(!_props._bCursorIsVisible) { + if(!_cursor_in_windowclientarea) { +// SetCursor(_pParentWindowGroup->_hMouseCursor); + ShowCursor(true); + _cursor_in_windowclientarea=true; + } + } + break; + } + + case WM_NCMOUSELEAVE: { + if(!_props._bCursorIsVisible) { + ShowCursor(false); +// SetCursor(NULL); + _cursor_in_windowclientarea=false; + } + break; + } + + case WM_MOUSELEAVE: { + // wdxdisplay_cat.fatal() << "XXXXX WM_MOUSELEAVE received\n"; + + _tracking_mouse_leaving=false; + handle_mouse_exit(); + break; + } + + case WM_CREATE: { + track_mouse_leaving(hwnd); + _cursor_in_windowclientarea=false; + ClearToBlack(hwnd,_props); + set_cursor_visibility(true); + break; + } + + case WM_IME_NOTIFY: + if (wparam == IMN_SETOPENSTATUS) { + HIMC hIMC = ImmGetContext(hwnd); + nassertr(hIMC != 0, 0); + _ime_open = (ImmGetOpenStatus(hIMC) != 0); + if (!_ime_open) { + _ime_active = false; // Sanity enforcement. + } + ImmReleaseContext(hwnd, hIMC); + } + break; + + case WM_IME_STARTCOMPOSITION: + // In case we're running fullscreen mode, we have to turn on + // explicit DX support for overlay windows now, so we'll be able + // to see the IME window. + _dxgsg->support_overlay_window(true); + _ime_active = true; + break; + + case WM_IME_ENDCOMPOSITION: + // Turn off the support for overlay windows, since we're done + // with the IME window for now and it just slows things down. + _dxgsg->support_overlay_window(false); + _ime_active = false; + break; + + case WM_IME_COMPOSITION: + if (lparam & GCS_RESULTSTR) { + if (!_input_devices.empty()) { + HIMC hIMC = ImmGetContext(hwnd); + nassertr(hIMC != 0, 0); + + static const int max_ime_result = 128; + static char ime_result[max_ime_result]; + + if (_ime_composition_w) { + // Since ImmGetCompositionStringA() doesn't seem to work + // for Win2000 (it always returns question mark + // characters), we have to use ImmGetCompositionStringW() + // on this OS. This is actually the easier of the two + // functions to use. + + DWORD result_size = + ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, + ime_result, max_ime_result); + + // Add this string into the text buffer of the application. + + // ImmGetCompositionStringW() returns a string, but it's + // filled in with wstring data: every two characters defines a + // 16-bit unicode char. The docs aren't clear on the + // endianness of this. I guess it's safe to assume all Win32 + // machines are little-endian. + for (DWORD i = 0; i < result_size; i += 2) { + int result = + ((int)(unsigned char)ime_result[i + 1] << 8) | + (unsigned char)ime_result[i]; + _input_devices[0].keystroke(result); + } + } else { + // On the other hand, ImmGetCompositionStringW() doesn't + // work on Win95 or Win98; for these OS's we must use + // ImmGetCompositionStringA(). + DWORD result_size = + ImmGetCompositionStringA(hIMC, GCS_RESULTSTR, + ime_result, max_ime_result); + + // ImmGetCompositionStringA() returns an encoded ANSI + // string, which we now have to map to wide-character + // Unicode. + static const int max_wide_result = 128; + static wchar_t wide_result[max_wide_result]; + + int wide_size = + MultiByteToWideChar(CP_ACP, 0, + ime_result, result_size, + wide_result, max_wide_result); + if (wide_size == 0) { + PrintErrorMessage(LAST_ERROR); + } + for (int i = 0; i < wide_size; i++) { + _input_devices[0].keystroke(wide_result[i]); + } + } + + ImmReleaseContext(hwnd, hIMC); + } + return 0; + } + break; + + case WM_CHAR: + // Ignore WM_CHAR messages if we have the IME open, since + // everything will come in through WM_IME_COMPOSITION. (It's + // supposed to come in through WM_CHAR, too, but there seems to + // be a bug in Win2000 in that it only sends question mark + // characters through here.) + if (!_ime_open && !_input_devices.empty()) { + _input_devices[0].keystroke(wparam); + } + break; + + case WM_SYSKEYDOWN: { + // Alt and F10 are sent as WM_SYSKEYDOWN instead of WM_KEYDOWN + // want to use defwindproc on Alt syskey so std windows cmd Alt-F4 works, etc + POINT point; + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + handle_keypress(lookup_key(wparam), point.x, point.y); + if (wparam == VK_F10) { + //bypass default windproc F10 behavior (it activates the main menu, but we have none) + return 0; + } + } + break; + + case WM_SYSCOMMAND: + if(wparam==SC_KEYMENU) { + // if Alt is released (alone w/o other keys), defwindproc will send + // this command, which will 'activate' the title bar menu (we have none) + // and give focus to it. we dont want this to happen, so kill this msg + return 0; + } + break; + + case WM_KEYDOWN: { + POINT point; + + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + handle_keypress(lookup_key(wparam), point.x, point.y); + + // Handle Cntrl-V paste from clipboard. Is there a better way + // to detect this hotkey? + if ((wparam=='V') && (GetKeyState(VK_CONTROL) < 0) && + !_input_devices.empty()) { + HGLOBAL hglb; + char *lptstr; + + if (!IsClipboardFormatAvailable(CF_TEXT)) + return 0; + + if (!OpenClipboard(NULL)) + return 0; + + // Maybe we should support CF_UNICODETEXT if it is available + // too? + hglb = GetClipboardData(CF_TEXT); + if (hglb!=NULL) { + lptstr = (char *) GlobalLock(hglb); + if (lptstr != NULL) { + char *pChar; + for(pChar=lptstr;*pChar!=NULL;pChar++) { + _input_devices[0].keystroke((uchar)*pChar); + } + GlobalUnlock(hglb); + } + } + CloseClipboard(); + } + break; + } + + case WM_SYSKEYUP: + case WM_KEYUP: + handle_keyrelease(lookup_key(wparam)); + break; + + case WM_LBUTTONDOWN: + button = 0; + case WM_MBUTTONDOWN: + if(button < 0) + button = 1; + case WM_RBUTTONDOWN: + if(!DX_IS_READY) + break; + + if(button < 0) + button = 2; + SetCapture(hwnd); + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); + handle_keypress(MouseButton::button(button), x, y); + return 0; + + case WM_LBUTTONUP: + button = 0; + case WM_MBUTTONUP: + if(button < 0) + button = 1; + case WM_RBUTTONUP: + if(!DX_IS_READY) + break; + + if(button < 0) + button = 2; + ReleaseCapture(); + #if 0 + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); + #endif + handle_keyrelease(MouseButton::button(button)); + return 0; + + case WM_SETCURSOR: + // Turn off any GDI window cursor + // dx8 cursor not working yet + + if(_use_dx8_cursor && _props._fullscreen) { + // SetCursor( NULL ); + // _dxgsg->scrn.pD3DDevice->ShowCursor(true); + + set_cursor_visibility(true); + return TRUE; // prevent Windows from setting cursor to window class cursor (see docs on WM_SETCURSOR) + } + break; + + case WM_MOVE: + if(!DX_IS_READY) + break; + handle_window_move(LOWORD(lparam), HIWORD(lparam) ); + return 0; + +#if 0 + doesnt work yet + + case WM_GETMINMAXINFO: { + + // make sure window size doesnt go to zero + LPMINMAXINFO pInfo=(LPMINMAXINFO) lparam; + wdxdisplay_cat.spam() << "initial WM_GETMINMAXINFO: MinX:" << pInfo->ptMinTrackSize.x << " MinY:" << pInfo->ptMinTrackSize.y << endl; + + RECT client_rect; + GetClientRect( hwnd, &client_rect ); + + wdxdisplay_cat.spam() << "WM_GETMINMAXINFO: ClientRect: left: " << client_rect.left << " right: " << client_rect.right + << " top: " << client_rect.top << " bottom: " << client_rect.bottom << endl; + + + UINT client_ysize=RECT_YSIZE(client_rect); + UINT client_xsize=RECT_XSIZE(client_rect); + + if(client_ysize==0) { + RECT wnd_rect; + GetWindowRect( hwnd, &wnd_rect ); + wdxdisplay_cat.spam() << "WM_GETMINMAXINFO: WndRect: left: " << wnd_rect.left << " right: " << wnd_rect.right + << " top: " << wnd_rect.top << " bottom: " << wnd_rect.bottom << endl; + + pInfo->ptMinTrackSize.y=RECT_YSIZE(wnd_rect)-client_ysize+2; + } + + if(client_xsize==0) { + RECT wnd_rect; + GetWindowRect( hwnd, &wnd_rect ); + pInfo->ptMinTrackSize.x=RECT_XSIZE(wnd_rect)-client_xsize+2; + } + + if((client_ysize==0) || (client_xsize==0)) { + wdxdisplay_cat.spam() << "final WM_GETMINMAXINFO: MinX:" << pInfo->ptMinTrackSize.x << " MinY:" << pInfo->ptMinTrackSize.y << endl; + return 0; + } + break; + } +#endif + + case WM_EXITSIZEMOVE: + #ifdef _DEBUG + wdxdisplay_cat.spam() << "WM_EXITSIZEMOVE received" << endl; + #endif + + if(_WindowAdjustingType==Resizing) { + bool bSucceeded=handle_windowed_resize(hwnd,true); + + if(!bSucceeded) { +#if 0 + bugbug need to fix this stuff + SetWindowPos(hwnd,NULL,0,0,lastxsize,lastysize, + SWP_NOMOVE | +#endif + } + } + + _WindowAdjustingType = NotAdjusting; + _dxgsg->SetDXReady(true); + return 0; + + case WM_ENTERSIZEMOVE: { + if(_dxgsg!=NULL) + _dxgsg->SetDXReady(false); // dont see pic during resize + _WindowAdjustingType = MovingOrResizing; + } + break; + + case WM_SIZE: { + + #ifdef _DEBUG + { + width = LOWORD(lparam); height = HIWORD(lparam); + wdxdisplay_cat.spam() << "WM_SIZE received with width:" << width << " height: " << height << " flags: " << + ((wparam == SIZE_MAXHIDE)? "SIZE_MAXHIDE " : "") << ((wparam == SIZE_MAXSHOW)? "SIZE_MAXSHOW " : "") << + ((wparam == SIZE_MINIMIZED)? "SIZE_MINIMIZED " : "") << ((wparam == SIZE_RESTORED)? "SIZE_RESTORED " : "") << + ((wparam == SIZE_MAXIMIZED)? "SIZE_MAXIMIZED " : "") << endl; + } + #endif + // old comment -- added SIZE_RESTORED to handle 3dfx case + if(_props._fullscreen || ((_dxgsg==NULL) || (_dxgsg->scrn.hWnd==NULL)) || ((wparam != SIZE_RESTORED) && (wparam != SIZE_MAXIMIZED))) + break; + + width = LOWORD(lparam); height = HIWORD(lparam); + + if((_props._xsize != width) || (_props._ysize != height)) { + _WindowAdjustingType = Resizing; + + // for maximized,unmaximize, need to call resize code artificially + // since no WM_EXITSIZEMOVE is generated. + if(wparam==SIZE_MAXIMIZED) { + _bSizeIsMaximized=TRUE; + window_proc(hwnd, WM_EXITSIZEMOVE, 0x0,0x0); + } else if((wparam==SIZE_RESTORED) && _bSizeIsMaximized) { + _bSizeIsMaximized=FALSE; // only want to reinit dx if restoring from maximized state + window_proc(hwnd, WM_EXITSIZEMOVE, 0x0,0x0); + } + } + + break; + } + + case WM_DISPLAYCHANGE: { + #ifdef _DEBUG + width = LOWORD(lparam); height = HIWORD(lparam); + DWORD newbitdepth=wparam; + wdxdisplay_cat.spam() <<"WM_DISPLAYCHANGE received with width:" << width << " height: " << height << " bpp: " << wparam<< endl; + #endif + + // unfortunately this doesnt seem to work because RestoreAllSurfaces doesn't + // seem to think we're back in the original displaymode even after I've received + // the WM_DISPLAYCHANGE msg, and returns WRONGMODE error. So the only way I can + // think of to make this work is to have the timer periodically check for restored + // coop level + + // if(_props._fullscreen && !_window_active) { + // if(_dxgsg!=NULL) + // _dxgsg->CheckCooperativeLevel(DO_REACTIVATE_WINDOW); + // else reactivate_window(); + // } + + // does the windowed case handle displaychange properly? no. need to recreate all devices + } + break; + + case WM_SETFOCUS: { + // wdxdisplay_cat.info() << "got WM_SETFOCUS\n"; + if(!DX_IS_READY) { + break; + } + + POINT point; + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + + // this is a hack to make sure common modifier keys have proper state + // since at focus loss, app may never receive key-up event corresponding to + // a key-down. it would be better to know the exact set of ModifierButtons the + // user is using, since we may miss some here + + for(int i=0;iflags << endl; + break; + } + + case WM_GETMINMAXINFO: + wdxdisplay_cat.spam() << "WM_GETMINMAXINFO received\n" << endl; + break; +#endif + + case WM_ERASEBKGND: + // WM_ERASEBKGND will be ignored during resizing, because + // we dont want to redraw as user is manually resizing window + if(_WindowAdjustingType) + break; + return 0; // dont let GDI waste time redrawing the deflt background + + case WM_TIMER: + // 2 cases of app deactivation: + // + // 1) user has switched out of fullscreen mode + // this is first signalled when ACTIVATEAPP returns false + // for this case, we dont wake up until WM_SIZE returns restore or maximize + // and WM_TIMER just periodically reawakens app for idle processing + + // unfortunately this doesnt seem to work because RestoreAllSurfaces doesn't + // seem to think we're back in the original displaymode even after I've received + // the WM_DISPLAYCHANGE msg, and returns WRONGMODE error. So the only way I can + // think of to make this work is to have the timer periodically check for restored + // coop level, as it does in case 2) + + // + // 2) windowed app has lost access to dx because another app has taken dx exclusive mode + // here we rely on WM_TIMER to periodically check if it is ok to reawaken app. + // windowed apps currently run regardless of if its window is in the foreground + // so we cannot rely on window messages to reawaken app + + if((wparam==_PandaPausedTimer) && ((!_window_active)||_active_minimized_fullscreen)) { + assert(_dxgsg!=NULL); + _dxgsg->CheckCooperativeLevel(DO_REACTIVATE_WINDOW); + + // wdxdisplay_cat.spam() << "periodic return of control to app\n"; + _return_control_to_app = true; + // throw_event("PandaPaused"); + // do we still need to do this since I return control to app periodically using timer msgs? + // does app need to know to avoid major computation? + } + + #ifdef DINPUT_DEBUG_POLL + // probably want to get rid of this in favor of event-based input + if(dx_use_joystick && (wparam==_pParentWindowGroup->_pDInputInfo->_JoystickPollTimer)) { + DIJOYSTATE2 js; + ZeroMemory(&js,sizeof(js)); + if(_pParentWindowGroup->_pDInputInfo->ReadJoystick(0,js)) { + // for now just print stuff out to make sure it works + wdxdisplay_cat.debug() << "joyPos (X: " << js.lX << ",Y: " << js.lY << ",Z: " << js.lZ << ")\n"; + for(int i=0;i<128;i++) { + if(js.rgbButtons[i]!=0) + wdxdisplay_cat.debug() << "joyButton "<< i << " pressed\n"; + } + } else { + wdxdisplay_cat.error() << "read of Joystick failed!\n"; + exit(1); + } + } + #endif + return 0; + + case WM_CLOSE: + #ifdef _DEBUG + wdxdisplay_cat.spam() << "WM_CLOSE received\n"; + #endif + // close_window(); + delete _pParentWindowGroup; + + // BUGBUG: right now there is no way to tell the panda app the graphics window is invalid or + // has been closed by the user, to prevent further methods from being called on the window. + // this needs to be added to panda for multiple windows to work. in the meantime, just + // trigger an exit here if # windows==0, since that is the expected behavior when all + // windows are closed (should be done by the app though, and it assumes you only make this + // type of panda gfx window) + + if(hwnd_pandawin_map.size()==0) { + exit(0); + } + return 0; + + case WM_ACTIVATEAPP: { + #ifdef _DEBUG + wdxdisplay_cat.spam() << "WM_ACTIVATEAPP(" << (bool)(wparam!=0) <<") received\n"; + #endif + + if((!wparam) && _props._fullscreen) { + deactivate_window(); + return 0; + } // dont want to reactivate until window is actually un-minimized (see WM_SIZE) + break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +// should be used by both fullscrn and windowed resize +bool wdxGraphicsWindow::reset_device_resize_window(UINT new_xsize, UINT new_ysize) { + DXScreenData *pScrn=&_dxgsg->scrn; + assert((new_xsize>0)&&(new_ysize>0)); + bool bRetval=true; + + D3DPRESENT_PARAMETERS d3dpp; + memcpy(&d3dpp,&pScrn->PresParams,sizeof(D3DPRESENT_PARAMETERS)); + d3dpp.BackBufferWidth = new_xsize; + d3dpp.BackBufferHeight = new_ysize; + HRESULT hr=_dxgsg->reset_d3d_device(&d3dpp); + + if(FAILED(hr)) { + bRetval=false; + wdxdisplay_cat.error() << "reset_device_resize_window Reset() failed" << D3DERRORSTRING(hr); + if(hr==D3DERR_OUTOFVIDEOMEMORY) { + hr=_dxgsg->reset_d3d_device(&pScrn->PresParams); + if(FAILED(hr)) { + wdxdisplay_cat.error() << "reset_device_resize_window Reset() failed OutOfVidmem, then failed again doing Reset w/original params:" << D3DERRORSTRING(hr); + exit(1); + } else { + if(wdxdisplay_cat.is_info()) + wdxdisplay_cat.info() << "reset of original size (" <PresParams.BackBufferWidth << "," + << pScrn->PresParams.BackBufferHeight << ") succeeded\n"; + } + } else { + exit(1); + } + } + + init_resized_window(); + return bRetval; +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_reshape +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +bool wdxGraphicsWindow::handle_windowed_resize(HWND hWnd,bool bDoDxReset) { + // handles windowed, non-fullscreen resizing + GdiFlush(); + + assert(!_props._fullscreen); + + if(bDoDxReset && (_dxgsg!=NULL)) { + if(_dxgsg->scrn.pD3DDevice==NULL) { + //assume this is initial creation reshape, so ignore this call + return true; + } + } + + if(_dxgsg!=NULL) + _dxgsg->SetDXReady(false); + + RECT view_rect; + + GetClientRect( hWnd, &view_rect ); + ClientToScreen( hWnd, (POINT*)&view_rect.left ); // translates top,left pnt + ClientToScreen( hWnd, (POINT*)&view_rect.right ); // translates right,bottom pnt + + _props._xorg = view_rect.left; // _props origin should reflect upper left of view rectangle + _props._yorg = view_rect.top; + + DWORD xsize= RECT_XSIZE(view_rect); + DWORD ysize= RECT_YSIZE(view_rect); + + if((xsize==0)||(ysize==0)) { + return false; + } + + bool bResizeSucceeded=true; + +/* + fail if resize fails, dont adjust size + do { + // change _props xsize,ysize (need to do this here in case _dxgsg==NULL) + resized(xsize,ysize); + + if((_dxgsg!=NULL)&& bDoDxReset) { + bResizeSucceeded=reset_device_resize_window(xsize,ysize); // create the new resized rendertargets + if(!bResizeSucceeded) { + // size was too large. try a smaller size + if(wdxdisplay_cat.is_debug()) { + wdxdisplay_cat.debug() << "windowed_resize to size: (" << xsize << "," << ysize << ") failed due to out-of-memory, retrying w/reduced size\n"; + } + + xsize *= 0.8f; + ysize *= 0.8f; + + view_rect.right=view_rect.left+xsize; + view_rect.bottom=view_rect.top+ysize; + } + } + } while(!bResizeSucceeded); +*/ + + // change _props xsize,ysize (need to do this here in case _dxgsg==NULL) + // reset_device_resize will call it again, this is OK + resized(xsize,ysize); + + if((_dxgsg!=NULL)&& bDoDxReset) { + bResizeSucceeded=reset_device_resize_window(xsize,ysize); // create the new resized rendertargets + if(!bResizeSucceeded) { + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "windowed_resize to size: (" << xsize << "," << ysize << ") failed due to out-of-memory\n"; + } else { + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "windowed_resize to origin: (" << _props._xorg << "," << _props._yorg << "), size: (" << _props._xsize << "," << _props._ysize << ")\n"; + } + } + + if(_dxgsg!=NULL) + _dxgsg->SetDXReady(true); + + return bResizeSucceeded; +} + +void wdxGraphicsWindow::deactivate_window(void) { + // current policy is to suspend minimized or deactivated fullscreen windows, but leave + // regular windows running normally + + if((!_window_active) || _exiting_window || _active_minimized_fullscreen) { + #ifdef _DEBUG + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "deactivate_window called, but ignored in current mode\n"; + #endif + return; + } + + if(bResponsive_minimized_fullscreen_window) { + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "WDX fullscreen window switching to active minimized mode...\n"; + _active_minimized_fullscreen = true; + } else { + + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "WDX window deactivated, waiting...\n"; + + _window_active = false; + } + + if(_props._fullscreen) { + // make sure window is minimized + + WINDOWPLACEMENT wndpl; + wndpl.length=sizeof(WINDOWPLACEMENT); + if(!GetWindowPlacement(_dxgsg->scrn.hWnd,&wndpl)) { + wdxdisplay_cat.error() << "GetWindowPlacement failed!\n"; + return; + } + + if((wndpl.showCmd!=SW_MINIMIZE)&&(wndpl.showCmd!=SW_SHOWMINIMIZED)) { + ShowWindow(_dxgsg->scrn.hWnd, SW_MINIMIZE); + } + + throw_event("PandaPaused"); // right now this is used to signal python event handler to disable audio + } + +// if(!bResponsive_minimized_fullscreen_window) { + // need this even in responsive-mode to trigger the dxgsg check of cooplvl, i think? + + _PandaPausedTimer = SetTimer(_dxgsg->scrn.hWnd,PAUSED_TIMER_ID,500,NULL); + if(_PandaPausedTimer!=PAUSED_TIMER_ID) { + wdxdisplay_cat.error() << "Error in SetTimer!\n"; + } +// } + + + // bugbug: need to handle dinput devices +} + +// currently this should only be called from CheckCoopLvl to return from Alt-tab +void wdxGraphicsWindow::reactivate_window(void) { + if((!_window_active)||(_active_minimized_fullscreen)) { + + // first see if dx cooperative level is OK for reactivation + // if(!_dxgsg->CheckCooperativeLevel()) + // return; + + if(_PandaPausedTimer!=NULL) { + KillTimer(_dxgsg->scrn.hWnd,_PandaPausedTimer); + _PandaPausedTimer = NULL; + } + + if(!_window_active) { + _window_active = true; + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "WDX window re-activated...\n"; + } else { + _active_minimized_fullscreen = false; + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "WDX window unminimized from active-minimized state...\n"; + } + + // need to call dx_init and ResourceManagerDiscardBytes since D3D Reset() was called + init_resized_window(); + + // move window to top of zorder + // if(_props._fullscreen) + // SetWindowPos(_DisplayDataArray[0].hWnd, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER); + GdiFlush(); + } + + if(_props._fullscreen) { + throw_event("PandaRestarted"); // right now this is used to signal python event handler to re-enable audio + } +} + +//////////////////////////////////////////////////////////////////// +// Function: Constructor +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +wdxGraphicsWindow::wdxGraphicsWindow(GraphicsPipe* pipe) : GraphicsWindow(pipe) { + _ime_active = false; + _pParentWindowGroup=NULL; + _pParentWindowGroup=new wdxGraphicsWindowGroup(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: Constructor +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +wdxGraphicsWindow::wdxGraphicsWindow(GraphicsPipe* pipe, const GraphicsWindow::Properties& props) + : GraphicsWindow(pipe, props) { + _ime_open = false; + _pParentWindowGroup=NULL; + _pParentWindowGroup=new wdxGraphicsWindowGroup(this); +} + +bool supports_color_cursors(D3DADAPTER_IDENTIFIER8 &DevID) { + // TODO: add more cards as more testing is done + if(IS_NVIDIA(DevID)) { + // all nvidia seem to support 256 color + return true; + } else if(IS_ATI(DevID)) { + // radeons seem to be in the 5100 range and support color, assume anything in 6000 or above + // is newer than radeon and supports 256 color + if(((DevID.DeviceId>=0x5100) && (DevID.DeviceId<=0x5200)) || + (DevID.DeviceId>=0x6000)) + return true; + } else if IS_MATROX(DevID) { + if(DevID.DeviceId==0x0525) // G400 seems to support color cursors, havent tested other matrox + return true; + } + + return false; +} + +HCURSOR CreateNullCursor(HINSTANCE hInst) { + #define CURSORBYTESIZE (32*4) + + // 1-bit 32x32 + BYTE ANDPlane[CURSORBYTESIZE],XORPlane[CURSORBYTESIZE]; + + ZeroMemory(XORPlane,CURSORBYTESIZE); + memset(ANDPlane,0xFF,CURSORBYTESIZE); + + return CreateCursor(hInst,0,0,32,32,ANDPlane,XORPlane); +} + +void wdxGraphicsWindowGroup::CreateWindows(void) { + HINSTANCE hProgramInstance = GetModuleHandle(NULL); + WNDCLASS wc; + static bool wc_registered = false; + _hParentWindow = NULL; + _bLoadedCustomCursor=false; + + // Clear before filling in window structure! + ZeroMemory(&wc, sizeof(WNDCLASS)); + wc.style = CS_HREDRAW | CS_VREDRAW; //CS_OWNDC; + wc.lpfnWndProc = (WNDPROC) static_window_proc; + wc.hInstance = hProgramInstance; + + // all this must be moved to dx_init, since we need to create DX surface + string windows_icon_filename = get_icon_filename().to_os_specific(); + + + if(!windows_icon_filename.empty()) { + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + // loads a .ico fmt file + wc.hIcon = (HICON) LoadImage(NULL, windows_icon_filename.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); + + if(wc.hIcon==NULL) { + wdxdisplay_cat.warning() << "windows icon filename '" << windows_icon_filename << "' not found!!\n"; + } + } else { + wc.hIcon = NULL; // use default app icon + } + +#if 0 + // Note: dx_init() uses the cursor handle to create the dx cursor surface + string windows_color_cursor_filename = get_color_cursor_filename().to_os_specific(); + + if(!windows_color_cursor_filename.empty()) { + // card support for full color non-black/white GDI cursors varies greatly. if the cursor is not supported, + // it is rendered in software by GDI, which causes a flickering effect (because it's not synced + // with flip?). GDI transparently masks the lack of HW support so there is no easy way for app to detect + // if HW cursor support exists. alternatives are to tie cursor motion to frame rate using DDraw blts + // or overlays (this is done automatically by DX8 runtime mouse cursor support), or to have separate thread draw cursor + // (sync issues?). instead we do mono cursor unless card is known to support 256 color cursors + bool bSupportsColorCursor=true; + + #if 0 + // remove this check for now, since dx8 should emulate color cursors + /* if any card doesnt support color, dont load it*/ + for(int w=0;w<_windows.size();w++) + bSupportsColorCursor &= supports_color_cursors(_windows[w]->_dxgsg->scrn.DXDeviceID); + #endif + + if(bSupportsColorCursor) { + DWORD load_flags = LR_LOADFROMFILE; + + if(dx_full_screen) { + // I think cursors should use LR_CREATEDIBSECTION since they should not be mapped to the device palette (in the case of 256-color cursors) + // since they are not going to be used on the desktop + load_flags |= LR_CREATEDIBSECTION; + } + + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + // loads a .cur fmt file. + _hMouseCursor = (HCURSOR) LoadImage(NULL, windows_color_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, load_flags ); + + if(_hMouseCursor==NULL) { + wdxdisplay_cat.warning() << "windows color cursor filename '" << windows_color_cursor_filename << "' not found!!\n"; + goto try_mono_cursor; + + } + + _bLoadedCustomCursor=true; + } + } + + try_mono_cursor: +#endif + + if(!_bLoadedCustomCursor) { + string windows_mono_cursor_filename = get_mono_cursor_filename().to_os_specific(); + + if(!windows_mono_cursor_filename.empty()) { + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + DWORD load_flags = LR_LOADFROMFILE; + + if(dx_full_screen) { + // I think cursors should use LR_CREATEDIBSECTION since they should not be mapped to the device palette (in the case of 256-color cursors) + // since they are not going to be used on the desktop + load_flags |= LR_CREATEDIBSECTION; + } + // loads a .cur fmt file. + _hMouseCursor = (HCURSOR) LoadImage(NULL, windows_mono_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, load_flags); + + if(_hMouseCursor==NULL) { + wdxdisplay_cat.warning() << "windows mono cursor filename '" << windows_mono_cursor_filename << "' not found!!\n"; + } else _bLoadedCustomCursor=true; + } + } + + if(!_bLoadedCustomCursor) + _hMouseCursor = LoadCursor(NULL, DEFAULT_CURSOR); + + // need both a mouse and no-mouse class in case we have mixed fullscrn/windowed + // windowed must use GDI mouse, fullscrn usually wont + if (!wc_registered) { + // We only need to register the window class once per session. + + wc.hCursor = _hMouseCursor; // for windowed mode use the GDI cursor. + // bugbug: for fullscreen do we need to do a SetWindowLongNULL + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = WDX_WINDOWCLASSNAME; + + if(!RegisterClass(&wc)) { + wdxdisplay_cat.error() << "could not register window class " << WDX_WINDOWCLASSNAME << endl; + } + + if(dx_use_dx_cursor) { + wc.hCursor = CreateNullCursor(hProgramInstance); + if(wc.hCursor==NULL) + wdxdisplay_cat.error() << "failed to create NULL cursor, error=" << GetLastError() << endl; + + wc.lpszClassName = WDX_WINDOWCLASSNAME_NOCURSOR; + + if(!RegisterClass(&wc)) { + wdxdisplay_cat.error() << "could not register window class " << WDX_WINDOWCLASSNAME_NOCURSOR << endl; + } + } + + wc_registered = true; + } + + DWORD base_window_style = WS_POPUP | WS_SYSMENU; // for CreateWindow + + global_wdxwinptr = _windows[0]; // for use during createwin() bugbug look at this again + + // rect now contains the coords for the entire window, not the client + // extra windows must be parented to the first so app doesnt minimize when user selects them + for(DWORD devnum=0;devnum<_windows.size();devnum++) { + DWORD xleft,ytop,xsize,ysize; + GraphicsWindow::Properties *props = &_windows[devnum]->_props; + DWORD final_window_style; + + final_window_style=base_window_style; + char *pWindowClassName; + + if(_windows[devnum]->_props._fullscreen) { + MONITORINFO minfo; + ZeroMemory(&minfo, sizeof(MONITORINFO)); + minfo.cbSize = sizeof(MONITORINFO); + // since DX8 cant be installed on w95, ok to statically link to GetMonInfo + // get upper-left corner coords using GetMonitorInfo + GetMonitorInfo(_windows[devnum]->_dxgsg->scrn.hMon, &minfo); + xleft=minfo.rcMonitor.left; + ytop=minfo.rcMonitor.top; + xsize=props->_xsize; + ysize=props->_ysize; + + pWindowClassName= (dx_use_dx_cursor ? WDX_WINDOWCLASSNAME_NOCURSOR : WDX_WINDOWCLASSNAME); + } else { + // specify client area, use adjustwindowrect to figure out size of final window to + // pass to CreateWin + + RECT win_rect; + SetRect(&win_rect, props->_xorg, props->_yorg, props->_xorg + props->_xsize, + props->_yorg + props->_ysize); + + if(props->_border) + final_window_style |= WS_OVERLAPPEDWINDOW; // should we just use WS_THICKFRAME instead? + + AdjustWindowRect(&win_rect, final_window_style, false); //compute window size based on desired client area size + + // make sure origin is on screen + if(win_rect.left < 0) { + win_rect.right -= win_rect.left; win_rect.left = 0; + } + if(win_rect.top < 0) { + win_rect.bottom -= win_rect.top; win_rect.top = 0; + } + + xleft=win_rect.left; + ytop= win_rect.top; + xsize=RECT_XSIZE(win_rect); + ysize=RECT_YSIZE(win_rect); + + pWindowClassName=WDX_WINDOWCLASSNAME; + } + + wdxdisplay_cat.info() << "opening " << props->_xsize << "x" << props->_ysize + << ((_windows[devnum]->_props._fullscreen) ? " fullscreen" : " regular") << " window\n"; + + if((xsize==0) || (ysize==0)) { + wdxdisplay_cat.fatal() << "can't create window with zero area for device " << devnum << "!\n"; + exit(1); + } + + // BUGBUG: this sets window posns based on desktop arrangement of monitors (that is what GetMonInfo is for). + // need to move to chancfg stuff instead (i.e. use the properties x/yorg's) when that is ready + HWND hWin = CreateWindow(pWindowClassName, props->_title.c_str(), + final_window_style, xleft,ytop,xsize,ysize, + _hParentWindow, NULL, hProgramInstance, 0); + + if(!hWin) { + wdxdisplay_cat.fatal() << "CreateWindow failed for device " << devnum << "!, LastError=" << GetLastError() << endl; + #ifdef _DEBUG + PrintErrorMessage(LAST_ERROR); + #endif + exit(1); + } + + _windows[devnum]->set_window_handle(hWin); + _windows[devnum]->_dxgsg->scrn.pProps = &_windows[devnum]->_props; + + if(devnum==0) + _hParentWindow=hWin; + } + +/* + } else { +// assert(_windows.size()==1); + + GraphicsWindow::Properties *props = &_windows[0]->_props; + + RECT win_rect; + SetRect(&win_rect, props->_xorg, props->_yorg, props->_xorg + props->_xsize, + props->_yorg + props->_ysize); + + if(props->_border) + window_style |= WS_OVERLAPPEDWINDOW; // should we just use WS_THICKFRAME instead? + + AdjustWindowRect(&win_rect, window_style, FALSE); //compute window size based on desired client area size + + // make sure origin is on screen + if(win_rect.left < 0) { + win_rect.right -= win_rect.left; win_rect.left = 0; + } + if(win_rect.top < 0) { + win_rect.bottom -= win_rect.top; win_rect.top = 0; + } + + _hParentWindow = + CreateWindow(WDX_WINDOWCLASSNAME, props->_title.c_str(), + window_style, + win_rect.left, win_rect.top, win_rect.right-win_rect.left,win_rect.bottom-win_rect.top, + NULL, NULL, hProgramInstance, 0); + _windows[0]->set_window_handle(_hParentWindow); + } + + if(_hParentWindow==NULL) { + wdxdisplay_cat.fatal() << "CreateWindow failed!\n"; + exit(1); + } +*/ + for(DWORD devnum=0;devnum<_windows.size();devnum++) { + wdxGraphicsWindow *pWDXWin = _windows[devnum]; + // for use by the window_proc + hwnd_pandawin_map[pWDXWin->_dxgsg->scrn.hWnd] = pWDXWin; + +/* + // DC is mostly used for writing fps meter (but also old palette code, which needs updating) + // probably only need to do this for devnum 0 + HDC hdc = GetDC(pWDXWin->_dxgsg_>scrn.hWnd); + pWDXWin->_dxgsg->Set_HDC(hdc); +*/ + } + + // now we can stop using the global_wdxwinptr crutch since windows are created + global_wdxwinptr = NULL; // get rid of any reference to this obj +} + +//////////////////////////////////////////////////////////////////// +// Function: config +// Access: +// Description: Set up win32 window. +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::config_window(wdxGraphicsWindowGroup *pParentGroup) { +// assert(_pParentWindowGroup==NULL); + _pParentWindowGroup=pParentGroup; + + GraphicsWindow::config(); + + _hdc = NULL; + _gsg = _dxgsg = NULL; + _exiting_window = false; + _window_active = true; + _return_control_to_app = false; + _active_minimized_fullscreen = false; + + if(_props._fullscreen || dx_full_screen) { + _props._fullscreen = dx_full_screen= true; + } + + _use_dx8_cursor = dx_use_dx_cursor; + if(!_props._fullscreen) + _use_dx8_cursor = false; + + _WindowAdjustingType = NotAdjusting; + _bSizeIsMaximized=FALSE; + + _gsg = _dxgsg = NULL; + // Create a GSG to manage the graphics + if(_gsg==NULL) { + make_gsg(); + if(_gsg==NULL) { + wdxdisplay_cat.error() << "make_gsg() failed!\n"; + exit(1); + } + } + _dxgsg = DCAST(DXGraphicsStateGuardian, _gsg); + _dxgsg->scrn.bIsDX81 = pParentGroup->_bIsDX81; + + // Check the version of the OS we are running. If we are running + // win2000, we must use ImmGetCompositionStringW() to report the + // characters returned by the IME, since WM_CHAR and + // ImmGetCompositionStringA() both just return question marks. + // However, this function doesn't work for Win98; on this OS, we + // have to use ImmGetCompositionStringA() instead, which returns an + // encoded string in shift-jis (which we then have to decode). + + // For now, this is user-configurable, to allow testing of this code + // on both OS's. After we verify that truth of the above claim, we + // should base this decision on GetVersionEx() or maybe + // VerifyVersionInfo(). + + _ime_composition_w = ime_composition_w; + + // need to re-evaluate above in light of this, it seems that + // ImmGetCompositionStringW should work on both: + // The Input Method Editor and Unicode Windows 98/Me, Windows + // NT/2000/XP: Windows supports a Unicode interface for the + // IME, in addition to the ANSI interface originally supported. + // Windows 98/Me supports all the Unicode functions except + // ImmIsUIMessage. Also, all the messages in Windows 98/Me are + // ANSI based. Since Windows 98/Me does not support Unicode + // messages, applications can use ImmGetCompositionString to + // receive Unicode characters from a Unicode based IME on + // Windows 98/Me. There are two issues involved with Unicode + // handling and the IME. One is that the Unicode versions of + // IME routines return the size of a buffer in bytes rather + // than 16-bit Unicode characters,and the other is the IME + // normally returns Unicode characters (rather than DBCS) in + // the WM_CHAR and WM_IME_CHAR messages. Use RegisterClassW + // to cause the WM_CHAR and WM_IME_CHAR messages to return + // Unicode characters in the wParam parameter rather than DBCS + // characters. This is only available under Windows NT; it is + // stubbed out in Windows 95/98/Me. +} + +void wdxGraphicsWindow::finish_window_setup(void) { + // Now indicate that we have our keyboard/mouse device ready. + GraphicsWindowInputDevice device = GraphicsWindowInputDevice::pointer_and_keyboard("keyboard/mouse"); + _input_devices.push_back(device); + + // move windows to top of zorder + HWND hWin = _dxgsg->scrn.hWnd; + + // call twice to override STARTUPINFO value, which may be set to hidden initially (by emacs for instance) + ShowWindow(hWin, SW_SHOWNORMAL); + ShowWindow(hWin, SW_SHOWNORMAL); + // UpdateWindow( _mwindow ); + SetWindowPos(hWin, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE); +} + +// this handles external programmatic requests for resizing (usually fullscrn resize) +bool wdxGraphicsWindow::resize(unsigned int xsize,unsigned int ysize) { + bool bResizeSucceeded=false; + + if((xsize==_props._xsize)&&(ysize==_props._ysize)) { + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "redundant resize() called, returning\n"; + return true; + } + + if(!_props._fullscreen) { + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "resize("<scrn.hWnd,&wi); + AdjustWindowRectEx(&win_rect, wi.dwStyle, false, wi.dwExStyle); //compute window size based on desired client area size + + // make sure origin is on screen + if(win_rect.left < 0) { + win_rect.right -= win_rect.left; win_rect.left = 0; + _props._xorg=0; + } + if(win_rect.top < 0) { + win_rect.bottom -= win_rect.top; win_rect.top = 0; + _props._yorg=0; + } + + SetWindowPos(_dxgsg->scrn.hWnd, NULL, win_rect.left,win_rect.top, RECT_XSIZE(win_rect), RECT_YSIZE(win_rect), SWP_NOZORDER | SWP_NOSENDCHANGING); + // WM_ERASEBKGND will be ignored, because _WindowAdjustingType!=NotAdjusting because + // we dont want to redraw as user is manually resizing window, so need to force explicit + // background clear for the programmatic resize fn call + _WindowAdjustingType=NotAdjusting; + + //window_proc(_mwindow, WM_ERASEBKGND,(WPARAM)_hdc,0x0); // this doesnt seem to be working in toontown resize, so I put ddraw blackblt in handle_windowed_resize instead + + return handle_windowed_resize(_dxgsg->scrn.hWnd,true); + } + + assert(IS_VALID_PTR(_dxgsg)); + + if(wdxdisplay_cat.is_info()) + wdxdisplay_cat.info() << "fullscrn resize("<SetDXReady(false); + + bool bCouldntFindValidZBuf; + D3DFORMAT pixFmt; + bool bNeedZBuffer = (_dxgsg->scrn.PresParams.EnableAutoDepthStencil!=false); + bool bNeedStencilBuffer = IS_STENCIL_FORMAT(_dxgsg->scrn.PresParams.AutoDepthStencilFormat); + + bool bIsGoodMode=false; + + if(!special_check_fullscreen_resolution(xsize,ysize)) { + // bypass the lowvidmem test below for certain "lowmem" cards we know have valid modes + + // wdxdisplay_cat.info() << "1111111 lowvidmemcard="<< _dxgsg->scrn.bIsLowVidMemCard << endl; + if(_dxgsg->scrn.bIsLowVidMemCard && (!((xsize==640) && (ysize==480)))) { + wdxdisplay_cat.error() << "resize() failed: will not try to resize low vidmem device #" << _dxgsg->scrn.CardIDNum << " to non-640x480!\n"; + goto Error_Return; + } + } + + // must ALWAYS use search_for_valid_displaymode even if we know a-priori that res is valid so we can + // get a valid pixfmt + search_for_valid_displaymode(xsize,ysize,bNeedZBuffer,bNeedStencilBuffer, + &_dxgsg->scrn.SupportedScreenDepthsMask,&bCouldntFindValidZBuf, + &pixFmt); + bIsGoodMode=(pixFmt!=D3DFMT_UNKNOWN); + + if(!bIsGoodMode) { + wdxdisplay_cat.error() << "resize() failed: " + << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes") + << " at " << xsize << "x" << ysize << " for device #" << _dxgsg->scrn.CardIDNum <scrn.DisplayMode.Width=xsize; + _dxgsg->scrn.DisplayMode.Height=ysize; + _dxgsg->scrn.DisplayMode.Format = pixFmt; + _dxgsg->scrn.DisplayMode.RefreshRate = D3DPRESENT_RATE_DEFAULT; + + _dxgsg->scrn.PresParams.BackBufferFormat = pixFmt; // make reset_device_resize use presparams or displaymode?? + + // resized(xsize,ysize); not needed? + + bResizeSucceeded=reset_device_resize_window(xsize,ysize); + + if(!bResizeSucceeded) { + wdxdisplay_cat.error() << "resize() failed with OUT-OF-MEMORY error!\n"; + + if((!IS_16BPP_DISPLAY_FORMAT(_dxgsg->scrn.PresParams.BackBufferFormat)) && + (_dxgsg->scrn.SupportedScreenDepthsMask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) { + // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers + _dxgsg->scrn.DisplayMode.Format = ((_dxgsg->scrn.SupportedScreenDepthsMask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5); + dx_force_16bpp_zbuffer=true; + if(wdxdisplay_cat.info()) + wdxdisplay_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #"<< _dxgsg->scrn.CardIDNum << endl; + + bResizeSucceeded= reset_device_resize_window(xsize,ysize); // create the new resized rendertargets + } + } + + Error_Return: + + _dxgsg->SetDXReady(true); + + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "fullscrn resize("<scrn.DXDeviceID.VendorId; + DWORD DeviceId=_dxgsg->scrn.DXDeviceID.DeviceId; + switch(VendorId) { + case 0x8086: // Intel + /*for now, just validate all the intel cards at these resolutions. + I dont have a complete list of intel deviceIDs (missing 82830, 845, etc) + // Intel i810,i815,82810 + if((DeviceId==0x7121)||(DeviceId==0x7123)||(DeviceId==0x7125)|| + (DeviceId==0x1132)) + */ + { + if((xsize==640)&&(ysize==480)) + return true; + if((xsize==800)&&(ysize==600)) + return true; + if((xsize==1024)&&(ysize==768)) + return true; + } + break; + } + + return false; +} + +UINT wdxGraphicsWindow:: +verify_window_sizes(UINT numsizes,UINT *dimen) { + // unfortunately this only works AFTER you make the window initially, + // so its really mostly useful for resizes only + assert(IS_VALID_PTR(_dxgsg)); + + UINT num_valid_modes=0; + + // not requesting same refresh rate since changing res might not support same refresh rate at new size + + UINT *pCurDim=(UINT *)dimen; + + for(UINT i=0;iscrn.bIsLowVidMemCard) { + bIsGoodMode=((xsize==640) && (ysize==480)); + } else { + search_for_valid_displaymode(xsize,ysize,_dxgsg->scrn.PresParams.EnableAutoDepthStencil!=false, + IS_STENCIL_FORMAT(_dxgsg->scrn.PresParams.AutoDepthStencilFormat), + &_dxgsg->scrn.SupportedScreenDepthsMask,&CouldntFindAnyValidZBuf, + &newPixFmt); + bIsGoodMode=(newPixFmt!=D3DFMT_UNKNOWN); + } + } + + if(bIsGoodMode) { + num_valid_modes++; + } else { + // tell caller the mode is invalid + pCurDim[0] = 0; + pCurDim[1] = 0; + } + + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "Fullscrn Mode (" << xsize << "," << ysize << ")\t" << (bIsGoodMode ? "V" : "Inv") <<"alid\n"; + } + + return num_valid_modes; +} + +BOOL WINAPI DX7_DriverEnumCallback( GUID* pGUID, TCHAR* strDesc,TCHAR* strName,VOID *argptr, HMONITOR hm) { +// #define PRNT(XX) ((XX!=NULL) ? XX : "NULL") +// cout << "strDesc: "<< PRNT(strDesc) << " strName: "<< PRNT(strName)<push_back(CurCardID); + return DDENUMRET_OK; +} + +void wdxGraphicsWindowGroup:: +find_all_card_memavails(void) { + if(g_pCardIDVec!=NULL) // we've already got the info + return; + + #define DDRAW_NAME "ddraw.dll" + + HINSTANCE hDDrawDLL = LoadLibrary(DDRAW_NAME); + if(hDDrawDLL == 0) { + wdxdisplay_cat.fatal() << "LoadLibrary(" << DDRAW_NAME <<") failed!, error=" << GetLastError() << endl; + exit(1); + } + + LPDIRECTDRAWCREATEEX pDDCreateEx; + + pDDCreateEx = (LPDIRECTDRAWCREATEEX) GetProcAddress(hDDrawDLL,"DirectDrawCreateEx"); + if(pDDCreateEx == NULL) { + wdxdisplay_cat.fatal() << "GetProcAddr failed for DDCreateEx" << endl; + exit(1); + } + + LPDIRECTDRAWENUMERATEEX pDDEnumEx = (LPDIRECTDRAWENUMERATEEX) GetProcAddress(hDDrawDLL,"DirectDrawEnumerateExA"); + if(pDDEnumEx == NULL) { + wdxdisplay_cat.fatal() << "GetProcAddr failed for DirectDrawEnumerateEx! (win95 system?)\n"; + exit(1); + } + + HRESULT hr = (*pDDEnumEx)(DX7_DriverEnumCallback, NULL, DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "DirectDrawEnumerateEx failed" << D3DERRORSTRING(hr); + exit(1); + } + + if(g_pCardIDVec==NULL) { + wdxdisplay_cat.error() << "DirectDrawEnumerateEx enum'ed no devices!\n"; + return; + } + + GUID ZeroGUID; + ZeroMemory(&ZeroGUID,sizeof(GUID)); + + if(g_pCardIDVec->size()>1) { + assert(IsEqualGUID(ZeroGUID,(*g_pCardIDVec)[0].DX7_DeviceGUID)); + // delete enum of primary display (always the first), since it is duplicated by explicit entry + g_pCardIDVec->erase(g_pCardIDVec->begin()); + } + + for(UINT i=0;isize();i++) { + LPDIRECTDRAW7 pDD; + BYTE ddd_space[sizeof(DDDEVICEIDENTIFIER2)+4]; //bug in DX7 requires 4 extra bytes for GetDeviceID + DDDEVICEIDENTIFIER2 *pDX7DeviceID=(DDDEVICEIDENTIFIER2 *)&ddd_space[0]; + GUID *pGUID= &((*g_pCardIDVec)[i].DX7_DeviceGUID); + + if(IsEqualGUID(*pGUID,ZeroGUID)) + pGUID=NULL; + + // Create the Direct Draw Object + hr = (*pDDCreateEx)(pGUID,(void **)&pDD, IID_IDirectDraw7, NULL); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "DirectDrawCreateEx failed for device ("<< i << ")" << D3DERRORSTRING(hr); + continue; + } + + ZeroMemory(ddd_space,sizeof(DDDEVICEIDENTIFIER2)); + + hr = pDD->GetDeviceIdentifier(pDX7DeviceID,0x0); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "GetDeviceID failed for device ("<< i << ")" << D3DERRORSTRING(hr); + continue; + } + + (*g_pCardIDVec)[i].DeviceID = pDX7DeviceID->dwDeviceId; + (*g_pCardIDVec)[i].VendorID = pDX7DeviceID->dwVendorId; + + // Get Current VidMem avail. Note this is only an estimate, when we switch to fullscreen + // mode from desktop, more vidmem will be available (typically 1.2 meg). I dont want + // to switch to fullscreen more than once due to the annoying monitor flicker, so try + // to figure out optimal mode using this estimate + DDSCAPS2 ddsGAVMCaps; + DWORD dwVidMemTotal,dwVidMemFree; + dwVidMemTotal=dwVidMemFree=0; + { + // print out total INCLUDING AGP just for information purposes and future use + // The real value I'm interested in for purposes of measuring possible valid screen sizes + // shouldnt include AGP + ZeroMemory(&ddsGAVMCaps,sizeof(DDSCAPS2)); + ddsGAVMCaps.dwCaps = DDSCAPS_VIDEOMEMORY; + + if(FAILED(hr = pDD->GetAvailableVidMem(&ddsGAVMCaps,&dwVidMemTotal,&dwVidMemFree))) { + wdxdisplay_cat.error() << "GetAvailableVidMem failed for device #"<< i << D3DERRORSTRING(hr); + // goto skip_device; + exit(1); // probably want to exit, since it may be my fault + } + } + wdxdisplay_cat.info() << "GetAvailableVidMem (including AGP) returns Total: "<GetAvailableVidMem(&ddsGAVMCaps,&dwVidMemTotal,&dwVidMemFree))) { + wdxdisplay_cat.error() << "GetAvailableVidMem failed for device #"<< i<< D3DERRORSTRING(hr); + // goto skip_device; + exit(1); // probably want to exit, since it may be my fault + } + + wdxdisplay_cat.info() << "GetAvailableVidMem (no AGP) returns Total: "<Release(); // release DD obj, since this is all we needed it for + + if(!dx_do_vidmemsize_check) { + // still calling the DD stuff to get deviceID, etc. is this necessary? + (*g_pCardIDVec)[i].MaxAvailVidMem = UNKNOWN_VIDMEM_SIZE; + (*g_pCardIDVec)[i].bIsLowVidMemCard = false; + continue; + } + + if(dwVidMemTotal==0) { // unreliable driver + dwVidMemTotal=UNKNOWN_VIDMEM_SIZE; + } else { + if(!ISPOW2(dwVidMemTotal)) { + // assume they wont return a proper max value, so + // round up to next pow of 2 + UINT count=0; + while((dwVidMemTotal >> count)!=0x0) + count++; + dwVidMemTotal = (1 << count); + } + } + + // after SetDisplayMode, GetAvailVidMem totalmem seems to go down by 1.2 meg (contradicting above + // comment and what I think would be correct behavior (shouldnt FS mode release the desktop vidmem?), + // so this is the true value + (*g_pCardIDVec)[i].MaxAvailVidMem = dwVidMemTotal; + + // I can never get this stuff to work reliably, so I'm just rounding up to nearest pow2. + // Could try to get HardwareInformation.MemorySize MB number from registry like video control panel, + // but its not clear how to find the proper registry location for a given card + + // #define LOWVIDMEMTHRESHOLD 3500000 + // #define CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 1000000 + + #define LOWVIDMEMTHRESHOLD 5700000 // 4MB cards should fall below this + #define CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 1000000 // if # is > 1MB, card is lying and I cant tell what it is + + // assume buggy drivers (this means you, FireGL2) may return zero (or small amts) for dwVidMemTotal, so ignore value if its < CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD + bool bLowVidMemFlag = ((dwVidMemTotal>CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD) && (dwVidMemTotal< LOWVIDMEMTHRESHOLD)); + + (*g_pCardIDVec)[i].bIsLowVidMemCard = bLowVidMemFlag; + wdxdisplay_cat.info() << "SetLowVidMem flag to "<< bLowVidMemFlag<< " based on adjusted VidMemTotal: " <=0x5100) && (_DXDeviceID.dwDeviceId<=0x5200)) || + (_DXDeviceID.dwDeviceId>=0x6000)) + bSupportsColorCursor=true; + } else if IS_MATROX(_DXDeviceID) { + if(_DXDeviceID.dwDeviceId==0x0525) // G400 seems to support color cursors, havent tested other matrox + bSupportsColorCursor=true; + } + + // TODO: add more cards as more testing is done + + if(bSupportsColorCursor) { + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + DWORD load_flags = LR_LOADFROMFILE; + + if(_props._fullscreen) { + // I think cursors should use LR_CREATEDIBSECTION since they should not be mapped to the device palette (in the case of 256-color cursors) + // since they are not going to be used on the desktop + load_flags |= LR_CREATEDIBSECTION; + } + + // loads a .cur fmt file. + HCURSOR hNewMouseCursor = (HCURSOR) LoadImage(NULL, windows_color_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, load_flags ); + + if(hNewMouseCursor==NULL) { + wdxdisplay_cat.warning() << "windows color cursor filename '" << windows_color_cursor_filename << "' not found!!\n"; + return; + } + + SetClassLongPtr(_mwindow, GCLP_HCURSOR, (LONG_PTR) hNewMouseCursor); + SetCursor(hNewMouseCursor); + + if(_bLoadedCustomCursor) + DestroyCursor(_hMouseCursor); + _hMouseCursor = hNewMouseCursor; + } +} +*/ + +int D3DFMT_to_DepthBits(D3DFORMAT fmt) { + switch(fmt) { + case D3DFMT_D16: return 16; + case D3DFMT_D24X8: + case D3DFMT_D24X4S4: + case D3DFMT_D24S8: return 24; + case D3DFMT_D32: return 32; + case D3DFMT_D15S1: return 15; + default: + wdxdisplay_cat.debug() << "D3DFMT_DepthBits: unhandled D3DFMT!\n"; + return 0; + } +} + +bool wdxGraphicsWindow::FindBestDepthFormat(DXScreenData &Display,D3DDISPLAYMODE &TestDisplayMode,D3DFORMAT *pBestFmt,bool bWantStencil,bool bForce16bpp,bool bVerboseMode) const { + // list fmts in order of preference + #define NUM_TEST_ZFMTS 3 + static D3DFORMAT NoStencilPrefList[NUM_TEST_ZFMTS]={D3DFMT_D32,D3DFMT_D24X8,D3DFMT_D16}; + static D3DFORMAT StencilPrefList[NUM_TEST_ZFMTS]={D3DFMT_D24S8,D3DFMT_D24X4S4,D3DFMT_D15S1}; + + // do not use Display.DisplayMode since that is probably not set yet, use TestDisplayMode instead + + // int want_color_bits = _props._want_color_bits; + // int want_depth_bits = _props._want_depth_bits; should we pay attn to these so panda user can select bitdepth? + + *pBestFmt = D3DFMT_UNKNOWN; + HRESULT hr; + + // nvidia likes zbuf depth to match rendertarget depth + bool bOnlySelect16bpp= (dx_force_16bpp_zbuffer || bForce16bpp || + (IS_NVIDIA(Display.DXDeviceID) && IS_16BPP_DISPLAY_FORMAT(TestDisplayMode.Format))); + + if(bVerboseMode) + wdxdisplay_cat.info() << "FindBestDepthFmt: bSelectOnly16bpp: " << bOnlySelect16bpp << endl; + + for(int i=0;iCheckDeviceFormat(Display.CardIDNum,D3DDEVTYPE_HAL,TestDisplayMode.Format, + D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,TestDepthFmt); + + if(FAILED(hr)) { + if(hr==D3DERR_NOTAVAILABLE) { + if(bVerboseMode) + wdxdisplay_cat.info() << "FindBestDepthFmt: ChkDevFmt returns NotAvail for " << D3DFormatStr(TestDepthFmt) << endl; + continue; + } + + wdxdisplay_cat.error() << "unexpected CheckDeviceFormat failure" << D3DERRORSTRING(hr); + exit(1); + } + + hr = Display.pD3D8->CheckDepthStencilMatch(Display.CardIDNum,D3DDEVTYPE_HAL, + TestDisplayMode.Format, // adapter format + TestDisplayMode.Format, // backbuffer fmt (should be the same in my apps) + TestDepthFmt); + if(SUCCEEDED(hr)) { + *pBestFmt = TestDepthFmt; + break; + } else { + if(hr==D3DERR_NOTAVAILABLE) { + if(bVerboseMode) + wdxdisplay_cat.info() << "FindBestDepthFmt: ChkDepMatch returns NotAvail for " << D3DFormatStr(TestDisplayMode.Format) << ", " << D3DFormatStr(TestDepthFmt) << endl; + } else { + wdxdisplay_cat.error() << "unexpected CheckDepthStencilMatch failure for " << D3DFormatStr(TestDisplayMode.Format) << ", " << D3DFormatStr(TestDepthFmt) << endl; + exit(1); + } + } + } + + if(bVerboseMode) + wdxdisplay_cat.info() << "FindBestDepthFmt returns fmt " << D3DFormatStr(*pBestFmt) << endl; + + return (*pBestFmt != D3DFMT_UNKNOWN); +} + +// all ptr args are output parameters +// if no valid mode found, returns *pSuggestedPixFmt = D3DFMT_UNKNOWN; +void wdxGraphicsWindow::search_for_valid_displaymode(UINT RequestedXsize,UINT RequestedYsize,bool bWantZBuffer,bool bWantStencil, + UINT *pSupportedScreenDepthsMask,bool *pCouldntFindAnyValidZBuf, + D3DFORMAT *pSuggestedPixFmt, bool bVerboseMode) { + assert(IS_VALID_PTR(_dxgsg)); + assert(IS_VALID_PTR(_dxgsg->scrn.pD3D8)); + HRESULT hr; + + #ifndef NDEBUG +// no longer true, due to special_check_fullscreen_res, where lowvidmem cards are allowed higher resolutions +// if(_dxgsg->scrn.bIsLowVidMemCard) +// nassertv((RequestedXsize==640)&&(RequestedYsize==480)); + #endif + + *pSuggestedPixFmt = D3DFMT_UNKNOWN; + *pSupportedScreenDepthsMask = 0x0; + *pCouldntFindAnyValidZBuf=false; + + int cNumModes=_dxgsg->scrn.pD3D8->GetAdapterModeCount(_dxgsg->scrn.CardIDNum); + D3DDISPLAYMODE BestDispMode; + ZeroMemory(&BestDispMode,sizeof(BestDispMode)); + + if(bVerboseMode) + wdxdisplay_cat.info() << "searching for valid display modes at res: (" << RequestedXsize << "," << RequestedYsize << "), TotalModes: " << cNumModes<< endl; + + // ignore memory based checks for min res 640x480. some cards just dont give accurate memavails. + // (should I do the check anyway for 640x480 32bpp?) + bool bDoMemBasedChecks=((!((RequestedXsize==640)&&(RequestedYsize==480))) && + (_dxgsg->scrn.MaxAvailVidMem!=UNKNOWN_VIDMEM_SIZE) && + (!special_check_fullscreen_resolution(RequestedXsize,RequestedYsize))); + + if(bVerboseMode || wdxdisplay_cat.is_spam()) { + wdxdisplay_cat.info() << "DoMemBasedChecks = " << bDoMemBasedChecks << endl; + } + + for(int i=0;iscrn.pD3D8->EnumAdapterModes(_dxgsg->scrn.CardIDNum,i,&dispmode); + if(FAILED(hr)) { + wdxdisplay_cat.error() << "EnumAdapterDisplayMode failed for device #"<<_dxgsg->scrn.CardIDNum<< D3DERRORSTRING(hr); + exit(1); + } + + if((dispmode.Width!=RequestedXsize) || (dispmode.Height!=RequestedYsize)) + continue; + + if((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) { + // dont want refresh rates under 60Hz, but 0 or 1 might indicate a default refresh rate, which is usually >=60 + if(bVerboseMode) + wdxdisplay_cat.info() << "skipping mode["<scrn.pD3D8->CheckDeviceFormat(_dxgsg->scrn.CardIDNum,D3DDEVTYPE_HAL,dispmode.Format, + D3DUSAGE_RENDERTARGET,D3DRTYPE_SURFACE,dispmode.Format); + if(FAILED(hr)) { + if(hr==D3DERR_NOTAVAILABLE) { + if(bVerboseMode) + wdxdisplay_cat.info() << "skipping mode["<scrn.CardIDNum << D3DERRORSTRING(hr); + exit(1); + } + } + + bool bIs16bppRenderTgt = IS_16BPP_DISPLAY_FORMAT(dispmode.Format); + float RendTgtMinMemReqmt; + + // if we have a valid memavail value, try to determine if we have enough space + if( bDoMemBasedChecks) { + + // assume user is testing fullscreen, not windowed, so use the dwTotal value + // see if 3 scrnbufs (front/back/z)at 16bpp at xsize*ysize will fit with a few + // extra megs for texmem + + // 8MB Rage Pro says it has 6.8 megs Total free and will run at 1024x768, so + // formula makes it so that is OK + + #define REQD_TEXMEM 1800000 + + float bytes_per_pixel = (bIs16bppRenderTgt ? 2 : 4); + assert(_props._mask & W_DOUBLE); + + // *2 for double buffer + + RendTgtMinMemReqmt = ((float)RequestedXsize)*((float)RequestedYsize)*bytes_per_pixel*2+REQD_TEXMEM; + + if(bVerboseMode || wdxdisplay_cat.is_spam()) + wdxdisplay_cat.info() << "Testing Mode (" <scrn.MaxAvailVidMem << endl; + + if(RendTgtMinMemReqmt>_dxgsg->scrn.MaxAvailVidMem) { + if(bVerboseMode || wdxdisplay_cat.is_debug()) + wdxdisplay_cat.info() << "not enough VidMem for render tgt, skipping display fmt " << D3DFormatStr(dispmode.Format) + << " (" << (int)RendTgtMinMemReqmt << " > " << _dxgsg->scrn.MaxAvailVidMem << ")\n"; + continue; + } + } + + if(bWantZBuffer) { + D3DFORMAT zformat; + if(!FindBestDepthFormat(_dxgsg->scrn,dispmode,&zformat,bWantStencil,false)) { + *pCouldntFindAnyValidZBuf=true; + continue; + } + + float MinMemReqmt = 0.0f; + + if(bDoMemBasedChecks) { + // test memory again, this time including zbuf size + float zbytes_per_pixel = (IS_16BPP_ZBUFFER(zformat) ? 2 : 4); + float MinMemReqmt = RendTgtMinMemReqmt + ((float)RequestedXsize)*((float)RequestedYsize)*zbytes_per_pixel; + + if(bVerboseMode || wdxdisplay_cat.is_spam()) + wdxdisplay_cat.info() << "Testing Mode w/Z (" << RequestedXsize << "x" << RequestedYsize << "," + << D3DFormatStr(dispmode.Format) << ")\nReqdVidMem: "<< (int)MinMemReqmt << " AvailVidMem: " << _dxgsg->scrn.MaxAvailVidMem << endl; + + if(MinMemReqmt>_dxgsg->scrn.MaxAvailVidMem) { + if(bVerboseMode || wdxdisplay_cat.is_debug()) + wdxdisplay_cat.info() << "not enough VidMem for RendTgt+zbuf, skipping display fmt " << D3DFormatStr(dispmode.Format) + << " (" << (int)MinMemReqmt << " > " << _dxgsg->scrn.MaxAvailVidMem << ")\n"; + continue; + } + } + + if((!bDoMemBasedChecks) || (MinMemReqmt<_dxgsg->scrn.MaxAvailVidMem)) { + if(!IS_16BPP_ZBUFFER(zformat)) { + // see if things fit with a 16bpp zbuffer + + if(!FindBestDepthFormat(_dxgsg->scrn,dispmode,&zformat,bWantStencil,true,bVerboseMode)) { + if(bVerboseMode) + wdxdisplay_cat.info() << "FindBestDepthFmt rejected Mode["<VendorId==0x00008086) + return true; + + return false; +} + +// returns true if successful +bool wdxGraphicsWindow::search_for_device(LPDIRECT3D8 pD3D8,DXDeviceInfo *pDevInfo) { + DWORD dwRenderWidth = _props._xsize; + DWORD dwRenderHeight = _props._ysize; + HRESULT hr; + + assert(_dxgsg!=NULL); + _dxgsg->scrn.pD3D8 = pD3D8; + _dxgsg->scrn.CardIDNum=pDevInfo->cardID; // could this change by end? + + bool bWantStencil = ((_props._mask & W_STENCIL)!=0); + + hr = pD3D8->GetAdapterIdentifier(pDevInfo->cardID,D3DENUM_NO_WHQL_LEVEL,&_dxgsg->scrn.DXDeviceID); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "D3D GetAdapterID failed" << D3DERRORSTRING(hr); + } + + D3DCAPS8 d3dcaps; + hr = pD3D8->GetDeviceCaps(pDevInfo->cardID,D3DDEVTYPE_HAL,&d3dcaps); + if(FAILED(hr)) { + if((hr==D3DERR_INVALIDDEVICE)||(hr==D3DERR_NOTAVAILABLE)) { + wdxdisplay_cat.fatal() << "No DirectX 8 D3D-capable 3D hardware detected for device # "<cardID<<" ("<szDescription << ")! Exiting...\n"; + } else { + wdxdisplay_cat.fatal() << "GetDeviceCaps failed" << D3DERRORSTRING(hr); + } + exit(1); + } + + //search_for_valid_displaymode needs these to be set + memcpy(&_dxgsg->scrn.d3dcaps,&d3dcaps,sizeof(D3DCAPS8)); + _dxgsg->scrn.CardIDNum=pDevInfo->cardID; + + _dxgsg->scrn.MaxAvailVidMem = UNKNOWN_VIDMEM_SIZE; + _dxgsg->scrn.bIsLowVidMemCard = false; + + // bugbug: wouldnt we like to do GetAVailVidMem so we can do upper-limit memory computation for dx8 cards too? + // otherwise verify_window_sizes cant do much + if((d3dcaps.MaxStreams==0)|| dx_pick_best_screenres) { + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "checking vidmem size\n"; + assert(IS_VALID_PTR(_pParentWindowGroup)); + + // look for low memory video cards + _pParentWindowGroup->find_all_card_memavails(); + + UINT IDnum; + + // simple linear search to match DX7 card info w/DX8 card ID + for(IDnum=0;IDnumsize();IDnum++) { +// wdxdisplay_cat.info() << "comparing '" << (*g_pCardIDVec)[IDnum].Driver << "' to '" << _dxgsg->scrn.DXDeviceID.Driver << "'\n"; + if(//(stricmp((*g_pCardIDVec)[IDnum].szDriver,pDevInfo->szDriver)==0) && + (pDevInfo->VendorID==(*g_pCardIDVec)[IDnum].VendorID) && + (pDevInfo->DeviceID==(*g_pCardIDVec)[IDnum].DeviceID) && + (pDevInfo->hMon==(*g_pCardIDVec)[IDnum].hMon)) + break; + } + + if(IDnumsize()) { + _dxgsg->scrn.MaxAvailVidMem = (*g_pCardIDVec)[IDnum].MaxAvailVidMem; + _dxgsg->scrn.bIsLowVidMemCard = (*g_pCardIDVec)[IDnum].bIsLowVidMemCard; + } else wdxdisplay_cat.error() << "Error: couldnt find a CardID match in DX7 info, assuming card is not a lowmem card\n"; + } + + if((bWantStencil) && (d3dcaps.StencilCaps==0x0)) { + wdxdisplay_cat.fatal() << "Stencil ability requested, but device #" << pDevInfo->cardID << " (" << _dxgsg->scrn.DXDeviceID.Description<<"), has no stencil capability!\n"; + exit(1); + } + + // just because TNL is true, it doesnt mean vtx shaders are supported in HW (see GF2) + // for this case, you probably want MIXED processing to use HW for fixed-fn vertex processing + // and SW for vtx shaders + _dxgsg->scrn.bIsTNLDevice=((d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)!=0); + _dxgsg->scrn.bCanUseHWVertexShaders = (d3dcaps.VertexShaderVersion >= D3DVS_VERSION(1,0)); + _dxgsg->scrn.bCanUsePixelShaders = (d3dcaps.PixelShaderVersion >= D3DPS_VERSION(1,0)); + + bool bNeedZBuffer = ((!(d3dcaps.RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) + && (_props._mask & W_DEPTH)); + + _dxgsg->scrn.PresParams.EnableAutoDepthStencil=bNeedZBuffer; + + D3DFORMAT pixFmt=D3DFMT_UNKNOWN; + + if(_props._fullscreen) { + _props._xorg = _props._yorg = 0; + + bool bCouldntFindValidZBuf; + if(!_dxgsg->scrn.bIsLowVidMemCard) { + bool bUseDefaultSize=dx_pick_best_screenres&& + ((_dxgsg->scrn.MaxAvailVidMem == UNKNOWN_VIDMEM_SIZE) || + is_badvidmem_card(&_dxgsg->scrn.DXDeviceID)); + + if(dx_pick_best_screenres && !bUseDefaultSize) { + typedef struct { + UINT memlimit; + DWORD scrnX,scrnY; + } Memlimres; + + const Memlimres MemRes[] = { + { 0, 640, 480}, + { 8000000, 800, 600}, + #if 0 + {16000000, 1024, 768}, + {32000000, 1280,1024}, // 32MB+ cards will choose this + #else + // unfortunately the 32MB card perf varies greatly (TNT2-GF2), + // so we need to be conservative since frame rate difference + // can change from 15->30fps when going from 1280x1024->800x600 + // on low-end 32mb cards + {16000000, 800, 600}, + {32000000, 800, 600}, // 32MB+ cards will choose this + #endif + // some monitors have trouble w/1600x1200, so dont pick this by deflt, + // even though 64MB cards should handle it + {64000000, 1280,1024} // 64MB+ cards will choose this + }; + const NumResLims = (sizeof(MemRes)/sizeof(Memlimres)); + + for(int i=NumResLims-1;i>=0;i--) { + // find biggest slot card can handle + if(_dxgsg->scrn.MaxAvailVidMem > MemRes[i].memlimit) { + dwRenderWidth=MemRes[i].scrnX; + dwRenderHeight=MemRes[i].scrnY; + + wdxdisplay_cat.info() << "pick_best_screenres: trying " << dwRenderWidth << "x" << dwRenderHeight << " based on " << _dxgsg->scrn.MaxAvailVidMem << " bytes avail\n"; + + search_for_valid_displaymode(dwRenderWidth,dwRenderHeight,bNeedZBuffer,bWantStencil, + &_dxgsg->scrn.SupportedScreenDepthsMask, + &bCouldntFindValidZBuf, + &pixFmt); + + // note I'm not saving refresh rate, will just use adapter default at given res for now + + if(pixFmt!=D3DFMT_UNKNOWN) + break; + + wdxdisplay_cat.info() << "skipping scrnres; " + << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes") + << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _dxgsg->scrn.CardIDNum << endl; + } + } + // otherwise just go with whatever was specified (we probably shouldve marked this card as lowmem if it gets to end of loop w/o breaking + } + + if(pixFmt==D3DFMT_UNKNOWN) { + + if(bUseDefaultSize) { + wdxdisplay_cat.info() << "pick_best_screenres: defaulted 800x600 based on no reliable vidmem size\n"; + dwRenderWidth=800; dwRenderHeight=600; + } + + search_for_valid_displaymode(dwRenderWidth,dwRenderHeight,bNeedZBuffer,bWantStencil, + &_dxgsg->scrn.SupportedScreenDepthsMask, + &bCouldntFindValidZBuf, + &pixFmt); + + // note I'm not saving refresh rate, will just use adapter default at given res for now + + if(pixFmt==D3DFMT_UNKNOWN) { + wdxdisplay_cat.fatal() + << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes") + << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _dxgsg->scrn.CardIDNum <scrn.SupportedScreenDepthsMask, + &bCouldntFindValidZBuf, + &pixFmt,true); + return false; + } + } + } else { + // Low Memory card + dwRenderWidth=640; + dwRenderHeight=480; + dx_force_16bpptextures = true; + + // force 16bpp zbuf? or let user get extra bits if they have the mem? + + search_for_valid_displaymode(dwRenderWidth,dwRenderHeight,bNeedZBuffer,bWantStencil, + &_dxgsg->scrn.SupportedScreenDepthsMask, + &bCouldntFindValidZBuf, + &pixFmt); + + // hack: figuring out exactly what res to use is tricky, instead I will + // just use 640x480 if we have < 3 meg avail + + if(_dxgsg->scrn.SupportedScreenDepthsMask & R5G6B5_FLAG) + pixFmt = D3DFMT_R5G6B5; + else if(_dxgsg->scrn.SupportedScreenDepthsMask & X1R5G5B5_FLAG) + pixFmt = D3DFMT_X1R5G5B5; + else { + wdxdisplay_cat.fatal() << "Low Memory VidCard has no supported FullScreen 16bpp resolutions at "<< dwRenderWidth << "x" << dwRenderHeight + << " for device #" << pDevInfo->cardID << " (" << _dxgsg->scrn.DXDeviceID.Description <<"), skipping device...\n"; + + // run it again in verbose mode to get more dbg info to log + search_for_valid_displaymode(dwRenderWidth,dwRenderHeight,bNeedZBuffer,bWantStencil, + &_dxgsg->scrn.SupportedScreenDepthsMask, + &bCouldntFindValidZBuf, + &pixFmt,true); + return false; + } + + if(wdxdisplay_cat.is_info()) + wdxdisplay_cat.info() << "Available VidMem (" << _dxgsg->scrn.MaxAvailVidMem << ") is under " << LOWVIDMEMTHRESHOLD <<", using 640x480 16bpp rendertargets to save tex vidmem.\n"; + } + } else { + // Windowed Mode + + D3DDISPLAYMODE dispmode; + hr=pD3D8->GetAdapterDisplayMode(pDevInfo->cardID,&dispmode); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "GetAdapterDisplayMode(" << pDevInfo->cardID << ") failed" << D3DERRORSTRING(hr); + exit(1); + } + pixFmt = dispmode.Format; + } + + _dxgsg->scrn.DisplayMode.Width=dwRenderWidth; + _dxgsg->scrn.DisplayMode.Height=dwRenderHeight; + _dxgsg->scrn.DisplayMode.Format = pixFmt; + _dxgsg->scrn.DisplayMode.RefreshRate = D3DPRESENT_RATE_DEFAULT; + _dxgsg->scrn.hMon=pDevInfo->hMon; + return true; +} + +//return true if successful +void wdxGraphicsWindow:: +CreateScreenBuffersAndDevice(DXScreenData &Display) { + + // only want this to apply to initial startup + dx_pick_best_screenres=false; + + DWORD dwRenderWidth=Display.DisplayMode.Width; + DWORD dwRenderHeight=Display.DisplayMode.Height; + LPDIRECT3D8 pD3D8=Display.pD3D8; + D3DCAPS8 *pD3DCaps = &Display.d3dcaps; + D3DPRESENT_PARAMETERS* pPresParams = &Display.PresParams; + RECT view_rect; + HRESULT hr; + bool bWantStencil = ((_props._mask & W_STENCIL)!=0); + + assert(pD3D8!=NULL); + assert(pD3DCaps->DevCaps & D3DDEVCAPS_HWRASTERIZATION); + + #ifndef NDEBUG + if(!(_props._mask & W_DEPTH)) { + wdxdisplay_cat.info() << "no zbuffer requested, skipping zbuffer creation\n"; + } + #endif + + pPresParams->BackBufferFormat = Display.DisplayMode.Format; // dont need dest alpha, so just use adapter format + + if(dx_sync_video && !(pD3DCaps->Caps & D3DCAPS_READ_SCANLINE)) { + wdxdisplay_cat.info() << "HW doesnt support syncing to vertical refresh, ignoring dx_sync_video\n"; + dx_sync_video=false; + } + + // verify the rendertarget fmt one last time + if(FAILED(pD3D8->CheckDeviceFormat(Display.CardIDNum, D3DDEVTYPE_HAL, Display.DisplayMode.Format,D3DUSAGE_RENDERTARGET, + D3DRTYPE_SURFACE, pPresParams->BackBufferFormat))) { + wdxdisplay_cat.error() << "device #"<BackBufferFormat) << endl; + goto Fallback_to_16bpp_buffers; + } + + if(FAILED(pD3D8->CheckDeviceType(Display.CardIDNum,D3DDEVTYPE_HAL, Display.DisplayMode.Format,pPresParams->BackBufferFormat, + _props._fullscreen))) { + wdxdisplay_cat.error() << "device #"<BackBufferFormat) << endl; + goto Fallback_to_16bpp_buffers; + } + + if(Display.PresParams.EnableAutoDepthStencil) { + if(!FindBestDepthFormat(Display,Display.DisplayMode,&Display.PresParams.AutoDepthStencilFormat,bWantStencil,false)) { + wdxdisplay_cat.error() << "FindBestDepthFormat failed in CreateScreenBuffers for device #"<Windowed = !_props._fullscreen; + + if(dx_multisample_antialiasing_level>1) { + // need to check both rendertarget and zbuffer fmts + hr = pD3D8->CheckDeviceMultiSampleType(Display.CardIDNum, D3DDEVTYPE_HAL, Display.DisplayMode.Format, + _props._fullscreen, D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level)); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "device #"<CheckDeviceMultiSampleType(Display.CardIDNum, D3DDEVTYPE_HAL, Display.PresParams.AutoDepthStencilFormat, + _props._fullscreen, D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level)); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "device #"<MultiSampleType = D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level); + + if(wdxdisplay_cat.is_info()) + wdxdisplay_cat.info() << "device #"<BackBufferCount = 1; + pPresParams->Flags = 0x0; + pPresParams->hDeviceWindow = Display.hWnd; + pPresParams->BackBufferWidth = Display.DisplayMode.Width; + pPresParams->BackBufferHeight = Display.DisplayMode.Height; + DWORD dwBehaviorFlags=0x0; + + if(_dxgsg->scrn.bIsTNLDevice) { + dwBehaviorFlags|=D3DCREATE_HARDWARE_VERTEXPROCESSING; + // note: we could create a pure device in this case if I eliminated the GetRenderState calls in dxgsg + + // also, no software vertex processing available since I specify D3DCREATE_HARDWARE_VERTEXPROCESSING + // and not D3DCREATE_MIXED_VERTEXPROCESSING + } else { + dwBehaviorFlags|=D3DCREATE_SOFTWARE_VERTEXPROCESSING; + } + + if(dx_preserve_fpu_state) + dwBehaviorFlags|=D3DCREATE_FPU_PRESERVE; + + // if window is not foreground in exclusive mode, ddraw thinks you are 'not active', so + // it changes your WM_ACTIVATEAPP from true to false, causing us + // to go into a 'wait-for WM_ACTIVATEAPP true' loop, and the event never comes so we hang + // in fullscreen wait. also doing this for windowed mode since it was requested. + if(!SetForegroundWindow(Display.hWnd)) { + wdxdisplay_cat.warning() << "SetForegroundWindow() failed!\n"; + } + + if(_props._fullscreen) { + pPresParams->SwapEffect = D3DSWAPEFFECT_DISCARD; // we dont care about preserving contents of old frame + pPresParams->FullScreen_PresentationInterval = (dx_sync_video ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE); + pPresParams->FullScreen_RefreshRateInHz = Display.DisplayMode.RefreshRate; + +#if 0 +/* this is incorrect, we dont need rendertarget to hold alpha to do normal alpha blending, since blending is usually just + based on source alpha. so for now its OK to pick rendertargets with same format as display + + // assume app requires alpha-blending + // will fullscrn alphablend work with DISCARD anyway even if this cap is not set? I dont see it being set by latest drivers + // for any card. need to test both dx8.0 and dx8.1, it may be that dx8.1 works even if cap is not set, but 8.0 doesnt + if((!Display.bIsDX81) || (!(d3dcaps.Caps3 & D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD))) { + pPresParams->SwapEffect = (dx_sync_video ? D3DSWAPEFFECT_COPY_VSYNC : D3DSWAPEFFECT_COPY); + + if(pPresParams->MultiSampleType != D3DMULTISAMPLE_NONE) { + wdxdisplay_cat.fatal() << "device #"<MultiSampleType != D3DMULTISAMPLE_NONE) + assert(pPresParams->SwapEffect == D3DSWAPEFFECT_DISCARD); // only valid effect for multisample + #endif + + ClearToBlack(Display.hWnd,_props); + + hr = pD3D8->CreateDevice(Display.CardIDNum, D3DDEVTYPE_HAL, _pParentWindowGroup->_hParentWindow, + dwBehaviorFlags, pPresParams, &Display.pD3DDevice); + + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "D3D CreateDevice failed for device #" << Display.CardIDNum << ", " << D3DERRORSTRING(hr); + + if(hr == D3DERR_OUTOFVIDEOMEMORY) + goto Fallback_to_16bpp_buffers; + } + + SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight); + } // end create full screen buffers + + else { // CREATE WINDOWED BUFFERS + + if(!(pD3DCaps->Caps2 & D3DCAPS2_CANRENDERWINDOWED)) { + wdxdisplay_cat.fatal() << "the 3D HW cannot render windowed, exiting..." << endl; + exit(1); + } + + D3DDISPLAYMODE dispmode; + hr = Display.pD3D8->GetAdapterDisplayMode(Display.CardIDNum, &dispmode); + + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "GetAdapterDisplayMode failed" << D3DERRORSTRING(hr); + exit(1); + } + + if(dispmode.Format == D3DFMT_P8) { + wdxdisplay_cat.fatal() << "Can't run windowed in an 8-bit or less display mode" << endl; + exit(1); + } + + pPresParams->FullScreen_PresentationInterval = 0; + + if(dx_multisample_antialiasing_level<2) { + if(dx_sync_video) { + pPresParams->SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; + } else { + pPresParams->SwapEffect = D3DSWAPEFFECT_DISCARD; //D3DSWAPEFFECT_COPY; does this make any difference? + } + } else { + pPresParams->SwapEffect = D3DSWAPEFFECT_DISCARD; + } + + assert((dwRenderWidth==pPresParams->BackBufferWidth)&&(dwRenderHeight==pPresParams->BackBufferHeight)); + + hr = pD3D8->CreateDevice(Display.CardIDNum, D3DDEVTYPE_HAL, _pParentWindowGroup->_hParentWindow, + dwBehaviorFlags, pPresParams, &Display.pD3DDevice); + + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "D3D CreateDevice failed for device #" << Display.CardIDNum << D3DERRORSTRING(hr); + exit(1); + } + } // end create windowed buffers + +// ======================================================== + + PRINT_REFCNT(wdxdisplay,_dxgsg->scrn.pD3DDevice); + + if(pPresParams->EnableAutoDepthStencil) { + _dxgsg->_buffer_mask |= RenderBuffer::T_depth; + if(IS_STENCIL_FORMAT(pPresParams->AutoDepthStencilFormat)) + _dxgsg->_buffer_mask |= RenderBuffer::T_stencil; + } + + init_resized_window(); + + return; + +Fallback_to_16bpp_buffers: + + if((!IS_16BPP_DISPLAY_FORMAT(pPresParams->BackBufferFormat)) && + (Display.SupportedScreenDepthsMask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) { + // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers + + Display.DisplayMode.Format = ((Display.SupportedScreenDepthsMask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5); + + dx_force_16bpp_zbuffer=true; + if(wdxdisplay_cat.info()) + wdxdisplay_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #"<< Display.CardIDNum << endl; + CreateScreenBuffersAndDevice(Display); + return; + } else if(!((dwRenderWidth==640)&&(dwRenderHeight==480))) { + if(wdxdisplay_cat.info()) + wdxdisplay_cat.info() << "CreateDevice failed w/out-of-vidmem, retrying at 640x480 w/16bpp buffers on device #"<< Display.CardIDNum << endl; + // try final fallback to 640x480x16 + dx_force_16bpp_zbuffer=true; + Display.DisplayMode.Width=640; + Display.DisplayMode.Height=480; + CreateScreenBuffersAndDevice(Display); + return; + } else { + exit(1); + } +} + +// assumes CreateDevice or Device->Reset() has just been called, +// and the new size is specified in _dxgsg->scrn.PresParams +void wdxGraphicsWindow::init_resized_window(void) { + DXScreenData *pDisplay=&_dxgsg->scrn; + HRESULT hr; + + DWORD newWidth = pDisplay->PresParams.BackBufferWidth; + DWORD newHeight = pDisplay->PresParams.BackBufferHeight; + + if(pDisplay->PresParams.Windowed) { + POINT ul,lr; + RECT client_rect; + + // need to figure out x,y origin offset of window client area on screen + // (we already know the client area size) + + GetClientRect(pDisplay->hWnd, &client_rect); + ul.x=client_rect.left; ul.y=client_rect.top; + lr.x=client_rect.right; lr.y=client_rect.bottom; + ClientToScreen(pDisplay->hWnd, &ul); + ClientToScreen(pDisplay->hWnd, &lr); + client_rect.left=ul.x; client_rect.top=ul.y; + client_rect.right=lr.x; client_rect.bottom=lr.y; + _props._xorg = client_rect.left; // _props should reflect view rectangle + _props._yorg = client_rect.top; + + #ifdef _DEBUG + // try to make sure GDI and DX agree on window client area size + // but client rect will not include any offscreen areas, so dont + // do check if window was bigger than screen (there are other bad + // cases too, like when window is positioned partly offscreen, + // or if window trim border make size bigger than screen) + + RECT desktop_rect; + GetClientRect(GetDesktopWindow(), &desktop_rect); + if((_props._xsizehWnd,_props); + + // clear textures and VB's out of video&AGP mem, so cache is reset + hr = pDisplay->pD3DDevice->ResourceManagerDiscardBytes(0); + if(FAILED(hr)) { + wdxdisplay_cat.error() << "ResourceManagerDiscardBytes failed for device #" << pDisplay->CardIDNum << D3DERRORSTRING(hr); + } + + // Create the viewport + D3DVIEWPORT8 vp = {0,0,_props._xsize,_props._ysize,0.0f,1.0f}; + hr = pDisplay->pD3DDevice->SetViewport( &vp ); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "SetViewport failed for device #" << pDisplay->CardIDNum << D3DERRORSTRING(hr); + exit(1); + } + + _dxgsg->dx_init(_pParentWindowGroup->_hMouseCursor); + // do not SetDXReady() yet since caller may want to do more work before letting rendering proceed + + SetCursor(_pParentWindowGroup->_hMouseCursor); + set_cursor_visibility(true); +} + +// does NOT override _props._bCursorIsVisible +INLINE void wdxGraphicsWindow::set_cursor_visibility(bool bVisible) { + bool bValidDXPtrs; + + if(_use_dx8_cursor) + bValidDXPtrs = (IS_VALID_PTR(_dxgsg) && IS_VALID_PTR(_dxgsg->scrn.pD3DDevice)); + + if(_props._bCursorIsVisible) { + if(_use_dx8_cursor) { + ShowCursor(false); + if(bValidDXPtrs) + _dxgsg->scrn.pD3DDevice->ShowCursor(bVisible); + } else { + ShowCursor(bVisible); + } + } else { + ShowCursor(false); + if(_use_dx8_cursor && bValidDXPtrs) + _dxgsg->scrn.pD3DDevice->ShowCursor(false); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: setup_colormap +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::setup_colormap(void) { + PIXELFORMATDESCRIPTOR pfd; + LOGPALETTE *logical; + int n; + + // should probably do this some other way than through opengl PixelFormat calls + + /* grab the pixel format */ + memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + DescribePixelFormat(_hdc, GetPixelFormat(_hdc), + sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + if(!(pfd.dwFlags & PFD_NEED_PALETTE || + pfd.iPixelType == PFD_TYPE_COLORINDEX)) + return; + + n = 1 << pfd.cColorBits; + + /* allocate a bunch of memory for the logical palette (assume 256 + colors in a Win32 palette */ + logical = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + + sizeof(PALETTEENTRY) * n); + memset(logical, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n); + + /* set the entries in the logical palette */ + logical->palVersion = 0x300; + logical->palNumEntries = n; + + /* start with a copy of the current system palette */ + GetSystemPaletteEntries(_hdc, 0, 256, &logical->palPalEntry[0]); + + if(pfd.iPixelType == PFD_TYPE_RGBA) { + int redMask = (1 << pfd.cRedBits) - 1; + int greenMask = (1 << pfd.cGreenBits) - 1; + int blueMask = (1 << pfd.cBlueBits) - 1; + int i; + + /* fill in an RGBA color palette */ + for(i = 0; i < n; ++i) { + logical->palPalEntry[i].peRed = + (((i >> pfd.cRedShift) & redMask) * 255) / redMask; + logical->palPalEntry[i].peGreen = + (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask; + logical->palPalEntry[i].peBlue = + (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask; + logical->palPalEntry[i].peFlags = 0; + } + } + + _colormap = CreatePalette(logical); + free(logical); + + SelectPalette(_hdc, _colormap, FALSE); + RealizePalette(_hdc); +} + +/* dont need to override the defaults (which just go to gsg->begin_frame()) +//////////////////////////////////////////////////////////////////// +// Function: begin_frame +// Access: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::begin_frame(void) { + GraphicsWindow::begin_frame(); +} + +//////////////////////////////////////////////////////////////////// +// Function: end_frame +// Access: +// Description: timer info, incs frame # +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::end_frame(void) { + GraphicsWindow::end_frame(); +} +*/ + +//////////////////////////////////////////////////////////////////// +// Function: handle_window_move +// Access: +// Description: we receive the new x and y position of the client +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::handle_window_move(int x, int y) { + _props._xorg = x; + _props._yorg = y; +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_mouse_motion +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::handle_mouse_motion(int x, int y) { + _input_devices[0].set_pointer_in_window(x, y); +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_mouse_exit +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::handle_mouse_exit(void) { + _input_devices[0].set_pointer_out_of_window(); +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_keypress +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow:: +handle_keypress(ButtonHandle key, int x, int y) { +/* + if(key.has_ascii_equivalent()) { + wdxdisplay_cat.spam() << key.get_ascii_equivalent() << endl; + + short d1 = GetKeyState(VK_CONTROL); + short d2 = GetKeyState(VK_SHIFT); + wdxdisplay_cat.spam().flags(ios::hex | ios::uppercase ); + wdxdisplay_cat.spam() << " Control: " << ((d1 < 0)? "down" : "up") << " Shift: " << ((d2 < 0)? "down" : "up") << endl; + } +*/ + _input_devices[0].set_pointer_in_window(x, y); + if(key != ButtonHandle::none()) { + _input_devices[0].button_down(key); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_keyrelease +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow:: +handle_keyrelease(ButtonHandle key) { + if(key != ButtonHandle::none()) { + _input_devices[0].button_up(key); + } +} + +void INLINE process_1_event(void) { + MSG msg; + + if(!GetMessage(&msg, NULL, 0, 0)) { + // WM_QUIT received + DestroyAllWindows(false); + exit(msg.wParam); // this will invoke AtExitFn + } + + // Translate virtual key messages + TranslateMessage(&msg); + // Call window_proc + DispatchMessage(&msg); +} + +void INLINE wdxGraphicsWindow::process_events(void) { + if(!_window_active) { + // Get 1 msg at a time until no more are left and we block and sleep, + // or message changes _return_control_to_app or _window_active status + + while((!_window_active) && (!_return_control_to_app)) { + process_1_event(); + } + _return_control_to_app = false; + + } else { + MSG msg; + + // handle all msgs on queue in a row + while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + process_1_event(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsWindow::get_gsg_type +// Access: Public, Virtual +// Description: Returns the TypeHandle of the kind of GSG preferred +// by this kind of window. +//////////////////////////////////////////////////////////////////// +TypeHandle wdxGraphicsWindow:: +get_gsg_type() const { + return DXGraphicsStateGuardian::get_class_type(); +} + +GraphicsWindow *wdxGraphicsWindow:: +make_wdxGraphicsWindow(const FactoryParams ¶ms) { + GraphicsWindow::WindowPipe *pipe_param; + if(!get_param_into(pipe_param, params)) { + wdxdisplay_cat.error() + << "No pipe specified for window creation!" << endl; + return NULL; + } + + GraphicsPipe *pipe = pipe_param->get_pipe(); + + GraphicsWindow::WindowProps *props_param; + if(!get_param_into(props_param, params)) { + return new wdxGraphicsWindow(pipe); + } else { + return new wdxGraphicsWindow(pipe, props_param->get_properties()); + } +} + +TypeHandle wdxGraphicsWindow::get_class_type(void) { + return _type_handle; +} + +void wdxGraphicsWindow::init_type(void) { + GraphicsWindow::init_type(); + register_type(_type_handle, "wdxGraphicsWindow8", + GraphicsWindow::get_class_type()); +} + +TypeHandle wdxGraphicsWindow::get_type(void) const { + return get_class_type(); +} + +//////////////////////////////////////////////////////////////////// +// Function: lookup_key +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +ButtonHandle wdxGraphicsWindow:: +lookup_key(WPARAM wparam) const { + // First, check for a few buttons that we filter out when the IME + // window is open. + if (!_ime_active) { + switch(wparam) { + case VK_BACK: return KeyboardButton::backspace(); + case VK_DELETE: return KeyboardButton::del(); + case VK_ESCAPE: return KeyboardButton::escape(); + case VK_SPACE: return KeyboardButton::space(); + case VK_UP: return KeyboardButton::up(); + case VK_DOWN: return KeyboardButton::down(); + case VK_LEFT: return KeyboardButton::left(); + case VK_RIGHT: return KeyboardButton::right(); + } + } + + // Now check for the rest of the buttons, including the ones that + // we allow through even when the IME window is open. + switch(wparam) { + case VK_TAB: return KeyboardButton::tab(); + case VK_PRIOR: return KeyboardButton::page_up(); + case VK_NEXT: return KeyboardButton::page_down(); + case VK_HOME: return KeyboardButton::home(); + case VK_END: return KeyboardButton::end(); + case VK_F1: return KeyboardButton::f1(); + case VK_F2: return KeyboardButton::f2(); + case VK_F3: return KeyboardButton::f3(); + case VK_F4: return KeyboardButton::f4(); + case VK_F5: return KeyboardButton::f5(); + case VK_F6: return KeyboardButton::f6(); + case VK_F7: return KeyboardButton::f7(); + case VK_F8: return KeyboardButton::f8(); + case VK_F9: return KeyboardButton::f9(); + case VK_F10: return KeyboardButton::f10(); + case VK_F11: return KeyboardButton::f11(); + case VK_F12: return KeyboardButton::f12(); + case VK_INSERT: return KeyboardButton::insert(); + case VK_CAPITAL: return KeyboardButton::caps_lock(); + case VK_NUMLOCK: return KeyboardButton::num_lock(); + case VK_SCROLL: return KeyboardButton::scroll_lock(); + case VK_SNAPSHOT: return KeyboardButton::print_screen(); + + case VK_SHIFT: + case VK_LSHIFT: + case VK_RSHIFT: + return KeyboardButton::shift(); + + case VK_CONTROL: + case VK_LCONTROL: + case VK_RCONTROL: + return KeyboardButton::control(); + + case VK_MENU: + case VK_LMENU: + case VK_RMENU: + return KeyboardButton::alt(); + + default: + int key = MapVirtualKey(wparam, 2); + if (isascii(key) && key != 0) { + // We used to try to remap lowercase to uppercase keys + // here based on the state of the shift and/or caps lock + // keys. But that's a mistake, and doesn't allow for + // international or user-defined keyboards; let Windows + // do that mapping. + + // Nowadays, we make a distinction between a "button" + // and a "keystroke". A button corresponds to a + // physical button on the keyboard and has a down and up + // event associated. A keystroke may or may not + // correspond to a physical button, but will be some + // Unicode character and will not have a corresponding + // up event. + return KeyboardButton::ascii_key(tolower(key)); + } + break; + } + return ButtonHandle::none(); +} + +int wdxGraphicsWindow:: +get_depth_bitwidth(void) { + assert(_dxgsg!=NULL); + if(_dxgsg->scrn.PresParams.EnableAutoDepthStencil) + return _dxgsg->scrn.depth_buffer_bitdepth; + else return 0; + +// GetSurfaceDesc is not reliable, on GF2, GetSurfDesc returns 32bpp when you created a 24bpp zbuf +// instead store the depth used at creation time + +// DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); +// _dxgsg->_zbuf->GetSurfaceDesc(&ddsd); +// return ddsd.ddpfPixelFormat.dwRGBBitCount; +} + +void wdxGraphicsWindow:: +get_framebuffer_format(PixelBuffer::Type &fb_type, PixelBuffer::Format &fb_format) { + assert(_dxgsg!=NULL); + + fb_type = PixelBuffer::T_unsigned_byte; + // this is sortof incorrect, since for F_rgb5 it's really 5 bits per channel + //would have to change a lot of texture stuff to make this correct though + + if(IS_16BPP_DISPLAY_FORMAT(_dxgsg->scrn.PresParams.BackBufferFormat)) + fb_format = PixelBuffer::F_rgb5; + else fb_format = PixelBuffer::F_rgb; +} + +// Global system parameters we want to modify during our run +static int iMouseTrails; +static bool bCursorShadowOn,bMouseVanish; + +#ifndef SPI_GETMOUSEVANISH +// get rid of this when we upgrade to winxp winuser.h in newest platform sdk +#define SPI_GETMOUSEVANISH 0x1020 +#define SPI_SETMOUSEVANISH 0x1021 +#endif + +#ifndef SPI_GETCURSORSHADOW +#error You have old windows headers, need to get latest MS Platform SDK +#endif + +void set_global_parameters(void) { + // turn off mousetrails and cursor shadow and mouse cursor vanish + // cursor shadow causes cursor blink and reduced frame rate due to lack of driver support for + // cursor alpha blending + + // this is a win2k/xp only param, could use GetVersionEx to do it just for win2k, + // but since it is just a param it will just cause a silent error on other OS's + // that should be ok + SystemParametersInfo(SPI_GETCURSORSHADOW,NULL,&bCursorShadowOn,NULL); + SystemParametersInfo(SPI_SETCURSORSHADOW,NULL,(PVOID)false,NULL); + + SystemParametersInfo(SPI_GETMOUSETRAILS,NULL,&iMouseTrails,NULL); + SystemParametersInfo(SPI_SETMOUSETRAILS,NULL,(PVOID)0,NULL); + + // this is ME/XP only feature + SystemParametersInfo(SPI_GETMOUSEVANISH,NULL,&bMouseVanish,NULL); + SystemParametersInfo(SPI_SETMOUSEVANISH,NULL,(PVOID)false,NULL); +} + +void restore_global_parameters(void) { + SystemParametersInfo(SPI_SETCURSORSHADOW,NULL,(PVOID)bCursorShadowOn,NULL); + SystemParametersInfo(SPI_SETMOUSETRAILS,NULL,(PVOID)iMouseTrails,NULL); + SystemParametersInfo(SPI_SETMOUSEVANISH,NULL,(PVOID)bMouseVanish,NULL); +} + + +// fns for exporting to python, which cant pass variable length arrays +wdxGraphicsWindowGroup::wdxGraphicsWindowGroup(GraphicsPipe *pipe,const GraphicsWindow::Properties &Win1Prop) { + GraphicsWindow::Properties WinPropArr[1]; + WinPropArr[0]=Win1Prop; + make_windows(pipe,1,WinPropArr); +} + +wdxGraphicsWindowGroup::wdxGraphicsWindowGroup(GraphicsPipe *pipe, + const GraphicsWindow::Properties &Win1Prop, + const GraphicsWindow::Properties &Win2Prop) { + GraphicsWindow::Properties WinPropArr[2]; + + WinPropArr[0]=Win1Prop; + WinPropArr[1]=Win2Prop; + make_windows(pipe,2,WinPropArr); +} + +wdxGraphicsWindowGroup::wdxGraphicsWindowGroup(GraphicsPipe *pipe, + const GraphicsWindow::Properties &Win1Prop, + const GraphicsWindow::Properties &Win2Prop, + const GraphicsWindow::Properties &Win3Prop) { + GraphicsWindow::Properties WinPropArr[3]; + + WinPropArr[0]=Win1Prop; + WinPropArr[1]=Win2Prop; + WinPropArr[2]=Win3Prop; + make_windows(pipe,3,WinPropArr); +} + +wdxGraphicsWindowGroup::wdxGraphicsWindowGroup(wdxGraphicsWindow *OneWindow) { + // init a 1 window group + // called from config_window + + _windows.reserve(1); + _windows.push_back(OneWindow); + initWindowGroup(); +} + +void wdxGraphicsWindowGroup::initWindowGroup(void) { + HRESULT hr; + + assert(_windows.size()>0); + _hOldForegroundWindow=GetForegroundWindow(); + _bClosingAllWindows= false; + + UINT num_windows=_windows.size(); + + #define D3D8_NAME "d3d8.dll" + #define D3DCREATE8 "Direct3DCreate8" + + _hD3D8_DLL = LoadLibrary(D3D8_NAME); + if(_hD3D8_DLL == 0) { + wdxdisplay_cat.fatal() << "PandaDX8 requires DX8, can't locate " << D3D8_NAME <<"!\n"; + exit(1); + } + + _hMouseCursor = NULL; + _bLoadedCustomCursor = false; + + _pDInputInfo = NULL; + + // can only get multimon HW acceleration in fullscrn on DX7 + + UINT numMonitors = GetSystemMetrics(SM_CMONITORS); + + if(numMonitors < num_windows) { + if(numMonitors==0) { + numMonitors=1; //win95 system will fail this call + } else { + wdxdisplay_cat.fatal() << "system has only "<< numMonitors << " monitors attached, couldn't find enough devices to meet multi window reqmt of " << num_windows << endl; + exit(1); + } + } + + // Do all DX7 stuff first + // find_all_card_memavails(); + + LPDIRECT3D8 pD3D8; + + typedef LPDIRECT3D8 (WINAPI *Direct3DCreate8_ProcPtr)(UINT SDKVersion); + + // dont want to statically link to possibly non-existent d3d8 dll, so must call D3DCr8 indirectly + Direct3DCreate8_ProcPtr D3DCreate8_Ptr = + (Direct3DCreate8_ProcPtr) GetProcAddress(_hD3D8_DLL, D3DCREATE8); + + if(D3DCreate8_Ptr == NULL) { + wdxdisplay_cat.fatal() << "GetProcAddress for "<< D3DCREATE8 << "failed!" << endl; + exit(1); + } + +// these were taken from the 8.0 and 8.1 d3d8.h SDK headers +#define D3D_SDK_VERSION_8_0 120 +#define D3D_SDK_VERSION_8_1 220 + + // are we using 8.0 or 8.1? + WIN32_FIND_DATA TempFindData; + HANDLE hFind; + char tmppath[MAX_PATH]; + GetSystemDirectory(tmppath,MAX_PATH); + strcat(tmppath,"\\dpnhpast.dll"); + hFind = FindFirstFile ( tmppath,&TempFindData ); + if(hFind != INVALID_HANDLE_VALUE) { + FindClose(hFind); + _bIsDX81=true; + pD3D8 = (*D3DCreate8_Ptr)(D3D_SDK_VERSION_8_1); + } else { + _bIsDX81=false; + pD3D8 = (*D3DCreate8_Ptr)(D3D_SDK_VERSION_8_0); + } + + if(pD3D8==NULL) { + wdxdisplay_cat.fatal() << D3DCREATE8 << " failed!\n"; + exit(1); + } + + _numAdapters = pD3D8->GetAdapterCount(); + if(_numAdapters < num_windows) { + wdxdisplay_cat.fatal() << "couldn't find enough devices attached to meet multi window reqmt of " << num_windows << endl; + exit(1); + } + + for(UINT i=0;i<_numAdapters;i++) { + D3DADAPTER_IDENTIFIER8 adapter_info; + ZeroMemory(&adapter_info,sizeof(D3DADAPTER_IDENTIFIER8)); + hr = pD3D8->GetAdapterIdentifier(i,D3DENUM_NO_WHQL_LEVEL,&adapter_info); + if(FAILED(hr)) { + wdxdisplay_cat.fatal() << "D3D GetAdapterID failed" << D3DERRORSTRING(hr); + } + + LARGE_INTEGER *DrvVer=&adapter_info.DriverVersion; + + wdxdisplay_cat.info() << "D3D8 Adapter[" << i << "]: " << adapter_info.Description << + ", Driver: " << adapter_info.Driver << ", DriverVersion: (" + << HIWORD(DrvVer->HighPart) << "." << LOWORD(DrvVer->HighPart) << "." + << HIWORD(DrvVer->LowPart) << "." << LOWORD(DrvVer->LowPart) << ")\nVendorID: 0x" + << (void*) adapter_info.VendorId << " DeviceID: 0x" << (void*) adapter_info.DeviceId + << " SubsysID: 0x" << (void*) adapter_info.SubSysId << " Revision: 0x" + << (void*) adapter_info.Revision << endl; + + HMONITOR hMon=pD3D8->GetAdapterMonitor(i); + if(hMon==NULL) { + wdxdisplay_cat.info() << "D3D8 Adapter[" << i << "]: seems to be disabled, skipping it\n"; + continue; + } + + DXDeviceInfo devinfo; + ZeroMemory(&devinfo,sizeof(devinfo)); + memcpy(&devinfo.guidDeviceIdentifier,&adapter_info.DeviceIdentifier,sizeof(GUID)); + strncpy(devinfo.szDescription,adapter_info.Description,MAX_DEVICE_IDENTIFIER_STRING); + strncpy(devinfo.szDriver,adapter_info.Driver,MAX_DEVICE_IDENTIFIER_STRING); + devinfo.VendorID=adapter_info.VendorId; + devinfo.DeviceID=adapter_info.DeviceId; + devinfo.hMon=hMon; + devinfo.cardID=i; + + _DeviceInfoVec.push_back(devinfo); + } + + for(UINT i=0;iconfig_window(this); + } + + UINT good_device_count=0; + + if(num_windows==1) { + UINT D3DAdapterNum = D3DADAPTER_DEFAULT; + + if(dx_preferred_deviceID!=-1) { + if(dx_preferred_deviceID>=(int)_numAdapters) { + wdxdisplay_cat.fatal() << "invalid 'dx-preferred-device-id', valid values are 0-" << _numAdapters-1 << ", using default adapter 0 instead\n"; + } else D3DAdapterNum=dx_preferred_deviceID; + } + if(_windows[0]->search_for_device(pD3D8,&(_DeviceInfoVec[D3DAdapterNum]))) + good_device_count=1; + } else { + for(UINT devnum=0;devnum<_DeviceInfoVec.size() && (good_device_count < num_windows);devnum++) { + if(_windows[devnum]->search_for_device(pD3D8,&(_DeviceInfoVec[devnum]))) + good_device_count++; + } + } + + if(good_device_count < num_windows) { + if(good_device_count==0) + wdxdisplay_cat.fatal() << "no usable display devices, exiting...\n"; + else wdxdisplay_cat.fatal() << "multi-device request for " << num_windows << "devices, found only "<< good_device_count << " usable ones, exiting!"; + exit(1); + } + + _DeviceInfoVec.clear(); // dont need this anymore + + if(wdxdisplay_cat.is_debug() && (g_pCardIDVec!=NULL)) { + // print out the MaxAvailVidMems + for(UINT i=0;i<_windows.size();i++) { + D3DADAPTER_IDENTIFIER8 adapter_info; + pD3D8->GetAdapterIdentifier(_windows[i]->_dxgsg->scrn.CardIDNum,D3DENUM_NO_WHQL_LEVEL,&adapter_info); + wdxdisplay_cat.info() << "D3D8 Adapter[" << i << "]: " << adapter_info.Description + << ", MaxAvailVideoMem: " << _windows[i]->_dxgsg->scrn.MaxAvailVidMem + << ", IsLowVidMemCard: " << (_windows[i]->_dxgsg->scrn.bIsLowVidMemCard ? "true" : "false") << endl; + } + } + + CreateWindows(); // creates win32 windows (need to do this before Setting coopLvls and display modes, + // but after we have all the monitor handles needed by CreateWindow() + +// SetCoopLevelsAndDisplayModes(); + + if(dx_show_fps_meter) + _windows[0]->_dxgsg->_bShowFPSMeter = true; // just show fps on 1st mon + + for(UINT i=0;iCreateScreenBuffersAndDevice(_windows[i]->_dxgsg->scrn); + } + + for(UINT i=0;ifinish_window_setup(); + } + + SAFE_DELETE(g_pCardIDVec); // dont need this anymore + + for(UINT i=0;i_dxgsg->SetDXReady(true); + } + + dx_pick_best_screenres = false; // only want to do this on startup, not resize + + #ifdef DINPUT_DEBUG_POLL + if(dx_use_joystick) { + _pDInputInfo = new DInput8Info; + assert(_pDInputInfo !=NULL); + if(!_pDInputInfo->InitDirectInput()) { + wdxdisplay_cat.error() << "InitDirectInput failed!\n"; + exit(1); + } + + if(!_pDInputInfo->CreateJoystickOrPad(_hParentWindow)) { // associate w/parent window of group for now + wdxdisplay_cat.error() << "CreateJoystickOrPad failed!\n"; + exit(1); + } + + // for now, just set up a WM_TIMER to poll the joystick. + // could configure it to do event-based input, and that is default w/action mapping + // which would be better, less processor intensive + + #define POLL_FREQUENCY_HZ 3 + _pDInputInfo->_JoystickPollTimer = SetTimer(_hParentWindow, JOYSTICK_POLL_TIMER_ID, 1000/POLL_FREQUENCY_HZ, NULL); + if(_pDInputInfo->_JoystickPollTimer!=JOYSTICK_POLL_TIMER_ID) { + wdxdisplay_cat.error() << "Error in joystick SetTimer!\n"; + } + } + #endif +} + +wdxGraphicsWindowGroup::wdxGraphicsWindowGroup(GraphicsPipe *pipe,int num_windows,GraphicsWindow::Properties *WinPropArray) { + make_windows(pipe,num_windows,WinPropArray); +} + +void wdxGraphicsWindowGroup:: +make_windows(GraphicsPipe *pipe,int num_windows,GraphicsWindow::Properties *WinPropArray) { + _hParentWindow=NULL; + _windows.reserve(num_windows); + int i; + + // first make all the objs without running the dx config() stuff + for(i=0;iclose_window(); + } + + if((_hOldForegroundWindow!=NULL) /*&& (scrn.hWnd==GetForegroundWindow())*/) { + SetForegroundWindow(_hOldForegroundWindow); + } + + if(_bLoadedCustomCursor && (_hMouseCursor!=NULL)) + DestroyCursor(_hMouseCursor); + + if(_hD3D8_DLL != NULL) { + FreeLibrary(_hD3D8_DLL); + _hD3D8_DLL = NULL; + } +} + diff --git a/panda/src/dxgsg8/wdxGraphicsWindow8.h.old b/panda/src/dxgsg8/wdxGraphicsWindow8.h.old new file mode 100644 index 0000000000..a164286249 --- /dev/null +++ b/panda/src/dxgsg8/wdxGraphicsWindow8.h.old @@ -0,0 +1,195 @@ +// Filename: wdxGraphicsWindow.h +// Created by: mike (09Jan97) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// +#ifndef WDXGRAPHICSWINDOW_H +#define WDXGRAPHICSWINDOW_H + +//////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////// +#include +#include +#include "dxGraphicsStateGuardian8.h" +#include + +//////////////////////////////////////////////////////////////////// +// Defines +//////////////////////////////////////////////////////////////////// +class wdxGraphicsPipe; +class wdxGraphicsWindowGroup; + +const int WDXWIN_CONFIGURE = 4; +const int WDXWIN_EVENT = 8; + +//#define FIND_CARD_MEMAVAILS + +typedef HRESULT (WINAPI * LPDIRECTDRAWCREATEEX)(GUID FAR * lpGuid, LPVOID *lplpDD, REFIID iid,IUnknown FAR *pUnkOuter); + +typedef struct { + UINT cardID; + char szDriver[MAX_DEVICE_IDENTIFIER_STRING]; + char szDescription[MAX_DEVICE_IDENTIFIER_STRING]; + GUID guidDeviceIdentifier; + DWORD VendorID,DeviceID; + HMONITOR hMon; +} DXDeviceInfo; +typedef vector DXDeviceInfoVec; + +//////////////////////////////////////////////////////////////////// +// Class : wdxGraphicsWindow +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX wdxGraphicsWindow : public GraphicsWindow { + friend class DXGraphicsStateGuardian; + friend class DXTextureContext; + friend class wdxGraphicsWindowGroup; + friend class DInput8Info; + +public: + wdxGraphicsWindow(GraphicsPipe* pipe); + wdxGraphicsWindow(GraphicsPipe* pipe,const GraphicsWindow::Properties& props); + + // this constructor will not initialize the wdx stuff, only the panda graphicswindow stuff + wdxGraphicsWindow(GraphicsPipe* pipe,const GraphicsWindow::Properties& props,wdxGraphicsWindowGroup *pParentGroup); + + virtual ~wdxGraphicsWindow(void); + + virtual TypeHandle get_gsg_type() const; + static GraphicsWindow* make_wdxGraphicsWindow(const FactoryParams ¶ms); + + void set_window_handle(HWND hwnd); + + LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); + void process_events(void); + + void handle_window_move( int x, int y ); + void handle_mouse_motion( int x, int y ); + void handle_mouse_exit(void); + void handle_keypress(ButtonHandle key, int x, int y ); + void handle_keyrelease(ButtonHandle key); + void dx_setup(); + +// dont need to override these now? +// virtual void begin_frame( void ); +// virtual void end_frame( void ); + + virtual bool resize(unsigned int xsize,unsigned int ysize); + virtual unsigned int verify_window_sizes(unsigned int numsizes,unsigned int *dimen); + bool special_check_fullscreen_resolution(UINT xsize,UINT ysize); + virtual int get_depth_bitwidth(void); + virtual void get_framebuffer_format(PixelBuffer::Type &fb_type, PixelBuffer::Format &fb_format); + +protected: + ButtonHandle lookup_key(WPARAM wparam) const; + void config_single_window(void); + void config_window(wdxGraphicsWindowGroup *pParentGroup); + void finish_window_setup(void); + bool search_for_device(LPDIRECT3D8 pD3D8,DXDeviceInfo *pDevinfo); + void search_for_valid_displaymode(UINT RequestedXsize,UINT RequestedYsize,bool bWantZBuffer,bool bWantStencil, + UINT *pSupportedScreenDepthsMask,bool *pCouldntFindAnyValidZBuf, + D3DFORMAT *pSuggestedPixFmt,bool bVerboseMode = false); + bool FindBestDepthFormat(DXScreenData &Display,D3DDISPLAYMODE &TestDisplayMode,D3DFORMAT *pBestFmt,bool bWantStencil,bool bForce16bpp,bool bVerboseMode = false) const; + void init_resized_window(void); + bool reset_device_resize_window(UINT new_xsize, UINT new_ysize); + void setup_colormap(void); + INLINE void track_mouse_leaving(HWND hwnd); + +public: + UINT_PTR _PandaPausedTimer; + DXGraphicsStateGuardian *_dxgsg; + void CreateScreenBuffersAndDevice(DXScreenData &Display); + +private: + wdxGraphicsWindowGroup *_pParentWindowGroup; + HDC _hdc; + HPALETTE _colormap; + typedef enum { NotAdjusting,MovingOrResizing,Resizing } WindowAdjustType; + WindowAdjustType _WindowAdjustingType; + bool _bSizeIsMaximized; + bool _ime_open; + bool _ime_active; + bool _ime_composition_w; + bool _exiting_window; + bool _window_inactive; + bool _active_minimized_fullscreen; + bool _return_control_to_app; + bool _cursor_in_windowclientarea; + bool _use_dx8_cursor; + bool _tracking_mouse_leaving; + int _depth_buffer_bpp; + +public: + static TypeHandle get_class_type(void); + static void init_type(void); + virtual TypeHandle get_type(void) const; + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + + void DestroyMe(bool bAtExitFnCalled); + virtual void do_close_window(); + void deactivate_window(void); + void reactivate_window(void); + INLINE void set_cursor_visibility(bool bVisible); + bool handle_windowed_resize(HWND hWnd,bool bDoDXReset); + +private: + static TypeHandle _type_handle; +}; + +// this class really belongs in panda, not here +class EXPCL_PANDADX wdxGraphicsWindowGroup { +// group of windows are all created at the same time + friend class wdxGraphicsWindow; + +PUBLISHED: + wdxGraphicsWindowGroup(GraphicsPipe *,const GraphicsWindow::Properties&); + wdxGraphicsWindowGroup(GraphicsPipe *,const GraphicsWindow::Properties&,const GraphicsWindow::Properties&); + wdxGraphicsWindowGroup(GraphicsPipe *,const GraphicsWindow::Properties&,const GraphicsWindow::Properties&, + const GraphicsWindow::Properties&); +public: + wdxGraphicsWindowGroup(wdxGraphicsWindow *OneWindow); + // dont publish variable length one, since FFI wont support it + wdxGraphicsWindowGroup(GraphicsPipe *pipe,int num_windows,GraphicsWindow::Properties *WinPropArray); + ~wdxGraphicsWindowGroup(); +// void SetCoopLevelsAndDisplayModes(void); +protected: + void find_all_card_memavails(void); +public: + void CreateWindows(void); + void make_windows(GraphicsPipe *,int num_windows,GraphicsWindow::Properties *pWinPropArray); + void initWindowGroup(void); + + pvector _windows; + DXDeviceInfoVec *_pDeviceInfoVec; // only used during init to store valid devices + HWND _hParentWindow; + HWND _hOldForegroundWindow; + HCURSOR _hMouseCursor; + bool _bLoadedCustomCursor; + bool _bClosingAllWindows; + bool _bIsDX81; + DWORD _numMonitors,_numAdapters; + LPDIRECT3D8 _pD3D8; + HINSTANCE _hD3D8_DLL; + DInput8Info *_pDInputInfo; + DXDeviceInfoVec _DeviceInfoVec; +}; + +extern void set_global_parameters(void); +extern void restore_global_parameters(void); +extern bool is_badvidmem_card(D3DADAPTER_IDENTIFIER8 *pDevID); + + +#endif