2317 lines
74 KiB
C++
2317 lines
74 KiB
C++
#include "lua.h"
|
|
#include "lua/lua.hpp"
|
|
#include "mini.h"
|
|
#include "jfile.h"
|
|
#include "log.h"
|
|
#include <filesystem>
|
|
#include <algorithm>
|
|
#include <vector>
|
|
#include <stack>
|
|
|
|
#include <unordered_map>
|
|
#include <string>
|
|
#include <mutex>
|
|
#include <queue>
|
|
#include <thread>
|
|
#include <atomic>
|
|
#include <iostream>
|
|
#include <nlohmann/json.hpp>
|
|
|
|
lua_State *L;
|
|
bool is_playing = false;
|
|
bool init_exists = false;
|
|
bool update_exists = false;
|
|
|
|
std::unordered_map<std::string, std::vector<int>> g_breakpoints;
|
|
std::mutex g_breakMutex;
|
|
|
|
std::queue<std::string> g_debugCommands;
|
|
std::mutex g_cmdMutex;
|
|
|
|
std::atomic<bool> g_running = true;
|
|
std::atomic<bool> g_paused = false;
|
|
|
|
std::string g_pauseFile;
|
|
int g_pauseLine = 0;
|
|
bool function_has_breakpoints = false;
|
|
std::stack<bool> funBreakStack;
|
|
bool debug_enabled = false;
|
|
|
|
enum StepMode {
|
|
STEP_NONE,
|
|
STEP_INTO,
|
|
STEP_OVER,
|
|
STEP_OUT
|
|
};
|
|
|
|
StepMode g_stepMode = STEP_NONE;
|
|
int g_stepDepth = 0;
|
|
|
|
namespace fs = std::filesystem;
|
|
using json = nlohmann::json;
|
|
|
|
std::string pathToChunk(const std::string& path) {
|
|
std::filesystem::path p(path);
|
|
|
|
// 1. Normalizar la ruta
|
|
p = p.lexically_normal();
|
|
|
|
// 2. Buscar el directorio "data"
|
|
auto it = std::find(p.begin(), p.end(), "data");
|
|
if (it == p.end())
|
|
return ""; // no es un script Lua válido
|
|
|
|
// 3. Construir la parte relativa después de "data"
|
|
std::filesystem::path rel;
|
|
for (++it; it != p.end(); ++it)
|
|
rel /= *it;
|
|
|
|
// 4. Quitar ".lua"
|
|
std::string s = rel.string();
|
|
if (s.ends_with(".lua"))
|
|
s = s.substr(0, s.size() - 4);
|
|
|
|
// 5. Convertir "/" → "."
|
|
for (char& c : s)
|
|
if (c == '/')
|
|
c = '.';
|
|
|
|
return s;
|
|
}
|
|
|
|
std::string chunkToPath(const std::string& chunk) {
|
|
// 1. Convertir "ia.test" → "ia/test"
|
|
std::string rel;
|
|
rel.reserve(chunk.size() + 10);
|
|
|
|
for (char c : chunk)
|
|
rel += (c == '.' ? '/' : c);
|
|
|
|
// 2. Añadir prefijo y sufijo
|
|
rel = "data/" + rel + ".lua";
|
|
|
|
// 3. Convertir a ruta absoluta
|
|
std::filesystem::path abs = std::filesystem::current_path() / rel;
|
|
|
|
return abs.lexically_normal().string();
|
|
}
|
|
|
|
int getStackDepth(lua_State* L) {
|
|
lua_Debug ar;
|
|
int depth = 0;
|
|
|
|
while (lua_getstack(L, depth, &ar)) {
|
|
depth++;
|
|
}
|
|
|
|
return depth;
|
|
}
|
|
|
|
json getStackTrace(lua_State* L) {
|
|
json frames = json::array();
|
|
lua_Debug ar;
|
|
|
|
int depth = 0;
|
|
while (lua_getstack(L, depth, &ar)) {
|
|
lua_getinfo(L, "nSl", &ar);
|
|
|
|
//const char* src = chunkToPath(ar.source).c_str();
|
|
|
|
json frame = {
|
|
{ "file", chunkToPath(ar.source).c_str() },
|
|
{ "line", ar.currentline },
|
|
{ "name", ar.name ? ar.name : "?" }
|
|
};
|
|
|
|
frames.push_back(frame);
|
|
depth++;
|
|
}
|
|
|
|
return json{
|
|
{ "frames", frames }
|
|
};
|
|
}
|
|
|
|
int allocateRefForTable(lua_State* L, int index) {
|
|
lua_pushvalue(L, index); // copia la tabla
|
|
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
return ref;
|
|
}
|
|
|
|
json getLocals(lua_State* L) {
|
|
json vars = json::array();
|
|
|
|
lua_Debug ar;
|
|
// Obtenemos el frame 0 (el actual)
|
|
if (!lua_getstack(L, 0, &ar)) {
|
|
return json{ {"variables", vars} };
|
|
}
|
|
|
|
// Pedimos info del frame
|
|
lua_getinfo(L, "nSl", &ar);
|
|
|
|
int i = 1;
|
|
const char* name;
|
|
|
|
while ((name = lua_getlocal(L, &ar, i)) != NULL) {
|
|
|
|
if (strcmp(name, "(temporary)") == 0) {
|
|
lua_pop(L, 1);
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
// El valor está ahora en la pila
|
|
json v;
|
|
|
|
v["name"] = name;
|
|
|
|
// Convertimos el valor Lua a string y tipo
|
|
int type = lua_type(L, -1);
|
|
|
|
switch (type) {
|
|
case LUA_TNUMBER:
|
|
v["value"] = std::to_string(lua_tonumber(L, -1));
|
|
v["type"] = "number";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TBOOLEAN:
|
|
v["value"] = lua_toboolean(L, -1) ? "true" : "false";
|
|
v["type"] = "boolean";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TSTRING:
|
|
v["value"] = lua_tostring(L, -1);
|
|
v["type"] = "string";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TTABLE:
|
|
v["value"] = "{table}";
|
|
v["type"] = "table";
|
|
v["ref"] = allocateRefForTable(L, -1);
|
|
break;
|
|
|
|
case LUA_TFUNCTION:
|
|
v["value"] = "function";
|
|
v["type"] = "function";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TNIL:
|
|
v["value"] = "nil";
|
|
v["type"] = "nil";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
default:
|
|
v["value"] = lua_typename(L, type);
|
|
v["type"] = lua_typename(L, type);
|
|
v["ref"] = 0;
|
|
break;
|
|
}
|
|
|
|
vars.push_back(v);
|
|
|
|
// Quitamos el valor de la pila
|
|
lua_pop(L, 1);
|
|
|
|
i++;
|
|
}
|
|
|
|
return json{
|
|
{ "variables", vars }
|
|
};
|
|
}
|
|
|
|
json getUpvalues(lua_State* L) {
|
|
json vars = json::array();
|
|
|
|
lua_Debug ar;
|
|
if (!lua_getstack(L, 0, &ar)) {
|
|
return json{ {"variables", vars} };
|
|
}
|
|
|
|
// Pedimos info del frame, incluyendo la función ("f")
|
|
lua_getinfo(L, "nSlf", &ar);
|
|
|
|
// La función está ahora en la pila
|
|
int funcIndex = lua_gettop(L);
|
|
|
|
int i = 1;
|
|
const char* name;
|
|
|
|
while ((name = lua_getupvalue(L, funcIndex, i)) != NULL) {
|
|
json v;
|
|
v["name"] = name;
|
|
|
|
int type = lua_type(L, -1);
|
|
|
|
switch (type) {
|
|
case LUA_TNUMBER:
|
|
v["value"] = std::to_string(lua_tonumber(L, -1));
|
|
v["type"] = "number";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TBOOLEAN:
|
|
v["value"] = lua_toboolean(L, -1) ? "true" : "false";
|
|
v["type"] = "boolean";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TSTRING:
|
|
v["value"] = lua_tostring(L, -1);
|
|
v["type"] = "string";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TTABLE:
|
|
v["value"] = "{table}";
|
|
v["type"] = "table";
|
|
v["ref"] = allocateRefForTable(L, -1);
|
|
break;
|
|
|
|
case LUA_TNIL:
|
|
v["value"] = "nil";
|
|
v["type"] = "nil";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
default:
|
|
v["value"] = lua_typename(L, type);
|
|
v["type"] = lua_typename(L, type);
|
|
v["ref"] = 0;
|
|
break;
|
|
}
|
|
|
|
vars.push_back(v);
|
|
|
|
lua_pop(L, 1); // quitamos el valor del upvalue
|
|
i++;
|
|
}
|
|
|
|
// Quitamos la función del stack
|
|
lua_pop(L, 1);
|
|
|
|
return json{
|
|
{ "variables", vars }
|
|
};
|
|
}
|
|
|
|
json getGlobals(lua_State* L) {
|
|
json vars = json::array();
|
|
|
|
// Empujamos _G a la pila
|
|
lua_pushglobaltable(L); // equivalente a lua_getglobal(L, "_G")
|
|
|
|
lua_pushnil(L); // primera clave
|
|
while (lua_next(L, -2) != 0) {
|
|
// Ahora en la pila:
|
|
// -1 → valor
|
|
// -2 → clave
|
|
// -3 → _G
|
|
|
|
// Solo aceptamos claves string
|
|
if (lua_type(L, -2) == LUA_TSTRING) {
|
|
const char* name = lua_tostring(L, -2);
|
|
|
|
json v;
|
|
v["name"] = name;
|
|
|
|
int type = lua_type(L, -1);
|
|
|
|
switch (type) {
|
|
case LUA_TNUMBER:
|
|
v["value"] = std::to_string(lua_tonumber(L, -1));
|
|
v["type"] = "number";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TBOOLEAN:
|
|
v["value"] = lua_toboolean(L, -1) ? "true" : "false";
|
|
v["type"] = "boolean";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TSTRING:
|
|
v["value"] = lua_tostring(L, -1);
|
|
v["type"] = "string";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TTABLE:
|
|
v["value"] = "{table}";
|
|
v["type"] = "table";
|
|
v["ref"] = allocateRefForTable(L, -1);
|
|
break;
|
|
|
|
case LUA_TFUNCTION:
|
|
v["value"] = "function";
|
|
v["type"] = "function";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TNIL:
|
|
v["value"] = "nil";
|
|
v["type"] = "nil";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
default:
|
|
v["value"] = lua_typename(L, type);
|
|
v["type"] = lua_typename(L, type);
|
|
v["ref"] = 0;
|
|
break;
|
|
}
|
|
|
|
vars.push_back(v);
|
|
}
|
|
|
|
lua_pop(L, 1); // pop valor, deja clave para lua_next
|
|
}
|
|
|
|
lua_pop(L, 1); // pop _G
|
|
|
|
return json{
|
|
{ "variables", vars }
|
|
};
|
|
}
|
|
|
|
json expandTable(lua_State* L, int ref) {
|
|
json vars = json::array();
|
|
|
|
// Recuperamos la tabla del registry
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
|
|
|
lua_pushnil(L);
|
|
while (lua_next(L, -2) != 0) {
|
|
json v;
|
|
|
|
// clave
|
|
if (lua_type(L, -2) == LUA_TSTRING) {
|
|
v["name"] = lua_tostring(L, -2);
|
|
} else if (lua_type(L, -2) == LUA_TNUMBER) {
|
|
v["name"] = std::to_string(lua_tonumber(L, -2));
|
|
} else {
|
|
v["name"] = "<non-string-key>";
|
|
}
|
|
|
|
// valor
|
|
int type = lua_type(L, -1);
|
|
|
|
switch (type) {
|
|
case LUA_TNUMBER:
|
|
v["value"] = std::to_string(lua_tonumber(L, -1));
|
|
v["type"] = "number";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TBOOLEAN:
|
|
v["value"] = lua_toboolean(L, -1) ? "true" : "false";
|
|
v["type"] = "boolean";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TSTRING:
|
|
v["value"] = lua_tostring(L, -1);
|
|
v["type"] = "string";
|
|
v["ref"] = 0;
|
|
break;
|
|
|
|
case LUA_TTABLE:
|
|
v["value"] = "{table}";
|
|
v["type"] = "table";
|
|
v["ref"] = allocateRefForTable(L, -1);
|
|
break;
|
|
|
|
default:
|
|
v["value"] = lua_typename(L, type);
|
|
v["type"] = lua_typename(L, type);
|
|
v["ref"] = 0;
|
|
break;
|
|
}
|
|
|
|
vars.push_back(v);
|
|
|
|
lua_pop(L, 1); // pop valor
|
|
}
|
|
|
|
lua_pop(L, 1); // pop tabla
|
|
|
|
return json{
|
|
{ "kind", "expand" },
|
|
{ "variables", vars }
|
|
};
|
|
}
|
|
|
|
void sendDebugResponse(const std::string& type, const json& payload) {
|
|
json msg = {
|
|
{ "type", type },
|
|
{ "payload", payload }
|
|
};
|
|
//printf("STACKTRACE: %s", msg.dump().c_str());
|
|
std::cout << "@@DEBUG@@" << msg.dump() << std::endl;
|
|
}
|
|
|
|
void processDebugCommand(const std::string& line) {
|
|
//printf("COMANDO PROCESADO: %s\n", line.c_str());
|
|
if (!line.starts_with("@@DEBUGCMD@@"))
|
|
return;
|
|
|
|
json j = json::parse(line.substr(12));
|
|
|
|
std::string cmd = j["cmd"];
|
|
|
|
if (cmd == "setBreakpoints") {
|
|
std::string file = j["file"];
|
|
std::vector<int> lines = j["lines"];
|
|
std::lock_guard<std::mutex> lock(g_breakMutex);
|
|
std::string chunk = pathToChunk(file);
|
|
//printf("Es un BREAKPOINT: %s, %i\n", chunk.c_str(), lines[0]);
|
|
g_breakpoints[chunk] = lines;
|
|
}
|
|
else if (cmd == "continue") {
|
|
printf("CONTINUA\n\n");
|
|
g_stepMode = STEP_NONE;
|
|
g_paused = false;
|
|
}
|
|
else if (cmd == "pause") {
|
|
g_stepMode = STEP_INTO;
|
|
g_paused = false;
|
|
}
|
|
else if (cmd == "stepOver") {
|
|
g_stepMode = STEP_OVER;
|
|
g_stepDepth = getStackDepth(L);
|
|
g_paused = false;
|
|
}
|
|
else if (cmd == "stepInto") {
|
|
g_stepMode = STEP_INTO;
|
|
g_paused = false;
|
|
}
|
|
else if (cmd == "stepOut") {
|
|
g_stepMode = STEP_OUT;
|
|
g_stepDepth = getStackDepth(L);
|
|
g_paused = false;
|
|
}
|
|
else if (cmd == "stackTrace") {
|
|
json result = getStackTrace(L);
|
|
sendDebugResponse("stackTrace", result);
|
|
}
|
|
else if (cmd == "locals") {
|
|
json result = getLocals(L);
|
|
json payload = {
|
|
{ "kind", "locals" },
|
|
{ "variables", result["variables"] }
|
|
};
|
|
sendDebugResponse("variables", payload);
|
|
}
|
|
else if (cmd == "upvalues") {
|
|
json result = getUpvalues(L);
|
|
json payload = {
|
|
{ "kind", "upvalues" },
|
|
{ "variables", result["variables"] }
|
|
};
|
|
sendDebugResponse("variables", payload);
|
|
}
|
|
else if (cmd == "globals") {
|
|
json result = getGlobals(L);
|
|
json payload = {
|
|
{ "kind", "globals" },
|
|
{ "variables", result["variables"] }
|
|
};
|
|
sendDebugResponse("variables", payload);
|
|
}
|
|
else if (cmd == "expand") {
|
|
int ref = j["ref"];
|
|
json result = expandTable(L, ref);
|
|
sendDebugResponse("variables", result);
|
|
}
|
|
|
|
}
|
|
|
|
bool isBreakpoint(const std::string& file, int line) {
|
|
std::lock_guard<std::mutex> lock(g_breakMutex);
|
|
|
|
//if (!g_breakpoints.empty()) {
|
|
// printf("file: %s\n", file.c_str());
|
|
//}
|
|
auto it = g_breakpoints.find(file);
|
|
if (it == g_breakpoints.end())
|
|
return false;
|
|
|
|
for (int bp : it->second) {
|
|
if (bp == line)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void sendBreakEvent(const std::string& file, int line) {
|
|
json j = {
|
|
{"type", "break"},
|
|
{"file", file},
|
|
{"line", line}
|
|
};
|
|
|
|
std::cout << "@@DEBUG@@" << j.dump() << std::endl;
|
|
std::cout.flush();
|
|
}
|
|
|
|
std::string waitForDebugCommand() {
|
|
//printf("HOLA");
|
|
while (true) {
|
|
{
|
|
std::lock_guard<std::mutex> lock(g_cmdMutex);
|
|
if (!g_debugCommands.empty()) {
|
|
std::string cmd = g_debugCommands.front();
|
|
g_debugCommands.pop();
|
|
return cmd;
|
|
}
|
|
}
|
|
|
|
SDL_Delay(1);
|
|
}
|
|
}
|
|
|
|
/*void debugCommandThread() {
|
|
std::string line;
|
|
|
|
while (true) {
|
|
if (!std::getline(std::cin, line)) {
|
|
break; // stdin cerrado
|
|
}
|
|
|
|
if (!g_running)
|
|
break;
|
|
|
|
std::lock_guard<std::mutex> lock(g_cmdMutex);
|
|
g_debugCommands.push(line);
|
|
}
|
|
}*/
|
|
|
|
bool shouldPauseForStepping(lua_State* L, lua_Debug* ar) {
|
|
int depth = getStackDepth(L);
|
|
|
|
switch (g_stepMode) {
|
|
case STEP_INTO:
|
|
return true; // siempre parar en la siguiente línea
|
|
|
|
case STEP_OVER:
|
|
return depth <= g_stepDepth;
|
|
|
|
case STEP_OUT:
|
|
return depth < g_stepDepth;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void pauseHere(const std::string& src, int line) {
|
|
g_paused = true;
|
|
g_pauseFile = src;
|
|
g_pauseLine = line;
|
|
g_stepMode = STEP_NONE;
|
|
|
|
sendBreakEvent(chunkToPath(src), line);
|
|
|
|
while (g_paused) {
|
|
std::string cmd = waitForDebugCommand();
|
|
processDebugCommand(cmd);
|
|
}
|
|
}
|
|
|
|
extern "C" void luaHook(lua_State* L, lua_Debug* ar) {
|
|
lua_getinfo(L, "Sl", ar);
|
|
|
|
const char* src = ar->source;
|
|
if (src[0]=='=') return;
|
|
|
|
if (ar->event == LUA_HOOKCALL) {
|
|
funBreakStack.push(function_has_breakpoints);
|
|
bool new_function_has_breakpoints = false;
|
|
{
|
|
std::lock_guard<std::mutex> lock(g_breakMutex);
|
|
auto it = g_breakpoints.find(src);
|
|
new_function_has_breakpoints = (it != g_breakpoints.end() && !it->second.empty());
|
|
}
|
|
if (new_function_has_breakpoints || g_stepMode != STEP_NONE) {
|
|
if (!function_has_breakpoints)
|
|
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0);
|
|
} else {
|
|
//if (function_has_breakpoints)
|
|
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0);
|
|
}
|
|
function_has_breakpoints = new_function_has_breakpoints;
|
|
}
|
|
else if (ar->event == LUA_HOOKRET) {
|
|
// Siempre volver al hook base
|
|
bool new_function_has_breakpoints = funBreakStack.empty() ? false : funBreakStack.top();
|
|
funBreakStack.pop();
|
|
if (new_function_has_breakpoints || g_stepMode != STEP_NONE) {
|
|
if (!function_has_breakpoints)
|
|
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0);
|
|
} else {
|
|
//if (function_has_breakpoints)
|
|
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0);
|
|
}
|
|
function_has_breakpoints = new_function_has_breakpoints;
|
|
}
|
|
else if (ar->event == LUA_HOOKLINE) {
|
|
if (ar->currentline <= 0) return;
|
|
const char* src = ar->source;
|
|
int line = ar->currentline;
|
|
|
|
if (isBreakpoint(src, line)) {
|
|
pauseHere(src, line);
|
|
return;
|
|
}
|
|
|
|
// 2. Stepping
|
|
if (g_stepMode != STEP_NONE) {
|
|
if (shouldPauseForStepping(L, ar)) {
|
|
pauseHere(src, line);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
uint32_t last_update = 0;
|
|
float delta_time = 0.0f;
|
|
// surface
|
|
// ===============================================
|
|
|
|
static int cpp_surf_new(lua_State *L) {
|
|
int w = luaL_checknumber(L, 1);
|
|
int h = luaL_checknumber(L, 2);
|
|
uint8_t s = newsurf(w, h);
|
|
if (s==255) {
|
|
luaL_error(L, "Error while creating new surface: Max surfaces reached");
|
|
return 0;
|
|
}
|
|
lua_pushinteger(L, s);
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_surf_load(lua_State *L) {
|
|
const char* str = luaL_checkstring(L, 1);
|
|
uint8_t s = loadsurf(str);
|
|
if (s==255) {
|
|
luaL_error(L, "Error while loading surface: Max surfaces reached");
|
|
return 0;
|
|
}
|
|
lua_pushinteger(L, s);
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_surf_loadex(lua_State *L) {
|
|
const char* str = luaL_checkstring(L, 1);
|
|
uint8_t s = loadsurf(str, true);
|
|
if (s==255) {
|
|
luaL_error(L, "Error while loading surface: Max surfaces reached");
|
|
return 0;
|
|
}
|
|
lua_pushinteger(L, s);
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_surf_save(lua_State *L) {
|
|
uint8_t surface = luaL_checkinteger(L, 1);
|
|
const char* str = luaL_checkstring(L, 2);
|
|
|
|
if (lua_istable(L, -1)) {
|
|
const int len = SDL_min(256, lua_rawlen(L, -1));
|
|
uint8_t *pal = (uint8_t*)malloc(len*3);
|
|
uint8_t *p=pal;
|
|
for (int i=1;i<=len;++i) {
|
|
lua_rawgeti(L, -1, i);
|
|
lua_getfield(L, -1, "r");
|
|
*(p++) = luaL_checknumber(L, -1);
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "g");
|
|
*(p++) = luaL_checknumber(L, -1);
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "b");
|
|
*(p++) = luaL_checknumber(L, -1);
|
|
lua_pop(L, 1);
|
|
lua_pop(L, 1);
|
|
//pal[i-1] = (r<<16)+(g<<8)+b;
|
|
}
|
|
savesurf(surface, str, pal, len);
|
|
} else {
|
|
savesurf(surface, str, nullptr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_surf_free(lua_State *L) {
|
|
uint8_t surface = luaL_checkinteger(L, 1);
|
|
freesurf(surface);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_surf_size(lua_State *L) {
|
|
uint8_t surface = luaL_checkinteger(L, 1);
|
|
lua_pushinteger(L, surfw(surface));
|
|
lua_pushinteger(L, surfh(surface));
|
|
return 2;
|
|
}
|
|
|
|
static int cpp_surf_target(lua_State *L) {
|
|
const int numargs = lua_gettop(L);
|
|
switch (numargs) {
|
|
case 0: {
|
|
lua_pushinteger(L, getdest());
|
|
return 1;
|
|
}
|
|
case 1: {
|
|
uint8_t surface = luaL_checkinteger(L, 1);
|
|
setdest(surface);
|
|
return 0;
|
|
}
|
|
default:
|
|
return luaL_error(L, "Function 'surface.target' Unexpected number of parameters.");
|
|
};
|
|
}
|
|
|
|
static int cpp_surf_source(lua_State *L) {
|
|
const int numargs = lua_gettop(L);
|
|
switch (numargs) {
|
|
case 0: {
|
|
lua_pushinteger(L, getsource());
|
|
return 1;
|
|
}
|
|
case 1: {
|
|
uint8_t surface = luaL_checkinteger(L, 1);
|
|
setsource(surface);
|
|
return 0;
|
|
}
|
|
default:
|
|
return luaL_error(L, "Function 'surface.source' Unexpected number of parameters.");
|
|
};
|
|
}
|
|
|
|
static int cpp_surf_cls(lua_State *L) {
|
|
uint8_t color = luaL_optinteger(L, 1, 0);
|
|
cls(color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_surf_pixel(lua_State *L) {
|
|
if (lua_gettop(L)==2) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
lua_pushinteger(L, sget(x, y));
|
|
return 1;
|
|
} else {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
uint8_t color = luaL_checkinteger(L, 3);
|
|
pset(x, y, color);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// map
|
|
// ===============================================
|
|
|
|
/*
|
|
static int cpp_map_new(lua_State *L) {
|
|
int w = luaL_checknumber(L, 1);
|
|
int h = luaL_checknumber(L, 2);
|
|
uint8_t s = newsurf(w, h);
|
|
uint8_t old = getmap(); if (old) freesurf(old);
|
|
setmap(s);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_map_load(lua_State *L) {
|
|
const char* str = luaL_checkstring(L, 1);
|
|
uint8_t s = loadsurf(str);
|
|
uint8_t old = getmap(); if (old) freesurf(old);
|
|
setmap(s);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_map_save(lua_State *L) {
|
|
uint8_t surface = getmap();
|
|
const char* str = luaL_checkstring(L, 1);
|
|
savesurf(surface, str, nullptr);
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
static int cpp_map_surf(lua_State *L) {
|
|
if (lua_gettop(L)==1) {
|
|
uint8_t surface = luaL_checkinteger(L, 1);
|
|
setmap(surface);
|
|
} else {
|
|
lua_pushinteger(L, getmap());
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_map_draw(lua_State *L) {
|
|
/*uint8_t celx = luaL_checknumber(L, 1);
|
|
uint8_t cely = luaL_checknumber(L, 2);
|
|
int sx = luaL_checknumber(L, 3);
|
|
int sy = luaL_checknumber(L, 4);
|
|
uint8_t celw = luaL_checknumber(L, 5);
|
|
uint8_t celh = luaL_checknumber(L, 6);
|
|
uint8_t layer = luaL_optinteger(L, 7, 0);*/
|
|
//uint8_t surface = luaL_checkinteger(L, 1);
|
|
//setsource(surface);
|
|
map(); //celx, cely, sx, sy, celw, celh, layer);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_map_tile(lua_State *L) {
|
|
if (lua_gettop(L)==2) {
|
|
int celx = luaL_checknumber(L, 1);
|
|
int cely = luaL_checknumber(L, 2);
|
|
lua_pushinteger(L, mget(celx, cely));
|
|
return 1;
|
|
} else {
|
|
int celx = luaL_checknumber(L, 1);
|
|
int cely = luaL_checknumber(L, 2);
|
|
uint8_t snum = luaL_checkinteger(L, 3);
|
|
mset(celx, cely, snum);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_map_cell(lua_State *L) {
|
|
if (lua_gettop(L)==2) {
|
|
int celx = luaL_checknumber(L, 1);
|
|
int cely = luaL_checknumber(L, 2);
|
|
settilesize(celx, cely);
|
|
lua_pushinteger(L, mget(celx, cely));
|
|
return 0;
|
|
} else {
|
|
lua_pushinteger(L, gettilew());
|
|
lua_pushinteger(L, gettileh());
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
|
|
// palette
|
|
// ===============================================
|
|
|
|
static int cpp_pal_load(lua_State *L) {
|
|
const char* str = luaL_checkstring(L, 1);
|
|
uint16_t size;
|
|
uint32_t *pal = loadpal(str, &size);
|
|
lua_createtable(L, 2, 0);
|
|
for (int i=0;i<size;++i) {
|
|
uint32_t color = pal[i];
|
|
lua_createtable(L, 0, 3);
|
|
|
|
lua_pushinteger(L, (color>>16)&0xff);
|
|
lua_setfield(L, -2, "r");
|
|
|
|
lua_pushinteger(L, (color>>8)&0xff);
|
|
lua_setfield(L, -2, "g");
|
|
|
|
lua_pushinteger(L, color&0xff);
|
|
lua_setfield(L, -2, "b");
|
|
|
|
lua_rawseti(L, -2, i+1);
|
|
}
|
|
free(pal);
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_pal_set(lua_State *L) {
|
|
int r,g,b;
|
|
if (lua_istable(L, -1)) {
|
|
uint32_t pal[256];
|
|
const int len = SDL_min(256, lua_rawlen(L, -1));
|
|
for (int i=0;i<len;++i) {
|
|
lua_rawgeti(L, -1, i+1);
|
|
lua_getfield(L, -1, "r");
|
|
r = luaL_checknumber(L, -1);
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "g");
|
|
g = luaL_checknumber(L, -1);
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "b");
|
|
b = luaL_checknumber(L, -1);
|
|
lua_pop(L, 1);
|
|
lua_pop(L, 1);
|
|
pal[i] = (r<<16)+(g<<8)+b;
|
|
}
|
|
setpal(pal);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_pal_color(lua_State *L) {
|
|
//if (lua_gettop(L) != 1) return luaL_error(L, "Function 'mini.palette.getColor' Unexpected number of parameters.");
|
|
if (lua_gettop(L) == 1) {
|
|
uint8_t index = luaL_checkinteger(L, 1);
|
|
uint32_t color = getcolor(index);
|
|
lua_pushinteger(L, (color>>16)&0xff);
|
|
lua_pushinteger(L, (color>>8)&0xff);
|
|
lua_pushinteger(L, color&0xff);
|
|
return 3;
|
|
} else {
|
|
uint8_t index = luaL_checkinteger(L, 1);
|
|
uint8_t r = luaL_checkinteger(L, 2);
|
|
uint8_t g = luaL_optinteger(L, 3, 0);
|
|
uint8_t b = luaL_optinteger(L, 4, 0);
|
|
uint32_t color = (r<<16) + (g<<8) + b;
|
|
setcolor(index, color);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_pal_trans(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushinteger(L, gettrans());
|
|
return 1;
|
|
} else {
|
|
uint8_t index = luaL_checkinteger(L, 1);
|
|
settrans(index);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_pal_subpal(lua_State *L) {
|
|
const int num_params = lua_gettop(L);
|
|
uint8_t index, index2, color;
|
|
switch (num_params) {
|
|
case 0:
|
|
reset_subpal();
|
|
break;
|
|
case 1:
|
|
index = luaL_checkinteger(L, 1);
|
|
lua_pushinteger(L, subpal(index,index));
|
|
return 1;
|
|
break;
|
|
case 2:
|
|
index = luaL_checkinteger(L, 1);
|
|
color = luaL_checkinteger(L, 2);
|
|
lua_pushinteger(L, subpal(index, color));
|
|
return 1;
|
|
break;
|
|
case 3:
|
|
index = luaL_checkinteger(L, 1);
|
|
index2 = luaL_checkinteger(L, 2);
|
|
color = luaL_checkinteger(L, 3);
|
|
for (int i=index;i<=index2;++i) subpal(i, color);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// viewport
|
|
// ===============================================
|
|
|
|
static int cpp_viewport_clip(lua_State *L) {
|
|
if (lua_gettop(L)==0) {
|
|
clip();
|
|
return 0;
|
|
} else {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int w = luaL_checknumber(L, 3);
|
|
int h = luaL_checknumber(L, 4);
|
|
clip(x, y, w, h);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_viewport_origin(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushinteger(L, camx());
|
|
lua_pushinteger(L, camy());
|
|
return 2;
|
|
} else {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
origin(x, y);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_viewport_tolocal(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
lua_pushinteger(L, x+camx());
|
|
lua_pushinteger(L, y+camy());
|
|
return 2;
|
|
}
|
|
|
|
|
|
// draw
|
|
// ===============================================
|
|
|
|
/*static int cpp_draw_pen(lua_State *L) {
|
|
uint8_t col = luaL_optinteger(L, 1, 6);
|
|
color(col);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_paper(lua_State *L) {
|
|
uint8_t col = luaL_optinteger(L, 1, 6);
|
|
bcolor(col);
|
|
return 0;
|
|
}*/
|
|
|
|
static int cpp_draw_line(lua_State *L) {
|
|
int x0 = luaL_checknumber(L, 1);
|
|
int y0 = luaL_checknumber(L, 2);
|
|
int x1 = luaL_checknumber(L, 3);
|
|
int y1 = luaL_checknumber(L, 4);
|
|
uint8_t color = luaL_checkinteger(L, 5);
|
|
line(x0, y0, x1, y1, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_hline(lua_State *L) {
|
|
int x0 = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int x1 = luaL_checknumber(L, 3);
|
|
uint8_t color = luaL_checkinteger(L, 4);
|
|
hline(x0, y, x1, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_vline(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y0 = luaL_checknumber(L, 2);
|
|
int y1 = luaL_checknumber(L, 3);
|
|
uint8_t color = luaL_checkinteger(L, 4);
|
|
vline(x, y0, y1, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_rect(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int w = luaL_checknumber(L, 3);
|
|
int h = luaL_checknumber(L, 4);
|
|
uint8_t color = luaL_checkinteger(L, 5);
|
|
rect(x, y, w, h, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_rectfill(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int w = luaL_checknumber(L, 3);
|
|
int h = luaL_checknumber(L, 4);
|
|
uint8_t color = luaL_checkinteger(L, 5);
|
|
rectfill(x, y, w, h, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_circ(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int r = luaL_optnumber(L, 3, 4);
|
|
uint8_t color = luaL_checkinteger(L, 4);
|
|
circ(x, y, r, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_circfill(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int r = luaL_optnumber(L, 3, 4);
|
|
uint8_t color = luaL_checkinteger(L, 4);
|
|
circfill(x, y, r, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_roundrect(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int w = luaL_checknumber(L, 3);
|
|
int h = luaL_checknumber(L, 4);
|
|
int r = luaL_optnumber(L, 5, 4);
|
|
uint8_t color = luaL_checkinteger(L, 6);
|
|
roundrect(x, y, w, h, r, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_roundrectfill(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int w = luaL_checknumber(L, 3);
|
|
int h = luaL_checknumber(L, 4);
|
|
int r = luaL_optnumber(L, 5, 4);
|
|
uint8_t color = luaL_checkinteger(L, 6);
|
|
roundrectfill(x, y, w, h, r, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_oval(lua_State *L) {
|
|
int x0 = luaL_checknumber(L, 1);
|
|
int y0 = luaL_checknumber(L, 2);
|
|
int x1 = luaL_checknumber(L, 3);
|
|
int y1 = luaL_checknumber(L, 4);
|
|
uint8_t color = luaL_checkinteger(L, 5);
|
|
oval(x0, y0, x1, y1, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_ovalfill(lua_State *L) {
|
|
int x0 = luaL_checknumber(L, 1);
|
|
int y0 = luaL_checknumber(L, 2);
|
|
int x1 = luaL_checknumber(L, 3);
|
|
int y1 = luaL_checknumber(L, 4);
|
|
uint8_t color = luaL_checkinteger(L, 5);
|
|
ovalfill(x0, y0, x1, y1, color);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_pattern(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
fillp(0xffff);
|
|
} else {
|
|
uint16_t pat = luaL_checkinteger(L, 1);
|
|
bool transparent = lua_toboolean(L, 2);
|
|
fillp(pat, transparent);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*static int cpp_draw_tline(lua_State *L) {
|
|
int x0 = luaL_checknumber(L, 1);
|
|
int y0 = luaL_checknumber(L, 2);
|
|
int x1 = luaL_checknumber(L, 3);
|
|
int y1 = luaL_checknumber(L, 4);
|
|
float mx = luaL_checknumber(L, 5);
|
|
float my = luaL_checknumber(L, 6);
|
|
float mdx = luaL_optnumber(L, 7, 0.125f);
|
|
float mdy = luaL_optnumber(L, 8, 0.0f);
|
|
tline(x0, y0, x1, y1, mx, my, mdx, mdy);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_thline(lua_State *L) {
|
|
int x0 = luaL_checknumber(L, 1);
|
|
int y = luaL_checknumber(L, 2);
|
|
int x1 = luaL_checknumber(L, 3);
|
|
float mx = luaL_checknumber(L, 4);
|
|
float my = luaL_checknumber(L, 5);
|
|
float mdx = luaL_optnumber(L, 6, 0.125f);
|
|
float mdy = luaL_optnumber(L, 7, 0.0f);
|
|
thline(x0, y, x1, mx, my, mdx, mdy);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_tvline(lua_State *L) {
|
|
int x = luaL_checknumber(L, 1);
|
|
int y0 = luaL_checknumber(L, 2);
|
|
int y1 = luaL_checknumber(L, 3);
|
|
float mx = luaL_checknumber(L, 4);
|
|
float my = luaL_checknumber(L, 5);
|
|
float mdx = luaL_optnumber(L, 6, 0.0f);
|
|
float mdy = luaL_optnumber(L, 7, 0.125f);
|
|
tvline(x, y0, y1, mx, my, mdx, mdy);
|
|
return 0;
|
|
}*/
|
|
|
|
static int cpp_draw_surface(lua_State *L) {
|
|
int sx = luaL_checknumber(L, 1);
|
|
int sy = luaL_checknumber(L, 2);
|
|
int sw = luaL_checknumber(L, 3);
|
|
int sh = luaL_checknumber(L, 4);
|
|
int dx = luaL_checknumber(L, 5);
|
|
int dy = luaL_checknumber(L, 6);
|
|
int dw = luaL_optnumber(L, 7, 0);
|
|
int dh = luaL_optnumber(L, 8, 0);
|
|
bool flip_x = lua_toboolean(L, 9);
|
|
bool flip_y = lua_toboolean(L, 10);
|
|
bool invert = lua_toboolean(L, 11);
|
|
blit(sx, sy, sw, sh, dx, dy, dw, dh, flip_x, flip_y, invert);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_surfaceRotated(lua_State *L) {
|
|
int sx = luaL_checknumber(L, 1);
|
|
int sy = luaL_checknumber(L, 2);
|
|
int sw = luaL_checknumber(L, 3);
|
|
int sh = luaL_checknumber(L, 4);
|
|
int dx = luaL_checknumber(L, 5);
|
|
int dy = luaL_checknumber(L, 6);
|
|
float a = luaL_checknumber(L, 7);
|
|
int dw = luaL_optnumber(L, 8, 0);
|
|
int dh = luaL_optnumber(L, 9, 0);
|
|
bool flip_x = lua_toboolean(L, 10);
|
|
bool flip_y = lua_toboolean(L, 11);
|
|
blit_r(sx, sy, sw, sh, dx, dy, dw, dh, flip_x, flip_y, a);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_text(lua_State *L) {
|
|
const char* str = luaL_checkstring(L, 1);
|
|
int x = luaL_checknumber(L, 2);
|
|
int y = luaL_checknumber(L, 3);
|
|
if (lua_gettop(L) > 3) {
|
|
uint8_t color = luaL_checkinteger(L, 4);
|
|
print(str, x, y, color);
|
|
} else {
|
|
print(str, x, y);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_draw_mode(lua_State *L) {
|
|
int mode = luaL_checknumber(L, 1);
|
|
set_draw_mode(mode);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// shaders
|
|
// ===============================================
|
|
|
|
static int cpp_shader_init(lua_State *L) {
|
|
const char* vstr = luaL_optstring(L, 1, NULL);
|
|
const char* fstr = luaL_optstring(L, 2, NULL);
|
|
shader_init(vstr, fstr);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_shader_enable(lua_State *L) {
|
|
shader_enable();
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_shader_disable(lua_State *L) {
|
|
shader_disable();
|
|
return 0;
|
|
}
|
|
|
|
|
|
// music
|
|
// ===============================================
|
|
|
|
static int cpp_music_play(lua_State *L) {
|
|
const char* str = luaL_checkstring(L, 1);
|
|
const int loop = luaL_optinteger(L, 2, -1);
|
|
playmusic(str, loop);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_music_pause(lua_State *L) {
|
|
pausemusic();
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_music_resume(lua_State *L) {
|
|
resumemusic();
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_music_stop(lua_State *L) {
|
|
const int time = luaL_optinteger(L, 1, 1000);
|
|
stopmusic(time);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_music_pos(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushnumber(L, musicpos());
|
|
return 1;
|
|
} else {
|
|
musicpos(luaL_checknumber(L, 1));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_music_enable(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushboolean(L, ismusicenabled());
|
|
return 1;
|
|
} else {
|
|
enablemusic(lua_toboolean(L, 1));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// sound
|
|
// ===============================================
|
|
|
|
static int cpp_sound_load(lua_State *L) {
|
|
const char* str = luaL_checkstring(L, 1);
|
|
lua_pushinteger(L,loadsound(str));
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_sound_free(lua_State *L) {
|
|
const int sound = luaL_checknumber(L, 1);
|
|
freesound(sound);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_sound_play(lua_State *L) {
|
|
const int sound = luaL_checknumber(L, 1);
|
|
const int volume = luaL_optinteger(L, 2, -1);
|
|
lua_pushinteger(L,playsound(sound, volume));
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_sound_stop(lua_State *L) {
|
|
const int sound = luaL_checknumber(L, 1);
|
|
stopsound(sound);
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_sound_enable(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushboolean(L, issoundenabled());
|
|
return 1;
|
|
} else {
|
|
enablesound(lua_toboolean(L, 1));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// sys
|
|
// ===============================================
|
|
|
|
static int cpp_sys_delta(lua_State *L) {
|
|
lua_pushnumber(L, delta_time);
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_sys_time(lua_State *L) {
|
|
lua_pushnumber(L, time());
|
|
return 1;
|
|
}
|
|
|
|
static uint32_t chrono_time = 0;
|
|
static int cpp_sys_chrono(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushnumber(L, float(SDL_GetTicks()-chrono_time)/1000.0f);
|
|
return 1;
|
|
} else {
|
|
chrono_time = SDL_GetTicks();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_sys_beat(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushboolean(L, beat(-1));
|
|
return 1;
|
|
} else {
|
|
int16_t beats = luaL_optnumber(L, 1, -1);
|
|
beat(beats);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_sys_update(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushinteger(L, getupdatemode());
|
|
return 1;
|
|
} else {
|
|
int mode = luaL_checknumber(L, 1);
|
|
int interval = luaL_optinteger(L, 2, 0);
|
|
setupdatemode(mode, interval);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_sys_dir(lua_State *L) {
|
|
std::string path = "./data";
|
|
if (lua_gettop(L) > 0) path = luaL_checkstring(L, 1);
|
|
|
|
// Collect entries
|
|
std::vector<fs::directory_entry> entries;
|
|
for (const auto& entry : fs::directory_iterator(path)) {
|
|
entries.push_back(entry);
|
|
}
|
|
|
|
// Sort: directories first, then files; both alphabetically
|
|
std::sort(entries.begin(), entries.end(),
|
|
[](const fs::directory_entry& a, const fs::directory_entry& b) {
|
|
bool adir = a.is_directory();
|
|
bool bdir = b.is_directory();
|
|
if (adir != bdir) return adir > bdir; // directories before files
|
|
return a.path().filename().string() < b.path().filename().string();
|
|
});
|
|
|
|
// Build Lua table
|
|
lua_newtable(L);
|
|
int i = 1;
|
|
for (const auto& entry : entries) {
|
|
lua_newtable(L);
|
|
|
|
// name field (canonical absolute path)
|
|
lua_pushstring(L, (const char*)fs::canonical(entry.path()).u8string().c_str());
|
|
lua_setfield(L, -2, "name");
|
|
|
|
// dir field
|
|
lua_pushboolean(L, entry.is_directory());
|
|
lua_setfield(L, -2, "dir");
|
|
|
|
lua_rawseti(L, -2, i++);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_sys_exit(lua_State *L) {
|
|
exit();
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_sys_fps(lua_State *L) {
|
|
lua_pushnumber(L, getfps());
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_sys_debug(lua_State *L) {
|
|
#ifdef DEBUG
|
|
lua_pushboolean(L, true);
|
|
#else
|
|
lua_pushboolean(L, false);
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_sys_clipboard(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushstring(L, SDL_GetClipboardText());
|
|
return 1;
|
|
} else {
|
|
const char* value = luaL_checkstring(L, 1);
|
|
SDL_SetClipboardText(value);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_sys_version(lua_State *L) {
|
|
lua_pushstring(L, MINI_VERSION);
|
|
return 1;
|
|
}
|
|
|
|
// win
|
|
// ===============================================
|
|
|
|
static int cpp_win_zoom(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushinteger(L, getzoom());
|
|
return 1;
|
|
} else {
|
|
const int value = luaL_optinteger(L, 1, 0);
|
|
setzoom(value);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_win_fullscreen(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushboolean(L, getfullscreen());
|
|
return 1;
|
|
} else {
|
|
setfullscreen(lua_toboolean(L, 1));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_win_cursor(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushboolean(L, getcursor());
|
|
return 1;
|
|
} else {
|
|
setcursor(lua_toboolean(L, 1));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cpp_win_res(lua_State *L) {
|
|
if (lua_gettop(L) == 0) {
|
|
lua_pushinteger(L, scrw());
|
|
lua_pushinteger(L, scrh());
|
|
return 2;
|
|
} else {
|
|
const int w = luaL_optinteger(L, 1, 160);
|
|
const int h = luaL_optinteger(L, 2, 120);
|
|
setres(w, h);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// conf
|
|
// ===============================================
|
|
|
|
static int cpp_conf_key(lua_State *L) {
|
|
const char* key = luaL_checkstring(L, 1);
|
|
if (lua_gettop(L) > 1) {
|
|
const char* value = luaL_checkstring(L, 2);
|
|
setconfig(key, value);
|
|
return 0;
|
|
} else {
|
|
const char* value = getconfig(key);
|
|
if (value==NULL) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushstring(L, value);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static int cpp_conf_folder(lua_State *L) {
|
|
lua_pushstring(L, configfolder());
|
|
return 1;
|
|
}
|
|
|
|
|
|
// font
|
|
// ===============================================
|
|
static int cpp_font_load(lua_State *L) {
|
|
const char* str = luaL_checkstring(L, 1);
|
|
uint8_t s = loadfont(str);
|
|
if (s==255) {
|
|
luaL_error(L, "Error while loading font: Max fonts reached");
|
|
return 0;
|
|
}
|
|
lua_pushinteger(L, s);
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_font_current(lua_State *L) {
|
|
const int numargs = lua_gettop(L);
|
|
switch (numargs) {
|
|
case 0: {
|
|
lua_pushinteger(L, getfont());
|
|
return 1;
|
|
}
|
|
case 1: {
|
|
uint8_t font = luaL_checkinteger(L, 1);
|
|
setfont(font);
|
|
return 0;
|
|
}
|
|
default:
|
|
return luaL_error(L, "Function 'font.current' Unexpected number of parameters.");
|
|
};
|
|
}
|
|
|
|
static int cpp_font_spacing(lua_State *L) {
|
|
const int numargs = lua_gettop(L);
|
|
switch (numargs) {
|
|
case 0: {
|
|
lua_pushinteger(L, getfontspacing());
|
|
return 1;
|
|
}
|
|
case 1: {
|
|
uint8_t spacing = luaL_checkinteger(L, 1);
|
|
setfontspacing(spacing);
|
|
return 0;
|
|
}
|
|
default:
|
|
return luaL_error(L, "Function 'font.spacing' Unexpected number of parameters.");
|
|
};
|
|
}
|
|
|
|
|
|
// mouse
|
|
// ===============================================
|
|
|
|
static int cpp_mouse_pos(lua_State *L) {
|
|
lua_pushinteger(L, mousex());
|
|
lua_pushinteger(L, mousey());
|
|
return 2;
|
|
}
|
|
|
|
static int cpp_mouse_wheel(lua_State *L) {
|
|
lua_pushinteger(L, mwheel());
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_mouse_down(lua_State *L) {
|
|
uint8_t i = luaL_checkinteger(L, 1);
|
|
lua_pushboolean(L, mbtn(i));
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_mouse_press(lua_State *L) {
|
|
uint8_t i = luaL_checkinteger(L, 1);
|
|
lua_pushboolean(L, mbtnp(i));
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_mouse_dblclick(lua_State *L) {
|
|
lua_pushboolean(L, doubleclick());
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_mouse_discard(lua_State *L) {
|
|
mdiscard();
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_mouse_inside(lua_State *L) {
|
|
int x = luaL_checkinteger(L, 1);
|
|
int y = luaL_checkinteger(L, 2);
|
|
int w = luaL_checkinteger(L, 3);
|
|
int h = luaL_checkinteger(L, 4);
|
|
lua_pushboolean(L, minside(x,y,w,h));
|
|
return 1;
|
|
}
|
|
|
|
|
|
// key
|
|
// ===============================================
|
|
|
|
static int cpp_key_down(lua_State *L) {
|
|
uint8_t i = luaL_checkinteger(L, 1);
|
|
lua_pushboolean(L, btn(i));
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_key_press(lua_State *L) {
|
|
if (lua_gettop(L) >=1 ) {
|
|
uint8_t i = luaL_checkinteger(L, 1);
|
|
lua_pushboolean(L, btnp(i));
|
|
} else {
|
|
lua_pushinteger(L, wbtnp());
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_key_any(lua_State *L) {
|
|
lua_pushboolean(L, anykey());
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_key_text(lua_State *L) {
|
|
textenable(lua_toboolean(L, 1));
|
|
return 0;
|
|
}
|
|
|
|
static int cpp_key_utf8char(lua_State *L) {
|
|
lua_pushstring(L, textinput());
|
|
return 1;
|
|
}
|
|
|
|
|
|
// pad
|
|
// ===============================================
|
|
|
|
static int cpp_pad_down(lua_State *L) {
|
|
int8_t i = luaL_checkinteger(L, 1);
|
|
lua_pushboolean(L, pad(i));
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_pad_press(lua_State *L) {
|
|
if (lua_gettop(L) >=1 ) {
|
|
int8_t i = luaL_checkinteger(L, 1);
|
|
lua_pushboolean(L, padp(i));
|
|
} else {
|
|
lua_pushinteger(L, wpad());
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_pad_any(lua_State *L) {
|
|
lua_pushinteger(L, wpad());
|
|
return 1;
|
|
}
|
|
|
|
static int cpp_utf8_sub(lua_State *L) {
|
|
size_t slen;
|
|
const char *s = luaL_checklstring(L, 1, &slen);
|
|
int i = luaL_checkinteger(L, 2);
|
|
int j = luaL_optinteger(L, 3, -1);
|
|
|
|
// Get utf8.offset
|
|
lua_getglobal(L, "utf8");
|
|
lua_getfield(L, -1, "offset");
|
|
|
|
// Compute start byte index
|
|
lua_pushvalue(L, 1); // string
|
|
lua_pushinteger(L, i); // start index
|
|
lua_call(L, 2, 1); // utf8.offset(s, i)
|
|
lua_Integer start = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
if (start == 0) {
|
|
lua_pushliteral(L, "");
|
|
lua_pop(L, 1); // pop utf8 table
|
|
return 1;
|
|
}
|
|
|
|
// Compute end byte index (j+1)
|
|
lua_getfield(L, -1, "offset");
|
|
lua_pushvalue(L, 1);
|
|
lua_pushinteger(L, j + 1);
|
|
lua_call(L, 2, 1);
|
|
lua_Integer end = lua_tointeger(L, -1);
|
|
lua_pop(L, 2); // pop result + utf8 table
|
|
|
|
if (end == 0) {
|
|
// until end of string
|
|
lua_pushlstring(L, s + start - 1, slen - (start - 1));
|
|
return 1;
|
|
}
|
|
|
|
lua_pushlstring(L, s + start - 1, (end - 1) - (start - 1));
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool lua_is_playing() {
|
|
return is_playing;
|
|
}
|
|
|
|
void lua_process_debugger_commands() {
|
|
while (true) {
|
|
std::string cmd;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(g_cmdMutex);
|
|
if (g_debugCommands.empty())
|
|
break;
|
|
|
|
cmd = g_debugCommands.front();
|
|
g_debugCommands.pop();
|
|
}
|
|
|
|
processDebugCommand(cmd);
|
|
}
|
|
}
|
|
|
|
void push_lua_funcs() {
|
|
lua_newtable(L);
|
|
lua_setglobal(L, "mini");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_surf_new); lua_setfield(L, -2, "new");
|
|
lua_pushcfunction(L,cpp_surf_load); lua_setfield(L, -2, "load");
|
|
lua_pushcfunction(L,cpp_surf_loadex); lua_setfield(L, -2, "loadex");
|
|
lua_pushcfunction(L,cpp_surf_save); lua_setfield(L, -2, "save");
|
|
lua_pushcfunction(L,cpp_surf_free); lua_setfield(L, -2, "free");
|
|
lua_pushcfunction(L,cpp_surf_size); lua_setfield(L, -2, "size");
|
|
lua_pushcfunction(L,cpp_surf_target); lua_setfield(L, -2, "target");
|
|
lua_pushcfunction(L,cpp_surf_source); lua_setfield(L, -2, "source");
|
|
lua_pushcfunction(L,cpp_surf_cls); lua_setfield(L, -2, "cls");
|
|
lua_pushcfunction(L,cpp_surf_pixel); lua_setfield(L, -2, "pixel");
|
|
|
|
lua_pushinteger(L, 0); lua_setfield(L, -2, "SCREEN");
|
|
lua_setglobal(L, "surf");
|
|
|
|
lua_newtable(L);
|
|
//lua_pushcfunction(L,cpp_map_new); lua_setfield(L, -2, "new");
|
|
//lua_pushcfunction(L,cpp_map_load); lua_setfield(L, -2, "load");
|
|
//lua_pushcfunction(L,cpp_map_save); lua_setfield(L, -2, "save");
|
|
lua_pushcfunction(L,cpp_map_surf); lua_setfield(L, -2, "surf");
|
|
lua_pushcfunction(L,cpp_map_draw); lua_setfield(L, -2, "draw");
|
|
lua_pushcfunction(L,cpp_map_tile); lua_setfield(L, -2, "tile");
|
|
lua_pushcfunction(L,cpp_map_cell); lua_setfield(L, -2, "cell");
|
|
lua_setglobal(L, "map");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_pal_load); lua_setfield(L, -2, "load");
|
|
lua_pushcfunction(L,cpp_pal_set); lua_setfield(L, -2, "set");
|
|
lua_pushcfunction(L,cpp_pal_color); lua_setfield(L, -2, "color");
|
|
lua_pushcfunction(L,cpp_pal_trans); lua_setfield(L, -2, "trans");
|
|
lua_pushcfunction(L,cpp_pal_subpal); lua_setfield(L, -2, "subpal");
|
|
lua_setglobal(L, "pal");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_viewport_clip); lua_setfield(L, -2, "clip");
|
|
lua_pushcfunction(L,cpp_viewport_origin); lua_setfield(L, -2, "origin");
|
|
lua_pushcfunction(L,cpp_viewport_tolocal); lua_setfield(L, -2, "tolocal");
|
|
lua_setglobal(L, "view");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_draw_line); lua_setfield(L, -2, "line");
|
|
lua_pushcfunction(L,cpp_draw_hline); lua_setfield(L, -2, "hline");
|
|
lua_pushcfunction(L,cpp_draw_vline); lua_setfield(L, -2, "vline");
|
|
lua_pushcfunction(L,cpp_draw_rect); lua_setfield(L, -2, "rect");
|
|
lua_pushcfunction(L,cpp_draw_rectfill); lua_setfield(L, -2, "rectf");
|
|
lua_pushcfunction(L,cpp_draw_circ); lua_setfield(L, -2, "circ");
|
|
lua_pushcfunction(L,cpp_draw_circfill); lua_setfield(L, -2, "circf");
|
|
lua_pushcfunction(L,cpp_draw_roundrect); lua_setfield(L, -2, "rrect");
|
|
lua_pushcfunction(L,cpp_draw_roundrectfill); lua_setfield(L, -2, "rrectf");
|
|
lua_pushcfunction(L,cpp_draw_oval); lua_setfield(L, -2, "oval");
|
|
lua_pushcfunction(L,cpp_draw_ovalfill); lua_setfield(L, -2, "ovalf");
|
|
lua_pushcfunction(L,cpp_draw_pattern); lua_setfield(L, -2, "pattern");
|
|
//lua_pushcfunction(L,cpp_draw_tline); lua_setfield(L, -2, "tline");
|
|
//lua_pushcfunction(L,cpp_draw_thline); lua_setfield(L, -2, "thline");
|
|
//lua_pushcfunction(L,cpp_draw_tvline); lua_setfield(L, -2, "tvline");
|
|
lua_pushcfunction(L,cpp_draw_surface); lua_setfield(L, -2, "surf");
|
|
lua_pushcfunction(L,cpp_draw_surfaceRotated); lua_setfield(L, -2, "surfrot");
|
|
lua_pushcfunction(L,cpp_draw_text); lua_setfield(L, -2, "text");
|
|
lua_pushcfunction(L,cpp_draw_mode); lua_setfield(L, -2, "mode");
|
|
|
|
lua_pushinteger(L, 0); lua_setfield(L, -2, "NORMAL");
|
|
lua_pushinteger(L, 1); lua_setfield(L, -2, "PATTERN");
|
|
lua_pushinteger(L, 2); lua_setfield(L, -2, "AND");
|
|
lua_pushinteger(L, 3); lua_setfield(L, -2, "OR");
|
|
lua_pushinteger(L, 4); lua_setfield(L, -2, "XOR");
|
|
lua_pushinteger(L, 5); lua_setfield(L, -2, "NOT");
|
|
|
|
lua_setglobal(L, "draw");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_shader_init); lua_setfield(L, -2, "init");
|
|
lua_pushcfunction(L,cpp_shader_enable); lua_setfield(L, -2, "enable");
|
|
lua_pushcfunction(L,cpp_shader_disable); lua_setfield(L, -2, "disable");
|
|
lua_setglobal(L, "shader");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_music_play); lua_setfield(L, -2, "play");
|
|
lua_pushcfunction(L,cpp_music_pause); lua_setfield(L, -2, "pause");
|
|
lua_pushcfunction(L,cpp_music_resume); lua_setfield(L, -2, "resume");
|
|
lua_pushcfunction(L,cpp_music_stop); lua_setfield(L, -2, "stop");
|
|
lua_pushcfunction(L,cpp_music_pos); lua_setfield(L, -2, "pos");
|
|
lua_pushcfunction(L,cpp_music_enable); lua_setfield(L, -2, "enabled");
|
|
lua_setglobal(L, "music");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_sound_load); lua_setfield(L, -2, "load");
|
|
lua_pushcfunction(L,cpp_sound_free); lua_setfield(L, -2, "free");
|
|
lua_pushcfunction(L,cpp_sound_play); lua_setfield(L, -2, "play");
|
|
lua_pushcfunction(L,cpp_sound_stop); lua_setfield(L, -2, "stop");
|
|
lua_pushcfunction(L,cpp_sound_enable); lua_setfield(L, -2, "enabled");
|
|
lua_setglobal(L, "sound");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_sys_delta); lua_setfield(L, -2, "delta");
|
|
lua_pushcfunction(L,cpp_sys_time); lua_setfield(L, -2, "time");
|
|
lua_pushcfunction(L,cpp_sys_chrono); lua_setfield(L, -2, "chrono");
|
|
lua_pushcfunction(L,cpp_sys_beat); lua_setfield(L, -2, "beat");
|
|
lua_pushcfunction(L,cpp_sys_update); lua_setfield(L, -2, "update");
|
|
lua_pushcfunction(L,cpp_sys_dir); lua_setfield(L, -2, "dir");
|
|
lua_pushcfunction(L,cpp_sys_exit); lua_setfield(L, -2, "quit");
|
|
lua_pushcfunction(L,cpp_sys_fps); lua_setfield(L, -2, "fps");
|
|
lua_pushcfunction(L,cpp_sys_debug); lua_setfield(L, -2, "debug");
|
|
lua_pushcfunction(L,cpp_sys_clipboard); lua_setfield(L, -2, "clipboard");
|
|
lua_pushcfunction(L,cpp_sys_version); lua_setfield(L, -2, "version");
|
|
|
|
lua_pushinteger(L, 0); lua_setfield(L, -2, "UPDATE_ALWAYS");
|
|
lua_pushinteger(L, 1); lua_setfield(L, -2, "UPDATE_WAIT");
|
|
lua_pushinteger(L, 2); lua_setfield(L, -2, "UPDATE_TIMEOUT");
|
|
|
|
lua_setglobal(L, "sys");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_win_zoom); lua_setfield(L, -2, "zoom");
|
|
lua_pushcfunction(L,cpp_win_fullscreen); lua_setfield(L, -2, "fullscreen");
|
|
lua_pushcfunction(L,cpp_win_cursor); lua_setfield(L, -2, "cursor");
|
|
lua_pushcfunction(L,cpp_win_res); lua_setfield(L, -2, "res");
|
|
lua_setglobal(L, "win");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_conf_key); lua_setfield(L, -2, "key");
|
|
lua_pushcfunction(L,cpp_conf_folder); lua_setfield(L, -2, "folder");
|
|
lua_setglobal(L, "config");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_font_load); lua_setfield(L, -2, "load");
|
|
lua_pushcfunction(L,cpp_font_current); lua_setfield(L, -2, "current");
|
|
lua_pushcfunction(L,cpp_font_spacing); lua_setfield(L, -2, "spacing");
|
|
|
|
lua_pushinteger(L, 0); lua_setfield(L, -2, "DEFAULT");
|
|
lua_setglobal(L, "font");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_mouse_pos); lua_setfield(L, -2, "pos");
|
|
lua_pushcfunction(L,cpp_mouse_wheel); lua_setfield(L, -2, "wheel");
|
|
lua_pushcfunction(L,cpp_mouse_down); lua_setfield(L, -2, "down");
|
|
lua_pushcfunction(L,cpp_mouse_press); lua_setfield(L, -2, "press");
|
|
lua_pushcfunction(L,cpp_mouse_dblclick); lua_setfield(L, -2, "dblclick");
|
|
lua_pushcfunction(L,cpp_mouse_discard); lua_setfield(L, -2, "discard");
|
|
lua_pushcfunction(L,cpp_mouse_inside); lua_setfield(L, -2, "inside");
|
|
|
|
lua_pushinteger(L, 1); lua_setfield(L, -2, "LEFT");
|
|
lua_pushinteger(L, 2); lua_setfield(L, -2, "MIDDLE");
|
|
lua_pushinteger(L, 3); lua_setfield(L, -2, "RIGHT");
|
|
lua_setglobal(L, "mouse");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_key_down); lua_setfield(L, -2, "down");
|
|
lua_pushcfunction(L,cpp_key_press); lua_setfield(L, -2, "press");
|
|
lua_pushcfunction(L,cpp_key_any); lua_setfield(L, -2, "any");
|
|
lua_pushcfunction(L,cpp_key_text); lua_setfield(L, -2, "text");
|
|
lua_pushcfunction(L,cpp_key_utf8char); lua_setfield(L, -2, "utf8char");
|
|
//lua_setglobal(L, "key");
|
|
|
|
//lua_newtable(L);
|
|
lua_pushinteger(L, 0); lua_setfield(L, -2, "UNKNOWN");
|
|
lua_pushinteger(L, 4); lua_setfield(L, -2, "A");
|
|
lua_pushinteger(L, 5); lua_setfield(L, -2, "B");
|
|
lua_pushinteger(L, 6); lua_setfield(L, -2, "C");
|
|
lua_pushinteger(L, 7); lua_setfield(L, -2, "D");
|
|
lua_pushinteger(L, 8); lua_setfield(L, -2, "E");
|
|
lua_pushinteger(L, 9); lua_setfield(L, -2, "F");
|
|
lua_pushinteger(L, 10); lua_setfield(L, -2, "G");
|
|
lua_pushinteger(L, 11); lua_setfield(L, -2, "H");
|
|
lua_pushinteger(L, 12); lua_setfield(L, -2, "I");
|
|
lua_pushinteger(L, 13); lua_setfield(L, -2, "J");
|
|
lua_pushinteger(L, 14); lua_setfield(L, -2, "K");
|
|
lua_pushinteger(L, 15); lua_setfield(L, -2, "L");
|
|
lua_pushinteger(L, 16); lua_setfield(L, -2, "M");
|
|
lua_pushinteger(L, 17); lua_setfield(L, -2, "N");
|
|
lua_pushinteger(L, 18); lua_setfield(L, -2, "O");
|
|
lua_pushinteger(L, 19); lua_setfield(L, -2, "P");
|
|
lua_pushinteger(L, 20); lua_setfield(L, -2, "Q");
|
|
lua_pushinteger(L, 21); lua_setfield(L, -2, "R");
|
|
lua_pushinteger(L, 22); lua_setfield(L, -2, "S");
|
|
lua_pushinteger(L, 23); lua_setfield(L, -2, "T");
|
|
lua_pushinteger(L, 24); lua_setfield(L, -2, "U");
|
|
lua_pushinteger(L, 25); lua_setfield(L, -2, "V");
|
|
lua_pushinteger(L, 26); lua_setfield(L, -2, "W");
|
|
lua_pushinteger(L, 27); lua_setfield(L, -2, "X");
|
|
lua_pushinteger(L, 28); lua_setfield(L, -2, "Y");
|
|
lua_pushinteger(L, 29); lua_setfield(L, -2, "Z");
|
|
lua_pushinteger(L, 30); lua_setfield(L, -2, "N1");
|
|
lua_pushinteger(L, 31); lua_setfield(L, -2, "N2");
|
|
lua_pushinteger(L, 32); lua_setfield(L, -2, "N3");
|
|
lua_pushinteger(L, 33); lua_setfield(L, -2, "N4");
|
|
lua_pushinteger(L, 34); lua_setfield(L, -2, "N5");
|
|
lua_pushinteger(L, 35); lua_setfield(L, -2, "N6");
|
|
lua_pushinteger(L, 36); lua_setfield(L, -2, "N7");
|
|
lua_pushinteger(L, 37); lua_setfield(L, -2, "N8");
|
|
lua_pushinteger(L, 38); lua_setfield(L, -2, "N9");
|
|
lua_pushinteger(L, 39); lua_setfield(L, -2, "N0");
|
|
lua_pushinteger(L, 40); lua_setfield(L, -2, "RETURN");
|
|
lua_pushinteger(L, 41); lua_setfield(L, -2, "ESCAPE");
|
|
lua_pushinteger(L, 42); lua_setfield(L, -2, "BACKSPACE");
|
|
lua_pushinteger(L, 43); lua_setfield(L, -2, "TAB");
|
|
lua_pushinteger(L, 44); lua_setfield(L, -2, "SPACE");
|
|
lua_pushinteger(L, 45); lua_setfield(L, -2, "MINUS");
|
|
lua_pushinteger(L, 46); lua_setfield(L, -2, "EQUALS");
|
|
lua_pushinteger(L, 47); lua_setfield(L, -2, "LEFTBRACKET");
|
|
lua_pushinteger(L, 48); lua_setfield(L, -2, "RIGHTBRACKET");
|
|
lua_pushinteger(L, 49); lua_setfield(L, -2, "BACKSLASH");
|
|
lua_pushinteger(L, 50); lua_setfield(L, -2, "NONUSHASH");
|
|
lua_pushinteger(L, 51); lua_setfield(L, -2, "SEMICOLON");
|
|
lua_pushinteger(L, 52); lua_setfield(L, -2, "APOSTROPHE");
|
|
lua_pushinteger(L, 53); lua_setfield(L, -2, "GRAVE");
|
|
lua_pushinteger(L, 54); lua_setfield(L, -2, "COMMA");
|
|
lua_pushinteger(L, 55); lua_setfield(L, -2, "PERIOD");
|
|
lua_pushinteger(L, 56); lua_setfield(L, -2, "SLASH");
|
|
lua_pushinteger(L, 57); lua_setfield(L, -2, "CAPSLOCK");
|
|
lua_pushinteger(L, 58); lua_setfield(L, -2, "F1");
|
|
lua_pushinteger(L, 59); lua_setfield(L, -2, "F2");
|
|
lua_pushinteger(L, 60); lua_setfield(L, -2, "F3");
|
|
lua_pushinteger(L, 61); lua_setfield(L, -2, "F4");
|
|
lua_pushinteger(L, 62); lua_setfield(L, -2, "F5");
|
|
lua_pushinteger(L, 63); lua_setfield(L, -2, "F6");
|
|
lua_pushinteger(L, 64); lua_setfield(L, -2, "F7");
|
|
lua_pushinteger(L, 65); lua_setfield(L, -2, "F8");
|
|
lua_pushinteger(L, 66); lua_setfield(L, -2, "F9");
|
|
lua_pushinteger(L, 67); lua_setfield(L, -2, "F10");
|
|
lua_pushinteger(L, 68); lua_setfield(L, -2, "F11");
|
|
lua_pushinteger(L, 69); lua_setfield(L, -2, "F12");
|
|
lua_pushinteger(L, 70); lua_setfield(L, -2, "PRINTSCREEN");
|
|
lua_pushinteger(L, 71); lua_setfield(L, -2, "SCROLLLOCK");
|
|
lua_pushinteger(L, 72); lua_setfield(L, -2, "PAUSE");
|
|
lua_pushinteger(L, 73); lua_setfield(L, -2, "INSERT");
|
|
lua_pushinteger(L, 74); lua_setfield(L, -2, "HOME");
|
|
lua_pushinteger(L, 75); lua_setfield(L, -2, "PAGEUP");
|
|
lua_pushinteger(L, 76); lua_setfield(L, -2, "DELETE");
|
|
lua_pushinteger(L, 77); lua_setfield(L, -2, "END");
|
|
lua_pushinteger(L, 78); lua_setfield(L, -2, "PAGEDOWN");
|
|
lua_pushinteger(L, 79); lua_setfield(L, -2, "RIGHT");
|
|
lua_pushinteger(L, 80); lua_setfield(L, -2, "LEFT");
|
|
lua_pushinteger(L, 81); lua_setfield(L, -2, "DOWN");
|
|
lua_pushinteger(L, 82); lua_setfield(L, -2, "UP");
|
|
lua_pushinteger(L, 83); lua_setfield(L, -2, "NUMLOCKCLEAR");
|
|
lua_pushinteger(L, 84); lua_setfield(L, -2, "KP_DIVIDE");
|
|
lua_pushinteger(L, 85); lua_setfield(L, -2, "KP_MULTIPLY");
|
|
lua_pushinteger(L, 86); lua_setfield(L, -2, "KP_MINUS");
|
|
lua_pushinteger(L, 87); lua_setfield(L, -2, "KP_PLUS");
|
|
lua_pushinteger(L, 88); lua_setfield(L, -2, "KP_ENTER");
|
|
lua_pushinteger(L, 89); lua_setfield(L, -2, "KP_1");
|
|
lua_pushinteger(L, 90); lua_setfield(L, -2, "KP_2");
|
|
lua_pushinteger(L, 91); lua_setfield(L, -2, "KP_3");
|
|
lua_pushinteger(L, 92); lua_setfield(L, -2, "KP_4");
|
|
lua_pushinteger(L, 93); lua_setfield(L, -2, "KP_5");
|
|
lua_pushinteger(L, 94); lua_setfield(L, -2, "KP_6");
|
|
lua_pushinteger(L, 95); lua_setfield(L, -2, "KP_7");
|
|
lua_pushinteger(L, 96); lua_setfield(L, -2, "KP_8");
|
|
lua_pushinteger(L, 97); lua_setfield(L, -2, "KP_9");
|
|
lua_pushinteger(L, 98); lua_setfield(L, -2, "KP_0");
|
|
lua_pushinteger(L, 99); lua_setfield(L, -2, "KP_PERIOD");
|
|
lua_pushinteger(L, 100); lua_setfield(L, -2, "NONUSBACKSLASH");
|
|
lua_pushinteger(L, 101); lua_setfield(L, -2, "APPLICATION");
|
|
lua_pushinteger(L, 224); lua_setfield(L, -2, "LCTRL");
|
|
lua_pushinteger(L, 225); lua_setfield(L, -2, "LSHIFT");
|
|
lua_pushinteger(L, 226); lua_setfield(L, -2, "LALT");
|
|
lua_pushinteger(L, 227); lua_setfield(L, -2, "LGUI");
|
|
lua_pushinteger(L, 228); lua_setfield(L, -2, "RCTRL");
|
|
lua_pushinteger(L, 229); lua_setfield(L, -2, "RSHIFT");
|
|
lua_pushinteger(L, 230); lua_setfield(L, -2, "RALT");
|
|
lua_pushinteger(L, 231); lua_setfield(L, -2, "RGUI");
|
|
|
|
lua_setglobal(L, "key");
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L,cpp_pad_down); lua_setfield(L, -2, "down");
|
|
lua_pushcfunction(L,cpp_pad_press); lua_setfield(L, -2, "press");
|
|
lua_pushcfunction(L,cpp_pad_any); lua_setfield(L, -2, "any");
|
|
//lua_setglobal(L, "gamepad");
|
|
|
|
//lua_newtable(L);
|
|
lua_pushinteger(L, -1); lua_setfield(L, -2, "INVALID");
|
|
lua_pushinteger(L, 0); lua_setfield(L, -2, "A");
|
|
lua_pushinteger(L, 1); lua_setfield(L, -2, "B");
|
|
lua_pushinteger(L, 2); lua_setfield(L, -2, "X");
|
|
lua_pushinteger(L, 3); lua_setfield(L, -2, "Y");
|
|
lua_pushinteger(L, 4); lua_setfield(L, -2, "BACK");
|
|
lua_pushinteger(L, 5); lua_setfield(L, -2, "GUIDE");
|
|
lua_pushinteger(L, 6); lua_setfield(L, -2, "START");
|
|
lua_pushinteger(L, 7); lua_setfield(L, -2, "LEFTSTICK");
|
|
lua_pushinteger(L, 8); lua_setfield(L, -2, "RIGHTSTICK");
|
|
lua_pushinteger(L, 9); lua_setfield(L, -2, "LEFTSHOULDER");
|
|
lua_pushinteger(L, 10); lua_setfield(L, -2, "RIGHTSHOULDER");
|
|
lua_pushinteger(L, 11); lua_setfield(L, -2, "UP");
|
|
lua_pushinteger(L, 12); lua_setfield(L, -2, "DOWN");
|
|
lua_pushinteger(L, 13); lua_setfield(L, -2, "LEFT");
|
|
lua_pushinteger(L, 14); lua_setfield(L, -2, "RIGHT");
|
|
lua_pushinteger(L, 15); lua_setfield(L, -2, "MISC1");
|
|
lua_pushinteger(L, 16); lua_setfield(L, -2, "PADDLE1");
|
|
lua_pushinteger(L, 17); lua_setfield(L, -2, "PADDLE2");
|
|
lua_pushinteger(L, 18); lua_setfield(L, -2, "PADDLE3");
|
|
lua_pushinteger(L, 19); lua_setfield(L, -2, "PADDLE4");
|
|
lua_pushinteger(L, 20); lua_setfield(L, -2, "TOUCHPAD");
|
|
|
|
lua_setglobal(L, "pad");
|
|
|
|
|
|
lua_getglobal(L, "utf8"); // push utf8 table
|
|
lua_pushcfunction(L, cpp_utf8_sub); // push C function
|
|
lua_setfield(L, -2, "sub"); // utf8.sub = cpp_utf8_sub
|
|
lua_pop(L, 1); // pop utf8 table
|
|
}
|
|
|
|
/*
|
|
int MiniLoader(lua_State *L) {
|
|
const char *name = luaL_checkstring(L, 1);
|
|
char filename[strlen(name)+5];
|
|
strcpy(filename, name);
|
|
strcat(filename, ".lua");
|
|
int size;
|
|
char* buffer = file_getfilebuffer(filename, size);
|
|
if (luaL_loadbuffer(L, buffer, size, filename)) {
|
|
log_msg(LOG_LUALD, "%s\n",lua_tostring(L, -1));
|
|
lua_pop(L,1);
|
|
//return ;
|
|
}
|
|
free(buffer);
|
|
return 1;
|
|
}
|
|
*/
|
|
|
|
int MiniLoader(lua_State *L) {
|
|
const char *name = luaL_checkstring(L, 1);
|
|
|
|
// 1. Convertir puntos en barras
|
|
std::string path(name);
|
|
std::string regpath(name);
|
|
std::replace(path.begin(), path.end(), '.', '/');
|
|
|
|
// 2. Detectar comodín "/*"
|
|
bool load_all = false;
|
|
if (path.size() >= 2 && path.substr(path.size()-2) == "/*") {
|
|
load_all = true;
|
|
path = path.substr(0, path.size()-2); // quitar "/*"
|
|
regpath = regpath.substr(0, regpath.size()-2); // quitar "/*"
|
|
}
|
|
|
|
if (load_all) {
|
|
std::vector<std::string> files = file_listdir(path.c_str(), "lua");
|
|
|
|
// Ejecutar todos los módulos
|
|
for (auto &f : files) {
|
|
std::string fullpath = path + "/" + f;
|
|
std::string registerpath = std::string(regpath + "." + f.substr(0,f.size()-4));
|
|
|
|
int size;
|
|
char* buffer = file_getfilebuffer(fullpath.c_str(), size);
|
|
if (!buffer) continue;
|
|
|
|
if (luaL_loadbuffer(L, buffer, size, registerpath.c_str()) == LUA_OK) {
|
|
lua_pcall(L, 0, 0, 0); // ejecutar módulo, sin devolver nada
|
|
lua_getglobal(L, "package");
|
|
lua_getfield(L, -1, "loaded");
|
|
lua_pushboolean(L, 1);
|
|
lua_setfield(L, -2, registerpath.c_str());
|
|
lua_pop(L, 2);
|
|
} else {
|
|
log_msg(LOG_LUALD, "Error cargando %s: %s\n", fullpath.c_str(), lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
// Devolver un loader vacío
|
|
lua_pushcfunction(L, [](lua_State* L) -> int {
|
|
lua_pushboolean(L, 1); // require devuelve true
|
|
return 1;
|
|
});
|
|
|
|
return 1;
|
|
}
|
|
|
|
// 3. Cargar un único archivo
|
|
std::string filename = path + ".lua";
|
|
|
|
int size;
|
|
char* buffer = file_getfilebuffer(filename.c_str(), size);
|
|
if (!buffer) {
|
|
lua_pushnil(L);
|
|
return 1;
|
|
}
|
|
|
|
if (luaL_loadbuffer(L, buffer, size, name)) {
|
|
log_msg(LOG_LUALD, "%s\n", lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
free(buffer);
|
|
lua_pushnil(L);
|
|
return 1;
|
|
}
|
|
|
|
free(buffer);
|
|
return 1;
|
|
}
|
|
|
|
void lua_init(const char *main_lua_file) {
|
|
L = luaL_newstate();
|
|
luaL_openlibs(L);
|
|
|
|
push_lua_funcs();
|
|
lua_register(L, "mini_loader", MiniLoader);
|
|
luaL_dostring(L, "table.insert(package.searchers,2,mini_loader)\n");
|
|
|
|
int size;
|
|
char* buffer = file_getfilebuffer(main_lua_file, size);
|
|
if (luaL_loadbuffer(L, buffer, size, "main")) {
|
|
log_msg(LOG_LUALD, "%s\n", lua_tostring(L, -1));
|
|
lua_pop(L,1);
|
|
return;
|
|
}
|
|
free(buffer);
|
|
if (lua_pcall(L,0, LUA_MULTRET, 0)) {
|
|
//luaL_traceback(L, L, NULL, 1);
|
|
log_msg(LOG_LUART, "%s\n", lua_tostring(L, -1));
|
|
lua_pop(L,1);
|
|
return;
|
|
}
|
|
|
|
// Check if _init and _update exist
|
|
lua_getglobal(L, "mini");
|
|
lua_getfield(L, -1, "init");
|
|
if (lua_isfunction(L,-1)) init_exists = true;
|
|
lua_pop(L,1);
|
|
lua_pop(L,1);
|
|
|
|
lua_getglobal(L, "mini");
|
|
lua_getfield(L, -1, "update");
|
|
if (lua_isfunction(L,-1)) update_exists = true;
|
|
lua_pop(L,1);
|
|
lua_pop(L,1);
|
|
|
|
//std::thread(debugCommandThread).detach();
|
|
printf("stdin isatty: %d\n", isatty(0));
|
|
is_playing = true;
|
|
}
|
|
|
|
void lua_call_init() {
|
|
if (!init_exists) return;
|
|
lua_process_debugger_commands();
|
|
lua_getglobal(L, "mini");
|
|
lua_getfield(L, -1, "init");
|
|
if (lua_pcall(L, 0, 0, 0)) {
|
|
log_msg(LOG_LUART, "%s\n", lua_tostring(L, -1));
|
|
lua_pop(L,1);
|
|
is_playing = false;
|
|
}
|
|
}
|
|
|
|
void lua_call_update() {
|
|
if (!update_exists) return;
|
|
function_has_breakpoints = false;
|
|
while (!funBreakStack.empty()) funBreakStack.pop();
|
|
lua_process_debugger_commands();
|
|
delta_time = float(SDL_GetTicks() - last_update)/1000.0f;
|
|
last_update = SDL_GetTicks();
|
|
lua_getglobal(L, "mini");
|
|
lua_getfield(L, -1, "update");
|
|
if (lua_pcall(L, 0, 0, 0)) {
|
|
log_msg(LOG_LUART, "%s\n", lua_tostring(L, -1));
|
|
lua_pop(L,1);
|
|
is_playing = false;
|
|
}
|
|
}
|
|
|
|
#include <poll.h>
|
|
|
|
std::jthread stdinThread([](std::stop_token st) {
|
|
std::string line;
|
|
|
|
struct pollfd pfd;
|
|
pfd.fd = 0; // stdin
|
|
pfd.events = POLLIN; // queremos saber si hay datos
|
|
|
|
while (!st.stop_requested()) {
|
|
int ret = poll(&pfd, 1, 10); // timeout 10 ms
|
|
|
|
if (ret > 0 && (pfd.revents & POLLIN)) {
|
|
if (!std::getline(std::cin, line)) {
|
|
break; // EOF
|
|
}
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(g_cmdMutex);
|
|
g_debugCommands.push(line);
|
|
printf("COMANDO RECIBIDO: %s\n", line.c_str());
|
|
}
|
|
} else {
|
|
SDL_Delay(1);
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
void lua_quit() {
|
|
if (!is_playing) return;
|
|
is_playing = false;
|
|
lua_close(L);
|
|
}
|
|
|
|
void lua_kill_thread() {
|
|
g_running = false;
|
|
stdinThread.request_stop();
|
|
}
|
|
|
|
void lua_toggle_debug() {
|
|
if (debug_enabled) {
|
|
debug_enabled = false;
|
|
lua_sethook(L, NULL,0, 0);
|
|
} else {
|
|
debug_enabled = true;
|
|
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0);
|
|
}
|
|
}
|