int EngineObjectParserBase::LuaCreate( lua_State *L ) { INIT_LUA_STACK_TRACKING( L ); EngineObjectParserBase *This = static_cast<EngineObjectParserBase *>(lua_touserdata( L, lua_upvalueindex( 1 ) )); // This pointer cannot be null because we stored it in an up value when created the library VERIFY( This, "This pointer is null" ); if( !This )return 0; try { This->CreateObj( L ); } catch( const std::runtime_error &err ) { SCRIPT_PARSING_ERROR( L, "Failed to create ", This->m_LibName, " object: \n", err.what() ); } // Push onto the stack the metatable associated with name given in the registry luaL_getmetatable( L, This->m_MetatableRegistryName.c_str() ); // -0 | +1 -> +1 // Pop a table from the top of the stack and set it as the new metatable // for the value at the given index (which is where the new user datum is) lua_setmetatable( L, -2 ); // -1 | +0 -> -1 CHECK_LUA_STACK_HEIGHT( +1 ); // Return number of return arguments // New userdatum is on the top of the stack return 1; }
void DrawAttribsParser::CreateObj( lua_State *L ) { INIT_LUA_STACK_TRACKING(L); DrawAttribs DrawAttrs; ParseLuaTable( L, 1, &DrawAttrs, m_Bindings ); CHECK_LUA_STACK_HEIGHT(); auto pDrawAttribs = reinterpret_cast<DrawAttribs*>(lua_newuserdata( L, sizeof( DrawAttribs ) )); memcpy(pDrawAttribs, &DrawAttrs, sizeof(DrawAttribs)); CHECK_LUA_STACK_HEIGHT( +1 ); }
void EngineObjectParserBase::PushObject( lua_State *L, const void *pData ) { INIT_LUA_STACK_TRACKING( L ); if( pData ) PushExistingObject( L, pData ); else lua_pushnil( L ); luaL_getmetatable( L, m_MetatableRegistryName.c_str() ); // -0 | +1 -> +1 lua_setmetatable( L, -2 ); // -1 | +0 -> -1 CHECK_LUA_STACK_HEIGHT( +1 ); }
IDeviceContext* EngineObjectParserBase::LoadDeviceContextFromRegistry( lua_State *L ) { INIT_LUA_STACK_TRACKING( L ); lua_pushstring( L, ScriptParser::DeviceContextRegistryKey ); // -0 | +1 -> +1 lua_gettable(L, LUA_REGISTRYINDEX ); // -1 | +1 -> +0 CheckType( L, -1, LUA_TLIGHTUSERDATA ); IDeviceContext* pContext = reinterpret_cast<IDeviceContext*>( lua_touserdata(L, -1) ); lua_pop( L, 1 ); // -1 | +0 -> -1 VERIFY( pContext != nullptr, "Device context is null" ); CHECK_LUA_STACK_HEIGHT(); return pContext; }
void SamplerParser::CreateObj( lua_State *L ) { INIT_LUA_STACK_TRACKING( L ); SSamDescWrapper SamplerDesc; ParseLuaTable( L, -1, &SamplerDesc, m_Bindings ); CHECK_LUA_STACK_HEIGHT(); auto ppSampler = reinterpret_cast<ISampler**>(lua_newuserdata( L, sizeof( ISampler* ) )); *ppSampler = nullptr; m_pRenderDevice->CreateSampler( SamplerDesc, ppSampler ); if( *ppSampler == nullptr ) SCRIPT_PARSING_ERROR(L, "Failed to create a sampler") CHECK_LUA_STACK_HEIGHT( +1 ); }
int EngineObjectParserBase::LuaIndex( lua_State *L ) { INIT_LUA_STACK_TRACKING( L ); // Whenever Lua calls C, the called function gets a new stack, which is independent // of previous stacks and of stacks of C functions that are still active. This stack // initially contains any arguments to the C function and it is where the C function // pushes its results to be returned to the calle // Note that the syntax var.Name is just syntactic sugar for var["Name"] // The first parameter to the __index() function is the object and the second is // the index EngineObjectParserBase *This = static_cast<EngineObjectParserBase *>(lua_touserdata( L, lua_upvalueindex( 1 ) )); // This pointer cannot be null because we stored it in an up value when created the library VERIFY( This, "This pointer is null" ); if( !This )return 0; auto pData = GetUserData<void*>( L, 1, This->m_MetatableRegistryName.c_str() ); auto Field = ReadValueFromLua<const Char*>( L, 2 ); // First try to find the field in the metatable // Push metatable onto the stack luaL_getmetatable( L, This->m_MetatableRegistryName.c_str() ); // -0 | +1 -> +1 // Duplicate key on the top of the stack lua_pushvalue( L, -2 ); // -0 | +1 -> +1 // Use rawget to avoid calling __index lua_rawget( L, -2 ); // -1 | +1 -> +0 // Remove metatable from the stack lua_remove( L, -2 ); // -1 | +0 -> -1 if( lua_type( L, -1 ) == LUA_TNIL ) { // Pop nil from the stack lua_pop( L, 1 ); // -1 | +0 -> -1 This->ReadField( L, pData, Field ); } else { // Value is on top of the stack } CHECK_LUA_STACK_HEIGHT( +1 ); return 1; }
int EngineObjectParserBase::LuaNewIndex( lua_State *L ) { INIT_LUA_STACK_TRACKING( L ); EngineObjectParserBase *This = static_cast<EngineObjectParserBase *>(lua_touserdata( L, lua_upvalueindex( 1 ) )); // This pointer cannot be null because we stored it in an up value when created the library VERIFY( This, "This pointer is null" ); if( !This )return 0; auto pData = GetUserData<void*>( L, 1, This->m_MetatableRegistryName.c_str() ); auto Field = ReadValueFromLua<const Char*>( L, 2 ); This->UpdateField( L, pData, Field ); CHECK_LUA_STACK_HEIGHT(); return 0; }
void TextureViewParser::CreateObj( lua_State *L ) { INIT_LUA_STACK_TRACKING(L); auto *pTexture = *GetUserData<ITexture**>( L, 1, m_TextureLibMetatableName.c_str() ); STexViewDescWrapper TextureViewDesc; ParseLuaTable( L, 2, &TextureViewDesc, m_Bindings ); CHECK_LUA_STACK_HEIGHT(); auto ppTextureView = reinterpret_cast<ITextureView**>(lua_newuserdata( L, sizeof( ITextureView* ) )); *ppTextureView = nullptr; pTexture->CreateView( TextureViewDesc, ppTextureView ); if( *ppTextureView == nullptr ) SCRIPT_PARSING_ERROR(L, "Failed to create texture view") CHECK_LUA_STACK_HEIGHT( +1 ); }
int ShaderResourceBindingParser::GetVariable( lua_State *L ) { auto NumArgs = lua_gettop( L ); if( NumArgs < 3 ) { SCRIPT_PARSING_ERROR( L, "2 arguments (shader type and variable name) are expected" ); } INIT_LUA_STACK_TRACKING(L); int ArgStackInd = 1; // The object itself goes first auto *pShaderResBinding = *GetUserData<IShaderResourceBinding**>( L, ArgStackInd, m_MetatableRegistryName.c_str() ); // Shader type should be the first argument ++ArgStackInd; SHADER_TYPE ShaderType = SHADER_TYPE_UNKNOWN; EnumMemberBinder<SHADER_TYPE> ShaderTypeParser(0, "ShaderType", m_ShaderTypeEnumMapping); ShaderTypeParser.SetValue(L, ArgStackInd, &ShaderType); ++ArgStackInd; // Variable name should be the second argument auto VarName = ReadValueFromLua<String>( L, ArgStackInd ); auto pVar = pShaderResBinding->GetVariable(ShaderType, VarName.c_str()); auto pNewShaderVarLuaObj = reinterpret_cast<IShaderVariable**>(lua_newuserdata( L, sizeof( IShaderVariable* ) )); *pNewShaderVarLuaObj = pVar; pVar->AddRef(); // Push onto the stack the metatable associated with name given in the registry luaL_getmetatable( L, m_ShaderVarMetatableRegistryName.c_str() ); // -0 | +1 -> +1 // Pop a table from the top of the stack and set it as the new metatable // for the value at the given index (which is where the new user datum is) lua_setmetatable( L, -2 ); // -1 | +0 -> -1 CHECK_LUA_STACK_HEIGHT( +1 ); return 1; }
int EngineObjectParserBase::LuaGC( lua_State *L ) { INIT_LUA_STACK_TRACKING( L ); EngineObjectParserBase *This = static_cast<EngineObjectParserBase *>(lua_touserdata( L, lua_upvalueindex( 1 ) )); // This pointer cannot be null because we stored it in an up value when created the library VERIFY( This, "This pointer is null" ); if( !This )return 0; // Do not throw exception as this function can be called from dtor! //auto pData = GetUserData<void*>( L, 1, This->m_MetatableRegistryName.c_str() ); auto pData = reinterpret_cast<void*>(luaL_testudata( L, 1, This->m_MetatableRegistryName.c_str() )); if( pData ) { This->DestroyObj( pData ); } CHECK_LUA_STACK_HEIGHT(); return 0; }
int TextureViewParser::GetDefaultView( lua_State *L ) { INIT_LUA_STACK_TRACKING( L ); // Texture should be the first argument auto *pTexture = *GetUserData<ITexture**>( L, 1, m_TextureLibMetatableName.c_str() ); // View type should be the second argument TEXTURE_VIEW_TYPE ViewType; m_ViewTypeParser.SetValue( L, 2, &ViewType ); auto pView = pTexture->GetDefaultView( ViewType ); if( !pView ) SCRIPT_PARSING_ERROR( L, "Failed to get default texture view of type ", GetTexViewTypeLiteralName( ViewType ) ); // Push existing object PushObject(L, pView); CHECK_LUA_STACK_HEIGHT( +1 ); // Returning one value to Lua return 1; }
LuaState::LuaState( Uint32 OpenLibFlags ) { m_pLuaState = luaL_newstate(); //luaL_openlibs( m_pLuaState ); INIT_LUA_STACK_TRACKING( m_pLuaState ); struct LuaStdLibInfo { const char *name; lua_CFunction func; Uint32 Flag; }LuaStdLibs[] = { { "_G", luaopen_base, LUA_LIB_BASE }, { LUA_LOADLIBNAME, luaopen_package, LUA_LIB_PACKAGE }, { LUA_COLIBNAME, luaopen_coroutine, LUA_LIB_COROUTINE }, { LUA_TABLIBNAME, luaopen_table, LUA_LIB_TABLE }, { LUA_IOLIBNAME, luaopen_io, LUA_LIB_IO }, { LUA_OSLIBNAME, luaopen_os, LUA_LIB_OS }, { LUA_STRLIBNAME, luaopen_string, LUA_LIB_STRING }, { LUA_BITLIBNAME, luaopen_bit32, LUA_LIB_BIT32 }, { LUA_MATHLIBNAME, luaopen_math, LUA_LIB_MATH }, { LUA_DBLIBNAME, luaopen_debug, LUA_LIB_DEBUG }, { nullptr, nullptr, 0 } }; for( auto lib = LuaStdLibs; lib->func; lib++ ) { if( OpenLibFlags & lib->Flag ) { luaL_requiref( m_pLuaState, lib->name, lib->func, 1 ); // -0 | +1 -> +1 lua_pop( m_pLuaState, 1 ); // -1 | +0 -> -1 } } CHECK_LUA_STACK_HEIGHT(); }
void EngineObjectParserBase::RegisterTable( lua_State *L ) { INIT_LUA_STACK_TRACKING( L ); // If the registry already has the key with the same name, luaL_newmetatable() returns 0. // Otherwise, it creates a new table to be used as a metatable for userdata, adds it to the // registry with key tname, and returns 1. In both cases it pushes onto the stack the final // value associated with tname in the registry. auto Created = luaL_newmetatable( L, m_MetatableRegistryName.c_str() ); // -0 | +1 -> +1 VERIFY( Created, "Metatble with the same name already registered!" ); // http://lua-users.org/wiki/MetatableEvents luaL_Reg MetaMethods[] = { // An object is marked for finalization when its metatable is set and the metatable // has a field indexed by the string "__gc". NOTE: if a metatable without a __gc field // is set and that field is only later added to the metatable, the object will NOT be marked // for finalization. { "__gc", LuaGC }, { "__index", LuaIndex }, { "__newindex", LuaNewIndex }, { NULL, NULL } }; lua_pushlightuserdata( L, this ); // -0 | +1 -> +1 // Register all functions in the array into the table on the top of the stack // When nup (last parameter) is not zero, all functions are created sharing nup upvalues, // which must be previously pushed on the stack on top of the library table. // These values are popped from the stack after the registration. luaL_setfuncs( L, MetaMethods, 1 ); // -1 | +0 -> -1 // luaL_setfuncs() does the following for every function in the list: //lua_pushstring( L, FuncName ); //lua_pushlightuserdata( L, this ); //lua_pushcclosure( L, Function, 1 ); //lua_settable( L, -3 ); // Protect metatable from tampering in the script // If __metatable field is set, then getmetatable() function returns // what is stored in this field instead of the actual metatable // and setmetatable() is not allowed to access it lua_pushliteral( L, "__metatable" ); // -0 | +1 -> +1 lua_pushliteral( L, "Metatable is not accessible!" ); // -0 | +1 -> +1 // Note that lua_settable() may trigger a metamethod // for the "newindex" event lua_settable( L, -3 ); // -2 | +0 -> -2 // Pop metatable lua_pop( L, 1 ); // -1 | +0 -> -1 CHECK_LUA_STACK_HEIGHT(); luaL_Reg Methods[] = { { "Create", LuaCreate }, { NULL, NULL } }; // Create a new table with a size optimized to store all entries in the array Methods // (but does not actually store them). luaL_newlibtable( L, Methods ); // -0 | +1 -> +1 // Push pointer onto the stack lua_pushlightuserdata( L, this ); // -0 | +1 -> +1 // Register all functions in the array into the table on the top of the stack // When nup (last parameter) is not zero, all functions are created sharing nup upvalues, // which must be previously pushed on the stack on top of the library table. // These values are popped from the stack after the registration. luaL_setfuncs( L, Methods, 1 ); // -1 | +0 -> -1 // Pop a value from the stack and set it as the new value of global name. lua_setglobal( L, m_LibName.c_str() ); // -1 | +0 -> -1 CHECK_LUA_STACK_HEIGHT(); }