Browse Source

Allow programatically enabling/disabling Plasma Modifiers.

Previously, this functionality was implemented in context-dependent operators. Considering that Korman is becoming increasingly complex and is now generating entirely new objects (potentially with modifiers) as part of its export process, it was becoming cumbersome to use those operators.
pull/374/head
Adam Johnson 1 year ago
parent
commit
76459cfccf
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 8
      korman/operators/op_mesh.py
  2. 91
      korman/operators/op_modifier.py
  3. 37
      korman/properties/modifiers/base.py
  4. 5
      korman/properties/modifiers/sound.py

8
korman/operators/op_mesh.py

@ -96,7 +96,7 @@ class PlasmaAddFlareOperator(PlasmaMeshOperator, bpy.types.Operator):
bpyscene.objects.active = flare_root bpyscene.objects.active = flare_root
# Enable VFM on Empty # Enable VFM on Empty
bpy.ops.object.plasma_modifier_add(types="viewfacemod") flare_root.plasma_modifiers.viewfacemod.enabled = True
flare_root.plasma_modifiers.viewfacemod.preset_options = "Sprite" flare_root.plasma_modifiers.viewfacemod.preset_options = "Sprite"
# Create a textured Plane # Create a textured Plane
@ -416,8 +416,8 @@ class PlasmaAddLadderMeshOperator(PlasmaMeshOperator, bpy.types.Operator):
origin_to_bottom(upper_rgn) origin_to_bottom(upper_rgn)
upper_rgn.rotation_euler[2] = math.radians(90.0) upper_rgn.rotation_euler[2] = math.radians(90.0)
bpy.ops.object.plasma_modifier_add(types="laddermod")
laddermod = upper_rgn.plasma_modifiers.laddermod laddermod = upper_rgn.plasma_modifiers.laddermod
laddermod.enabled = True
laddermod.is_enabled = self.lower_entry_enabled laddermod.is_enabled = self.lower_entry_enabled
laddermod.num_loops = (self.ladder_height - 6) / 2 laddermod.num_loops = (self.ladder_height - 6) / 2
laddermod.direction = "DOWN" laddermod.direction = "DOWN"
@ -457,8 +457,8 @@ class PlasmaAddLadderMeshOperator(PlasmaMeshOperator, bpy.types.Operator):
origin_to_bottom(lower_rgn) origin_to_bottom(lower_rgn)
lower_rgn.rotation_euler[2] = math.radians(-90.0) lower_rgn.rotation_euler[2] = math.radians(-90.0)
bpy.ops.object.plasma_modifier_add(types="laddermod")
laddermod = lower_rgn.plasma_modifiers.laddermod laddermod = lower_rgn.plasma_modifiers.laddermod
laddermod.enabled = True
laddermod.is_enabled = self.lower_entry_enabled laddermod.is_enabled = self.lower_entry_enabled
laddermod.num_loops = (self.ladder_height - 6) / 2 laddermod.num_loops = (self.ladder_height - 6) / 2
laddermod.direction = "UP" laddermod.direction = "UP"
@ -604,8 +604,8 @@ class PlasmaAddLinkingBookMeshOperator(PlasmaMeshOperator, bpy.types.Operator):
# Add Linking Book modifier # Add Linking Book modifier
bpyscene.objects.active = panel_root bpyscene.objects.active = panel_root
panel_root.select = True panel_root.select = True
bpy.ops.object.plasma_modifier_add(types="linkingbookmod")
lbmod = panel_root.plasma_modifiers.linkingbookmod lbmod = panel_root.plasma_modifiers.linkingbookmod
lbmod.enabled = True
lbmod.clickable_region = clk_rgn lbmod.clickable_region = clk_rgn
lbmod.seek_point = seek_point lbmod.seek_point = seek_point
lbmod.anim_type = self.link_anim_type lbmod.anim_type = self.link_anim_type

91
korman/operators/op_modifier.py

@ -13,11 +13,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>. # along with Korman. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy import bpy
from bpy.props import * from bpy.props import *
import itertools
import time import time
from typing import *
from ..ordered_set import OrderedSet
from ..properties import modifiers from ..properties import modifiers
def _fetch_modifiers(): def _fetch_modifiers():
@ -32,7 +36,7 @@ def _fetch_modifiers():
return items return items
class ModifierOperator: class ModifierOperator:
def _get_modifier(self, context): def _get_modifier(self, context) -> modifiers.PlasmaModifierProperties:
if self.active_modifier == -1: if self.active_modifier == -1:
return None return None
pl_mods = context.object.plasma_modifiers.modifiers pl_mods = context.object.plasma_modifiers.modifiers
@ -51,24 +55,16 @@ class ModifierAddOperator(ModifierOperator, bpy.types.Operator):
bl_label = "Add Modifier" bl_label = "Add Modifier"
bl_description = "Adds a Plasma Modifier" bl_description = "Adds a Plasma Modifier"
types = EnumProperty(name="Modifier Type", types = EnumProperty(
name="Modifier Type",
description="The type of modifier we add to the list", description="The type of modifier we add to the list",
items=_fetch_modifiers()) items=_fetch_modifiers()
)
def execute(self, context): def execute(self, context):
plmods = context.object.plasma_modifiers modifier = getattr(context.object.plasma_modifiers, self.types)
myType = self.types modifier.enabled = True
theMod = getattr(plmods, myType)
theMod.display_order = plmods.determine_next_id()
theMod.created()
# Determine if this modifier has any dependencies and make sure they're enabled
deps = getattr(theMod, "pl_depends", set())
for dep in deps:
depMod = getattr(plmods, dep)
if not depMod.enabled:
bpy.ops.object.plasma_modifier_add(types=dep)
return {"FINISHED"} return {"FINISHED"}
@ -195,61 +191,36 @@ class ModifierRemoveOperator(ModifierOperator, bpy.types.Operator):
bl_label = "Remove Modifier" bl_label = "Remove Modifier"
bl_description = "Removes this Plasma Modifier" bl_description = "Removes this Plasma Modifier"
active_modifier = IntProperty(name="Modifier Display Order", active_modifier = IntProperty(
name="Modifier Display Order",
default=-1, default=-1,
options={"HIDDEN"}) options={"HIDDEN"}
)
mods2delete = CollectionProperty(type=modifiers.PlasmaModifierSpec, options=set())
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
mods = context.object.plasma_modifiers pl_mods = context.object.plasma_modifiers
mod = self._get_modifier(context)
mods_to_delete = itertools.chain(
(getattr(pl_mods, i) for i in mod.get_dependents()),
[mod]
)
layout.label("This action will remove the following modifiers:") layout.label("This action will remove the following modifiers:")
layout = layout.column_flow(align=True) layout = layout.column_flow(align=True)
for i in self.mods2delete: for mod in filter(lambda x: x.enabled, mods_to_delete):
mod = getattr(mods, i.name) layout.label(f" {mod.bl_label}", icon=getattr(mod, "bl_icon", "NONE"))
layout.label(" {}".format(mod.bl_label), icon=getattr(mod, "bl_icon", "NONE"))
def execute(self, context): def execute(self, context):
want2delete = set((i.name for i in self.mods2delete)) self._get_modifier(context).enabled = False
mods = sorted(context.object.plasma_modifiers.modifiers, key=lambda x: x.display_order)
subtract = 0
for mod in mods:
if mod.pl_id in want2delete:
mod.display_order = -1
mod.destroyed()
subtract += 1
else:
mod.display_order -= subtract
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event): def invoke(self, context, event):
mods = context.object.plasma_modifiers has_dependents = any(
self.mods2delete.clear() getattr(context.object.plasma_modifiers, i).enabled
for i in self._get_modifier(context).get_dependents()
want2delete = OrderedSet() )
if self.active_modifier == -1: if not has_dependents:
want2delete.update((i.pl_id for i in context.object.plasma_modifiers.modifiers))
else:
want2delete.add(self._get_modifier(context).pl_id)
# Here's the rub
# When we start, we should have just one modifier in want2delete
# HOWEVER, the mod may have dependencies, which in turn may have more deps
# So we collect them into the list... you dig?
for i in want2delete:
for mod in modifiers.PlasmaModifierProperties.__subclasses__():
if not getattr(mods, mod.pl_id).enabled:
continue
if i in getattr(mod, "pl_depends", set()):
want2delete.add(mod.pl_id)
for i in want2delete:
mod = self.mods2delete.add()
mod.name = i
if len(want2delete) == 1:
return self.execute(context) return self.execute(context)
else: else:
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)

37
korman/properties/modifiers/base.py

@ -17,7 +17,8 @@ import bpy
from bpy.props import * from bpy.props import *
import abc import abc
from typing import Any, Dict, Generator, Optional import itertools
from typing import Any, Dict, FrozenSet, Optional
class PlasmaModifierProperties(bpy.types.PropertyGroup): class PlasmaModifierProperties(bpy.types.PropertyGroup):
@property @property
@ -51,9 +52,31 @@ class PlasmaModifierProperties(bpy.types.PropertyGroup):
return False return False
@property @property
def enabled(self): def enabled(self) -> bool:
return self.display_order >= 0 return self.display_order >= 0
@enabled.setter
def enabled(self, value: bool) -> None:
plmods = self.id_data.plasma_modifiers
if value and self.enabled is False:
self.display_order = plmods.determine_next_id()
self.created()
# Determine if this modifier has any dependencies and make sure they're enabled
for dep in getattr(self, "pl_depends", set()):
getattr(plmods, dep).enabled = True
elif not value and self.enabled is True:
mods_to_delete = frozenset(itertools.chain([self.pl_id], self.get_dependents()))
enabled_mods = sorted(self.id_data.plasma_modifiers.modifiers, key=lambda x: x.display_order)
subtract = 0
for modifier in enabled_mods:
if modifier.pl_id in mods_to_delete:
modifier.display_order = -1
modifier.destroyed()
subtract += 1
else:
modifier.display_order -= subtract
def export(self, exporter, bo, so): def export(self, exporter, bo, so):
"""This is the main phase of the modifier export where most, if not all, PRP objects should """This is the main phase of the modifier export where most, if not all, PRP objects should
be generated. No new Blender objects should be created unless their lifespan is constrained be generated. No new Blender objects should be created unless their lifespan is constrained
@ -75,6 +98,16 @@ class PlasmaModifierProperties(bpy.types.PropertyGroup):
"""Indicates that the geometry's faces should be sorted by the engine""" """Indicates that the geometry's faces should be sorted by the engine"""
return False return False
@classmethod
def get_dependents(cls) -> FrozenSet[str]:
"""Returns the set of modifiers that depend on this modifier being active."""
deps = set()
for i in PlasmaModifierProperties.__subclasses__():
if cls.pl_id in getattr(i, "pl_depends", []):
deps.add(i.pl_id)
deps.update(i.get_dependents())
return frozenset(deps)
def harvest_actors(self): def harvest_actors(self):
return () return ()

5
korman/properties/modifiers/sound.py

@ -556,8 +556,7 @@ class PlasmaSoundEmitter(PlasmaModifierProperties):
emitter_obj.plasma_modifiers.modifiers emitter_obj.plasma_modifiers.modifiers
) )
for i in bad_mods: for i in bad_mods:
# HACK: You can't set the enabled property. i.enabled = False
i.display_order = -1
# But only 3D stereo sounds! # But only 3D stereo sounds!
soundemit_mod = emitter_obj.plasma_modifiers.soundemit soundemit_mod = emitter_obj.plasma_modifiers.soundemit
@ -630,7 +629,7 @@ class PlasmaSoundEmitter(PlasmaModifierProperties):
if not my_anim_groups: if not my_anim_groups:
group = bo.plasma_modifiers.animation_group group = bo.plasma_modifiers.animation_group
if not group.enabled: if not group.enabled:
toggle.track(group, "display_order", sum((1 for i in bo.plasma_modifiers.modifiers))) toggle.track(group, "enabled", True)
for i in group.children: for i in group.children:
toggle.track(i, "enabled", False) toggle.track(i, "enabled", False)
my_anim_groups.append(group) my_anim_groups.append(group)

Loading…
Cancel
Save