diff --git a/DDrawCompat/Config/Config.cpp b/DDrawCompat/Config/Config.cpp index 0166824..5d81adb 100644 --- a/DDrawCompat/Config/Config.cpp +++ b/DDrawCompat/Config/Config.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,7 @@ namespace Config Settings::SupportedResolutions supportedResolutions; Settings::SupportedDepthFormats supportedDepthFormats; Settings::SupportedTextureFormats supportedTextureFormats; + Settings::SurfacePatches surfacePatches; Settings::TerminateHotKey terminateHotKey; Settings::TextureFilter textureFilter; Settings::ThreadPriorityBoost threadPriorityBoost; diff --git a/DDrawCompat/Config/ListSetting.cpp b/DDrawCompat/Config/ListSetting.cpp index 0b3b8ac..55e6e31 100644 --- a/DDrawCompat/Config/ListSetting.cpp +++ b/DDrawCompat/Config/ListSetting.cpp @@ -8,6 +8,15 @@ namespace Config { } + void ListSetting::appendToList(std::string& list, const std::string& value) + { + if (!list.empty()) + { + list += ", "; + } + list += value; + } + void ListSetting::setValue(const std::string& value) { std::vector values; diff --git a/DDrawCompat/Config/ListSetting.h b/DDrawCompat/Config/ListSetting.h index e94597b..91b2265 100644 --- a/DDrawCompat/Config/ListSetting.h +++ b/DDrawCompat/Config/ListSetting.h @@ -13,5 +13,7 @@ namespace Config virtual void setValue(const std::string& value) override; virtual void setValues(const std::vector& values) = 0; + + static void appendToList(std::string& list, const std::string& value); }; } diff --git a/DDrawCompat/Config/Settings/SurfacePatches.cpp b/DDrawCompat/Config/Settings/SurfacePatches.cpp new file mode 100644 index 0000000..4d6cea4 --- /dev/null +++ b/DDrawCompat/Config/Settings/SurfacePatches.cpp @@ -0,0 +1,78 @@ +#include +#include +#include + +namespace Config +{ + namespace Settings + { + SurfacePatches::SurfacePatches() + : ListSetting("SurfacePatches", "none") + , m_top(0) + , m_bottom(0) + { + } + + std::string SurfacePatches::getValueStr() const + { + std::string result; + if (0 != m_top) + { + appendToList(result, "top:" + std::to_string(m_top)); + } + if (0 != m_bottom) + { + appendToList(result, "bottom:" + std::to_string(m_bottom)); + } + if (result.empty()) + { + result = "none"; + } + return result; + } + + void SurfacePatches::setValues(const std::vector& values) + { + unsigned top = 0; + unsigned bottom = 0; + + for (const auto& v : values) + { + if ("none" == v) + { + if (1 != values.size()) + { + throw ParsingError("'none' cannot be combined with other values"); + } + m_top = 0; + m_bottom = 0; + return; + } + + auto separator = v.find(':'); + if (std::string::npos == separator || 0 == separator || v.size() - 1 == separator) + { + throw ParsingError("invalid value: '" + v + "'"); + } + + auto specifier = v.substr(0, separator); + auto rows = Parser::parseInt(v.substr(separator + 1), 1, 1000); + if ("top" == specifier) + { + top = rows; + } + else if ("bottom" == specifier) + { + bottom = rows; + } + else + { + throw ParsingError("invalid specifier: '" + specifier + "'"); + } + } + + m_top = top; + m_bottom = bottom; + } + } +} diff --git a/DDrawCompat/Config/Settings/SurfacePatches.h b/DDrawCompat/Config/Settings/SurfacePatches.h new file mode 100644 index 0000000..d3b6cba --- /dev/null +++ b/DDrawCompat/Config/Settings/SurfacePatches.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace Config +{ + namespace Settings + { + class SurfacePatches : public ListSetting + { + public: + SurfacePatches(); + + virtual std::string getValueStr() const override; + + unsigned getTop() const { return m_top; } + unsigned getBottom() const { return m_bottom; } + + private: + void setValues(const std::vector& values) override; + + unsigned m_top; + unsigned m_bottom; + }; + } + + extern Settings::SurfacePatches surfacePatches; +} diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 8f975af..88c3411 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -620,11 +621,20 @@ namespace D3dDdi } } + unsigned topExtraRows = 0; + unsigned totalExtraRows = 0; + if (1 == m_fixedData.SurfCount && !m_origData.Flags.Texture) + { + topExtraRows = Config::surfacePatches.getTop(); + totalExtraRows = topExtraRows + Config::surfacePatches.getBottom(); + } + std::uintptr_t bufferSize = reinterpret_cast(surfaceInfo.back().pSysMem) + - surfaceInfo.back().SysMemPitch * surfaceInfo.back().Height + ALIGNMENT; + surfaceInfo.back().SysMemPitch * (surfaceInfo.back().Height + totalExtraRows) + ALIGNMENT; m_lockBuffer.reset(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufferSize)); - BYTE* bufferStart = static_cast(DDraw::Surface::alignBuffer(m_lockBuffer.get())); + BYTE* bufferStart = static_cast(DDraw::Surface::alignBuffer( + static_cast(m_lockBuffer.get()) + topExtraRows * surfaceInfo.back().SysMemPitch)); for (UINT i = 0; i < m_fixedData.SurfCount; ++i) { surfaceInfo[i].pSysMem = bufferStart + reinterpret_cast(surfaceInfo[i].pSysMem); diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 5ccf80c..b7f45e1 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -208,6 +208,7 @@ + @@ -366,6 +367,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 2d572ca..2343e09 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -711,6 +711,9 @@ Header Files\Overlay + + Header Files\Config\Settings + @@ -1112,6 +1115,9 @@ Source Files\Overlay + + Source Files\Config\Settings + diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 61e775d..6d8ea5e 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -1,7 +1,8 @@ #include -#include #include +#include +#include #include #include #include @@ -29,6 +30,7 @@ namespace LONG g_width = 0; LONG g_height = 0; DWORD g_pitch = 0; + DWORD g_startOffset = 0; HANDLE g_surfaceFileMapping = nullptr; void* g_surfaceView = nullptr; bool g_isFullscreen = false; @@ -82,7 +84,7 @@ namespace } void* bits = nullptr; - return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, section, Config::alignSysMemSurfaces.get()); + return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, section, g_startOffset); } } @@ -206,7 +208,7 @@ namespace Gdi desc.ddpfPixelFormat = DDraw::DirectDraw::getRgbPixelFormat(g_bpp); desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; desc.lPitch = g_pitch; - desc.lpSurface = static_cast(g_surfaceView) + Config::alignSysMemSurfaces.get() + + desc.lpSurface = static_cast(g_surfaceView) + g_startOffset + (rect.top - g_bounds.top) * g_pitch + (rect.left - g_bounds.left) * g_bpp / 8; return desc; @@ -287,10 +289,16 @@ namespace Gdi CloseHandle(g_surfaceFileMapping); } + auto totalExtraRows = Config::surfacePatches.getTop() + Config::surfacePatches.getBottom(); g_surfaceFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, - g_pitch * g_height + 8, nullptr); + (g_height + totalExtraRows) * g_pitch + DDraw::Surface::ALIGNMENT, nullptr); g_surfaceView = MapViewOfFile(g_surfaceFileMapping, FILE_MAP_WRITE, 0, 0, 0); + auto start = static_cast(g_surfaceView); + start += Config::surfacePatches.getTop() * g_pitch; + start = static_cast(DDraw::Surface::alignBuffer(start)); + g_startOffset = start - static_cast(g_surfaceView); + for (auto& dc : g_dcs) { SelectObject(dc.first, createDib(dc.second.useDefaultPalette));