1
0
mirror of https://github.com/DxWnd/DxWnd.reloaded synced 2024-12-30 09:25:35 +01:00
DxWnd.reloaded/dll/shareddc.cpp
gho tik db2398ce2e v2_04_18_src
Former-commit-id: a236d8102f7cf07342c20cc701e08f30e8f4f142
2017-03-06 11:50:32 -05:00

481 lines
17 KiB
C++

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <d3d9.h>
#include "dxwnd.h"
#include "dxwcore.hpp"
#include "syslibs.h"
#include "dxhelper.h"
#include "resource.h"
#include "hddraw.h"
#include "shareddc.hpp"
//#define D3D9TRY
#define SHAREDDCDEBUG FALSE
#if SHAREDDCDEBUG
#define _Warn(s) {char cap[80]; sprintf(cap, "Warn at %d", __LINE__); MessageBox(NULL, (s), cap, MB_OK);}
#else
#define _Warn(s)
#endif
extern HandleDDThreadLock_Type pReleaseDDThreadLock;
extern GetDC_Type pGetDCMethod();
extern ReleaseDC_Type pReleaseDCMethod();
/*---------------------------------------------------------------------------------+
| |
| Constructor, Desctructor |
| |
+---------------------------------------------------------------------------------*/
dxwSDC::dxwSDC()
{
OutTraceB("dxwSDC::dxwSDC: Initialize\n");
PrimaryDC = NULL;
lpDDSPrimary = NULL;
LastScreenWidth = LastScreenHeight = 0;
LastHDC = NULL;
CurrenthWnd = NULL;
}
dxwSDC::~dxwSDC()
{
//OutTraceB("dxwSDC::~dxwSDC: Destroy\n");
}
/*---------------------------------------------------------------------------------+
| |
| GetPrimaryDC: builds a suitable DC to write to, according to the input DC |
| |
+---------------------------------------------------------------------------------*/
static IDirect3DSurface9 *pDestSurface = NULL;
HDC dxwSDC::GetPrimaryDC(HDC hdc)
{
return GetPrimaryDC(hdc, NULL);
}
HDC dxwSDC::GetPrimaryDC(HDC hdc, HDC hdcsrc)
{
HRESULT res;
extern HandleDDThreadLock_Type pReleaseDDThreadLock;
extern void *lpD3DActiveDevice;
OutTraceB("dxwSDC::GetPrimaryDC: hdc=%x\n", hdc);
CurrentHDCSrc = hdcsrc;
CurrentHDC = hdc;
// look for ddraw first
//if(pReleaseDDThreadLock)(*pReleaseDDThreadLock)();
lpDDSPrimary = dxwss.GetPrimarySurface();
if (lpDDSPrimary) {
if(pReleaseDDThreadLock)(*pReleaseDDThreadLock)();
res=((*pGetDCMethod())(lpDDSPrimary, &PrimaryDC));
while((PrimaryDC == NULL) && lpDDSPrimary) {
OutTraceB("dxwSDC::GetPrimaryDC: found primary surface with no DC, unref lpdds=%x\n", lpDDSPrimary);
dxwss.UnrefSurface(lpDDSPrimary);
lpDDSPrimary = dxwss.GetPrimarySurface();
if (lpDDSPrimary) (*pGetDCMethod())(lpDDSPrimary, &PrimaryDC);
}
if (!PrimaryDC) {
_Warn("No primary DC");
OutTraceB("dxwSDC::GetPrimaryDC: no ddraw primary DC\n");
return NULL;
}
// avoid double Getdc on same hdc and lock
// if(PrimaryDC == hdc) (*pReleaseDC)(lpDDSPrimary, PrimaryDC);
OutTraceB("dxwSDC::GetPrimaryDC: ddraw PrimaryDC=%x\n", PrimaryDC);
VirtualSurfaceType = VIRTUAL_ON_DDRAW;
}
else {
// finally, search GDI DC
PrimaryDC = (*pGDIGetDC)(dxw.GethWnd());
if (!PrimaryDC) {
_Warn("No window DC");
OutTraceB("dxwSDC::GetPrimaryDC: no windows DC\n");
return NULL;
}
OutTraceB("dxwSDC::GetPrimaryDC: gdi PrimaryDC=%x\n", PrimaryDC);
VirtualSurfaceType = VIRTUAL_ON_WINDOW;
}
// whenever the hdc changes, rebuild the virtual DC
if(hdc != LastHDC) do {
LastHDC = hdc;
RECT client;
if(VirtualHDC){
//(*pGDIReleaseDC)(dxw.GethWnd(), VirtualHDC);
DeleteObject(VirtualHDC);
}
if(!(VirtualHDC=(*pGDICreateCompatibleDC)(PrimaryDC))){
OutTraceE("CreateCompatibleDC: ERROR err=%d at=%d\n", GetLastError(), __LINE__);
_Warn("CreateCompatibleDC ERROR");
break;
}
if(!(CurrenthWnd = WindowFromDC(hdc))){
OutTraceE("dxwSDC::GetPrimaryDC: WindowFromDC ERROR err=%d at=%d\n", GetLastError(), __LINE__);
_Warn("WindowFromDC ERROR");
break;
}
if(!(*pGetClientRect)(CurrenthWnd, &client)){
OutTraceE("dxwSDC::GetPrimaryDC: GetClietError ERROR err=%d at=%d\n", GetLastError(), __LINE__);
_Warn("GetClietError ERROR");
break;
}
dxw.UnmapClient(&client);
ScreenWidth = client.right;
ScreenHeight = client.bottom;
OutTraceB("dxwSDC::GetPrimaryDC: VirtualHDC INITIALIZE size=(%dx%d)\n", LastScreenWidth, LastScreenHeight);
if(!(VirtualPic=(*pCreateCompatibleBitmap)(PrimaryDC, ScreenWidth, ScreenHeight))){
OutTraceE("dxwSDC::GetPrimaryDC: CreateCompatibleBitmap ERROR err=%d at=%d\n", GetLastError(), __LINE__);
_Warn("CreateCompatibleBitmap ERROR");
}
if(!(*pSelectObject)(VirtualHDC, VirtualPic)){
OutTraceE("dxwSDC::GetPrimaryDC: SelectObject ERROR err=%d at=%d\n", GetLastError(), __LINE__);
_Warn("SelectObject ERROR");
}
DeleteObject(VirtualPic);
VirtualPic = 0;
} while(0);
if(CurrenthWnd && CurrenthWnd!=dxw.GethWnd()){
POINT zero1 = {0, 0};
POINT zero2 = {0, 0};
(*pClientToScreen)(CurrenthWnd, &zero1);
(*pClientToScreen)(dxw.GethWnd(), &zero2);
WinOffset.x = zero1.x - zero2.x;
WinOffset.y = zero1.y - zero2.y;
VirtualOffset = WinOffset;
dxw.UnmapClient(&VirtualOffset);
OutTraceB("dxwSDC::GetPrimaryDC: WinOffset=(%d,%d)->(%d,%d)\n", WinOffset.x, WinOffset.y, VirtualOffset.x, VirtualOffset.y);
}
else {
WinOffset.x = 0;
WinOffset.y = 0;
VirtualOffset.x = 0;
VirtualOffset.y = 0;
OutTraceB("dxwSDC::GetPrimaryDC: same window\n");
}
if(PrimaryDC){
switch(VirtualSurfaceType){
case VIRTUAL_ON_DDRAW:
if(!(*pGDIBitBlt)(VirtualHDC, 0, 0, ScreenWidth, ScreenHeight, PrimaryDC, VirtualOffset.x, VirtualOffset.y, SRCCOPY)){
OutTraceE("dxwSDC::GetPrimaryDC: BitBlt ERROR err=%d at=%d\n", GetLastError(), __LINE__);
_Warn("BitBlt ERROR");
}
OutTraceB("dxwSDC::GetPrimaryDC: fill=(0,0)-(%dx%d) from=(%d,%d)\n", ScreenWidth, ScreenHeight, VirtualOffset.x, VirtualOffset.y);
break;
case VIRTUAL_ON_WINDOW:
int w, h;
dxw.MapClient(&VirtualOffset);
w = ScreenWidth;
h = ScreenHeight;
dxw.MapClient(&w, &h);
if(!(*pGDIStretchBlt)(VirtualHDC, 0, 0, ScreenWidth, ScreenHeight, PrimaryDC, VirtualOffset.x, VirtualOffset.y, w, h, SRCCOPY)){
OutTraceE("dxwSDC::GetPrimaryDC: StretchBlt ERROR err=%d at=%d\n", GetLastError(), __LINE__);
_Warn("StretchBlt ERROR");
}
OutTraceB("dxwSDC::GetPrimaryDC: fill=(0,0)-(%dx%d) from=(%d,%d)-(%dx%d)\n", ScreenWidth, ScreenHeight, VirtualOffset.x, VirtualOffset.y, w, h);
break;
}
}
POINT origin = {};
POINT mainwin = {};
(*pGetDCOrgEx)(hdc, &origin);
(*pGetDCOrgEx)((*pGDIGetDC)(dxw.GethWnd()), &mainwin);
origin.x -= mainwin.x;
origin.y -= mainwin.y;
OutTraceB("dxwSDC::GetPrimaryDC: origin=(%d,%d)\n", origin.x, origin.y);
copyDcAttributes(VirtualHDC, hdc, origin);
setClippingRegion(VirtualHDC, hdc, origin);
return VirtualHDC;
}
void dxwSDC::SetOrigin(int x, int y)
{
HybridX = x;
HybridY = y;
}
/*---------------------------------------------------------------------------------+
| |
| GetHdc: returns the DC to write for the GDI call |
| |
+---------------------------------------------------------------------------------*/
HDC dxwSDC::GetHdc(void)
{
return VirtualHDC;
}
/*---------------------------------------------------------------------------------+
| |
| PutPrimaryDC: transfers the DC content to the primary surface and the screen |
| |
+---------------------------------------------------------------------------------*/
BOOL dxwSDC::PutPrimaryDC(HDC hdc, BOOL UpdateScreen, int XDest, int YDest, int nDestWidth, int nDestHeight)
{
extern Unlock1_Type pUnlock1;
BOOL ret;
HRESULT res;
ret = TRUE;
if (nDestWidth == 0) nDestWidth=ScreenWidth-XDest;
if (nDestHeight == 0) nDestHeight=ScreenHeight-YDest;
if (IsDebug){
char sRect[81];
if(UpdateScreen) sprintf(sRect, "pos=(%d,%d) size=(%dx%d) winoffset=(%d,%d) virtoffset=(%d,%d)",
XDest, YDest, nDestWidth, nDestHeight, WinOffset.x, WinOffset.y, VirtualOffset.x, VirtualOffset.y);
else strcpy(sRect, "");
char *sType;
switch(VirtualSurfaceType){
case VIRTUAL_ON_D3D: sType="D3D"; break;
case VIRTUAL_ON_DDRAW: sType="DDRAW"; break;
case VIRTUAL_ON_WINDOW: sType="WINDOW"; break;
default: sType="???"; break;
}
OutTrace("dxwSDC::PutPrimaryDC: hdc=%x type=%s update=%x %s\n", hdc, sType, UpdateScreen, sRect);
}
if(UpdateScreen){
switch(VirtualSurfaceType){
case VIRTUAL_ON_DDRAW:
ret=(*pGDIBitBlt)(PrimaryDC, XDest+VirtualOffset.x, YDest+VirtualOffset.y, nDestWidth, nDestHeight, VirtualHDC, XDest, YDest, SRCCOPY);
if(!ret || (ret==GDI_ERROR)) {
OutTraceE("dxwSDC::PutPrimaryDC: BitBlt ERROR ret=%x err=%d\n", ret, GetLastError());
}
res=(*pReleaseDCMethod())(lpDDSPrimary, PrimaryDC);
if(res){
OutTraceE("dxwSDC::PutPrimaryDC: ReleaseDC ERROR res=%x\n", res);
}
dxw.ScreenRefresh();
// trick: duplicate the operation using the stretched mode to blit over clipped areas.
// good for "Star Treck: Armada".
if((dxw.dwFlags8 & SHAREDDCHYBRID) && CurrentHDCSrc && (WindowFromDC(CurrentHDC)!=dxw.GethWnd())){
int nWDest, nHDest, nXDest, nYDest;
OutTraceB("dxwSDC::PutPrimaryDC: StretchBlt over ddraw\n");
nXDest= XDest;
nYDest= YDest;
nWDest= nDestWidth;
nHDest= nDestHeight;
dxw.MapClient(&nXDest, &nYDest, &nWDest, &nHDest);
res=(*pGDIStretchBlt)(
CurrentHDC, nXDest, nYDest, nWDest, nHDest,
CurrentHDCSrc, HybridX, HybridY, nDestWidth, nDestHeight, SRCCOPY);
if(!res) OutTraceE("dxwSDC::PutPrimaryDC: StretchBlt ERROR err=%d\n", GetLastError());
//RECT rect = {nXDest, nYDest, nXDest+nWDest, nYDest+nHDest};
//res = (*pFrameRect)(CurrentHDC, &rect, 0);
}
break;
case VIRTUAL_ON_WINDOW:
SetStretchBltMode(PrimaryDC, HALFTONE);
RECT RealArea, VirtualArea;
// some fullscreen games ("Imperialism II") blitted from negative coordinates -2,-2 !!
if(XDest < 0) {
nDestWidth += XDest;
XDest=0;
}
if(YDest < 0) {
nDestHeight += YDest;
YDest=0;
}
VirtualArea.left = XDest;
VirtualArea.top = YDest;
VirtualArea.right = nDestWidth;
VirtualArea.bottom = nDestHeight;
RealArea = VirtualArea;
dxw.MapClient(&RealArea);
OffsetRect(&RealArea, WinOffset.x, WinOffset.y);
ret=TRUE;
if(PrimaryDC)ret=(*pGDIStretchBlt)(PrimaryDC, RealArea.left, RealArea.top, RealArea.right, RealArea.bottom, VirtualHDC, VirtualArea.left, VirtualArea.top, VirtualArea.right, VirtualArea.bottom, SRCCOPY);
ret=(*pGDIReleaseDC)(dxw.GethWnd(), PrimaryDC);
break;
}
}
else {
switch(VirtualSurfaceType){
case VIRTUAL_ON_DDRAW:
res=(*pReleaseDCMethod())(lpDDSPrimary, PrimaryDC);
if(res){
OutTraceE("dxwSDC::PutPrimaryDC: ReleaseDC ERROR res=%x\n", res);
}
break;
case VIRTUAL_ON_WINDOW:
ret=(*pGDIReleaseDC)(dxw.GethWnd(), PrimaryDC);
if(!ret){
OutTraceE("dxwSDC::PutPrimaryDC: ReleaseDC ERROR err=%d\n", GetLastError());
}
break;
}
}
OutTraceB("dxwSDC::PutPrimaryDC: hdc=%x PrimaryDC=%x ret=%x\n", hdc, PrimaryDC, ret);
return ret;
}
BOOL dxwSDC::PutPrimaryDC(HDC hdc, BOOL UpdateScreen)
{
return PutPrimaryDC(hdc, UpdateScreen, 0, 0, LastScreenWidth, LastScreenHeight);
}
/*---------------------------------------------------------------------------------+
| |
| Service routines |
| |
+---------------------------------------------------------------------------------*/
void dxwSDC::copyDcAttributes(HDC destDC, HDC origDc, POINT origin)
{
origFont = (*pSelectObject)(destDC, GetCurrentObject(origDc, OBJ_FONT));
origBrush = (*pSelectObject)(destDC, GetCurrentObject(origDc, OBJ_BRUSH));
origPen = (*pSelectObject)(destDC, GetCurrentObject(origDc, OBJ_PEN));
if (GM_ADVANCED == GetGraphicsMode(origDc)){
SetGraphicsMode(destDC, GM_ADVANCED);
XFORM transform = {};
GetWorldTransform(origDc, &transform);
SetWorldTransform(destDC, &transform);
}
SetMapMode(destDC, GetMapMode(origDc));
POINT viewportOrg = {};
GetViewportOrgEx(origDc, &viewportOrg);
SetViewportOrgEx(destDC, viewportOrg.x + origin.x, viewportOrg.y + origin.y, NULL);
SIZE viewportExt = {};
GetViewportExtEx(origDc, &viewportExt);
SetViewportExtEx(destDC, viewportExt.cx, viewportExt.cy, NULL);
POINT windowOrg = {};
GetWindowOrgEx(origDc, &windowOrg);
SetWindowOrgEx(destDC, windowOrg.x, windowOrg.y, NULL);
SIZE windowExt = {};
GetWindowExtEx(origDc, &windowExt);
SetWindowExtEx(destDC, windowExt.cx, windowExt.cy, NULL);
SetArcDirection(destDC, GetArcDirection(origDc));
SetBkColor(destDC, GetBkColor(origDc));
SetBkMode(destDC, GetBkMode(origDc));
SetDCBrushColor(destDC, GetDCBrushColor(origDc));
SetDCPenColor(destDC, GetDCPenColor(origDc));
SetLayout(destDC, GetLayout(origDc));
SetPolyFillMode(destDC, GetPolyFillMode(origDc));
SetROP2(destDC, GetROP2(origDc));
SetStretchBltMode(destDC, GetStretchBltMode(origDc));
SetTextAlign(destDC, GetTextAlign(origDc));
SetTextCharacterExtra(destDC, GetTextCharacterExtra(origDc));
SetTextColor(destDC, GetTextColor(origDc));
OutTraceB("dxwSDC::copyDcAttributes: orig=(%d,%d)\n", origin.x, origin.y);
if(!(*pSetWindowOrgEx)(destDC, -origin.x, -origin.y, NULL))
OutTraceE("dxwSDC::copyDcAttributes: SetWindowOrgEx ERROR orig=(%d,%d) err=%d\n", origin.x, origin.y, GetLastError());
POINT brushOrg = {};
GetBrushOrgEx(origDc, &brushOrg);
SetBrushOrgEx(destDC, brushOrg.x, brushOrg.y, NULL);
POINT currentPos = {};
(*pGetCurrentPositionEx)(origDc, &currentPos);
dxw.MapClient(&currentPos);
(*pMoveToEx)(destDC, currentPos.x, currentPos.y, NULL);
}
typedef struct
{
HDC compatDc;
POINT origin;
HWND rootWnd;
} ExcludeClipRectsData_Type;
static BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam)
{
ExcludeClipRectsData_Type *excludeClipRectsData = (ExcludeClipRectsData_Type *)lParam;
if (!IsWindowVisible(hwnd)) return TRUE; // go ahead
if (hwnd == excludeClipRectsData->rootWnd) return FALSE; // stop
if(dxw.IsDesktop(hwnd)) return FALSE;
RECT rect = {};
(*pGetClientRect)(hwnd, &rect);
OffsetRect(&rect, -excludeClipRectsData->origin.x, -excludeClipRectsData->origin.y);
ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom);
OutTraceB("dxwSDC::excludeClipRects: hwnd=%x rect=(%d,%d)-(%d,%d)\n", hwnd, rect.left, rect.top, rect.right, rect.bottom);
return TRUE;
}
void dxwSDC::setClippingRegion(HDC compatDc, HDC origDc, POINT origin)
{
OutTraceB("dxwSDC::setClippingRegion: compdc=%x origdc=%x origin=(%d,%d)\n", compatDc, origDc, origin.x, origin.y);
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
const bool isEmptyClipRgn = (1 != GetRandomRgn(origDc, clipRgn, SYSRGN));
OutTraceB("dxwSDC::setClippingRegion: isEmptyClipRgn=%x\n", isEmptyClipRgn);
// scale clip region
POINT upleft={0, 0};
//(*pClientToScreen)(dxw.GethWnd(), &upleft);
(*pClientToScreen)(CurrenthWnd, &upleft);
if(IsDebug){
OutTraceB("dxwSDC::setClippingRegion: hwnd=%x upleft=(%d,%d)\n", CurrenthWnd, upleft.x, upleft.y);
}
OffsetRgn(clipRgn, -upleft.x, -upleft.y);
if(IsDebug){
RECT RgnBox;
GetRgnBox(clipRgn, &RgnBox);
OutTraceB("dxwSDC::setClippingRegion: RgnBox=(%d,%d)-(%d,%d) size=(%dx%d)\n",
RgnBox.left, RgnBox.top, RgnBox.right, RgnBox.bottom, RgnBox.right-RgnBox.left, RgnBox.bottom-RgnBox.top);
}
// end of scaling
(*pSelectClipRgn)(compatDc, isEmptyClipRgn ? NULL : clipRgn);
DeleteObject(clipRgn);
HRGN origClipRgn = (*pCreateRectRgn)(0, 0, 0, 0);
if (1 == GetClipRgn(origDc, origClipRgn))
{
OutTraceB("dxwSDC::setClippingRegion: GetClipRgn==1\n");
OffsetRgn(origClipRgn, origin.x, origin.y);
ExtSelectClipRgn(compatDc, origClipRgn, RGN_AND);
if(IsDebug){
RECT RgnBox;
GetRgnBox(origClipRgn, &RgnBox); // for logging only
OutTraceB("dxwSDC::setClippingRegion: OrigRgnBox=(%d,%d)-(%d,%d)\n", RgnBox.left, RgnBox.top, RgnBox.right, RgnBox.bottom);
}
}
DeleteObject(origClipRgn);
if(dxw.dwFlags7 & FIXCLIPPERAREA){
// to finish .....
// on Win10 this part seems unnecessary and giving troubles .....
if (!isEmptyClipRgn){
OutTraceB("dxwSDC::setClippingRegion: isEmptyClipRgn FALSE\n");
HWND hwnd = WindowFromDC(origDc);
if (hwnd && (!dxw.IsDesktop(hwnd))){
ExcludeClipRectsData_Type excludeClipRectsData = { compatDc, origin, dxw.GethWnd() };
//ExcludeClipRectsData_Type excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) };
OutTraceB("dxwSDC::setClippingRegion: compatdc=%x origin=(%d,%d) ancestor=%x\n",
compatDc, origin.x, origin.y, dxw.GethWnd());
EnumWindows(&excludeClipRectsForOverlappingWindows,(LPARAM)(&excludeClipRectsData));
}
}
}
}