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 %.o: %.s
$(AS) $< -o $@ $(AS) $< -o $@
#%.dds: %.png %.dds: %.png
# WINEDEBUG=-all wine $(HOME)/Texconv.exe -y -nogpu -nowic -dx10 --format BC7_UNORM_SRGB -m 1 $< -o $(dir $@) WINEDEBUG=-all wine $(HOME)/Texconv.exe -y -nogpu -nowic -dx10 --format BC7_UNORM_SRGB -m 1 $< -o $(dir $@)
%.pcm: %.wav %.pcm: %.wav
ffmpeg -loglevel quiet -y -i $< -c:a pcm_s16le -ar 48000 -ac 2 -f s16le $@ 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, void draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex, uint32_t frameIndex,
float dissolveLerp, float dissolveLerp,
float textLerp); float textLerp,
float framebufferWidth,
float framebufferHeight);
}; };
} }

View File

@ -4,6 +4,8 @@
struct PushConstant { struct PushConstant {
float DissolveLerp; float DissolveLerp;
float TextLerp; float TextLerp;
float Width;
float Height;
}; };
[[vk::push_constant]] PushConstant PushConstant; [[vk::push_constant]] PushConstant PushConstant;
@ -31,7 +33,17 @@ float4 mix(float4 x, float4 y, float a)
VSOutput VSMain(VSInput input) VSOutput VSMain(VSInput input)
{ {
VSOutput output = (VSOutput)0; 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.Texture = input.Texture;
output.DissolveLerp = PushConstant.DissolveLerp; output.DissolveLerp = PushConstant.DissolveLerp;
output.TextLerp = PushConstant.TextLerp; output.TextLerp = PushConstant.TextLerp;
@ -42,14 +54,14 @@ VSOutput VSMain(VSInput input)
[shader("pixel")] [shader("pixel")]
float4 PSMain(VSOutput input) : SV_TARGET 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); float4 color = float4(0, 0, 0, 0);
if (input.DissolveLerp >= 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 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); color = mix(color01, color2, input.DissolveLerp);
} else { } else {
color = color0; color = color0;

View File

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

View File

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

View File

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

View File

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

View File

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