X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Fscene.cpp;h=70bccbe1a73f11d31424654a630ef2d1600e21db;hb=c0763f1f26189bdc2ee487e38ccb7e8fe77fac25;hp=2612de639961e8336d3eb4a6a8d8f8fb1f5f842a;hpb=e4ebe67b6523038484df30d1d5fafc6055398acc;p=nageru diff --git a/nageru/scene.cpp b/nageru/scene.cpp index 2612de6..70bccbe 100644 --- a/nageru/scene.cpp +++ b/nageru/scene.cpp @@ -59,9 +59,9 @@ size_t Scene::compute_chain_number_for_block(size_t block_idx, const bitset<256> size_t currently_chosen_alternative; if (disabled.test(block_idx)) { - // It doesn't matter, so pick 0 as the canonical choice + // It doesn't matter, so pick the canonical choice // (this is the only one that is actually instantiated). - currently_chosen_alternative = 0; + currently_chosen_alternative = block->canonical_alternative; } else { currently_chosen_alternative = block->currently_chosen_alternative; } @@ -80,8 +80,27 @@ bitset<256> Scene::find_disabled_blocks(size_t chain_idx) const { assert(blocks.size() < 256); - bitset<256> ret; - find_disabled_blocks(chain_idx, blocks.size() - 1, /*currently_disabled=*/false, &ret); + // The find_disabled_blocks() recursion logic needs only one pass by itself, + // but the disabler logic is not so smart, so we just run multiple times + // until it converges. + bitset<256> prev, ret; + do { + find_disabled_blocks(chain_idx, blocks.size() - 1, /*currently_disabled=*/false, &ret); + prev = ret; + for (Block *block : blocks) { + EffectType chosen_type = block->alternatives[block->chosen_alternative(chain_idx)]->effect_type; + if (ret.test(block->idx) || chosen_type == IDENTITY_EFFECT) continue; // Already disabled. + + for (Block::Index disabler_idx : block->disablers) { + Block *disabler = blocks[disabler_idx]; + EffectType chosen_type = disabler->alternatives[disabler->chosen_alternative(chain_idx)]->effect_type; + if (ret.test(disabler->idx) || chosen_type == IDENTITY_EFFECT) { + ret.set(block->idx); + break; + } + } + } + } while (prev != ret); return ret; } @@ -113,7 +132,8 @@ bool Scene::is_noncanonical_chain(size_t chain_idx) const } assert(blocks.size() < 256); for (size_t block_idx = 0; block_idx < blocks.size(); ++block_idx) { - if (disabled.test(block_idx) && blocks[block_idx]->chosen_alternative(chain_idx) != 0) { + Block *block = blocks[block_idx]; + if (disabled.test(block_idx) && block->chosen_alternative(chain_idx) != block->canonical_alternative) { return true; } } @@ -217,6 +237,15 @@ int Scene::add_effect(lua_State* L) block->alternatives.push_back(blueprint); } + int identity_index = find_index_of(block, IDENTITY_EFFECT); + if (identity_index == -1) { + block->canonical_alternative = 0; + } else { + // Pick the IdentityEffect as the canonical alternative, in case it + // helps us disable more stuff. + block->canonical_alternative = identity_index; + } + find_inputs_for_block(L, scene, block); scene->blocks.push_back(block); @@ -237,6 +266,8 @@ int Scene::add_optional_effect(lua_State* L) // An IdentityEffect will be the alternative for when the effect is disabled. block->alternatives.push_back(new EffectBlueprint(IDENTITY_EFFECT)); + block->canonical_alternative = 1; + find_inputs_for_block(L, scene, block); scene->blocks.push_back(block); @@ -633,6 +664,27 @@ int Block_disable(lua_State *L) return 0; } +int Block_always_disable_if_disabled(lua_State *L) +{ + assert(lua_gettop(L) == 2); + Block *block = *(Block **)luaL_checkudata(L, 1, "Block"); + Block *disabler_block = *(Block **)luaL_checkudata(L, 2, "Block"); + + int my_alternative = find_index_of(block, IDENTITY_EFFECT); + int their_alternative = find_index_of(disabler_block, IDENTITY_EFFECT); + if (my_alternative == -1) { + luaL_error(L, "always_disable_if_disabled() called on something that didn't have an IdentityEffect fallback (try add_optional_effect())"); + } + if (their_alternative == -1) { + luaL_error(L, "always_disable_if_disabled() with an argument that didn't have an IdentityEffect fallback (try add_optional_effect())"); + } + + block->disablers.push_back(disabler_block->idx); + + lua_pop(L, 2); + return 0; +} + int Block_set_int(lua_State *L) { assert(lua_gettop(L) == 3);