window resize with integer scaling

This commit is contained in:
Zack Buhman 2026-05-28 22:08:25 -05:00
parent bb10732ce1
commit f2edffd898
9 changed files with 54 additions and 36 deletions

View File

@ -113,8 +113,8 @@ all: main
%.o: %.s
$(AS) $< -o $@
#%.dds: %.png
# WINEDEBUG=-all wine $(HOME)/Texconv.exe -y -nogpu -nowic -dx10 --format BC7_UNORM_SRGB -m 1 $< -o $(dir $@)
%.dds: %.png
WINEDEBUG=-all wine $(HOME)/Texconv.exe -y -nogpu -nowic -dx10 --format BC7_UNORM_SRGB -m 1 $< -o $(dir $@)
%.pcm: %.wav
ffmpeg -loglevel quiet -y -i $< -c:a pcm_s16le -ar 48000 -ac 2 -f s16le $@

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -47,6 +47,8 @@ namespace renpy::composite {
void draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex,
float dissolveLerp,
float textLerp);
float textLerp,
float framebufferWidth,
float framebufferHeight);
};
}

View File

@ -4,6 +4,8 @@
struct PushConstant {
float DissolveLerp;
float TextLerp;
float Width;
float Height;
};
[[vk::push_constant]] PushConstant PushConstant;
@ -31,7 +33,17 @@ float4 mix(float4 x, float4 y, float a)
VSOutput VSMain(VSInput input)
{
VSOutput output = (VSOutput)0;
output.Position = float4(input.Position, 0, 1);
float2 canonicalSize = float2(1280, 720);
float2 size = float2(PushConstant.Width, PushConstant.Height);
while (canonicalSize.x * 2 <= size.x && canonicalSize.y * 2 <= size.y) {
canonicalSize *= 2;
}
float2 inverseSize = 1.0 / size;
float2 scale = canonicalSize * inverseSize;
output.Position = float4(input.Position * scale, 0, 1);
output.Texture = input.Texture;
output.DissolveLerp = PushConstant.DissolveLerp;
output.TextLerp = PushConstant.TextLerp;
@ -42,14 +54,14 @@ VSOutput VSMain(VSInput input)
[shader("pixel")]
float4 PSMain(VSOutput input) : SV_TARGET
{
float4 color0 = Texture[0].Sample(ClosestSampler, input.Texture);
float4 color0 = Texture[0].Load(int3(input.Texture * float2(1280, 720), 0));
float4 color = float4(0, 0, 0, 0);
if (input.DissolveLerp >= 0) {
float4 color1 = Texture[1].Sample(ClosestSampler, input.Texture);
float4 color1 = Texture[1].Load(int3(input.Texture * float2(1280, 720), 0));
float4 color01 = mix(color0, color1, input.TextLerp);
float4 color2 = Texture[2].Sample(ClosestSampler, input.Texture);
float4 color2 = Texture[2].Load(int3(input.Texture * float2(1280, 720), 0));
color = mix(color01, color2, input.DissolveLerp);
} else {
color = color0;

View File

@ -709,7 +709,7 @@ namespace font::outline {
if (state.say.stringIndex != -1u) {
char const * const string = renpy::script::strings[state.say.stringIndex];
uint32_t x = textboxLeft << 6;
uint32_t y = 590 << 6;
uint32_t y = 600 << 6;
centered(frameIndex, string,
x, y,
textboxLeft, textboxWidth,
@ -720,11 +720,11 @@ namespace font::outline {
if (state.say.characterIndex != -1u) {
const renpy::language::character & character = renpy::script::characters[state.say.characterIndex];
char const * const string = character.characterName;
uint32_t x = 580 << 6;
uint32_t y = 550 << 6;
uint32_t x = 550 << 6;
uint32_t y = 565 << 6;
centered(frameIndex, string,
x, y,
580, 118,
550, 180,
outputIndex,
character.color);
}

View File

@ -443,22 +443,22 @@ void offscreenRender(VkCommandBuffer commandBuffer, int frameIndex,
// viewport/scissor
VkViewport shadowViewport{
VkViewport viewport{
.x = 0,
.y = 0,
.width = static_cast<float>(windowSize.x),
.height = static_cast<float>(windowSize.y),
.width = 1280,
.height = 720,
.minDepth = 0.0f,
.maxDepth = 1.0f
};
vkCmdSetViewport(commandBuffer, 0, 1, &shadowViewport);
VkRect2D shadowScissor{
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{
.extent{
.width = (uint32_t)windowSize.x,
.height = (uint32_t)windowSize.y
.width = 1280,
.height = 720
}
};
vkCmdSetScissor(commandBuffer, 0, 1, &shadowScissor);
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
// draw
@ -663,8 +663,9 @@ int main()
// window and surface
//////////////////////////////////////////////////////////////////////
SDL_Window * window = SDL_CreateWindow("Vulkan", 1280, 720, SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE);
SDL_Window * window = SDL_CreateWindow("The Road to Alysen", 1280, 720, SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE);
SDL_CHECK_NONNULL(window);
SDL_CHECK(SDL_SetWindowMinimumSize(window, 1280, 720));
SDL_CHECK(SDL_Vulkan_CreateSurface(window, instance, nullptr, &surface));
SDL_CHECK(SDL_GetWindowSize(window, &windowSize.x, &windowSize.y));
VkSurfaceCapabilitiesKHR surfaceCapabilities{};
@ -918,6 +919,7 @@ int main()
renpy::interpreter interpreter_state;
interpreter_state.reset();
interpreter_state.pc = 11;
//////////////////////////////////////////////////////////////////////
// renpy composite
@ -1338,16 +1340,16 @@ int main()
VkViewport viewport{
.x = 0,
.y = 0,
.width = static_cast<float>(windowSize.x),
.height = static_cast<float>(windowSize.y),
.width = static_cast<float>(surfaceCapabilities.currentExtent.width),
.height = static_cast<float>(surfaceCapabilities.currentExtent.height),
.minDepth = 0.0f,
.maxDepth = 1.0f
};
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{
.extent{
.width = (uint32_t)windowSize.x,
.height = (uint32_t)windowSize.y
.width = (uint32_t)surfaceCapabilities.currentExtent.width,
.height = (uint32_t)surfaceCapabilities.currentExtent.height
}
};
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
@ -1374,7 +1376,7 @@ int main()
dissolve_lerp = clamp01(delta / interpreter_state.dissolveDuration);
text_lerp = clamp01(delta / textDissolveDuration);
}
composite_state.draw(commandBuffer, frameIndex, dissolve_lerp, text_lerp);
composite_state.draw(commandBuffer, frameIndex, dissolve_lerp, text_lerp, surfaceCapabilities.currentExtent.width, surfaceCapabilities.currentExtent.height);
vkCmdEndRendering(commandBuffer);

View File

@ -215,7 +215,7 @@ namespace renpy::composite {
{
VkPushConstantRange pushConstantRange{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.size = (sizeof (float)),
.size = (sizeof (float)) * 4,
};
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
@ -387,12 +387,14 @@ namespace renpy::composite {
void vulkan::draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex,
float dissolveLerp,
float textLerp)
float textLerp,
float framebufferWidth,
float framebufferHeight)
{
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
float lerp[2] = { dissolveLerp, textLerp };
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, (sizeof (float)) * 2, lerp);
float constants[4] = { dissolveLerp, textLerp, framebufferWidth, framebufferHeight };
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, (sizeof (float)) * 4, constants);
VkDescriptorSet descriptorSets[1] = {
descriptorSet0,

View File

@ -185,7 +185,7 @@ const int strings_length = (sizeof (strings)) / (sizeof (strings[0]));
const language::character characters[] = {
{ .characterName = "Alice", .color = 0x00765e }, // 0
{ .characterName = "Cat", .color = 0x590093 }, // 1
{ .characterName = "Eily", .color = 0x0b6092 }, // 2
{ .characterName = "Mouse Girls", .color = 0x0b6092 }, // 2
{ .characterName = "Mouse Girls", .color = 0x000000 }, // 3
{ .characterName = "Narrator", .color = 0x000000 }, // 4
{ .characterName = "Leona", .color = 0x590093 }, // 5

View File

@ -545,20 +545,20 @@ namespace renpy {
.imageIndex = -2, // white gradient 1
};
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {244, 200},
.topLeft = {336, 720 - 200},
.size = {216, 184},
.topLeft = {336, 720 - 184},
.imageIndex = 0, // flower
};
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {-244, 200},
.topLeft = {1280 - (336 + 244), 720 - 200},
.size = {-216, 184},
.topLeft = {1280 - (336 + 216), 720 - 184},
.imageIndex = 0, // flower
};
if (state.say.characterIndex != -1u) {
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {148, 30},
.topLeft = {560, 528},
.size = {180, 30},
.topLeft = {550, 542},
.color = 0x80ffffffu,
.imageIndex = -4, // white gradient 2
};