From d60b23781b04a01b58ff7dfae236545f366209bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Sat, 5 Apr 2025 14:35:43 -0400 Subject: [PATCH] Implement `Graphics.transition` binding and related bindings in libretro builds --- binding-sandbox/graphics-binding.h | 130 +++++++++++++++++++++++++++-- binding/graphics-binding.cpp | 9 +- src/core.cpp | 4 - src/display/graphics.cpp | 25 +++--- src/display/graphics.h | 13 +-- 5 files changed, 151 insertions(+), 30 deletions(-) diff --git a/binding-sandbox/graphics-binding.h b/binding-sandbox/graphics-binding.h index ee89f7c8..cd9658e8 100644 --- a/binding-sandbox/graphics-binding.h +++ b/binding-sandbox/graphics-binding.h @@ -25,6 +25,7 @@ #include "sandbox.h" #include "sharedstate.h" #include "graphics.h" +#include "bitmap.h" namespace mkxp_sandbox { SANDBOX_COROUTINE(graphics_binding_init, @@ -32,6 +33,7 @@ namespace mkxp_sandbox { SANDBOX_COROUTINE(coro, VALUE operator()(VALUE self) { BOOST_ASIO_CORO_REENTER (this) { + shState->graphics().update(); SANDBOX_YIELD; } @@ -42,6 +44,123 @@ namespace mkxp_sandbox { return sb()->bind()()(self); } + static VALUE freeze(VALUE self) { + shState->graphics().freeze(); + return SANDBOX_NIL; + } + + static VALUE transition(int32_t argc, wasm_ptr_t argv, VALUE self) { + SANDBOX_COROUTINE(coro, + Bitmap *trans_map; + wasm_ptr_t str; + int32_t duration; + int32_t vague; + int32_t i; + + VALUE operator()(int32_t argc, wasm_ptr_t argv, VALUE self) { + BOOST_ASIO_CORO_REENTER (this) { + trans_map = NULL; + duration = 8; + vague = 40; + + if (argc >= 1) { + SANDBOX_AWAIT_AND_SET(duration, rb_num2uint, ((VALUE *)(**sb() + argv))[0]); + if (argc >= 2) { + SANDBOX_AWAIT_AND_SET(str, rb_string_value_cstr, &((VALUE *)(**sb() + argv))[1]); + if (*(const char *)(**sb() + str)) { + trans_map = new Bitmap((const char *)(**sb() + str)); + } + if (argc >= 3) { + SANDBOX_AWAIT_AND_SET(vague, rb_num2int, ((VALUE *)(**sb() + argv))[2]); + } + } + } + + for (i = 0; i < duration; ++i) { + shState->graphics().transition(duration, trans_map, vague, i, i); + SANDBOX_YIELD; + } + } + + return SANDBOX_NIL; + } + + ~coro() { + if (trans_map != NULL) { + delete trans_map; + } + } + ) + + return sb()->bind()()(argc, argv, self); + } + + static VALUE wait(VALUE self, VALUE value) { + SANDBOX_COROUTINE(coro, + int32_t duration; + int32_t i; + + VALUE operator()(VALUE self, VALUE value) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(duration, rb_num2uint, value); + + for (i = 0; i < duration; ++i) { + shState->graphics().wait(duration, i, i); + SANDBOX_YIELD; + } + } + + return SANDBOX_NIL; + } + ) + + return sb()->bind()()(self, value); + } + + static VALUE fadeout(VALUE self, VALUE value) { + SANDBOX_COROUTINE(coro, + int32_t duration; + int32_t i; + + VALUE operator()(VALUE self, VALUE value) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(duration, rb_num2uint, value); + + for (i = 0; i < duration; ++i) { + shState->graphics().fadeout(duration, i, i); + SANDBOX_YIELD; + } + } + + return SANDBOX_NIL; + } + ) + + return sb()->bind()()(self, value); + } + + static VALUE fadein(VALUE self, VALUE value) { + SANDBOX_COROUTINE(coro, + int32_t duration; + int32_t i; + + VALUE operator()(VALUE self, VALUE value) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(duration, rb_num2uint, value); + + for (i = 0; i < duration; ++i) { + shState->graphics().fadein(duration, i, i); + SANDBOX_YIELD; + } + } + + return SANDBOX_NIL; + } + ) + + return sb()->bind()()(self, value); + } + static VALUE frame_reset(VALUE self) { GFX_LOCK; shState->graphics().frameReset(); @@ -76,18 +195,17 @@ namespace mkxp_sandbox { return sb()->bind()()(60.0); // TODO: use actual FPS } - static VALUE todo(int32_t argc, wasm_ptr_t argv, VALUE self) { - return SANDBOX_NIL; - } - VALUE module; void operator()() { BOOST_ASIO_CORO_REENTER (this) { SANDBOX_AWAIT_AND_SET(module, rb_define_module, "Graphics"); SANDBOX_AWAIT(rb_define_module_function, module, "update", (VALUE (*)(ANYARGS))update, 0); - SANDBOX_AWAIT(rb_define_module_function, module, "freeze", (VALUE (*)(ANYARGS))todo, -1); - SANDBOX_AWAIT(rb_define_module_function, module, "transition", (VALUE (*)(ANYARGS))todo, -1); + SANDBOX_AWAIT(rb_define_module_function, module, "freeze", (VALUE (*)(ANYARGS))freeze, 0); + SANDBOX_AWAIT(rb_define_module_function, module, "transition", (VALUE (*)(ANYARGS))transition, -1); + SANDBOX_AWAIT(rb_define_module_function, module, "wait", (VALUE (*)(ANYARGS))wait, 1); + SANDBOX_AWAIT(rb_define_module_function, module, "fadeout", (VALUE (*)(ANYARGS))fadeout, 1); + SANDBOX_AWAIT(rb_define_module_function, module, "fadein", (VALUE (*)(ANYARGS))fadein, 1); SANDBOX_AWAIT(rb_define_module_function, module, "frame_reset", (VALUE (*)(ANYARGS))frame_reset, 0); SANDBOX_AWAIT(rb_define_module_function, module, "frame_count", (VALUE (*)(ANYARGS))get_frame_count, 0); SANDBOX_AWAIT(rb_define_module_function, module, "frame_count=", (VALUE (*)(ANYARGS))set_frame_count, 1); diff --git a/binding/graphics-binding.cpp b/binding/graphics-binding.cpp index 894163b6..ebb25848 100644 --- a/binding/graphics-binding.cpp +++ b/binding/graphics-binding.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "graphics.h" +#include "bitmap.h" #include "sharedstate.h" #include "binding-util.h" #include "binding-types.h" @@ -77,7 +78,7 @@ RB_METHOD_GUARD_END typedef struct { int duration; - const char *filename; + Bitmap *transMap; int vague; } TransitionArgs; @@ -91,19 +92,19 @@ RB_METHOD_GUARD(graphicsTransition) rb_get_args(argc, argv, "|izi", &duration, &filename, &vague RB_ARG_END); - TransitionArgs args = {duration, filename, vague}; + TransitionArgs args = {duration, *filename ? new Bitmap(filename) : 0, vague}; #if RAPI_MAJOR >= 2 drop_gvl_guard([](void *args) -> void* { TransitionArgs &a = *((TransitionArgs*)args); GFX_GUARD_EXC( shState->graphics().transition(a.duration, - a.filename, + a.transMap, a.vague ); ); return 0; }, &args, 0, 0); #else - GFX_GUARD_EXC( shState->graphics().transition(duration, filename, vague); ) + GFX_GUARD_EXC( shState->graphics().transition(duration, transMap, vague); ) #endif return Qnil; diff --git a/src/core.cpp b/src/core.cpp index 31310130..b4c63fca 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -439,10 +439,6 @@ extern "C" RETRO_API void retro_run() { } } - if (mkxp_retro::sandbox.has_value()) { - shState->graphics().update(); - } - void *fb; if (hw_render.context_type != RETRO_HW_CONTEXT_NONE) { gl.UseProgram(0); diff --git a/src/display/graphics.cpp b/src/display/graphics.cpp index 16d7e5a6..0c84df69 100644 --- a/src/display/graphics.cpp +++ b/src/display/graphics.cpp @@ -1321,14 +1321,13 @@ void Graphics::freeze() { p->compositeToBuffer(p->frozenScene); } -void Graphics::transition(int duration, const char *filename, int vague) { +void Graphics::transition(int duration, Bitmap *transMap, int vague, int start, int stop) { p->checkSyncLock(); if (!p->frozen) return; vague = clamp(vague, 1, 256); - Bitmap *transMap = *filename ? new Bitmap(filename) : 0; setBrightness(255); @@ -1373,7 +1372,7 @@ void Graphics::transition(int duration, const char *filename, int vague) { glState.blend.pushSet(false); - for (int i = 0; i < duration; ++i) { + for (int i = start; i <= stop && i < duration; ++i) { #ifndef MKXPZ_RETRO /* We need to clean up transMap properly before * a possible longjmp, so we manually test for @@ -1431,9 +1430,13 @@ void Graphics::transition(int duration, const char *filename, int vague) { glState.blend.pop(); +#ifndef MKXPZ_RETRO delete transMap; +#endif // MKXPZ_RETRO - p->frozen = false; + if (stop == INT_MAX || stop + 1 >= duration) { + p->frozen = false; + } } void Graphics::frameReset() { @@ -1467,20 +1470,20 @@ double Graphics::averageFrameRate() { return p->averageFPS(); } -void Graphics::wait(int duration) { - for (int i = 0; i < duration; ++i) { +void Graphics::wait(int duration, int start, int stop) { + for (int i = start; i <= stop && i < duration; ++i) { p->checkShutDownReset(); p->redrawScreen(); } } -void Graphics::fadeout(int duration) { +void Graphics::fadeout(int duration, int start, int stop) { FBO::unbind(); float curr = p->brightness; float diff = 255.0f - curr; - for (int i = duration - 1; i > -1; --i) { + for (int i = std::min(stop, duration - 1); i >= start; --i) { setBrightness(diff + (curr / duration) * i); if (p->frozen) { @@ -1501,14 +1504,14 @@ void Graphics::fadeout(int duration) { } } -void Graphics::fadein(int duration) { +void Graphics::fadein(int duration, int start, int stop) { FBO::unbind(); float curr = p->brightness; float diff = 255.0f - curr; - for (int i = 1; i <= duration; ++i) { - setBrightness(curr + (diff / duration) * i); + for (int i = start; i <= stop && i < duration;) { + setBrightness(curr + (diff / duration) * ++i); if (p->frozen) { int scaleIsSpecial = GLMeta::blitScaleIsSpecial(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), p->frozenScene, IntRect(0, 0, p->scRes.x, p->scRes.y)); diff --git a/src/display/graphics.h b/src/display/graphics.h index b5a6e7e0..f1c6aeea 100644 --- a/src/display/graphics.h +++ b/src/display/graphics.h @@ -22,6 +22,7 @@ #ifndef GRAPHICS_H #define GRAPHICS_H +#include #include "util.h" class Scene; @@ -42,17 +43,19 @@ public: void update(bool checkForShutdown = true); void freeze(); void transition(int duration = 8, - const char *filename = "", - int vague = 40); + Bitmap *transMap = 0, + int vague = 40, + int start = 0, + int stop = INT_MAX); void frameReset(); DECL_ATTR( FrameRate, int ) DECL_ATTR( FrameCount, int ) DECL_ATTR( Brightness, int ) - void wait(int duration); - void fadeout(int duration); - void fadein(int duration); + void wait(int duration, int start = 0, int stop = INT_MAX); + void fadeout(int duration, int start = 0, int stop = INT_MAX); + void fadein(int duration, int start = 0, int stop = INT_MAX); Bitmap *snapToBitmap();