Work on lua bindings

This commit is contained in:
James Lambert 2022-09-05 17:12:08 -06:00
parent 134cd46d40
commit a9b9f336c9
26 changed files with 1082 additions and 4 deletions

2
.gitignore vendored
View file

@ -5,6 +5,8 @@
*.z64
*.blend1
lua-5.4.4/
build/
debugger
gfxvalidator

View file

@ -0,0 +1,198 @@
local pending_definitions = {}
local RefType = {}
function reference_to(value)
return setmetatable({ value = value }, RefType)
end
function is_reference_type(value)
return getmetatable(value) == RefType
end
local RawType = {}
function raw(value)
return setmetatable({ value = value}, RawType)
end
function is_raw(value)
return getmetatable(value) == RawType
end
local MacroType = {}
function macro(name, ...)
if (type(name) ~= "string") then
error("name should be of type string got " .. type(name))
end
return setmetatable({ name = name, args = {...}}, MacroType)
end
function is_macro(value)
return getmetatable(value) == MacroType
end
local function validate_definition(data, visited, name_path)
if (visited[data]) then
error("Circular reference found '" .. name_path .. "'")
return false
end
local data_type = type(data)
if (data_type == "nil" or data_type == "boolean" or data_type == "number" or data_type == "string") then
return true
end
if (data_type == "function" or data_type == "userdata" or data_type == "thread") then
error("Cannot use '" .. data_type .. "' in a c file definition for path '" .. name_path .. "'")
return false
end
if (is_reference_type(data) or is_raw(data)) then
return true
end
visited[data] = true
for k, v in pairs(data) do
local key_type = type(k)
if (key_type ~= "string" and key_type ~= "number") then
error("Cannot use '" .. data_type .. "' as a key in a c file definiton for path '" .. name_path .. "'")
return false
end
local name
if (key_type == "number") then
name = name_path .. "[" .. (k - 1) .. "]"
else
name = name_path .. "." .. k
end
if (not validate_definition(v, visited, name)) then
return false
end
end
visited[data] = nil
return true
end
function add_definition(nameHint, dataType, location, data)
if (type(nameHint) ~= "string") then
error("nameHint should be a string")
end
if (type(dataType) ~= "string") then
error("dataType should be a string")
end
if (type(location) ~= "string") then
error("location should be a string")
end
if (not validate_definition(data, {}, nameHint)) then
return false
end
table.insert(pending_definitions, {
nameHint = nameHint,
dataType = dataType,
location = location,
data = data
})
return true
end
local function populate_name_mapping(path, object, result)
if (type(object) ~= "table") then
return
end
if (is_reference_type(object) or is_macro(object)) then
return
end
result[object] = path
for k, v in pairs(object) do
if type(k) == "number" then
populate_name_mapping(path .. "[" .. (k - 1) .. "]", v, result)
else
populate_name_mapping(path .. "." .. k, v, result)
end
end
end
local function replace_references(object, name_mapping, name_path)
if type(object) ~= "table" then
return object
end
if (is_reference_type(object)) then
local referenceName = name_mapping[object.value]
if (referenceName == nil) then
error("A reference '" .. name_path .. "' was used on an object not exported in a definition")
end
return raw("&" .. referenceName)
end
local changes = {}
local hasChanges = false
for k, v in pairs(object) do
local name
if (type(k) == "number") then
name = name_path .. "[" .. (k - 1) .. "]"
else
name = name_path .. "." .. k
end
local replacement = replace_references(v, name_mapping, name)
if (replacement ~= v) then
changes[k] = replacement;
hasChanges = true
end
end
if (not hasChanges) then
return object
end
local result = {}
for k, v in pairs(object) do
result[k] = changes[k] or object[k]
end
return result
end
function consume_pending_definitions()
local result = pending_definitions
consume_pending_definitions = {}
return result
end
function process_definitions(definitions)
local name_mapping = {}
for k, v in pairs(definitions) do
populate_name_mapping(v.name, v.data, name_mapping)
end
for k, v in pairs(definitions) do
v.data = replace_references(v.data, name_mapping, v.name)
end
end

View file

@ -25,6 +25,7 @@
#include "src/materials/MaterialState.h"
#include "src/materials/MaterialTranslator.h"
#include "src/StringUtils.h"
#include "src/lua_generator/LuaGenerator.h"
void handler(int sig) {
void *array[10];
@ -226,6 +227,15 @@ int main(int argc, char *argv[]) {
generateMeshCollider(fileDef, *collisionOutput);
break;
}
case FileOutputType::Script:
{
NodeGroups nodesByGroup(scene);
for (auto script : args.mScriptFiles) {
std::cout << "Generating definitions from script " << script << std::endl;
generateFromLuaScript(script, scene, fileDef, nodesByGroup, settings);
}
break;
}
}
std::cout << "Writing output" << std::endl;

View file

@ -1,12 +1,16 @@
GCC_FLAGS = -Wall -Werror -g -rdynamic -I./yaml-cpp/include
LINKER_FLAGS = -L./yaml-cpp -lassimp -lyaml-cpp -lpng -ltiff
LINKER_FLAGS = -L./yaml-cpp -lassimp -lyaml-cpp -lpng -ltiff -llua -ldl
SRC_FILES = main.cpp $(shell find src/ -type f -name '*.cpp')
OBJ_FILES = $(patsubst %.cpp, build/%.o, $(SRC_FILES))
LUA_SRC_FILES = $(shell find lua/ -type f -name '*.lua')
LUA_OBJ_FILES = $(patsubst %.lua, build/%.o, $(LUA_SRC_FILES))
DEPS = $(patsubst %.cpp, build/%.d, $(SRC_FILES))
.PHONY: default
@ -14,13 +18,18 @@ default: skeletool64
-include $(DEPS)
build/lua/%.o: lua/%.lua
@mkdir -p $(@D)
luac -o $(@:%.o=%.out) $<
ld -r -b binary -o $@ $(@:%.o=%.out)
build/%.o: %.cpp
@mkdir -p $(@D)
g++ $(GCC_FLAGS) -c $< -o $@
$(CC) $(GCC_FLAGS) -MM $^ -MF "$(@:.o=.d)" -MT"$@"
skeletool64: $(OBJ_FILES)
g++ -g -o skeletool64 $(OBJ_FILES) $(LINKER_FLAGS)
skeletool64: $(OBJ_FILES) $(LUA_OBJ_FILES)
g++ -g -o skeletool64 $(OBJ_FILES) $(LUA_OBJ_FILES) $(LINKER_FLAGS)
clean:
rm -r build/

View file

@ -57,6 +57,8 @@ bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArgumen
output.mForceMaterialName = curr;
} else if (lastParameter == "pallete") {
output.mForcePallete = curr;
} else if (lastParameter == "script") {
output.mScriptFiles.push_back(curr);
}
lastParameter = "";
@ -100,6 +102,9 @@ bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArgumen
lastParameter = "default-material";
} else if (strcmp(curr, "--force-material") == 0) {
lastParameter = "force-material";
} else if (strcmp(curr, "--script") == 0) {
output.mOutputType = FileOutputType::Script;
lastParameter = "script";
} else {
if (curr[0] == '-') {
hasError = true;

View file

@ -12,6 +12,7 @@ enum class FileOutputType {
Level,
Materials,
CollisionMesh,
Script,
};
struct CommandLineArguments {
@ -20,6 +21,7 @@ struct CommandLineArguments {
FileOutputType mOutputType;
std::string mPrefix;
std::vector<std::string> mMaterialFiles;
std::vector<std::string> mScriptFiles;
std::string mDefaultMaterial;
std::string mForceMaterialName;
std::string mForcePallete;

View file

@ -2,6 +2,15 @@
#include "RenderChunk.h"
#include <algorithm>
RenderChunk::RenderChunk(): mBonePair(nullptr, nullptr),
mMesh(nullptr),
mMeshRoot(nullptr),
mAttachedDLIndex(-1),
mMaterial(nullptr) {
}
RenderChunk::RenderChunk(std::pair<Bone*, Bone*> bonePair, std::shared_ptr<ExtendedMesh> mesh, aiNode* meshRoot, Material* material):
mBonePair(bonePair),
mMesh(mesh),

View file

@ -13,6 +13,7 @@
class RenderChunk {
public:
RenderChunk();
RenderChunk(std::pair<Bone*, Bone*> bonePair, std::shared_ptr<ExtendedMesh> mesh, aiNode* meshRoot, Material* material);
RenderChunk(std::pair<Bone*, Bone*> bonePair, int attachedDLIndex, Material* material);
// if bones are the same, chunk cooresponds to a single bone

View file

@ -45,7 +45,7 @@ std::string StringDataChunk::EscapeAndWrapString(const std::string& string) {
if (escapeChar) {
result << '\\' << escapeChar;
} else {
result << escapeChar;
result << currChar;
}
}

View file

@ -0,0 +1,30 @@
#include "LuaBasicTypes.h"
void toLua(lua_State* L, const std::string& string) {
lua_pushlstring(L, string.c_str(), string.size());
}
void fromLua(lua_State* L, std::string& string) {
size_t len;
const char* str = lua_tolstring(L, -1, &len);
string.assign(str, len);
lua_pop(L, 1);
}
void toLua(lua_State* L, int number) {
lua_pushinteger(L, number);
}
void fromLua(lua_State* L, int& number) {
number = lua_tointeger(L, -1);
lua_pop(L, 1);
}
void toLua(lua_State* L, double number) {
lua_pushnumber(L, number);
}
void fromLua(lua_State* L, double& number) {
number = lua_tonumber(L, -1);
lua_pop(L, 1);
}

View file

@ -0,0 +1,110 @@
#ifndef __LUA_BASIC_TYPES_H__
#define __LUA_BASIC_TYPES_H__
#include <lua.hpp>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <iostream>
void toLua(lua_State* L, const std::string& string);
void fromLua(lua_State* L, std::string& string);
void toLua(lua_State* L, int number);
void fromLua(lua_State* L, int& number);
void toLua(lua_State* L, double number);
void fromLua(lua_State* L, double& number);
template <typename T> void toLua(lua_State* L, const std::vector<T> vector) {
lua_createtable(L, vector.size(), 0);
int tableIndex = lua_gettop(L);
int index = 1;
for (const auto& element : vector) {
toLua(L, element);
lua_seti(L, tableIndex, index);
++index;
}
}
template <typename T> void fromLua(lua_State* L, std::vector<T>& result) {
lua_len(L, -1);
int length;
fromLua(L, length);
result.resize(length);
for (int i = 1; i <= length; ++i) {
lua_geti(L, -1, i);
fromLua(L, result[i-1]);
}
lua_pop(L, 1);
}
template <typename T> void toLua(lua_State* L, const T* array, unsigned count) {
lua_createtable(L, count, 0);
int tableIndex = lua_gettop(L);
for (unsigned i = 0; i < count; ++i) {
toLua(L, array[i]);
lua_seti(L, tableIndex, i + 1);
++i;
}
}
template <typename A, typename B> void toLua(lua_State* L, const std::pair<A, B>& pair) {
lua_createtable(L, 2, 0);
int tableIndex = lua_gettop(L);
toLua(L, pair.first);
lua_seti(L, tableIndex, 1);
toLua(L, pair.second);
lua_seti(L, tableIndex, 2);
}
template <typename A, typename B> void fromLua(lua_State* L, std::pair<A, B>& pair) {
lua_geti(L, -1, 1);
fromLua(L, pair.first);
lua_geti(L, -1, 2);
fromLua(L, pair.second);
lua_pop(L, 1);
}
template <typename T> int luaSharedPtrGC(lua_State* L) {
std::shared_ptr<T>* ptr = (std::shared_ptr<T>*)luaL_checkudata(L, 1, typeid(std::shared_ptr<T>).name());
ptr->~shared_ptr();
return 0;
}
template <typename T> void toLua(lua_State* L, std::shared_ptr<T> ptr) {
std::shared_ptr<T>* result = (std::shared_ptr<T>*)lua_newuserdata(L, sizeof(std::shared_ptr<T>));
int resultIndex = lua_gettop(L);
new(result) std::shared_ptr<T>(ptr);
if (luaL_newmetatable(L, typeid(std::shared_ptr<T>).name())) {
lua_pushcfunction(L, luaSharedPtrGC<T>);
lua_setfield(L, -2, "__gc");
}
lua_setmetatable(L, resultIndex);
}
template <typename T> void fromLua(lua_State* L, std::shared_ptr<T>& output) {
std::shared_ptr<T>* ptr = (std::shared_ptr<T>*)luaL_checkudata(L, -1, typeid(std::shared_ptr<T>).name());
output = *ptr;
lua_pop(L, 1);
}
#endif

View file

@ -0,0 +1,189 @@
#include "LuaDefinitionWriter.h"
#include "LuaGenerator.h"
#include "../StringUtils.h"
std::unique_ptr<DataChunk> buildDataChunk(lua_State* L);
std::unique_ptr<DataChunk> buildMacroChunk(lua_State* L) {
lua_getfield(L, -1, "name");
std::string name = lua_tostring(L, -1);
lua_pop(L, 1);
std::unique_ptr<MacroDataChunk> result(new MacroDataChunk(name));
lua_getfield(L, -1, "args");
int args = lua_gettop(L);
lua_pushnil(L); /* first key */
while (lua_next(L, args) != 0) {
result->Add(std::move(buildDataChunk(L)));
lua_pop(L, 1);
}
lua_pop(L, 1);
return result;
}
std::unique_ptr<DataChunk> buildStructureChunk(lua_State* L) {
int topStart = lua_gettop(L);
std::unique_ptr<StructureDataChunk> result(new StructureDataChunk());
lua_pushnil(L); /* first key */
while (lua_next(L, topStart) != 0) {
int keyType = lua_type(L, -2);
if (keyType == LUA_TNUMBER) {
result->Add(std::move(buildDataChunk(L)));
} else if (keyType == LUA_TSTRING) {
result->Add(lua_tostring(L, -2), std::move(buildDataChunk(L)));
}
lua_pop(L, 1);
}
return result;
}
std::unique_ptr<DataChunk> buildDataChunk(lua_State* L) {
int type = lua_type(L, -1);
if (type == LUA_TNUMBER) {
if (lua_isinteger(L, -1))
{
int result = lua_tointeger(L, -1);
return std::unique_ptr<DataChunk>(new PrimitiveDataChunk<int>(result));
}
double result = lua_tonumber(L, -1);
return std::unique_ptr<DataChunk>(new PrimitiveDataChunk<double>(result));
}
if (type == LUA_TNIL) {
return std::unique_ptr<DataChunk>(new PrimitiveDataChunk<int>(0));
}
if (type == LUA_TBOOLEAN) {
return std::unique_ptr<DataChunk>(new PrimitiveDataChunk<int>(lua_toboolean(L, -1)));
}
if (type == LUA_TSTRING) {
size_t len;
const char* buffer = lua_tolstring(L, -1, &len);
std::string bufferAsString(buffer, len);
return std::unique_ptr<DataChunk>(new StringDataChunk(bufferAsString));
}
if (type == LUA_TTABLE) {
lua_getglobal(L, "is_raw");
lua_pushnil(L);
lua_copy(L, -3, -1);
lua_call(L, 1, 1);
if (lua_toboolean(L, -1)) {
// pop the bool
lua_pop(L, 1);
lua_getfield(L, -1, "value");
std::unique_ptr<DataChunk> result(new PrimitiveDataChunk<std::string>(lua_tostring(L, -1)));
lua_pop(L, 1);
return result;
}
lua_pop(L, 1);
lua_getglobal(L, "is_macro");
lua_pushnil(L);
lua_copy(L, -3, -1);
lua_call(L, 1, 1);
if (lua_toboolean(L, -1)) {
// pop the bool
lua_pop(L, 1);
return buildMacroChunk(L);
}
lua_pop(L, 1);
return buildStructureChunk(L);
}
return std::unique_ptr<DataChunk>(nullptr);
}
void processCFileDefinition(lua_State* L, CFileDefinition& fileDef, const char* filename) {
int topStart = lua_gettop(L);
lua_getfield(L, topStart, "name");
std::string definitionName = lua_tostring(L, -1);
lua_pop(L, 1);
lua_getfield(L, topStart, "dataType");
std::string dataType = lua_tostring(L, -1);
lua_pop(L, 1);
lua_getfield(L, topStart, "location");
std::string location = lua_tostring(L, -1);
lua_pop(L, 1);
bool isArray = false;
if (EndsWith(dataType, "[]")) {
isArray = true;
dataType = dataType.substr(0, dataType.length() - 2);
}
lua_getfield(L, topStart, "data");
std::unique_ptr<DataChunk> dataChunk = buildDataChunk(L);
lua_pop(L, 1);
std::unique_ptr<FileDefinition> definition(new DataFileDefinition(dataType, definitionName, isArray, location, std::move(dataChunk)));
fileDef.AddDefinition(std::move(definition));
}
void dumpDefinitions(lua_State* L, CFileDefinition& fileDef, const char* filename) {
int topStart = lua_gettop(L);
lua_getglobal(L, "consume_pending_definitions");
int errcode = lua_pcall(L, 0, 1, 0);
if (checkLuaError(L, errcode, filename)) {
lua_settop(L, topStart);
return;
}
int definitionArray = lua_gettop(L);
lua_pushnil(L); /* first key */
while (lua_next(L, definitionArray) != 0) {
int entry = lua_gettop(L);
lua_getfield(L, entry, "nameHint");
const char* nameHint = lua_tostring(L, -1);
std::string name = fileDef.GetUniqueName(nameHint);
lua_pop(L, 1);
lua_pushstring(L, name.c_str());
lua_setfield(L, entry, "name");
lua_pop(L, 1);
}
lua_getglobal(L, "process_definitions");
lua_pushnil(L);
lua_copy(L, definitionArray, -1);
errcode = lua_pcall(L, 1, LUA_MULTRET, 0);
if (checkLuaError(L, errcode, filename)) {
lua_settop(L, topStart);
return;
}
lua_settop(L, definitionArray);
lua_pushnil(L); /* first key */
while (lua_next(L, topStart + 1) != 0) {
processCFileDefinition(L, fileDef, filename);
lua_pop(L, 1);
}
lua_settop(L, topStart);
}

View file

@ -0,0 +1,9 @@
#ifndef __LUA_DEFINITON_WRITER_H__
#define __LUA_DEFINITON_WRITER_H__
#include <lua.hpp>
#include "../CFileDefinition.h"
void dumpDefinitions(lua_State* L, CFileDefinition& fileDef, const char* filename);
#endif

View file

@ -0,0 +1,54 @@
#include "LuaDisplayListSettings.h"
#include <string.h>
#include "./LuaMesh.h"
Material* luaGetMaterial(lua_State* L, const DisplayListSettings& defaults) {
int materialType = lua_type(L, -1);
if (materialType == LUA_TSTRING) {
auto material = defaults.mMaterials.find(lua_tostring(L, -1));
if (material != defaults.mMaterials.end()) {
return material->second.get();
}
}
if (materialType == LUA_TTABLE) {
lua_pushnil(L);
lua_copy(L, -2, -1);
Material* result = nullptr;
fromLua(L, result);
return result;
}
return nullptr;
}
void fromLua(lua_State* L, DisplayListSettings& result, const DisplayListSettings& defaults) {
result = defaults;
int topStart = lua_gettop(L);
lua_pushnil(L); /* first key */
while (lua_next(L, topStart) != 0) {
int keyType = lua_type(L, -2);
if (keyType == LUA_TSTRING) {
const char* key = lua_tostring(L, -2);
if (strcmp(key, "defaultMaterial") == 0) {
Material* material = luaGetMaterial(L, defaults);
if (!material) {
luaL_error(L, "invlaid defaultMaterial");
}
result.mDefaultMaterialState = material->mState;
}
}
lua_pop(L, 1);
}
}

View file

@ -0,0 +1,9 @@
#ifndef __LUA_DISPLAY_LIST_SETTINGS_H__
#define __LUA_DISPLAY_LIST_SETTINGS_H__
#include <lua.hpp>
#include "../DisplayListSettings.h"
void fromLua(lua_State* L, DisplayListSettings& result, const DisplayListSettings& defaults);
#endif

View file

@ -0,0 +1 @@
EMIT(definition_writer)

View file

@ -0,0 +1,92 @@
#include "LuaGenerator.h"
#include "../FileUtils.h"
#include "LuaDefinitionWriter.h"
#include "LuaTransform.h"
#include "LuaNodeGroups.h"
#include "LuaScene.h"
#include "LuaMesh.h"
#include <lua.hpp>
#include <iostream>
#define EMIT(name) extern const char _binary_build_lua_##name##_out_start[]; extern const char _binary_build_lua_##name##_out_end[];
#include "LuaFiles.h"
#undef EMIT
struct LuaFile {
const char* start;
const char* end;
const char* name;
};
struct LuaFile luaFiles[] = {
#define EMIT(name) {_binary_build_lua_##name##_out_start, _binary_build_lua_##name##_out_end, "lua/" #name ".lua"},
#include "LuaFiles.h"
#undef EMIT
};
bool checkLuaError(lua_State *L, int errCode, const char* filename) {
if (errCode != LUA_OK) {
const char* error = lua_tostring(L, -1);
if (error) {
std::cerr << "Error running " << filename << ":" << std::endl << error << std::endl;
} else {
std::cerr << "Unknown error running " << filename;
}
return true;
}
return false;
}
void generateFromLuaScript(
const std::string& filename,
const aiScene* scene,
CFileDefinition& fileDefinition,
NodeGroups& nodeGroups,
const DisplayListSettings& settings
) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
generateLuaTransform(L);
populateLuaScene(L, scene);
populateLuaNodeGroups(L, nodeGroups);
populateLuaMesh(L, scene, fileDefinition, settings);
for (unsigned i = 0; i < sizeof(luaFiles) / sizeof(*luaFiles); ++i) {
struct LuaFile* file = &luaFiles[i];
luaL_loadbuffer(L, file->start, file->end - file->start, file->name);
int stackSize = lua_gettop(L);
int errCode = lua_pcall(L, 0, LUA_MULTRET, 0);
if (checkLuaError(L, errCode, file->name)) {
lua_close(L);
return;
}
lua_settop(L, stackSize);
}
std::string directory = DirectoryName(filename) + "/?.lua;";
// set the directory of the script location as a search path
lua_getglobal(L, "package");
int packageLocation = lua_gettop(L);
lua_pushstring(L, directory.c_str());
lua_getfield(L, packageLocation, "path");
lua_concat(L, 2);
lua_setfield(L, packageLocation, "path");
int errCode = luaL_dofile(L, filename.c_str());
if (checkLuaError(L, errCode, filename.c_str())) {
lua_close(L);
return;
}
dumpDefinitions(L, fileDefinition, filename.c_str());
lua_close(L);
}

View file

@ -0,0 +1,20 @@
#ifndef __LUA_GENERATOR_H__
#define __LUA_GENERATOR_H__
#include <lua.hpp>
#include <assimp/scene.h>
#include "../CFileDefinition.h"
#include "../DisplayListSettings.h"
#include "../definition_generator/DefinitionGenerator.h"
bool checkLuaError(lua_State *L, int errCode, const char* filename);
void generateFromLuaScript(
const std::string& filename,
const aiScene* scene,
CFileDefinition& fileDefinition,
NodeGroups& nodeGroups,
const DisplayListSettings& settings
);
#endif

View file

@ -0,0 +1,157 @@
#include "LuaMesh.h"
#include "../definition_generator/MeshDefinitionGenerator.h"
#include "./LuaBasicTypes.h"
#include "./LuaScene.h"
#include "../MeshWriter.h"
#include "./LuaDisplayListSettings.h"
void toLua(lua_State* L, Material* material) {
lua_createtable(L, 1, 0);
luaL_getmetatable(L, "Material");
lua_setmetatable(L, -2);
toLua(L, material->mName);
lua_setfield(L, -2, "name");
lua_pushlightuserdata(L, material);
lua_setfield(L, -2, "ptr");
}
void fromLua(lua_State* L, Material *& material) {
lua_getfield(L, -1, "ptr");
material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 2);
}
void meshToLua(lua_State* L, std::shared_ptr<ExtendedMesh> mesh) {
lua_createtable(L, 0, 1);
toLua(L, mesh);
lua_setfield(L, -2, "ptr");
}
void meshFromLua(lua_State* L, std::shared_ptr<ExtendedMesh>& mesh) {
lua_getfield(L, -1, "ptr");
fromLua(L, mesh);
lua_pop(L, 1);
}
void toLua(lua_State* L, const Bone* bone) {
lua_pushlightuserdata(L, const_cast<Bone*>(bone));
}
void fromLua(lua_State*L, Bone *& bone) {
bone = (Bone*)lua_touserdata(L, -1);
lua_pop(L, 1);
}
void toLua(lua_State* L, const RenderChunk& renderChunk) {
lua_createtable(L, 0, 5);
int tableIndex = lua_gettop(L);
toLua(L, renderChunk.mBonePair);
lua_setfield(L, tableIndex, "bone_pair");
meshToLua(L, renderChunk.mMesh);
lua_setfield(L, tableIndex, "mesh");
toLua(L, renderChunk.mMeshRoot);
lua_setfield(L, tableIndex, "meshRoot");
toLua(L, renderChunk.mAttachedDLIndex);
lua_setfield(L, tableIndex, "attached_dl_index");
toLua(L, renderChunk.mMaterial);
lua_setfield(L, tableIndex, "material");
}
void fromLua(lua_State* L, RenderChunk& result) {
lua_getfield(L, -1, "bone_pair");
fromLua(L, result.mBonePair);
lua_getfield(L, -1, "mesh");
meshFromLua(L, result.mMesh);
lua_getfield(L, -1, "meshRoot");
fromLua(L, result.mMeshRoot);
lua_getfield(L, -1, "attached_dl_index");
fromLua(L, result.mAttachedDLIndex);
lua_getfield(L, -1, "material");
fromLua(L, result.mMaterial);
lua_pop(L, 1);
}
int luaBuildRenderChunks(lua_State* L) {
const aiScene* scene = (const aiScene*)lua_touserdata(L, lua_upvalueindex(1));
CFileDefinition* fileDefinition = (CFileDefinition*)lua_touserdata(L, lua_upvalueindex(2));
DisplayListSettings* settings = (DisplayListSettings*)lua_touserdata(L, lua_upvalueindex(3));
luaL_checktype(L, 1, LUA_TTABLE);
lua_getfield(L, 1, "ptr");
aiNode* node = (aiNode*)lua_touserdata(L, -1);
std::vector<RenderChunk> renderChunks;
if (node) {
MeshDefinitionGenerator::AppendRenderChunks(scene, node, *fileDefinition, *settings, renderChunks);
}
toLua(L, renderChunks);
return 1;
}
int luaGenerateMesh(lua_State* L) {
const aiScene* scene = (const aiScene*)lua_touserdata(L, lua_upvalueindex(1));
CFileDefinition* fileDefinition = (CFileDefinition*)lua_touserdata(L, lua_upvalueindex(2));
DisplayListSettings* settings = (DisplayListSettings*)lua_touserdata(L, lua_upvalueindex(3));
luaL_checktype(L, 1, LUA_TTABLE);
const char* location = luaL_checkstring(L, 2);
std::vector<RenderChunk> renderChunks;
lua_pushnil(L);
lua_copy(L, 1, -1);
fromLua(L, renderChunks);
std::string result;
if (lua_gettop(L) >= 3 && lua_type(L, 3) == LUA_TTABLE) {
lua_settop(L, 3);
DisplayListSettings settingOverride;
fromLua(L, settingOverride, *settings);
result = generateMesh(scene, *fileDefinition, renderChunks, settingOverride, location);
} else {
result = generateMesh(scene, *fileDefinition, renderChunks, *settings, location);
}
toLua(L, result);
return 1;
}
void populateLuaMesh(lua_State* L, const aiScene* scene, CFileDefinition& fileDefinition, const DisplayListSettings& settings) {
lua_newtable(L);
luaL_setmetatable(L, "Material");
lua_pushlightuserdata(L, const_cast<aiScene*>(scene));
lua_pushlightuserdata(L, &fileDefinition);
lua_pushlightuserdata(L, const_cast<DisplayListSettings*>(&settings));
lua_pushcclosure(L, luaBuildRenderChunks, 3);
lua_setglobal(L, "generate_render_chunks");
lua_pushlightuserdata(L, const_cast<aiScene*>(scene));
lua_pushlightuserdata(L, &fileDefinition);
lua_pushlightuserdata(L, const_cast<DisplayListSettings*>(&settings));
lua_pushcclosure(L, luaGenerateMesh, 3);
lua_setglobal(L, "generate_mesh");
}

View file

@ -0,0 +1,13 @@
#ifndef __LUA_MESH_H__
#define __LUA_MESH_H__
#include <lua.hpp>
#include <assimp/scene.h>
#include "../CFileDefinition.h"
#include "../DisplayListSettings.h"
void fromLua(lua_State* L, Material *& material);
void populateLuaMesh(lua_State* L, const aiScene* scene, CFileDefinition& fileDefinition, const DisplayListSettings& settings);
#endif

View file

@ -0,0 +1,31 @@
#include "LuaNodeGroups.h"
#include "LuaBasicTypes.h"
#include "LuaScene.h"
void toLua(lua_State* L, const NodeWithArguments& nodes) {
lua_createtable(L, 0, 2);
int tableIndex = lua_gettop(L);
toLua(L, nodes.arguments);
lua_setfield(L, tableIndex, "arguments");
toLua(L, nodes.node);
lua_setfield(L, tableIndex, "node");
}
int luaNodesForType(lua_State* L) {
std::string prefix = luaL_checkstring(L, 1);
NodeGroups* nodeGroups = (NodeGroups*)lua_touserdata(L, lua_upvalueindex(1));
std::vector<NodeWithArguments> result = nodeGroups->NodesForType(prefix);
toLua(L, result);
return 1;
}
void populateLuaNodeGroups(lua_State* L, NodeGroups& nodeGroups) {
lua_pushlightuserdata(L, (NodeGroups*)&nodeGroups);
lua_pushcclosure(L, luaNodesForType, 1);
lua_setglobal(L, "nodes_for_type");
}

View file

@ -0,0 +1,9 @@
#ifndef __LUA_NODE_GROUPS_H__
#define __LUA_NODE_GROUPS_H__
#include <lua.hpp>
#include "../definition_generator/DefinitionGenerator.h"
void populateLuaNodeGroups(lua_State* L, NodeGroups& nodeGroups);
#endif

View file

@ -0,0 +1,79 @@
#include "LuaScene.h"
#include "LuaBasicTypes.h"
#include "LuaTransform.h"
#include <iostream>
void toLua(lua_State* L, const aiNode* node) {
if (!node) {
lua_pushnil(L);
return;
}
// check if node ia already built in the cache
lua_getglobal(L, "node_cache");
int nodeCache = lua_gettop(L);
lua_pushlightuserdata(L, const_cast<aiNode*>(node));
lua_gettable(L, nodeCache);
if (!lua_isnil(L, -1)) {
lua_remove(L, nodeCache);
return;
}
lua_pop(L, 1);
lua_createtable(L, 0, 1);
int tableIndex = lua_gettop(L);
luaL_getmetatable(L, "aiNode");
lua_setmetatable(L, tableIndex);
lua_pushlightuserdata(L, const_cast<aiNode*>(node));
lua_setfield(L, tableIndex, "ptr");
toLua(L, node->mName.C_Str());
lua_setfield(L, tableIndex, "name");
toLua(L, node->mTransformation);
lua_setfield(L, tableIndex, "transformation");
// save node into the cache before building related nodes
lua_pushlightuserdata(L, const_cast<aiNode*>(node));
lua_pushnil(L);
lua_copy(L, tableIndex, -1);
lua_settable(L, nodeCache);
toLua(L, node->mParent);
lua_setfield(L, tableIndex, "parent");
toLua(L, node->mChildren, node->mNumChildren);
lua_setfield(L, tableIndex, "children");
lua_remove(L, nodeCache);
}
void fromLua(lua_State* L, aiNode *& node) {
lua_getfield(L, -1, "ptr");
node = (aiNode*)lua_touserdata(L, -1);
lua_pop(L, 2);
}
void toLua(lua_State* L, const aiScene* scene) {
lua_createtable(L, 0, 1);
int tableIndex = lua_gettop(L);
luaL_getmetatable(L, "aiScene");
lua_setmetatable(L, tableIndex);
lua_pushlightuserdata(L, const_cast<aiScene*>(scene));
lua_setfield(L, tableIndex, "ptr");
toLua(L, scene->mRootNode);
lua_setfield(L, tableIndex, "root");
}
void populateLuaScene(lua_State* L, const aiScene* scene) {
lua_newtable(L);
lua_setglobal(L, "node_cache");
toLua(L, scene);
lua_setglobal(L, "scene");
}

View file

@ -0,0 +1,13 @@
#ifndef __LUA_SCENE_H__
#define __LUA_SCENE_H__
#include <assimp/scene.h>
#include <lua.hpp>
void toLua(lua_State* L, const aiNode* node);
void fromLua(lua_State* L, aiNode *& node);
void populateLuaScene(lua_State* L, const aiScene* scene);
#endif

View file

@ -0,0 +1,15 @@
#include "LuaTransform.h"
void toLua(lua_State* L, const aiMatrix4x4& matrix) {
aiMatrix4x4* result = (aiMatrix4x4*)lua_newuserdata(L, sizeof(aiMatrix4x4));
new(result) aiMatrix4x4(matrix);
luaL_getmetatable(L, "aiMatrix4x4");
lua_setmetatable(L, -2);
}
void generateLuaTransform(lua_State* L) {
luaL_newmetatable(L, "aiMatrix4x4");
lua_pop(L, 1);
}

View file

@ -0,0 +1,11 @@
#ifndef __LUA_TRANSFORM_H__
#define __LUA_TRANSFORM_H__
#include <lua.hpp>
#include <assimp/scene.h>
void toLua(lua_State* L, const aiMatrix4x4& matrix);
void generateLuaTransform(lua_State* L);
#endif