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/font/outline.o \
src/renpy/vulkan.o \ src/renpy/vulkan.o \
src/renpy/script.o \ src/renpy/script.o \
src/renpy/interpreter.o src/renpy/interpreter.o \
src/renpy/interact.o
WORLDS = \ WORLDS = \
data/minecraft/midnightmeadow/inthash.o \ 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 count;
uint32_t optionIndex; uint32_t optionIndex;
} menu; } menu;
bool interactionWait;
uint32_t findImage(uint32_t imageIndex); uint32_t findImage(uint32_t imageIndex);
void showImage(uint32_t imageIndex, uint32_t transformIndex); void showImage(uint32_t imageIndex, uint32_t transformIndex);

View File

@ -82,7 +82,9 @@ namespace renpy {
void create_instance_buffers(); void create_instance_buffers();
void draw(VkCommandBuffer commandBuffer, void draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex, 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.Position = float4(position * 2.0 - 1.0, 0, 1);
output.Texture = texture; output.Texture = texture;
output.TextureIndex = input.TextureIndex; output.TextureIndex = input.TextureIndex;
output.Color = input.Color; output.Color = input.Color.zyxw;
return output; return output;
} }
@ -44,8 +44,8 @@ float4 PSGradient1(VSOutput input) : SV_TARGET
float a = smoothstep(0.05, 0.2, input.Texture.x); float a = smoothstep(0.05, 0.2, input.Texture.x);
float b = 1.0 - smoothstep(0.8, 0.95, 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 c = smoothstep(0.05, 0.2, input.Texture.y);
float d = a * b * c * 0.5; float d = a * b * c * input.Color.w;
float3 color = float3(1.0, 1.0, 1.0); float3 color = input.Color.xyz;
return float4(color, d); 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 a = smoothstep(0.05, 0.2, input.Texture.x);
float b = 1.0 - smoothstep(0.8, 0.95, input.Texture.x); float b = 1.0 - smoothstep(0.8, 0.95, input.Texture.x);
float d = a * b * 0.5; float d = a * b * input.Color.w;
float3 color = float3(1.0, 1.0, 1.0); float3 color = input.Color.xyz;
return float4(color, d); 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 a = smoothstep(0.02, 0.1, input.Texture.x);
float b = 1.0 - smoothstep(0.9, 0.98, input.Texture.x); float b = 1.0 - smoothstep(0.9, 0.98, input.Texture.x);
float d = a * b * 0.5; float d = a * b * input.Color.w;
float3 color = float3(1.0, 1.0, 1.0); float3 color = input.Color.xyz;
return float4(color, d); return float4(color, d);
} }

View File

@ -23,6 +23,7 @@
#include "font/outline.h" #include "font/outline.h"
#include "renpy/vulkan.h" #include "renpy/vulkan.h"
#include "renpy/interpreter.h" #include "renpy/interpreter.h"
#include "renpy/interact.h"
#include "scenes/shadow_test/shadow_test.h" #include "scenes/shadow_test/shadow_test.h"
#include "scenes/eidelwind/eidelwind.h" #include "scenes/eidelwind/eidelwind.h"
@ -723,7 +724,6 @@ int main()
renpy::interpreter interpreter_state; renpy::interpreter interpreter_state;
interpreter_state.reset(); interpreter_state.reset();
interpreter_state.interpret();
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// initialize view // initialize view
@ -767,6 +767,8 @@ int main()
//collada_state.update(0); //collada_state.update(0);
while (quit == false) { while (quit == false) {
interpreter_state.interpret();
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
if (event.type == SDL_EVENT_QUIT) { if (event.type == SDL_EVENT_QUIT) {
@ -1082,7 +1084,12 @@ int main()
//minecraft_state.draw(commandBuffer, frameIndex); //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); font_state.draw(commandBuffer, frameIndex, interpreter_state);
vkCmdEndRendering(commandBuffer); 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.stringIndex = -1;
say.characterIndex = -1; say.characterIndex = -1;
menu.count = 0; menu.count = 0;
interactionWait = false;
} }
uint32_t interpreter::findImage(uint32_t imageIndex) uint32_t interpreter::findImage(uint32_t imageIndex)
@ -86,6 +87,7 @@ namespace renpy {
assert(statement.say.stringIndex < (uint32_t)script::strings_length); assert(statement.say.stringIndex < (uint32_t)script::strings_length);
say.stringIndex = statement.say.stringIndex; say.stringIndex = statement.say.stringIndex;
say.characterIndex = statement.say.characterIndex; say.characterIndex = statement.say.characterIndex;
interactionWait = true;
pc += 1; pc += 1;
break; break;
case language::type::hide: case language::type::hide:
@ -110,6 +112,11 @@ namespace renpy {
menu.optionIndex = statement.menu.optionIndex; menu.optionIndex = statement.menu.optionIndex;
pc += 1; pc += 1;
break; 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: default:
fprintf(stderr, "unknown statement type at pc %d\n", pc); fprintf(stderr, "unknown statement type at pc %d\n", pc);
pc += 1; pc += 1;
@ -119,16 +126,13 @@ namespace renpy {
void interpreter::interpret() void interpreter::interpret()
{ {
while (true) { while (!interactionWait) {
//while (true) {
uint32_t last_pc = pc; uint32_t last_pc = pc;
interpret_one(); interpret_one();
assert(pc != last_pc); assert(pc != last_pc);
if (pc == 17) { //if (pc == 18) break;
break;
}
//if (stop)
//break;
} }
} }
}; };

View File

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