+const Block *Scene::find_root_input_block(lua_State *L, const Block *block)
+{
+ if (block->is_input) {
+ assert(block->inputs.size() == 0);
+ return block;
+ }
+
+ const Block *ret = nullptr;
+ for (size_t input_idx : block->inputs) {
+ const Block *parent = find_root_input_block(L, blocks[input_idx]);
+ if (parent != nullptr) {
+ if (ret != nullptr) {
+ luaL_error(L, "add_auto_white_balance() was connected to more than one input");
+ }
+ ret = parent;
+ }
+ }
+ return ret;
+}
+
+int Scene::add_auto_white_balance(lua_State* L)
+{
+ assert(lua_gettop(L) >= 1);
+ Scene *scene = (Scene *)luaL_checkudata(L, 1, "Scene");
+
+ Block *block = new Block;
+ block->declaration_point = get_declaration_point(L);
+ block->idx = scene->blocks.size();
+
+ block->alternatives.push_back(new EffectBlueprint(WHITE_BALANCE_EFFECT));
+ block->alternatives.push_back(new EffectBlueprint(IDENTITY_EFFECT));
+
+ block->canonical_alternative = 1;
+
+ find_inputs_for_block(L, scene, block, /*first_input_idx=*/2);
+
+ if (block->inputs.size() != 1) {
+ luaL_error(L, "add_auto_white_balance() needs exactly one input");
+ }
+ block->root_input_block = scene->find_root_input_block(L, block);
+ if (block->root_input_block == nullptr) {
+ luaL_error(L, "add_auto_white_balance() was not connected to an input");
+ }
+
+ scene->blocks.push_back(block);
+
+ return wrap_lua_existing_object_nonowned<Block>(L, "Block", block);
+}
+