X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Ftheme.cpp;h=fb1fa2fd7380c5422fc00dba6eb221dccc350f8c;hb=337e2d06624b4b46eb2e7e5365e2ece219f9f100;hp=71a59a24525a8c123da024212e40d9395f5d1769;hpb=021fa9fa5ce103ae5843647fee3d5d1d7038d32f;p=nageru diff --git a/nageru/theme.cpp b/nageru/theme.cpp index 71a59a2..fb1fa2f 100644 --- a/nageru/theme.cpp +++ b/nageru/theme.cpp @@ -39,6 +39,7 @@ #include "input_state.h" #include "lua_utils.h" #include "pbo_frame_allocator.h" +#include "scene.h" class Mixer; @@ -77,21 +78,6 @@ int ThemeMenu_set(lua_State *L) return theme->set_theme_menu(L); } -namespace { - -// Contains basically the same data as InputState, but does not hold on to -// a reference to the frames. This is important so that we can release them -// without having to wait for Lua's GC. -struct InputStateInfo { - InputStateInfo(const InputState& input_state); - - unsigned last_width[MAX_VIDEO_CARDS], last_height[MAX_VIDEO_CARDS]; - bool last_interlaced[MAX_VIDEO_CARDS], last_has_signal[MAX_VIDEO_CARDS], last_is_connected[MAX_VIDEO_CARDS]; - unsigned last_frame_rate_nom[MAX_VIDEO_CARDS], last_frame_rate_den[MAX_VIDEO_CARDS]; - bool has_last_subtitle[MAX_VIDEO_CARDS]; - std::string last_subtitle[MAX_VIDEO_CARDS]; -}; - InputStateInfo::InputStateInfo(const InputState &input_state) { for (unsigned signal_num = 0; signal_num < MAX_VIDEO_CARDS; ++signal_num) { @@ -116,21 +102,19 @@ InputStateInfo::InputStateInfo(const InputState &input_state) } } -enum EffectType { - WHITE_BALANCE_EFFECT, - RESAMPLE_EFFECT, - PADDING_EFFECT, - INTEGRAL_PADDING_EFFECT, - OVERLAY_EFFECT, - RESIZE_EFFECT, - MULTIPLY_EFFECT, - MIX_EFFECT, - LIFT_GAMMA_GAIN_EFFECT +// An effect that does nothing. +class IdentityEffect : public Effect { +public: + IdentityEffect() {} + string effect_type_id() const override { return "IdentityEffect"; } + string output_fragment_shader() override { return read_file("identity.frag"); } }; Effect *instantiate_effect(EffectChain *chain, EffectType effect_type) { switch (effect_type) { + case IDENTITY_EFFECT: + return new IdentityEffect; case WHITE_BALANCE_EFFECT: return new WhiteBalanceEffect; case RESAMPLE_EFFECT: @@ -155,27 +139,12 @@ Effect *instantiate_effect(EffectChain *chain, EffectType effect_type) } } -// An EffectBlueprint refers to an Effect before it's being added to the graph. -// It contains enough information to instantiate the effect, including any -// parameters that were set before it was added to the graph. Once it is -// instantiated, it forwards its calls on to the real Effect instead. -struct EffectBlueprint { - EffectBlueprint(EffectType effect_type) : effect_type(effect_type) {} - - EffectType effect_type; - map int_parameters; - map float_parameters; - map> vec3_parameters; - map> vec4_parameters; - - Effect *effect = nullptr; // Gets filled out when it's instantiated. -}; +namespace { Effect *get_effect_from_blueprint(EffectChain *chain, lua_State *L, int idx) { EffectBlueprint *blueprint = *(EffectBlueprint **)luaL_checkudata(L, idx, "EffectBlueprint"); if (blueprint->effect != nullptr) { - // NOTE: This will change in the future. luaL_error(L, "An effect can currently only be added to one chain.\n"); } @@ -217,6 +186,8 @@ InputStateInfo *get_input_state_info(lua_State *L, int idx) return nullptr; } +} // namespace + bool checkbool(lua_State* L, int idx) { luaL_checktype(L, idx, LUA_TBOOLEAN); @@ -230,6 +201,28 @@ string checkstdstring(lua_State *L, int index) return string(cstr, len); } +namespace { + +int Scene_new(lua_State* L) +{ + assert(lua_gettop(L) == 2); + Theme *theme = get_theme_updata(L); + int aspect_w = luaL_checknumber(L, 1); + int aspect_h = luaL_checknumber(L, 2); + + return wrap_lua_object(L, "Scene", theme, aspect_w, aspect_h); +} + +int Scene_gc(lua_State* L) +{ + assert(lua_gettop(L) == 1); + Scene *chain = (Scene *)luaL_checkudata(L, 1, "Scene"); + chain->~Scene(); + return 0; +} + +} // namespace + void add_outputs_and_finalize(EffectChain *chain, bool is_main_chain) { // Add outputs as needed. @@ -281,6 +274,8 @@ void add_outputs_and_finalize(EffectChain *chain, bool is_main_chain) chain->finalize(); } +namespace { + int EffectChain_new(lua_State* L) { assert(lua_gettop(L) == 2); @@ -560,6 +555,12 @@ int HTMLInput_get_signal_num(lua_State* L) } #endif +int IdentityEffect_new(lua_State* L) +{ + assert(lua_gettop(L) == 0); + return wrap_lua_object_nonowned(L, "EffectBlueprint", IDENTITY_EFFECT); +} + int WhiteBalanceEffect_new(lua_State* L) { assert(lua_gettop(L) == 0); @@ -618,6 +619,7 @@ int InputStateInfo_get_width(lua_State* L) { assert(lua_gettop(L) == 2); InputStateInfo *input_state_info = get_input_state_info(L, 1); + Theme *theme = get_theme_updata(L); int signal_num = theme->map_signal(luaL_checknumber(L, 2)); lua_pushnumber(L, input_state_info->last_width[signal_num]); @@ -777,6 +779,28 @@ int EffectBlueprint_set_vec4(lua_State *L) return 0; } +const luaL_Reg Scene_funcs[] = { + { "new", Scene_new }, + { "__gc", Scene_gc }, + { "add_input", Scene::add_input }, + { "add_effect", Scene::add_effect }, + { "add_optional_effect", Scene::add_optional_effect }, + { "finalize", Scene::finalize }, + { NULL, NULL } +}; + +const luaL_Reg Block_funcs[] = { + { "display", Block_display }, + { "choose_alternative", Block_choose_alternative }, + { "enable", Block_enable }, + { "disable", Block_disable }, + { "set_int", Block_set_int }, + { "set_float", Block_set_float }, + { "set_vec3", Block_set_vec3 }, + { "set_vec4", Block_set_vec4 }, + { NULL, NULL } +}; + const luaL_Reg EffectBlueprint_funcs[] = { // NOTE: No new() function; that's for the individual effects. { "set_int", EffectBlueprint_set_int }, @@ -835,6 +859,11 @@ const luaL_Reg HTMLInput_funcs[] = { // All of these are solely for new(); the returned metatable will be that of // EffectBlueprint, and Effect (returned from add_effect()) is its own type. +const luaL_Reg IdentityEffect_funcs[] = { + { "new", IdentityEffect_new }, + { NULL, NULL } +}; + const luaL_Reg WhiteBalanceEffect_funcs[] = { { "new", WhiteBalanceEffect_new }, { NULL, NULL } @@ -1200,12 +1229,15 @@ Theme::Theme(const string &filename, const vector &search_dirs, Resource // Set up the API we provide. register_constants(); + register_class("Scene", Scene_funcs); + register_class("Block", Block_funcs); register_class("EffectBlueprint", EffectBlueprint_funcs); register_class("EffectChain", EffectChain_funcs); register_class("LiveInputWrapper", LiveInputWrapper_funcs); register_class("ImageInput", ImageInput_funcs); register_class("VideoInput", VideoInput_funcs); register_class("HTMLInput", HTMLInput_funcs); + register_class("IdentityEffect", IdentityEffect_funcs); register_class("WhiteBalanceEffect", WhiteBalanceEffect_funcs); register_class("ResampleEffect", ResampleEffect_funcs); register_class("PaddingEffect", PaddingEffect_funcs); @@ -1276,31 +1308,8 @@ void Theme::register_class(const char *class_name, const luaL_Reg *funcs) assert(lua_gettop(L) == 0); } -Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned height, const InputState &input_state) +Theme::Chain Theme::get_chain_from_effect_chain(EffectChain *effect_chain, unsigned num, const InputState &input_state) { - Chain chain; - - lock_guard lock(m); - assert(lua_gettop(L) == 0); - lua_getglobal(L, "get_chain"); /* function to be called */ - lua_pushnumber(L, num); - lua_pushnumber(L, t); - lua_pushnumber(L, width); - lua_pushnumber(L, height); - wrap_lua_object(L, "InputStateInfo", input_state); - - if (lua_pcall(L, 5, 2, 0) != 0) { - fprintf(stderr, "error running function `get_chain': %s\n", lua_tostring(L, -1)); - abort(); - } - - EffectChain *effect_chain = (EffectChain *)luaL_testudata(L, -2, "EffectChain"); - if (effect_chain == nullptr) { - fprintf(stderr, "get_chain() for chain number %d did not return an EffectChain\n", - num); - abort(); - } - chain.chain = effect_chain; if (!lua_isfunction(L, -1)) { fprintf(stderr, "Argument #-1 should be a function\n"); abort(); @@ -1308,8 +1317,9 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he lua_pushvalue(L, -1); shared_ptr funcref(new LuaRefWithDeleter(&m, L, luaL_ref(L, LUA_REGISTRYINDEX))); lua_pop(L, 2); - assert(lua_gettop(L) == 0); + Chain chain; + chain.chain = effect_chain; chain.setup_chain = [this, funcref, input_state, effect_chain]{ lock_guard lock(m); @@ -1341,6 +1351,53 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he this->input_state = nullptr; }; + return chain; +} + +Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned height, const InputState &input_state) +{ + const char *func_name = "get_scene"; // For error reporting. + Chain chain; + + lock_guard lock(m); + assert(lua_gettop(L) == 0); + lua_getglobal(L, "get_scene"); /* function to be called */ + if (lua_isnil(L, -1)) { + // Try the pre-1.9.0 name for compatibility. + lua_pop(L, 1); + lua_getglobal(L, "get_chain"); + func_name = "get_chain"; + } + lua_pushnumber(L, num); + lua_pushnumber(L, t); + lua_pushnumber(L, width); + lua_pushnumber(L, height); + wrap_lua_object(L, "InputStateInfo", input_state); + + if (lua_pcall(L, 5, LUA_MULTRET, 0) != 0) { + fprintf(stderr, "error running function “%s”: %s\n", func_name, lua_tostring(L, -1)); + abort(); + } + + if (luaL_testudata(L, -1, "Scene") != nullptr) { + if (lua_gettop(L) != 1) { + luaL_error(L, "%s() for chain number %d returned an Scene, but also other items", func_name); + } + Scene *auto_effect_chain = (Scene *)luaL_testudata(L, -1, "Scene"); + auto chain_and_setup = auto_effect_chain->get_chain(this, L, num, input_state); + chain.chain = chain_and_setup.first; + chain.setup_chain = move(chain_and_setup.second); + } else if (luaL_testudata(L, -2, "EffectChain") != nullptr) { + // Old-style (pre-Nageru 1.9.0) return of a single chain and prepare function. + if (lua_gettop(L) != 2) { + luaL_error(L, "%s() for chain number %d returned an EffectChain, but needs to also return a prepare function (or use Scene)", func_name); + } + EffectChain *effect_chain = (EffectChain *)luaL_testudata(L, -2, "EffectChain"); + chain = get_chain_from_effect_chain(effect_chain, num, input_state); + } else { + luaL_error(L, "%s() for chain number %d did not return an EffectChain or Scene\n", func_name, num); + } + assert(lua_gettop(L) == 0); // TODO: Can we do better, e.g. by running setup_chain() and seeing what it references? // Actually, setup_chain does maybe hold all the references we need now anyway?