diff --git a/binding-mri/oneshot-binding.cpp b/binding-mri/oneshot-binding.cpp index d8a5e02..1c13dba 100644 --- a/binding-mri/oneshot-binding.cpp +++ b/binding-mri/oneshot-binding.cpp @@ -10,7 +10,6 @@ RB_METHOD(oneshotSetYesNo) { RB_UNUSED_PARAM; - const char *yes; const char *no; rb_get_args(argc, argv, "zz", &yes, &no RB_ARG_END); @@ -21,7 +20,6 @@ RB_METHOD(oneshotSetYesNo) RB_METHOD(oneshotMsgBox) { RB_UNUSED_PARAM; - int type; VALUE body; VALUE title = Qnil; @@ -31,6 +29,19 @@ RB_METHOD(oneshotMsgBox) return rb_bool_new(shState->oneshot().msgbox(type, bodyStr.c_str(), titleStr.c_str())); } +RB_METHOD(oneshotTextInput) +{ + // const char* prompt, int char_limit, const char* font + RB_UNUSED_PARAM; + VALUE prompt; + int char_limit = 100; + VALUE font = Qnil; + rb_get_args(argc, argv, "S|iS", &prompt, &char_limit, &font RB_ARG_END); + std::string promptStr = std::string(RSTRING_PTR(prompt), RSTRING_LEN(prompt)); + std::string fontStr = (font == Qnil) ? "" : std::string(RSTRING_PTR(font), RSTRING_LEN(font)); + return rb_str_new2(shState->oneshot().textinput(promptStr.c_str(), char_limit, fontStr.c_str()).c_str()); +} + RB_METHOD(oneshotResetObscured) { RB_UNUSED_PARAM; @@ -108,6 +119,7 @@ void oneshotBindingInit() //Functions _rb_define_module_function(module, "set_yes_no", oneshotSetYesNo); _rb_define_module_function(module, "msgbox", oneshotMsgBox); + _rb_define_module_function(module, "textinput", oneshotTextInput); _rb_define_module_function(module, "reset_obscured", oneshotResetObscured); _rb_define_module_function(module, "obscured_cleared?", oneshotObscuredCleared); _rb_define_module_function(module, "allow_exit", oneshotAllowExit); diff --git a/src/eventthread.cpp b/src/eventthread.cpp index fdebe83..4fb6349 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -282,6 +282,10 @@ void EventThread::process(RGSSThreadData &rtData) break; + case SDL_TEXTINPUT: + if (rtData.inputText.length() < rtData.inputTextLimit) rtData.inputText += event.text.text; + break; + case SDL_KEYDOWN : if (event.key.keysym.scancode == SDL_SCANCODE_F1) { @@ -339,6 +343,15 @@ void EventThread::process(RGSSThreadData &rtData) break; } + if (rtData.acceptingTextInput) { + if (event.key.keysym.sym == SDLK_BACKSPACE && rtData.inputText.length() > 0) + rtData.inputText.pop_back(); + else if (event.key.keysym.sym == SDLK_RETURN) + rtData.acceptingTextInput.clear(); + + break; + } + keyStates[event.key.keysym.scancode] = true; break; diff --git a/src/eventthread.h b/src/eventthread.h index 1a9e11f..763b728 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -238,6 +238,9 @@ struct RGSSThreadData /* Set when attempting to exit and allowExit is false */ AtomicFlag triedExit; + /* True if accepting text input */ + AtomicFlag acceptingTextInput; + EventThread *ethread; UnidirMessage windowSizeMsg; UnidirMessage bindingUpdateMsg; @@ -255,6 +258,8 @@ struct RGSSThreadData Config config; std::string rgssErrorMsg; + std::string inputText; + int inputTextLimit; RGSSThreadData(EventThread *ethread, const char *argv0, diff --git a/src/oneshot.cpp b/src/oneshot.cpp index 20beed2..9b7756e 100644 --- a/src/oneshot.cpp +++ b/src/oneshot.cpp @@ -8,6 +8,8 @@ #include "debugwriter.h" #include +#include +#include //OS-Specific code #if defined _WIN32 @@ -210,6 +212,9 @@ #error "Operating system not detected." #endif +#define DEF_SCREEN_W 640 +#define DEF_SCREEN_H 480 + struct OneshotPrivate { //Main SDL window @@ -359,6 +364,130 @@ static WCHAR *w32_toWide(const char *str) } #endif +LTexture::LTexture() { + //Initialize + mTexture = NULL; + mWidth = 0; + mHeight = 0; +} + +LTexture::~LTexture() { + //Deallocate + free(); +} + +bool LTexture::loadFromFile(std::string path, SDL_Renderer *gRenderer) { + //Get rid of preexisting texture + free(); + + //The final texture + SDL_Texture *newTexture = NULL; + + //Load image at specified path + SDL_Surface *loadedSurface = IMG_Load(path.c_str()); + if (loadedSurface == NULL) { + printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError()); + } else { + //Color key image + SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0, 0xFF, 0xFF)); + + //Create texture from surface pixels + newTexture = SDL_CreateTextureFromSurface(gRenderer, loadedSurface); + if (newTexture == NULL) { + printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError()); + } else { + //Get image dimensions + mWidth = loadedSurface->w; + mHeight = loadedSurface->h; + } + + //Get rid of old loaded surface + SDL_FreeSurface(loadedSurface); + } + + //Return success + mTexture = newTexture; + return mTexture != NULL; +} + +#ifdef _SDL_TTF_H +bool LTexture::loadFromRenderedText(std::string textureText, SDL_Color textColor, SDL_Renderer *gRenderer, TTF_Font *gFont) { + //Get rid of preexisting texture + free(); + + //Render text surface + SDL_Surface *textSurface = TTF_RenderText_Solid(gFont, textureText.c_str(), textColor); + if (textSurface != NULL) { + //Create texture from surface pixels + mTexture = SDL_CreateTextureFromSurface(gRenderer, textSurface); + if (mTexture == NULL) { + printf("Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError()); + } else { + //Get image dimensions + mWidth = textSurface->w; + mHeight = textSurface->h; + } + + //Get rid of old surface + SDL_FreeSurface(textSurface); + } else { + printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError()); + } + + + //Return success + return mTexture != NULL; +} +#endif + +void LTexture::free() { + //Free texture if it exists + if (mTexture != NULL) { + SDL_DestroyTexture(mTexture); + mTexture = NULL; + mWidth = 0; + mHeight = 0; + } +} + +void LTexture::setColor(Uint8 red, Uint8 green, Uint8 blue) { + //Modulate texture rgb + SDL_SetTextureColorMod(mTexture, red, green, blue); +} + +void LTexture::setBlendMode(SDL_BlendMode blending) { + //Set blending function + SDL_SetTextureBlendMode(mTexture, blending); +} + +void LTexture::setAlpha(Uint8 alpha) { + //Modulate texture alpha + SDL_SetTextureAlphaMod(mTexture, alpha); +} + +void LTexture::render(SDL_Renderer *gRenderer, int x, int y, SDL_Rect *clip, double angle, SDL_Point *center, + SDL_RendererFlip flip) { + //Set rendering space and render to screen + SDL_Rect renderQuad = {x, y, mWidth, mHeight }; + + //Set clip rendering dimensions + if (clip != NULL) { + renderQuad.w = clip->w; + renderQuad.h = clip->h; + } + + //Render to screen + SDL_RenderCopyEx(gRenderer, mTexture, clip, &renderQuad, angle, center, flip); +} + +int LTexture::getWidth() { + return mWidth; +} + +int LTexture::getHeight() { + return mHeight; +} + Oneshot::Oneshot(RGSSThreadData &threadData) : threadData(threadData) { @@ -778,6 +907,69 @@ bool Oneshot::msgbox(int type, const char *body, const char *title) #endif } +std::string Oneshot::textinput(const char* prompt, int char_limit, const char* font) { + SDL_Color textColor = {0xFF, 0xFF, 0xFF, 0xFF}; //Set text color as black + SDL_Renderer *gRenderer = SDL_CreateRenderer(threadData.window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + // SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF); + LTexture gPromptTextTexture; + LTexture gInputTextTexture; + + //Open the font + TTF_Font *gFont = TTF_OpenFont("VL-Gothic-Regular.ttf", 18); // XXX Implement font changing + if (gFont == NULL) { + printf("Failed to load lazy font! SDL_ttf Error: %s\n", TTF_GetError()); + // success = false; + } else { + //Render the prompt + if (!gPromptTextTexture.loadFromRenderedText(prompt, textColor, gRenderer, gFont)) { + printf("Failed to render prompt text!\n"); + // success = false; + } + } + + gInputTextTexture.loadFromRenderedText(threadData.inputText.c_str(), textColor, gRenderer, gFont); + SDL_StartTextInput(); + threadData.acceptingTextInput.set(); + threadData.inputTextLimit = char_limit; + threadData.inputText.clear(); + + //Main loop + while (threadData.acceptingTextInput) { + if (threadData.inputText.length() > 0) gInputTextTexture.loadFromRenderedText(threadData.inputText.c_str(), textColor, gRenderer, gFont); + else gInputTextTexture.loadFromRenderedText(" ", textColor, gRenderer, gFont); + + //Clear screen + // SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF); + SDL_RenderClear(gRenderer); + + //Render text textures + gPromptTextTexture.render(gRenderer, (DEF_SCREEN_W - gPromptTextTexture.getWidth()) / 2, + (DEF_SCREEN_H / 2) - gPromptTextTexture.getHeight()); + gInputTextTexture.render(gRenderer, (DEF_SCREEN_W - gInputTextTexture.getWidth()) / 2, + (DEF_SCREEN_H / 2)); + + //Update screen + SDL_RenderPresent(gRenderer); + } + + //Disable text input + SDL_StopTextInput(); + + //Free loaded images + gPromptTextTexture.free(); + gInputTextTexture.free(); + + //Free global font + TTF_CloseFont(gFont); + gFont = NULL; + + //Destroy renderer + SDL_DestroyRenderer(gRenderer); + gRenderer = NULL; + + return threadData.inputText; +} + void Oneshot::setWindowPos(int x, int y) { SDL_LockMutex(p->winMutex); diff --git a/src/oneshot.h b/src/oneshot.h index 2f30912..49b3da2 100644 --- a/src/oneshot.h +++ b/src/oneshot.h @@ -1,12 +1,62 @@ #ifndef ONESHOT_H #define ONESHOT_H +#include +#include +#include + #include "etc-internal.h" #include struct OneshotPrivate; struct RGSSThreadData; +//Texture wrapper class +class LTexture { + public: + //Initializes variables + LTexture(); + + //Deallocates memory + ~LTexture(); + + //Loads image at specified path + bool loadFromFile(std::string path, SDL_Renderer *gRenderer); + + #ifdef _SDL_TTF_H + //Creates image from font string + bool loadFromRenderedText(std::string textureText, SDL_Color textColor, SDL_Renderer *gRenderer, TTF_Font *gFont); + #endif + + //Deallocates texture + void free(); + + //Set color modulation + void setColor(Uint8 red, Uint8 green, Uint8 blue); + + //Set blending + void setBlendMode(SDL_BlendMode blending); + + //Set alpha modulation + void setAlpha(Uint8 alpha); + + //Renders texture at given point + void render(SDL_Renderer *gRenderer, int x, int y, SDL_Rect *clip = NULL, double angle = 0.0, SDL_Point *center = NULL, + SDL_RendererFlip flip = SDL_FLIP_NONE); + + //Gets image dimensions + int getWidth(); + int getHeight(); + + private: + //The actual hardware texture + SDL_Texture *mTexture; + + //Image dimensions + int mWidth; + int mHeight; +}; + class Oneshot { public: @@ -63,6 +113,7 @@ public: //Functions bool msgbox(int type, const char *body, const char *title); + std::string textinput(const char* prompt, int char_limit, const char* font); //Dirty flag for obscured texture bool obscuredDirty;