Add Ruby-accessible delta clocks (microseconds)

This commit is contained in:
Struma 2021-02-25 21:29:21 -05:00 committed by Roza
parent d4d2b7c7cb
commit 02c06be88a
9 changed files with 120 additions and 3 deletions

View file

@ -104,6 +104,7 @@ void CUSLBindingInit();
void httpBindingInit(); void httpBindingInit();
RB_METHOD(mkxpDelta);
RB_METHOD(mriPrint); RB_METHOD(mriPrint);
RB_METHOD(mriP); RB_METHOD(mriP);
RB_METHOD(mkxpDataDirectory); RB_METHOD(mkxpDataDirectory);
@ -188,6 +189,7 @@ static void mriBindingInit() {
assert(!"unreachable"); assert(!"unreachable");
VALUE mod = rb_define_module("System"); VALUE mod = rb_define_module("System");
_rb_define_module_function(mod, "delta", mkxpDelta);
_rb_define_module_function(mod, "data_directory", mkxpDataDirectory); _rb_define_module_function(mod, "data_directory", mkxpDataDirectory);
_rb_define_module_function(mod, "set_window_title", mkxpSetTitle); _rb_define_module_function(mod, "set_window_title", mkxpSetTitle);
_rb_define_module_function(mod, "show_settings", mkxpSettingsMenu); _rb_define_module_function(mod, "show_settings", mkxpSettingsMenu);
@ -244,6 +246,7 @@ static void printP(int argc, VALUE *argv, const char *convMethod,
showMsg(RSTRING_PTR(dispString)); showMsg(RSTRING_PTR(dispString));
} }
RB_METHOD(mriPrint) { RB_METHOD(mriPrint) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -260,6 +263,12 @@ RB_METHOD(mriP) {
return Qnil; return Qnil;
} }
RB_METHOD(mkxpDelta) {
RB_UNUSED_PARAM;
return ULL2NUM(shState->runTime());
}
RB_METHOD(mkxpDataDirectory) { RB_METHOD(mkxpDataDirectory) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;

View file

@ -25,6 +25,12 @@
#include "binding-types.h" #include "binding-types.h"
#include "exception.h" #include "exception.h"
RB_METHOD(graphicsDelta) {
RB_UNUSED_PARAM;
return ULL2NUM(shState->graphics().getDelta());
}
RB_METHOD(graphicsUpdate) RB_METHOD(graphicsUpdate)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -255,6 +261,7 @@ void graphicsBindingInit()
{ {
VALUE module = rb_define_module("Graphics"); VALUE module = rb_define_module("Graphics");
_rb_define_module_function(module, "delta", graphicsDelta);
_rb_define_module_function(module, "update", graphicsUpdate); _rb_define_module_function(module, "update", graphicsUpdate);
_rb_define_module_function(module, "freeze", graphicsFreeze); _rb_define_module_function(module, "freeze", graphicsFreeze);
_rb_define_module_function(module, "transition", graphicsTransition); _rb_define_module_function(module, "transition", graphicsTransition);

View file

@ -28,6 +28,12 @@
#include <SDL_joystick.h> #include <SDL_joystick.h>
#include <string> #include <string>
RB_METHOD(inputDelta) {
RB_UNUSED_PARAM;
return ULL2NUM(shState->input().getDelta());
}
RB_METHOD(inputUpdate) { RB_METHOD(inputUpdate) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -138,6 +144,19 @@ RB_METHOD(inputCount) {
return UINT2NUM(shState->input().count(num)); return UINT2NUM(shState->input().count(num));
} }
RB_METHOD(inputRepeatTime) {
RB_UNUSED_PARAM;
rb_check_argc(argc, 1);
VALUE button;
rb_scan_args(argc, argv, "1", &button);
int num = getButtonArg(&button);
return ULL2NUM(shState->input().repeatTime(num));
}
RB_METHOD(inputPressEx) { RB_METHOD(inputPressEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -208,6 +227,20 @@ RB_METHOD(inputCountEx) {
return UINT2NUM(shState->input().repeatcount(NUM2INT(button), 1)); return UINT2NUM(shState->input().repeatcount(NUM2INT(button), 1));
} }
RB_METHOD(inputRepeatTimeEx) {
RB_UNUSED_PARAM;
VALUE button;
rb_scan_args(argc, argv, "1", &button);
if (SYMBOL_P(button)) {
int num = getScancodeArg(&button);
return ULL2NUM(shState->input().repeatTimeEx(num, 0));
}
return ULL2NUM(shState->input().repeatTimeEx(NUM2INT(button), 1));
}
RB_METHOD(inputDir4) { RB_METHOD(inputDir4) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -357,17 +390,20 @@ static elementsN(buttonCodes);
void inputBindingInit() { void inputBindingInit() {
VALUE module = rb_define_module("Input"); VALUE module = rb_define_module("Input");
_rb_define_module_function(module, "delta", inputDelta);
_rb_define_module_function(module, "update", inputUpdate); _rb_define_module_function(module, "update", inputUpdate);
_rb_define_module_function(module, "press?", inputPress); _rb_define_module_function(module, "press?", inputPress);
_rb_define_module_function(module, "trigger?", inputTrigger); _rb_define_module_function(module, "trigger?", inputTrigger);
_rb_define_module_function(module, "repeat?", inputRepeat); _rb_define_module_function(module, "repeat?", inputRepeat);
_rb_define_module_function(module, "release?", inputRelease); _rb_define_module_function(module, "release?", inputRelease);
_rb_define_module_function(module, "count", inputCount); _rb_define_module_function(module, "count", inputCount);
_rb_define_module_function(module, "time?", inputRepeatTime);
_rb_define_module_function(module, "pressex?", inputPressEx); _rb_define_module_function(module, "pressex?", inputPressEx);
_rb_define_module_function(module, "triggerex?", inputTriggerEx); _rb_define_module_function(module, "triggerex?", inputTriggerEx);
_rb_define_module_function(module, "repeatex?", inputRepeatEx); _rb_define_module_function(module, "repeatex?", inputRepeatEx);
_rb_define_module_function(module, "releaseex?", inputReleaseEx); _rb_define_module_function(module, "releaseex?", inputReleaseEx);
_rb_define_module_function(module, "repeatcount", inputCountEx); _rb_define_module_function(module, "repeatcount", inputCountEx);
_rb_define_module_function(module, "timeex?", inputRepeatTimeEx);
_rb_define_module_function(module, "dir4", inputDir4); _rb_define_module_function(module, "dir4", inputDir4);
_rb_define_module_function(module, "dir8", inputDir8); _rb_define_module_function(module, "dir8", inputDir8);

View file

@ -421,6 +421,9 @@ struct GraphicsPrivate {
int frameCount; int frameCount;
int brightness; int brightness;
unsigned long long last_update;
FPSLimiter fpsLimiter; FPSLimiter fpsLimiter;
// Can be set from Ruby. Takes priority over config setting. // Can be set from Ruby. Takes priority over config setting.
@ -440,7 +443,7 @@ struct GraphicsPrivate {
screen(scRes.x, scRes.y), threadData(rtData), screen(scRes.x, scRes.y), threadData(rtData),
glCtx(SDL_GL_GetCurrentContext()), frameRate(DEF_FRAMERATE), glCtx(SDL_GL_GetCurrentContext()), frameRate(DEF_FRAMERATE),
frameCount(0), brightness(255), fpsLimiter(frameRate), frameCount(0), brightness(255), fpsLimiter(frameRate),
useFrameSkip(rtData->config.frameSkip), frozen(false) { useFrameSkip(rtData->config.frameSkip), frozen(false), last_update() {
recalculateScreenSize(rtData); recalculateScreenSize(rtData);
updateScreenResoRatio(rtData); updateScreenResoRatio(rtData);
@ -584,6 +587,10 @@ Graphics::Graphics(RGSSThreadData *data) {
Graphics::~Graphics() { delete p; } Graphics::~Graphics() { delete p; }
unsigned long long Graphics::getDelta() {
return shState->runTime() - p->last_update;
}
void Graphics::update() { void Graphics::update() {
p->checkShutDownReset(); p->checkShutDownReset();
p->checkSyncLock(); p->checkSyncLock();
@ -612,6 +619,7 @@ void Graphics::update() {
p->checkResize(); p->checkResize();
p->redrawScreen(); p->redrawScreen();
p->last_update = shState->runTime();
} }
void Graphics::freeze() { void Graphics::freeze() {

View file

@ -34,6 +34,8 @@ struct AtomicFlag;
class Graphics class Graphics
{ {
public: public:
unsigned long long getDelta();
void update(); void update();
void freeze(); void freeze();
void transition(int duration = 8, void transition(int duration = 8,

View file

@ -680,9 +680,13 @@ struct InputPrivate
int rawRepeating; int rawRepeating;
unsigned int repeatCount; unsigned int repeatCount;
unsigned int rawRepeatCount; unsigned int rawRepeatCount;
unsigned long long repeatTime;
unsigned long long rawRepeatTime;
unsigned int repeatStart; unsigned int repeatStart;
unsigned int repeatDelay; unsigned int repeatDelay;
unsigned long long last_update;
struct struct
{ {
@ -708,6 +712,8 @@ struct InputPrivate
InputPrivate(const RGSSThreadData &rtData) InputPrivate(const RGSSThreadData &rtData)
{ {
last_update = 0;
initStaticKbBindings(); initStaticKbBindings();
initMsBindings(); initMsBindings();
@ -1005,12 +1011,15 @@ struct InputPrivate
else else
{ {
rawRepeatCount = 0; rawRepeatCount = 0;
rawRepeatTime = shState->runTime();
rawRepeating = i; rawRepeating = i;
} }
break; return;
} }
} }
rawRepeating = -1;
} }
void updateDir4() void updateDir4()
@ -1101,6 +1110,10 @@ Input::Input(const RGSSThreadData &rtData)
p = new InputPrivate(rtData); p = new InputPrivate(rtData);
} }
unsigned long long Input::getDelta() {
return shState->runTime() - p->last_update;
}
void Input::recalcRepeat(unsigned int fps) { void Input::recalcRepeat(unsigned int fps) {
p->recalcRepeatTime(fps); p->recalcRepeatTime(fps);
} }
@ -1126,8 +1139,10 @@ void Input::update()
{ {
p->repeating = repeatCand; p->repeating = repeatCand;
p->repeatCount = 0; p->repeatCount = 0;
p->repeatTime = shState->runTime();
p->getState(repeatCand).repeated = true; p->getState(repeatCand).repeated = true;
p->last_update = p->repeatTime;
return; return;
} }
@ -1146,10 +1161,12 @@ void Input::update()
bool repeated = p->repeatCount >= p->repeatStart && ((p->repeatCount+1) & p->repeatDelay) == 0; bool repeated = p->repeatCount >= p->repeatStart && ((p->repeatCount+1) & p->repeatDelay) == 0;
p->getState(p->repeating).repeated |= repeated; p->getState(p->repeating).repeated |= repeated;
p->last_update = shState->runTime();
return; return;
} }
p->repeating = None; p->repeating = None;
p->last_update = shState->runTime();
} }
std::vector<std::string> Input::getBindings(ButtonCode code) { std::vector<std::string> Input::getBindings(ButtonCode code) {
@ -1203,6 +1220,13 @@ unsigned int Input::count(int button) {
return p->repeatCount; return p->repeatCount;
} }
unsigned long long Input::repeatTime(int button) {
if (button != p->repeating)
return 0;
return shState->runTime() - p->repeatTime;
}
bool Input::isPressedEx(int code, bool isVKey) bool Input::isPressedEx(int code, bool isVKey)
{ {
return p->getStateRaw(code, isVKey).pressed; return p->getStateRaw(code, isVKey).pressed;
@ -1239,6 +1263,19 @@ unsigned int Input::repeatcount(int code, bool isVKey) {
return p->rawRepeatCount; return p->rawRepeatCount;
} }
unsigned long long Input::repeatTimeEx(int code, bool isVKey) {
int c = code;
if (isVKey) {
try { c = vKeyToScancode[code]; }
catch (...) { return 0; }
}
if (c != p->rawRepeating)
return 0;
return shState->runTime() - p->rawRepeatTime;
}
int Input::dir4Value() int Input::dir4Value()
{ {
return p->dir4Data.active; return p->dir4Data.active;

View file

@ -55,6 +55,7 @@ public:
void recalcRepeat(unsigned int fps); void recalcRepeat(unsigned int fps);
unsigned long long getDelta();
void update(); void update();
std::vector<std::string> getBindings(ButtonCode code); std::vector<std::string> getBindings(ButtonCode code);
@ -64,11 +65,13 @@ public:
bool isRepeated(int button); bool isRepeated(int button);
bool isReleased(int button); bool isReleased(int button);
unsigned int count(int button); unsigned int count(int button);
unsigned long long repeatTime(int button);
bool isPressedEx(int code, bool isVKey); bool isPressedEx(int code, bool isVKey);
bool isTriggeredEx(int code, bool isVKey); bool isTriggeredEx(int code, bool isVKey);
bool isRepeatedEx(int code, bool isVKey); bool isRepeatedEx(int code, bool isVKey);
bool isReleasedEx(int code, bool isVKey); bool isReleasedEx(int code, bool isVKey);
unsigned int repeatcount(int code, bool isVKey); unsigned int repeatcount(int code, bool isVKey);
unsigned long long repeatTimeEx(int code, bool isVKey);
int dir4Value(); int dir4Value();
int dir8Value(); int dir8Value();

View file

@ -41,6 +41,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <chrono>
SharedState *SharedState::instance = 0; SharedState *SharedState::instance = 0;
int SharedState::rgssVersion = 0; int SharedState::rgssVersion = 0;
@ -97,6 +98,8 @@ struct SharedStatePrivate
Quad gpQuad; Quad gpQuad;
unsigned int stampCounter; unsigned int stampCounter;
std::chrono::time_point<std::chrono::high_resolution_clock> startupTime;
SharedStatePrivate(RGSSThreadData *threadData) SharedStatePrivate(RGSSThreadData *threadData)
: bindingData(0), : bindingData(0),
@ -113,6 +116,9 @@ struct SharedStatePrivate
fontState(threadData->config), fontState(threadData->config),
stampCounter(0) stampCounter(0)
{ {
startupTime = std::chrono::high_resolution_clock::now();
/* Shaders have been compiled in ShaderSet's constructor */ /* Shaders have been compiled in ShaderSet's constructor */
if (gl.ReleaseShaderCompiler) if (gl.ReleaseShaderCompiler)
gl.ReleaseShaderCompiler(); gl.ReleaseShaderCompiler();
@ -357,6 +363,12 @@ Font &SharedState::defaultFont() const
return *p->defaultFont; return *p->defaultFont;
} }
unsigned long long SharedState::runTime() {
if (!p) return 0;
const auto now = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(now - p->startupTime).count();
}
unsigned int SharedState::genTimeStamp() unsigned int SharedState::genTimeStamp()
{ {
return p->stampCounter++; return p->stampCounter++;

View file

@ -84,6 +84,9 @@ struct SharedState
sigc::signal<void> prepareDraw; sigc::signal<void> prepareDraw;
unsigned int genTimeStamp(); unsigned int genTimeStamp();
// Returns time since SharedState was constructed in microseconds
unsigned long long runTime();
/* Returns global quad IBO, and ensures it has indices /* Returns global quad IBO, and ensures it has indices
* for at least minSize quads */ * for at least minSize quads */