From 7a3239ee1b07e87e28fd9c3161e984e854b0122e Mon Sep 17 00:00:00 2001 From: Dom Chen Date: Fri, 15 Dec 2023 00:34:26 +0800 Subject: [PATCH] Add the windows demo. (#76) * Add the windows demo. * Update README.md. --- .github/workflows/build.yml | 2 +- README.md | 89 +++---- .../fileTemplates/includes/TGFX File Header.h | 17 ++ .../fileTemplates/internal/C Header File.h | 7 + .../fileTemplates/internal/C Source File.c | 8 + .../fileTemplates/internal/C++ Class Header.h | 9 + qt/.idea/fileTemplates/internal/C++ Class.cc | 7 + src/opengl/egl/EGLWindow.cpp | 14 +- .../fileTemplates/includes/TGFX File Header.h | 17 ++ .../fileTemplates/internal/C Header File.h | 7 + .../fileTemplates/internal/C Source File.c | 8 + .../fileTemplates/internal/C++ Class Header.h | 9 + win/.idea/fileTemplates/internal/C++ Class.cc | 7 + win/.idea/misc.xml | 4 + win/CMakeLists.txt | 50 ++++ win/app.rc | 1 + win/images/tgfx.ico | Bin 0 -> 12237 bytes win/src/TGFXWindow.cpp | 235 ++++++++++++++++++ win/src/TGFXWindow.h | 58 +++++ win/src/main.cpp | 48 ++++ 20 files changed, 551 insertions(+), 46 deletions(-) create mode 100644 qt/.idea/fileTemplates/includes/TGFX File Header.h create mode 100644 qt/.idea/fileTemplates/internal/C Header File.h create mode 100644 qt/.idea/fileTemplates/internal/C Source File.c create mode 100644 qt/.idea/fileTemplates/internal/C++ Class Header.h create mode 100644 qt/.idea/fileTemplates/internal/C++ Class.cc create mode 100644 win/.idea/fileTemplates/includes/TGFX File Header.h create mode 100644 win/.idea/fileTemplates/internal/C Header File.h create mode 100644 win/.idea/fileTemplates/internal/C Source File.c create mode 100644 win/.idea/fileTemplates/internal/C++ Class Header.h create mode 100644 win/.idea/fileTemplates/internal/C++ Class.cc create mode 100644 win/.idea/misc.xml create mode 100644 win/CMakeLists.txt create mode 100644 win/app.rc create mode 100644 win/images/tgfx.ico create mode 100644 win/src/TGFXWindow.cpp create mode 100644 win/src/TGFXWindow.h create mode 100644 win/src/main.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8d72e80..d170ed4c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -240,7 +240,7 @@ jobs: - name: Build Windows run: | - node build_tgfx -a x64 + node build_tgfx -s ./win Hello2D -o ./out/release/win -a x64 - name: Save Third-Party Cache if: ${{ (github.event_name == 'push') && (steps.third-party-cache.outputs.cache-hit != 'true') }} diff --git a/README.md b/README.md index f9edd1f2..f04515bb 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ provided above in the [**Build Prerequisites**](#build-prerequisites) and [**Dependencies**](#dependencies) sections. They will guide you through the necessary steps to configure your development environment. -### Android Demo +### Android The android demo project requires the **Android NDK**. We recommend using the **19.2.5345600** version, which has been fully tested with the tgfx library. If you open the project with Android @@ -146,7 +146,7 @@ please search for a solution on Google. However, if you believe the problem is a project configuration, you can open an [Issue](https://github.com/Tencent/tgfx/issues/new/choose) to address it. -### iOS Demo +### iOS Run the following command in the `ios/` directory or double-click on it: @@ -178,7 +178,7 @@ generate a project with webp encoding support, please run the following command: Finally, open XCode and launch the `ios/Hello2D.xcworkspace` to build and run the demo project. -### macOS Demo +### macOS Run the following command in the `mac/` directory or double-click on it: @@ -204,7 +204,7 @@ a project with freetype support, please run the following command: At last, launch XCode and open the `mac/Hello2D.xcworkspace`. You'll be ready to go! -### Web Demo +### Web The web demo project requires the **Emscripten SDK**. You can download and install it from the [official website](https://emscripten.org/). We recommend using the **3.1.20** version, @@ -251,25 +251,62 @@ npm run build:debug With these steps completed, you will be able to debug C++ files directly within Chrome DevTools. +To build the demo project in CLion, please Open the `Settings` panel in CLion and go to +`Build, Execution, Deployment` > `CMake`. Create a new build target. And then set the `CMake options` +to the following value: + +``` +DCMAKE_TOOLCHAIN_FILE="path/to/emscripten/emscripten/version/cmake/Modules/Platform/Emscripten.cmake" +``` + +Once you have created the build target, make sure to adjust the `Configurations` accordingly to +align with the newly created build target. By doing so, you will gain the ability to build the tgfx +library in CLion. + Additionally, please note that when using `ESModule` for your project, it is necessary to manually pack the generated `.wasm` file into the final web program. This is because common packing tools usually ignore the `.wasm` file. Moreover, remember to upload the `.wasm` file to a server, enabling users to access it from the network. -### QT Demo +### Windows + +To start, open the `win/` directory in CLion. Next, open the `File->Setting` panel and navigate to +`Build, Execution, Deployment->ToolChains`. Set the toolchain of CLion to `Visual Studio` with either +`amd64` (Recommended) or `x86` architecture. Once done, you'll be able to build and run the `Hello2D` +target. + +If you prefer to use the VS Studio IDE, you can open the `x64 Native Tools Command Prompt for VS 2019` +and execute the following command in the `win/` directory: + +``` +cmake -G "Visual Studio 16 2019" -A x64 -B ./build-x64 +``` + +This will generate a project for the `x64` architecture. If you want to generate a project for the +`x86` architecture, open the `x86 Native Tools Command Prompt for VS 2019` and run the following +command instead: + +``` +cmake -G "Visual Studio 16 2019" -A Win32 -B ./build-x86 +``` + +Finally, go to the `build-x64/` or `build-x86/` directory and open the `Hello2D.sln` file. You'll be +ready to go! -For **macOS** users, to begin, please open the `qt/` folder in CLion. Then, navigate to the -`qt/QTCMAKE.cfg` file to modify the QT path with your local QT installation path. Once done, you can -proceed to build and run the `Hello2D` target. +### QT -For Windows users, ensure that the ToolChain of CLion is set to Visual Studio with `amd64` +For **macOS** users, just open the `qt/` directory in CLion. Then, navigate to the `qt/QTCMAKE.cfg` +file to modify the QT path with your local QT installation path. Once done, you can proceed to build +and run the `Hello2D` target. + +For **Windows** users, ensure that the ToolChain of CLion is set to `Visual Studio` with `amd64` architecture. Then, navigate to the `qt/` folder in CLion and find the `qt/QTCMAKE.cfg` file. Modify the QT path to match your local QT installation path. Afterward, access the configuration panel of the `Hello2D` target in CLion. Enter the local QT DLL library path in the `Environment Variables` row, e.g., `PATH=C:\Qt\6.6.1\msvc2019_64\bin`. Finally, you're ready to build and run the `Hello2D` target. -## Build TGFX +## Build Library Aside from directly integrating the source code of tgfx into your project, you also have the option of linking with the precompiled libraries. TGFX utilizes the [**vendor_tools**](https://github.com/libpag/vendor_tools) @@ -313,38 +350,6 @@ To access more details and options, execute the command along with the `-h [--he node build_tgfx -h ``` -## Development - -We recommend using the [**CLion**](https://www.jetbrains.com/clion/) IDE on the macOS platform for -development. After synchronizing with `depsync`, there are a few configurations that need to be set -up before opening the project in CLion. - -### macOS - -No additional configurations of CLion are necessary. **Please note that currently, the unit test -targets for tgfx can only be accessed on macOS**. - -### Windows - -Open the **File->Setting** panel, and go to **Build, Execution, Deployment->ToolChains**, then set -the toolchain of CLion to **Visual Studio** with **amd64 (Recommended)** or **x86** architecture. - -### Web - -If you wish to target the web platform, you'll need to install the **Emscripten SDK** and follow -these steps: - -- Open the `Settings` panel in CLion and go to `Build, Execution, Deployment` > `CMake`. Create a new build target. -- Set the `CMake options` to the following value: - -``` -DCMAKE_TOOLCHAIN_FILE="path/to/emscripten/emscripten/version/cmake/Modules/Platform/Emscripten.cmake" -``` - -- After creating the build target, modify the `Configurations` located before the `Run / Debug` buttons to match the newly created build target. - -Once you've completed these steps, you'll have the ability to build the tgfx library and conduct debugging in CLion. - ## Contribution diff --git a/qt/.idea/fileTemplates/includes/TGFX File Header.h b/qt/.idea/fileTemplates/includes/TGFX File Header.h new file mode 100644 index 00000000..9a045aca --- /dev/null +++ b/qt/.idea/fileTemplates/includes/TGFX File Header.h @@ -0,0 +1,17 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/qt/.idea/fileTemplates/internal/C Header File.h b/qt/.idea/fileTemplates/internal/C Header File.h new file mode 100644 index 00000000..d7f0678b --- /dev/null +++ b/qt/.idea/fileTemplates/internal/C Header File.h @@ -0,0 +1,7 @@ +#parse("TGFX File Header.h") + +#pragma once + +namespace tgfx { + +} // namespace tgfx diff --git a/qt/.idea/fileTemplates/internal/C Source File.c b/qt/.idea/fileTemplates/internal/C Source File.c new file mode 100644 index 00000000..1df3e1b3 --- /dev/null +++ b/qt/.idea/fileTemplates/internal/C Source File.c @@ -0,0 +1,8 @@ +#parse("TGFX File Header.h") +#if (${HEADER_FILENAME}) +#[[#include]]# "${HEADER_FILENAME}" +#end + +namespace tgfx { + +} // namespace tgfx \ No newline at end of file diff --git a/qt/.idea/fileTemplates/internal/C++ Class Header.h b/qt/.idea/fileTemplates/internal/C++ Class Header.h new file mode 100644 index 00000000..e1c28ff0 --- /dev/null +++ b/qt/.idea/fileTemplates/internal/C++ Class Header.h @@ -0,0 +1,9 @@ +#parse("TGFX File Header.h") + +#pragma once + +namespace tgfx { +class ${NAME} { + public: +}; +} // namespace tgfx diff --git a/qt/.idea/fileTemplates/internal/C++ Class.cc b/qt/.idea/fileTemplates/internal/C++ Class.cc new file mode 100644 index 00000000..6df4f00d --- /dev/null +++ b/qt/.idea/fileTemplates/internal/C++ Class.cc @@ -0,0 +1,7 @@ +#parse("TGFX File Header.h") + +#[[#include]]# "${HEADER_FILENAME}" + +namespace tgfx { + +} // namespace tgfx diff --git a/src/opengl/egl/EGLWindow.cpp b/src/opengl/egl/EGLWindow.cpp index ed421256..2b6eb586 100644 --- a/src/opengl/egl/EGLWindow.cpp +++ b/src/opengl/egl/EGLWindow.cpp @@ -20,6 +20,8 @@ #if defined(__ANDROID__) || defined(ANDROID) #include +#elif defined(_WIN32) +#include #endif #include #include @@ -55,13 +57,19 @@ std::shared_ptr EGLWindow::onCreateSurface(Context* context) { EGLint width = 0; EGLint height = 0; - // If the rendering size changes,eglQuerySurface based on ANativeWindow may give the wrong size. -#if defined(__ANDROID__) || defined(ANDROID) if (nativeWindow) { + // If the rendering size changes,eglQuerySurface() may give the wrong size on same platforms. +#if defined(__ANDROID__) || defined(ANDROID) width = ANativeWindow_getWidth(nativeWindow); height = ANativeWindow_getHeight(nativeWindow); - } +#elif defined(_WIN32) + RECT rect; + GetClientRect(nativeWindow, &rect); + width = static_cast(rect.right - rect.left); + height = static_cast(rect.bottom - rect.top); #endif + } + if (width <= 0 || height <= 0) { auto eglDevice = static_cast(device.get()); eglQuerySurface(eglDevice->eglDisplay, eglDevice->eglSurface, EGL_WIDTH, &width); diff --git a/win/.idea/fileTemplates/includes/TGFX File Header.h b/win/.idea/fileTemplates/includes/TGFX File Header.h new file mode 100644 index 00000000..9a045aca --- /dev/null +++ b/win/.idea/fileTemplates/includes/TGFX File Header.h @@ -0,0 +1,17 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/win/.idea/fileTemplates/internal/C Header File.h b/win/.idea/fileTemplates/internal/C Header File.h new file mode 100644 index 00000000..d7f0678b --- /dev/null +++ b/win/.idea/fileTemplates/internal/C Header File.h @@ -0,0 +1,7 @@ +#parse("TGFX File Header.h") + +#pragma once + +namespace tgfx { + +} // namespace tgfx diff --git a/win/.idea/fileTemplates/internal/C Source File.c b/win/.idea/fileTemplates/internal/C Source File.c new file mode 100644 index 00000000..1df3e1b3 --- /dev/null +++ b/win/.idea/fileTemplates/internal/C Source File.c @@ -0,0 +1,8 @@ +#parse("TGFX File Header.h") +#if (${HEADER_FILENAME}) +#[[#include]]# "${HEADER_FILENAME}" +#end + +namespace tgfx { + +} // namespace tgfx \ No newline at end of file diff --git a/win/.idea/fileTemplates/internal/C++ Class Header.h b/win/.idea/fileTemplates/internal/C++ Class Header.h new file mode 100644 index 00000000..e1c28ff0 --- /dev/null +++ b/win/.idea/fileTemplates/internal/C++ Class Header.h @@ -0,0 +1,9 @@ +#parse("TGFX File Header.h") + +#pragma once + +namespace tgfx { +class ${NAME} { + public: +}; +} // namespace tgfx diff --git a/win/.idea/fileTemplates/internal/C++ Class.cc b/win/.idea/fileTemplates/internal/C++ Class.cc new file mode 100644 index 00000000..6df4f00d --- /dev/null +++ b/win/.idea/fileTemplates/internal/C++ Class.cc @@ -0,0 +1,7 @@ +#parse("TGFX File Header.h") + +#[[#include]]# "${HEADER_FILENAME}" + +namespace tgfx { + +} // namespace tgfx diff --git a/win/.idea/misc.xml b/win/.idea/misc.xml new file mode 100644 index 00000000..f1c67dfa --- /dev/null +++ b/win/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/win/CMakeLists.txt b/win/CMakeLists.txt new file mode 100644 index 00000000..9c28d840 --- /dev/null +++ b/win/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.13) +project(Hello2D) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif () + +if (MSVC) + add_compile_options("/utf-8") + string(TOLOWER ${MSVC_C_ARCHITECTURE_ID} ARCH) +endif (MSVC) + +if (CMAKE_BUILD_TYPE MATCHES "Debug") + add_definitions(-DDEBUG) +else () + add_definitions(-DNDEBUG) +endif () + +add_definitions(-DNOMINMAX -D_USE_MATH_DEFINES -DWIN32 -D_WINDOWS -D_CRT_SECURE_NO_WARNINGS) +find_library(Bcrypt_LIB Bcrypt) +list(APPEND HELLO_2D_LIBS ${Bcrypt_LIB}) +find_library(ws2_32_LIB ws2_32) +list(APPEND HELLO_2D_LIBS ${ws2_32_LIB}) +find_library(SHCORE_LIB SHCore) +list(APPEND HELLO_2D_LIBS ${SHCORE_LIB}) +file(GLOB ANGLE_LIBS ../vendor/angle/win/${ARCH}/*${CMAKE_STATIC_LIBRARY_SUFFIX}) +list(APPEND HELLO_2D_LIBS ${ANGLE_LIBS}) +list(APPEND HELLO_2D_INCLUDES ../vendor/angle/include) + +file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/libEGL.dll) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../vendor/angle/win/${ARCH}/libEGL.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/libGLESv2.dll) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../vendor/angle/win/${ARCH}/libGLESv2.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +if (ARCH STREQUAL "x86") + file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/zlib.dll) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../vendor/angle/win/${ARCH}/zlib.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +endif () + +set(TGFX_BUILD_DRAWERS ON) + +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ ./tgfx) + +file(GLOB_RECURSE HELLO_2D_SOURCE_FILES src/*.*) +add_executable(Hello2D WIN32 ${HELLO_2D_SOURCE_FILES} app.rc) +target_include_directories(Hello2D PRIVATE ${HELLO_2D_INCLUDES} src) +target_link_libraries(Hello2D tgfx-drawers tgfx ${HELLO_2D_LIBS}) \ No newline at end of file diff --git a/win/app.rc b/win/app.rc new file mode 100644 index 00000000..99441720 --- /dev/null +++ b/win/app.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "images/tgfx.ico" \ No newline at end of file diff --git a/win/images/tgfx.ico b/win/images/tgfx.ico new file mode 100644 index 0000000000000000000000000000000000000000..3d233ce90c92bc34d58173ccc9c875da074ccd01 GIT binary patch literal 12237 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 IvU&dh0Zo?QM*si- literal 0 HcmV?d00001 diff --git a/win/src/TGFXWindow.cpp b/win/src/TGFXWindow.cpp new file mode 100644 index 00000000..acc9e78a --- /dev/null +++ b/win/src/TGFXWindow.cpp @@ -0,0 +1,235 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "TGFXWindow.h" +#include +#include + +namespace hello2d { +static constexpr LPCWSTR ClassName = L"TGFXWindow"; + +TGFXWindow::TGFXWindow() { + createAppHost(); +} + +TGFXWindow::~TGFXWindow() { + destroy(); +} + +bool TGFXWindow::open() { + destroy(); + WNDCLASS windowClass = RegisterWindowClass(); + auto pixelRatio = getPixelRatio(); + int initWidth = static_cast(pixelRatio * 800); + int initHeight = static_cast(pixelRatio * 600); + windowHandle = + CreateWindowEx(WS_EX_APPWINDOW, windowClass.lpszClassName, L"Hello2D", WS_OVERLAPPEDWINDOW, 0, + 0, initWidth, initHeight, nullptr, nullptr, windowClass.hInstance, this); + + if (windowHandle == nullptr) { + return false; + } + SetWindowLongPtr(windowHandle, GWLP_USERDATA, reinterpret_cast(this)); + centerAndShow(); + return true; +} + +WNDCLASS TGFXWindow::RegisterWindowClass() { + auto hInstance = GetModuleHandle(nullptr); + WNDCLASS windowClass{}; + windowClass.hCursor = LoadCursor(nullptr, IDC_ARROW); + windowClass.lpszClassName = ClassName; + windowClass.style = CS_HREDRAW | CS_VREDRAW; + windowClass.cbClsExtra = 0; + windowClass.cbWndExtra = 0; + windowClass.hInstance = hInstance; + windowClass.hIcon = LoadIcon(hInstance, L"IDI_ICON1"); + windowClass.hbrBackground = nullptr; + windowClass.lpszMenuName = nullptr; + windowClass.lpfnWndProc = WndProc; + RegisterClass(&windowClass); + return windowClass; +} + +LRESULT CALLBACK TGFXWindow::WndProc(HWND window, UINT message, WPARAM wparam, + LPARAM lparam) noexcept { + auto tgfxWindow = reinterpret_cast(GetWindowLongPtr(window, GWLP_USERDATA)); + if (tgfxWindow != nullptr) { + return tgfxWindow->handleMessage(window, message, wparam, lparam); + } + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT TGFXWindow::handleMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) noexcept { + LRESULT result = 0; + switch (message) { + case WM_DESTROY: + destroy(); + PostQuitMessage(0); + break; + case WM_PAINT: + draw(); + break; + case WM_LBUTTONDOWN: + lastDrawIndex++; + ::InvalidateRect(windowHandle, nullptr, TRUE); + break; + default: + result = DefWindowProc(windowHandle, message, wparam, lparam); + break; + } + return result; +} + +void TGFXWindow::destroy() { + if (windowHandle) { + DestroyWindow(windowHandle); + windowHandle = nullptr; + UnregisterClass(ClassName, nullptr); + } +} + +void TGFXWindow::centerAndShow() { + if ((GetWindowStyle(windowHandle) & WS_CHILD) != 0) { + return; + } + RECT rcDlg = {0}; + ::GetWindowRect(windowHandle, &rcDlg); + RECT rcArea = {0}; + RECT rcCenter = {0}; + HWND hWnd = windowHandle; + HWND hWndCenter = ::GetWindowOwner(windowHandle); + if (hWndCenter != nullptr) { + hWnd = hWndCenter; + } + + MONITORINFO oMonitor = {}; + oMonitor.cbSize = sizeof(oMonitor); + ::GetMonitorInfo(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &oMonitor); + rcArea = oMonitor.rcWork; + + if (hWndCenter == nullptr) { + rcCenter = rcArea; + } else { + ::GetWindowRect(hWndCenter, &rcCenter); + } + + int DlgWidth = rcDlg.right - rcDlg.left; + int DlgHeight = rcDlg.bottom - rcDlg.top; + + // Find dialog's upper left based on rcCenter + int xLeft = (rcCenter.left + rcCenter.right) / 2 - DlgWidth / 2; + int yTop = (rcCenter.top + rcCenter.bottom) / 2 - DlgHeight / 2; + + // The dialog is outside the screen, move it inside + if (xLeft < rcArea.left) { + if (xLeft < 0) { + xLeft = GetSystemMetrics(SM_CXSCREEN) / 2 - DlgWidth / 2; + } else { + xLeft = rcArea.left; + } + } else if (xLeft + DlgWidth > rcArea.right) { + xLeft = rcArea.right - DlgWidth; + } + + if (yTop < rcArea.top) { + if (yTop < 0) { + yTop = GetSystemMetrics(SM_CYSCREEN) / 2 - DlgHeight / 2; + } else { + yTop = rcArea.top; + } + + } else if (yTop + DlgHeight > rcArea.bottom) { + yTop = rcArea.bottom - DlgHeight; + } + ::SetWindowPos(windowHandle, nullptr, xLeft, yTop, -1, -1, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW); +} + +float TGFXWindow::getPixelRatio() { + UINT dpi = 96; + if (windowHandle != nullptr) { + auto monitor = ::MonitorFromWindow(windowHandle, MONITOR_DEFAULTTONEAREST); + UINT dpiX = 96; + UINT dpiY = 96; + GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + dpi = dpiX; + } else { + dpi = GetDpiForSystem(); + } + return static_cast(dpi) / 96.0f; +} + +void TGFXWindow::createAppHost() { + appHost = std::make_unique(); + std::filesystem::path filePath = __FILE__; + auto rootPath = filePath.parent_path().parent_path().parent_path().string(); + auto imagePath = rootPath + R"(\resources\assets\bridge.jpg)"; + auto image = tgfx::Image::MakeFromFile(imagePath); + appHost->addImage("bridge", image); + auto typeface = tgfx::Typeface::MakeFromName("Microsoft YaHei", ""); + appHost->addTypeface("default", typeface); + typeface = tgfx::Typeface::MakeFromName("Segoe UI Emoji", ""); + appHost->addTypeface("emoji", typeface); +} + +void TGFXWindow::draw() { + if (!tgfxWindow) { + tgfxWindow = tgfx::EGLWindow::MakeFrom(windowHandle); + } + if (tgfxWindow == nullptr) { + return; + } + RECT rect; + GetClientRect(windowHandle, &rect); + auto width = static_cast(rect.right - rect.left); + auto height = static_cast(rect.bottom - rect.top); + auto pixelRatio = getPixelRatio(); + auto sizeChanged = appHost->updateScreen(width, height, pixelRatio); + if (sizeChanged) { + tgfxWindow->invalidSize(); + } + auto device = tgfxWindow->getDevice(); + if (device == nullptr) { + return; + } + auto context = device->lockContext(); + if (context == nullptr) { + return; + } + auto surface = tgfxWindow->getSurface(context); + if (surface == nullptr) { + device->unlock(); + return; + } + auto canvas = surface->getCanvas(); + canvas->clear(); + canvas->save(); + auto numDrawers = drawers::Drawer::Count() - 1; + auto index = (lastDrawIndex % numDrawers) + 1; + auto drawer = drawers::Drawer::GetByName("GridBackground"); + drawer->draw(canvas, appHost.get()); + drawer = drawers::Drawer::GetByIndex(index); + drawer->draw(canvas, appHost.get()); + canvas->restore(); + surface->flush(); + context->submit(); + tgfxWindow->present(context); + device->unlock(); +} +} // namespace hello2d \ No newline at end of file diff --git a/win/src/TGFXWindow.h b/win/src/TGFXWindow.h new file mode 100644 index 00000000..1a6e9f45 --- /dev/null +++ b/win/src/TGFXWindow.h @@ -0,0 +1,58 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifndef UNICODE +#define UNICODE +#endif + +#include +#include +#include +#include +#include +#include "drawers/Drawer.h" +#include "tgfx/opengl/egl/EGLWindow.h" + +namespace hello2d { +class TGFXWindow { + public: + TGFXWindow(); + virtual ~TGFXWindow(); + + bool open(); + + private: + HWND windowHandle = nullptr; + int lastDrawIndex = 0; + std::shared_ptr tgfxWindow = nullptr; + std::shared_ptr appHost = nullptr; + + static WNDCLASS RegisterWindowClass(); + static LRESULT CALLBACK WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept; + + LRESULT handleMessage(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept; + + void destroy(); + void centerAndShow(); + float getPixelRatio(); + void createAppHost(); + void draw(); +}; +} // namespace hello2d diff --git a/win/src/main.cpp b/win/src/main.cpp new file mode 100644 index 00000000..192e52f9 --- /dev/null +++ b/win/src/main.cpp @@ -0,0 +1,48 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef UNICODE +#define UNICODE +#endif + +#include +#include "TGFXWindow.h" + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { +#if WINVER >= 0x0603 // Windows 8.1 + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); +#else + SetProcessDPIAware(); +#endif + + hello2d::TGFXWindow tgfxWindow = {}; + tgfxWindow.open(); + + MSG msg = {}; + while (GetMessage(&msg, nullptr, 0, 0) > 0) { + if (msg.message == WM_QUIT) { + return (int)msg.wParam; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; +} \ No newline at end of file