diff options
author | 2017-11-21 13:18:02 -0500 | |
---|---|---|
committer | 2017-11-21 18:37:19 +0000 | |
commit | eff04b5ec287e0fee0d44207c10d2d11f7eade8a (patch) | |
tree | ea2cf00ea329c81611536aaa9a9f1eca47c67e9a /tools/sk_app/win | |
parent | 2aa09dbe8aced37aa6bb285e62df45deb0e81650 (diff) |
Remove SampleApp and convert HelloWorld to sk_app
There is still a large amount of views code that could be trimmed down,
but which is used to implement samples (in viewer). Seemed simpler to
remove some of this code in pieces.
Bug: skia:
Change-Id: Ia3415060d03c8de604a154e3dc38379b754daab6
Reviewed-on: https://skia-review.googlesource.com/72801
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'tools/sk_app/win')
-rw-r--r-- | tools/sk_app/win/ANGLEWindowContext_win.cpp | 177 | ||||
-rw-r--r-- | tools/sk_app/win/GLWindowContext_win.cpp | 141 | ||||
-rw-r--r-- | tools/sk_app/win/RasterWindowContext_win.cpp | 100 | ||||
-rw-r--r-- | tools/sk_app/win/VulkanWindowContext_win.cpp | 79 | ||||
-rw-r--r-- | tools/sk_app/win/WindowContextFactory_win.h | 33 | ||||
-rw-r--r-- | tools/sk_app/win/Window_win.cpp | 393 | ||||
-rw-r--r-- | tools/sk_app/win/Window_win.h | 44 | ||||
-rw-r--r-- | tools/sk_app/win/main_win.cpp | 80 |
8 files changed, 1047 insertions, 0 deletions
diff --git a/tools/sk_app/win/ANGLEWindowContext_win.cpp b/tools/sk_app/win/ANGLEWindowContext_win.cpp new file mode 100644 index 0000000000..bfdff5c6f4 --- /dev/null +++ b/tools/sk_app/win/ANGLEWindowContext_win.cpp @@ -0,0 +1,177 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include "../GLWindowContext.h" +#include "WindowContextFactory_win.h" +#include "gl/GrGLAssembleInterface.h" +#include "gl/GrGLDefines.h" + +using sk_app::GLWindowContext; +using sk_app::DisplayParams; + +namespace { + +EGLDisplay get_angle_egl_display(HDC hdc) { + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; + eglGetPlatformDisplayEXT = + (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); + + // We expect ANGLE to support this extension + if (!eglGetPlatformDisplayEXT) { + return EGL_NO_DISPLAY; + } + + // We currently only support D3D11 ANGLE. + static constexpr EGLint kType = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE; + static constexpr EGLint attribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, kType, EGL_NONE}; + return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, hdc, attribs); +} + +class ANGLEGLWindowContext_win : public GLWindowContext { +public: + ANGLEGLWindowContext_win(HWND, const DisplayParams&); + ~ANGLEGLWindowContext_win() override; + +protected: + void onSwapBuffers() override; + + sk_sp<const GrGLInterface> onInitializeContext() override; + void onDestroyContext() override; + +private: + HWND fHWND; + EGLDisplay fDisplay = EGL_NO_DISPLAY; + EGLContext fContext = EGL_NO_CONTEXT; + EGLSurface fSurface = EGL_NO_SURFACE; + + typedef GLWindowContext INHERITED; +}; + +ANGLEGLWindowContext_win::ANGLEGLWindowContext_win(HWND wnd, const DisplayParams& params) + : INHERITED(params), fHWND(wnd) { + this->initializeContext(); +} + +ANGLEGLWindowContext_win::~ANGLEGLWindowContext_win() { this->destroyContext(); } + +sk_sp<const GrGLInterface> ANGLEGLWindowContext_win::onInitializeContext() { + HDC dc = GetDC(fHWND); + fDisplay = get_angle_egl_display(dc); + if (EGL_NO_DISPLAY == fDisplay) { + return nullptr; + } + + EGLint majorVersion; + EGLint minorVersion; + if (!eglInitialize(fDisplay, &majorVersion, &minorVersion)) { + SkDebugf("Could not initialize display!\n"); + return nullptr; + } + EGLint numConfigs; + fSampleCount = this->getDisplayParams().fMSAASampleCount; + const int sampleBuffers = fSampleCount > 0 ? 1 : 0; + const EGLint configAttribs[] = {EGL_RENDERABLE_TYPE, + // We currently only support ES3. + EGL_OPENGL_ES3_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_SAMPLE_BUFFERS, + sampleBuffers, + EGL_SAMPLES, + fSampleCount, + EGL_NONE}; + + EGLConfig surfaceConfig; + if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) { + SkDebugf("Could not create choose config!\n"); + return nullptr; + } + // We currently only support ES3. + const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; + fContext = eglCreateContext(fDisplay, surfaceConfig, nullptr, contextAttribs); + if (EGL_NO_CONTEXT == fContext) { + SkDebugf("Could not create context!\n"); + return nullptr; + } + fSurface = eglCreateWindowSurface(fDisplay, surfaceConfig, fHWND, nullptr); + if (EGL_NO_SURFACE == fSurface) { + SkDebugf("Could not create surface!\n"); + return nullptr; + } + if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { + SkDebugf("Could not make contxt current!\n"); + return nullptr; + } + + sk_sp<const GrGLInterface> interface(GrGLAssembleInterface( + nullptr, + [](void* ctx, const char name[]) -> GrGLFuncPtr { return eglGetProcAddress(name); })); + if (interface) { + interface->fFunctions.fClearStencil(0); + interface->fFunctions.fClearColor(0, 0, 0, 0); + interface->fFunctions.fStencilMask(0xffffffff); + interface->fFunctions.fClear(GR_GL_STENCIL_BUFFER_BIT | GR_GL_COLOR_BUFFER_BIT); + + // use DescribePixelFormat to get the stencil depth. + int pixelFormat = GetPixelFormat(dc); + PIXELFORMATDESCRIPTOR pfd; + DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd); + fStencilBits = pfd.cStencilBits; + + RECT rect; + GetClientRect(fHWND, &rect); + fWidth = rect.right - rect.left; + fHeight = rect.bottom - rect.top; + interface->fFunctions.fViewport(0, 0, fWidth, fHeight); + } + return interface; +} + +void ANGLEGLWindowContext_win::onDestroyContext() { + eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (EGL_NO_CONTEXT != fContext) { + eglDestroyContext(fDisplay, fContext); + } + if (EGL_NO_SURFACE != fSurface) { + eglDestroySurface(fDisplay, fSurface); + } + if (EGL_NO_DISPLAY != fDisplay) { + eglTerminate(fDisplay); + } +} + +void ANGLEGLWindowContext_win::onSwapBuffers() { + if (!eglSwapBuffers(fDisplay, fSurface)) { + SkDebugf("Could not complete eglSwapBuffers.\n"); + } +} + +} // anonymous namespace + +namespace sk_app { +namespace window_context_factory { + +WindowContext* NewANGLEForWin(HWND wnd, const DisplayParams& params) { + ANGLEGLWindowContext_win* ctx = new ANGLEGLWindowContext_win(wnd, params); + if (!ctx->isValid()) { + delete ctx; + return nullptr; + } + return ctx; +} + +} // namespace window_context_factory +} // namespace sk_app diff --git a/tools/sk_app/win/GLWindowContext_win.cpp b/tools/sk_app/win/GLWindowContext_win.cpp new file mode 100644 index 0000000000..17a6b32962 --- /dev/null +++ b/tools/sk_app/win/GLWindowContext_win.cpp @@ -0,0 +1,141 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <Windows.h> +#include <GL/gl.h> +#include "../GLWindowContext.h" +#include "GrGLInterface.h" +#include "WindowContextFactory_win.h" +#include "win/SkWGL.h" + +using sk_app::GLWindowContext; +using sk_app::DisplayParams; + +namespace { + +class GLWindowContext_win : public GLWindowContext { +public: + GLWindowContext_win(HWND, const DisplayParams&); + ~GLWindowContext_win() override; + +protected: + void onSwapBuffers() override; + + sk_sp<const GrGLInterface> onInitializeContext() override; + void onDestroyContext() override; + +private: + HWND fHWND; + HGLRC fHGLRC; + + typedef GLWindowContext INHERITED; +}; + +GLWindowContext_win::GLWindowContext_win(HWND wnd, const DisplayParams& params) + : INHERITED(params) + , fHWND(wnd) + , fHGLRC(NULL) { + + // any config code here (particularly for msaa)? + + this->initializeContext(); +} + +GLWindowContext_win::~GLWindowContext_win() { + this->destroyContext(); +} + +sk_sp<const GrGLInterface> GLWindowContext_win::onInitializeContext() { + HDC dc = GetDC(fHWND); + + fHGLRC = SkCreateWGLContext(dc, fDisplayParams.fMSAASampleCount, false /* deepColor */, + kGLPreferCompatibilityProfile_SkWGLContextRequest); + if (NULL == fHGLRC) { + return nullptr; + } + + // Look to see if RenderDoc is attached. If so, re-create the context with a core profile + if (wglMakeCurrent(dc, fHGLRC)) { + const GrGLInterface* glInterface = GrGLCreateNativeInterface(); + bool renderDocAttached = glInterface->hasExtension("GL_EXT_debug_tool"); + SkSafeUnref(glInterface); + if (renderDocAttached) { + wglDeleteContext(fHGLRC); + fHGLRC = SkCreateWGLContext(dc, fDisplayParams.fMSAASampleCount, false /* deepColor */, + kGLPreferCoreProfile_SkWGLContextRequest); + if (NULL == fHGLRC) { + return nullptr; + } + } + } + + if (wglMakeCurrent(dc, fHGLRC)) { + glClearStencil(0); + glClearColor(0, 0, 0, 0); + glStencilMask(0xffffffff); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // use DescribePixelFormat to get the stencil and color bit depth. + int pixelFormat = GetPixelFormat(dc); + PIXELFORMATDESCRIPTOR pfd; + DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd); + fStencilBits = pfd.cStencilBits; + + // Get sample count if the MSAA WGL extension is present + SkWGLExtensions extensions; + if (extensions.hasExtension(dc, "WGL_ARB_multisample")) { + static const int kSampleCountAttr = SK_WGL_SAMPLES; + extensions.getPixelFormatAttribiv(dc, + pixelFormat, + 0, + 1, + &kSampleCountAttr, + &fSampleCount); + } else { + fSampleCount = 0; + } + + RECT rect; + GetClientRect(fHWND, &rect); + fWidth = rect.right - rect.left; + fHeight = rect.bottom - rect.top; + glViewport(0, 0, fWidth, fHeight); + } + return sk_sp<const GrGLInterface>(GrGLCreateNativeInterface()); +} + + +void GLWindowContext_win::onDestroyContext() { + wglDeleteContext(fHGLRC); + fHGLRC = NULL; +} + + +void GLWindowContext_win::onSwapBuffers() { + HDC dc = GetDC((HWND)fHWND); + SwapBuffers(dc); + ReleaseDC((HWND)fHWND, dc); +} + + +} // anonymous namespace + +namespace sk_app { +namespace window_context_factory { + +WindowContext* NewGLForWin(HWND wnd, const DisplayParams& params) { + GLWindowContext_win* ctx = new GLWindowContext_win(wnd, params); + if (!ctx->isValid()) { + delete ctx; + return nullptr; + } + return ctx; +} + +} // namespace window_context_factory +} // namespace sk_app diff --git a/tools/sk_app/win/RasterWindowContext_win.cpp b/tools/sk_app/win/RasterWindowContext_win.cpp new file mode 100644 index 0000000000..85bb65e674 --- /dev/null +++ b/tools/sk_app/win/RasterWindowContext_win.cpp @@ -0,0 +1,100 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "../RasterWindowContext.h" +#include "SkAutoMalloc.h" +#include "SkSurface.h" +#include "WindowContextFactory_win.h" + +#include <Windows.h> + +using sk_app::RasterWindowContext; +using sk_app::DisplayParams; + +namespace { + +class RasterWindowContext_win : public RasterWindowContext { +public: + RasterWindowContext_win(HWND, const DisplayParams&); + + sk_sp<SkSurface> getBackbufferSurface() override; + void swapBuffers() override; + bool isValid() override { return SkToBool(fWnd); } + void resize(int w, int h) override; + void setDisplayParams(const DisplayParams& params) override; + +protected: + SkAutoMalloc fSurfaceMemory; + sk_sp<SkSurface> fBackbufferSurface; + HWND fWnd; + +private: + typedef RasterWindowContext INHERITED; +}; + +RasterWindowContext_win::RasterWindowContext_win(HWND wnd, const DisplayParams& params) + : INHERITED(params) + , fWnd(wnd) { + RECT rect; + GetWindowRect(wnd, &rect); + this->resize(rect.right - rect.left, rect.bottom - rect.top); +} + +void RasterWindowContext_win::setDisplayParams(const DisplayParams& params) { + fDisplayParams = params; + RECT rect; + GetWindowRect(fWnd, &rect); + this->resize(rect.right - rect.left, rect.bottom - rect.top); +} + +void RasterWindowContext_win::resize(int w, int h) { + fWidth = w; + fHeight = h; + fBackbufferSurface.reset(); + const size_t bmpSize = sizeof(BITMAPINFOHEADER) + w * h * sizeof(uint32_t); + fSurfaceMemory.reset(bmpSize); + BITMAPINFO* bmpInfo = reinterpret_cast<BITMAPINFO*>(fSurfaceMemory.get()); + ZeroMemory(bmpInfo, sizeof(BITMAPINFO)); + bmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmpInfo->bmiHeader.biWidth = w; + bmpInfo->bmiHeader.biHeight = -h; // negative means top-down bitmap. Skia draws top-down. + bmpInfo->bmiHeader.biPlanes = 1; + bmpInfo->bmiHeader.biBitCount = 32; + bmpInfo->bmiHeader.biCompression = BI_RGB; + void* pixels = bmpInfo->bmiColors; + + SkImageInfo info = SkImageInfo::Make(w, h, fDisplayParams.fColorType, kPremul_SkAlphaType, + fDisplayParams.fColorSpace); + fBackbufferSurface = SkSurface::MakeRasterDirect(info, pixels, sizeof(uint32_t) * w); +} + +sk_sp<SkSurface> RasterWindowContext_win::getBackbufferSurface() { return fBackbufferSurface; } + +void RasterWindowContext_win::swapBuffers() { + BITMAPINFO* bmpInfo = reinterpret_cast<BITMAPINFO*>(fSurfaceMemory.get()); + HDC dc = GetDC(fWnd); + StretchDIBits(dc, 0, 0, fWidth, fHeight, 0, 0, fWidth, fHeight, bmpInfo->bmiColors, bmpInfo, + DIB_RGB_COLORS, SRCCOPY); + ReleaseDC(fWnd, dc); +} + +} // anonymous namespace + +namespace sk_app { +namespace window_context_factory { + +WindowContext* NewRasterForWin(HWND wnd, const DisplayParams& params) { + WindowContext* ctx = new RasterWindowContext_win(wnd, params); + if (!ctx->isValid()) { + delete ctx; + ctx = nullptr; + } + return ctx; +} + +} // namespace window_context_factory +} // namespace sk_app diff --git a/tools/sk_app/win/VulkanWindowContext_win.cpp b/tools/sk_app/win/VulkanWindowContext_win.cpp new file mode 100644 index 0000000000..16c527cba0 --- /dev/null +++ b/tools/sk_app/win/VulkanWindowContext_win.cpp @@ -0,0 +1,79 @@ + +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <Windows.h> +#include "WindowContextFactory_win.h" + +#include "../VulkanWindowContext.h" +#include "Window_win.h" + +#include "vk/GrVkInterface.h" +#include "vk/GrVkUtil.h" + +#include "vk/VkTestUtils.h" + +namespace sk_app { +namespace window_context_factory { + +WindowContext* NewVulkanForWin(HWND hwnd, const DisplayParams& params) { + PFN_vkGetInstanceProcAddr instProc; + PFN_vkGetDeviceProcAddr devProc; + if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) { + return nullptr; + } + + auto createVkSurface = [hwnd, instProc] (VkInstance instance) -> VkSurfaceKHR { + static PFN_vkCreateWin32SurfaceKHR createWin32SurfaceKHR = nullptr; + if (!createWin32SurfaceKHR) { + createWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) + instProc(instance, "vkCreateWin32SurfaceKHR"); + } + HINSTANCE hinstance = GetModuleHandle(0); + VkSurfaceKHR surface; + + VkWin32SurfaceCreateInfoKHR surfaceCreateInfo; + memset(&surfaceCreateInfo, 0, sizeof(VkWin32SurfaceCreateInfoKHR)); + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + surfaceCreateInfo.pNext = nullptr; + surfaceCreateInfo.flags = 0; + surfaceCreateInfo.hinstance = hinstance; + surfaceCreateInfo.hwnd = hwnd; + + VkResult res = createWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface); + if (VK_SUCCESS != res) { + return VK_NULL_HANDLE; + } + + return surface; + }; + + auto canPresent = [instProc] (VkInstance instance, VkPhysicalDevice physDev, + uint32_t queueFamilyIndex) { + static PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR + getPhysicalDeviceWin32PresentationSupportKHR = nullptr; + if (!getPhysicalDeviceWin32PresentationSupportKHR) { + getPhysicalDeviceWin32PresentationSupportKHR = + (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) + instProc(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); + } + + VkBool32 check = getPhysicalDeviceWin32PresentationSupportKHR(physDev, queueFamilyIndex); + return (VK_FALSE != check); + }; + + WindowContext* ctx = new VulkanWindowContext(params, createVkSurface, canPresent, + instProc, devProc); + if (!ctx->isValid()) { + delete ctx; + return nullptr; + } + return ctx; +} + +} // namespace window_context_factory +} // namespace sk_app diff --git a/tools/sk_app/win/WindowContextFactory_win.h b/tools/sk_app/win/WindowContextFactory_win.h new file mode 100644 index 0000000000..959b529f49 --- /dev/null +++ b/tools/sk_app/win/WindowContextFactory_win.h @@ -0,0 +1,33 @@ + +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef WindowContextFactory_win_DEFINED +#define WindowContextFactory_win_DEFINED + +#include <Windows.h> + +namespace sk_app { + +class WindowContext; +struct DisplayParams; + +namespace window_context_factory { + +WindowContext* NewVulkanForWin(HWND, const DisplayParams&); + +WindowContext* NewGLForWin(HWND, const DisplayParams&); + +WindowContext* NewANGLEForWin(HWND, const DisplayParams&); + +WindowContext* NewRasterForWin(HWND, const DisplayParams&); + +} // namespace window_context_factory + +} // namespace sk_app + +#endif diff --git a/tools/sk_app/win/Window_win.cpp b/tools/sk_app/win/Window_win.cpp new file mode 100644 index 0000000000..10db0ec675 --- /dev/null +++ b/tools/sk_app/win/Window_win.cpp @@ -0,0 +1,393 @@ +/* +* Copyright 2016 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include "Window_win.h" + +#include <tchar.h> +#include <windows.h> +#include <windowsx.h> + +#include "SkUtils.h" +#include "../WindowContext.h" +#include "WindowContextFactory_win.h" +#ifdef SK_VULKAN +#include "../VulkanWindowContext.h" +#endif + +namespace sk_app { + +static int gWindowX = CW_USEDEFAULT; +static int gWindowY = 0; +static int gWindowWidth = CW_USEDEFAULT; +static int gWindowHeight = 0; + +Window* Window::CreateNativeWindow(void* platformData) { + HINSTANCE hInstance = (HINSTANCE)platformData; + + Window_win* window = new Window_win(); + if (!window->init(hInstance)) { + delete window; + return nullptr; + } + + return window; +} + +void Window_win::closeWindow() { + RECT r; + if (GetWindowRect(fHWnd, &r)) { + gWindowX = r.left; + gWindowY = r.top; + gWindowWidth = r.right - r.left; + gWindowHeight = r.bottom - r.top; + } + DestroyWindow(fHWnd); +} + +Window_win::~Window_win() { + this->closeWindow(); +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + + +bool Window_win::init(HINSTANCE hInstance) { + fHInstance = hInstance ? hInstance : GetModuleHandle(nullptr); + + // The main window class name + static const TCHAR gSZWindowClass[] = _T("SkiaApp"); + + static WNDCLASSEX wcex; + static bool wcexInit = false; + if (!wcexInit) { + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = fHInstance; + wcex.hIcon = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO); + wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);; + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wcex.lpszMenuName = nullptr; + wcex.lpszClassName = gSZWindowClass; + wcex.hIconSm = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO);; + + if (!RegisterClassEx(&wcex)) { + return false; + } + wcexInit = true; + } + + /* + if (fullscreen) + { + DEVMODE dmScreenSettings; + // If full screen set the screen to maximum size of the users desktop and 32bit. + memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); + dmScreenSettings.dmSize = sizeof(dmScreenSettings); + dmScreenSettings.dmPelsWidth = (unsigned long)width; + dmScreenSettings.dmPelsHeight = (unsigned long)height; + dmScreenSettings.dmBitsPerPel = 32; + dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + + // Change the display settings to full screen. + ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); + + // Set the position of the window to the top left corner. + posX = posY = 0; + } + */ + // gIsFullscreen = fullscreen; + + fHWnd = CreateWindow(gSZWindowClass, nullptr, WS_OVERLAPPEDWINDOW, + gWindowX, gWindowY, gWindowWidth, gWindowHeight, + nullptr, nullptr, fHInstance, nullptr); + if (!fHWnd) + { + return false; + } + + SetWindowLongPtr(fHWnd, GWLP_USERDATA, (LONG_PTR)this); + RegisterTouchWindow(fHWnd, 0); + + return true; +} + +static Window::Key get_key(WPARAM vk) { + static const struct { + WPARAM fVK; + Window::Key fKey; + } gPair[] = { + { VK_BACK, Window::Key::kBack }, + { VK_CLEAR, Window::Key::kBack }, + { VK_RETURN, Window::Key::kOK }, + { VK_UP, Window::Key::kUp }, + { VK_DOWN, Window::Key::kDown }, + { VK_LEFT, Window::Key::kLeft }, + { VK_RIGHT, Window::Key::kRight }, + { VK_TAB, Window::Key::kTab }, + { VK_PRIOR, Window::Key::kPageUp }, + { VK_NEXT, Window::Key::kPageDown }, + { VK_HOME, Window::Key::kHome }, + { VK_END, Window::Key::kEnd }, + { VK_DELETE, Window::Key::kDelete }, + { VK_ESCAPE, Window::Key::kEscape }, + { VK_SHIFT, Window::Key::kShift }, + { VK_CONTROL, Window::Key::kCtrl }, + { VK_MENU, Window::Key::kOption }, + { 'A', Window::Key::kA }, + { 'C', Window::Key::kC }, + { 'V', Window::Key::kV }, + { 'X', Window::Key::kX }, + { 'Y', Window::Key::kY }, + { 'Z', Window::Key::kZ }, + }; + for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { + if (gPair[i].fVK == vk) { + return gPair[i].fKey; + } + } + return Window::Key::kNONE; +} + +static uint32_t get_modifiers(UINT message, WPARAM wParam, LPARAM lParam) { + uint32_t modifiers = 0; + + switch (message) { + case WM_UNICHAR: + case WM_CHAR: + if (0 == (lParam & (1 << 30))) { + modifiers |= Window::kFirstPress_ModifierKey; + } + if (lParam & (1 << 29)) { + modifiers |= Window::kOption_ModifierKey; + } + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (0 == (lParam & (1 << 30))) { + modifiers |= Window::kFirstPress_ModifierKey; + } + if (lParam & (1 << 29)) { + modifiers |= Window::kOption_ModifierKey; + } + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + if (lParam & (1 << 29)) { + modifiers |= Window::kOption_ModifierKey; + } + break; + + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: + if (wParam & MK_CONTROL) { + modifiers |= Window::kControl_ModifierKey; + } + if (wParam & MK_SHIFT) { + modifiers |= Window::kShift_ModifierKey; + } + break; + } + + return modifiers; +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HDC hdc; + + Window_win* window = (Window_win*) GetWindowLongPtr(hWnd, GWLP_USERDATA); + + bool eventHandled = false; + + switch (message) { + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + window->onPaint(); + EndPaint(hWnd, &ps); + eventHandled = true; + break; + + case WM_CLOSE: + PostQuitMessage(0); + eventHandled = true; + break; + + case WM_ACTIVATE: + // disable/enable rendering here, depending on wParam != WA_INACTIVE + break; + + case WM_SIZE: + window->onResize(LOWORD(lParam), HIWORD(lParam)); + eventHandled = true; + break; + + case WM_UNICHAR: + eventHandled = window->onChar((SkUnichar)wParam, + get_modifiers(message, wParam, lParam)); + break; + + case WM_CHAR: { + const uint16_t* c = reinterpret_cast<uint16_t*>(&wParam); + eventHandled = window->onChar(SkUTF16_NextUnichar(&c), + get_modifiers(message, wParam, lParam)); + } break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + eventHandled = window->onKey(get_key(wParam), Window::kDown_InputState, + get_modifiers(message, wParam, lParam)); + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + eventHandled = window->onKey(get_key(wParam), Window::kUp_InputState, + get_modifiers(message, wParam, lParam)); + break; + + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: { + int xPos = GET_X_LPARAM(lParam); + int yPos = GET_Y_LPARAM(lParam); + + //if (!gIsFullscreen) + //{ + // RECT rc = { 0, 0, 640, 480 }; + // AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + // xPos -= rc.left; + // yPos -= rc.top; + //} + + Window::InputState istate = ((wParam & MK_LBUTTON) != 0) ? Window::kDown_InputState + : Window::kUp_InputState; + + eventHandled = window->onMouse(xPos, yPos, istate, + get_modifiers(message, wParam, lParam)); + } break; + + case WM_MOUSEMOVE: { + int xPos = GET_X_LPARAM(lParam); + int yPos = GET_Y_LPARAM(lParam); + + //if (!gIsFullscreen) + //{ + // RECT rc = { 0, 0, 640, 480 }; + // AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + // xPos -= rc.left; + // yPos -= rc.top; + //} + + eventHandled = window->onMouse(xPos, yPos, Window::kMove_InputState, + get_modifiers(message, wParam, lParam)); + } break; + + case WM_MOUSEWHEEL: + eventHandled = window->onMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f, + get_modifiers(message, wParam, lParam)); + break; + + case WM_TOUCH: { + uint16_t numInputs = LOWORD(wParam); + std::unique_ptr<TOUCHINPUT[]> inputs(new TOUCHINPUT[numInputs]); + if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, inputs.get(), + sizeof(TOUCHINPUT))) { + RECT rect; + GetClientRect(hWnd, &rect); + for (uint16_t i = 0; i < numInputs; ++i) { + TOUCHINPUT ti = inputs[i]; + Window::InputState state; + if (ti.dwFlags & TOUCHEVENTF_DOWN) { + state = Window::kDown_InputState; + } else if (ti.dwFlags & TOUCHEVENTF_MOVE) { + state = Window::kMove_InputState; + } else if (ti.dwFlags & TOUCHEVENTF_UP) { + state = Window::kUp_InputState; + } else { + continue; + } + // TOUCHINPUT coordinates are in 100ths of pixels + // Adjust for that, and make them window relative + LONG tx = (ti.x / 100) - rect.left; + LONG ty = (ti.y / 100) - rect.top; + eventHandled = window->onTouch(ti.dwID, state, tx, ty) || eventHandled; + } + } + } break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return eventHandled ? 0 : 1; +} + +void Window_win::setTitle(const char* title) { + SetWindowTextA(fHWnd, title); +} + +void Window_win::show() { + ShowWindow(fHWnd, SW_SHOW); +} + + +bool Window_win::attach(BackendType attachType) { + fBackend = attachType; + + switch (attachType) { + case kNativeGL_BackendType: + fWindowContext = window_context_factory::NewGLForWin(fHWnd, fRequestedDisplayParams); + break; +#if SK_ANGLE + case kANGLE_BackendType: + fWindowContext = window_context_factory::NewANGLEForWin(fHWnd, fRequestedDisplayParams); + break; +#endif + case kRaster_BackendType: + fWindowContext = window_context_factory::NewRasterForWin(fHWnd, + fRequestedDisplayParams); + break; +#ifdef SK_VULKAN + case kVulkan_BackendType: + fWindowContext = window_context_factory::NewVulkanForWin(fHWnd, + fRequestedDisplayParams); + break; +#endif + } + this->onBackendCreated(); + + return (SkToBool(fWindowContext)); +} + +void Window_win::onInval() { + InvalidateRect(fHWnd, nullptr, false); +} + +void Window_win::setRequestedDisplayParams(const DisplayParams& params, bool allowReattach) { + // GL on Windows doesn't let us change MSAA after the window is created + if (params.fMSAASampleCount != this->getRequestedDisplayParams().fMSAASampleCount + && allowReattach) { + // Need to change these early, so attach() creates the window context correctly + fRequestedDisplayParams = params; + + delete fWindowContext; + this->closeWindow(); + this->init(fHInstance); + this->attach(fBackend); + } + + INHERITED::setRequestedDisplayParams(params, allowReattach); +} + +} // namespace sk_app diff --git a/tools/sk_app/win/Window_win.h b/tools/sk_app/win/Window_win.h new file mode 100644 index 0000000000..139ab874c6 --- /dev/null +++ b/tools/sk_app/win/Window_win.h @@ -0,0 +1,44 @@ +/* +* Copyright 2016 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#ifndef Window_win_DEFINED +#define Window_win_DEFINED + +#include <windows.h> +#include "../Window.h" + +namespace sk_app { + +class Window_win : public Window { +public: + Window_win() : Window() {} + ~Window_win() override; + + bool init(HINSTANCE instance); + + void setTitle(const char*) override; + void show() override; + + bool attach(BackendType) override; + + void onInval() override; + + void setRequestedDisplayParams(const DisplayParams&, bool allowReattach) override; + +private: + void closeWindow(); + + HINSTANCE fHInstance; + HWND fHWnd; + BackendType fBackend; + + typedef Window INHERITED; +}; + +} // namespace sk_app + +#endif diff --git a/tools/sk_app/win/main_win.cpp b/tools/sk_app/win/main_win.cpp new file mode 100644 index 0000000000..4800258973 --- /dev/null +++ b/tools/sk_app/win/main_win.cpp @@ -0,0 +1,80 @@ +/* +* Copyright 2016 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include <windows.h> +#include <tchar.h> + +#include "SkTypes.h" +#include "Timer.h" +#include "Window_win.h" +#include "../Application.h" + +using sk_app::Application; + +static char* tchar_to_utf8(const TCHAR* str) { +#ifdef _UNICODE + int size = WideCharToMultiByte(CP_UTF8, 0, str, wcslen(str), NULL, 0, NULL, NULL); + char* str8 = (char*)sk_malloc_throw(size + 1); + WideCharToMultiByte(CP_UTF8, 0, str, wcslen(str), str8, size, NULL, NULL); + str8[size] = '\0'; + return str8; +#else + return _strdup(str); +#endif +} + +// This file can work with GUI or CONSOLE subsystem types since we define _tWinMain and main(). + +static int main_common(HINSTANCE hInstance, int show, int argc, char**argv); + +int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, + int nCmdShow) { + + // convert from lpCmdLine to argc, argv. + char* argv[4096]; + int argc = 0; + TCHAR exename[1024], *next; + int exenameLen = GetModuleFileName(NULL, exename, SK_ARRAY_COUNT(exename)); + // we're ignoring the possibility that the exe name exceeds the exename buffer + (void)exenameLen; + argv[argc++] = tchar_to_utf8(exename); + TCHAR* arg = _tcstok_s(lpCmdLine, _T(" "), &next); + while (arg != NULL) { + argv[argc++] = tchar_to_utf8(arg); + arg = _tcstok_s(NULL, _T(" "), &next); + } + int result = main_common(hInstance, nCmdShow, argc, argv); + for (int i = 0; i < argc; ++i) { + sk_free(argv[i]); + } + return result; +} + +int main(int argc, char**argv) { + return main_common(GetModuleHandle(NULL), SW_SHOW, argc, argv); +} + +static int main_common(HINSTANCE hInstance, int show, int argc, char**argv) { + + Application* app = Application::Create(argc, argv, (void*)hInstance); + + MSG msg = { 0 }; + + // Main message loop + while (WM_QUIT != msg.message) { + if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + app->onIdle(); + } + } + + delete app; + + return (int)msg.wParam; +} |