diff options
Diffstat (limited to 'src/vke.cpp')
| -rw-r--r-- | src/vke.cpp | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/src/vke.cpp b/src/vke.cpp new file mode 100644 index 0000000..6e3ed3a --- /dev/null +++ b/src/vke.cpp @@ -0,0 +1,591 @@ +/* +* Vulkan Example base class, stripped down version +* +* Copyright (C) 2016-2018 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#define TINYGLTF_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#include "tiny_gltf.h" + +#include "vke.hpp" +#include "macros.hpp" + +#define ENGINE_NAME "vke" +#define ENGINE_VERSION 1 + +#include "VulkanDevice.hpp" + +#include "resource.hpp" +#include "buffer.hpp" +#include "texture.hpp" + +#include "shadingcontext.hpp" +#include "rendertarget.hpp" + +#include "VulkanSwapChain.hpp" +#include "camera.hpp" + +int32_t nextValuePair(std::stringstream *stream) +{ + std::string pair; + *stream >> pair; + uint32_t spos = pair.find("="); + std::string value = pair.substr(spos + 1); + int32_t val = std::stoi(value); + return val; +} +// Basic parser fpr AngelCode bitmap font format files +// See http://www.angelcode.com/products/bmfont/doc/file_format.html for details +std::array<bmchar, 255> parsebmFont(const std::string& fileName) +{ + std::array<bmchar, 255> fontChars; + +#if defined(__ANDROID__) + // Font description file is stored inside the apk + // So we need to load it using the asset manager + AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, fileName.c_str(), AASSET_MODE_STREAMING); + assert(asset); + size_t size = AAsset_getLength(asset); + + assert(size > 0); + + void *fileData = malloc(size); + AAsset_read(asset, fileData, size); + AAsset_close(asset); + + std::stringbuf sbuf((const char*)fileData); + std::istream istream(&sbuf); +#else + std::filebuf fileBuffer; + fileBuffer.open(fileName, std::ios::in); + std::istream istream(&fileBuffer); +#endif + + assert(istream.good()); + + while (!istream.eof()) + { + std::string line; + std::stringstream lineStream; + std::getline(istream, line); + lineStream << line; + + std::string info; + lineStream >> info; + + if (info == "char") + { + // char id + uint32_t charid = nextValuePair(&lineStream); + // Char properties + fontChars[charid].x = nextValuePair(&lineStream); + fontChars[charid].y = nextValuePair(&lineStream); + fontChars[charid].width = nextValuePair(&lineStream); + fontChars[charid].height = nextValuePair(&lineStream); + fontChars[charid].xoffset = nextValuePair(&lineStream); + fontChars[charid].yoffset = nextValuePair(&lineStream); + fontChars[charid].xadvance = nextValuePair(&lineStream); + fontChars[charid].page = nextValuePair(&lineStream); + } + } + return fontChars; +} + +std::vector<const char*> vke::engine_t::args; + +VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char * pLayerPrefix, const char * pMsg, void * pUserData) +{ + std::string prefix(""); + if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { + prefix += "ERROR:"; + }; + if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { + prefix += "WARNING:"; + }; + if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { + prefix += "DEBUG:"; + } + std::stringstream debugMessage; + debugMessage << prefix << " [" << pLayerPrefix << "] Code " << msgCode << " : " << pMsg; +#if defined(__ANDROID__) + LOGD("%s", debugMessage.str().c_str()); +#else + std::cout << debugMessage.str() << "\n"; +#endif + fflush(stdout); + return VK_FALSE; +} + +std::string vke::engine_t::getWindowTitle() +{ + std::string device(this->device->properties.deviceName); + std::string windowTitle; + windowTitle = title + " - " + device + " - " + std::to_string(lastFPS) + " fps"; + return windowTitle; +} + +static void onkey_callback (GLFWwindow* window, int key, int scanCode, int action ,int mods){ + vke::engine_t* e = (vke::engine_t*)glfwGetWindowUserPointer(window); + if (action == GLFW_PRESS) + e->keyDown(key); + else + e->keyUp(key); +} +static void char_callback (GLFWwindow* window, uint32_t c){ + vke::engine_t* e = (vke::engine_t*)glfwGetWindowUserPointer(window); +} +static void mouse_move_callback(GLFWwindow* window, double x, double y){ + vke::engine_t* e = (vke::engine_t*)glfwGetWindowUserPointer(window); + e->handleMouseMove((int32_t)x, (int32_t)y); +} +static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){ + vke::engine_t* e = (vke::engine_t*)glfwGetWindowUserPointer(window); + if (state == GLFW_PRESS){ + e->mouseButtons[but] = true; + e->handleMouseButtonDown(but); + }else{ + e->mouseButtons[but] = false; + e->handleMouseButtonUp(but); + } +} + +vke::engine_t::engine_t (uint32_t _width, uint32_t _height, + VkPhysicalDeviceType preferedGPU) +{ + width = _width; + height = _height; + + char* numConvPtr; + // Parse command line arguments + for (size_t i = 0; i < args.size(); i++) + { + if (args[i] == std::string("-validation")) { + settings.validation = true; + } + if (args[i] == std::string("-vsync")) { + settings.vsync = true; + } + if ((args[i] == std::string("-f")) || (args[i] == std::string("--fullscreen"))) { + settings.fullscreen = true; + } + if ((args[i] == std::string("-w")) || (args[i] == std::string("--width"))) { + uint32_t w = strtol(args[i + 1], &numConvPtr, 10); + if (numConvPtr != args[i + 1]) { width = w; }; + } + if ((args[i] == std::string("-h")) || (args[i] == std::string("--height"))) { + uint32_t h = strtol(args[i + 1], &numConvPtr, 10); + if (numConvPtr != args[i + 1]) { height = h; }; + } + } + + glfwInit(); + assert (glfwVulkanSupported()==GLFW_TRUE); + + uint32_t enabledExtsCount = 0, phyCount = 0; + const char ** enabledExts = glfwGetRequiredInstanceExtensions (&enabledExtsCount); + std::vector<const char*> enabledExtentions; + enabledExtentions.assign(enabledExts, enabledExts + enabledExtsCount); + + _createInstance ("vkChess", enabledExtentions); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); + glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); + + window = glfwCreateWindow (width, height, "Window Title", NULL, NULL); + + glfwSetWindowUserPointer (window, this); + + glfwSetKeyCallback (window, onkey_callback); + glfwSetCharCallback (window, char_callback); + glfwSetMouseButtonCallback (window, mouse_button_callback); + glfwSetCursorPosCallback (window, mouse_move_callback); + //glfwSetScrollCallback (e->window, onScroll); + + VK_CHECK_RESULT(glfwCreateWindowSurface(instance, window, NULL, &surface)); + + VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &phyCount, nullptr)); + assert(phyCount > 0); + std::vector<VkPhysicalDevice> physicalDevices(phyCount); + VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &phyCount, physicalDevices.data())); + + for (uint i=0; i<phyCount; i++){ + phyInfos = new vke::vkPhyInfo(physicalDevices[i], surface); + if (phyInfos->properties.deviceType == preferedGPU) + break; + } + + camera = new Camera(); +} + + +vke::engine_t::~engine_t() +{ + delete sharedUBOs.matrices; + delete sharedUBOs.params; + delete phyInfos; + delete camera; + + delete renderTarget; + delete swapChain; + + if (surface != VK_NULL_HANDLE) + vkDestroySurfaceKHR(instance, surface, nullptr); + + surface = VK_NULL_HANDLE; + + delete device; + + //if (settings.validation) + // vkDestroyDebugReportCallback(instance, debugReportCallback, nullptr); + + vkDestroyInstance (instance, VK_NULL_HANDLE); +} + +void vke::engine_t::start () { + std::vector<const char*> devLayers; + +#if DEBUG + if (settings.validation) + devLayers.push_back ("VK_LAYER_LUNARG_standard_validation"); +#endif + + device = new vke::device_t (phyInfos, devLayers); + + swapChain = new swap_chain_t (this, false); + swapChain->create (width, height); + + renderTarget = new render_target_t(device, settings.sampleCount); + renderTarget->createDefaultPresentableTarget (swapChain); + + prepareUniformBuffers(); + + prepare(); + + prepared = true; + + while (!glfwWindowShouldClose (window)) { + glfwPollEvents(); + auto tStart = std::chrono::high_resolution_clock::now(); + if (viewUpdated) + { + viewUpdated = false; + viewChanged(); + } + + render(); + + frameCounter++; + auto tEnd = std::chrono::high_resolution_clock::now(); + auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); + frameTimer = tDiff / 1000.0f; + camera->update(frameTimer); + if (camera->moving()) + viewUpdated = true; + fpsTimer += (float)tDiff; + if (fpsTimer > 1000.0f) + { + glfwSetWindowTitle(window, getWindowTitle().c_str()); + lastFPS = (float)frameCounter * (1000.0f / fpsTimer); + fpsTimer = 0.0f; + frameCounter = 0; + } + } +} + +void vke::engine_t::prepare(){} + +void vke::engine_t::prepareFrame() +{ + VkResult err = swapChain->acquireNextImage (device->dev); + if ((err == VK_ERROR_OUT_OF_DATE_KHR) || (err == VK_SUBOPTIMAL_KHR)) { + windowResize(); + } else { + VK_CHECK_RESULT(err); + } +} + +void vke::engine_t::_createInstance (const std::string& app_name, std::vector<const char*>& extentions) { + VkApplicationInfo infos = {VK_STRUCTURE_TYPE_APPLICATION_INFO}; + infos.pApplicationName = app_name.c_str(); + infos.applicationVersion= 1; + infos.pEngineName = ENGINE_NAME; + infos.engineVersion = ENGINE_VERSION; + infos.apiVersion = VK_API_VERSION_1_0; + + + std::vector<const char*> enabledLayers; + +#if DEBUG + if (settings.validation) + enabledLayers.push_back ("VK_LAYER_LUNARG_standard_validation"); +#endif + + VkInstanceCreateInfo inst_info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; + inst_info.pApplicationInfo = &infos; + inst_info.enabledExtensionCount = extentions.size(); + inst_info.ppEnabledExtensionNames = extentions.data(); + inst_info.enabledLayerCount = enabledLayers.size(); + inst_info.ppEnabledLayerNames = enabledLayers.data(); + + VK_CHECK_RESULT(vkCreateInstance (&inst_info, NULL, &instance)); + +} + + +//void vks::VkEngine::handleEvent(const xcb_generic_event_t *event) +//{ +// switch (event->response_type & 0x7f) +// { +// case XCB_CLIENT_MESSAGE: +// if ((*(xcb_client_message_event_t*)event).data.data32[0] == +// (*atom_wm_delete_window).atom) { +// quit = true; +// } +// break; +// case XCB_MOTION_NOTIFY: +// { +// xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)event; +// handleMouseMove((int32_t)motion->event_x, (int32_t)motion->event_y); +// break; +// } +// break; +// case XCB_BUTTON_PRESS: +// { +// xcb_button_press_event_t *press = (xcb_button_press_event_t *)event; +// switch (press->detail) { +// case XCB_BUTTON_INDEX_1: +// mouseButtons.left = true; +// break; +// case XCB_BUTTON_INDEX_2: +// mouseButtons.middle = true; +// break; +// case XCB_BUTTON_INDEX_3: +// mouseButtons.right = true; +// break; +// case XCB_BUTTON_INDEX_4://wheel scroll up +// camera.translate(glm::vec3(0.0f, 0.0f, camera.zoomSpeed)); +// viewUpdated = true; +// break; +// case XCB_BUTTON_INDEX_5://wheel scroll down +// camera.translate(glm::vec3(0.0f, 0.0f, -camera.zoomSpeed)); +// viewUpdated = true; +// break; +// } +// handleMouseButtonDown(press->detail); +// } +// break; +// case XCB_BUTTON_RELEASE: +// { +// xcb_button_press_event_t *press = (xcb_button_press_event_t *)event; +// if (press->detail == XCB_BUTTON_INDEX_1) +// mouseButtons.left = false; +// if (press->detail == XCB_BUTTON_INDEX_2) +// mouseButtons.middle = false; +// if (press->detail == XCB_BUTTON_INDEX_3) +// mouseButtons.right = false; +// handleMouseButtonUp(press->detail); +// } +// break; +// case XCB_KEY_PRESS: +// { +// const xcb_key_release_event_t *keyEvent = (const xcb_key_release_event_t *)event; +// switch (keyEvent->detail) +// { +// case KEY_W: +// camera.keys.up = true; +// break; +// case KEY_S: +// camera.keys.down = true; +// break; +// case KEY_A: +// camera.keys.left = true; +// break; +// case KEY_D: +// camera.keys.right = true; +// break; +// case KEY_P: +// paused = !paused; +// break; +// } +// keyDown(keyEvent->detail); +// } +// break; +// case XCB_KEY_RELEASE: +// { +// const xcb_key_release_event_t *keyEvent = (const xcb_key_release_event_t *)event; +// switch (keyEvent->detail) +// { +// case KEY_W: +// camera.keys.up = false; +// break; +// case KEY_S: +// camera.keys.down = false; +// break; +// case KEY_A: +// camera.keys.left = false; +// break; +// case KEY_D: +// camera.keys.right = false; +// break; +// case KEY_ESCAPE: +// quit = true; +// break; +// } +// keyUp(keyEvent->detail); +// keyPressed(keyEvent->detail); +// } +// break; +// case XCB_DESTROY_NOTIFY: +// quit = true; +// break; +// case XCB_CONFIGURE_NOTIFY: +// { +// const xcb_configure_notify_event_t *cfgEvent = (const xcb_configure_notify_event_t *)event; +// if ((prepared) && ((cfgEvent->width != width) || (cfgEvent->height != height))) +// { +// destWidth = cfgEvent->width; +// destHeight = cfgEvent->height; +// if ((destWidth > 0) && (destHeight > 0)) +// { +// windowResize(); +// } +// } +// } +// break; +// default: +// break; +// } +//} + + +void vke::engine_t::viewChanged() { + updateUniformBuffers(); +} + +void vke::engine_t::prepareUniformBuffers() +{ + // Objact vertex shader uniform buffer + sharedUBOs.matrices = new buffer_t(device, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + sizeof(mvpMatrices)); + + // Shared parameter uniform buffer + sharedUBOs.params = new buffer_t(device, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + sizeof(lightingParams)); + + // Map persistent + sharedUBOs.matrices->map(); + sharedUBOs.params->map(); + + updateUniformBuffers(); + updateParams(); +} +void vke::engine_t::updateUniformBuffers() +{ + // 3D object + mvpMatrices.projection = camera->matrices.perspective; + mvpMatrices.view = camera->matrices.view; + mvpMatrices.view3 = glm::mat4(glm::mat3(camera->matrices.view)); + mvpMatrices.camPos = camera->position * -1.0f; + sharedUBOs.matrices->copyTo (&mvpMatrices, sizeof(mvpMatrices)); +} +void vke::engine_t::updateParams() +{ + lightingParams.lightDir = glm::vec4(-10.0f, 150.f, -10.f, 1.0f); + sharedUBOs.params->copyTo(&lightingParams, sizeof(lightingParams)); +} + +void vke::engine_t::windowResize() +{ + if (!prepared) + return; + prepared = false; + + vkDeviceWaitIdle(device->dev); + + swapChain->create (width, height); + + vkDeviceWaitIdle(device->dev); + + camera->updateAspectRatio((float)width / (float)height); + viewChanged(); + + prepared = true; +} + +void vke::engine_t::keyDown(uint32_t key) { + switch (key) { + case GLFW_KEY_ESCAPE : + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + } + +} +void vke::engine_t::keyUp(uint32_t key) { + keyPressed (key); +} +void vke::engine_t::keyPressed(uint32_t key) { + switch (key) { + case GLFW_KEY_F1: + if (lightingParams.exposure > 0.1f) { + lightingParams.exposure -= 0.1f; + updateParams(); + std::cout << "Exposure: " << lightingParams.exposure << std::endl; + } + break; + case GLFW_KEY_F2: + if (lightingParams.exposure < 10.0f) { + lightingParams.exposure += 0.1f; + updateParams(); + std::cout << "Exposure: " << lightingParams.exposure << std::endl; + } + break; + case GLFW_KEY_F3: + if (lightingParams.gamma > 0.1f) { + lightingParams.gamma -= 0.1f; + updateParams(); + std::cout << "Gamma: " << lightingParams.gamma << std::endl; + } + break; + case GLFW_KEY_F4: + if (lightingParams.gamma < 10.0f) { + lightingParams.gamma += 0.1f; + updateParams(); + std::cout << "Gamma: " << lightingParams.gamma << std::endl; + } + break; + } +} +void vke::engine_t::handleMouseMove(int32_t x, int32_t y) +{ + int32_t dx = (int32_t)mousePos.x - x; + int32_t dy = (int32_t)mousePos.y - y; + + bool handled = false; + + if (handled) { + mousePos = glm::vec2((float)x, (float)y); + return; + } + + if (mouseButtons[GLFW_MOUSE_BUTTON_RIGHT]) { + camera->rotate(glm::vec3(-dy * camera->rotationSpeed, -dx * camera->rotationSpeed, 0.0f)); + viewUpdated = true; + } + if (mouseButtons[GLFW_MOUSE_BUTTON_MIDDLE]) { + camera->translate(glm::vec3(-dx * 0.01f, -dy * 0.01f, 0.0f)); + viewUpdated = true; + } + mousePos = glm::vec2((float)x, (float)y); +} +void vke::engine_t::handleMouseButtonDown(int buttonIndex) {} +void vke::engine_t::handleMouseButtonUp(int buttonIndex) {} + |