diff --git a/d2gl/src/app.cpp b/d2gl/src/app.cpp index d9e95d6..0a7a7b0 100644 --- a/d2gl/src/app.cpp +++ b/d2gl/src/app.cpp @@ -38,6 +38,7 @@ void checkCompatibilityMode() char msg[128] = { 0 }; sprintf_s(msg, "Please disable the '%s' compatibility mode for game executable and then try to start the game again.", str); MessageBoxA(NULL, msg, "Compatibility mode detected!", MB_OK); + error_log("Compatibility mode '%s' detected!", str); break; } str = strtok_s(NULL, " ", &context); @@ -45,30 +46,19 @@ void checkCompatibilityMode() } } -void checkDPIAwareness() -{ - bool setDpiAware = SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); - if (!setDpiAware) { - HRESULT result = SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); - setDpiAware = result == S_OK || result == E_ACCESSDENIED; - } - if (!setDpiAware) - SetProcessDPIAware(); -} - void dllAttach(HMODULE hmodule) { std::string command_line = GetCommandLineA(); helpers::strToLower(command_line); + if (command_line.find("-w ") != std::string::npos || command_line.find("-w") == command_line.length() - 2) + return; + if (command_line.find("d2vidtst") != std::string::npos) { App.video_test = true; return; } - if (command_line.find("-w") != std::string::npos) - return; - bool flag_3dfx = command_line.find("-3dfx") != std::string::npos; flag_3dfx = !flag_3dfx ? *d2::video_mode == 4 : flag_3dfx; @@ -80,16 +70,31 @@ void dllAttach(HMODULE hmodule) logInit(); + auto ini_pos = command_line.find("-config "); + if (ini_pos != std::string::npos) { + std::string custom_ini = ""; + for (size_t i = ini_pos + 8; i < command_line.length(); i++) { + if (command_line.at(i) == ' ') + break; + custom_ini += command_line.at(i); + } + custom_ini.erase(std::remove(custom_ini.begin(), custom_ini.end(), ' '), custom_ini.end()); + if (custom_ini.length() > 0) { + App.ini_file = "d2gl_" + custom_ini + ".ini"; + trace_log("Custom config file: %s", App.ini_file.c_str()); + } + } + if (helpers::getVersion() == Version::Unknown) { MessageBoxA(NULL, "Game version is not supported!", "Unsupported version!", MB_OK | MB_ICONERROR); error_log("Game version is not supported!"); exit(1); } - trace_log("Game version %s detected.", helpers::getVersionString().c_str()); + trace_log("Diablo 2 LoD version %s detected.", helpers::getVersionString().c_str()); timeBeginPeriod(1); checkCompatibilityMode(); - checkDPIAwareness(); + win32::setDPIAwareness(); App.hmodule = hmodule; option::loadIni(); diff --git a/d2gl/src/app.h b/d2gl/src/app.h index d0fc27c..6acd554 100644 --- a/d2gl/src/app.h +++ b/d2gl/src/app.h @@ -74,6 +74,7 @@ struct D2GLApp { glm::ivec2 offset = { 0, 0 }; glm::uvec2 size = { 800, 600 }; glm::vec2 scale = { 1.0f, 1.0f }; + glm::bvec2 stretched = { false, false }; } viewport; struct { @@ -90,7 +91,7 @@ struct D2GLApp { bool locked = false; glm::vec2 scale = { 1.0f, 1.0f }; glm::vec2 unscale = { 1.0f, 1.0f }; - bool no_lock = false; + bool unlock = false; } cursor; Select resolutions = {}; diff --git a/d2gl/src/d2/common.cpp b/d2gl/src/d2/common.cpp index be4276d..e875082 100644 --- a/d2gl/src/d2/common.cpp +++ b/d2gl/src/d2/common.cpp @@ -139,6 +139,12 @@ void initHooks() no_intro.add(PatchType::Swap, getOffset((DLL_D2LAUNCH), (0x24F84), (0x27AD0), (0x1E288), (0x1E194), (0x1E2B8), (0x1E174), (0x1E36C), (0x2D4CFC)), 4, 0x00000000); no_intro.toggle(App.skip_intro); + if (isVer(V_113d)) { + Patch multiple_instance = Patch(); + multiple_instance.add(PatchType::Swap, getOffset((DLL_D2GFX), (), (), (), (), (), (), (0xB6B0), ()), 2, 0xEB450000); + multiple_instance.toggle(true); + } + Patch game_loop = Patch(); game_loop.add(PatchType::Call, getOffset((DLL_D2CLIENT), (0x9B3D, 0xE87A5F0B), (0xA2A2, 0xE8B51B0C), (0x89A2F, 0xE84A37F8), (0x3356F, 0xE85E9CFD), (0x7D1BF, 0xE84801F9), (0x44E2F, 0xE81A85FC), (0x45E7F, 0xE8E473FC), (0x4F256, 0xE8E5550C)), 5, (uintptr_t)gameDrawBeginStub); game_loop.add(PatchType::Auto, getOffset((DLL_D2CLIENT, 0x5333DB3B), (0x865AC, 0x33ED894C), (0x81B7C, 0x33DB894C), (0xA35F6), (0x669F6), (0x90156), (0xC39E6), (0x1D3E6), (0x56EE1, 0x8BEC83EC)), isVerMax(V_110) ? 6 : 5, (uintptr_t)uiDrawBeginStub); diff --git a/d2gl/src/d2/funcs.cpp b/d2gl/src/d2/funcs.cpp index 38858b1..696256a 100644 --- a/d2gl/src/d2/funcs.cpp +++ b/d2gl/src/d2/funcs.cpp @@ -108,6 +108,11 @@ bool isUnitDead(UnitAny* unit) return unit && (d2::getUnitFlag(unit) & 0x10000); } +wchar_t* getPlayerName(UnitAny* unit) +{ + return (wchar_t*)(isVer(V_109d) ? unit->v109.pPlayerData->szName : unit->v110.pPlayerData->szName); +} + MonsterType getMonsterType(UnitAny* unit) { if (isVer(V_109d)) { @@ -137,6 +142,14 @@ ItemQuality getItemQuality(UnitAny* unit) return isVer(V_109d) ? unit->v109.pItemData->dwQuality : unit->v110.pItemData->dwQuality; } +bool isMercUnit(UnitAny* unit) +{ + if (unit->dwType != d2::UnitType::Monster || isVer(V_109d)) + return false; + + return unit->v110.dwClassId == MERC_A1 || unit->v110.dwClassId == MERC_A2 || unit->v110.dwClassId == MERC_A3 || unit->v110.dwClassId == MERC_A4 || unit->v110.dwClassId == MERC_A5; +} + CellFile* getCellFile(CellContext* cell) { if (isVerMin(V_113c)) @@ -194,7 +207,7 @@ void __stdcall drawImageHooked(CellContext* cell, int x, int y, uint32_t gamma, if (App.hd_cursor && App.game.draw_stage >= DrawStage::Cursor) return; - if (modules::HDText::Instance().drawImage(cell, x, y, gamma, draw_mode)) { + if (modules::HDText::Instance().drawImage(cell, x, y, draw_mode)) { const auto pos = modules::MotionPrediction::Instance().drawImage(x, y, D2DrawFn::Image, gamma, draw_mode); drawImage(cell, pos.x, pos.y, gamma, draw_mode, palette); } @@ -208,7 +221,7 @@ void __stdcall drawPerspectiveImageHooked(CellContext* cell, int x, int y, uint3 void __stdcall drawShiftedImageHooked(CellContext* cell, int x, int y, uint32_t gamma, int draw_mode, int global_palette_shift) { - if (modules::HDText::Instance().drawShiftedImage(cell, x, y, gamma, draw_mode)) { + if (modules::HDText::Instance().drawShiftedImage(cell, x, y)) { auto pos = modules::MotionPrediction::Instance().drawImage(x, y, D2DrawFn::ShiftedImage); drawShiftedImage(cell, pos.x, pos.y, gamma, draw_mode, global_palette_shift); } @@ -318,7 +331,7 @@ void __fastcall drawFramedTextHooked(const wchar_t* str, int x, int y, uint32_t void __fastcall drawRectangledTextHooked(const wchar_t* str, int x, int y, uint32_t rect_color, uint32_t rect_transparency, uint32_t color) { const auto pos = modules::MotionPrediction::Instance().drawText(str, x, y, D2DrawFn::RectangledText); - if (!modules::HDText::Instance().drawRectangledText(str, pos.x, pos.y, rect_color, rect_transparency, color)) + if (!modules::HDText::Instance().drawRectangledText(str, pos.x, pos.y, rect_transparency, color)) drawRectangledText(str, pos.x, pos.y, rect_color, rect_transparency, color); } diff --git a/d2gl/src/d2/funcs.h b/d2gl/src/d2/funcs.h index e1c4669..a5f6f45 100644 --- a/d2gl/src/d2/funcs.h +++ b/d2gl/src/d2/funcs.h @@ -29,16 +29,21 @@ bool isEscMenuOpen(); UnitAny* getPlayerUnit(); UnitAny* findUnit(uint32_t type_id); + DWORD getUnitID(UnitAny* unit); DWORD getUnitFlag(UnitAny* unit); Path* getUnitPath(UnitAny* unit); StaticPath* getUnitStaticPath(UnitAny* unit); uint32_t getUnitStat(UnitAny* unit, uint32_t stat); UnitAny* getSelectedItem(); + bool isUnitDead(UnitAny* unit); +wchar_t* getPlayerName(UnitAny* unit); MonsterType getMonsterType(UnitAny* unit); wchar_t* getMonsterName(UnitAny* unit); + ItemQuality getItemQuality(UnitAny* unit); +bool isMercUnit(UnitAny* unit); CellFile* getCellFile(CellContext* cell); DWORD getCellNo(CellContext* cell); diff --git a/d2gl/src/d2/structs.h b/d2gl/src/d2/structs.h index d1ad671..37a4dd9 100644 --- a/d2gl/src/d2/structs.h +++ b/d2gl/src/d2/structs.h @@ -30,6 +30,12 @@ enum class UnitType { Count, }; +#define MERC_A1 0x010f +#define MERC_A2 0x0152 +#define MERC_A3 0x0167 +#define MERC_A4 0x0420 // PD2 +#define MERC_A5 0x0231 + enum class ItemQuality { None, Inferior, @@ -208,6 +214,10 @@ struct StaticPath { DWORD dwFlags; }; +struct PlayerData { + char szName[16]; +}; + struct MonStatsTxt { DWORD _1[19]; BYTE bAlign; @@ -286,7 +296,7 @@ struct UnitAny { DWORD dwUnitId; DWORD dwMode; union { - void* pPlayerData; + PlayerData* pPlayerData; ItemData* pItemData; MonsterData110* pMonsterData; void* pObjectData; @@ -327,7 +337,7 @@ struct UnitAny { }; DWORD _3[13]; union { - void* pPlayerData; + PlayerData* pPlayerData; ItemData* pItemData; MonsterData109* pMonsterData; void* pObjectData; diff --git a/d2gl/src/graphic/command_buffer.cpp b/d2gl/src/graphic/command_buffer.cpp index fbb38f5..1531835 100644 --- a/d2gl/src/graphic/command_buffer.cpp +++ b/d2gl/src/graphic/command_buffer.cpp @@ -38,15 +38,9 @@ inline void CommandBuffer::next() m_count++; } -void CommandBuffer::pushCommand(CommandType type) +void CommandBuffer::pushCommand(CommandType type, uint32_t index) { m_command->type = type; - next(); -} - -void CommandBuffer::setBlendState(uint32_t index) -{ - m_command->type = CommandType::SetBlendState; m_command->index = index; next(); } diff --git a/d2gl/src/graphic/command_buffer.h b/d2gl/src/graphic/command_buffer.h index 84929c6..72564e0 100644 --- a/d2gl/src/graphic/command_buffer.h +++ b/d2gl/src/graphic/command_buffer.h @@ -34,7 +34,7 @@ struct TexData { struct TexUpdateQueue { uint32_t count = 0; uint32_t data_offset = 0; - std::array tex_data = {}; + std::array tex_data = {}; }; enum class UBOType { @@ -49,7 +49,7 @@ struct UBOData { struct UBOUpdateQueue { uint32_t count = 0; - std::array data; + std::array data; }; struct GameTexUpdate { @@ -66,7 +66,7 @@ struct HDTextMasking { class CommandBuffer { uint32_t m_count = 0; Command* m_command = nullptr; - std::array m_commands; + std::array m_commands; UBOUpdateQueue m_ubo_update_queue; TexUpdateQueue m_tex_update_queue; @@ -92,8 +92,7 @@ class CommandBuffer { void reset(); void next(); - void pushCommand(CommandType type); - void setBlendState(uint32_t index); + void pushCommand(CommandType type, uint32_t index = 0); void drawIndexed(uint32_t start, uint32_t count); void resize(); diff --git a/d2gl/src/graphic/context.cpp b/d2gl/src/graphic/context.cpp index 9c73e2a..c0459a7 100644 --- a/d2gl/src/graphic/context.cpp +++ b/d2gl/src/graphic/context.cpp @@ -100,12 +100,12 @@ Context::Context() glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_unit); trace_log("OpenGL: GL_MAX_TEXTURE_IMAGE_UNITS = %d", max_texture_unit); - if (App.debug && glewIsSupported("GL_KHR_debug")) { + if ((App.debug || App.log) && glewIsSupported("GL_KHR_debug")) { glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(Context::debugMessageCallback, nullptr); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); - trace("GL_KHR_debug enabled!"); + trace_log("OpenGL: GL_KHR_debug enabled!"); } if (App.use_compute_shader && (glewIsSupported("GL_VERSION_4_3") || glewIsSupported("GL_ARB_compute_shader"))) { @@ -294,7 +294,7 @@ Context::Context() m_frame.frame_times.assign(FRAMETIME_SAMPLE_COUNT, m_frame.frame_time); m_limiter.timer = CreateWaitableTimer(NULL, TRUE, NULL); - setFpsLimit(App.foreground_fps.active, App.foreground_fps.range.value); + setFpsLimit(!App.vsync && App.foreground_fps.active, App.foreground_fps.range.value); m_vertices_mod.count = 0; m_vertices_mod.ptr = m_vertices_mod.data[m_frame_index].data(); @@ -423,7 +423,7 @@ void Context::renderThread(void* context) } ctx->drawQuad(3 + App.bloom.active, App.lut.selected); - ctx->bindPipeline(ctx->m_game_pipeline, ctx->m_current_blend_index); + ctx->bindPipeline(ctx->m_game_pipeline, command->index); break; case CommandType::Begin: if (cmd->m_screen == GameScreen::Movie) { @@ -465,12 +465,15 @@ void Context::renderThread(void* context) ctx->m_upscale_texture->fillFromBuffer(ctx->m_game_framebuffer); + const glm::ivec2 viewport_size = { App.viewport.stretched.x ? App.window.size.x : App.viewport.size.x, App.viewport.stretched.y ? App.window.size.y : App.viewport.size.y }; + const glm::ivec2 viewport_offset = { App.viewport.stretched.x ? 0 : App.viewport.offset.x, App.viewport.stretched.y ? 0 : App.viewport.offset.y }; + if (App.sharpen.active || App.fxaa) { ctx->bindFrameBuffer(ctx->m_postfx_framebuffer, false); ctx->setViewport(App.viewport.size); } else { ctx->bindDefaultFrameBuffer(); - ctx->setViewport(App.viewport.size, App.viewport.offset); + ctx->setViewport(viewport_size, viewport_offset); } ctx->bindPipeline(ctx->m_upscale_pipeline); ctx->drawQuad(); @@ -480,7 +483,7 @@ void Context::renderThread(void* context) ctx->m_postfx_texture->fillFromBuffer(ctx->m_postfx_framebuffer); else { ctx->bindDefaultFrameBuffer(); - ctx->setViewport(App.viewport.size, App.viewport.offset); + ctx->setViewport(viewport_size, viewport_offset); } ctx->bindPipeline(ctx->m_postfx_pipeline); ctx->drawQuad(App.fxaa); @@ -492,7 +495,7 @@ void Context::renderThread(void* context) ctx->m_fxaa_compute_pipeline->dispatchCompute(0, ctx->m_fxaa_work_size, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } ctx->bindDefaultFrameBuffer(); - ctx->setViewport(App.viewport.size, App.viewport.offset); + ctx->setViewport(viewport_size, viewport_offset); ctx->bindPipeline(ctx->m_postfx_pipeline); ctx->drawQuad(2 + App.gl_caps.compute_shader); } @@ -517,15 +520,9 @@ void Context::renderThread(void* context) glDrawElements(GL_TRIANGLES, cmd->m_vertex_mod_count / 4 * 6, GL_UNSIGNED_INT, 0); } - static GLsync sync; - sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - glFlush(); - glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000000); - - ReleaseSemaphore(ctx->m_semaphore_gpu[frame_index], 1, NULL); - option::Menu::instance().draw(); SwapBuffers(App.hdc); + ReleaseSemaphore(ctx->m_semaphore_gpu[frame_index], 1, NULL); if (ctx->m_limiter.active) { WaitForSingleObject(ctx->m_limiter.timer, (DWORD)ctx->m_limiter.frame_len_ms + 1); @@ -607,7 +604,6 @@ void Context::onResize(glm::uvec2 w_size, glm::uvec2 g_size, uint32_t bpp) texture_ci.min_filter = GL_LINEAR; texture_ci.mag_filter = GL_LINEAR; m_game_texture = Context::createTexture(texture_ci); - trace("bpp: %d", color_bpp); } } @@ -683,14 +679,14 @@ void Context::onStageChange() case DrawStage::UI: if (App.api == Api::Glide && (App.bloom.active || App.lut.selected)) { flushVertices(); - m_command_buffer[m_frame_index].pushCommand(CommandType::PreFx); + m_command_buffer[m_frame_index].pushCommand(CommandType::PreFx, m_current_blend_index); } break; case DrawStage::Map: if (modules::MiniMap::Instance().isActive()) { flushVertices(); m_blend_locked = true; - m_command_buffer[m_frame_index].setBlendState(3); + m_command_buffer[m_frame_index].pushCommand(CommandType::SetBlendState, 3); setVertexFlag(true, 0x08); setVertexFlag(!*d2::automap_on, 0x10); } @@ -699,7 +695,7 @@ void Context::onStageChange() if (modules::MiniMap::Instance().isActive()) { flushVertices(); m_blend_locked = false; - m_command_buffer[m_frame_index].setBlendState(m_current_blend_index); + m_command_buffer[m_frame_index].pushCommand(CommandType::SetBlendState, m_current_blend_index); setVertexFlag(false, 0x08); modules::MiniMap::Instance().draw(); @@ -719,7 +715,7 @@ void Context::setBlendState(uint32_t index) flushVertices(); m_current_blend_index = g_blend_types.at(index).first; if (!m_blend_locked) - m_command_buffer[m_frame_index].setBlendState(m_current_blend_index); + m_command_buffer[m_frame_index].pushCommand(CommandType::SetBlendState, m_current_blend_index); } void Context::beginFrame() @@ -777,6 +773,7 @@ void Context::presentFrame() m_frame.frame_times.pop_front(); m_frame.frame_times.push_back(m_frame.frame_time); + m_frame.average_frame_time = std::reduce(m_frame.frame_times.begin(), m_frame.frame_times.end()) / FRAMETIME_SAMPLE_COUNT; m_frame.frame_count++; } @@ -882,11 +879,6 @@ void Context::toggleVsync() resetFileTime(); } -const double Context::getAvgFrameTime() -{ - return std::reduce(m_frame.frame_times.begin(), m_frame.frame_times.end()) / FRAMETIME_SAMPLE_COUNT; -} - void Context::setFpsLimit(bool active, int max_fps) { m_limiter.active = active; @@ -944,45 +936,46 @@ void Context::imguiRender() void APIENTRY Context::debugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* data) { - if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) - return; - const char* source_str; const char* severity_str; // clang-format off switch (type) { - case GL_DEBUG_TYPE_ERROR: logTrace(C_RED, false, "\nError: "); break; - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: logTrace(C_YELLOW, false, "\nDeprecated behavior: "); break; - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: logTrace(C_YELLOW, false, "\nUndefined behavior: "); break; - case GL_DEBUG_TYPE_PORTABILITY: logTrace(C_BLUE, false, "\nPortability: "); break; - case GL_DEBUG_TYPE_PERFORMANCE: logTrace(C_BLUE, false, "\nPerformance: "); break; - case GL_DEBUG_TYPE_MARKER: logTrace(C_MAGENTA, false, "\nMarker: "); break; - case GL_DEBUG_TYPE_OTHER: logTrace(C_GRAY, false, "\nOther: "); break; - default: logTrace(C_RED, false, "\nUnknown: "); + case GL_DEBUG_TYPE_ERROR: logTrace(C_RED, false, "\nError: "); break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: logTrace(C_YELLOW, false, "\nDeprecated behavior: "); break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: logTrace(C_YELLOW, false, "\nUndefined behavior: "); break; + case GL_DEBUG_TYPE_PORTABILITY: logTrace(C_BLUE, false, "\nPortability: "); break; + case GL_DEBUG_TYPE_PERFORMANCE: logTrace(C_BLUE, false, "\nPerformance: "); break; + case GL_DEBUG_TYPE_MARKER: logTrace(C_MAGENTA, false, "\nMarker: "); break; + case GL_DEBUG_TYPE_OTHER: logTrace(C_GRAY, false, "\nOther: "); break; + default: logTrace(C_RED, false, "\nUnknown: "); } switch (source) { - case GL_DEBUG_SOURCE_API: source_str = "Api"; break; - case GL_DEBUG_SOURCE_WINDOW_SYSTEM: source_str = "Window system"; break; - case GL_DEBUG_SOURCE_SHADER_COMPILER: source_str = "Shader compiler"; break; - case GL_DEBUG_SOURCE_THIRD_PARTY: source_str = "Third party"; break; - case GL_DEBUG_SOURCE_APPLICATION: source_str = "Application"; break; - case GL_DEBUG_SOURCE_OTHER: source_str = "Other"; break; - default: source_str = "Unknown"; + case GL_DEBUG_SOURCE_API: source_str = "Api"; break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: source_str = "Window system"; break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: source_str = "Shader compiler"; break; + case GL_DEBUG_SOURCE_THIRD_PARTY: source_str = "Third party"; break; + case GL_DEBUG_SOURCE_APPLICATION: source_str = "Application"; break; + case GL_DEBUG_SOURCE_OTHER: source_str = "Other"; break; + default: source_str = "Unknown"; } switch (severity) { - case GL_DEBUG_SEVERITY_HIGH: severity_str = "High"; break; - case GL_DEBUG_SEVERITY_MEDIUM: severity_str = "Medium"; break; - case GL_DEBUG_SEVERITY_LOW: severity_str = "Low"; break; - case GL_DEBUG_SEVERITY_NOTIFICATION: severity_str = "Notification"; break; - default: severity_str = "Unknown"; + case GL_DEBUG_SEVERITY_HIGH: severity_str = "High"; break; + case GL_DEBUG_SEVERITY_MEDIUM: severity_str = "Medium"; break; + case GL_DEBUG_SEVERITY_LOW: severity_str = "Low"; break; + case GL_DEBUG_SEVERITY_NOTIFICATION: severity_str = "Notification"; break; + default: severity_str = "Unknown"; } // clang-format on logTrace(C_WHITE, false, "[%u / %s]: ", id, severity_str); logTrace(C_GRAY, true, "%s", source_str); trace("%s", message); + + if (App.log) + logFileWrite(0, "OpenGL: [%u / %s]: %s | %s", id, severity_str, source_str, message); } + } \ No newline at end of file diff --git a/d2gl/src/graphic/context.h b/d2gl/src/graphic/context.h index 4e738d8..8b3b234 100644 --- a/d2gl/src/graphic/context.h +++ b/d2gl/src/graphic/context.h @@ -83,6 +83,7 @@ struct FrameMetrics { double frame_time = 0.0; double prev_time = 0.0; std::deque frame_times; + double average_frame_time = 0.0; LARGE_INTEGER time = { 0 }; double frequency = 0.0; @@ -201,8 +202,8 @@ class Context { inline void setVertexOffset(glm::vec<2, uint16_t> offsets) { m_vertex_params.offsets = offsets; } inline void setVertexFlag(bool set, uint16_t flag) { m_vertex_params.flags = set ? (m_vertex_params.flags | flag) : (m_vertex_params.flags & ~flag); } - const double getAvgFrameTime(); inline const double getFrameTime() { return m_frame.frame_time; } + inline const double getAvgFrameTime() { return m_frame.average_frame_time; } inline const uint32_t getFrameCount() { return m_frame.frame_count; } inline const uint32_t getVertexCount() { return m_frame.vertex_count; } inline const uint32_t getDrawCallCount() { return m_frame.drawcall_count; } diff --git a/d2gl/src/graphic/pipeline.cpp b/d2gl/src/graphic/pipeline.cpp index 1cea075..f0ba74e 100644 --- a/d2gl/src/graphic/pipeline.cpp +++ b/d2gl/src/graphic/pipeline.cpp @@ -84,8 +84,6 @@ void Pipeline::bind(uint32_t index) if (current_program == m_id && current_blend_index == index) return; - // App.context->flushVertices();//TODO - if (current_program != m_id) { glUseProgram(m_id); current_program = m_id; diff --git a/d2gl/src/helpers.h b/d2gl/src/helpers.h index aa89e48..c66ab4f 100644 --- a/d2gl/src/helpers.h +++ b/d2gl/src/helpers.h @@ -29,6 +29,8 @@ #define DLL_D2COMMON "d2common.dll" #define DLL_D2LAUNCH "d2launch.dll" #define DLL_USER32 "user32.dll" +#define DLL_NTDLL "ntdll.dll" +#define DLL_SHCORE "shcore.dll" #define UNPACK(...) __VA_ARGS__ #define getOffset(def, v109d, v110, v111, v111b, v112, v113c, v113d, v114d) helpers::getVersionOffset({ UNPACK def }, { UNPACK v109d }, { UNPACK v110 }, { UNPACK v111 }, { UNPACK v111b }, { UNPACK v112 }, { UNPACK v113c }, { UNPACK v113d }, { UNPACK v114d }) diff --git a/d2gl/src/modules/hd_text.cpp b/d2gl/src/modules/hd_text.cpp index e2c3e02..640e95e 100644 --- a/d2gl/src/modules/hd_text.cpp +++ b/d2gl/src/modules/hd_text.cpp @@ -22,6 +22,7 @@ #include "d2/stubs.h" #include "font.h" #include "modules/mini_map.h" +#include "modules/motion_prediction.h" namespace d2gl::modules { @@ -36,7 +37,7 @@ const std::map g_font_sizes = { { 0, { 1, 10.8f, 1.14f, 1.0f, 0.115f } }, // Char name on stats panel { 4, { 1, 10.2f, 1.14f, 1.0f, 0.115f } }, // Skill tree level number 2digits { 5, { 1, 14.8f, 1.14f, 1.0f, 0.115f } }, // Menu screen copyright text - { 6, { 1, 8.8f, 1.14f, 1.0f, 0.115f } }, // All Small texts + { 6, { 1, 8.0f, 1.14f, 1.0f, 0.115f } }, // All Small texts { 8, { 1, 12.4f, 1.14f, 1.0f, 0.115f } }, // Talking Text { 12, { 1, 8.8f, 1.14f, 1.0f, 0.115f } }, // ? { 13, { 1, 11.6f, 1.14f, 1.0f, 0.090f } }, // Message, Shrine, Keybind config @@ -79,7 +80,7 @@ const std::vector g_options_texts = { { 0, { 184, 26 }, TextAlign::Right, L"AUDIO ONLY" }, { 0, { 169, 26 }, TextAlign::Right, L"TEXT ONLY" }, { 1, { 39, 36 }, TextAlign::Center, L"VIDEO OPTIONS" }, - { 0, { 175, 26 }, TextAlign::Left, L"RESOUTION" }, + { 0, { 175, 26 }, TextAlign::Left, L"RESOLUTION" }, { 0, { 135, 26 }, TextAlign::Right, L"800x600" }, { 0, { 123, 26 }, TextAlign::Right, L"640x480" }, { 1, { 9, 26 }, TextAlign::Left, L"LIGHTING QUALITY" }, @@ -169,7 +170,7 @@ bool HDText::drawText(const wchar_t* str, int x, int y, uint32_t color, uint32_t case 1: if (x == 113 || x == 385) { pos.y += isVer(V_109d) ? -5.0f : 8.0f; - if (color == 0 || color == 2) { + if (color == 0 || color == 2 || y == 155 || y == 248 || y == 341 || y == 434) { font = getFont(6); m_fonts[font.id]->setSize(font.size); m_fonts[font.id]->setMetrics(font); @@ -189,9 +190,10 @@ bool HDText::drawText(const wchar_t* str, int x, int y, uint32_t color, uint32_t static bool map_text = false; if (App.game.draw_stage == DrawStage::Map && modules::MiniMap::Instance().isActive()) { - if (m_text_size == 6 && !*d2::automap_on) - return true; - else if (m_text_size != 6) { + if (m_text_size == 6 && !*d2::automap_on) { + m_map_names = true; + return false; + } else if (m_text_size != 6) { if (*d2::screen_shift != 0) return true; @@ -238,9 +240,16 @@ bool HDText::drawFramedText(const wchar_t* str, int x, int y, uint32_t color, ui return false; const auto unit = d2::getSelectedUnit(); - if (isVerMin(V_111) && unit && unit->dwType == d2::UnitType::Monster && y == 32 && !centered) { - drawMonsterHealthBar(unit); - return true; + if (unit) { + if (unit->dwType == d2::UnitType::Monster && isVerMin(V_111) && y == 32 && !centered) { + drawMonsterHealthBar(unit); + return true; + } + + if (unit->dwType == d2::UnitType::Player || d2::isMercUnit(unit)) { + m_hovered_player_id = d2::getUnitID(unit) | ((uint8_t)unit->dwType << 24); + return false; + } } auto font = getFont(1); @@ -289,11 +298,11 @@ bool HDText::drawFramedText(const wchar_t* str, int x, int y, uint32_t color, ui const auto quality = d2::getItemQuality(item); uint32_t border_color = m_border_color; switch (quality) { - case d2::ItemQuality::Unique: border_color = 0x2b2215DD; break; - case d2::ItemQuality::Set: border_color = 0x1c3418DD; break; - case d2::ItemQuality::Rare: border_color = 0x31311eDD; break; - case d2::ItemQuality::Craft: border_color = 0x2f2102DD; break; - case d2::ItemQuality::Magic: border_color = 0x1d1d31DD; break; + case d2::ItemQuality::Unique: border_color = 0x2B2215DD; break; + case d2::ItemQuality::Set: border_color = 0x1C3418DD; break; + case d2::ItemQuality::Rare: border_color = 0x31311EDD; break; + case d2::ItemQuality::Craft: border_color = 0x2F2102DD; break; + case d2::ItemQuality::Magic: border_color = 0x1D1D31DD; break; } m_object_bg->setColor(border_color, 2); } else @@ -331,7 +340,7 @@ bool HDText::drawFramedText(const wchar_t* str, int x, int y, uint32_t color, ui return true; } -bool HDText::drawRectangledText(const wchar_t* str, int x, int y, uint32_t rect_color, uint32_t rect_transparency, uint32_t color) // TODO: remove rect_color +bool HDText::drawRectangledText(const wchar_t* str, int x, int y, uint32_t rect_transparency, uint32_t color) { if (!isActive() || !str) return false; @@ -385,7 +394,7 @@ bool HDText::drawRectangledText(const wchar_t* str, int x, int y, uint32_t rect_ bool HDText::drawSolidRect(int left, int top, int right, int bottom, uint32_t color, int draw_mode) { - if (!isActive()) + if (App.game.screen != GameScreen::InGame || !isActive()) return false; if (isVerMax(V_110)) { @@ -401,19 +410,31 @@ bool HDText::drawSolidRect(int left, int top, int right, int bottom, uint32_t co monster_hp = false; } - if (color != 0) - return false; - const int width = right - left; const int height = bottom - top; + // if (draw_mode == 1) + // trace("[] | %d | %d | %dx%d | %dx%d", color, draw_mode, left, top, width, height); + + if (height == 16 && m_hovered_player_id && m_text_size == 1) { + if (m_hovered_player_hp1 == 0) { + m_hovered_player_hp1 = width; + m_hovered_player_pos = { left, top }; + } else + m_hovered_player_hp2 = width; + return true; + } + + if (color != 0) // skip drawing except black color + return false; + if (draw_mode == 5 && height == 5 && top == 14) // hireling & summon hp return false; if (right - left == App.game.size.x || bottom - top == App.game.size.y) // FreeRes black bars return false; - if ((*d2::screen_shift == 2 || *d2::screen_shift == 3) && width == 320 && height == 432) // Plugy stats panel bg + if ((*d2::screen_shift == 2 || *d2::screen_shift == 3) && width == 320 && (height == 432 || height == 236)) // Plugy stats panel bg return false; if (draw_mode == 2 && width == 24 && height <= 24) // PD2 buff timer bg @@ -437,9 +458,6 @@ bool HDText::drawSolidRect(int left, int top, int right, int bottom, uint32_t co // draw_mode == 7 : BH setting tab bg // draw_mode == 8 : BH setting checkbox bg - // if (draw_mode == 1) - // trace("%d | %dx%d | %dx%d", draw_mode, left, top, width, height); - m_object_bg->setPosition({ (float)left, (float)top }); m_object_bg->setSize({ (float)width, (float)height }); m_object_bg->setColor(bg_color, 1); @@ -495,6 +513,11 @@ uint16_t HDText::getFontHeight() void HDText::drawSubText(uint8_t fn) { + if (m_map_names) { + m_map_names = false; + return; + } + if (!isActive() || !d2::sub_text_ptr) return; @@ -523,13 +546,19 @@ void HDText::drawSubText(uint8_t fn) y = (int*)(ptr + 0x8); } + if (m_hovered_player_id) { + drawPlayerHealthBar(str, *color); + *length = 0; + return; + } + if (str) { drawText(str, *x, *y, *color, 1); *length = 0; } } -bool HDText::drawImage(d2::CellContext* cell, int x, int y, uint32_t gamma, int draw_mode) // TODO: remove gamma +bool HDText::drawImage(d2::CellContext* cell, int x, int y, int draw_mode) { if (!isActive() || !cell) return true; @@ -593,7 +622,7 @@ bool HDText::drawImage(d2::CellContext* cell, int x, int y, uint32_t gamma, int return true; } -bool HDText::drawShiftedImage(d2::CellContext* cell, int x, int y, uint32_t gamma, int draw_mode) // TODO: remove gamma, draw_mode +bool HDText::drawShiftedImage(d2::CellContext* cell, int x, int y) { if (!isActive()) return true; @@ -755,18 +784,20 @@ void HDText::drawMonsterHealthBar(d2::UnitAny* unit) if (text_size.x + 40.0f > bar_size.x) bar_size.x = text_size.x + 40.0f; - m_object_bg->setFlags(2); glm::vec2 bar_pos = { center - bar_size.x / 2, 18.0f }; + m_object_bg->setFlags(2); m_object_bg->setPosition(bar_pos); m_object_bg->setSize({ bar_size.x * hp_percent, bar_size.y }); m_object_bg->setColor(m_monster_hp, 1); App.context->pushObject(m_object_bg); - m_object_bg->setPosition({ bar_pos.x + bar_size.x * hp_percent, bar_pos.y }); - m_object_bg->setSize({ bar_size.x * (1.0f - hp_percent), bar_size.y }); - m_object_bg->setColor(m_bg_color, 1); - App.context->pushObject(m_object_bg); + if (hp_percent < 1.0f) { + m_object_bg->setPosition({ bar_pos.x + bar_size.x * hp_percent, bar_pos.y }); + m_object_bg->setSize({ bar_size.x * (1.0f - hp_percent), bar_size.y }); + m_object_bg->setColor(m_bg_color, 1); + App.context->pushObject(m_object_bg); + } wchar_t text_color = L'\x30'; if (type == d2::MonsterType::Boss || type == d2::MonsterType::SuperUnique) @@ -780,6 +811,49 @@ void HDText::drawMonsterHealthBar(d2::UnitAny* unit) m_fonts[font.id]->drawText(name, text_pos, g_text_colors.at(text_color)); } +void HDText::drawPlayerHealthBar(const wchar_t* name, uint32_t color) +{ + const uint32_t hp = m_hovered_player_hp1; + const uint32_t max_hp = m_hovered_player_hp1 + m_hovered_player_hp2; + + auto font = getFont(1); + m_fonts[font.id]->setSize(font.size); + m_fonts[font.id]->setMetrics(font); + m_fonts[font.id]->setBoxed(false); + m_fonts[font.id]->setMasking(false); + m_fonts[font.id]->setAlign(TextAlign::Center); + + const auto text_size = m_fonts[font.id]->getTextSize(name); + float hp_percent = (float)hp / (float)max_hp; + + glm::vec2 bar_size = { 60.0f, 16.0f }; + if (text_size.x + 20.0f > bar_size.x) + bar_size.x = text_size.x + 20.0f; + + auto offset = modules::MotionPrediction::Instance().getUnitOffset(m_hovered_player_id); + const float center = (float)(m_hovered_player_pos.x + max_hp / 2) + (float)offset.x; + glm::vec2 bar_pos = { center - bar_size.x / 2, (float)m_hovered_player_pos.y + (float)offset.y }; + + m_object_bg->setFlags(2); + m_object_bg->setPosition(bar_pos); + m_object_bg->setSize({ bar_size.x * hp_percent, bar_size.y }); + m_object_bg->setColor(m_monster_hp, 1); + App.context->pushObject(m_object_bg); + + if (hp_percent < 1.0f) { + m_object_bg->setPosition({ bar_pos.x + bar_size.x * hp_percent, bar_pos.y }); + m_object_bg->setSize({ bar_size.x * (1.0f - hp_percent), bar_size.y }); + m_object_bg->setColor(m_bg_color, 1); + App.context->pushObject(m_object_bg); + } + + glm::vec2 text_pos = { center - text_size.x / 2, bar_pos.y + (App.api == Api::Glide ? 14.4f : 13.8f) }; + m_fonts[font.id]->drawText(name, text_pos, g_text_colors.at(getColor(color))); + + m_hovered_player_id = 0; + m_hovered_player_hp1 = m_hovered_player_hp2 = 0; +} + inline const D2FontInfo& HDText::getFont(uint32_t size) { return g_font_sizes.find(size) != g_font_sizes.end() ? g_font_sizes.at(size) : g_font_sizes.at(0); diff --git a/d2gl/src/modules/hd_text.h b/d2gl/src/modules/hd_text.h index f1ed281..6d41b02 100644 --- a/d2gl/src/modules/hd_text.h +++ b/d2gl/src/modules/hd_text.h @@ -49,6 +49,7 @@ class HDText { uint32_t m_last_text_height = 0; uint32_t m_last_text_width = 0; uint32_t m_map_text_line = 1; + bool m_map_names = false; bool m_bordered_rect = false; bool m_draw_sub_text = true; @@ -63,6 +64,11 @@ class HDText { clock_t m_entry_timer = 0; int m_cur_level_no = 0; + uint32_t m_hovered_player_id = 0; + uint32_t m_hovered_player_hp1 = 0; + uint32_t m_hovered_player_hp2 = 0; + glm::ivec2 m_hovered_player_pos = { 0, 0 }; + const uint32_t m_bg_color = 0x000000CC; const uint32_t m_border_color = 0x222222DD; const uint32_t m_alt_bg_color = 0x00000099; @@ -86,7 +92,7 @@ class HDText { bool drawText(const wchar_t* str, int x, int y, uint32_t color, uint32_t centered); bool drawFramedText(const wchar_t* str, int x, int y, uint32_t color, uint32_t centered); - bool drawRectangledText(const wchar_t* str, int x, int y, uint32_t rect_color, uint32_t rect_transparency, uint32_t color); + bool drawRectangledText(const wchar_t* str, int x, int y, uint32_t rect_transparency, uint32_t color); bool drawSolidRect(int left, int top, int right, int bottom, uint32_t color, int draw_mode); uint32_t getNormalTextWidth(const wchar_t* str, const int n_chars); @@ -97,8 +103,8 @@ class HDText { inline void borderedRect(bool draw = true) { m_bordered_rect = draw; } void drawSubText(uint8_t fn = 1); - bool drawImage(d2::CellContext* cell, int x, int y, uint32_t gamma, int draw_mode); - bool drawShiftedImage(d2::CellContext* cell, int x, int y, uint32_t gamma, int draw_mode); + bool drawImage(d2::CellContext* cell, int x, int y, int draw_mode); + bool drawShiftedImage(d2::CellContext* cell, int x, int y); void drawRectFrame(); void loadUIImage(); @@ -109,6 +115,7 @@ class HDText { private: void drawMonsterHealthBar(d2::UnitAny* unit); + void drawPlayerHealthBar(const wchar_t* name, uint32_t color); inline wchar_t getColor(uint32_t color); inline const D2FontInfo& getFont(uint32_t size); diff --git a/d2gl/src/modules/motion_prediction.cpp b/d2gl/src/modules/motion_prediction.cpp index 7d29a97..e8c43e1 100644 --- a/d2gl/src/modules/motion_prediction.cpp +++ b/d2gl/src/modules/motion_prediction.cpp @@ -130,6 +130,14 @@ glm::ivec2 MotionPrediction::getGlobalOffsetPerspective() return { 0, 0 }; } +glm::ivec2 MotionPrediction::getUnitOffset(uint32_t type_id) +{ + if (isActive()) + return m_units[type_id].offset; + + return { 0, 0 }; +} + glm::ivec2 MotionPrediction::drawImage(int x, int y, D2DrawFn fn, uint32_t gamma, int draw_mode) { glm::ivec2 pos = { x, y }; diff --git a/d2gl/src/modules/motion_prediction.h b/d2gl/src/modules/motion_prediction.h index 40979c7..32dd248 100644 --- a/d2gl/src/modules/motion_prediction.h +++ b/d2gl/src/modules/motion_prediction.h @@ -76,6 +76,7 @@ class MotionPrediction { glm::ivec2 getGlobalOffset(bool skip = false); glm::ivec2 getGlobalOffsetPerspective(); + glm::ivec2 getUnitOffset(uint32_t type_id); glm::ivec2 drawImage(int x, int y, D2DrawFn fn, uint32_t gamma = 0, int draw_mode = 0); glm::ivec2 drawLine(int start_x, int start_y); diff --git a/d2gl/src/option/ini.cpp b/d2gl/src/option/ini.cpp index edcbbf2..02f6828 100644 --- a/d2gl/src/option/ini.cpp +++ b/d2gl/src/option/ini.cpp @@ -194,7 +194,10 @@ void saveIni() "; Bloom effect.\n" "bloom=%s\n" "bloom_exposure=%.3f\n" - "bloom_gamma=%.3f\n\n\n"; + "bloom_gamma=%.3f\n\n" + "; Stretch viewport to window size.\n" + "stretched_horizontal=%s\n" + "stretched_vertical=%s\n\n\n"; sprintf_s(buf, graphic_setting, shader_str.c_str(), @@ -208,7 +211,9 @@ void saveIni() boolString(App.fxaa), boolString(App.bloom.active), App.bloom.exposure.value, - App.bloom.gamma.value); + App.bloom.gamma.value, + boolString(App.viewport.stretched.x), + boolString(App.viewport.stretched.y)); out_file << buf; static const char* feature_setting = @@ -233,8 +238,8 @@ void saveIni() "no_pickup=%s\n\n" "; Show FPS Counter (bottom center).\n" "show_fps=%s\n\n" - "; No Cursor Lock (cursor will not locked within window).\n" - "no_cursor_lock=%s\n\n\n"; + "; Unlock Cursor (cursor will not locked within window).\n" + "unlock_cursor=%s\n\n\n"; sprintf_s(buf, feature_setting, boolString(App.hd_cursor), @@ -249,7 +254,7 @@ void saveIni() boolString(App.skip_intro), boolString(App.no_pickup), boolString(App.show_fps), - boolString(App.cursor.no_lock)); + boolString(App.cursor.unlock)); out_file << buf; static const char* other_setting = @@ -262,9 +267,9 @@ void saveIni() "; Frame Latency (how many frames cpu generate before rendering).\n" "; Set 1-5 (increasing this value notice less frame stutter but introduces more input lag).\n" "frame_latency=%d\n\n" - "; Comma delimitered DLLs to load (early: right after attached).\n" + "; Comma-delimited DLLs to load (early: right after attached).\n" "load_dlls_early=%s\n\n" - "; Comma delimitered DLLs to load (late: right after window created).\n" + "; Comma-delimited DLLs to load (late: right after window created).\n" "load_dlls_late=%s\n"; sprintf_s(buf, other_setting, @@ -330,6 +335,9 @@ void loadIni() App.bloom.exposure.value = getFloat("Graphic", "bloom_exposure", App.bloom.exposure); App.bloom.gamma.value = getFloat("Graphic", "bloom_gamma", App.bloom.gamma); + App.viewport.stretched.x = getBool("Graphic", "stretched_horizontal", App.viewport.stretched.x); + App.viewport.stretched.y = getBool("Graphic", "stretched_vertical", App.viewport.stretched.y); + App.hd_cursor = getBool("Feature", "hd_cursor", App.hd_cursor); App.hd_text = getBool("Feature", "hd_text", App.hd_text); @@ -345,7 +353,7 @@ void loadIni() App.skip_intro = getBool("Feature", "skip_intro", App.skip_intro); App.no_pickup = getBool("Feature", "no_pickup", App.no_pickup); App.show_fps = getBool("Feature", "show_fps", App.show_fps); - App.cursor.no_lock = getBool("Feature", "no_cursor_lock", App.cursor.no_lock); + App.cursor.unlock = getBool("Feature", "unlock_cursor", App.cursor.unlock); App.gl_ver_major = getInt("Other", "gl_ver_major", App.gl_ver_major, 3, 4); App.gl_ver_minor = getInt("Other", "gl_ver_minor", App.gl_ver_minor, 0, 6); diff --git a/d2gl/src/option/menu.cpp b/d2gl/src/option/menu.cpp index e94570b..a9470fe 100644 --- a/d2gl/src/option/menu.cpp +++ b/d2gl/src/option/menu.cpp @@ -201,13 +201,13 @@ void Menu::draw() drawCombo_m("Window Size", App.resolutions, "Select window size.", "", resolutions); ImGui::Dummy({ 0.0f, 4.0f }); ImGui::BeginDisabled(App.resolutions.selected); - drawInput2("##ws", "Input custom width & height. (min: 800 x 600)", (glm::ivec2*)(&m_options.window.size_save), { 800, 600 }, { App.desktop_resolution.z, App.desktop_resolution.w }); + drawInput2("##ws", "Input custom width & height. (min: 800 x 600)", (glm::ivec2*)(&m_options.window.size_save), { 800, 600 }, { App.desktop_resolution.z, App.desktop_resolution.w }); ImGui::EndDisabled(); drawSeparator(); drawCheckbox_m("Centered Window", m_options.window.centered, "Make window centered to desktop screen.", centered_window); ImGui::Dummy({ 0.0f, 4.0f }); ImGui::BeginDisabled(m_options.window.centered); - drawInput2("##wp", "Window position from top left corner.", &m_options.window.position, { App.desktop_resolution.x, App.desktop_resolution.y }, { App.desktop_resolution.z, App.desktop_resolution.w }); + drawInput2("##wp", "Window position from top left corner.", &m_options.window.position, { App.desktop_resolution.x, App.desktop_resolution.y }, { App.desktop_resolution.z, App.desktop_resolution.w }); ImGui::EndDisabled(); ImGui::EndDisabled(); childSeparator("##w2", true); @@ -302,6 +302,14 @@ void Menu::draw() drawDescription("Bloom Gamma setting.", m_colors[Color::Gray], 12); ImGui::EndDisabled(); ImGui::EndDisabled(); + drawSeparator(); + drawLabel("Stretched Viewport", m_colors[Color::Orange]); + drawCheckbox_m("Horizontal", App.viewport.stretched.x, "", stretched_horizontal) + saveBool("Graphic", "stretched_horizontal", App.viewport.stretched.x); + ImGui::SameLine(150.0f); + drawCheckbox_m("Vertical", App.viewport.stretched.y, "", stretched_vertical) + saveBool("Graphic", "stretched_vertical", App.viewport.stretched.y); + drawDescription("Stretch viewport to window size.", m_colors[Color::Gray], 14); childEnd(); tabEnd(); } @@ -387,8 +395,8 @@ void Menu::draw() drawCheckbox_m("Show FPS", App.show_fps, "FPS Counter on bottom center.", show_fps) saveBool("Feature", "show_fps", App.show_fps); drawSeparator(); - drawCheckbox_m("No Cursor Lock", App.cursor.no_lock, "Cursor will not locked within window.", no_cursor_lock) - saveBool("Feature", "no_cursor_lock", App.cursor.no_lock); + drawCheckbox_m("Unlock Cursor", App.cursor.unlock, "Cursor will not locked within window.", unlock_cursor) + saveBool("Feature", "unlock_cursor", App.cursor.unlock); childEnd(); tabEnd(); } @@ -396,10 +404,16 @@ void Menu::draw() } ImGui::PopFont(); ImGui::SetCursorPos({ 16.0f, 460.0f }); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0.0f, 0.0f }); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f); + ImGui::BeginChildFrame(ImGui::GetID("#wiki"), { 300.0f, 24.0f }, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground); + ImGui::PopStyleVar(3); ImGui::PushFont(m_fonts[15]); if (ImGui::Button(" Open Configuration Wiki Page > ")) ShellExecute(0, 0, L"https://github.com/bayaraa/d2gl/wiki/Configuration", 0, 0, SW_SHOW); ImGui::PopFont(); + ImGui::EndChildFrame(); ImGui::End(); // clang-format on diff --git a/d2gl/src/pch.h b/d2gl/src/pch.h index 84824da..5f21516 100644 --- a/d2gl/src/pch.h +++ b/d2gl/src/pch.h @@ -23,10 +23,10 @@ #include #include -#include #include #include +#include #include #include #include diff --git a/d2gl/src/win32.cpp b/d2gl/src/win32.cpp index 20452d0..f597ebb 100644 --- a/d2gl/src/win32.cpp +++ b/d2gl/src/win32.cpp @@ -69,7 +69,7 @@ int WINAPI ShowCursor(BOOL bShow) BOOL WINAPI SetCursorPos(int X, int Y) { - if (App.hwnd && !App.cursor.no_lock) { + if (App.hwnd && !App.cursor.unlock) { POINT pt = { (LONG)((float)X * App.cursor.scale.x), (LONG)((float)Y * App.cursor.scale.y) }; pt.x += App.viewport.offset.x; pt.y += App.viewport.offset.y; @@ -252,7 +252,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (!App.cursor.locked) { setCursorLock(); - return 0; + if (!App.cursor.unlock) + return 0; } [[fallthrough]]; @@ -271,21 +272,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (option::Menu::instance().isVisible()) return DefWindowProc(hWnd, uMsg, wParam, lParam); - if (!App.cursor.no_lock && !App.cursor.locked) + if (!App.cursor.unlock && !App.cursor.locked) return 0; int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); - if (App.cursor.no_lock) { - x = (int)((float)(x - App.viewport.offset.x) * App.cursor.unscale.x); - y = (int)((float)(y - App.viewport.offset.y) * App.cursor.unscale.y); - } else { - x = (int)((float)glm::max(x - App.viewport.offset.x, 0) * App.cursor.unscale.x); - y = (int)((float)glm::max(y - App.viewport.offset.y, 0) * App.cursor.unscale.y); - x = glm::min(x, (int)App.game.size.x); - y = glm::min(y, (int)App.game.size.y); - } + x = (int)((float)glm::max(x - App.viewport.offset.x, 0) * App.cursor.unscale.x); + y = (int)((float)glm::max(y - App.viewport.offset.y, 0) * App.cursor.unscale.y); + x = glm::min(x, (int)App.game.size.x); + y = glm::min(y, (int)App.game.size.y); lParam = MAKELPARAM(x, y); @@ -401,12 +397,13 @@ void setWindowMetrics() void setCursorLock() { if (!App.cursor.locked) { - RECT rc = { App.viewport.offset.x, App.viewport.offset.y, (int)App.viewport.size.x + App.viewport.offset.x, (int)App.viewport.size.y + App.viewport.offset.y }; - MapWindowPoints(App.hwnd, NULL, (LPPOINT)&rc, 2); - - if (!App.cursor.no_lock) + if (!App.cursor.unlock) { + RECT rc = { App.viewport.offset.x, App.viewport.offset.y, (int)App.viewport.size.x + App.viewport.offset.x, (int)App.viewport.size.y + App.viewport.offset.y }; + MapWindowPoints(App.hwnd, NULL, (LPPOINT)&rc, 2); ClipCursor(&rc); - ShowCursor_Og(false); + } + + while(ShowCursor_Og(false) >= 0); App.cursor.locked = true; } } @@ -414,9 +411,12 @@ void setCursorLock() void setCursorUnlock() { if (App.cursor.locked) { - if (!App.cursor.no_lock) + if (!App.cursor.unlock) ClipCursor(NULL); - ShowCursor_Og(true); + + if (option::Menu::instance().isVisible()) + while(ShowCursor_Og(true) <= 0); + App.cursor.locked = false; } } @@ -436,7 +436,9 @@ void windowResize() void toggleDarkmode() { - static SetWindowCompositionAttribute_t SetWindowCompositionAttribute = (SetWindowCompositionAttribute_t)helpers::getProcOffset(DLL_USER32, "SetWindowCompositionAttribute"); + typedef BOOL(WINAPI* SetWindowCompositionAttribute_t)(HWND hWnd, WINDCOMPATTRDATA*); + SetWindowCompositionAttribute_t SetWindowCompositionAttribute = (SetWindowCompositionAttribute_t)helpers::getProcOffset(DLL_USER32, "SetWindowCompositionAttribute"); + if (SetWindowCompositionAttribute) { BOOL dark = (BOOL)App.window.dark_mode; WINDCOMPATTRDATA data = { WINDCOMPATTR::WCA_USEDARKMODECOLORS, &dark, sizeof(dark) }; @@ -448,4 +450,37 @@ void toggleDarkmode() } } +void setDPIAwareness() +{ + auto info = getOSVersion(); + trace_log("Windows version %d.%d (build: %d) detected.", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber); + + if (info.dwMajorVersion >= HIBYTE(_WIN32_WINNT_WIN10)) { // Win10+ + typedef BOOL(WINAPI* SetProcessDpiAwareness_t)(DPI_AWARENESS_CONTEXT); + SetProcessDpiAwareness_t SetProcessDpiAwareness = (SetProcessDpiAwareness_t)helpers::getProcOffset(DLL_USER32, "SetProcessDpiAwarenessContext"); + if (SetProcessDpiAwareness) + SetProcessDpiAwareness(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + } else if (info.dwMajorVersion == HIBYTE(_WIN32_WINNT_WINBLUE) && info.dwMinorVersion == LOBYTE(_WIN32_WINNT_WINBLUE)) { // Win8.1 + typedef HRESULT(WINAPI* SetProcessDpiAwareness_t)(PROCESS_DPI_AWARENESS); + SetProcessDpiAwareness_t SetProcessDpiAwareness = (SetProcessDpiAwareness_t)helpers::getProcOffset(DLL_SHCORE, "SetProcessDpiAwareness"); + if (SetProcessDpiAwareness) + SetProcessDpiAwareness(PROCESS_DPI_AWARENESS::PROCESS_PER_MONITOR_DPI_AWARE); + } else + SetProcessDPIAware(); +} + +RTL_OSVERSIONINFOW getOSVersion() +{ + typedef LONG NTSTATUS, *PNTSTATUS; + typedef NTSTATUS (WINAPI* RtlGetVersion_t)(PRTL_OSVERSIONINFOW); + static RtlGetVersion_t RtlGetVersion = (RtlGetVersion_t)helpers::getProcOffset(DLL_NTDLL, "RtlGetVersion"); + + RTL_OSVERSIONINFOW info = { 0 }; + info.dwOSVersionInfoSize = sizeof(info); + if (RtlGetVersion) + RtlGetVersion(&info); + + return info; +} + } \ No newline at end of file diff --git a/d2gl/src/win32.h b/d2gl/src/win32.h index 27a88af..b61fcb7 100644 --- a/d2gl/src/win32.h +++ b/d2gl/src/win32.h @@ -28,8 +28,12 @@ struct WINDCOMPATTRDATA { PVOID pvData; SIZE_T cbData; }; +enum class PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +}; -typedef BOOL(WINAPI* SetWindowCompositionAttribute_t)(HWND hWnd, WINDCOMPATTRDATA*); typedef int(WINAPI* ShowCursor_t)(BOOL bShow); typedef BOOL(WINAPI* SetCursorPos_t)(int X, int Y); typedef BOOL(WINAPI* SetWindowPos_t)(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); @@ -37,7 +41,6 @@ typedef LRESULT(WINAPI* SendMessageA_t)(HWND hWnd, UINT Msg, WPARAM wParam, LPAR typedef int(WINAPI* DrawTextA_t)(HDC hdc, LPCSTR lpchText, int cchText, LPRECT lprc, UINT format); typedef COLORREF(WINAPI* GetPixel_t)(HDC hdc, int x, int y); -extern SetWindowCompositionAttribute_t SetWindowCompositionAttribute; extern ShowCursor_t ShowCursor_Og; extern SetCursorPos_t SetCursorPos_Og; extern SetWindowPos_t SetWindowPos_Og; @@ -65,5 +68,7 @@ void setCursorLock(); void setCursorUnlock(); void windowResize(); void toggleDarkmode(); +void setDPIAwareness(); +RTL_OSVERSIONINFOW getOSVersion(); } \ No newline at end of file diff --git a/ddraw/ddraw.rc b/ddraw/ddraw.rc index 469f300..60926e2 100644 Binary files a/ddraw/ddraw.rc and b/ddraw/ddraw.rc differ diff --git a/ddraw/ddraw.vcxproj b/ddraw/ddraw.vcxproj index ffd34ad..7a376bb 100644 --- a/ddraw/ddraw.vcxproj +++ b/ddraw/ddraw.vcxproj @@ -76,7 +76,7 @@ true false $(ProjectDir)..\d2gl\vendor\lib\;%(AdditionalLibraryDirectories) - dxguid.lib;glew32s.lib;opengl32.lib;detours.lib;version.lib;winmm.lib;shcore.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + dxguid.lib;glew32s.lib;opengl32.lib;detours.lib;version.lib;winmm.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) false LIBCMT ddraw.def @@ -110,7 +110,7 @@ true false $(ProjectDir)..\d2gl\vendor\lib\;%(AdditionalLibraryDirectories) - dxguid.lib;glew32s.lib;opengl32.lib;detours.lib;version.lib;winmm.lib;shcore.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + dxguid.lib;glew32s.lib;opengl32.lib;detours.lib;version.lib;winmm.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) false LIBCMT ddraw.def diff --git a/glide3x/glide3x.rc b/glide3x/glide3x.rc index 2f77395..a4631d3 100644 Binary files a/glide3x/glide3x.rc and b/glide3x/glide3x.rc differ diff --git a/glide3x/glide3x.vcxproj b/glide3x/glide3x.vcxproj index 15583ac..685e037 100644 --- a/glide3x/glide3x.vcxproj +++ b/glide3x/glide3x.vcxproj @@ -77,7 +77,7 @@ Windows true false - glew32s.lib;opengl32.lib;detours.lib;version.lib;winmm.lib;shcore.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + glew32s.lib;opengl32.lib;detours.lib;version.lib;winmm.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) $(ProjectDir)..\d2gl\vendor\lib\;%(AdditionalLibraryDirectories) false LIBCMT @@ -112,7 +112,7 @@ true true false - glew32s.lib;opengl32.lib;detours.lib;version.lib;winmm.lib;shcore.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + glew32s.lib;opengl32.lib;detours.lib;version.lib;winmm.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) $(ProjectDir)..\d2gl\vendor\lib\;%(AdditionalLibraryDirectories) false LIBCMT