diff --git a/inc/IDirectDrawSurface.h b/inc/IDirectDrawSurface.h index b015fea..b6258be 100644 --- a/inc/IDirectDrawSurface.h +++ b/inc/IDirectDrawSurface.h @@ -35,6 +35,8 @@ typedef struct IDirectDrawSurfaceImpl DWORD last_flip_tick; DWORD last_blt_tick; + struct IDirectDrawSurfaceImpl *backbuffer; + } IDirectDrawSurfaceImpl; typedef struct IDirectDrawSurfaceImplVtbl IDirectDrawSurfaceImplVtbl; diff --git a/inc/dd.h b/inc/dd.h index c423207..a6e6a2d 100644 --- a/inc/dd.h +++ b/inc/dd.h @@ -106,6 +106,7 @@ typedef struct cnc_ddraw BOOL nonexclusive; BOOL fixchildwindows; BOOL d3d9linear; + BOOL backbuffer; int maxgameticks; BOOL alt_key_down; BOOL bnet_active; diff --git a/inc/ddsurface.h b/inc/ddsurface.h index 5f9f388..87ee368 100644 --- a/inc/ddsurface.h +++ b/inc/ddsurface.h @@ -26,6 +26,8 @@ HRESULT dds_Lock(IDirectDrawSurfaceImpl* This, LPRECT lpDestRect, LPDDSURFACEDES HRESULT dds_SetColorKey(IDirectDrawSurfaceImpl* This, DWORD flags, LPDDCOLORKEY colorKey); HRESULT dds_SetPalette(IDirectDrawSurfaceImpl* This, LPDIRECTDRAWPALETTE lpDDPalette); HRESULT dds_Unlock(IDirectDrawSurfaceImpl* This, LPVOID lpRect); +void* dds_GetBuffer(IDirectDrawSurfaceImpl* This); +HDC dds_GetHDC(IDirectDrawSurfaceImpl* This); HRESULT dd_CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE FAR* lpDDSurface, IUnknown FAR* unkOuter); diff --git a/src/IDirectDraw/IDirectDrawSurface.c b/src/IDirectDraw/IDirectDrawSurface.c index 1a6d008..fc90e20 100644 --- a/src/IDirectDraw/IDirectDrawSurface.c +++ b/src/IDirectDraw/IDirectDrawSurface.c @@ -86,6 +86,9 @@ ULONG __stdcall IDirectDrawSurface__Release(IDirectDrawSurfaceImpl *This) if (This->bmi) HeapFree(GetProcessHeap(), 0, This->bmi); + if (This->backbuffer) + IDirectDrawSurface_Release(This->backbuffer); + if(This->palette && (!g_ddraw || (void*)This->palette != g_ddraw->last_freed_palette)) { IDirectDrawPalette_Release(This->palette); diff --git a/src/config.c b/src/config.c index a6939f5..108eee4 100644 --- a/src/config.c +++ b/src/config.c @@ -50,6 +50,7 @@ void cfg_load() g_ddraw->nonexclusive = cfg_get_bool("nonexclusive", FALSE); g_ddraw->fixchildwindows = cfg_get_bool("fixchildwindows", TRUE); g_ddraw->d3d9linear = cfg_get_bool("d3d9linear", TRUE); + g_ddraw->backbuffer = cfg_get_bool("backbuffer", TRUE); g_ddraw->sierrahack = cfg_get_bool("sierrahack", FALSE); // Sierra Caesar III, Pharaoh, and Zeus hack g_ddraw->dk2hack = cfg_get_bool("dk2hack", FALSE); // Dungeon Keeper 2 hack @@ -552,6 +553,11 @@ static void cfg_create_ini() "renderer=opengl\n" "nonexclusive=true\n" "\n" + "; Tzar: The Burden of the Crown\n" + "; Note: Must set 'DIRECTXDEVICE=0' in 'Tzar.ini'\n" + "[Tzar]\n" + "handlemouse=false\n" + "\n" , fh); fclose(fh); diff --git a/src/ddsurface.c b/src/ddsurface.c index c1681c2..088fd69 100644 --- a/src/ddsurface.c +++ b/src/ddsurface.c @@ -75,10 +75,12 @@ HRESULT dds_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestRect, LPDIRECTDRAWSUR int dst_x = dst_rect.left; int dst_y = dst_rect.top; + void* dst_buf = dds_GetBuffer(This); + void* src_buf = dds_GetBuffer(src_surface); - if (This->surface && (dwFlags & DDBLT_COLORFILL) && dst_w > 0 && dst_h > 0) + if (dst_buf && (dwFlags & DDBLT_COLORFILL) && dst_w > 0 && dst_h > 0) { - unsigned char *dst = (unsigned char *)This->surface + (dst_x * This->lx_pitch) + (This->l_pitch * dst_y); + unsigned char *dst = (unsigned char *)dst_buf + (dst_x * This->lx_pitch) + (This->l_pitch * dst_y); unsigned char *first_row = dst; unsigned int dst_pitch = dst_w * This->lx_pitch; int x, i; @@ -151,11 +153,11 @@ HRESULT dds_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestRect, LPDIRECTDRAWSUR for (x1 = 0; x1 < width; x1++) { - unsigned char c = ((unsigned char *)src_surface->surface)[x1 + src_x + ysrc]; + unsigned char c = ((unsigned char *)src_buf)[x1 + src_x + ysrc]; if (c < color_key.dwColorSpaceLowValue || c > color_key.dwColorSpaceHighValue) { - ((unsigned char *)This->surface)[x1 + dst_x + ydst] = c; + ((unsigned char *)dst_buf)[x1 + dst_x + ydst] = c; } } } @@ -170,11 +172,11 @@ HRESULT dds_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestRect, LPDIRECTDRAWSUR for (x1 = 0; x1 < width; x1++) { - unsigned short c = ((unsigned short *)src_surface->surface)[x1 + src_x + ysrc]; + unsigned short c = ((unsigned short *)src_buf)[x1 + src_x + ysrc]; if (c < color_key.dwColorSpaceLowValue || c > color_key.dwColorSpaceHighValue) { - ((unsigned short *)This->surface)[x1 + dst_x + ydst] = c; + ((unsigned short *)dst_buf)[x1 + dst_x + ydst] = c; } } } @@ -193,10 +195,10 @@ HRESULT dds_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestRect, LPDIRECTDRAWSUR int height = dst_h > src_h ? src_h : dst_h; unsigned char *src = - (unsigned char *)src_surface->surface + (src_x * src_surface->lx_pitch) + (src_surface->l_pitch * src_y); + (unsigned char *)src_buf + (src_x * src_surface->lx_pitch) + (src_surface->l_pitch * src_y); unsigned char *dst = - (unsigned char *)This->surface + (dst_x * This->lx_pitch) + (This->l_pitch * dst_y); + (unsigned char *)dst_buf + (dst_x * This->lx_pitch) + (This->l_pitch * dst_y); unsigned int dst_pitch = width * This->lx_pitch; @@ -316,8 +318,8 @@ HRESULT dds_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestRect, LPDIRECTDRAWSUR if (This->bpp == 8) { unsigned char *d, *s, v; - unsigned char *src = (unsigned char *)src_surface->surface; - unsigned char *dst = (unsigned char *)This->surface; + unsigned char *src = (unsigned char *)src_buf; + unsigned char *dst = (unsigned char *)dst_buf; do { switch (current->type) @@ -355,8 +357,8 @@ HRESULT dds_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestRect, LPDIRECTDRAWSUR else if (This->bpp == 16) { unsigned short *d, *s, v; - unsigned short *src = (unsigned short *)src_surface->surface; - unsigned short *dst = (unsigned short *)This->surface; + unsigned short *src = (unsigned short *)src_buf; + unsigned short *dst = (unsigned short *)dst_buf; do { switch (current->type) @@ -466,6 +468,9 @@ HRESULT dds_BltFast(IDirectDrawSurfaceImpl *This, DWORD dst_x, DWORD dst_y, LPDI int dst_w = dst_rect.right - dst_rect.left; int dst_h = dst_rect.bottom - dst_rect.top; + void* dst_buf = dds_GetBuffer(This); + void* src_buf = dds_GetBuffer(src_surface); + if (src_surface && dst_w > 0 && dst_h > 0) { if (flags & DDBLTFAST_SRCCOLORKEY) @@ -480,11 +485,11 @@ HRESULT dds_BltFast(IDirectDrawSurfaceImpl *This, DWORD dst_x, DWORD dst_y, LPDI for (x1 = 0; x1 < dst_w; x1++) { - unsigned char c = ((unsigned char *)src_surface->surface)[x1 + src_x + ysrc]; + unsigned char c = ((unsigned char *)src_buf)[x1 + src_x + ysrc]; if (c < src_surface->color_key.dwColorSpaceLowValue || c > src_surface->color_key.dwColorSpaceHighValue) { - ((unsigned char *)This->surface)[x1 + dst_x + ydst] = c; + ((unsigned char *)dst_buf)[x1 + dst_x + ydst] = c; } } } @@ -499,11 +504,11 @@ HRESULT dds_BltFast(IDirectDrawSurfaceImpl *This, DWORD dst_x, DWORD dst_y, LPDI for (x1 = 0; x1 < dst_w; x1++) { - unsigned short c = ((unsigned short *)src_surface->surface)[x1 + src_x + ysrc]; + unsigned short c = ((unsigned short *)src_buf)[x1 + src_x + ysrc]; if (c < src_surface->color_key.dwColorSpaceLowValue || c > src_surface->color_key.dwColorSpaceHighValue) { - ((unsigned short *)This->surface)[x1 + dst_x + ydst] = c; + ((unsigned short *)dst_buf)[x1 + dst_x + ydst] = c; } } } @@ -512,10 +517,10 @@ HRESULT dds_BltFast(IDirectDrawSurfaceImpl *This, DWORD dst_x, DWORD dst_y, LPDI else { unsigned char *src = - (unsigned char *)src_surface->surface + (src_x * src_surface->lx_pitch) + (src_surface->l_pitch * src_y); + (unsigned char *)src_buf + (src_x * src_surface->lx_pitch) + (src_surface->l_pitch * src_y); unsigned char *dst = - (unsigned char *)This->surface + (dst_x * This->lx_pitch) + (This->l_pitch * dst_y); + (unsigned char *)dst_buf + (dst_x * This->lx_pitch) + (This->l_pitch * dst_y); unsigned int dst_pitch = dst_w * This->lx_pitch; @@ -591,7 +596,7 @@ HRESULT dds_GetSurfaceDesc(IDirectDrawSurfaceImpl *This, LPDDSURFACEDESC lpDDSur lpDDSurfaceDesc->dwWidth = This->width; lpDDSurfaceDesc->dwHeight = This->height; lpDDSurfaceDesc->lPitch = This->l_pitch; - lpDDSurfaceDesc->lpSurface = This->surface; + lpDDSurfaceDesc->lpSurface = dds_GetBuffer(This); lpDDSurfaceDesc->ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); lpDDSurfaceDesc->ddpfPixelFormat.dwFlags = DDPF_RGB; lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount = This->bpp; @@ -634,6 +639,19 @@ HRESULT dds_Flip(IDirectDrawSurfaceImpl *This, LPDIRECTDRAWSURFACE surface, DWOR { if(This->caps & DDSCAPS_PRIMARYSURFACE && g_ddraw->render.run) { + if (This->backbuffer) + { + EnterCriticalSection(&g_ddraw->cs); + void* surface = InterlockedExchangePointer(&This->surface, This->backbuffer->surface); + HBITMAP bitmap = (HBITMAP)InterlockedExchangePointer(&This->bitmap, This->backbuffer->bitmap); + HDC hdc = (HDC)InterlockedExchangePointer(&This->hdc, This->backbuffer->hdc); + + InterlockedExchangePointer(&This->backbuffer->surface, surface); + InterlockedExchangePointer(&This->backbuffer->bitmap, bitmap); + InterlockedExchangePointer(&This->backbuffer->hdc, hdc); + LeaveCriticalSection(&g_ddraw->cs); + } + This->last_flip_tick = timeGetTime(); InterlockedExchange(&g_ddraw->render.surface_updated, TRUE); @@ -659,8 +677,16 @@ HRESULT dds_GetAttachedSurface(IDirectDrawSurfaceImpl *This, LPDDSCAPS lpDdsCaps { if ((This->caps & DDSCAPS_PRIMARYSURFACE) && (This->caps & DDSCAPS_FLIP) && (lpDdsCaps->dwCaps & DDSCAPS_BACKBUFFER)) { - IDirectDrawSurface_AddRef(This); - *surface = (LPDIRECTDRAWSURFACE)This; + if (This->backbuffer) + { + IDirectDrawSurface_AddRef(This->backbuffer); + *surface = (LPDIRECTDRAWSURFACE)This->backbuffer; + } + else + { + IDirectDrawSurface_AddRef(This); + *surface = (LPDIRECTDRAWSURFACE)This; + } } return DD_OK; @@ -696,9 +722,9 @@ HRESULT dds_GetDC(IDirectDrawSurfaceImpl *This, HDC FAR *a) NULL; if (data) - SetDIBColorTable(This->hdc, 0, 256, data); + SetDIBColorTable(dds_GetHDC(This), 0, 256, data); - *a = This->hdc; + *a = dds_GetHDC(This); return DD_OK; } @@ -752,7 +778,7 @@ HRESULT dds_Lock(IDirectDrawSurfaceImpl *This, LPRECT lpDestRect, LPDDSURFACEDES if (lpDestRect && lpDDSurfaceDesc && lpDestRect->left >= 0 && lpDestRect->top >= 0) { lpDDSurfaceDesc->lpSurface = - (char*)This->surface + (lpDestRect->left * This->lx_pitch) + (lpDestRect->top * This->l_pitch); + (char*)dds_GetBuffer(This) + (lpDestRect->left * This->lx_pitch) + (lpDestRect->top * This->l_pitch); } return ret; @@ -810,12 +836,12 @@ HRESULT dds_Unlock(IDirectDrawSurfaceImpl *This, LPVOID lpRect) if (hwnd && (This->caps & DDSCAPS_PRIMARYSURFACE)) { if (g_ddraw->primary->palette && g_ddraw->primary->palette->data_rgb) - SetDIBColorTable(g_ddraw->primary->hdc, 0, 256, g_ddraw->primary->palette->data_rgb); + SetDIBColorTable(dds_GetHDC(g_ddraw->primary), 0, 256, g_ddraw->primary->palette->data_rgb); //GdiTransparentBlt idea taken from Aqrit's war2 ddraw RGBQUAD quad; - GetDIBColorTable(g_ddraw->primary->hdc, 0xFE, 1, &quad); + GetDIBColorTable(dds_GetHDC(g_ddraw->primary), 0xFE, 1, &quad); COLORREF color = RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue); BOOL erase = FALSE; @@ -835,7 +861,7 @@ HRESULT dds_Unlock(IDirectDrawSurfaceImpl *This, LPVOID lpRect) 0, rc.right - rc.left, rc.bottom - rc.top, - g_ddraw->primary->hdc, + dds_GetHDC(g_ddraw->primary), rc.left, rc.top, rc.right - rc.left, @@ -878,6 +904,28 @@ HRESULT dds_Unlock(IDirectDrawSurfaceImpl *This, LPVOID lpRect) return DD_OK; } +void* dds_GetBuffer(IDirectDrawSurfaceImpl* This) +{ + if (!This) + return NULL; + + if (This->backbuffer || (This->caps & DDSCAPS_BACKBUFFER)) + return (void*)InterlockedExchangeAdd(&This->surface, 0); + + return This->surface; +} + +HDC dds_GetHDC(IDirectDrawSurfaceImpl* This) +{ + if (!This) + return NULL; + + if (This->backbuffer || (This->caps & DDSCAPS_BACKBUFFER)) + return (HDC)InterlockedExchangeAdd(&This->hdc, 0); + + return This->hdc; +} + HRESULT dd_CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE FAR *lpDDSurface, IUnknown FAR * unkOuter) { dbg_dump_dds_flags(lpDDSurfaceDesc->dwFlags); @@ -980,6 +1028,19 @@ HRESULT dd_CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE FA if (lpDDSurfaceDesc->dwFlags & DDSD_BACKBUFFERCOUNT) { dprintf(" dwBackBufferCount=%d\n", lpDDSurfaceDesc->dwBackBufferCount); + + if (g_ddraw->backbuffer) + { + DDSURFACEDESC desc; + memset(&desc, 0, sizeof(DDSURFACEDESC)); + + desc.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER; + + desc.dwWidth = dst_surface->width; + desc.dwHeight = dst_surface->height; + + dd_CreateSurface(&desc, &dst_surface->backbuffer, unkOuter); + } } dprintf(" surface = %p (%dx%d@%d)\n", dst_surface, (int)dst_surface->width, (int)dst_surface->height, (int)dst_surface->bpp); diff --git a/src/debug.c b/src/debug.c index d84c83b..3ca4fb3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -146,9 +146,9 @@ void dbg_draw_frame_info_start() if (g_ddraw->primary) { if (g_ddraw->primary->palette && g_ddraw->primary->palette->data_rgb) - SetDIBColorTable(g_ddraw->primary->hdc, 0, 256, g_ddraw->primary->palette->data_rgb); - - DrawText(g_ddraw->primary->hdc, debug_text, -1, &debugrc, DT_NOCLIP); + SetDIBColorTable(dds_GetHDC(g_ddraw->primary), 0, 256, g_ddraw->primary->palette->data_rgb); + + DrawText(dds_GetHDC(g_ddraw->primary), debug_text, -1, &debugrc, DT_NOCLIP); } DWORD tick_start = timeGetTime(); diff --git a/src/screenshot.c b/src/screenshot.c index adbe17e..7a2ce10 100644 --- a/src/screenshot.c +++ b/src/screenshot.c @@ -9,7 +9,7 @@ BOOL ss_take_screenshot(struct IDirectDrawSurfaceImpl *src) { - if (!src || !src->palette || !src->surface) + if (!src || !src->palette || !dds_GetBuffer(src)) return FALSE; int i; @@ -54,7 +54,7 @@ BOOL ss_take_screenshot(struct IDirectDrawSurfaceImpl *src) state.info_raw.bitdepth = 8; state.encoder.auto_convert = 0; - unsigned int error = lodepng_encode(&png, &pngsize, src->surface, src->width, src->height, &state); + unsigned int error = lodepng_encode(&png, &pngsize, dds_GetBuffer(src), src->width, src->height, &state); if (!error) lodepng_save_file(png, pngsize, filename); diff --git a/src/utils.c b/src/utils.c index 7b111aa..2b88e57 100644 --- a/src/utils.c +++ b/src/utils.c @@ -321,7 +321,7 @@ BOOL CALLBACK util_enum_child_proc(HWND hwnd, LPARAM lparam) MapWindowPoints(HWND_DESKTOP, g_ddraw->hwnd, (LPPOINT)&pos, 2); - BitBlt(hdc, 0, 0, size.right, size.bottom, this->hdc, pos.left, pos.top, SRCCOPY); + BitBlt(hdc, 0, 0, size.right, size.bottom, dds_GetHDC(this), pos.left, pos.top, SRCCOPY); ReleaseDC(hwnd, hdc); } @@ -332,7 +332,7 @@ BOOL CALLBACK util_enum_child_proc(HWND hwnd, LPARAM lparam) static unsigned char util_get_pixel(int x, int y) { - return ((unsigned char*)g_ddraw->primary->surface)[y * g_ddraw->primary->l_pitch + x * g_ddraw->primary->lx_pitch]; + return ((unsigned char*)dds_GetBuffer(g_ddraw->primary))[y * g_ddraw->primary->l_pitch + x * g_ddraw->primary->lx_pitch]; } BOOL util_detect_cutscene()