Mercurial > love-experiments
annotate src/common/runtime.cpp @ 1098:a74672ba1320 minor
Merge in channels from love-experiments
Rewritten love.thread and changed communication
method from weird system before, to channels.
| author | Bart van Strien <bart.bes+projects@gmail.com> |
|---|---|
| date | Wed, 04 Jul 2012 17:15:16 +0200 |
| parents | 86a44f2bc38f |
| children | 7c7332becb70 |
| rev | line source |
|---|---|
| 1096 | 1 /** |
| 2 * Copyright (c) 2006-2012 LOVE Development Team | |
| 3 * | |
| 4 * This software is provided 'as-is', without any express or implied | |
| 5 * warranty. In no event will the authors be held liable for any damages | |
| 6 * arising from the use of this software. | |
| 7 * | |
| 8 * Permission is granted to anyone to use this software for any purpose, | |
| 9 * including commercial applications, and to alter it and redistribute it | |
| 10 * freely, subject to the following restrictions: | |
| 11 * | |
| 12 * 1. The origin of this software must not be misrepresented; you must not | |
| 13 * claim that you wrote the original software. If you use this software | |
| 14 * in a product, an acknowledgment in the product documentation would be | |
| 15 * appreciated but is not required. | |
| 16 * 2. Altered source versions must be plainly marked as such, and must not be | |
| 17 * misrepresented as being the original software. | |
| 18 * 3. This notice may not be removed or altered from any source distribution. | |
| 19 **/ | |
| 20 | |
| 21 #include "runtime.h" | |
| 22 | |
| 23 // LOVE | |
| 24 #include "Module.h" | |
| 25 #include "Object.h" | |
| 26 #include "Reference.h" | |
| 27 #include "StringMap.h" | |
|
1098
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
28 #include <thread/threads.h> |
| 1096 | 29 |
| 30 // STD | |
| 31 #include <iostream> | |
| 32 | |
| 33 namespace love | |
| 34 { | |
| 35 | |
| 36 static thread::Mutex *gcmutex = 0; | |
| 37 void *_gcmutex = 0; | |
| 38 /** | |
| 39 * Called when an object is collected. The object is released | |
| 40 * once in this function, possibly deleting it. | |
| 41 **/ | |
| 42 static int w__gc(lua_State *L) | |
| 43 { | |
| 44 if (!gcmutex) | |
| 45 { | |
|
1098
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
46 gcmutex = thread::newMutex(); |
| 1096 | 47 _gcmutex = (void *) gcmutex; |
| 48 } | |
| 49 Proxy *p = (Proxy *)lua_touserdata(L, 1); | |
| 50 Object *t = (Object *)p->data; | |
| 51 if (p->own) | |
| 52 { | |
| 53 thread::Lock lock(gcmutex); | |
| 54 t->release(); | |
| 55 } | |
| 56 return 0; | |
| 57 } | |
| 58 | |
| 59 static int w__tostring(lua_State *L) | |
| 60 { | |
| 61 lua_pushvalue(L, lua_upvalueindex(1)); | |
| 62 return 1; | |
| 63 } | |
| 64 | |
| 65 static int w__typeOf(lua_State *L) | |
| 66 { | |
| 67 Proxy *p = (Proxy *)lua_touserdata(L, 1); | |
| 68 Type t = luax_type(L, 2); | |
| 69 luax_pushboolean(L, p->flags[t]); | |
| 70 return 1; | |
| 71 } | |
| 72 | |
| 73 static int w__eq(lua_State *L) | |
| 74 { | |
| 75 Proxy *p1 = (Proxy *)lua_touserdata(L, 1); | |
| 76 Proxy *p2 = (Proxy *)lua_touserdata(L, 2); | |
| 77 luax_pushboolean(L, p1->data == p2->data); | |
| 78 return 1; | |
| 79 } | |
| 80 | |
| 81 Reference *luax_refif (lua_State *L, int type) | |
| 82 { | |
| 83 Reference *r = 0; | |
| 84 | |
| 85 // Create a reference only if the test succeeds. | |
| 86 if (lua_type(L, -1) == type) | |
| 87 r = new Reference(L); | |
| 88 else // Pop the value even if it fails (but also if it succeeds). | |
| 89 lua_pop(L, 1); | |
| 90 | |
| 91 return r; | |
| 92 } | |
| 93 | |
| 94 void luax_printstack(lua_State *L) | |
| 95 { | |
| 96 for (int i = 1; i<=lua_gettop(L); i++) | |
| 97 { | |
| 98 std::cout << i << " - " << luaL_typename(L, i) << std::endl; | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 bool luax_toboolean(lua_State *L, int idx) | |
| 103 { | |
| 104 return (lua_toboolean(L, idx) != 0); | |
| 105 } | |
| 106 | |
| 107 void luax_pushboolean(lua_State *L, bool b) | |
| 108 { | |
| 109 lua_pushboolean(L, b ? 1 : 0); | |
| 110 } | |
| 111 | |
| 112 bool luax_optboolean(lua_State *L, int idx, bool b) | |
| 113 { | |
| 114 if (lua_isboolean(L, idx) == 1) | |
| 115 return (lua_toboolean(L, idx) == 1 ? true : false); | |
| 116 return b; | |
| 117 } | |
| 118 | |
|
1098
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
119 std::string luax_tostring(lua_State *L, int idx) |
|
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
120 { |
|
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
121 size_t len; |
|
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
122 const char *str = lua_tolstring(L, idx, &len); |
|
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
123 return std::string(str, len); |
|
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
124 } |
|
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
125 |
| 1096 | 126 std::string luax_checkstring(lua_State *L, int idx) |
| 127 { | |
| 128 size_t len; | |
| 129 const char *str = luaL_checklstring(L, idx, &len); | |
| 130 return std::string(str, len); | |
| 131 } | |
| 132 | |
| 133 void luax_pushstring(lua_State *L, std::string str) | |
| 134 { | |
| 135 lua_pushlstring(L, str.data(), str.size()); | |
| 136 } | |
| 137 | |
| 138 int luax_assert_argc(lua_State *L, int min) | |
| 139 { | |
| 140 int argc = lua_gettop(L); | |
| 141 if (argc < min) | |
| 142 return luaL_error(L, "Incorrect number of arguments. Got [%d], expected at least [%d]", argc, min); | |
| 143 return 0; | |
| 144 } | |
| 145 | |
| 146 int luax_assert_argc(lua_State *L, int min, int max) | |
| 147 { | |
| 148 int argc = lua_gettop(L); | |
| 149 if (argc < min || argc > max) | |
| 150 return luaL_error(L, "Incorrect number of arguments. Got [%d], expected [%d-%d]", argc, min, max); | |
| 151 return 0; | |
| 152 } | |
| 153 | |
| 154 int luax_assert_function(lua_State *L, int n) | |
| 155 { | |
| 156 if (!lua_isfunction(L, n)) | |
| 157 return luaL_error(L, "Argument must be of type \"function\"."); | |
| 158 return 0; | |
| 159 } | |
| 160 | |
| 161 int luax_register_module(lua_State *L, const WrappedModule &m) | |
| 162 { | |
| 163 // Put a reference to the C++ module in Lua. | |
| 164 luax_getregistry(L, REGISTRY_MODULES); | |
| 165 | |
| 166 Proxy *p = (Proxy *)lua_newuserdata(L, sizeof(Proxy)); | |
| 167 p->own = true; | |
| 168 p->data = m.module; | |
| 169 p->flags = m.flags; | |
| 170 | |
| 171 luaL_newmetatable(L, m.module->getName()); | |
| 172 lua_pushvalue(L, -1); | |
| 173 lua_setfield(L, -2, "__index"); | |
| 174 lua_pushcfunction(L, w__gc); | |
| 175 lua_setfield(L, -2, "__gc"); | |
| 176 | |
| 177 lua_setmetatable(L, -2); | |
| 178 lua_setfield(L, -2, m.name); // _modules[name] = proxy | |
| 179 lua_pop(L, 1); | |
| 180 | |
| 181 // Gets the love table. | |
| 182 luax_insistglobal(L, "love"); | |
| 183 | |
| 184 // Create new table for module. | |
| 185 lua_newtable(L); | |
| 186 | |
| 187 // Register all the functions. | |
| 188 luaL_register(L, 0, m.functions); | |
| 189 | |
| 190 // Register types. | |
| 191 if (m.types != 0) | |
| 192 for (const lua_CFunction *t = m.types; *t != 0; t++) | |
| 193 (*t)(L); | |
| 194 | |
| 195 lua_pushvalue(L, -1); | |
| 196 lua_setfield(L, -3, m.name); // love.graphics = table | |
| 197 lua_remove(L, -2); // love | |
| 198 | |
| 199 return 1; | |
| 200 } | |
| 201 | |
| 202 int luax_preload(lua_State *L, lua_CFunction f, const char *name) | |
| 203 { | |
| 204 lua_getglobal(L, "package"); | |
| 205 lua_getfield(L, -1, "preload"); | |
| 206 lua_pushcfunction(L, f); | |
| 207 lua_setfield(L, -2, name); | |
| 208 lua_pop(L, 2); | |
| 209 return 0; | |
| 210 } | |
| 211 | |
| 212 int luax_register_type(lua_State *L, const char *tname, const luaL_Reg *f) | |
| 213 { | |
| 214 luaL_newmetatable(L, tname); | |
| 215 | |
| 216 // m.__index = m | |
| 217 lua_pushvalue(L, -1); | |
| 218 lua_setfield(L, -2, "__index"); | |
| 219 | |
| 220 // setup gc | |
| 221 lua_pushcfunction(L, w__gc); | |
| 222 lua_setfield(L, -2, "__gc"); | |
| 223 | |
| 224 // Add equality | |
| 225 lua_pushcfunction(L, w__eq); | |
| 226 lua_setfield(L, -2, "__eq"); | |
| 227 | |
| 228 // Add tostring function. | |
| 229 lua_pushstring(L, tname); | |
| 230 lua_pushcclosure(L, w__tostring, 1); | |
| 231 lua_setfield(L, -2, "__tostring"); | |
| 232 | |
| 233 // Add tostring to as type() as well. | |
| 234 lua_pushstring(L, tname); | |
| 235 lua_pushcclosure(L, w__tostring, 1); | |
| 236 lua_setfield(L, -2, "type"); | |
| 237 | |
| 238 // Add typeOf | |
| 239 lua_pushcfunction(L, w__typeOf); | |
| 240 lua_setfield(L, -2, "typeOf"); | |
| 241 | |
| 242 if (f != 0) | |
| 243 luaL_register(L, 0, f); | |
| 244 | |
| 245 lua_pop(L, 1); // Pops metatable. | |
| 246 return 0; | |
| 247 } | |
| 248 | |
| 249 int luax_table_insert(lua_State *L, int tindex, int vindex, int pos) | |
| 250 { | |
| 251 if (tindex < 0) | |
| 252 tindex = lua_gettop(L)+1+tindex; | |
| 253 if (vindex < 0) | |
| 254 vindex = lua_gettop(L)+1+vindex; | |
| 255 if (pos == -1) | |
| 256 { | |
| 257 lua_pushvalue(L, vindex); | |
| 258 lua_rawseti(L, tindex, lua_objlen(L, tindex)+1); | |
| 259 return 0; | |
| 260 } | |
| 261 else if (pos < 0) | |
| 262 pos = lua_objlen(L, tindex)+1+pos; | |
| 263 for (int i = lua_objlen(L, tindex)+1; i > pos; i--) | |
| 264 { | |
| 265 lua_rawgeti(L, tindex, i-1); | |
| 266 lua_rawseti(L, tindex, i); | |
| 267 } | |
| 268 lua_pushvalue(L, vindex); | |
| 269 lua_rawseti(L, tindex, pos); | |
| 270 return 0; | |
| 271 } | |
| 272 | |
| 273 int luax_register_searcher(lua_State *L, lua_CFunction f, int pos) | |
| 274 { | |
| 275 // Add the package loader to the package.loaders table. | |
| 276 lua_getglobal(L, "package"); | |
| 277 | |
| 278 if (lua_isnil(L, -1)) | |
| 279 return luaL_error(L, "Can't register searcher: package table does not exist."); | |
| 280 | |
| 281 lua_getfield(L, -1, "loaders"); | |
| 282 | |
| 283 if (lua_isnil(L, -1)) | |
| 284 return luaL_error(L, "Can't register searcher: package.loaders table does not exist."); | |
| 285 | |
| 286 lua_pushcfunction(L, f); | |
| 287 luax_table_insert(L, -2, -1, pos); | |
| 288 lua_pop(L, 3); | |
| 289 return 0; | |
| 290 } | |
| 291 | |
| 292 void luax_newtype(lua_State *L, const char *name, bits flags, void *data, bool own) | |
| 293 { | |
| 294 Proxy *u = (Proxy *)lua_newuserdata(L, sizeof(Proxy)); | |
| 295 | |
| 296 u->data = data; | |
| 297 u->flags = flags; | |
| 298 u->own = own; | |
| 299 | |
| 300 luaL_newmetatable(L, name); | |
| 301 lua_setmetatable(L, -2); | |
| 302 } | |
| 303 | |
| 304 bool luax_istype(lua_State *L, int idx, love::bits type) | |
| 305 { | |
| 306 if (lua_isuserdata(L, idx) == 0) | |
| 307 return false; | |
| 308 | |
| 309 return ((((Proxy *)lua_touserdata(L, idx))->flags & type) == type); | |
| 310 } | |
| 311 | |
| 312 int luax_getfunction(lua_State *L, const char *mod, const char *fn) | |
| 313 { | |
| 314 lua_getglobal(L, "love"); | |
| 315 if (lua_isnil(L, -1)) return luaL_error(L, "Could not find global love!"); | |
| 316 lua_getfield(L, -1, mod); | |
| 317 if (lua_isnil(L, -1)) return luaL_error(L, "Could not find love.%s!", mod); | |
| 318 lua_getfield(L, -1, fn); | |
| 319 if (lua_isnil(L, -1)) return luaL_error(L, "Could not find love.%s.%s!", mod, fn); | |
| 320 | |
| 321 lua_remove(L, -2); // remove mod | |
| 322 lua_remove(L, -2); // remove fn | |
| 323 return 0; | |
| 324 } | |
| 325 | |
| 326 int luax_convobj(lua_State *L, int idx, const char *mod, const char *fn) | |
| 327 { | |
| 328 // Convert string to a file. | |
| 329 luax_getfunction(L, mod, fn); | |
| 330 lua_pushvalue(L, idx); // The initial argument. | |
| 331 lua_call(L, 1, 1); // Call the function, one arg, one return value. | |
| 332 lua_replace(L, idx); // Replace the initial argument with the new object. | |
| 333 return 0; | |
| 334 } | |
| 335 | |
| 336 int luax_convobj(lua_State *L, int idxs[], int n, const char *mod, const char *fn) | |
| 337 { | |
| 338 luax_getfunction(L, mod, fn); | |
| 339 for (int i = 0; i < n; i++) | |
| 340 { | |
| 341 lua_pushvalue(L, idxs[i]); // The arguments. | |
| 342 } | |
| 343 lua_call(L, n, 1); // Call the function, n args, one return value. | |
| 344 lua_replace(L, idxs[0]); // Replace the initial argument with the new object. | |
| 345 return 0; | |
| 346 } | |
| 347 | |
| 348 int luax_strtofile(lua_State *L, int idx) | |
| 349 { | |
| 350 return luax_convobj(L, idx, "filesystem", "newFile"); | |
| 351 } | |
| 352 | |
| 353 int luax_filetodata(lua_State *L, int idx) | |
| 354 { | |
| 355 return luax_convobj(L, idx, "filesystem", "read"); | |
| 356 } | |
| 357 | |
| 358 int luax_insist(lua_State *L, int idx, const char *k) | |
| 359 { | |
| 360 // Convert to absolute index if necessary. | |
| 361 if (idx < 0 && idx > LUA_REGISTRYINDEX) | |
| 362 idx = lua_gettop(L) + ++idx; | |
| 363 | |
| 364 lua_getfield(L, idx, k); | |
| 365 | |
| 366 // Create if necessary. | |
| 367 if (!lua_istable(L, -1)) | |
| 368 { | |
| 369 lua_pop(L, 1); // Pop the non-table. | |
| 370 lua_newtable(L); | |
| 371 lua_pushvalue(L, -1); // Duplicate the table to leave on top. | |
| 372 lua_setfield(L, idx, k); // lua_stack[idx][k] = lua_stack[-1] (table) | |
| 373 } | |
| 374 | |
| 375 return 1; | |
| 376 } | |
| 377 | |
| 378 int luax_insistglobal(lua_State *L, const char *k) | |
| 379 { | |
| 380 lua_getglobal(L, k); | |
| 381 | |
| 382 if (!lua_istable(L, -1)) | |
| 383 { | |
| 384 lua_pop(L, 1); // Pop the non-table. | |
| 385 lua_newtable(L); | |
| 386 lua_pushvalue(L, -1); | |
| 387 lua_setglobal(L, k); | |
| 388 } | |
| 389 | |
| 390 return 1; | |
| 391 } | |
| 392 | |
| 393 int luax_insistlove(lua_State *L, const char *k) | |
| 394 { | |
| 395 luax_insistglobal(L, "love"); | |
| 396 luax_insist(L, -1, k); | |
| 397 | |
| 398 // The love table should be replaced with the top stack | |
| 399 // item. Only the reqested table should remain on the stack. | |
| 400 lua_replace(L, -2); | |
| 401 | |
| 402 return 1; | |
| 403 } | |
| 404 | |
| 405 int luax_getregistry(lua_State *L, Registry r) | |
| 406 { | |
| 407 switch (r) | |
| 408 { | |
| 409 case REGISTRY_GC: | |
| 410 return luax_insistlove(L, "_gc"); | |
| 411 case REGISTRY_MODULES: | |
| 412 return luax_insistlove(L, "_modules"); | |
| 413 default: | |
| 414 return luaL_error(L, "Attempted to use invalid registry."); | |
| 415 } | |
| 416 } | |
| 417 | |
| 418 StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[] = | |
| 419 { | |
| 420 {"Invalid", INVALID_ID}, | |
| 421 | |
| 422 {"Object", OBJECT_ID}, | |
| 423 {"Data", DATA_ID}, | |
| 424 {"Module", MODULE_ID}, | |
| 425 | |
| 426 // Filesystem | |
| 427 {"File", FILESYSTEM_FILE_ID}, | |
| 428 {"FileData", FILESYSTEM_FILE_DATA_ID}, | |
| 429 | |
| 430 // Font | |
| 431 {"GlyphData", FONT_GLYPH_DATA_ID}, | |
| 432 {"Rasterizer", FONT_RASTERIZER_ID}, | |
| 433 | |
| 434 // Graphics | |
| 435 {"Drawable", GRAPHICS_DRAWABLE_ID}, | |
| 436 {"Image", GRAPHICS_IMAGE_ID}, | |
| 437 {"Quad", GRAPHICS_QUAD_ID}, | |
| 438 {"Font", GRAPHICS_FONT_ID}, | |
| 439 {"ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_ID}, | |
| 440 {"SpriteBatch", GRAPHICS_SPRITE_BATCH_ID}, | |
| 441 {"Canvas", GRAPHICS_CANVAS_ID}, | |
| 442 | |
| 443 // Image | |
| 444 {"ImageData", IMAGE_IMAGE_DATA_ID}, | |
| 445 | |
| 446 // Audio | |
| 447 {"Source", AUDIO_SOURCE_ID}, | |
| 448 | |
| 449 // Sound | |
| 450 {"SoundData", SOUND_SOUND_DATA_ID}, | |
| 451 {"Decoder", SOUND_DECODER_ID}, | |
| 452 | |
| 453 // Physics | |
| 454 {"World", PHYSICS_WORLD_ID}, | |
| 455 {"Contact", PHYSICS_CONTACT_ID}, | |
| 456 {"Body", PHYSICS_BODY_ID}, | |
| 457 {"Shape", PHYSICS_SHAPE_ID}, | |
| 458 {"CircleShape", PHYSICS_CIRCLE_SHAPE_ID}, | |
| 459 {"PolygonShape", PHYSICS_POLYGON_SHAPE_ID}, | |
| 460 {"Joint", PHYSICS_JOINT_ID}, | |
| 461 {"MouseJoint", PHYSICS_MOUSE_JOINT_ID}, | |
| 462 {"DistanceJoint", PHYSICS_DISTANCE_JOINT_ID}, | |
| 463 {"PrismaticJoint", PHYSICS_PRISMATIC_JOINT_ID}, | |
| 464 {"RevoluteJoint", PHYSICS_REVOLUTE_JOINT_ID}, | |
| 465 {"PulleyJoint", PHYSICS_PULLEY_JOINT_ID}, | |
| 466 {"GearJoint", PHYSICS_GEAR_JOINT_ID}, | |
| 467 | |
| 468 // Thread | |
| 469 {"Thread", THREAD_THREAD_ID}, | |
|
1098
a74672ba1320
Merge in channels from love-experiments
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
470 {"Channel", THREAD_CHANNEL_ID}, |
| 1096 | 471 |
| 472 // The modules themselves. Only add abstracted modules here. | |
| 473 {"filesystem", MODULE_FILESYSTEM_ID}, | |
| 474 {"image", MODULE_IMAGE_ID}, | |
| 475 {"sound", MODULE_SOUND_ID}, | |
| 476 }; | |
| 477 | |
| 478 StringMap<Type, TYPE_MAX_ENUM> types(typeEntries, sizeof(typeEntries)); | |
| 479 | |
| 480 Type luax_type(lua_State *L, int idx) | |
| 481 { | |
| 482 Type t = INVALID_ID; | |
| 483 types.find(luaL_checkstring(L, idx), t); | |
| 484 return t; | |
| 485 } | |
| 486 | |
| 487 } // love |
