From 8161487b26a862c88736331dbe8931ca15c55c48 Mon Sep 17 00:00:00 2001 From: Warmist Date: Mon, 30 Jul 2018 22:56:10 +0300 Subject: [PATCH] IT'S ALIVE! --- CMakeLists.txt | 2 + projects/circle.lua | 11 -- projects/spirograph.lua | 102 ++++++++++++++++++ src/limgui.cpp | 4 + src/limgui.h | 7 +- src/lua_buffers.cpp | 229 ++++++++++++++++++++++++++++++++++++++++ src/lua_buffers.h | 6 ++ src/main.cpp | 81 +++++++++++++- 8 files changed, 425 insertions(+), 17 deletions(-) create mode 100644 src/lua_buffers.cpp create mode 100644 src/lua_buffers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a5f643e..45a29a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ set(SRCS src/imgui-SFML.cpp src/filesys.cpp src/limgui.cpp + src/lua_buffers.cpp ${IMGUI}/imgui.cpp ${IMGUI}/imgui_draw.cpp ${IMGUI}/imgui_demo.cpp @@ -48,6 +49,7 @@ set(HDRS src/limgui.h src/stb_image.h src/stb_image_write.h + src/lua_buffers.h ${LUA}/lua.hpp ${LUA}/lualib.h ) diff --git a/projects/circle.lua b/projects/circle.lua index b562d24..e69de29 100644 --- a/projects/circle.lua +++ b/projects/circle.lua @@ -1,11 +0,0 @@ -for i=1,10 do - print(i) -end -color={0,0,0,0} - -function update( ) - imgui.Begin("Hello") - local changed - changed,color=imgui.ColorEdit3("thing",color) - imgui.End() -end \ No newline at end of file diff --git a/projects/spirograph.lua b/projects/spirograph.lua index e69de29..ae1d7db 100644 --- a/projects/spirograph.lua +++ b/projects/spirograph.lua @@ -0,0 +1,102 @@ +--[[ Example: +imgui_config=make_config{ + {"debug_display",false}, + {"complexity",0.5,type="float"}, --implied min=0,max=1 + {"shapes","3"}, + {"w",3,type="int",min=1,max=5}, +} + +Begin +End +Bullet +BulletText +RadioButton +CollapsingHeader +SliderFloat +SliderAngle +SliderInt +InputText +]] +function make_config(tbl,defaults) + local ret={} + defaults=defaults or {} + for i,v in ipairs(tbl) do + ret[v[1]]=defaults[v[1]] or v[2] + ret[i]=v + end + return ret +end + +img_buf=img_buf or buffers.Make("color") +tick=tick or 0 +config=make_config({ + {"color",{0.5,0,0,1},type="color"}, + {"k",0.2,type="float"}, + {"l",0.4,type="float"}, + {"R",400,type="int",min=0,max=512}, + {"ticking",100,type="float",min=1,max=10000}, +},config) + +function draw_config( tbl ) + for _,entry in ipairs(tbl) do + local name=entry[1] + local v=tbl[name] + local k=name + if type(v)=="boolean" then + if imgui.Button(k) then + tbl[k]=not tbl[k] + end + elseif type(v)=="string" then + local changing + changing,tbl[k]=imgui.InputText(k,tbl[k]) + entry.changing=changing + else --if type(v)~="table" then + + if entry.type=="int" then + local changing + changing,tbl[k]=imgui.SliderInt(k,tbl[k],entry.min or 0,entry.max or 100) + entry.changing=changing + elseif entry.type=="float" then + local changing + changing,tbl[k]=imgui.SliderFloat(k,tbl[k],entry.min or 0,entry.max or 1) + entry.changing=changing + elseif entry.type=="angle" then + local changing + changing,tbl[k]=imgui.SliderAngle(k,tbl[k],entry.min or 0,entry.max or 360) + entry.changing=changing + elseif entry.type=="color" then + local changing + changing,tbl[k]=imgui.ColorEdit4(k,tbl[k],true) + entry.changing=changing + end + + end + end +end +function pos( t ) + local k=config.k + local l=config.l + return config.R*((1-k)*math.cos(t)+l*k*math.cos(((1-k)/k)*t)), + config.R*((1-k)*math.sin(t)-l*k*math.sin(((1-k)/k)*t)) +end +function update( ) + imgui.Begin("Hello") + + draw_config(config) + local c_u8={config.color[1]*255,config.color[2]*255,config.color[3]*255,config.color[4]*255} + if imgui.Button("Clear image") then + local s=STATE.size + for x=0,s[1]-1 do + for y=0,s[2]-1 do + img_buf:set(x,y,{0,0,0,0}) + end + end + end + imgui.End() + for i=1,config.ticking do + local x,y=pos(tick/config.ticking); + img_buf:set(x+512,y+512,c_u8) + tick=tick+1 + end + buffers.Present(img_buf) +end \ No newline at end of file diff --git a/src/limgui.cpp b/src/limgui.cpp index b491f84..e7b5d07 100644 --- a/src/limgui.cpp +++ b/src/limgui.cpp @@ -2,6 +2,10 @@ #include #include + +#include "lua.hpp" +#include "lualib.h" +#include "lauxlib.h" int lua_absindex(lua_State *L, int i) { if (i < 0 && i > LUA_REGISTRYINDEX) i += lua_gettop(L) + 1; diff --git a/src/limgui.h b/src/limgui.h index 722af06..a9762f1 100644 --- a/src/limgui.h +++ b/src/limgui.h @@ -1,9 +1,6 @@ #pragma once -#include "lua.hpp" -#include "lualib.h" -#include "lauxlib.h" - +struct lua_State; int lua_open_imgui(lua_State* L); - +//NOTE: call this because on error, there might be unmatched imgui::begin/end(s) void fixup_imgui_state(); \ No newline at end of file diff --git a/src/lua_buffers.cpp b/src/lua_buffers.cpp new file mode 100644 index 0000000..da3c777 --- /dev/null +++ b/src/lua_buffers.cpp @@ -0,0 +1,229 @@ +#include "lua_buffers.h" + +#include "SFML\Graphics.hpp" + +#include "lua.hpp" +#include "lualib.h" +#include "lauxlib.h" + +#include +enum class buffer_type { + vector_u8x4, + vector_float, +}; +struct u8x4 { + uint8_t r, g, b, a; +}; +struct buffer_entry +{ + int w; + buffer_type t; +}; +std::unordered_map buffer_registry; + +void get_current_size(lua_State* L, int& x, int& y) +{ + lua_getglobal(L, "STATE"); + lua_getfield(L, -1, "size"); + + lua_rawgeti(L, -1, 1); + x=lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_rawgeti(L, -1, 2); + y = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_pop(L, 2); +} + + + +template +struct buffer_value_access{ +static constexpr char* name(); +static int push(lua_State* L, const T& v); +static T to_element(lua_State* L, int id); +static std::vector* check(lua_State* L, int id) { return *reinterpret_cast**>(luaL_checkudata(L, id, name())); } +static int get_buffer(lua_State* L) +{ + auto ptr = buffer_value_access::check(L, 1); + int x = luaL_checkinteger(L, 2); + int y = luaL_checkinteger(L, 3); + auto e = buffer_registry[ptr]; + auto& v = ptr->at(x*e.w + y); \ + return buffer_value_access::push(L, v); +} +static int set_buffer(lua_State* L) { + auto ptr = buffer_value_access::check(L, 1); + int x = luaL_checkinteger(L, 2); + int y = luaL_checkinteger(L, 3); + auto new_value = buffer_value_access::to_element(L, 4); + auto e = buffer_registry[ptr]; + ptr->at(x*e.w + y) = new_value; + return 0; +} +static int del_buffer(lua_State* L) { + auto ptr= check(L, 1); + buffer_registry.erase(ptr); delete ptr; + return 0; +} +static int len_buffer(lua_State* L) { + auto ptr = check(L, 1); + lua_pushnumber(L, ptr->size()); + return 1; +} +static int index_buffer(lua_State* L) { + auto ptr = check(L, 1); + int id = luaL_checkinteger(L, 2); + auto& v = ptr->at(id); + return push(L, v); +} +static int newindex_buffer(lua_State* L){ + auto ptr = check(L, 1); + int id = luaL_checkinteger(L, 2); + auto new_value = to_element(L, 3); + ptr->at(id) = new_value; + return 0; +} +static void resize_buffer(void* d, int w, int h){ + auto p = reinterpret_cast*>(d); + p->resize(w*h); + buffer_registry[d].w = w; +} +static int make_buffer(lua_State* L, int w, int h){ + auto ret = new std::vector(w*h); + buffer_registry[ret].w = w; + auto np=lua_newuserdata(L,sizeof(ret)); + *reinterpret_cast**>(np)=ret; + if (luaL_newmetatable(L, name())) + { + lua_pushcfunction(L, del_buffer); + lua_setfield(L, -2, "__gc"); + lua_pushcfunction(L, len_buffer); + lua_setfield(L, -2, "__len"); + + lua_pushcfunction(L, get_buffer); + lua_setfield(L, -2, "get"); + lua_pushcfunction(L, set_buffer); + lua_setfield(L, -2, "set"); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + } + lua_setmetatable(L, -2); + return 1; +} +}; + +static int make_lua_auto_buffer(lua_State* L) +{ + const char* buf_type = luaL_checkstring(L, 1); + int x, y; + get_current_size(L, x, y); + + if (strcmp(buf_type, "color")==0) + { + return buffer_value_access::make_buffer(L,x,y); + } else if (strcmp(buf_type, "float") == 0) + { + return buffer_value_access::make_buffer(L, x, y); + } +} +static int present_buffer(lua_State* L) +{ + auto ptr= buffer_value_access::check(L, 1); + lua_getglobal(L, "STATE"); + lua_getfield(L, -1, "texture"); + + auto tex=reinterpret_cast(lua_touserdata(L, -1)); + lua_pop(L, 2); + tex->update(reinterpret_cast(ptr->data())); + return 0; +} +static const luaL_Reg lua_buffers_lib[] = { + { "Make",make_lua_auto_buffer }, + { "Present",present_buffer}, + { NULL, NULL } +}; + +int lua_open_buffers(lua_State * L) +{ + luaL_newlib(L, lua_buffers_lib); + + lua_setglobal(L, "buffers"); + + return 1; +} + +void resize_lua_buffers(int w, int h) +{ + for (auto& v : buffer_registry) + { + switch (v.second.t) + { +#define DO_BUFFER_RESIZE(tname,name) case buffer_type::vector_##tname: buffer_value_access::resize_buffer(v.first,w,h);break + DO_BUFFER_RESIZE(u8x4, color); + DO_BUFFER_RESIZE(float, float); + default: + break; + } + } +} +#undef DO_BUFFER_RESIZE + +template<> +static constexpr char * buffer_value_access::name() +{ + return "color_buffer"; +} + +template<> +static int buffer_value_access::push(lua_State * L, const u8x4& v) +{ + lua_newtable(L); + + lua_pushinteger(L, v.r); + lua_rawseti(L, -2, 1); + + lua_pushinteger(L, v.g); + lua_rawseti(L, -2, 2); + + lua_pushinteger(L, v.b); + lua_rawseti(L, -2, 3); + + lua_pushinteger(L, v.a); + lua_rawseti(L, -2, 4); + + return 1; +} + +template<> +static u8x4 buffer_value_access::to_element(lua_State * L, int id) +{ + u8x4 ret; + luaL_checktype(L, id, LUA_TTABLE); + lua_rawgeti(L, id, 1); ret.r = lua_tointeger(L, -1); lua_pop(L, 1); + lua_rawgeti(L, id, 2); ret.g = lua_tointeger(L, -1); lua_pop(L, 1); + lua_rawgeti(L, id, 3); ret.b = lua_tointeger(L, -1); lua_pop(L, 1); + lua_rawgeti(L, id, 4); ret.a = lua_tointeger(L, -1); lua_pop(L, 1); + return ret; +} + +template<> +static constexpr char * buffer_value_access::name() +{ + return "float_buffer"; +} + +template<> +static int buffer_value_access::push(lua_State * L, const float& v) +{ + lua_pushnumber(L, v); + return 1; +} + +template<> +static float buffer_value_access::to_element(lua_State * L, int id) +{ + return luaL_checknumber(L, id); +} \ No newline at end of file diff --git a/src/lua_buffers.h b/src/lua_buffers.h new file mode 100644 index 0000000..2889d83 --- /dev/null +++ b/src/lua_buffers.h @@ -0,0 +1,6 @@ +#pragma once + +struct lua_State; +int lua_open_buffers(lua_State* L); + +void resize_lua_buffers(int w,int h); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ee07d6f..704d356 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "filesys.h" #include "limgui.h" +#include "lua_buffers.h" void load_projects(const char* prefix,file_watcher& fwatch) { std::string path_prefix = prefix; @@ -42,12 +43,58 @@ static int docall(lua_State *L, int narg, int nres) { lua_remove(L, base); /* remove message handler from the stack */ return status; } +static int lua_read_only(lua_State* L) +{ + luaL_error(L,"Tried to write to read-only table"); + return 0; +} +struct lua_global_state +{ + sf::Vector2u size; + sf::Texture* tex; + void write(lua_State* L) + { + if (!L) + return; + lua_newtable(L); + + lua_newtable(L); + lua_pushinteger(L, size.x); + lua_rawseti(L, -2, 1); + lua_pushinteger(L, size.y); + lua_rawseti(L, -2, 2); + + lua_setfield(L, -2, "size"); + + lua_pushlightuserdata(L, tex); + lua_setfield(L, -2, "texture"); + + lua_newtable(L); + + lua_pushvalue(L, -2); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lua_read_only); + lua_setfield(L, -2, "__newindex"); + + lua_pushboolean(L, false); + lua_setfield(L, -2, "__metatable"); + + lua_setmetatable(L, -2); + + lua_setglobal(L, "STATE"); + } +}; struct project { lua_State *L=nullptr; std::string path; std::vector errors; bool is_errored = false; + lua_global_state state; + + + project() {} ~project() { if(L)lua_close(L); }; @@ -57,12 +104,19 @@ struct project { L = luaL_newstate(); luaL_openlibs(L); lua_open_imgui(L); - + lua_open_buffers(L); //lua_pushlightuserdata(L, this); //lua_setglobal(L, "__project"); + + state.write(L); } void reload_file() { + if (path == "") + { + is_errored = true; + return; + } if (luaL_dofile(L, path.c_str()) != 0) { size_t len; @@ -109,6 +163,7 @@ struct project { } fixup_imgui_state(); } + }; int main(int argc, char** argv) { @@ -123,9 +178,19 @@ int main(int argc, char** argv) sf::RenderWindow window(sf::VideoMode(1024, 1024), "PixelDance"); window.setFramerateLimit(60); ImGui::SFML::Init(window); + auto csize = window.getSize(); + + sf::Texture back_buffer; + + back_buffer.create(csize.x, csize.y); + + sf::Sprite back_buffer_sprite; + back_buffer_sprite.setTexture(back_buffer); project current_project; + current_project.state = { csize ,&back_buffer}; current_project.init_lua(); + int selected_project = -1; int old_selected = selected_project; sf::Clock deltaClock; @@ -137,6 +202,15 @@ int main(int argc, char** argv) if (event.type == sf::Event::Closed) { window.close(); } + if (event.type == sf::Event::Resized) + { + auto ev = event.size; + back_buffer.create(ev.width, ev.height); + + current_project.state = { sf::Vector2u(ev.width,ev.height),&back_buffer }; + current_project.state.write(current_project.L); + resize_lua_buffers(ev.width, ev.height); + } } bool need_reload = false; if (fwatch.check_changes()) @@ -188,6 +262,10 @@ int main(int argc, char** argv) { current_project.load_file(fwatch.files[selected_project].path); } + else + { + current_project.load_file(""); + } } old_selected = selected_project; ImGui::Separator(); @@ -208,6 +286,7 @@ int main(int argc, char** argv) window.clear(); + window.draw(back_buffer_sprite); ImGui::SFML::Render(window); window.display(); }