diff --git a/korman/operators/__init__.py b/korman/operators/__init__.py index 3e35852..ef4e5c4 100644 --- a/korman/operators/__init__.py +++ b/korman/operators/__init__.py @@ -17,6 +17,7 @@ from . import op_export as exporter from . import op_lightmap as lightmap from . import op_modifier as modifier from . import op_nodes as nodes +from . import op_sound as sound from . import op_texture as texture from . import op_toolbox as toolbox from . import op_world as world diff --git a/korman/operators/op_sound.py b/korman/operators/op_sound.py new file mode 100644 index 0000000..44b6adc --- /dev/null +++ b/korman/operators/op_sound.py @@ -0,0 +1,88 @@ +# This file is part of Korman. +# +# Korman is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Korman is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Korman. If not, see . + +import bpy +from bpy.props import * + +class SoundOperator: + @classmethod + def poll(cls, context): + return context.scene.render.engine == "PLASMA_GAME" + + +class PlasmaSoundOpenOperator(SoundOperator, bpy.types.Operator): + bl_idname = "sound.plasma_open" + bl_label = "Load Sound" + bl_options = {"INTERNAL"} + + filter_glob = StringProperty(default="*.ogg;*.wav", options={"HIDDEN"}) + filepath = StringProperty(subtype="FILE_PATH") + + data_path = StringProperty(options={"HIDDEN"}) + sound_property = StringProperty(options={"HIDDEN"}) + + def execute(self, context): + # Check to see if the sound exists... Because the sneakily introduced bpy.data.sounds.load + # check_existing doesn't tell us if it already exists... dammit... + # We don't want to take ownership forcefully if we don't have to. + for i in bpy.data.sounds: + if self.filepath == i.filepath: + sound = i + break + else: + sound = bpy.data.sounds.load(self.filepath) + sound.plasma_owned = True + sound.use_fake_user = True + + # Now do the stanky leg^H^H^H^H^H^H^H^H^H^H deed and put the sound on the mod + dest = eval(self.data_path) + setattr(dest, self.sound_property, sound.name) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + + +class PlasmaSoundPackOperator(SoundOperator, bpy.types.Operator): + bl_idname = "sound.plasma_pack" + bl_label = "Pack" + bl_options = {"INTERNAL"} + + def execute(self, context): + soundemit = context.active_object.plasma_modifiers.soundemit + sound = bpy.data.sounds.get(soundemit.sounds[soundemit.active_sound_index].sound_data) + sound.pack() + return {"FINISHED"} + + +class PlasmaSoundUnpackOperator(SoundOperator, bpy.types.Operator): + bl_idname = "sound.plasma_unpack" + bl_label = "Unpack" + bl_options = {"INTERNAL"} + + method = EnumProperty(name="Method", description="How to unpack", + # See blender/makesrna/intern/rna_packedfile.c + items=[("USE_LOCAL", "Use local file", "", 5), + ("WRITE_LOCAL", "Write Local File (overwrite existing)", "", 4), + ("USE_ORIGINAL", "Use Original File", "", 6), + ("WRITE_ORIGINAL", "Write Original File (overwrite existing)", "", 3)], + options=set()) + + def execute(self, context): + soundemit = context.active_object.plasma_modifiers.soundemit + sound = bpy.data.sounds.get(soundemit.sounds[soundemit.active_sound_index].sound_data) + sound.unpack(self.method) + return {"FINISHED"} diff --git a/korman/properties/modifiers/__init__.py b/korman/properties/modifiers/__init__.py index 6223ac8..938e333 100644 --- a/korman/properties/modifiers/__init__.py +++ b/korman/properties/modifiers/__init__.py @@ -22,6 +22,7 @@ from .logic import * from .physics import * from .region import * from .render import * +from .sound import * from .water import * class PlasmaModifiers(bpy.types.PropertyGroup): diff --git a/korman/properties/modifiers/sound.py b/korman/properties/modifiers/sound.py new file mode 100644 index 0000000..b315f91 --- /dev/null +++ b/korman/properties/modifiers/sound.py @@ -0,0 +1,64 @@ +# This file is part of Korman. +# +# Korman is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Korman is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Korman. If not, see . + +import bpy +from bpy.props import * +from bpy.app.handlers import persistent +from PyHSPlasma import * + +from .base import PlasmaModifierProperties +from ...exporter import ExportError + +class PlasmaSound(bpy.types.PropertyGroup): + enabled = BoolProperty(name="Enabled", default=True, options=set()) + sound_data = StringProperty(name="Sound", description="Sound Datablock", options=set()) + + +class PlasmaSoundEmitter(PlasmaModifierProperties): + pl_id = "soundemit" + + bl_category = "Logic" + bl_label = "Sound Emitter" + bl_description = "Point at which sound(s) are played" + bl_icon = "SPEAKER" + + sounds = CollectionProperty(type=PlasmaSound) + active_sound_index = IntProperty(options={"HIDDEN"}) + + def export(self, exporter, bo, so): + pass + + @classmethod + def register(cls): + bpy.types.Sound.plasma_owned = BoolProperty(default=False, options={"HIDDEN"}) + + @property + def requires_actor(self): + return True + + +@persistent +def _toss_orphaned_sounds(scene): + used_sounds = set() + for i in bpy.data.objects: + soundemit = i.plasma_modifiers.soundemit + used_sounds.update((j.sound_data for j in soundemit.sounds)) + for i in bpy.data.sounds: + if i.plasma_owned and i.name not in used_sounds: + i.use_fake_user = False + i.user_clear() + +# collects orphaned Plasma owned sound datablocks +bpy.app.handlers.save_pre.append(_toss_orphaned_sounds) diff --git a/korman/ui/modifiers/__init__.py b/korman/ui/modifiers/__init__.py index 5cf2fe7..ffbf492 100644 --- a/korman/ui/modifiers/__init__.py +++ b/korman/ui/modifiers/__init__.py @@ -19,4 +19,5 @@ from .logic import * from .physics import * from .region import * from .render import * +from .sound import * from .water import * diff --git a/korman/ui/modifiers/sound.py b/korman/ui/modifiers/sound.py new file mode 100644 index 0000000..feabe39 --- /dev/null +++ b/korman/ui/modifiers/sound.py @@ -0,0 +1,60 @@ +# This file is part of Korman. +# +# Korman is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Korman is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Korman. If not, see . + +import bpy + +class SoundListUI(bpy.types.UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_property, index=0, flt_flag=0): + if item.sound_data: + sound = bpy.data.sounds.get(item.sound_data) + icon = "SOUND" if sound is not None else "ERROR" + layout.prop(item, "sound_data", emboss=False, icon=icon, text="") + layout.prop(item, "enabled", text="") + else: + layout.label("[Empty]") + + +def soundemit(modifier, layout, context): + row = layout.row() + row.template_list("SoundListUI", "sounds", modifier, "sounds", modifier, "active_sound_index", + rows=2, maxrows=3) + col = row.column(align=True) + op = col.operator("object.plasma_modifier_collection_add", icon="ZOOMIN", text="") + op.modifier = modifier.pl_id + op.collection = "sounds" + op = col.operator("object.plasma_modifier_collection_remove", icon="ZOOMOUT", text="") + op.modifier = modifier.pl_id + op.collection = "sounds" + op.index = modifier.active_sound_index + + try: + sound = modifier.sounds[modifier.active_sound_index] + except: + pass + else: + # Sound datablock picker + row = layout.row(align=True) + row.prop_search(sound, "sound_data", bpy.data, "sounds", text="") + open_op = row.operator("sound.plasma_open", icon="FILESEL", text="") + open_op.data_path = repr(sound) + open_op.sound_property = "sound_data" + + # Pack/Unpack + data = bpy.data.sounds.get(sound.sound_data) + if data is not None: + if data.packed_file is None: + row.operator("sound.plasma_pack", icon="UGLYPACKAGE", text="") + else: + row.operator_menu_enum("sound.plasma_unpack", "method", icon="PACKAGE", text="")