diff --git a/source/common/audio/music/music_config.cpp b/source/common/audio/music/music_config.cpp index 12573b781..86eef267e 100644 --- a/source/common/audio/music/music_config.cpp +++ b/source/common/audio/music/music_config.cpp @@ -85,17 +85,17 @@ CUSTOM_CVAR(Bool, adl_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUA FORWARD_BOOL_CVAR(adl_fullpan); } -CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_CVAR(adl_bank); } -CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_BOOL_CVAR(adl_use_custom_bank); } -CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_STRING_CVAR(adl_custom_bank); } @@ -261,12 +261,12 @@ CUSTOM_CVAR(Bool, opn_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUA FORWARD_BOOL_CVAR(opn_fullpan); } -CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_BOOL_CVAR(opn_use_custom_bank); } -CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_STRING_CVAR(opn_custom_bank); } diff --git a/source/common/platform/posix/sdl/i_system.cpp b/source/common/platform/posix/sdl/i_system.cpp index 1dc656a69..b2f0d8436 100644 --- a/source/common/platform/posix/sdl/i_system.cpp +++ b/source/common/platform/posix/sdl/i_system.cpp @@ -175,10 +175,11 @@ void I_PrintStr(const char *cp) { const char * srcp = cp; FString printData = ""; + bool terminal = isatty(STDOUT_FILENO); while (*srcp != 0) { - if (*srcp == 0x1c && con_printansi) + if (*srcp == 0x1c && con_printansi && terminal) { srcp += 1; EColorRange range = V_ParseFontColor((const uint8_t*&)srcp, CR_UNTRANSLATED, CR_YELLOW); @@ -224,7 +225,7 @@ void I_PrintStr(const char *cp) if (StartScreen) CleanProgressBar(); fputs(printData.GetChars(),stdout); - fputs("\033[0m",stdout); + if (terminal) fputs("\033[0m",stdout); if (StartScreen) RedrawProgressBar(ProgressBarCurPos,ProgressBarMaxPos); } diff --git a/source/common/rendering/polyrenderer/backend/poly_framebuffer.cpp b/source/common/rendering/polyrenderer/backend/poly_framebuffer.cpp index 7ce16369b..a71523a46 100644 --- a/source/common/rendering/polyrenderer/backend/poly_framebuffer.cpp +++ b/source/common/rendering/polyrenderer/backend/poly_framebuffer.cpp @@ -152,6 +152,10 @@ void PolyFrameBuffer::FlushDrawCommands() } } +EXTERN_CVAR(Float, vid_brightness) +EXTERN_CVAR(Float, vid_contrast) +EXTERN_CVAR(Float, vid_saturation) + void PolyFrameBuffer::Update() { twoD.Reset(); @@ -177,8 +181,9 @@ void PolyFrameBuffer::Update() if (dst) { #if 1 + // [GEC] with the help of dpJudas a new system of copying and applying gamma in the video buffer auto copyqueue = std::make_shared(&mFrameMemory); - copyqueue->Push(dst, pitch / pixelsize, src, w, h, w, pixelsize); + copyqueue->Push(dst, pitch / pixelsize, src, w, h, w, vid_gamma, vid_contrast, vid_brightness, vid_saturation); DrawerThreads::Execute(copyqueue); #else for (int y = 0; y < h; y++) @@ -366,6 +371,40 @@ FTexture *PolyFrameBuffer::WipeEndScreen() TArray PolyFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) { + // [GEC] Really necessary to apply gamma, brightness, contrast and saturation for screenshot + + std::vector gammatablebuf(256); + uint8_t* gammatable = gammatablebuf.data(); + + float InvGamma = 1.0f / clamp(vid_gamma, 0.1f, 4.f); + float Brightness = clamp(vid_brightness, -0.8f, 0.8f); + float Contrast = clamp(vid_contrast, 0.1f, 3.f); + float Saturation = clamp(vid_saturation, -15.0f, 15.f); + + for (int x = 0; x < 256; x++) + { + float ramp = (float)(x / 255.f); + // Apply Contrast + // vec4 finalColor = vec4((((originalColor.rgb - vec3(0.5)) * Contrast) + vec3(0.5)), 1.0); + if(vid_contrast != 1.0f) + ramp = (((ramp - 0.5f) * Contrast) + 0.5f); + + // Apply Brightness + // vec4 finalColor = vec4(originalColor.rgb + Brightness, 1.0); + if (vid_brightness != 0.0f) + ramp += (Brightness / 2.0f); + + // Apply Gamma + // FragColor.rgb = pow(fragColor.rgb, vec3(1.0/gamma)); + if (vid_gamma != 1.0f) + ramp = pow(ramp, InvGamma); + + // Clamp ramp + ramp = clamp(ramp, 0.0f, 1.f); + + gammatable[x] = (uint8_t)(ramp * 255); + } + int w = SCREENWIDTH; int h = SCREENHEIGHT; @@ -380,9 +419,44 @@ TArray PolyFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_ for (int x = 0; x < w; x++) { - ScreenshotBuffer[dindex ] = pixels[sindex + 2]; - ScreenshotBuffer[dindex + 1] = pixels[sindex + 1]; - ScreenshotBuffer[dindex + 2] = pixels[sindex ]; + uint32_t red = pixels[sindex + 2]; + uint32_t green = pixels[sindex + 1]; + uint32_t blue = pixels[sindex]; + + if (vid_saturation != 1.0f) + { + float NewR = (float)(red / 255.f); + float NewG = (float)(green / 255.f); + float NewB = (float)(blue / 255.f); + + // Apply Saturation + // float luma = dot(In, float3(0.2126729, 0.7151522, 0.0721750)); + // Out = luma.xxx + Saturation.xxx * (In - luma.xxx); + //float luma = (NewR * 0.2126729f) + (NewG * 0.7151522f) + (NewB * 0.0721750f); // Rec. 709 + float luma = (NewR * 0.299f) + (NewG * 0.587f) + (NewB * 0.114f); //Rec. 601 + NewR = luma + (Saturation * (NewR - luma)); + NewG = luma + (Saturation * (NewG - luma)); + NewB = luma + (Saturation * (NewB - luma)); + + // Clamp All + NewR = clamp(NewR, 0.0f, 1.f); + NewG = clamp(NewG, 0.0f, 1.f); + NewB = clamp(NewB, 0.0f, 1.f); + + red = (uint32_t)(NewR * 255.f); + green = (uint32_t)(NewG * 255.f); + blue = (uint32_t)(NewB * 255.f); + } + + // Apply Contrast / Brightness / Gamma + red = gammatable[red]; + green = gammatable[green]; + blue = gammatable[blue]; + + ScreenshotBuffer[dindex ] = red; + ScreenshotBuffer[dindex + 1] = green; + ScreenshotBuffer[dindex + 2] = blue; + dindex += 3; sindex += 4; } diff --git a/source/common/rendering/polyrenderer/backend/poly_framebuffer.h b/source/common/rendering/polyrenderer/backend/poly_framebuffer.h index a3c4eee29..76eae0ced 100644 --- a/source/common/rendering/polyrenderer/backend/poly_framebuffer.h +++ b/source/common/rendering/polyrenderer/backend/poly_framebuffer.h @@ -96,3 +96,119 @@ private: }; inline PolyFrameBuffer *GetPolyFrameBuffer() { return static_cast(screen); } + +// [GEC] Original code of dpJudas, I add the formulas of gamma, brightness, contrast and saturation. +class CopyAndApplyGammaCommand : public DrawerCommand +{ +public: + CopyAndApplyGammaCommand(void* dest, int destpitch, const void* src, int width, int height, int srcpitch, + float gamma, float contrast, float brightness, float saturation) : dest(dest), src(src), destpitch(destpitch), width(width), height(height), srcpitch(srcpitch), + gamma(gamma), contrast(contrast), brightness(brightness), saturation(saturation) + { + } + + void Execute(DrawerThread* thread) + { + float Saturation = clamp(saturation, -15.0f, 15.f); + + std::vector gammatablebuf(256); + uint8_t* gammatable = gammatablebuf.data(); + InitGammaTable(gammatable); + + int w = width; + int start = thread->skipped_by_thread(0); + int count = thread->count_for_thread(0, height); + int sstep = thread->num_cores * srcpitch; + int dstep = thread->num_cores * destpitch; + uint32_t* d = (uint32_t*)dest + start * destpitch; + const uint32_t* s = (const uint32_t*)src + start * srcpitch; + for (int y = 0; y < count; y++) + { + for (int x = 0; x < w; x++) + { + uint32_t red = RPART(s[x]); + uint32_t green = GPART(s[x]); + uint32_t blue = BPART(s[x]); + uint32_t alpha = APART(s[x]); + + if (saturation != 1.0f) + { + float NewR = (float)(red / 255.f); + float NewG = (float)(green / 255.f); + float NewB = (float)(blue / 255.f); + + // Apply Saturation + // float luma = dot(In, float3(0.2126729, 0.7151522, 0.0721750)); + // Out = luma.xxx + Saturation.xxx * (In - luma.xxx); + //float luma = (NewR * 0.2126729f) + (NewG * 0.7151522f) + (NewB * 0.0721750f); // Rec. 709 + float luma = (NewR * 0.299f) + (NewG * 0.587f) + (NewB * 0.114f); //Rec. 601 + NewR = luma + (Saturation * (NewR - luma)); + NewG = luma + (Saturation * (NewG - luma)); + NewB = luma + (Saturation * (NewB - luma)); + + // Clamp All + NewR = clamp(NewR, 0.0f, 1.f); + NewG = clamp(NewG, 0.0f, 1.f); + NewB = clamp(NewB, 0.0f, 1.f); + + red = (uint32_t)(NewR * 255.f); + green = (uint32_t)(NewG * 255.f); + blue = (uint32_t)(NewB * 255.f); + } + + // Apply Contrast / Brightness / Gamma + red = gammatable[red]; + green = gammatable[green]; + blue = gammatable[blue]; + + d[x] = MAKEARGB(alpha, (uint8_t)red, (uint8_t)green, (uint8_t)blue); + } + d += dstep; + s += sstep; + } + } + +private: + void InitGammaTable(uint8_t *gammatable) + { + float InvGamma = 1.0f / clamp(gamma, 0.1f, 4.f); + float Brightness = clamp(brightness, -0.8f, 0.8f); + float Contrast = clamp(contrast, 0.1f, 3.f); + + for (int x = 0; x < 256; x++) + { + float ramp = (float)(x / 255.f); + + // Apply Contrast + // vec4 finalColor = vec4((((originalColor.rgb - vec3(0.5)) * Contrast) + vec3(0.5)), 1.0); + if (contrast != 1.0f) + ramp = (((ramp - 0.5f) * Contrast) + 0.5f); + + // Apply Brightness + // vec4 finalColor = vec4(originalColor.rgb + Brightness, 1.0); + if (brightness != 0.0f) + ramp += (Brightness / 2.0f); + + // Apply Gamma + // FragColor.rgb = pow(fragColor.rgb, vec3(1.0/gamma)); + if (gamma != 1.0f) + ramp = pow(ramp, InvGamma); + + // Clamp ramp + ramp = clamp(ramp, 0.0f, 1.f); + + gammatable[x] = (uint8_t)(ramp * 255); + } + } + + void* dest; + const void* src; + int destpitch; + int width; + int height; + int srcpitch; + float gamma; + float contrast; + float brightness; + float saturation; +}; diff --git a/source/common/rendering/polyrenderer/drawers/screen_shader.cpp b/source/common/rendering/polyrenderer/drawers/screen_shader.cpp index 285c97670..7e225bef1 100644 --- a/source/common/rendering/polyrenderer/drawers/screen_shader.cpp +++ b/source/common/rendering/polyrenderer/drawers/screen_shader.cpp @@ -538,12 +538,13 @@ static void MainFP(int x0, int x1, PolyTriangleThreadData* thread) // frag = frag * vColor; // frag.rgb = frag.rgb + uFogColor.rgb; - uint32_t startR = (int)((thread->mainVertexShader.Data.uObjectColor.r) * 255.0f); - uint32_t startG = (int)((thread->mainVertexShader.Data.uObjectColor.g) * 255.0f); - uint32_t startB = (int)((thread->mainVertexShader.Data.uObjectColor.b) * 255.0f); - uint32_t rangeR = (int)((thread->mainVertexShader.Data.uAddColor.r) * 255.0f) - startR; - uint32_t rangeG = (int)((thread->mainVertexShader.Data.uAddColor.g) * 255.0f) - startG; - uint32_t rangeB = (int)((thread->mainVertexShader.Data.uAddColor.b) * 255.0f) - startB; + // [GEC] I leave the default floating values. + float startR = thread->mainVertexShader.Data.uObjectColor.r; + float startG = thread->mainVertexShader.Data.uObjectColor.g; + float startB = thread->mainVertexShader.Data.uObjectColor.b; + float rangeR = thread->mainVertexShader.Data.uAddColor.r - startR; + float rangeG = thread->mainVertexShader.Data.uAddColor.g - startG; + float rangeB = thread->mainVertexShader.Data.uAddColor.b - startB; for (int x = x0; x < x1; x++) { @@ -555,15 +556,22 @@ static void MainFP(int x0, int x1, PolyTriangleThreadData* thread) uint32_t gray = (r * 77 + g * 143 + b * 37) >> 8; gray += (gray >> 7); // gray*=256/255 - r = (startR + ((gray * rangeR) >> 8)) << 1; - g = (startG + ((gray * rangeG) >> 8)) << 1; - b = (startB + ((gray * rangeB) >> 8)) << 1; + // [GEC] I use the same method as in shaders using floating values. + // This avoids errors in the invulneravility colormap in Doom and Heretic. + float fgray = (float)(gray / 255.f); + float fr = (startR + (fgray * rangeR)) * 2; + float fg = (startG + (fgray * rangeG)) * 2; + float fb = (startB + (fgray * rangeB)) * 2; - r = MIN(r, (uint32_t)255); - g = MIN(g, (uint32_t)255); - b = MIN(b, (uint32_t)255); + fr = clamp(fr, 0.0f, 1.0f); + fg = clamp(fg, 0.0f, 1.0f); + fb = clamp(fb, 0.0f, 1.0f); - fragcolor[x] = MAKEARGB(a, r, g, b); + r = (uint32_t)(fr * 255.f); + g = (uint32_t)(fg * 255.f); + b = (uint32_t)(fb * 255.f); + + fragcolor[x] = MAKEARGB(a, (uint8_t)r, (uint8_t)g, (uint8_t)b); } } else diff --git a/source/common/rendering/vulkan/renderer/vk_renderbuffers.cpp b/source/common/rendering/vulkan/renderer/vk_renderbuffers.cpp index e3217076d..34e44096d 100644 --- a/source/common/rendering/vulkan/renderer/vk_renderbuffers.cpp +++ b/source/common/rendering/vulkan/renderer/vk_renderbuffers.cpp @@ -212,13 +212,18 @@ void VkRenderBuffers::CreateSceneNormal(int width, int height, VkSampleCountFlag ImageBuilder builder; builder.setSize(width, height); builder.setSamples(samples); - builder.setFormat(VK_FORMAT_A2R10G10B10_UNORM_PACK32); + builder.setFormat(SceneNormalFormat); builder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + if (!builder.isFormatSupported(fb->device, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) + { + SceneNormalFormat = VK_FORMAT_R8G8B8A8_UNORM; + builder.setFormat(SceneNormalFormat); + } SceneNormal.Image = builder.create(fb->device); SceneNormal.Image->SetDebugName("VkRenderBuffers.SceneNormal"); ImageViewBuilder viewbuilder; - viewbuilder.setImage(SceneNormal.Image.get(), VK_FORMAT_A2R10G10B10_UNORM_PACK32); + viewbuilder.setImage(SceneNormal.Image.get(), SceneNormalFormat); SceneNormal.View = viewbuilder.create(fb->device); SceneNormal.View->SetDebugName("VkRenderBuffers.SceneNormalView"); } diff --git a/source/common/rendering/vulkan/renderer/vk_renderbuffers.h b/source/common/rendering/vulkan/renderer/vk_renderbuffers.h index b1df96b02..92ad9c5be 100644 --- a/source/common/rendering/vulkan/renderer/vk_renderbuffers.h +++ b/source/common/rendering/vulkan/renderer/vk_renderbuffers.h @@ -24,6 +24,7 @@ public: VkTextureImage SceneFog; VkFormat SceneDepthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT; + VkFormat SceneNormalFormat = VK_FORMAT_A2R10G10B10_UNORM_PACK32; static const int NumPipelineImages = 2; VkTextureImage PipelineImage[NumPipelineImages]; diff --git a/source/common/rendering/vulkan/renderer/vk_renderpass.cpp b/source/common/rendering/vulkan/renderer/vk_renderpass.cpp index 2e0973c08..44c325ecf 100644 --- a/source/common/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/source/common/rendering/vulkan/renderer/vk_renderpass.cpp @@ -281,7 +281,7 @@ std::unique_ptr VkRenderPassSetup::CreateRenderPass(int clearT { auto buffers = GetVulkanFrameBuffer()->GetBuffers(); - VkFormat drawBufferFormats[] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_A2R10G10B10_UNORM_PACK32 }; + VkFormat drawBufferFormats[] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R8G8B8A8_UNORM, buffers->SceneNormalFormat }; RenderPassBuilder builder; @@ -420,7 +420,8 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli builder.setTopology(vktopology[key.DrawType]); builder.setDepthStencilEnable(key.DepthTest, key.DepthWrite, key.StencilTest); builder.setDepthFunc(depthfunc2vk[key.DepthFunc]); - builder.setDepthClampEnable(key.DepthClamp); + if (fb->device->UsedDeviceFeatures.depthClamp) + builder.setDepthClampEnable(key.DepthClamp); builder.setDepthBias(key.DepthBias, 0.0f, 0.0f, 0.0f); // Note: CCW and CW is intentionally swapped here because the vulkan and opengl coordinate systems differ. diff --git a/source/common/rendering/vulkan/system/vk_builders.h b/source/common/rendering/vulkan/system/vk_builders.h index 5f0e3c0fc..343313bbd 100644 --- a/source/common/rendering/vulkan/system/vk_builders.h +++ b/source/common/rendering/vulkan/system/vk_builders.h @@ -45,7 +45,7 @@ public: void setMemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0); void setLinearTiling(); - bool isFormatSupported(VulkanDevice *device); + bool isFormatSupported(VulkanDevice *device, VkFormatFeatureFlags bufferFeatures = 0); std::unique_ptr create(VulkanDevice *device, VkDeviceSize* allocatedBytes = nullptr); std::unique_ptr tryCreate(VulkanDevice *device); @@ -410,7 +410,7 @@ inline void ImageBuilder::setMemoryType(VkMemoryPropertyFlags requiredFlags, VkM allocInfo.memoryTypeBits = memoryTypeBits; } -inline bool ImageBuilder::isFormatSupported(VulkanDevice *device) +inline bool ImageBuilder::isFormatSupported(VulkanDevice *device, VkFormatFeatureFlags bufferFeatures) { VkImageFormatProperties properties = { }; VkResult result = vkGetPhysicalDeviceImageFormatProperties(device->PhysicalDevice.Device, imageInfo.format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage, imageInfo.flags, &properties); @@ -421,6 +421,13 @@ inline bool ImageBuilder::isFormatSupported(VulkanDevice *device) if (imageInfo.mipLevels > properties.maxMipLevels) return false; if (imageInfo.arrayLayers > properties.maxArrayLayers) return false; if ((imageInfo.samples & properties.sampleCounts) != imageInfo.samples) return false; + if (bufferFeatures != 0) + { + VkFormatProperties formatProperties = { }; + vkGetPhysicalDeviceFormatProperties(device->PhysicalDevice.Device, imageInfo.format, &formatProperties); + if ((formatProperties.bufferFeatures & bufferFeatures) != bufferFeatures) + return false; + } return true; } diff --git a/source/common/rendering/vulkan/system/vk_device.cpp b/source/common/rendering/vulkan/system/vk_device.cpp index 8fc6e8949..2e7ca9aad 100644 --- a/source/common/rendering/vulkan/system/vk_device.cpp +++ b/source/common/rendering/vulkan/system/vk_device.cpp @@ -108,8 +108,7 @@ bool VulkanDevice::CheckRequiredFeatures(const VkPhysicalDeviceFeatures &f) { return f.samplerAnisotropy == VK_TRUE && - f.fragmentStoresAndAtomics == VK_TRUE && - f.depthClamp == VK_TRUE; + f.fragmentStoresAndAtomics == VK_TRUE; } void VulkanDevice::SelectPhysicalDevice()