|
1 | 1 | #include "VirtualDMD.h" |
2 | 2 |
|
| 3 | +#include <vector> |
| 4 | + |
| 5 | +#include "xbrz/xbrz.h" |
| 6 | + |
3 | 7 | void VirtualDMD::Update(uint8_t* pData) |
| 8 | +{ |
| 9 | + switch (m_renderingMode) |
| 10 | + { |
| 11 | + case RenderingMode::SmoothScaling: |
| 12 | + RenderSmoothScaling(pData); |
| 13 | + break; |
| 14 | + |
| 15 | + case RenderingMode::XBRZ: |
| 16 | + RenderXBRZ(pData); |
| 17 | + break; |
| 18 | + |
| 19 | + default: |
| 20 | + RenderDots(pData); |
| 21 | + break; |
| 22 | + } |
| 23 | +} |
| 24 | + |
| 25 | +void VirtualDMD::RenderDots(uint8_t* pData) |
4 | 26 | { |
5 | 27 | // Get window size to calculate scaling |
6 | 28 | int windowWidth, windowHeight; |
@@ -56,3 +78,95 @@ void VirtualDMD::Update(uint8_t* pData) |
56 | 78 |
|
57 | 79 | SDL_RenderPresent(m_pRenderer); |
58 | 80 | } |
| 81 | + |
| 82 | +void VirtualDMD::RenderSmoothScaling(uint8_t* pData) |
| 83 | +{ |
| 84 | + int windowWidth, windowHeight; |
| 85 | + SDL_GetRenderOutputSize(m_pRenderer, &windowWidth, &windowHeight); |
| 86 | + |
| 87 | + // Create source texture |
| 88 | + SDL_Texture* srcTexture = |
| 89 | + SDL_CreateTexture(m_pRenderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STATIC, m_width, m_height); |
| 90 | + SDL_UpdateTexture(srcTexture, NULL, pData, m_width * 3); |
| 91 | + |
| 92 | + // Create intermediate texture at 4x resolution |
| 93 | + int intermediateW = m_width * 4; |
| 94 | + int intermediateH = m_height * 4; |
| 95 | + SDL_Texture* intermediate = |
| 96 | + SDL_CreateTexture(m_pRenderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_TARGET, intermediateW, intermediateH); |
| 97 | + |
| 98 | + // First scale pass (nearest neighbor to 4x) |
| 99 | + SDL_SetRenderTarget(m_pRenderer, intermediate); |
| 100 | + SDL_SetTextureScaleMode(srcTexture, SDL_SCALEMODE_NEAREST); |
| 101 | + SDL_RenderTexture(m_pRenderer, srcTexture, NULL, NULL); |
| 102 | + |
| 103 | + // Second scale pass (linear to final size) |
| 104 | + SDL_SetRenderTarget(m_pRenderer, NULL); |
| 105 | + SDL_SetTextureScaleMode(intermediate, SDL_SCALEMODE_LINEAR); |
| 106 | + SDL_FRect dest = {0, 0, (float)windowWidth, (float)windowHeight}; |
| 107 | + SDL_RenderTexture(m_pRenderer, intermediate, NULL, &dest); |
| 108 | + |
| 109 | + SDL_RenderPresent(m_pRenderer); |
| 110 | + |
| 111 | + // Cleanup |
| 112 | + SDL_DestroyTexture(srcTexture); |
| 113 | + SDL_DestroyTexture(intermediate); |
| 114 | +} |
| 115 | + |
| 116 | +void VirtualDMD::RenderXBRZ(uint8_t* pData) |
| 117 | +{ |
| 118 | + // Get the window size |
| 119 | + int windowWidth, windowHeight; |
| 120 | + SDL_GetRenderOutputSize(m_pRenderer, &windowWidth, &windowHeight); |
| 121 | + |
| 122 | + // Prepare source ARGB buffer |
| 123 | + const int srcWidth = m_width; |
| 124 | + const int srcHeight = m_height; |
| 125 | + std::vector<uint32_t> srcImage(srcWidth * srcHeight); |
| 126 | + |
| 127 | + for (int y = 0; y < srcHeight; ++y) |
| 128 | + { |
| 129 | + for (int x = 0; x < srcWidth; ++x) |
| 130 | + { |
| 131 | + int i = y * srcWidth + x; |
| 132 | + int j = i * 3; |
| 133 | + uint8_t r = pData[j]; |
| 134 | + uint8_t g = pData[j + 1]; |
| 135 | + uint8_t b = pData[j + 2]; |
| 136 | + srcImage[i] = (255u << 24) | (r << 16) | (g << 8) | b; // ARGB format |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + // Set up xBRZ scaler configuration |
| 141 | + xbrz::ScalerCfg cfg; |
| 142 | + cfg.luminanceWeight = 1.0; |
| 143 | + cfg.equalColorTolerance = 30.0; |
| 144 | + cfg.centerDirectionBias = 4.0; |
| 145 | + cfg.dominantDirectionThreshold = 3.6; |
| 146 | + cfg.steepDirectionThreshold = 2.2; |
| 147 | + |
| 148 | + // xBRZ upscale (max factor: 6) |
| 149 | + const size_t scaleFactor = 6; |
| 150 | + const int scaledWidth = srcWidth * scaleFactor; |
| 151 | + const int scaledHeight = srcHeight * scaleFactor; |
| 152 | + std::vector<uint32_t> dstImage(scaledWidth * scaledHeight); |
| 153 | + |
| 154 | + xbrz::scale(scaleFactor, srcImage.data(), dstImage.data(), srcWidth, srcHeight, xbrz::ColorFormat::ARGB, cfg, 0, |
| 155 | + srcHeight); |
| 156 | + |
| 157 | + // Create an SDL texture from the scaled buffer |
| 158 | + SDL_Texture* texture = |
| 159 | + SDL_CreateTexture(m_pRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, scaledWidth, scaledHeight); |
| 160 | + |
| 161 | + SDL_UpdateTexture(texture, nullptr, dstImage.data(), scaledWidth * sizeof(uint32_t)); |
| 162 | + |
| 163 | + // Clear and render the texture |
| 164 | + SDL_RenderClear(m_pRenderer); |
| 165 | + |
| 166 | + SDL_FRect dstRect = {0.0f, 0.0f, (float)windowWidth, (float)windowHeight}; |
| 167 | + SDL_RenderTexture(m_pRenderer, texture, nullptr, &dstRect); |
| 168 | + |
| 169 | + SDL_RenderPresent(m_pRenderer); |
| 170 | + |
| 171 | + SDL_DestroyTexture(texture); |
| 172 | +} |
0 commit comments