#include #include "dxwnd.h" #include "dxwcore.hpp" #include "syslibs.h" /* ------------------------------------------------------------------ */ // Constructor, destructor, initialization.... /* ------------------------------------------------------------------ */ dxwCore::dxwCore() { // initialization stuff .... FullScreen=FALSE; SethWnd(NULL); SetScreenSize(); dwMaxDDVersion=7; hParentWnd = 0; hChildWnd = 0; bActive = TRUE; bDInputAbs = 0; TimeShift = 0; lpDDSPrimHDC = NULL; //IsWithinDDraw = FALSE; IsGDIPalette = FALSE; memset(PrimSurfaces, 0, sizeof(PrimSurfaces)); // preserved syslibs pointers pClientToScreen=ClientToScreen; pClipCursor=ClipCursor; pGetClientRect=GetClientRect; pGetCursorPos=GetCursorPos; pInvalidateRect=InvalidateRect; pScreenToClient=ScreenToClient; } dxwCore::~dxwCore() { } void dxwCore::InitTarget(TARGETMAP *target) { dwFlags1 = target->flags; dwFlags2 = target->flags2; dwTFlags = target->tflags; gsModules = target->module; MaxFPS = target->MaxFPS; CustomOpenGLLib = target->OpenGLLib; if(!strlen(CustomOpenGLLib)) CustomOpenGLLib=NULL; // bounds control dwTargetDDVersion = target->dxversion; if(dwTargetDDVersion<0) dwTargetDDVersion=0; if(dwTargetDDVersion>10) dwTargetDDVersion=10; TimeShift = target->InitTS; if(TimeShift < -8) TimeShift = -8; if(TimeShift > 8) TimeShift = 8; FakeVersionId = target->FakeVersionId; } /* ------------------------------------------------------------------ */ // Primary surfaces auxiliary functions /* ------------------------------------------------------------------ */ void dxwCore::MarkPrimarySurface(LPDIRECTDRAWSURFACE ps) { int i; // OutTraceD("PRIMARYSURFACE add %x\n",ps); for (i=0;ileft+CLIP_TOLERANCE) curr.x=lpClipRegion->left; if (curr.y < lpClipRegion->top+CLIP_TOLERANCE) curr.y=lpClipRegion->top; if (curr.x >= lpClipRegion->right-CLIP_TOLERANCE) curr.x=lpClipRegion->right-1; if (curr.y >= lpClipRegion->bottom-CLIP_TOLERANCE) curr.y=lpClipRegion->bottom-1; } else{ if (curr.x < CLIP_TOLERANCE) curr.x=0; if (curr.y < CLIP_TOLERANCE) curr.y=0; if (curr.x >= (LONG)dxw.GetScreenWidth()-CLIP_TOLERANCE) curr.x=dxw.GetScreenWidth()-1; if (curr.y >= (LONG)dxw.GetScreenHeight()-CLIP_TOLERANCE) curr.y=dxw.GetScreenHeight()-1; } return curr; } void dxwCore::FixNCHITCursorPos(LPPOINT lppoint) { RECT rect; POINT point; point=*lppoint; (*pGetClientRect)(dxw.GethWnd(), &rect); (*pScreenToClient)(dxw.GethWnd(), &point); if (point.x < 0) return; if (point.y < 0) return; if (point.x > rect.right) return; if (point.y > rect.bottom) return; *lppoint=point; lppoint->x = (lppoint->x * dxw.GetScreenWidth()) / rect.right; lppoint->y = (lppoint->y * dxw.GetScreenHeight()) / rect.bottom; if(lppoint->x < CLIP_TOLERANCE) lppoint->x=0; if(lppoint->y < CLIP_TOLERANCE) lppoint->y=0; if(lppoint->x > (LONG)dxw.GetScreenWidth()-CLIP_TOLERANCE) lppoint->x=dxw.GetScreenWidth()-1; if(lppoint->y > (LONG)dxw.GetScreenHeight()-CLIP_TOLERANCE) lppoint->y=dxw.GetScreenHeight()-1; } void dxwCore::SetClipCursor() { RECT Rect; POINT UpLeftCorner; OutTraceD("SetClipCursor:\n"); if (hWnd==NULL) { OutTraceD("SetClipCursor: ASSERT hWnd==NULL\n"); return; } (*pGetClientRect)(hWnd, &Rect); UpLeftCorner.x=UpLeftCorner.y=0; (*pClientToScreen)(hWnd, &UpLeftCorner); Rect.left+=UpLeftCorner.x; Rect.right+=UpLeftCorner.x; Rect.top+=UpLeftCorner.y; Rect.bottom+=UpLeftCorner.y; (*pClipCursor)(NULL); if(!(*pClipCursor)(&Rect)){ OutTraceE("ClipCursor: ERROR err=%d at %d\n", GetLastError(), __LINE__); } OutTraceD("SetClipCursor: rect=(%d,%d)-(%d,%d)\n", Rect.left, Rect.top, Rect.right, Rect.bottom); } void dxwCore::EraseClipCursor() { OutTraceD("EraseClipCursor:\n"); (*pClipCursor)(NULL); } // MapWindow Rect: returns a rectangle in the real coordinate system from the virtual coordinates // of an emulated fullscreen window. NULL or void returns the rectangle of the whole client area. RECT dxwCore::MapWindowRect(void) { return MapWindowRect(NULL); } RECT dxwCore::MapWindowRect(LPRECT lpRect) { POINT UpLeft={0,0}; RECT RetRect; RECT ClientRect; if (!(*pGetClientRect)(hWnd, &ClientRect)){ OutTraceE("GetClientRect ERROR: err=%d hwnd=%x at %d\n", GetLastError(), hWnd, __LINE__); } if(lpRect){ RetRect.left = lpRect->left * ClientRect.right / dwScreenWidth; RetRect.right = lpRect->right * ClientRect.right / dwScreenWidth; RetRect.top = lpRect->top * ClientRect.bottom / dwScreenHeight; RetRect.bottom = lpRect->bottom * ClientRect.bottom / dwScreenHeight; } else { RetRect=ClientRect; } if(!(*pClientToScreen)(hWnd, &UpLeft)){ OutTraceE("ClientToScreen ERROR: err=%d hwnd=%x at %d\n", GetLastError(), hWnd, __LINE__); } if(!OffsetRect(&RetRect ,UpLeft.x, UpLeft.y)){ OutTraceE("OffsetRect ERROR: err=%d hwnd=%x at %d\n", GetLastError(), hWnd, __LINE__); } return RetRect; } void dxwCore::MapRect(int *nXDest, int *nYDest, int *nWDest, int *nHDest) { RECT client; (*pGetClientRect)(hWnd, &client); *nXDest= *nXDest * client.right / dwScreenWidth; *nYDest= *nYDest * client.bottom / dwScreenHeight; *nWDest= *nWDest * client.right / dwScreenWidth; *nHDest= *nHDest * client.bottom / dwScreenHeight; } void dxwCore::ScreenRefresh(void) { // optimization: don't blit too often! // 20mSec seems a good compromise. #define DXWREFRESHINTERVAL 20 LPDIRECTDRAWSURFACE lpDDSPrim; // extern LPDIRECTDRAWSURFACE GetPrimarySurface(); extern HRESULT WINAPI extBlt(LPDIRECTDRAWSURFACE lpdds, LPRECT lpdestrect, LPDIRECTDRAWSURFACE lpddssrc, LPRECT lpsrcrect, DWORD dwflags, LPDDBLTFX lpddbltfx); static int t = -1; if (t == -1) t = GetTickCount()-(DXWREFRESHINTERVAL+1); // V.2.1.69: trick - subtract int tn = GetTickCount(); if (tn-t < DXWREFRESHINTERVAL) return; lpDDSPrim=dxw.GetPrimarySurface(); // if too early .... if (lpDDSPrim) extBlt(lpDDSPrim, NULL, lpDDSPrim, NULL, 0, NULL); (*pInvalidateRect)(hWnd, NULL, FALSE); t = tn; } static void CountFPS(HWND hwnd) { static DWORD time = 0xFFFFFFFF; static DWORD FPSCount = 0; extern void SetFPS(int); //DXWNDSTATUS Status; DWORD tmp; tmp = GetTickCount(); if((tmp - time) > 1000) { char sBuf[80+12+1]; // title + fps string + terminator char *fpss; // log fps count OutTrace("FPSCount=%d\n", FPSCount); // show fps count on status win GetHookInfo()->FPSCount = FPSCount; // for overlay display // show fps on win title bar if (dxw.dwFlags2 & SHOWFPS){ GetWindowText(hwnd, sBuf, 80); fpss=strstr(sBuf," ~ ("); if(fpss==NULL) fpss=&sBuf[strlen(sBuf)]; sprintf(fpss, " ~ (%d FPS)", FPSCount); SetWindowText(hwnd, sBuf); } // reset FPSCount=0; time = tmp; } else { FPSCount++; } } static void LimitFrameCount(DWORD delay) { static DWORD oldtime=(*pGetTickCount)(); DWORD newtime; newtime = (*pGetTickCount)(); // use '<' and not '<=' to avoid the risk of sleeping forever.... if(newtime < oldtime+delay) (*pSleep)(oldtime+delay-newtime); oldtime = newtime; } static BOOL SkipFrameCount(DWORD delay) { static DWORD oldtime=(*pGetTickCount)(); DWORD newtime; newtime = (*pGetTickCount)(); // use '<' and not '<=' to avoid the risk of sleeping forever.... if(newtime < oldtime+delay) return TRUE; oldtime = newtime; return FALSE; } BOOL dxwCore::HandleFPS() { if(dwFlags2 & (SHOWFPS|SHOWFPSOVERLAY)) CountFPS(hWnd); if(dwFlags2 & LIMITFPS) LimitFrameCount(dxw.MaxFPS); if(dwFlags2 & SKIPFPS) if(SkipFrameCount(dxw.MaxFPS)) return TRUE; return FALSE; } static DWORD TimeShifter(DWORD val, int shift) { int exp, reminder; if (shift > 0) { exp = shift >> 1; reminder = shift & 0x1; if (reminder) val -= (val >> 2); // val * (1-1/4) = val * 3/4 val >>= exp; // val * 2^exp } if (shift < 0) { exp = (-shift) >> 1; reminder = (-shift) & 0x1; val <<= exp; // val / 2^exp if (reminder) val += (val >> 1); // val * (1+1/2) = val * 3/2 } return val; } DWORD dxwCore::GetTickCount(void) { DWORD dwTick; static DWORD dwLastRealTick=0; static DWORD dwLastFakeTick=0; DWORD dwNextRealTick; dwNextRealTick=(*pGetTickCount)(); dwTick=(dwNextRealTick-dwLastRealTick); TimeShift=GetHookInfo()->TimeShift; dwTick = TimeShifter(dwTick, TimeShift); dwLastFakeTick += dwTick; dwLastRealTick = dwNextRealTick; return dwLastFakeTick; } DWORD dxwCore::StretchTime(DWORD dwTimer) { TimeShift=GetHookInfo()->TimeShift; dwTimer = TimeShifter(dwTimer, -TimeShift); return dwTimer; } void dxwCore::GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) { DWORD dwTick; DWORD dwCurrentTick; FILETIME CurrFileTime; static DWORD dwStartTick=0; static DWORD dwUpdateTick=0; static FILETIME StartFileTime; extern DXWNDSTATUS *pStatus; if(dwStartTick==0) { SYSTEMTIME StartingTime; // first time through, initialize & return true time dwStartTick = (*pGetTickCount)(); (*pGetSystemTime)(&StartingTime); SystemTimeToFileTime(&StartingTime, &StartFileTime); *lpSystemTimeAsFileTime = StartFileTime; } else { dwCurrentTick=(*pGetTickCount)(); dwTick=(dwCurrentTick-dwStartTick); TimeShift=GetHookInfo()->TimeShift; dwTick = TimeShifter(dwTick, TimeShift); // From MSDN: Contains a 64-bit value representing the number of // 100-nanosecond intervals since January 1, 1601 (UTC). // So, since 1mSec = 10.000 * 100nSec, you still have to multiply by 10.000. CurrFileTime.dwHighDateTime = StartFileTime.dwHighDateTime; // wrong !!!! CurrFileTime.dwLowDateTime = StartFileTime.dwLowDateTime + (10000 * dwTick); // wrong !!!! *lpSystemTimeAsFileTime=CurrFileTime; // reset to avoid time jumps on TimeShift changes... StartFileTime = CurrFileTime; dwStartTick = dwCurrentTick; } } void dxwCore::GetSystemTime(LPSYSTEMTIME lpSystemTime) { DWORD dwTick; DWORD dwCurrentTick; FILETIME CurrFileTime; static DWORD dwStartTick=0; static DWORD dwUpdateTick=0; static FILETIME StartFileTime; extern DXWNDSTATUS *pStatus; if(dwStartTick==0) { SYSTEMTIME StartingTime; // first time through, initialize & return true time dwStartTick = (*pGetTickCount)(); (*pGetSystemTime)(&StartingTime); SystemTimeToFileTime(&StartingTime, &StartFileTime); *lpSystemTime = StartingTime; } else { dwCurrentTick=(*pGetTickCount)(); dwTick=(dwCurrentTick-dwStartTick); TimeShift=GetHookInfo()->TimeShift; dwTick = TimeShifter(dwTick, TimeShift); // From MSDN: Contains a 64-bit value representing the number of // 100-nanosecond intervals since January 1, 1601 (UTC). // So, since 1mSec = 10.000 * 100nSec, you still have to multiply by 10.000. CurrFileTime.dwHighDateTime = StartFileTime.dwHighDateTime; // wrong !!!! CurrFileTime.dwLowDateTime = StartFileTime.dwLowDateTime + (10000 * dwTick); // wrong !!!! FileTimeToSystemTime(&CurrFileTime, lpSystemTime); // reset to avoid time jumps on TimeShift changes... StartFileTime = CurrFileTime; dwStartTick = dwCurrentTick; } } void dxwCore::ShowFPS(HDC xdc) { char sBuf[81]; static DWORD dwTimer = 0; static int corner = 0; static int x, y; static DWORD color; if((*pGetTickCount)()-dwTimer > 4000){ RECT rect; dwTimer = (*pGetTickCount)(); corner = dwTimer % 4; color=0xFF0000; // blue (*pGetClientRect)(hWnd, &rect); switch (corner) { case 0: x=10; y=10; break; case 1: x=rect.right-60; y=10; break; case 2: x=rect.right-60; y=rect.bottom-20; break; case 3: x=10; y=rect.bottom-20; break; } } SetTextColor(xdc,color); //SetBkMode(xdc, TRANSPARENT); SetBkMode(xdc, OPAQUE); sprintf(sBuf, "FPS: %d", GetHookInfo()->FPSCount); TextOut(xdc, x, y, sBuf, strlen(sBuf)); } void dxwCore::ShowFPS(LPDIRECTDRAWSURFACE lpdds) { HDC xdc; // the working dc char sBuf[81]; static DWORD dwTimer = 0; static int corner = 0; static int x, y; static DWORD color; if((*pGetTickCount)()-dwTimer > 4000){ dwTimer = (*pGetTickCount)(); corner = dwTimer % 4; color=0xFF0000; // blue switch (corner) { case 0: x=10; y=10; break; case 1: x=dwScreenWidth-60; y=10; break; case 2: x=dwScreenWidth-60; y=dwScreenHeight-20; break; case 3: x=10; y=dwScreenHeight-20; break; } } if (FAILED(lpdds->GetDC(&xdc))) return; SetTextColor(xdc,color); //SetBkMode(xdc, TRANSPARENT); SetBkMode(xdc, OPAQUE); sprintf(sBuf, "FPS: %d", GetHookInfo()->FPSCount); TextOut(xdc, x, y, sBuf, strlen(sBuf)); lpdds->ReleaseDC(xdc); } char *dxwCore::GetTSCaption(int shift) { static char *sTSCaption[17]={ "x16","x12","x8","x6", "x4","x3","x2","x1.5", "x1", ":1.5",":2",":3",":4", ":6",":8",":12",":16"}; if (shift<0 || shift>16) return "???"; return sTSCaption[shift+8]; } char *dxwCore::GetTSCaption(void) { return GetTSCaption(TimeShift); }