mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
TWP: Test threads and breaktime
This commit is contained in:
1 parent
00274a3565
commit
4e27881da2
4 files changed
+403
-75
No files matched your search
+43
-29
@@ -64,7 +64,7 @@ Common::String TwpEngine::getGameId() const {
|
||||
Common::Error TwpEngine::run() {
|
||||
Graphics::PixelFormat fmt(4, 8, 8, 8, 8, 0, 8, 16, 24);
|
||||
initGraphics(1280, 720, &fmt);
|
||||
_screen = new Graphics::Screen();
|
||||
_screen = new Graphics::Screen(1280, 720, fmt);
|
||||
|
||||
XorKey key{{0x4F, 0xD0, 0xA0, 0xAC, 0x4A, 0x56, 0xB9, 0xE5, 0x93, 0x79, 0x45, 0xA5, 0xC1, 0xCB, 0x31, 0x93}, 0xAD};
|
||||
// XorKey key{{0x4F, 0xD0, 0xA0, 0xAC, 0x4A, 0x56, 0xB9, 0xE5, 0x93, 0x79, 0x45, 0xA5, 0xC1, 0xCB, 0x31, 0x93}, 0x6D};
|
||||
@@ -74,36 +74,39 @@ Common::Error TwpEngine::run() {
|
||||
Common::File f;
|
||||
f.open("ThimbleweedPark.ggpack1");
|
||||
|
||||
GGPackDecoder pack;
|
||||
pack.open(&f, key);
|
||||
Scene scene;
|
||||
scene.pack.open(&f, key);
|
||||
|
||||
GGPackEntryReader r;
|
||||
r.open(pack, "RaySheet.png");
|
||||
const SQChar *code = R"(
|
||||
function bounceImage() {
|
||||
local image = createObject("RaySheet", ["fstand_head1"]);
|
||||
local x = random(100, 1180);
|
||||
local y = random(100, 620);
|
||||
|
||||
Image::PNGDecoder d;
|
||||
d.loadStream(r);
|
||||
const Graphics::Surface *surface = d.getSurface();
|
||||
do {
|
||||
local steps = random(100, 150);
|
||||
local end_x = random(0, 1180);
|
||||
local end_y = random(0, 620);
|
||||
|
||||
GGPackEntryReader r2;
|
||||
r2.open(pack, "RaySheet.json");
|
||||
Common::Array<char> data(r2.size());
|
||||
r2.read(&data[0], r2.size());
|
||||
Common::String s(&data[0], r2.size());
|
||||
local dx = (end_x - x) / steps;
|
||||
local dy = (end_y - y) / steps;
|
||||
|
||||
Common::JSONValue *jRay = Common::JSON::parse(s.c_str());
|
||||
const Common::JSONObject &jRayObj = jRay->asObject();
|
||||
const Common::JSONObject &jFrames = jRayObj["frames"]->asObject();
|
||||
const Common::JSONObject &jFrame = jFrames["bstand_body1"]->asObject();
|
||||
const Common::JSONObject &jRect = jFrame["frame"]->asObject();
|
||||
for (local i = 0; i < steps; i++) {
|
||||
x += dx;
|
||||
y += dy;
|
||||
objectAt(image, x, y);
|
||||
breaktime(0.01);
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
int x = (int)jRect["x"]->asIntegerNumber();
|
||||
int y = (int)jRect["y"]->asIntegerNumber();
|
||||
int w = (int)jRect["w"]->asIntegerNumber();
|
||||
int h = (int)jRect["h"]->asIntegerNumber();
|
||||
Common::Rect rect(x, y, x + w, y + h);
|
||||
for (local i = 1; i <= 100; i++) {
|
||||
startthread(bounceImage);
|
||||
})";
|
||||
|
||||
Vm v;
|
||||
v.exec("print(\"Hello world \"+random(-2.7,8.6));\ncreateObject(\"RaySheet\",[\"bstand_body1\"]);");
|
||||
v.setScene(&scene);
|
||||
v.exec(code);
|
||||
|
||||
// Set the engine's debugger console
|
||||
setDebugger(new Console());
|
||||
@@ -113,21 +116,32 @@ Common::Error TwpEngine::run() {
|
||||
if (saveSlot != -1)
|
||||
(void)loadGameState(saveSlot);
|
||||
|
||||
_screen->copyRectToSurface(*surface, 1280 / 2, 720 / 2, rect);
|
||||
|
||||
_screen->update();
|
||||
|
||||
// Simple event handling loop
|
||||
Common::Event e;
|
||||
while (!shouldQuit()) {
|
||||
const uint deltaTimeMs = 10;
|
||||
while (g_system->getEventManager()->pollEvent(e)) {
|
||||
}
|
||||
|
||||
// update threads
|
||||
for (int i = 0; i < scene.threads.size(); i++) {
|
||||
Thread *thread = scene.threads[i];
|
||||
if (thread->update(deltaTimeMs)) {
|
||||
// TODO: delete it
|
||||
}
|
||||
}
|
||||
|
||||
// update screen
|
||||
_screen->clear(0xFF808080);
|
||||
for (int i = 0; i < scene.entities.size(); i++) {
|
||||
Entity &ett = scene.entities[i];
|
||||
_screen->transBlitFrom(ett.surface, ett.rect, Common::Point(ett.x, ett.y));
|
||||
}
|
||||
_screen->update();
|
||||
|
||||
// Delay for a bit. All events loops should have a delay
|
||||
// to prevent the system being unduly loaded
|
||||
g_system->delayMillis(10);
|
||||
g_system->delayMillis(deltaTimeMs);
|
||||
}
|
||||
|
||||
return Common::kNoError;
|
||||
|
||||
+2
-4
@@ -61,11 +61,9 @@ public:
|
||||
Common::String getGameId() const;
|
||||
|
||||
/**
|
||||
* Gets a random number
|
||||
* Gets the random source
|
||||
*/
|
||||
uint32 getRandomNumber(uint maxNum) {
|
||||
return _randomSource.getRandomNumber(maxNum);
|
||||
}
|
||||
Common::RandomSource& getRandomSource() { return _randomSource; }
|
||||
|
||||
bool hasFeature(EngineFeature f) const override {
|
||||
return
|
||||
|
||||
+310
-41
@@ -19,11 +19,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "twp/twp.h"
|
||||
#include "twp/vm.h"
|
||||
#include "common/array.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/random.h"
|
||||
#include "image/png.h"
|
||||
#include "squirrel/squirrel.h"
|
||||
#include "squirrel/sqvm.h"
|
||||
#include "squirrel/sqobject.h"
|
||||
@@ -34,33 +36,84 @@
|
||||
#include "squirrel/sqstdmath.h"
|
||||
#include "squirrel/sqstdio.h"
|
||||
#include "squirrel/sqstdaux.h"
|
||||
#include "squirrel/sqfuncproto.h"
|
||||
#include "squirrel/sqclosure.h"
|
||||
|
||||
namespace Twp {
|
||||
|
||||
static SQRESULT get(HSQUIRRELVM v, int i, std::string &value) {
|
||||
static Scene *gScene = nullptr;
|
||||
static HSQUIRRELVM gVm = nullptr;
|
||||
|
||||
static SQObjectPtr sqObj(HSQUIRRELVM v, const char *value) {
|
||||
SQObjectPtr string = SQString::Create(_ss(v), value);
|
||||
return string;
|
||||
}
|
||||
|
||||
static inline SQObject sqObj(HSQUIRRELVM v, int value) {
|
||||
SQObject o;
|
||||
o._type = OT_INTEGER;
|
||||
o._unVal.nInteger = value;
|
||||
return o;
|
||||
}
|
||||
|
||||
static SQRESULT get(HSQUIRRELVM v, int i, Common::String &value) {
|
||||
const SQChar *val;
|
||||
SQRESULT result = sq_getstring(v, i, &val);
|
||||
value = val;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void getArray(HSQUIRRELVM v, HSQOBJECT o, std::vector<std::string> &arr) {
|
||||
sq_pushobject(v, o);
|
||||
sq_pushnull(v);
|
||||
while(SQ_SUCCEEDED(sq_next(v, -2))) {
|
||||
const SQChar* str;
|
||||
sq_getstring(v, -1, &str);
|
||||
arr.push_back(str);
|
||||
sq_pop(v, 2);
|
||||
}
|
||||
sq_pop(v, 1);
|
||||
static void getArray(HSQUIRRELVM v, HSQOBJECT o, Common::Array<Common::String> &arr) {
|
||||
sq_pushobject(v, o);
|
||||
sq_pushnull(v);
|
||||
while (SQ_SUCCEEDED(sq_next(v, -2))) {
|
||||
const SQChar *str;
|
||||
sq_getstring(v, -1, &str);
|
||||
arr.push_back(str);
|
||||
sq_pop(v, 2);
|
||||
}
|
||||
sq_pop(v, 1);
|
||||
}
|
||||
|
||||
static SQRESULT getArray(HSQUIRRELVM v, int i, std::vector<std::string> &arr) {
|
||||
HSQOBJECT obj;
|
||||
SQRESULT result = sq_getstackobj(v, i, &obj);
|
||||
getArray(v, obj, arr);
|
||||
return result;
|
||||
static SQRESULT getArray(HSQUIRRELVM v, int i, Common::Array<Common::String> &arr) {
|
||||
HSQOBJECT obj;
|
||||
SQRESULT result = sq_getstackobj(v, i, &obj);
|
||||
getArray(v, obj, arr);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Thread *thread(HSQUIRRELVM v) {
|
||||
return *Common::find_if(gScene->threads.begin(), gScene->threads.end(), [&](Thread *t) {
|
||||
return t->threadObj._unVal.pThread == v;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static SQInteger breakfunc(HSQUIRRELVM v, const F &func) {
|
||||
Thread *t = thread(v);
|
||||
if (!t)
|
||||
return sq_throwerror(v, "failed to get thread");
|
||||
t->suspend();
|
||||
func(*t);
|
||||
return -666;
|
||||
}
|
||||
|
||||
// When called in a function started with startthread, execution is suspended for time seconds.
|
||||
// It is an error to call breaktime in a function that was not started with startthread.
|
||||
//
|
||||
// . code-block:: Squirrel
|
||||
// for (local x = 1; x < 4; x += 1) {
|
||||
// playSound(soundPhoneRinging)
|
||||
// breaktime(5.0)
|
||||
// }
|
||||
static SQInteger breaktime(HSQUIRRELVM v) {
|
||||
SQFloat time;
|
||||
if (SQ_FAILED(sq_getfloat(v, 2, &time)))
|
||||
return sq_throwerror(v, "failed to get time");
|
||||
if (time == 0.f)
|
||||
return breakfunc(v, [](Thread &t) { t.numFrames = 1; });
|
||||
else
|
||||
return breakfunc(v, [&](Thread &t) { t.waitTime = time; });
|
||||
}
|
||||
|
||||
// Returns a random number from from to to inclusively.
|
||||
@@ -69,14 +122,13 @@ static SQRESULT getArray(HSQUIRRELVM v, int i, std::vector<std::string> &arr) {
|
||||
// .. code-block:: Squirrel
|
||||
// wait_time = random(0.5, 2.0)
|
||||
static SQInteger sq_random(HSQUIRRELVM v) {
|
||||
Common::RandomSource rnd("twp");
|
||||
if (sq_gettype(v, 2) == OT_FLOAT || sq_gettype(v, 3) == OT_FLOAT) {
|
||||
SQFloat min, max;
|
||||
sq_getfloat(v, 2, &min);
|
||||
sq_getfloat(v, 3, &max);
|
||||
if (min > max)
|
||||
SWAP(min, max);
|
||||
float scale = rnd.getRandomNumber(RAND_MAX) / (float)RAND_MAX;
|
||||
float scale = g_engine->getRandomSource().getRandomNumber(RAND_MAX) / (float)RAND_MAX;
|
||||
SQFloat value = min + scale * (max - min);
|
||||
sq_pushfloat(v, value);
|
||||
} else {
|
||||
@@ -85,7 +137,7 @@ static SQInteger sq_random(HSQUIRRELVM v) {
|
||||
sq_getinteger(v, 3, &max);
|
||||
if (min > max)
|
||||
SWAP(min, max);
|
||||
SQInteger value = rnd.getRandomNumberRngSigned(min, max);
|
||||
SQInteger value = g_engine->getRandomSource().getRandomNumberRngSigned(min, max);
|
||||
sq_pushinteger(v, value);
|
||||
}
|
||||
return 1;
|
||||
@@ -99,8 +151,8 @@ static SQInteger sq_random(HSQUIRRELVM v) {
|
||||
// They do not have verbs or local variables by default, but these can be added when the object is created so it can be used in the construction of sentences.
|
||||
static SQInteger createObject(HSQUIRRELVM v) {
|
||||
SQInteger numArgs = sq_gettop(v);
|
||||
std::string sheet;
|
||||
std::vector<std::string> frames;
|
||||
Common::String sheet;
|
||||
Common::Array<Common::String> frames;
|
||||
SQInteger framesIndex = 2;
|
||||
|
||||
// get sheet parameter if any
|
||||
@@ -114,7 +166,7 @@ static SQInteger createObject(HSQUIRRELVM v) {
|
||||
if (numArgs >= 2) {
|
||||
switch (sq_gettype(v, framesIndex)) {
|
||||
case OT_STRING: {
|
||||
std::string frame;
|
||||
Common::String frame;
|
||||
get(v, framesIndex, frame);
|
||||
frames.push_back(frame);
|
||||
} break;
|
||||
@@ -126,12 +178,156 @@ static SQInteger createObject(HSQUIRRELVM v) {
|
||||
}
|
||||
}
|
||||
|
||||
debug("Create object: %s, %zu", sheet.c_str(), frames.size());
|
||||
// var obj = gEngine.room.createObject(sheet, frames)
|
||||
// push(v, obj.table)
|
||||
debug("Create object: %s, %u", sheet.c_str(), frames.size());
|
||||
|
||||
// TODO: share resources load png to surface
|
||||
GGPackEntryReader r;
|
||||
r.open(gScene->pack, sheet + ".png");
|
||||
Image::PNGDecoder d;
|
||||
d.loadStream(r);
|
||||
const Graphics::Surface *surface = d.getSurface();
|
||||
|
||||
// load sheet json
|
||||
GGPackEntryReader r2;
|
||||
r2.open(gScene->pack, sheet + ".json");
|
||||
Common::Array<char> data(r2.size());
|
||||
r2.read(&data[0], r2.size());
|
||||
Common::String s(&data[0], r2.size());
|
||||
|
||||
debug(s.c_str());
|
||||
|
||||
// TODO: change to load each frame
|
||||
Common::JSONValue *json = Common::JSON::parse(s.c_str());
|
||||
const Common::JSONObject &jRect = json->asObject()["frames"]->asObject()[frames[0]]->asObject()["frame"]->asObject();
|
||||
|
||||
int x = (int)jRect["x"]->asIntegerNumber();
|
||||
int y = (int)jRect["y"]->asIntegerNumber();
|
||||
int w = (int)jRect["w"]->asIntegerNumber();
|
||||
int h = (int)jRect["h"]->asIntegerNumber();
|
||||
|
||||
delete json;
|
||||
|
||||
// TODO: create an entity
|
||||
Entity e;
|
||||
e.surface.copyFrom(*surface);
|
||||
e.rect = Common::Rect(x, y, x + w, y + h);
|
||||
|
||||
static int gId = 3000;
|
||||
sq_newtable(v);
|
||||
sq_pushstring(v, _SC("_id"), -1);
|
||||
sq_pushinteger(v, gId++);
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_getstackobj(v, -1, &e.obj);
|
||||
sq_addref(gVm, &e.obj);
|
||||
sq_pop(v, 1);
|
||||
|
||||
gScene->entities.push_back(e);
|
||||
|
||||
sq_pushobject(v, e.obj);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger _startthread(HSQUIRRELVM v, bool global) {
|
||||
SQInteger size = sq_gettop(v);
|
||||
|
||||
Thread *t = new Thread();
|
||||
t->global = global;
|
||||
|
||||
static uint64 gThreadId = 300000;
|
||||
sq_newtable(v);
|
||||
sq_pushstring(v, _SC("_id"), -1);
|
||||
sq_pushinteger(v, gThreadId++);
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_getstackobj(v, -1, &t->obj);
|
||||
sq_addref(gVm, &t->obj);
|
||||
sq_pop(v, 1);
|
||||
|
||||
sq_resetobject(&t->envObj);
|
||||
if (SQ_FAILED(sq_getstackobj(v, 1, &t->envObj)))
|
||||
return sq_throwerror(v, "Couldn't get environment from stack");
|
||||
sq_addref(gVm, &t->envObj);
|
||||
|
||||
// create thread and store it on the stack
|
||||
sq_newthread(gVm, 1024);
|
||||
sq_resetobject(&t->threadObj);
|
||||
if (SQ_FAILED(sq_getstackobj(gVm, -1, &t->threadObj)))
|
||||
return sq_throwerror(v, "Couldn't get coroutine thread from stack");
|
||||
sq_addref(gVm, &t->threadObj);
|
||||
|
||||
for (int i = 0; i < size - 2; i++) {
|
||||
HSQOBJECT arg;
|
||||
sq_resetobject(&arg);
|
||||
if (SQ_FAILED(sq_getstackobj(v, 3 + i, &arg)))
|
||||
return sq_throwerror(v, "Couldn't get coroutine args from stack");
|
||||
t->args.push_back(arg);
|
||||
sq_addref(gVm, &arg);
|
||||
}
|
||||
|
||||
// get the closure
|
||||
sq_resetobject(&t->closureObj);
|
||||
if (SQ_FAILED(sq_getstackobj(v, 2, &t->closureObj)))
|
||||
return sq_throwerror(v, "Couldn't get coroutine thread from stack");
|
||||
sq_addref(gVm, &t->closureObj);
|
||||
|
||||
const SQChar *name = nullptr;
|
||||
if (SQ_SUCCEEDED(sq_getclosurename(v, 2)))
|
||||
sq_getstring(v, -1, &name);
|
||||
|
||||
t->name = Common::String::format("%s %s (%lld)", name == nullptr ? "<anonymous>" : name, _stringval(_closure(t->closureObj)->_function->_sourcename), _closure(t->closureObj)->_function->_lineinfos->_line);
|
||||
sq_pop(gVm, 1);
|
||||
if (name)
|
||||
sq_pop(v, 1); // pop name
|
||||
sq_pop(v, 1); // pop closure
|
||||
|
||||
gScene->threads.push_back(t);
|
||||
|
||||
debug("create thread %s", t->name.c_str());
|
||||
|
||||
// call the closure in the thread
|
||||
if (!t->call())
|
||||
return sq_throwerror(v, "call failed");
|
||||
|
||||
sq_pushobject(v, t->obj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQInteger startthread(HSQUIRRELVM v) {
|
||||
return _startthread(v, false);
|
||||
}
|
||||
|
||||
static SQInteger startglobalthread(HSQUIRRELVM v) {
|
||||
return _startthread(v, true);
|
||||
}
|
||||
|
||||
static SQInteger objectAt(HSQUIRRELVM v) {
|
||||
HSQOBJECT o;
|
||||
sq_getstackobj(v, 2, &o);
|
||||
|
||||
SQObjectPtr id;
|
||||
_table(o)->Get(sqObj(v, "_id"), id);
|
||||
|
||||
Entity *ett = Common::find_if(gScene->entities.begin(), gScene->entities.end(), [&](Entity &e) {
|
||||
SQObjectPtr id2;
|
||||
_table(e.obj)->Get(sqObj(v, "_id"), id2);
|
||||
return _integer(id) == _integer(id2);
|
||||
});
|
||||
|
||||
if (!ett)
|
||||
return sq_throwerror(v, "failed to get object");
|
||||
|
||||
SQInteger x, y;
|
||||
if (SQ_FAILED(sq_getinteger(v, 3, &x)))
|
||||
return sq_throwerror(v, "failed to get x");
|
||||
if (SQ_FAILED(sq_getinteger(v, 4, &y)))
|
||||
return sq_throwerror(v, "failed to get y");
|
||||
ett->x = x;
|
||||
ett->y = y;
|
||||
debug("Object at: %lld, %lld", x, y);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void regFunc(HSQUIRRELVM v, SQFUNCTION f, const SQChar *functionName, SQInteger nparamscheck, const SQChar *typemask) {
|
||||
sq_pushroottable(v);
|
||||
sq_pushstring(v, functionName, -1);
|
||||
@@ -142,18 +338,6 @@ static void regFunc(HSQUIRRELVM v, SQFUNCTION f, const SQChar *functionName, SQI
|
||||
sq_pop(v, 1); // pops the root table
|
||||
}
|
||||
|
||||
static SQObjectPtr sqObj(HSQUIRRELVM v, const char *value) {
|
||||
SQObjectPtr string = SQString::Create(_ss(v), value);
|
||||
return string;
|
||||
}
|
||||
|
||||
static inline SQObject sqObj(HSQUIRRELVM v, int value) {
|
||||
SQObject o;
|
||||
o._type = OT_INTEGER;
|
||||
o._unVal.nInteger = value;
|
||||
return o;
|
||||
}
|
||||
|
||||
static void sqExec(HSQUIRRELVM v, const char *code) {
|
||||
SQInteger top = sq_gettop(v);
|
||||
if (SQ_FAILED(sq_compilebuffer(v, code, strlen(code), "twp", SQTrue))) {
|
||||
@@ -202,23 +386,37 @@ static void printfunc(HSQUIRRELVM v, const SQChar *s, ...) {
|
||||
debug("TWP: %s", buf);
|
||||
}
|
||||
|
||||
Vm::Vm() {
|
||||
v = sq_open(1024);
|
||||
Vm::Vm()
|
||||
: _scene(nullptr) {
|
||||
gVm = v = sq_open(1024);
|
||||
sq_setcompilererrorhandler(v, errorHandler);
|
||||
sq_newclosure(v, aux_printerror, 0);
|
||||
sq_seterrorhandler(v);
|
||||
sq_setprintfunc(v, printfunc, printfunc);
|
||||
|
||||
sq_pushroottable(v);
|
||||
sqstd_register_stringlib(v);
|
||||
sqstd_register_mathlib(v);
|
||||
sqstd_register_iolib(v);
|
||||
sq_pop(v, 1);
|
||||
|
||||
regFunc(v, sq_random, _SC("random"), 0, nullptr);
|
||||
regFunc(v, createObject, _SC("createObject"), 0, nullptr);
|
||||
regFunc(v, startthread, _SC("startthread"), 0, nullptr);
|
||||
regFunc(v, startglobalthread, _SC("startglobalthread"), 0, nullptr);
|
||||
regFunc(v, objectAt, _SC("objectAt"), 0, nullptr);
|
||||
regFunc(v, breaktime, _SC("breaktime"), 0, nullptr);
|
||||
|
||||
SQObject platform = sqObj(v, 666);
|
||||
_table(v->_roottable)->NewSlot(sqObj(v, _SC("PLATFORM")), SQObjectPtr(platform));
|
||||
}
|
||||
|
||||
Vm::~Vm() {
|
||||
if(_scene) {
|
||||
for (int i = 0; i < _scene->threads.size(); i++) {
|
||||
delete _scene->threads[i];
|
||||
}
|
||||
}
|
||||
sq_close(v);
|
||||
}
|
||||
|
||||
@@ -226,4 +424,75 @@ void Vm::exec(const SQChar *code) {
|
||||
sqExec(v, code);
|
||||
}
|
||||
|
||||
void Vm::setScene(Scene *scene) {
|
||||
gScene = _scene = scene;
|
||||
}
|
||||
|
||||
Thread::Thread() : paused(false), waitTime(0), numFrames(0), stopRequest(false) {
|
||||
}
|
||||
|
||||
Thread::~Thread() {
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
sq_release(gVm, &args[i]);
|
||||
}
|
||||
sq_release(gVm, &threadObj);
|
||||
sq_release(gVm, &envObj);
|
||||
sq_release(gVm, &closureObj);
|
||||
}
|
||||
|
||||
bool Thread::call() {
|
||||
HSQUIRRELVM v = threadObj._unVal.pThread;
|
||||
// call the closure in the thread
|
||||
SQInteger top = sq_gettop(v);
|
||||
sq_pushobject(v, closureObj);
|
||||
sq_pushobject(v, envObj);
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
sq_pushobject(v, args[i]);
|
||||
}
|
||||
if (SQ_FAILED(sq_call(v, 1 + args.size(), SQFalse, SQTrue))) {
|
||||
sq_settop(v, top);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Thread::isDead() {
|
||||
SQInteger state = sq_getvmstate(threadObj._unVal.pThread);
|
||||
return stopRequest || state == 0;
|
||||
}
|
||||
|
||||
bool Thread::isSuspended() {
|
||||
SQInteger state = sq_getvmstate(threadObj._unVal.pThread);
|
||||
return state != 1;
|
||||
}
|
||||
|
||||
void Thread::suspend() {
|
||||
// TODO: pauseable
|
||||
if (!isSuspended()) {
|
||||
sq_suspendvm(threadObj._unVal.pThread);
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::resume() {
|
||||
if (!isDead() && isSuspended()) {
|
||||
sq_wakeupvm(threadObj._unVal.pThread, SQFalse, SQFalse, SQTrue, SQFalse);
|
||||
}
|
||||
}
|
||||
|
||||
bool Thread::update(float elapsed) {
|
||||
if (paused) {
|
||||
} else if (waitTime > 0) {
|
||||
waitTime -= elapsed;
|
||||
if (waitTime <= 0) {
|
||||
waitTime = 0;
|
||||
resume();
|
||||
}
|
||||
} else if (numFrames > 0) {
|
||||
numFrames -= 1;
|
||||
numFrames = 0;
|
||||
resume();
|
||||
}
|
||||
return isDead();
|
||||
}
|
||||
|
||||
} // namespace Twp
|
||||
+48
-1
@@ -22,17 +22,64 @@
|
||||
#ifndef TWPVM_H
|
||||
#define TWPVM_H
|
||||
|
||||
#include "squirrel/squirrel.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "twp/squirrel/squirrel.h"
|
||||
#include "twp/ggpack.h"
|
||||
|
||||
namespace Twp {
|
||||
class Entity {
|
||||
public:
|
||||
HSQOBJECT obj;
|
||||
Graphics::ManagedSurface surface;
|
||||
Common::Rect rect;
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
Thread();
|
||||
~Thread();
|
||||
|
||||
bool call();
|
||||
bool update(float elapsed);
|
||||
void suspend();
|
||||
void resume();
|
||||
bool isDead();
|
||||
bool isSuspended();
|
||||
|
||||
public:
|
||||
uint64 id;
|
||||
Common::String name;
|
||||
bool global;
|
||||
HSQOBJECT obj, threadObj, envObj, closureObj;
|
||||
Common::Array<HSQOBJECT> args;
|
||||
bool paused;
|
||||
float waitTime;
|
||||
int numFrames;
|
||||
bool stopRequest;
|
||||
};
|
||||
|
||||
class Scene {
|
||||
public:
|
||||
Common::Array<Entity> entities;
|
||||
Common::Array<Thread*> threads;
|
||||
GGPackDecoder pack;
|
||||
};
|
||||
|
||||
class Vm {
|
||||
public:
|
||||
Vm();
|
||||
~Vm();
|
||||
|
||||
void setScene(Scene* scene);
|
||||
void exec(const SQChar *code);
|
||||
|
||||
private:
|
||||
HSQUIRRELVM v;
|
||||
Scene* _scene;
|
||||
};
|
||||
} // End of namespace Twp
|
||||
|
||||
|
||||
Reference in new issue
Block a user