implement interaction/menus

This commit is contained in:
Zack Buhman 2026-05-26 20:51:39 -05:00
parent 06db7983ca
commit 5a0299d9dd
9 changed files with 108 additions and 20 deletions

View File

@ -62,7 +62,8 @@ OBJS = \
src/font/outline.o \
src/renpy/vulkan.o \
src/renpy/script.o \
src/renpy/interpreter.o
src/renpy/interpreter.o \
src/renpy/interact.o
WORLDS = \
data/minecraft/midnightmeadow/inthash.o \

17
include/renpy/interact.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "renpy/interpreter.h"
namespace renpy {
namespace menu {
constexpr int width = 480;
constexpr int height = 40;
constexpr int x = 400;
constexpr int y = 100;
constexpr int yStride = 100;
};
bool overlap(int width, int height, int x, int y, int mx, int my);
void update(interpreter & state, int mx, int my, bool mLeft);
}

View File

@ -40,6 +40,7 @@ namespace renpy {
uint32_t count;
uint32_t optionIndex;
} menu;
bool interactionWait;
uint32_t findImage(uint32_t imageIndex);
void showImage(uint32_t imageIndex, uint32_t transformIndex);

View File

@ -82,7 +82,9 @@ namespace renpy {
void create_instance_buffers();
void draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex,
renpy::interpreter const& state);
renpy::interpreter const& state,
int mx,
int my);
};
}

View File

@ -34,7 +34,7 @@ VSOutput VSMain(VSInput input)
output.Position = float4(position * 2.0 - 1.0, 0, 1);
output.Texture = texture;
output.TextureIndex = input.TextureIndex;
output.Color = input.Color;
output.Color = input.Color.zyxw;
return output;
}
@ -44,8 +44,8 @@ float4 PSGradient1(VSOutput input) : SV_TARGET
float a = smoothstep(0.05, 0.2, input.Texture.x);
float b = 1.0 - smoothstep(0.8, 0.95, input.Texture.x);
float c = smoothstep(0.05, 0.2, input.Texture.y);
float d = a * b * c * 0.5;
float3 color = float3(1.0, 1.0, 1.0);
float d = a * b * c * input.Color.w;
float3 color = input.Color.xyz;
return float4(color, d);
}
@ -53,8 +53,8 @@ float4 PSGradient2(VSOutput input) : SV_TARGET
{
float a = smoothstep(0.05, 0.2, input.Texture.x);
float b = 1.0 - smoothstep(0.8, 0.95, input.Texture.x);
float d = a * b * 0.5;
float3 color = float3(1.0, 1.0, 1.0);
float d = a * b * input.Color.w;
float3 color = input.Color.xyz;
return float4(color, d);
}
@ -62,8 +62,8 @@ float4 PSGradient3(VSOutput input) : SV_TARGET
{
float a = smoothstep(0.02, 0.1, input.Texture.x);
float b = 1.0 - smoothstep(0.9, 0.98, input.Texture.x);
float d = a * b * 0.5;
float3 color = float3(1.0, 1.0, 1.0);
float d = a * b * input.Color.w;
float3 color = input.Color.xyz;
return float4(color, d);
}

View File

@ -23,6 +23,7 @@
#include "font/outline.h"
#include "renpy/vulkan.h"
#include "renpy/interpreter.h"
#include "renpy/interact.h"
#include "scenes/shadow_test/shadow_test.h"
#include "scenes/eidelwind/eidelwind.h"
@ -723,7 +724,6 @@ int main()
renpy::interpreter interpreter_state;
interpreter_state.reset();
interpreter_state.interpret();
//////////////////////////////////////////////////////////////////////
// initialize view
@ -767,6 +767,8 @@ int main()
//collada_state.update(0);
while (quit == false) {
interpreter_state.interpret();
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_EVENT_QUIT) {
@ -1082,7 +1084,12 @@ int main()
//minecraft_state.draw(commandBuffer, frameIndex);
renpy_state.draw(commandBuffer, frameIndex, interpreter_state);
float mx;
float my;
uint32_t mouseFlags = SDL_GetMouseState(&mx, &my);
bool mLeft = (mouseFlags & SDL_BUTTON_LMASK) != 0;
renpy::update(interpreter_state, mx, my, mLeft);
renpy_state.draw(commandBuffer, frameIndex, interpreter_state, mx, my);
font_state.draw(commandBuffer, frameIndex, interpreter_state);
vkCmdEndRendering(commandBuffer);

47
src/renpy/interact.cpp Normal file
View File

@ -0,0 +1,47 @@
#include <assert.h>
#include <stdio.h>
#include "renpy/script.h"
#include "renpy/interact.h"
namespace renpy {
bool overlap(int width, int height, int x, int y, int mx, int my)
{
int minX = x;
int minY = y;
int maxX = x + width;
int maxY = y + height;
return mx >= minX && mx <= maxX && my >= minY && my <= maxY;
}
static bool lastmLeft = false;
void update(interpreter & state, int mx, int my, bool mLeft)
{
bool mDown = mLeft && (!lastmLeft);
lastmLeft = mLeft;
if (mDown) {
state.interactionWait = false;
}
if (state.menu.count == 0 || !mDown)
return;
for (uint32_t i = 0; i < state.menu.count; i++) {
int y = menu::yStride * i + menu::y;
bool overlap = renpy::overlap(menu::width, menu::height, menu::x, y, mx, my);
if (overlap) {
// jump to menu item
uint32_t optionIndex = state.menu.optionIndex + i;
assert(optionIndex < (uint32_t)script::options_length);
uint32_t next_pc = script::options[optionIndex].statementIndex;
fprintf(stderr, "interact[%d]: menu jump %d\n", state.pc, next_pc);
state.pc = next_pc;
state.menu.count = 0;
break;
}
}
}
}

View File

@ -14,6 +14,7 @@ namespace renpy {
say.stringIndex = -1;
say.characterIndex = -1;
menu.count = 0;
interactionWait = false;
}
uint32_t interpreter::findImage(uint32_t imageIndex)
@ -86,6 +87,7 @@ namespace renpy {
assert(statement.say.stringIndex < (uint32_t)script::strings_length);
say.stringIndex = statement.say.stringIndex;
say.characterIndex = statement.say.characterIndex;
interactionWait = true;
pc += 1;
break;
case language::type::hide:
@ -110,6 +112,11 @@ namespace renpy {
menu.optionIndex = statement.menu.optionIndex;
pc += 1;
break;
case language::type::jump:
fprintf(stderr, "interpret_one[%d]: jump %d\n", pc, statement.jump.statementIndex);
assert(statement.jump.statementIndex < (uint32_t)script::statements_length);
pc = statement.jump.statementIndex;
break;
default:
fprintf(stderr, "unknown statement type at pc %d\n", pc);
pc += 1;
@ -119,16 +126,13 @@ namespace renpy {
void interpreter::interpret()
{
while (true) {
while (!interactionWait) {
//while (true) {
uint32_t last_pc = pc;
interpret_one();
assert(pc != last_pc);
if (pc == 17) {
break;
}
//if (stop)
//break;
//if (pc == 18) break;
}
}
};

View File

@ -11,6 +11,7 @@
#include "renpy/vulkan.h"
#include "renpy/script.h"
#include "renpy/interact.h"
namespace renpy {
static const _Float16 vertexData[] = {
@ -510,7 +511,9 @@ namespace renpy {
void vulkan::draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex,
renpy::interpreter const& state)
renpy::interpreter const& state,
int mx,
int my)
{
int outputIndex = 0;
// update
@ -534,6 +537,7 @@ namespace renpy {
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {708, 200},
.topLeft = {286, 720 - 200},
.color = 0x80ffffffu,
.imageIndex = -2, // white gradient 1
};
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
@ -551,14 +555,19 @@ namespace renpy {
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {148, 30},
.topLeft = {560, 528},
.color = 0x80ffffffu,
.imageIndex = -4, // white gradient 2
};
}
} else {
for (uint32_t i = 0; i < state.menu.count; i++) {
int y = menu::yStride * i + menu::y;
bool overlap = renpy::overlap(menu::width, menu::height, menu::x, y, mx, my);
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {480, 40},
.topLeft = {400, (int16_t)(100 * i + 100)},
.size = {menu::width, menu::height},
.topLeft = {menu::x, (int16_t)(y)},
.color = overlap ? 0xf0494493u : 0xa0ffffffu,
.imageIndex = -3, // white gradient 2
};
}