251 lines
5.9 KiB
C++
251 lines
5.9 KiB
C++
/*
|
|
* Copyright (C) 2016 Google, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* 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 <cassert>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
#include "Helpers.h"
|
|
#include "Game.h"
|
|
#include "ShellWin32.h"
|
|
|
|
namespace {
|
|
|
|
class Win32Timer {
|
|
public:
|
|
Win32Timer()
|
|
{
|
|
LARGE_INTEGER freq;
|
|
QueryPerformanceFrequency(&freq);
|
|
freq_ = static_cast<double>(freq.QuadPart);
|
|
|
|
reset();
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
QueryPerformanceCounter(&start_);
|
|
}
|
|
|
|
double get() const
|
|
{
|
|
LARGE_INTEGER now;
|
|
QueryPerformanceCounter(&now);
|
|
|
|
return static_cast<double>(now.QuadPart - start_.QuadPart) / freq_;
|
|
}
|
|
|
|
private:
|
|
double freq_;
|
|
LARGE_INTEGER start_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
ShellWin32::ShellWin32(Game &game) : Shell(game), hwnd_(nullptr)
|
|
{
|
|
instance_extensions_.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
init_vk();
|
|
}
|
|
|
|
ShellWin32::~ShellWin32()
|
|
{
|
|
cleanup_vk();
|
|
FreeLibrary(hmodule_);
|
|
}
|
|
|
|
void ShellWin32::create_window()
|
|
{
|
|
const std::string class_name(settings_.name + "WindowClass");
|
|
|
|
hinstance_ = GetModuleHandle(nullptr);
|
|
|
|
WNDCLASSEX win_class = {};
|
|
win_class.cbSize = sizeof(WNDCLASSEX);
|
|
win_class.style = CS_HREDRAW | CS_VREDRAW;
|
|
win_class.lpfnWndProc = window_proc;
|
|
win_class.hInstance = hinstance_;
|
|
win_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
win_class.lpszClassName = class_name.c_str();
|
|
RegisterClassEx(&win_class);
|
|
|
|
const DWORD win_style =
|
|
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_OVERLAPPEDWINDOW;
|
|
|
|
RECT win_rect = { 0, 0, settings_.initial_width, settings_.initial_height };
|
|
AdjustWindowRect(&win_rect, win_style, false);
|
|
|
|
hwnd_ = CreateWindowEx(WS_EX_APPWINDOW,
|
|
class_name.c_str(),
|
|
settings_.name.c_str(),
|
|
win_style,
|
|
0,
|
|
0,
|
|
win_rect.right - win_rect.left,
|
|
win_rect.bottom - win_rect.top,
|
|
nullptr,
|
|
nullptr,
|
|
hinstance_,
|
|
nullptr);
|
|
|
|
SetForegroundWindow(hwnd_);
|
|
SetWindowLongPtr(hwnd_, GWLP_USERDATA, (LONG_PTR) this);
|
|
}
|
|
|
|
PFN_vkGetInstanceProcAddr ShellWin32::load_vk()
|
|
{
|
|
const char filename[] = "vulkan-1.dll";
|
|
HMODULE mod;
|
|
PFN_vkGetInstanceProcAddr get_proc;
|
|
|
|
mod = LoadLibrary(filename);
|
|
if (mod) {
|
|
get_proc = reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetProcAddress(
|
|
mod, "vkGetInstanceProcAddr"));
|
|
}
|
|
|
|
if (!mod || !get_proc) {
|
|
std::stringstream ss;
|
|
ss << "failed to load " << filename;
|
|
|
|
if (mod)
|
|
FreeLibrary(mod);
|
|
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
|
|
hmodule_ = mod;
|
|
|
|
return get_proc;
|
|
}
|
|
|
|
bool ShellWin32::can_present(VkPhysicalDevice phy, uint32_t queue_family)
|
|
{
|
|
return vk::GetPhysicalDeviceWin32PresentationSupportKHR(
|
|
phy, queue_family) == VK_TRUE;
|
|
}
|
|
|
|
VkSurfaceKHR ShellWin32::create_surface(VkInstance instance)
|
|
{
|
|
VkWin32SurfaceCreateInfoKHR surface_info = {};
|
|
surface_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
|
surface_info.hinstance = hinstance_;
|
|
surface_info.hwnd = hwnd_;
|
|
|
|
VkSurfaceKHR surface;
|
|
vk::assert_success(vk::CreateWin32SurfaceKHR(instance, &surface_info, nullptr, &surface));
|
|
|
|
return surface;
|
|
}
|
|
|
|
LRESULT ShellWin32::handle_message(UINT msg, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
switch (msg) {
|
|
case WM_SIZE:
|
|
{
|
|
UINT w = LOWORD(lparam);
|
|
UINT h = HIWORD(lparam);
|
|
resize_swapchain(w, h);
|
|
}
|
|
break;
|
|
case WM_KEYDOWN:
|
|
{
|
|
Game::Key key;
|
|
|
|
switch (wparam) {
|
|
case VK_ESCAPE:
|
|
key = Game::KEY_ESC;
|
|
break;
|
|
case VK_UP:
|
|
key = Game::KEY_UP;
|
|
break;
|
|
case VK_DOWN:
|
|
key = Game::KEY_DOWN;
|
|
break;
|
|
case VK_SPACE:
|
|
key = Game::KEY_SPACE;
|
|
break;
|
|
default:
|
|
key = Game::KEY_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
game_.on_key(key);
|
|
}
|
|
break;
|
|
case WM_CLOSE:
|
|
game_.on_key(Game::KEY_SHUTDOWN);
|
|
break;
|
|
case WM_DESTROY:
|
|
quit();
|
|
break;
|
|
default:
|
|
return DefWindowProc(hwnd_, msg, wparam, lparam);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ShellWin32::quit()
|
|
{
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
void ShellWin32::run()
|
|
{
|
|
create_window();
|
|
|
|
create_context();
|
|
resize_swapchain(settings_.initial_width, settings_.initial_height);
|
|
|
|
Win32Timer timer;
|
|
double current_time = timer.get();
|
|
|
|
while (true) {
|
|
bool quit = false;
|
|
|
|
assert(settings_.animate);
|
|
|
|
// process all messages
|
|
MSG msg;
|
|
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
|
if (msg.message == WM_QUIT) {
|
|
quit = true;
|
|
break;
|
|
}
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (quit)
|
|
break;
|
|
|
|
acquire_back_buffer();
|
|
|
|
double t = timer.get();
|
|
add_game_time(static_cast<float>(t - current_time));
|
|
|
|
present_back_buffer();
|
|
|
|
current_time = t;
|
|
}
|
|
|
|
destroy_context();
|
|
|
|
DestroyWindow(hwnd_);
|
|
}
|