From e903fe7f8b8fca62f2f497f24adf87c410dac73d Mon Sep 17 00:00:00 2001 From: Melody Madeline Lyons Date: Fri, 5 Jul 2024 09:18:43 -0700 Subject: [PATCH] Add basic screen module (How tf was this so easy??) --- binding/binding-mri.cpp | 2 + binding/meson.build | 1 + binding/osfm-screen-binding.cpp | 118 ++++++++++++++++++++++++++++++++ binding/viewport-binding.cpp | 43 +++++++++--- src/display/graphics.cpp | 5 ++ src/display/graphics.h | 2 + src/display/viewport.cpp | 13 ++-- src/display/viewport.h | 6 +- src/eventthread.cpp | 6 ++ 9 files changed, 179 insertions(+), 17 deletions(-) create mode 100644 binding/osfm-screen-binding.cpp diff --git a/binding/binding-mri.cpp b/binding/binding-mri.cpp index 064f95bf8..3febbf52f 100644 --- a/binding/binding-mri.cpp +++ b/binding/binding-mri.cpp @@ -122,6 +122,7 @@ void modshotAleffectBindingInit(); #endif void modshotwindowBindingInit(); void modshotSystemBindingInit(); +void osfmBindingInit(); RB_METHOD(mkxpDelta); RB_METHOD(mriPrint); @@ -221,6 +222,7 @@ static void mriBindingInit() { #endif modshotwindowBindingInit(); modshotSystemBindingInit(); + osfmBindingInit(); VALUE _mkxp_module = rb_define_module("MKXP"); _rb_define_module_function(_mkxp_module, "allow_force_quit", compatEnableForceQuit); diff --git a/binding/meson.build b/binding/meson.build index 170b3092d..b22a06fd8 100644 --- a/binding/meson.build +++ b/binding/meson.build @@ -40,6 +40,7 @@ binding_source = [files( 'oneshot-wallpaper-binding.cpp', 'modshot-window-binding.cpp', 'modshot-system-binding.cpp', + 'osfm-screen-binding.cpp', )] audio_binding_source = [files( diff --git a/binding/osfm-screen-binding.cpp b/binding/osfm-screen-binding.cpp new file mode 100644 index 000000000..0c6ef53b7 --- /dev/null +++ b/binding/osfm-screen-binding.cpp @@ -0,0 +1,118 @@ +#include +#include "etc-internal.h" +#include "gl-fun.h" +#include "gl-util.h" +#include "gl-meta.h" +#include "texpool.h" +#include "graphics.h" +#include "scene.h" +#include "binding-util.h" +#include "sharedstate.h" + + +class WindowScene : public Scene { +public: + TEXFBO tex; + + WindowScene() { + tex = shState->texPool().request(480, 480); + } + + void composite() { + glState.viewport.set(IntRect(0, 0, 480, 480)); + + FBO::bind(tex.fbo); + + gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + FBO::clear(); + + Scene::composite(); + } + + void requestViewportRender(const Vec4& color, const Vec4& flash, const Vec4& tone, const bool scanned, const Vec4 rbg, const Vec4 rbg2, const float cubic) { + // do nothing + } +}; + +struct ScreenWindow { + SDL_Window* window; + WindowScene scene; + + ScreenWindow(); + ~ScreenWindow(); + + Scene* getScene(); +}; + +ScreenWindow::ScreenWindow(){ + window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 480, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS); +} +ScreenWindow::~ScreenWindow() { + if (window) + SDL_DestroyWindow(window); +} + +Scene* ScreenWindow::getScene() { + return &scene; +} + +DEF_TYPE_CUSTOMNAME(ScreenWindow, "Screen::Window"); + +#define GUARD_DISPOSED(w) if (!w->window) rb_raise(rb_eRuntimeError, "Window already disposed!"); + +RB_METHOD(screenWindowInit) { + ScreenWindow* w = new ScreenWindow(); + + setPrivateData(self, w); + + return self; +} + +RB_METHOD(screenWindowDispose) { + ScreenWindow* w = getPrivateData(self); + + delete w; + setPrivateData(self, nullptr); + + return Qnil; +} + +RB_METHOD(screenWindowDraw) { + ScreenWindow* w = getPrivateData(self); + + GUARD_DISPOSED(w); + + SDL_GLContext ctx = shState->graphics().context(); + int err = SDL_GL_MakeCurrent(w->window, ctx); + if (err != 0) { + rb_raise(rb_eRuntimeError, "Failed to make window current: %s", SDL_GetError()); + } + + w->scene.composite(); + + GLMeta::blitBeginScreen(Vec2i(480, 480), false); + GLMeta::blitSource(w->scene.tex, 0); + + FBO::clear(); + + GLMeta::blitRectangle(IntRect(0, 0, 480, 480), IntRect(0,480,480,-480), false); + + GLMeta::blitEnd(); + + SDL_GL_SwapWindow(w->window); + + return Qnil; +} + + +void osfmBindingInit() { + VALUE module = rb_define_module("Screen"); + + VALUE klass = rb_define_class_under(module, "Window", rb_cObject); + rb_define_alloc_func(klass, classAllocate<&ScreenWindowType>); + + _rb_define_method(klass, "initialize", screenWindowInit); + _rb_define_method(klass, "dispose", screenWindowDispose); + _rb_define_method(klass, "draw", screenWindowDraw); +} \ No newline at end of file diff --git a/binding/viewport-binding.cpp b/binding/viewport-binding.cpp index 0a14ccc37..47c76b1b7 100644 --- a/binding/viewport-binding.cpp +++ b/binding/viewport-binding.cpp @@ -23,6 +23,10 @@ #include "binding-util.h" #include "disposable-binding.h" #include "flashable-binding.h" +#include "ruby/internal/core/rtypeddata.h" +#include "ruby/internal/intern/object.h" +#include "ruby/internal/special_consts.h" +#include "scene.h" #include "sceneelement-binding.h" #include "sharedstate.h" #include "viewport.h" @@ -33,30 +37,53 @@ DEF_TYPE(Viewport); DEF_ALLOCFUNC(Viewport); #endif +// oh yes. this is awful. there should be a header for this +// more fun this way :3 +extern rb_data_type_t ScreenWindowType; +struct ScreenWindow { + Scene* getScene(); +}; + RB_METHOD(viewportInitialize) { Viewport *v; - + if (argc == 0 && rgssVer >= 3) { GFX_LOCK; v = new Viewport(); - } else if (argc == 1) { - /* The rect arg is only used to init the viewport, - * and does NOT replace its 'rect' property */ + // could either be a Rect or a Window + } else if (argc == 1 || argc == 2) { VALUE rectObj; + VALUE screenWindowObj = Qnil; Rect *rect; - rb_get_args(argc, argv, "o", &rectObj RB_ARG_END); + rb_get_args(argc, argv, "o|o", &rectObj, &screenWindowObj RB_ARG_END); rect = getPrivateDataCheck(rectObj, RectType); + + Scene *scene = nullptr; + if (!NIL_P(screenWindowObj)) { + ScreenWindow* window = getPrivateDataCheck(screenWindowObj, ScreenWindowType); + scene = window->getScene(); + rb_iv_set(self, "screen_window", screenWindowObj); // so it doesn't get GC'd + } GFX_LOCK; - v = new Viewport(rect); + v = new Viewport(rect, scene); } else { int x, y, width, height; + VALUE screenWindowObj = Qnil; + + rb_get_args(argc, argv, "iiii|o", &x, &y, &width, &height, &screenWindowObj RB_ARG_END); + + Scene *scene = nullptr; + if (!NIL_P(screenWindowObj)) { + ScreenWindow* window = getPrivateDataCheck(screenWindowObj, ScreenWindowType); + scene = window->getScene(); + rb_iv_set(self, "screen_window", screenWindowObj); // so it doesn't get GC'd + } - rb_get_args(argc, argv, "iiii", &x, &y, &width, &height RB_ARG_END); GFX_LOCK; - v = new Viewport(x, y, width, height); + v = new Viewport(x, y, width, height, scene); } setPrivateData(self, v); diff --git a/src/display/graphics.cpp b/src/display/graphics.cpp index f7379d627..093341ae1 100644 --- a/src/display/graphics.cpp +++ b/src/display/graphics.cpp @@ -1918,4 +1918,9 @@ void Graphics::remDisposable(Disposable *d) { p->dispList.remove(d->link); } const TEX::ID &Graphics::obscuredTex() const { return p->obscuredTex; +} + +SDL_GLContext Graphics::context() const +{ + return p->glCtx; } \ No newline at end of file diff --git a/src/display/graphics.h b/src/display/graphics.h index 0c983380c..1eff52292 100644 --- a/src/display/graphics.h +++ b/src/display/graphics.h @@ -101,6 +101,8 @@ class Graphics void lock(bool force = false); void unlock(bool force = false); + SDL_GLContext context() const; + private: Graphics(RGSSThreadData *data); ~Graphics(); diff --git a/src/display/viewport.cpp b/src/display/viewport.cpp index 6f13116f8..82d15dfea 100644 --- a/src/display/viewport.cpp +++ b/src/display/viewport.cpp @@ -21,6 +21,7 @@ #include "viewport.h" +#include "scene.h" #include "sharedstate.h" #include "etc.h" #include "util.h" @@ -111,22 +112,22 @@ struct ViewportPrivate } }; -Viewport::Viewport(int x, int y, int width, int height) - : SceneElement(*shState->screen()), +Viewport::Viewport(int x, int y, int width, int height, Scene *scene) + : SceneElement(scene ? *scene : *shState->screen()), sceneLink(this) { initViewport(x, y, width, height); } -Viewport::Viewport(Rect *rect) - : SceneElement(*shState->screen()), +Viewport::Viewport(Rect *rect, Scene *scene) + : SceneElement(scene ? *scene : *shState->screen()), sceneLink(this) { initViewport(rect->x, rect->y, rect->width, rect->height); } -Viewport::Viewport() - : SceneElement(*shState->screen()), +Viewport::Viewport(Scene *scene) + : SceneElement(scene ? *scene : *shState->screen()), sceneLink(this) { const Graphics &graphics = shState->graphics(); diff --git a/src/display/viewport.h b/src/display/viewport.h index 542c9ee90..4fb84cd65 100644 --- a/src/display/viewport.h +++ b/src/display/viewport.h @@ -32,9 +32,9 @@ struct ViewportPrivate; class Viewport : public Scene, public SceneElement, public Flashable, public Disposable { public: - Viewport(int x, int y, int width, int height); - Viewport(Rect *rect); - Viewport(); + Viewport(int x, int y, int width, int height, Scene* scene = 0); + Viewport(Rect *rect, Scene* scene = 0); + Viewport(Scene* scene = 0); ~Viewport(); void update(); diff --git a/src/eventthread.cpp b/src/eventthread.cpp index b7afd95ca..fd9a17ea8 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -691,6 +691,12 @@ int EventThread::eventFilter(void *data, SDL_Event *event) return 0; /* Workaround for Windows pausing on drag */ case SDL_WINDOWEVENT: + { + unsigned int win_id = SDL_GetWindowID(rtData.window); + if (win_id != event->window.windowID) // filter out events from other windows + return 0; + } + if (event->window.event == SDL_WINDOWEVENT_MOVED) { if (shState != NULL && shState->rgssVersion > 0)