Browse Source

Implement sol3 into lua script

master
Riyyi 3 years ago
parent
commit
c7a97d3c1f
  1. 197
      inferno/src/inferno/script/lua.cpp
  2. 37
      inferno/src/inferno/script/lua.h
  3. 82
      inferno/src/inferno/script/registration.cpp
  4. 60
      inferno/src/inferno/script/registration.h

197
inferno/src/inferno/script/lua.cpp

@ -1,205 +1,78 @@
extern "C" {
#include <lua/lua.h>
#include <lua/lualib.h>
#include <lua/lauxlib.h>
}
#include "sol/unsafe_function_result.hpp"
#include "inferno/assertions.h"
#include "inferno/file.h"
#include "inferno/scene/components.h"
#include "inferno/scene/scene.h"
#include "inferno/script/lua.h"
#include "inferno/script/registration.h"
namespace Inferno {
void Lua::initialize()
{
m_state = luaL_newstate();
// Type registration
// ---------------------------------
Registration::fill(m_state);
// Add GetComponent()
// Load libraries
// ---------------------------------
constexpr int32_t componentUpValueAmount = 1;
lua_pushlightuserdata(m_state, this);
lua_pushcclosure(m_state, Lua::getComponent, componentUpValueAmount);
lua_setglobal(m_state, "GetComponent");
m_state.open_libraries(sol::lib::base);
// Add Metatable
// Component get functions
// ---------------------------------
luaL_newmetatable(m_state, "ComponentMetatable");
m_state.set_function("getTagComponent", [this]() -> TagComponent* {
return &m_scene->getComponent<TagComponent>(m_entity);
});
constexpr int32_t indexUpValueAmount = 1;
lua_pushstring(m_state, "__index");
lua_pushlightuserdata(m_state, this);
lua_pushcclosure(m_state, Lua::componentIndex, indexUpValueAmount);
lua_settable(m_state, -3); // Pops the string and table
m_state.set_function("getTransformComponent", [this]() -> TransformComponent* {
return &m_scene->getComponent<TransformComponent>(m_entity);
});
constexpr int32_t newIndexUpValueAmount = 1;
lua_pushstring(m_state, "__newindex");
lua_pushlightuserdata(m_state, this);
lua_pushcclosure(m_state, Lua::componentNewIndex, newIndexUpValueAmount);
lua_settable(m_state, -3); // Pops the string and table
// (*m_state).set_function("GetComponent", &Lua::getComponentSol);
m_state.set_function("getCameraComponent", [this]() -> CameraComponent* {
return &m_scene->getComponent<CameraComponent>(m_entity);
});
// Load and Initialize Script
m_state.set_function("getSpriteComponent", [this]() -> SpriteComponent* {
return &m_scene->getComponent<SpriteComponent>(m_entity);
});
// Load and Initialize script
// ---------------------------------
loadScript();
getFunction("LuaScript", "initialize");
callFunction();
callFunction("LuaScript", "initialize");
}
void Lua::destroy()
{
getFunction("LuaScript", "destroy");
callFunction();
lua_close(m_state);
m_state = nullptr;
callFunction("LuaScript", "destroy");
}
void Lua::update(float deltaTime)
{
getFunction("LuaScript", "update");
lua_pushnumber(m_state, deltaTime); // Push float argument
callFunction(1);
}
void Lua::valid(int32_t error)
{
ASSERT(error == LUA_OK, "{}", lua_tostring(m_state, -1));
m_state["LuaScript"]["transform"] = &m_scene->getComponent<TransformComponent>(m_entity);
callFunction("LuaScript", "update", deltaTime);
}
void Lua::loadScript()
{
std::string script = File::read(m_path);
int32_t error = luaL_dostring(m_state, script.c_str());
valid(error);
}
void Lua::getFunction(const char* table, const char* function)
{
Lua::isTable(m_state, table); // Push table
int32_t tableIdx = lua_gettop(m_state); // Get table stack index
lua_pushstring(m_state, function); // Push string
lua_gettable(m_state, -2); // Pop string key, push value
lua_pushvalue(m_state, tableIdx); // Push table
}
void Lua::callFunction(int32_t parameters)
{
int32_t error = lua_pcall(m_state, parameters + 1, 0, 0); // Call function()
valid(error);
}
void Lua::isTable(lua_State* state, int32_t table)
{
ASSERT(lua_istable(state, table));
}
void Lua::isTable(lua_State* state, const char* table)
{
lua_getglobal(state, table); // Push table on the stack
Lua::isTable(state, -1);
}
int32_t Lua::getComponent(lua_State* state) // Local scope state, so stack begins at 1!
{
ASSERT(lua_gettop(state) == 1, "Lua called with wrong amount of arguments");
ASSERT(lua_islightuserdata(state, lua_upvalueindex(1)), "Lua did not receive required lightuserdata");
Lua* self = static_cast<Lua*>(lua_touserdata(state, lua_upvalueindex(1)));
// Verify parameter
std::string componentName = lua_tostring(state, -1);
ASSERT(lua_isstring(state, -1), "Lua did not receive correct parameter");
// Create userdata
/*void* pointer =*/ lua_newuserdatauv(state, sizeof(0), 2); // Push userdata
ASSERT(lua_isuserdata(state, -1), "Lua could not create userdata");
// Get component
void* component = nullptr;
if (componentName.compare("CameraComponent") == 0) {
component = static_cast<void*>(&self->m_scene->getComponent<CameraComponent>(self->m_entity));
}
// Add metatable to userdata
luaL_getmetatable(state, "ComponentMetatable"); // Push table
ASSERT(lua_istable(state, -1), "Lua could not find metatable");
lua_setmetatable(state, -2); // Pop table, set it as metatable onto userdata
// Add uservalues to userdata
lua_pushstring(state, componentName.c_str()); // Push string
lua_setiuservalue(state, -2, 1); // Pop value, set it as the n-th uservalue onto userdata
lua_pushlightuserdata(state, component); // Push pointer
lua_setiuservalue(state, -2, 2); // Pop value, set it as the n-th uservalue onto userdata
return 1; // Return amount of stack items pushed
auto result = m_state.script(script.c_str(),
[](lua_State*, sol::protected_function_result pfr) { return pfr; });
ASSERT(result.valid(), "Lua script {}", ((sol::error)result).what());
}
int32_t Lua::componentIndex(lua_State* state) // Local scope state, so stack begins at 1!
sol::table Lua::getTable(const char* name)
{
ASSERT(lua_gettop(state) == 2, "Lua called with wrong amount of arguments");
ASSERT(lua_isuserdata(state, -2)); // 1 // <component>.x
ASSERT(lua_isstring(state, -1)); // 2 // component.<x>
// ASSERT(lua_islightuserdata(state, lua_upvalueindex(1)), "Lua did not receive required lightuserdata");
// Lua* self = static_cast<Lua*>(lua_touserdata(state, lua_upvalueindex(1)));
lua_getiuservalue(state, 1, 1); // Push the n-th uservalue from userdata
ASSERT(lua_isstring(state, -1), "Lua did not receive component type correctly");
std::string componentName = lua_tostring(state, -1);
if (componentName.compare("CameraComponent") == 0) {
lua_getiuservalue(state, 1, 2); // Push the n-th uservalue from userdata
ASSERT(lua_islightuserdata(state, -1), "Lua did not receive component pointer correctly");
CameraComponent* component = (CameraComponent*)lua_touserdata(state, -1);
std::string index = lua_tostring(state, 2);
if (index.compare("fov") == 0) {
lua_pushnumber(state, component->fov);
return 1;
}
else {
ASSERT_NOT_REACHED();
}
}
return 0;
}
int32_t Lua::componentNewIndex(lua_State* state) // Local scope state, so stack begins at 1!
{
ASSERT(lua_gettop(state) == 3, "Lua called with wrong amount of arguments");
ASSERT(lua_isuserdata(state, -3)); // 1 // <component>.x = thing
ASSERT(lua_isstring(state, -2)); // 2 // component.<x> = thing
// Value we want to set -1 // 3 // component.x = <thing>
lua_getiuservalue(state, 1, 1); // Push the n-th uservalue from userdata
ASSERT(lua_isstring(state, -1), "Lua did not receive component type correctly");
std::string componentName = lua_tostring(state, -1);
if (componentName.compare("CameraComponent") == 0) {
lua_getiuservalue(state, 1, 2); // Push the n-th uservalue from userdata
ASSERT(lua_islightuserdata(state, -1), "Lua did not receive component pointer correctly");
CameraComponent* component = (CameraComponent*)lua_touserdata(state, -1);
std::string index = lua_tostring(state, 2);
if (index.compare("fov") == 0) {
component->fov = lua_tonumber(state, 3);
}
else {
ASSERT_NOT_REACHED();
}
}
return 0;
sol::table table = m_state[name];
ASSERT(table.valid(), "Lua table does not exist");
return table;
}
}

37
inferno/src/inferno/script/lua.h

@ -1,10 +1,16 @@
#ifndef LUA_H
#define LUA_H
#include <cstdint> // int32_t, uint32_t
#include <cstdint> // uint32_t
#include <string> // std::string
#include <lua/lua.h> // lua_State
#define SOL_ALL_SAFETIES_ON 1
#include "sol/protected_function.hpp"
#include "sol/protected_function_result.hpp"
#include "sol/state.hpp"
#include "sol/table.hpp"
#include "inferno/assertions.h"
namespace Inferno {
@ -18,21 +24,26 @@ namespace Inferno {
void destroy();
void update(float deltaTime);
void valid(int32_t error);
void loadScript();
void getFunction(const char* table, const char* function);
void callFunction(int32_t parameters = 0);
private:
static void isTable(lua_State* state, int32_t table);
static void isTable(lua_State* state, const char* table);
static int32_t getComponent(lua_State* state);
static int32_t componentIndex(lua_State* state);
static int32_t componentNewIndex(lua_State* state);
sol::table getTable(const char* name);
template<typename... P>
void callFunction(const char* table, const char* function, P&&... parameters)
{
sol::table solTable = getTable(table);
sol::protected_function solFunction = solTable[function];
// Only call function if it exists
if (solFunction.valid()) {
sol::protected_function_result result = solFunction(solTable, parameters...);
ASSERT(result.valid(), "Lua function {}", ((sol::error)result).what());
}
}
sol::state m_state;
std::string m_path = "";
lua_State* m_state = nullptr;
Scene* m_scene = nullptr;
uint32_t m_entity = 0;

82
inferno/src/inferno/script/registration.cpp

@ -0,0 +1,82 @@
#include "glm/ext/vector_float2.hpp" // glm::vec2
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "inferno/scene/components.h"
#include "inferno/script/registration.h"
namespace Inferno {
void Registration::fill(sol::state_view &state)
{
glm(state);
component(state);
}
void Registration::glm(sol::state_view& state)
{
auto vec2 = state.new_usertype<glm::vec2>(
"vec2",
sol::call_constructor, sol::constructors<glm::vec2(), glm::vec2(float), glm::vec2(float, float)>(),
"x", &glm::vec2::x, "y", &glm::vec2::y,
"r", &glm::vec2::r, "g", &glm::vec2::g,
"s", &glm::vec2::s, "t", &glm::vec2::t,
"__add", addition<glm::vec2, float>(),
"__sub", subtraction<glm::vec2, float>(),
"__mul", multiplication<glm::vec2, float>(),
"__div", division<glm::vec2, float>()
);
auto vec3 = state.new_usertype<glm::vec3>(
"vec3",
sol::call_constructor, sol::constructors<glm::vec3(), glm::vec3(float), glm::vec3(float, float, float)>(),
"x", &glm::vec3::x, "y", &glm::vec3::y, "z", &glm::vec3::z,
"r", &glm::vec3::r, "g", &glm::vec3::g, "b", &glm::vec3::b,
"s", &glm::vec3::s, "t", &glm::vec3::t, "p", &glm::vec3::p,
"__add", addition<glm::vec3, float>(),
"__sub", subtraction<glm::vec3, float>(),
"__mul", multiplication<glm::vec3, float>(),
"__div", division<glm::vec3, float>()
// "__tostring", [](glm::vec3 self) { return self.x; } // Template!!! convert via logstream
);
auto vec4 = state.new_usertype<glm::vec4>(
"vec4",
sol::call_constructor, sol::constructors<glm::vec4(), glm::vec4(float), glm::vec4(float, float, float, float)>(),
"x", &glm::vec4::x, "y", &glm::vec4::y, "z", &glm::vec4::z, "w", &glm::vec4::w,
"r", &glm::vec4::r, "g", &glm::vec4::g, "b", &glm::vec4::b, "a", &glm::vec4::a,
"s", &glm::vec4::s, "t", &glm::vec4::t, "p", &glm::vec4::p, "q", &glm::vec4::q,
"__add", addition<glm::vec4, float>(),
"__sub", subtraction<glm::vec4, float>(),
"__mul", multiplication<glm::vec4, float>(),
"__div", division<glm::vec4, float>()
);
}
void Registration::component(sol::state_view& state)
{
auto tagComponent = state.new_usertype<TagComponent>("TagComponent", sol::no_constructor);
tagComponent["tag"] = &TagComponent::tag;
auto transformComponent = state.new_usertype<TransformComponent>("TransformComponent", sol::no_constructor);
transformComponent["translate"] = &TransformComponent::translate;
transformComponent["rotate"] = &TransformComponent::rotate;
transformComponent["scale"] = &TransformComponent::scale;
transformComponent["transform"] = &TransformComponent::transform;
auto cameraComponent = state.new_usertype<CameraComponent>("CameraComponent", sol::no_constructor);
cameraComponent["type"] = &CameraComponent::type;
cameraComponent["zoomLevel"] = &CameraComponent::zoomLevel;
cameraComponent["rotateAxis"] = &CameraComponent::rotateAxis;
cameraComponent["fov"] = &CameraComponent::fov;
cameraComponent["pitch"] = &CameraComponent::pitch;
cameraComponent["yaw"] = &CameraComponent::yaw;
cameraComponent["up"] = &CameraComponent::up;
cameraComponent["projection"] = &CameraComponent::projection;
auto spriteComponent = state.new_usertype<SpriteComponent>("SpriteComponent", sol::no_constructor);
spriteComponent["color"] = &SpriteComponent::color;
spriteComponent["texture"] = &SpriteComponent::texture;
}
}

60
inferno/src/inferno/script/registration.h

@ -0,0 +1,60 @@
#ifndef REGISTRATION_H
#define REGISTRATION_H
#include "sol/overload.hpp" // sol::overload
#include "sol/state_view.hpp" // sol::state_view
namespace Inferno {
class Registration final {
public:
static void fill(sol::state_view& state);
private:
static void glm(sol::state_view& state);
static void component(sol::state_view& state);
template<typename T, typename V>
static auto addition()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs + rhs; },
[](const T& lhs, const V& rhs) { return lhs + rhs; },
[](const V& lhs, const T& rhs) { return lhs + rhs; }
);
}
template<typename T, typename V>
static auto subtraction()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs - rhs; },
[](const T& lhs, const V& rhs) { return lhs - rhs; },
[](const V& lhs, const T& rhs) { return lhs - rhs; }
);
}
template<typename T, typename V>
static auto multiplication()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs * rhs; },
[](const T& lhs, const V& rhs) { return lhs * rhs; },
[](const V& lhs, const T& rhs) { return lhs * rhs; }
);
}
template<typename T, typename V>
static auto division()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs / rhs; },
[](const T& lhs, const V& rhs) { return lhs / rhs; },
[](const V& lhs, const T& rhs) { return lhs / rhs; }
);
}
};
}
#endif // REGISTRATION_H
Loading…
Cancel
Save