mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
Add configurable MSAA anti-aliasing, update auth screen and terrain shader
- MSAA: conditional 2-att (off) vs 3-att (on) render pass with auto-resolve - MSAA: multisampled color+depth images, query max supported sample count - MSAA: .setMultisample() on all 25+ main-pass pipelines across 17 renderers - MSAA: recreatePipelines() on every sub-renderer for runtime MSAA changes - MSAA: Renderer::setMsaaSamples() orchestrates swapchain+pipeline+ImGui rebuild - MSAA: Anti-Aliasing combo (Off/2x/4x/8x) in Video settings, persisted - Update auth screen assets and terrain fragment shader
This commit is contained in:
parent
6d213ad49b
commit
e12141a673
54 changed files with 2069 additions and 144 deletions
|
|
@ -3,10 +3,13 @@
|
|||
#include "core/application.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include "rendering/renderer.hpp"
|
||||
#include "rendering/vk_context.hpp"
|
||||
#include "pipeline/asset_manager.hpp"
|
||||
#include "audio/music_manager.hpp"
|
||||
#include "game/expansion_profile.hpp"
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_vulkan.h>
|
||||
#include "stb_image.h"
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
|
@ -159,39 +162,34 @@ void AuthScreen::render(auth::AuthHandler& authHandler) {
|
|||
loginInfoLoaded = true;
|
||||
}
|
||||
|
||||
if (!videoInitAttempted) {
|
||||
videoInitAttempted = true;
|
||||
std::string videoPath = "assets/startscreen.mp4";
|
||||
if (!std::filesystem::exists(videoPath)) {
|
||||
videoPath = (std::filesystem::current_path() / "assets/startscreen.mp4").string();
|
||||
}
|
||||
backgroundVideo.open(videoPath);
|
||||
if (!bgInitAttempted) {
|
||||
bgInitAttempted = true;
|
||||
loadBackgroundImage();
|
||||
}
|
||||
backgroundVideo.update(ImGui::GetIO().DeltaTime);
|
||||
if (backgroundVideo.isReady()) {
|
||||
if (bgDescriptorSet) {
|
||||
ImVec2 screen = ImGui::GetIO().DisplaySize;
|
||||
float screenW = screen.x;
|
||||
float screenH = screen.y;
|
||||
float videoW = static_cast<float>(backgroundVideo.getWidth());
|
||||
float videoH = static_cast<float>(backgroundVideo.getHeight());
|
||||
if (videoW > 0.0f && videoH > 0.0f) {
|
||||
float imgW = static_cast<float>(bgWidth);
|
||||
float imgH = static_cast<float>(bgHeight);
|
||||
if (imgW > 0.0f && imgH > 0.0f) {
|
||||
float screenAspect = screenW / screenH;
|
||||
float videoAspect = videoW / videoH;
|
||||
float imgAspect = imgW / imgH;
|
||||
ImVec2 uv0(0.0f, 0.0f);
|
||||
ImVec2 uv1(1.0f, 1.0f);
|
||||
if (videoAspect > screenAspect) {
|
||||
float scale = screenAspect / videoAspect;
|
||||
if (imgAspect > screenAspect) {
|
||||
float scale = screenAspect / imgAspect;
|
||||
float crop = (1.0f - scale) * 0.5f;
|
||||
uv0.x = crop;
|
||||
uv1.x = 1.0f - crop;
|
||||
} else if (videoAspect < screenAspect) {
|
||||
float scale = videoAspect / screenAspect;
|
||||
} else if (imgAspect < screenAspect) {
|
||||
float scale = imgAspect / screenAspect;
|
||||
float crop = (1.0f - scale) * 0.5f;
|
||||
uv0.y = crop;
|
||||
uv1.y = 1.0f - crop;
|
||||
}
|
||||
ImDrawList* bg = ImGui::GetBackgroundDrawList();
|
||||
bg->AddImage(static_cast<ImTextureID>(static_cast<uintptr_t>(backgroundVideo.getTextureId())),
|
||||
bg->AddImage(reinterpret_cast<ImTextureID>(bgDescriptorSet),
|
||||
ImVec2(0, 0), ImVec2(screenW, screenH), uv0, uv1);
|
||||
}
|
||||
}
|
||||
|
|
@ -763,4 +761,164 @@ void AuthScreen::loadLoginInfo() {
|
|||
LOG_INFO("Login info loaded from ", path);
|
||||
}
|
||||
|
||||
static uint32_t findMemType(VkPhysicalDevice pd, uint32_t filter, VkMemoryPropertyFlags props) {
|
||||
VkPhysicalDeviceMemoryProperties mp;
|
||||
vkGetPhysicalDeviceMemoryProperties(pd, &mp);
|
||||
for (uint32_t i = 0; i < mp.memoryTypeCount; i++) {
|
||||
if ((filter & (1 << i)) && (mp.memoryTypes[i].propertyFlags & props) == props) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AuthScreen::loadBackgroundImage() {
|
||||
auto& app = core::Application::getInstance();
|
||||
auto* renderer = app.getRenderer();
|
||||
if (!renderer) return false;
|
||||
bgVkCtx = renderer->getVkContext();
|
||||
if (!bgVkCtx) return false;
|
||||
|
||||
std::string imgPath = "assets/krayonsignin.png";
|
||||
if (!std::filesystem::exists(imgPath))
|
||||
imgPath = (std::filesystem::current_path() / imgPath).string();
|
||||
|
||||
int channels;
|
||||
stbi_set_flip_vertically_on_load(false);
|
||||
unsigned char* data = stbi_load(imgPath.c_str(), &bgWidth, &bgHeight, &channels, 4);
|
||||
if (!data) {
|
||||
LOG_WARNING("Auth screen: failed to load background image: ", imgPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
VkDevice device = bgVkCtx->getDevice();
|
||||
VkPhysicalDevice physDevice = bgVkCtx->getPhysicalDevice();
|
||||
VkDeviceSize imageSize = static_cast<VkDeviceSize>(bgWidth) * bgHeight * 4;
|
||||
|
||||
// Staging buffer
|
||||
VkBuffer stagingBuffer;
|
||||
VkDeviceMemory stagingMemory;
|
||||
{
|
||||
VkBufferCreateInfo bufInfo{};
|
||||
bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufInfo.size = imageSize;
|
||||
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
vkCreateBuffer(device, &bufInfo, nullptr, &stagingBuffer);
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs);
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memReqs.size;
|
||||
allocInfo.memoryTypeIndex = findMemType(physDevice, memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
vkAllocateMemory(device, &allocInfo, nullptr, &stagingMemory);
|
||||
vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0);
|
||||
|
||||
void* mapped;
|
||||
vkMapMemory(device, stagingMemory, 0, imageSize, 0, &mapped);
|
||||
memcpy(mapped, data, imageSize);
|
||||
vkUnmapMemory(device, stagingMemory);
|
||||
}
|
||||
stbi_image_free(data);
|
||||
|
||||
// Create VkImage
|
||||
{
|
||||
VkImageCreateInfo imgInfo{};
|
||||
imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imgInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imgInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
imgInfo.extent = {static_cast<uint32_t>(bgWidth), static_cast<uint32_t>(bgHeight), 1};
|
||||
imgInfo.mipLevels = 1;
|
||||
imgInfo.arrayLayers = 1;
|
||||
imgInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imgInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imgInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
vkCreateImage(device, &imgInfo, nullptr, &bgImage);
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
vkGetImageMemoryRequirements(device, bgImage, &memReqs);
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memReqs.size;
|
||||
allocInfo.memoryTypeIndex = findMemType(physDevice, memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
vkAllocateMemory(device, &allocInfo, nullptr, &bgMemory);
|
||||
vkBindImageMemory(device, bgImage, bgMemory, 0);
|
||||
}
|
||||
|
||||
// Transfer
|
||||
bgVkCtx->immediateSubmit([&](VkCommandBuffer cmd) {
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = bgImage;
|
||||
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.imageExtent = {static_cast<uint32_t>(bgWidth), static_cast<uint32_t>(bgHeight), 1};
|
||||
vkCmdCopyBufferToImage(cmd, stagingBuffer, bgImage,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
});
|
||||
|
||||
vkDestroyBuffer(device, stagingBuffer, nullptr);
|
||||
vkFreeMemory(device, stagingMemory, nullptr);
|
||||
|
||||
// Image view
|
||||
{
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = bgImage;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
vkCreateImageView(device, &viewInfo, nullptr, &bgImageView);
|
||||
}
|
||||
|
||||
// Sampler
|
||||
{
|
||||
VkSamplerCreateInfo samplerInfo{};
|
||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
vkCreateSampler(device, &samplerInfo, nullptr, &bgSampler);
|
||||
}
|
||||
|
||||
bgDescriptorSet = ImGui_ImplVulkan_AddTexture(bgSampler, bgImageView,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
LOG_INFO("Auth screen background loaded: ", bgWidth, "x", bgHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AuthScreen::destroyBackgroundImage() {
|
||||
if (!bgVkCtx) return;
|
||||
VkDevice device = bgVkCtx->getDevice();
|
||||
vkDeviceWaitIdle(device);
|
||||
if (bgDescriptorSet) { ImGui_ImplVulkan_RemoveTexture(bgDescriptorSet); bgDescriptorSet = VK_NULL_HANDLE; }
|
||||
if (bgSampler) { vkDestroySampler(device, bgSampler, nullptr); bgSampler = VK_NULL_HANDLE; }
|
||||
if (bgImageView) { vkDestroyImageView(device, bgImageView, nullptr); bgImageView = VK_NULL_HANDLE; }
|
||||
if (bgImage) { vkDestroyImage(device, bgImage, nullptr); bgImage = VK_NULL_HANDLE; }
|
||||
if (bgMemory) { vkFreeMemory(device, bgMemory, nullptr); bgMemory = VK_NULL_HANDLE; }
|
||||
}
|
||||
|
||||
}} // namespace wowee::ui
|
||||
|
|
|
|||
|
|
@ -261,6 +261,21 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
|||
}
|
||||
}
|
||||
|
||||
// Apply saved MSAA setting once when renderer is available
|
||||
if (!msaaSettingsApplied_ && pendingAntiAliasing > 0) {
|
||||
auto* renderer = core::Application::getInstance().getRenderer();
|
||||
if (renderer) {
|
||||
static const VkSampleCountFlagBits aaSamples[] = {
|
||||
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT,
|
||||
VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT
|
||||
};
|
||||
renderer->setMsaaSamples(aaSamples[pendingAntiAliasing]);
|
||||
msaaSettingsApplied_ = true;
|
||||
}
|
||||
} else {
|
||||
msaaSettingsApplied_ = true;
|
||||
}
|
||||
|
||||
// Apply auto-loot setting to GameHandler every frame (cheap bool sync)
|
||||
gameHandler.setAutoLoot(pendingAutoLoot);
|
||||
|
||||
|
|
@ -5866,6 +5881,17 @@ void GameScreen::renderSettingsWindow() {
|
|||
if (renderer) renderer->setShadowsEnabled(pendingShadows);
|
||||
saveSettings();
|
||||
}
|
||||
{
|
||||
const char* aaLabels[] = { "Off", "2x MSAA", "4x MSAA", "8x MSAA" };
|
||||
if (ImGui::Combo("Anti-Aliasing", &pendingAntiAliasing, aaLabels, 4)) {
|
||||
static const VkSampleCountFlagBits aaSamples[] = {
|
||||
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT,
|
||||
VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT
|
||||
};
|
||||
if (renderer) renderer->setMsaaSamples(aaSamples[pendingAntiAliasing]);
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
if (ImGui::SliderInt("Ground Clutter Density", &pendingGroundClutterDensity, 0, 150, "%d%%")) {
|
||||
if (renderer) {
|
||||
if (auto* tm = renderer->getTerrainManager()) {
|
||||
|
|
@ -5896,11 +5922,13 @@ void GameScreen::renderSettingsWindow() {
|
|||
pendingVsync = kDefaultVsync;
|
||||
pendingShadows = kDefaultShadows;
|
||||
pendingGroundClutterDensity = kDefaultGroundClutterDensity;
|
||||
pendingAntiAliasing = 0;
|
||||
pendingResIndex = defaultResIndex;
|
||||
window->setFullscreen(pendingFullscreen);
|
||||
window->setVsync(pendingVsync);
|
||||
window->applyResolution(kResolutions[pendingResIndex][0], kResolutions[pendingResIndex][1]);
|
||||
if (renderer) renderer->setShadowsEnabled(pendingShadows);
|
||||
if (renderer) renderer->setMsaaSamples(VK_SAMPLE_COUNT_1_BIT);
|
||||
if (renderer) {
|
||||
if (auto* tm = renderer->getTerrainManager()) {
|
||||
tm->setGroundClutterDensityScale(static_cast<float>(pendingGroundClutterDensity) / 100.0f);
|
||||
|
|
@ -6831,6 +6859,7 @@ void GameScreen::saveSettings() {
|
|||
// Gameplay
|
||||
out << "auto_loot=" << (pendingAutoLoot ? 1 : 0) << "\n";
|
||||
out << "ground_clutter_density=" << pendingGroundClutterDensity << "\n";
|
||||
out << "antialiasing=" << pendingAntiAliasing << "\n";
|
||||
|
||||
// Controls
|
||||
out << "mouse_sensitivity=" << pendingMouseSensitivity << "\n";
|
||||
|
|
@ -6908,6 +6937,7 @@ void GameScreen::loadSettings() {
|
|||
// Gameplay
|
||||
else if (key == "auto_loot") pendingAutoLoot = (std::stoi(val) != 0);
|
||||
else if (key == "ground_clutter_density") pendingGroundClutterDensity = std::clamp(std::stoi(val), 0, 150);
|
||||
else if (key == "antialiasing") pendingAntiAliasing = std::clamp(std::stoi(val), 0, 3);
|
||||
// Controls
|
||||
else if (key == "mouse_sensitivity") pendingMouseSensitivity = std::clamp(std::stof(val), 0.05f, 1.0f);
|
||||
else if (key == "invert_mouse") pendingInvertMouse = (std::stoi(val) != 0);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ bool UIManager::initialize(core::Window* win) {
|
|||
initInfo.MinImageCount = 2;
|
||||
initInfo.ImageCount = vkCtx->getSwapchainImageCount();
|
||||
initInfo.PipelineInfoMain.RenderPass = vkCtx->getImGuiRenderPass();
|
||||
initInfo.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
initInfo.PipelineInfoMain.MSAASamples = vkCtx->getMsaaSamples();
|
||||
|
||||
ImGui_ImplVulkan_Init(&initInfo);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue