summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2012-08-31 18:39:11 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2012-08-31 18:39:11 (GMT)
commit493a32a1b28f15cf02bb69c3735b9a411448c523 (patch)
tree838b39db197c1f9cab5740703bb03f9b24702c56 /src
parent322d224fa7a1d5f155c87596bb2f5927989e9933 (diff)
downloadpowder-493a32a1b28f15cf02bb69c3735b9a411448c523.zip
powder-493a32a1b28f15cf02bb69c3735b9a411448c523.tar.gz
Some Lua interface API stuff
Diffstat (limited to 'src')
-rw-r--r--src/cat/LuaButton.cpp134
-rw-r--r--src/cat/LuaButton.h33
-rw-r--r--src/cat/LuaLuna.h128
-rw-r--r--src/cat/LuaScriptInterface.cpp65
-rw-r--r--src/cat/LuaScriptInterface.h14
-rw-r--r--src/cat/LuaWindow.cpp101
-rw-r--r--src/cat/LuaWindow.h30
-rw-r--r--src/game/GameController.cpp10
-rw-r--r--src/game/GameController.h1
-rw-r--r--src/interface/Button.h1
10 files changed, 513 insertions, 4 deletions
diff --git a/src/cat/LuaButton.cpp b/src/cat/LuaButton.cpp
new file mode 100644
index 0000000..8a3c92d
--- /dev/null
+++ b/src/cat/LuaButton.cpp
@@ -0,0 +1,134 @@
+extern "C"
+{
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+}
+
+#include <iostream>
+#include "LuaButton.h"
+#include "interface/Button.h"
+
+const char LuaButton::className[] = "Button";
+
+#define method(class, name) {#name, &class::name}
+Luna<LuaButton>::RegType LuaButton::methods[] = {
+ method(LuaButton, action),
+ method(LuaButton, text),
+ method(LuaButton, position),
+ method(LuaButton, size),
+ {0, 0}
+};
+
+LuaButton::LuaButton(lua_State * l) :
+ actionFunction(0)
+{
+ this->l = l;
+ int posX = luaL_optinteger(l, 1, 0);
+ int posY = luaL_optinteger(l, 2, 0);
+ int sizeX = luaL_optinteger(l, 3, 10);
+ int sizeY = luaL_optinteger(l, 4, 10);
+ std::string text = luaL_optstring(l, 5, "");
+ std::string toolTip = luaL_optstring(l, 6, "");;
+
+ button = new ui::Button(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text, toolTip);
+ class ClickAction : public ui::ButtonAction
+ {
+ LuaButton * luaButton;
+ public:
+ ClickAction(LuaButton * luaButton) : luaButton(luaButton) {}
+ void ActionCallback(ui::Button * sender)
+ {
+ luaButton->triggerAction();
+ }
+ };
+ button->SetActionCallback(new ClickAction(this));
+}
+
+int LuaButton::action(lua_State * l)
+{
+ if(lua_type(l, 1) != LUA_TNIL)
+ {
+ luaL_checktype(l, 1, LUA_TFUNCTION);
+ lua_pushvalue(l, 1);
+ actionFunction = luaL_ref(l, LUA_REGISTRYINDEX);
+ }
+ else
+ {
+ actionFunction = 0;
+ }
+}
+
+int LuaButton::text(lua_State * l)
+{
+ int args = lua_gettop(l);
+ if(args)
+ {
+ luaL_checktype(l, 1, LUA_TSTRING);
+ button->SetText(lua_tostring(l, 1));
+ return 0;
+ }
+ else
+ {
+ lua_pushstring(l, button->GetText().c_str());
+ return 1;
+ }
+}
+
+int LuaButton::position(lua_State * l)
+{
+ int args = lua_gettop(l);
+ if(args)
+ {
+ luaL_checktype(l, 1, LUA_TNUMBER);
+ luaL_checktype(l, 2, LUA_TNUMBER);
+ button->Position = ui::Point(lua_tointeger(l, 1), lua_tointeger(l, 2));
+ return 0;
+ }
+ else
+ {
+ lua_pushinteger(l, button->Position.X);
+ lua_pushinteger(l, button->Position.Y);
+ return 2;
+ }
+}
+
+int LuaButton::size(lua_State * l)
+{
+ int args = lua_gettop(l);
+ if(args)
+ {
+ luaL_checktype(l, 1, LUA_TNUMBER);
+ luaL_checktype(l, 2, LUA_TNUMBER);
+ button->Size = ui::Point(lua_tointeger(l, 1), lua_tointeger(l, 2));
+ button->Invalidate();
+ return 0;
+ }
+ else
+ {
+ lua_pushinteger(l, button->Size.X);
+ lua_pushinteger(l, button->Size.Y);
+ return 2;
+ }
+}
+
+void LuaButton::triggerAction()
+{
+ if(actionFunction)
+ {
+ std::cout << actionFunction << std::endl;
+ lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction);
+ lua_pushinteger(l, 1);
+ if (lua_pcall(l, 1, 1, 0))
+ {
+ //Log error somewhere
+ }
+ }
+}
+
+LuaButton::~LuaButton()
+{
+ if(button->GetParentWindow())
+ button->GetParentWindow()->RemoveComponent(button);
+ delete button;
+} \ No newline at end of file
diff --git a/src/cat/LuaButton.h b/src/cat/LuaButton.h
new file mode 100644
index 0000000..ef5bb54
--- /dev/null
+++ b/src/cat/LuaButton.h
@@ -0,0 +1,33 @@
+#pragma once
+
+extern "C" {
+ #include "lua.h"
+ #include "lauxlib.h"
+ #include "lualib.h"
+}
+
+#include "LuaLuna.h"
+
+namespace ui
+{
+ class Button;
+}
+
+class LuaButton
+{
+ ui::Button * button;
+ int actionFunction;
+ lua_State * l;
+ void triggerAction();
+ int action(lua_State * l);
+ int text(lua_State * l);
+ int position(lua_State * l);
+ int size(lua_State * l);
+public:
+ static const char className[];
+ static Luna<LuaButton>::RegType methods[];
+
+ ui::Button * GetComponent() { return button; }
+ LuaButton(lua_State * l);
+ ~LuaButton();
+}; \ No newline at end of file
diff --git a/src/cat/LuaLuna.h b/src/cat/LuaLuna.h
new file mode 100644
index 0000000..d15a7c6
--- /dev/null
+++ b/src/cat/LuaLuna.h
@@ -0,0 +1,128 @@
+#pragma once
+//http://lua-users.org/wiki/SimplerCppBinding
+
+extern "C" {
+#include "lua.h"
+#include "lauxlib.h"
+}
+
+template <typename T> class Luna
+{
+ typedef struct { T *pT; } userdataType;
+public:
+ typedef int (T::*mfp)(lua_State *L);
+ typedef struct { const char *name; mfp mfunc; } RegType;
+
+ static void Register(lua_State *L)
+ {
+ lua_newtable(L);
+ int methods = lua_gettop(L);
+
+ luaL_newmetatable(L, T::className);
+ int metatable = lua_gettop(L);
+
+ // store method table in globals so that
+ // scripts can add functions written in Lua.
+ lua_pushstring(L, T::className);
+ lua_pushvalue(L, methods);
+ lua_settable(L, LUA_GLOBALSINDEX);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methods);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methods);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__tostring");
+ lua_pushcfunction(L, tostring_T);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_T);
+ lua_settable(L, metatable);
+
+ lua_newtable(L); // mt for method table
+ int mt = lua_gettop(L);
+ lua_pushliteral(L, "__call");
+ lua_pushcfunction(L, new_T);
+ lua_pushliteral(L, "new");
+ lua_pushvalue(L, -2); // dup new_T function
+ lua_settable(L, methods); // add new_T to method table
+ lua_settable(L, mt); // mt.__call = new_T
+ lua_setmetatable(L, methods);
+
+ // fill method table with methods from class T
+ for (RegType *l = T::methods; l->name; l++)
+ {
+ /* edited by Snaily: shouldn't it be const RegType *l ... ? */
+ lua_pushstring(L, l->name);
+ lua_pushlightuserdata(L, (void*)l);
+ lua_pushcclosure(L, thunk, 1);
+ lua_settable(L, methods);
+ }
+
+ lua_pop(L, 2); // drop metatable and method table
+ }
+
+ // get userdata from Lua stack and return pointer to T object
+ static T * check(lua_State * L, int narg)
+ {
+ userdataType *ud = static_cast<userdataType*>(luaL_checkudata(L, narg, T::className));
+ if(!ud)
+ luaL_typerror(L, narg, T::className);
+ return ud->pT; // pointer to T object
+ }
+
+ static inline T * get(void * userData)
+ {
+ return ((userdataType*)userData)->pT;
+ }
+
+private:
+ Luna(); // hide default constructor
+
+ // member function dispatcher
+ static int thunk(lua_State * L)
+ {
+ // stack has userdata, followed by method args
+ T *obj = check(L, 1); // get 'self', or if you prefer, 'this'
+ lua_remove(L, 1); // remove self so member function args start at index 1
+ // get member function from upvalue
+ RegType *l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
+ return (obj->*(l->mfunc))(L); // call member function
+ }
+
+ // create a new T object and
+ // push onto the Lua stack a userdata containing a pointer to T object
+ static int new_T(lua_State * L)
+ {
+ lua_remove(L, 1); // use classname:new(), instead of classname.new()
+ T *obj = new T(L); // call constructor for T objects
+ userdataType *ud = static_cast<userdataType*>(lua_newuserdata(L, sizeof(userdataType)));
+ ud->pT = obj; // store pointer to object in userdata
+ luaL_getmetatable(L, T::className); // lookup metatable in Lua registry
+ lua_setmetatable(L, -2);
+ return 1; // userdata containing pointer to T object
+ }
+
+ // garbage collection metamethod
+ static int gc_T(lua_State *L)
+ {
+ userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
+ T *obj = ud->pT;
+ delete obj; // call destructor for T objects
+ return 0;
+ }
+
+ static int tostring_T (lua_State * L)
+ {
+ char buff[32];
+ userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
+ T *obj = ud->pT;
+ sprintf(buff, "%p", obj);
+ lua_pushfstring(L, "%s (%s)", T::className, buff);
+ return 1;
+ }
+}; \ No newline at end of file
diff --git a/src/cat/LuaScriptInterface.cpp b/src/cat/LuaScriptInterface.cpp
index 84b4b9e..fe098a0 100644
--- a/src/cat/LuaScriptInterface.cpp
+++ b/src/cat/LuaScriptInterface.cpp
@@ -25,6 +25,10 @@
#include "LuaBit.h"
+#include "LuaLuna.h"
+#include "LuaWindow.h"
+#include "LuaButton.h"
+
#ifdef WIN
#include <direct.h>
#else
@@ -48,6 +52,7 @@ LuaScriptInterface::LuaScriptInterface(GameModel * m):
luaL_openlibs(l);
luaopen_bit(l);
+ initInterfaceAPI();
initRendererAPI();
initElementsAPI();
@@ -251,10 +256,66 @@ tpt.partsdata = nil");
lua_el_mode[i] = 0;
}
- //Autorun
- luacon_eval("dofile(\"autorun.lua\")"); //Autorun lua script
}
+void LuaScriptInterface::Init()
+{
+ if(luacon_eval("dofile(\"autorun.lua\")"))
+ {
+ luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
+ }
+}
+
+void LuaScriptInterface::SetWindow(ui::Window * window)
+{
+ Window = window;
+}
+
+//// Begin Interface API
+
+void LuaScriptInterface::initInterfaceAPI()
+{
+ struct luaL_reg interfaceAPIMethods [] = {
+ {"showWindow", interface_showWindow},
+ {"closeWindow", interface_closeWindow},
+ {"addComponent", interface_addComponent},
+ {NULL, NULL}
+ };
+ luaL_register(l, "interface", interfaceAPIMethods);
+ Luna<LuaWindow>::Register(l);
+ Luna<LuaButton>::Register(l);
+}
+
+int LuaScriptInterface::interface_addComponent(lua_State * l)
+{
+ void * luaComponent = NULL;
+ ui::Component * component = NULL;
+ if(luaComponent = luaL_checkudata(l, 1, "Button"))
+ component = Luna<LuaButton>::get(luaComponent)->GetComponent();
+ else
+ luaL_typerror(l, 1, "Component");
+ if(luacon_ci->Window && component)
+ luacon_ci->Window->AddComponent(component);
+ return 0;
+}
+
+int LuaScriptInterface::interface_showWindow(lua_State * l)
+{
+ LuaWindow * window = Luna<LuaWindow>::check(l, 1);
+ if(window && ui::Engine::Ref().GetWindow()!=window->GetWindow())
+ ui::Engine::Ref().ShowWindow(window->GetWindow());
+ return 0;
+}
+
+int LuaScriptInterface::interface_closeWindow(lua_State * l)
+{
+ LuaWindow * window = Luna<LuaWindow>::check(l, 1);
+ if(window && ui::Engine::Ref().GetWindow()==window->GetWindow())
+ ui::Engine::Ref().CloseWindow();
+ return 0;
+}
+
+
//// Begin Renderer API
void LuaScriptInterface::initRendererAPI()
diff --git a/src/cat/LuaScriptInterface.h b/src/cat/LuaScriptInterface.h
index 96fd66b..37adc65 100644
--- a/src/cat/LuaScriptInterface.h
+++ b/src/cat/LuaScriptInterface.h
@@ -18,6 +18,11 @@ extern "C"
#include "CommandInterface.h"
#include "simulation/Simulation.h"
+namespace ui
+{
+ class Window;
+}
+
//Because lua only has bindings for C, we're going to have to go outside "outside" the LuaScriptInterface, this means we can only have one instance :(
#define LOCAL_LUA_DIR "Lua"
@@ -53,7 +58,14 @@ class LuaScriptInterface: public CommandInterface {
static int elements_property(lua_State * l);
static int elements_loadDefault(lua_State * l);
static int elements_free(lua_State * l);
+
+ //Interface
+ void initInterfaceAPI();
+ static int interface_showWindow(lua_State * l);
+ static int interface_closeWindow(lua_State * l);
+ static int interface_addComponent(lua_State * l);
public:
+ ui::Window * Window;
lua_State *l;
LuaScriptInterface(GameModel * m);
virtual bool OnBrushChanged(int brushType, int rx, int ry);
@@ -64,6 +76,8 @@ public:
virtual bool OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
virtual bool OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
virtual void OnTick();
+ virtual void Init();
+ virtual void SetWindow(ui::Window * window);
virtual int Command(std::string command);
virtual std::string FormatCommand(std::string command);
virtual ~LuaScriptInterface();
diff --git a/src/cat/LuaWindow.cpp b/src/cat/LuaWindow.cpp
new file mode 100644
index 0000000..cedfcdc
--- /dev/null
+++ b/src/cat/LuaWindow.cpp
@@ -0,0 +1,101 @@
+extern "C"
+{
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+}
+
+#include <iostream>
+#include "LuaWindow.h"
+#include "LuaButton.h"
+#include "interface/Button.h"
+#include "interface/Window.h"
+
+const char LuaWindow::className[] = "Window";
+
+#define method(class, name) {#name, &class::name}
+Luna<LuaWindow>::RegType LuaWindow::methods[] = {
+ method(LuaWindow, position),
+ method(LuaWindow, size),
+ method(LuaWindow, addComponent),
+ {0, 0}
+};
+
+LuaWindow::LuaWindow(lua_State * l)
+{
+ this->l = l;
+ int posX = luaL_optinteger(l, 1, 0);
+ int posY = luaL_optinteger(l, 2, 0);
+ int sizeX = luaL_optinteger(l, 3, 10);
+ int sizeY = luaL_optinteger(l, 4, 10);
+
+ class DrawnWindow : public ui::Window
+ {
+ public:
+ DrawnWindow(ui::Point position, ui::Point size) : ui::Window(position, size) {}
+ virtual void OnDraw()
+ {
+ Graphics * g = ui::Engine::Ref().g;
+ g->clearrect(Position.X-2, Position.Y-2, Size.X+4, Size.Y+4);
+ g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 255, 255, 255, 255);
+ }
+ };
+
+ window = new DrawnWindow(ui::Point(posX, posY), ui::Point(sizeX, sizeY));
+}
+
+int LuaWindow::addComponent(lua_State * l)
+{
+ void * luaComponent = NULL;
+ ui::Component * component = NULL;
+ if(luaComponent = luaL_checkudata(l, 1, "Button"))
+ component = Luna<LuaButton>::get(luaComponent)->GetComponent();
+ else
+ luaL_typerror(l, 1, "Component");
+ if(component)
+ window->AddComponent(component);
+ return 0;
+}
+
+int LuaWindow::position(lua_State * l)
+{
+ int args = lua_gettop(l);
+ if(args)
+ {
+ luaL_checktype(l, 1, LUA_TNUMBER);
+ luaL_checktype(l, 2, LUA_TNUMBER);
+ window->Position = ui::Point(lua_tointeger(l, 1), lua_tointeger(l, 2));
+ return 0;
+ }
+ else
+ {
+ lua_pushinteger(l, window->Position.X);
+ lua_pushinteger(l, window->Position.Y);
+ return 2;
+ }
+}
+
+int LuaWindow::size(lua_State * l)
+{
+ int args = lua_gettop(l);
+ if(args)
+ {
+ luaL_checktype(l, 1, LUA_TNUMBER);
+ luaL_checktype(l, 2, LUA_TNUMBER);
+ window->Size = ui::Point(lua_tointeger(l, 1), lua_tointeger(l, 2));
+ return 0;
+ }
+ else
+ {
+ lua_pushinteger(l, window->Size.X);
+ lua_pushinteger(l, window->Size.Y);
+ return 2;
+ }
+}
+
+LuaWindow::~LuaWindow()
+{
+ if(ui::Engine::Ref().GetWindow() == window)
+ ui::Engine::Ref().CloseWindow();
+ delete window;
+} \ No newline at end of file
diff --git a/src/cat/LuaWindow.h b/src/cat/LuaWindow.h
new file mode 100644
index 0000000..ea7b98f
--- /dev/null
+++ b/src/cat/LuaWindow.h
@@ -0,0 +1,30 @@
+#pragma once
+
+extern "C" {
+ #include "lua.h"
+ #include "lauxlib.h"
+ #include "lualib.h"
+}
+
+#include "LuaLuna.h"
+
+namespace ui
+{
+ class Window;
+}
+
+class LuaWindow
+{
+ ui::Window * window;
+ lua_State * l;
+ int position(lua_State * l);
+ int size(lua_State * l);
+ int addComponent(lua_State * l);
+public:
+ static const char className[];
+ static Luna<LuaWindow>::RegType methods[];
+
+ ui::Window * GetWindow() { return window; }
+ LuaWindow(lua_State * l);
+ ~LuaWindow();
+}; \ No newline at end of file
diff --git a/src/game/GameController.cpp b/src/game/GameController.cpp
index 2258239..ffa763f 100644
--- a/src/game/GameController.cpp
+++ b/src/game/GameController.cpp
@@ -140,7 +140,8 @@ GameController::GameController():
options(NULL),
activePreview(NULL),
localBrowser(NULL),
- HasDone(false)
+ HasDone(false),
+ firstTick(true)
{
gameView = new GameView();
gameModel = new GameModel();
@@ -149,7 +150,7 @@ GameController::GameController():
gameModel->AddObserver(gameView);
commandInterface = new LuaScriptInterface(gameModel);//new TPTScriptInterface();
- //commandInterface->AttachGameModel(gameModel);
+ ((LuaScriptInterface*)commandInterface)->SetWindow(gameView);
//sim = new Simulation();
Client::Ref().AddListener(this);
@@ -658,6 +659,11 @@ bool GameController::KeyRelease(int key, Uint16 character, bool shift, bool ctrl
void GameController::Tick()
{
+ if(firstTick)
+ {
+ ((LuaScriptInterface*)commandInterface)->Init();
+ firstTick = false;
+ }
commandInterface->OnTick();
}
diff --git a/src/game/GameController.h b/src/game/GameController.h
index ea24bb2..af3f1bf 100644
--- a/src/game/GameController.h
+++ b/src/game/GameController.h
@@ -31,6 +31,7 @@ class GameController: public ClientListener
{
private:
//Simulation * sim;
+ bool firstTick;
int screenshotIndex;
PreviewController * activePreview;
GameView * gameView;
diff --git a/src/interface/Button.h b/src/interface/Button.h
index 6b7fb96..2244a91 100644
--- a/src/interface/Button.h
+++ b/src/interface/Button.h
@@ -53,6 +53,7 @@ public:
ButtonAction * GetActionCallback() { return actionCallback; }
void SetText(std::string buttonText);
void SetIcon(Icon icon);
+ inline std::string GetText() { return ButtonText; };
protected:
std::string toolTip;