From 0dc872bcea53e31ca292126c5a465f8c1087cf42 Mon Sep 17 00:00:00 2001 From: Mathew Velasquez Date: Fri, 30 Sep 2016 19:21:47 -0400 Subject: [PATCH] Journal screen stuff --- binding-mri/binding-mri.cpp | 2 + binding-mri/screen-binding.cpp | 84 +++++++++++++++++++ mkxp.pro | 7 +- scripts/Main.rb | 1 - src/config.cpp | 1 + src/config.h | 1 + src/main.cpp | 6 +- src/pipe.h | 148 +++++++++++++++++++++++++++++++++ src/screen.cpp | 106 +++++++++++++++++++++++ 9 files changed, 352 insertions(+), 4 deletions(-) create mode 100644 binding-mri/screen-binding.cpp create mode 100644 src/pipe.h create mode 100644 src/screen.cpp diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index 46151f3..3c4128a 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -73,6 +73,7 @@ void graphicsBindingInit(); void fileIntBindingInit(); +void screenBindingInit(); void oneshotBindingInit(); void steamBindingInit(); @@ -104,6 +105,7 @@ static void mriBindingInit() graphicsBindingInit(); fileIntBindingInit(); + screenBindingInit(); oneshotBindingInit(); steamBindingInit(); diff --git a/binding-mri/screen-binding.cpp b/binding-mri/screen-binding.cpp new file mode 100644 index 0000000..d08b502 --- /dev/null +++ b/binding-mri/screen-binding.cpp @@ -0,0 +1,84 @@ +#include "etc.h" +#include "binding-util.h" +#include "binding-types.h" +#include "debugwriter.h" +#include "config.h" +#include "sharedstate.h" +#include "pipe.h" + +static Pipe ipc; + +static void start() +{ + ipc.open("oneshot-pipe", Pipe::Write); + + // Create process +#ifdef _WIN32 + WCHAR path[MAX_PATH]; + WCHAR gameFolder[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, shState->config().gameFolder.c_str(), -1, gameFolder, MAX_PATH); + GetModuleFileNameW(NULL, path, MAX_PATH); + STARTUPINFOW si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + PROCESS_INFORMATION pi; + std::wstring argString = std::wstring(L"oneshot.exe \"--gameFolder=") + gameFolder + L"\" --screenMode=true"; + WCHAR *args = new WCHAR[argString.size() + 1]; + memcpy(args, argString.c_str(), (argString.size() + 1) * sizeof(WCHAR)); + CreateProcessW(path, args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + delete [] args; +#else +#ifdef linux + char path[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", path, PATH_MAX); + if (len == -1) + rb_raise(rb_eRuntimeError, "Cannot determine path of running executable"); + std::string exename = std::string(path, len); +#else +#endif + + pid_t pid = fork(); + if (pid == 0) { + execl(exename.c_str(), "oneshot", + (std::string("--gameFolder=") + shState->config().gameFolder).c_str(), + "--screenMode=true", NULL); + exit(1); + } +#endif + + ipc.connect(); +} + +RB_METHOD(screenStart) +{ + RB_UNUSED_PARAM; + start(); + return Qnil; +} + +RB_METHOD(screenFinish) +{ + RB_UNUSED_PARAM; + ipc.write("END", sizeof("END")); + ipc.close(); + return Qnil; +} + +RB_METHOD(screenSet) +{ + RB_UNUSED_PARAM; + const char *imageName; + rb_get_args(argc, argv, "z", &imageName RB_ARG_END); + if (!ipc.isOpen()) + start(); + ipc.write(imageName, strlen(imageName) + 1); + return Qnil; +} + +void screenBindingInit() +{ + VALUE module = rb_define_module("Screen"); + _rb_define_module_function(module, "start", screenStart); + _rb_define_module_function(module, "finish", screenFinish); + _rb_define_module_function(module, "set", screenSet); +} diff --git a/mkxp.pro b/mkxp.pro index c214377..5186e77 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -153,7 +153,8 @@ HEADERS += \ src/audiostream.h \ src/rgssad.h \ src/sdl-util.h \ - src/oneshot.h + src/oneshot.h \ + src/pipe.h SOURCES += \ src/main.cpp \ @@ -194,7 +195,9 @@ SOURCES += \ src/vorbissource.cpp \ src/oneshot.cpp \ binding-mri/steam-binding.cpp \ - src/xdg-user-dir-lookup.c + src/xdg-user-dir-lookup.c \ + src/screen.cpp \ + binding-mri/screen-binding.cpp STEAM { HEADERS += src/steam.h steamshim/steamshim_child.h diff --git a/scripts/Main.rb b/scripts/Main.rb index fb33e6d..afb8905 100644 --- a/scripts/Main.rb +++ b/scripts/Main.rb @@ -19,7 +19,6 @@ begin # Prepare for transition Graphics.freeze - #$debug = false $demo = false $GDC = false # Make scene object (title screen) diff --git a/src/config.cpp b/src/config.cpp index 725eeed..ec9fbb1 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -60,6 +60,7 @@ void Config::read(int argc, char *argv[]) { #define PO_DESC_ALL \ PO_DESC(debugMode, bool, false) \ + PO_DESC(screenMode, bool, false) \ PO_DESC(printFPS, bool, false) \ PO_DESC(fullscreen, bool, false) \ PO_DESC(fixedAspectRatio, bool, true) \ diff --git a/src/config.h b/src/config.h index 5499ded..5e10cc2 100644 --- a/src/config.h +++ b/src/config.h @@ -30,6 +30,7 @@ struct Config int rgssVersion; bool debugMode; + bool screenMode; bool printFPS; bool fullscreen; diff --git a/src/main.cpp b/src/main.cpp index eb57c7a..66345de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -161,7 +161,7 @@ int rgssThreadFun(void *userdata) static void showInitError(const std::string &msg) { Debug() << msg; - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "mkxp", msg.c_str(), 0); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OneShot", msg.c_str(), 0); } int main(int argc, char *argv[]) @@ -212,6 +212,10 @@ int main(int argc, char *argv[]) return 0; } + extern int screenMain(Config &conf); + if (conf.screenMode) + return screenMain(conf); + int imgFlags = IMG_INIT_PNG; if (IMG_Init(imgFlags) != imgFlags) { diff --git a/src/pipe.h b/src/pipe.h new file mode 100644 index 0000000..bd19341 --- /dev/null +++ b/src/pipe.h @@ -0,0 +1,148 @@ +#ifndef PIPE_H +#define PIPE_H + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#endif + +class Pipe +{ +public: + typedef enum { + Write, + Read, + } Mode; + + Pipe() + { +#ifdef _WIN32 + handle = NULL; +#else + fd = 0; +#endif + } + + Pipe(const char *name_, Mode mode_) + { + open(name_, mode_); + } + + ~Pipe() + { +#ifndef _WIN32 + if (mode == Write) + unlink(filename.c_str()); +#endif + } + + void open(const char *name_, Mode mode_) + { + name = name_; + mode = mode_; +#ifdef _WIN32 + filename = std::string("\\\\.\\pipe\\") + name; +#else + filename = std::string(P_tmpdir) + "/" + name; +#endif + + if (mode == Read) + { +#ifdef _WIN32 + handle = CreateFileA( + filename.c_str(), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); +#else + fd = ::open(filename.c_str(), O_RDONLY | O_NONBLOCK); +#endif + } else { +#ifdef _WIN32 + handle = CreateNamedPipeA( + filename.c_str(), + PIPE_ACCESS_OUTBOUND, + PIPE_TYPE_BYTE, + PIPE_UNLIMITED_INSTANCES, + 256, 0, 0, NULL); +#else + mkfifo(filename.c_str(), 0666); + fd = 0; +#endif + } + } + + void connect() + { +#ifdef _WIN32 + ConnectNamedPipe(handle, NULL); +#else + fd = ::open(filename.c_str(), O_WRONLY); +#endif + } + + void close() + { +#ifdef _WIN32 + CloseHandle(handle); + handle = NULL; +#else + ::close(fd); + fd = 0; +#endif + } + + bool read(char *buf) + { +#ifdef _WIN32 + OVERLAPPED overlapped; + memset(&overlapped, 0, sizeof(overlapped)); + if (!ReadFile(handle, buf, 1, NULL, &overlapped)) + { + if (GetLastError() == ERROR_IO_PENDING) + CancelIo(handle); + return false; + } + return true; +#else + return ::read(fd, buf, 1) == 1; +#endif + } + + void write(const char *buf, size_t size) + { +#ifdef _WIN32 + WriteFile(handle, buf, size, NULL, NULL); +#else + ::write(fd, buf, size); +#endif + } + + bool isOpen() + { +#ifdef _WIN32 + return handle != NULL; +#else + return fd != 0; +#endif + } + +private: + std::string name; + std::string filename; + Mode mode; +#ifdef _WIN32 + HANDLE handle; +#else + int fd; +#endif +}; + +#endif // PIPE_H diff --git a/src/screen.cpp b/src/screen.cpp new file mode 100644 index 0000000..2ce783e --- /dev/null +++ b/src/screen.cpp @@ -0,0 +1,106 @@ +#include +#include +#include + +#define FPS 60 +#define DEFAULT_WIDTH 320 +#define DEFAULT_HEIGHT 240 + +#include "config.h" +#include "debugwriter.h" +#include "pipe.h" + +static void showInitError(const std::string &msg) +{ + Debug() << msg; + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OneShot", msg.c_str(), 0); +} + +static bool readMessage(Pipe &ipc, char *buf, size_t size) +{ + size_t index = 0; + while (index < size - 1) { + if (ipc.read(buf + index)) { + ++index; + } else { + break; + } + } + buf[index] = 0; + + return index > 0; +} + +int screenMain(Config &conf) +{ + const SDL_Color colorKey = {0x00, 0xFF, 0x00, 0xFF}; + const SDL_Color black = {0x00, 0x00, 0x00, 0xFF}; + + Pipe ipc("oneshot-pipe", Pipe::Read); + + int imgFlags = IMG_INIT_PNG; + if (IMG_Init(imgFlags) != imgFlags) + { + showInitError(std::string("Error initializing SDL_image: ") + SDL_GetError()); + SDL_Quit(); + + return 0; + } + + SDL_Window *win; + win = SDL_CreateShapedWindow("The Journal", + SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + DEFAULT_WIDTH, DEFAULT_HEIGHT, 0); + + if (!win) + { + showInitError(std::string("Error creating window: ") + SDL_GetError()); + return 0; + } + + SDL_WindowShapeMode shapeMode; + shapeMode.mode = ShapeModeColorKey; + shapeMode.parameters.colorKey = colorKey; + + SDL_Surface *shape = SDL_CreateRGBSurface(0, DEFAULT_WIDTH, DEFAULT_HEIGHT, 8, 0, 0, 0, 0); + SDL_SetPaletteColors(shape->format->palette, &black, 0, 1); + + char messageBuf[256]; + + unsigned int ticks = SDL_GetTicks(); + for (;;) { + // Handle events + SDL_Event e; + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: + return 0; + } + } + + // Change shape + if (readMessage(ipc, messageBuf, sizeof(messageBuf))) { + if (strcmp(messageBuf, "END") == 0) + break; + std::string imgname = conf.gameFolder + "/Journal/" + messageBuf + ".png"; + SDL_FreeSurface(shape); + if ((shape = IMG_Load(imgname.c_str())) == NULL) + break; + SDL_SetWindowSize(win, shape->w, shape->h); + SDL_SetWindowShape(win, shape, &shapeMode); + } + + // Redraw + SDL_BlitSurface(shape, NULL, SDL_GetWindowSurface(win), NULL); + SDL_UpdateWindowSurface(win); + + // Regulate framerate + unsigned int ticksDelta = SDL_GetTicks() - ticks; + if (ticksDelta < 1000 / FPS) + SDL_Delay(1000 / FPS - ticksDelta); + ticks = SDL_GetTicks(); + } + + SDL_FreeSurface(shape); + return 0; +}