From 3597b73bc6e3e169f1d360de80d77e6e0ab65e96 Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Wed, 22 May 2013 20:12:50 +0000 Subject: [PATCH] expand SkLua to handle creation of its own State add lua sample BUG= R=robertphillips@google.com Review URL: https://codereview.chromium.org/15742009 git-svn-id: http://skia.googlecode.com/svn/trunk@9247 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gyp/SampleApp.gyp | 6 ++ include/utils/SkLua.h | 18 +++-- samplecode/SampleLua.cpp | 110 ++++++++++++++++++++++++++++++ src/utils/SkLua.cpp | 135 ++++++++++++++++++++++++++++--------- src/utils/SkLuaCanvas.cpp | 2 +- tools/lua/lua_pictures.cpp | 49 +------------- 6 files changed, 238 insertions(+), 82 deletions(-) create mode 100644 samplecode/SampleLua.cpp diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp index a240f32403..5531605512 100644 --- a/gyp/SampleApp.gyp +++ b/gyp/SampleApp.gyp @@ -76,6 +76,7 @@ '../samplecode/SampleLayers.cpp', '../samplecode/SampleLCD.cpp', '../samplecode/SampleLines.cpp', + '../samplecode/SampleLua.cpp', '../samplecode/SampleManyRects.cpp', '../samplecode/SampleMeasure.cpp', '../samplecode/SampleMipMap.cpp', @@ -129,6 +130,10 @@ # TiledPipeController '../src/pipe/utils/SamplePipeControllers.h', '../src/pipe/utils/SamplePipeControllers.cpp', + + # Lua + '../src/utils/SkLuaCanvas.cpp', + '../src/utils/SkLua.cpp', ], 'sources!': [ '../samplecode/SampleSkLayer.cpp', #relies on SkMatrix44 which doesn't compile @@ -146,6 +151,7 @@ 'experimental.gyp:experimental', 'pdf.gyp:pdf', 'views_animated.gyp:views_animated', + 'lua.gyp:lua', ], 'conditions' : [ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', { diff --git a/include/utils/SkLua.h b/include/utils/SkLua.h index 232ba9b8ee..8f48bc1ee1 100644 --- a/include/utils/SkLua.h +++ b/include/utils/SkLua.h @@ -10,6 +10,7 @@ #include "SkColor.h" #include "SkScalar.h" +#include "SkString.h" struct lua_State; @@ -19,7 +20,6 @@ class SkPaint; class SkPath; struct SkRect; class SkRRect; -class SkString; #define SkScalarToLua(x) SkScalarToDouble(x) #define SkLuaToScalar(x) SkDoubleToScalar(x) @@ -28,11 +28,17 @@ class SkLua { public: static void Load(lua_State*); - SkLua(lua_State*); + SkLua(const char termCode[] = NULL); // creates a new L, will close it + SkLua(lua_State*); // uses L, will not close it ~SkLua(); - lua_State* getL() const { return fL; } - + lua_State* get() const { return fL; } + lua_State* operator*() const { return fL; } + lua_State* operator->() const { return fL; } + + bool runCode(const char code[]); + bool runCode(const void* code, size_t size); + void pushBool(bool, const char tableKey[] = NULL); void pushString(const char[], const char tableKey[] = NULL); void pushString(const SkString&, const char tableKey[] = NULL); @@ -46,7 +52,9 @@ public: void pushCanvas(SkCanvas*, const char tableKey[] = NULL); private: - lua_State* fL; + lua_State* fL; + SkString fTermCode; + bool fWeOwnL; }; #endif diff --git a/samplecode/SampleLua.cpp b/samplecode/SampleLua.cpp new file mode 100644 index 0000000000..263138bf6b --- /dev/null +++ b/samplecode/SampleLua.cpp @@ -0,0 +1,110 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SampleCode.h" +#include "SkView.h" +#include "SkLua.h" +#include "SkCanvas.h" + +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} + +static const char gDrawName[] = "onDrawContent"; + +static const char gCode[] = "" + "local r = { left = 10, top = 10, right = 100, bottom = 80 } " + "local x = 0;" + "" + "local paint = Sk.newPaint();" + "paint:setAntiAlias(true);" + "" + "local color = {a = 1, r = 1, g = 0, b = 0};" + "" + "function onDrawContent(canvas) " + " color.g = x / 100;" + " paint:setColor(color) " + " canvas:translate(x, 0);" + " canvas:drawOval(r, paint) " + " x = x + 1;" + " if x > 100 then x = 0 end;" + "end"; + +class LuaView : public SampleView { +public: + LuaView() : fLua(NULL) {} + + virtual ~LuaView() { + SkDELETE(fLua); + } + + lua_State* ensureLua() { + if (NULL == fLua) { + fLua = SkNEW(SkLua); + fLua->runCode(gCode); + } + return fLua->get(); + } + +protected: + virtual bool onQuery(SkEvent* evt) SK_OVERRIDE { + if (SampleCode::TitleQ(*evt)) { + SampleCode::TitleR(evt, "Lua"); + return true; + } + SkUnichar uni; + if (SampleCode::CharQ(*evt, &uni)) { + switch (uni) { + default: + break; + } + } + return this->INHERITED::onQuery(evt); + } + + virtual void onDrawContent(SkCanvas* canvas) SK_OVERRIDE { + lua_State* L = this->ensureLua(); + + lua_getglobal(L, gDrawName); + if (!lua_isfunction(L, -1)) { + int t = lua_type(L, -1); + SkDebugf("--- expected %s function %d, ignoring.\n", gDrawName, t); + lua_pop(L, 1); + } else { + // does it make sense to try to "cache" the lua version of this + // canvas between draws? + fLua->pushCanvas(canvas); + if (lua_pcall(L, 1, 0, 0) != LUA_OK) { + SkDebugf("lua err: %s\n", lua_tostring(L, -1)); + } + } + // need a way for the lua-sample to tell us if they want animations... + // hard-code it ON for now. + this->inval(NULL); + } + + virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, + unsigned modi) SK_OVERRIDE { + return this->INHERITED::onFindClickHandler(x, y, modi); + } + + virtual bool onClick(Click* click) SK_OVERRIDE { + return this->INHERITED::onClick(click); + } + +private: + SkLua* fLua; + + typedef SampleView INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static SkView* MyFactory() { return new LuaView; } +static SkViewRegister reg(MyFactory); diff --git a/src/utils/SkLua.cpp b/src/utils/SkLua.cpp index 05da5cb195..c425a262b6 100644 --- a/src/utils/SkLua.cpp +++ b/src/utils/SkLua.cpp @@ -14,42 +14,44 @@ #include "SkString.h" extern "C" { -#include "lua.h" -#include "lauxlib.h" + #include "lua.h" + #include "lualib.h" + #include "lauxlib.h" } -static const char gSkCanvas_MTName[] = "SkCanvas_LuaMetaTableName"; -static const char gSkMatrix_MTName[] = "SkMatrix_LuaMetaTableName"; -static const char gSkRRect_MTName[] = "SkSkRRect_LuaMetaTableName"; -static const char gSkPath_MTName[] = "SkPath_LuaMetaTableName"; -static const char gSkPaint_MTName[] = "SkPaint_LuaMetaTableName"; +template const char* get_mtname(); +template <> const char* get_mtname() { return "SkCanvas_LuaMetaTableName"; } +template <> const char* get_mtname() { return "SkMatrix_LuaMetaTableName"; } +template <> const char* get_mtname() { return "SkSkRRect_LuaMetaTableName"; } +template <> const char* get_mtname() { return "SkPath_LuaMetaTableName"; } +template <> const char* get_mtname() { return "SkPaint_LuaMetaTableName"; } -static const char* get_mtname(const SkCanvas&) { return gSkCanvas_MTName; } -static const char* get_mtname(const SkMatrix&) { return gSkMatrix_MTName; } -static const char* get_mtname(const SkRRect&) { return gSkRRect_MTName; } -static const char* get_mtname(const SkPath&) { return gSkPath_MTName; } -static const char* get_mtname(const SkPaint&) { return gSkPaint_MTName; } +template T* push_new(lua_State* L) { + T* addr = (T*)lua_newuserdata(L, sizeof(T)); + new (addr) T; + luaL_getmetatable(L, get_mtname()); + lua_setmetatable(L, -2); + return addr; +} template void push_obj(lua_State* L, const T& obj) { new (lua_newuserdata(L, sizeof(T))) T(obj); - luaL_getmetatable(L, get_mtname(obj)); + luaL_getmetatable(L, get_mtname()); lua_setmetatable(L, -2); } template void push_ref(lua_State* L, T* ref) { *(T**)lua_newuserdata(L, sizeof(T*)) = SkRef(ref); - luaL_getmetatable(L, get_mtname(*ref)); + luaL_getmetatable(L, get_mtname()); lua_setmetatable(L, -2); } template T* get_ref(lua_State* L, int index) { - const T* ref = NULL; - return *(T**)luaL_checkudata(L, index, get_mtname(*ref)); + return *(T**)luaL_checkudata(L, index, get_mtname()); } template T* get_obj(lua_State* L, int index) { - const T* obj = NULL; - return (T*)luaL_checkudata(L, index, get_mtname(*obj)); + return (T*)luaL_checkudata(L, index, get_mtname()); } static bool lua2bool(lua_State* L, int index) { @@ -58,6 +60,44 @@ static bool lua2bool(lua_State* L, int index) { /////////////////////////////////////////////////////////////////////////////// +SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) { + fL = luaL_newstate(); + luaL_openlibs(fL); + SkLua::Load(fL); +} + +SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {} + +SkLua::~SkLua() { + if (fWeOwnL) { + if (fTermCode.size() > 0) { + lua_getglobal(fL, fTermCode.c_str()); + if (lua_pcall(fL, 0, 0, 0) != LUA_OK) { + SkDebugf("lua err: %s\n", lua_tostring(fL, -1)); + } + } + lua_close(fL); + } +} + +bool SkLua::runCode(const char code[]) { + int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0); + if (err) { + SkDebugf("--- lua failed\n"); + return false; + } + return true; +} + +bool SkLua::runCode(const void* code, size_t size) { + SkString str((const char*)code, size); + return this->runCode(str.c_str()); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0) + static void setfield_string(lua_State* L, const char key[], const char value[]) { lua_pushstring(L, value); lua_setfield(L, -2, key); @@ -68,19 +108,12 @@ static void setfield_number(lua_State* L, const char key[], double value) { lua_setfield(L, -2, key); } -SkLua::SkLua(lua_State* L) : fL(L) { - static bool gOnce; - if (!gOnce) { - SkLua::Load(L); - gOnce = true; - } +static void setfield_function(lua_State* L, + const char key[], lua_CFunction value) { + lua_pushcfunction(L, value); + lua_setfield(L, -2, key); } -SkLua::~SkLua() { -} - -#define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0) - void SkLua::pushBool(bool value, const char key[]) { lua_pushboolean(fL, value); CHECK_SETFIELD(key); @@ -224,6 +257,11 @@ static int lcanvas_getTotalMatrix(lua_State* L) { return 1; } +static int lcanvas_translate(lua_State* L) { + get_ref(L, 1)->translate(lua2scalar(L, 2), lua2scalar(L, 3)); + return 0; +} + static int lcanvas_gc(lua_State* L) { get_ref(L, 1)->unref(); return 0; @@ -236,6 +274,7 @@ static const struct luaL_Reg gSkCanvas_Methods[] = { { "drawCircle", lcanvas_drawCircle }, { "getSaveCount", lcanvas_getSaveCount }, { "getTotalMatrix", lcanvas_getTotalMatrix }, + { "translate", lcanvas_translate }, { "__gc", lcanvas_gc }, { NULL, NULL } }; @@ -460,9 +499,44 @@ private: /////////////////////////////////////////////////////////////////////////////// +static int lsk_newPaint(lua_State* L) { + push_new(L); + return 1; +} + +static int lsk_newPath(lua_State* L) { + push_new(L); + return 1; +} + +static int lsk_newRRect(lua_State* L) { + SkRRect* rr = push_new(L); + rr->setEmpty(); + return 1; +} + +static const struct luaL_Reg gSk_Functions[] = { + { "newPaint", lsk_newPaint }, + { "newPath", lsk_newPath }, + { "newRRect", lsk_newRRect }, + { NULL, NULL } +}; + +static void register_Sk(lua_State* L) { + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "Sk"); + // the Sk table is still on top + + setfield_function(L, "newPaint", lsk_newPaint); + setfield_function(L, "newPath", lsk_newPath); + setfield_function(L, "newRRect", lsk_newRRect); + lua_pop(L, 1); // pop off the Sk table +} + #define REG_CLASS(L, C) \ do { \ - luaL_newmetatable(L, g##C##_MTName); \ + luaL_newmetatable(L, get_mtname()); \ lua_pushvalue(L, -1); \ lua_setfield(L, -2, "__index"); \ luaL_setfuncs(L, g##C##_Methods, 0); \ @@ -470,6 +544,7 @@ private: } while (0) void SkLua::Load(lua_State* L) { + register_Sk(L); REG_CLASS(L, SkCanvas); REG_CLASS(L, SkPath); REG_CLASS(L, SkPaint); diff --git a/src/utils/SkLuaCanvas.cpp b/src/utils/SkLuaCanvas.cpp index be6cb6624a..d3ecd74bb0 100644 --- a/src/utils/SkLuaCanvas.cpp +++ b/src/utils/SkLuaCanvas.cpp @@ -27,7 +27,7 @@ public: } ~AutoCallLua() { - lua_State* L = this->getL(); + lua_State* L = this->get(); if (lua_pcall(L, 1, 0, 0) != LUA_OK) { SkDebugf("lua err: %s\n", lua_tostring(L, -1)); } diff --git a/tools/lua/lua_pictures.cpp b/tools/lua/lua_pictures.cpp index 1314c699d4..ae4e1cabda 100644 --- a/tools/lua/lua_pictures.cpp +++ b/tools/lua/lua_pictures.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkLua.h" #include "SkLuaCanvas.h" #include "SkPicture.h" #include "SkCommandLineFlags.h" @@ -60,50 +61,6 @@ static SkData* read_into_data(const char file[]) { return SkData::NewFromMalloc(buffer, len); } -class SkAutoLua { -public: - SkAutoLua(const char termCode[] = NULL) : fTermCode(termCode) { - fL = luaL_newstate(); - luaL_openlibs(fL); - } - ~SkAutoLua() { - if (fTermCode.size() > 0) { - lua_getglobal(fL, fTermCode.c_str()); - if (lua_pcall(fL, 0, 0, 0) != LUA_OK) { - SkDebugf("lua err: %s\n", lua_tostring(fL, -1)); - } - } - lua_close(fL); - } - - lua_State* get() const { return fL; } - lua_State* operator*() const { return fL; } - lua_State* operator->() const { return fL; } - - bool load(const char code[]) { - int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0); - if (err) { - SkDebugf("--- lua failed\n"); - return false; - } - return true; - } - bool load(const void* code, size_t size) { - SkString str((const char*)code, size); - return load(str.c_str()); - int err = luaL_loadbufferx(fL, (const char*)code, size, NULL, NULL) - || lua_pcall(fL, 0, 0, 0); - if (err) { - SkDebugf("--- lua failed\n"); - return false; - } - return true; - } -private: - lua_State* fL; - SkString fTermCode; -}; - static void call_canvas(lua_State* L, SkLuaCanvas* canvas, const char pictureFile[], const char funcName[]) { lua_getglobal(L, funcName); @@ -135,12 +92,12 @@ int tool_main(int argc, char** argv) { } SkAutoGraphics ag; - SkAutoLua L(gSummarizeFunc); + SkLua L(gSummarizeFunc); for (int i = 0; i < FLAGS_luaFile.count(); ++i) { SkAutoDataUnref data(read_into_data(FLAGS_luaFile[i])); SkDebugf("loading %s...\n", FLAGS_luaFile[i]); - if (!L.load(data->data(), data->size())) { + if (!L.runCode(data->data(), data->size())) { SkDebugf("failed to load luaFile %s\n", FLAGS_luaFile[i]); exit(-1); }