Browse Source

Implement material diffuse animations.

Closes #188.
pull/236/head
Adam Johnson 4 years ago
parent
commit
763b086b9c
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 92
      korman/exporter/material.py

92
korman/exporter/material.py

@ -16,8 +16,10 @@
import bpy import bpy
import functools import functools
import math import math
import mathutils
from pathlib import Path from pathlib import Path
from PyHSPlasma import * from PyHSPlasma import *
from typing import Union
import weakref import weakref
from .explosions import * from .explosions import *
@ -143,7 +145,10 @@ class MaterialConverter:
"NONE": self._export_texture_type_none, "NONE": self._export_texture_type_none,
} }
self._animation_exporters = { self._animation_exporters = {
"ambientCtl": functools.partial(self._export_layer_diffuse_animation, converter=self.get_material_ambient),
"opacityCtl": self._export_layer_opacity_animation, "opacityCtl": self._export_layer_opacity_animation,
"preshadeCtl": functools.partial(self._export_layer_diffuse_animation, converter=self.get_material_preshade),
"runtimeCtl": functools.partial(self._export_layer_diffuse_animation, converter=self.get_material_runtime),
"transformCtl": self._export_layer_transform_animation, "transformCtl": self._export_layer_transform_animation,
} }
@ -254,6 +259,7 @@ class MaterialConverter:
if not hsgmat.layers: if not hsgmat.layers:
layer = self._mgr.find_create_object(plLayer, name="{}_AutoLayer".format(mat_name), bl=bo) layer = self._mgr.find_create_object(plLayer, name="{}_AutoLayer".format(mat_name), bl=bo)
self._propagate_material_settings(bo, bm, layer) self._propagate_material_settings(bo, bm, layer)
layer = self._export_layer_animations(bo, bm, None, 0, layer)
hsgmat.addLayer(layer.key) hsgmat.addLayer(layer.key)
# Cache this material for later # Cache this material for later
@ -489,7 +495,7 @@ class MaterialConverter:
layer = self._export_layer_animations(bo, bm, slot, idx, layer) layer = self._export_layer_animations(bo, bm, slot, idx, layer)
return layer return layer
def _export_layer_animations(self, bo, bm, tex_slot, idx, base_layer): def _export_layer_animations(self, bo, bm, tex_slot, idx, base_layer) -> plLayer:
"""Exports animations on this texture and chains the Plasma layers as needed""" """Exports animations on this texture and chains the Plasma layers as needed"""
def harvest_fcurves(bl_id, collection, data_path=None): def harvest_fcurves(bl_id, collection, data_path=None):
@ -508,9 +514,16 @@ class MaterialConverter:
return None return None
fcurves = [] fcurves = []
texture = tex_slot.texture
mat_action = harvest_fcurves(bm, fcurves, "texture_slots[{}]".format(idx)) # Base layers get all of the fcurves for animating things like the diffuse color
tex_action = harvest_fcurves(texture, fcurves) texture = tex_slot.texture if tex_slot is not None else None
if idx == 0:
harvest_fcurves(bm, fcurves)
harvest_fcurves(texture, fcurves)
elif tex_slot is not None:
harvest_fcurves(bm, fcurves, tex_slot.path_from_id())
harvest_fcurves(texture, fcurves)
if not fcurves: if not fcurves:
return base_layer return base_layer
@ -518,7 +531,7 @@ class MaterialConverter:
# and chain this biotch up as best we can. # and chain this biotch up as best we can.
layer_animation = None layer_animation = None
for attr, converter in self._animation_exporters.items(): for attr, converter in self._animation_exporters.items():
ctrl = converter(tex_slot, base_layer, fcurves) ctrl = converter(bo, bm, tex_slot, base_layer, fcurves)
if ctrl is not None: if ctrl is not None:
if layer_animation is None: if layer_animation is None:
name = "{}_LayerAnim".format(base_layer.key.name) name = "{}_LayerAnim".format(base_layer.key.name)
@ -539,21 +552,39 @@ class MaterialConverter:
atc.begin = min((fcurve.range()[0] for fcurve in fcurves)) * (30.0 / fps) / fps atc.begin = min((fcurve.range()[0] for fcurve in fcurves)) * (30.0 / fps) / fps
atc.end = max((fcurve.range()[1] for fcurve in fcurves)) * (30.0 / fps) / fps atc.end = max((fcurve.range()[1] for fcurve in fcurves)) * (30.0 / fps) / fps
layer_props = tex_slot.texture.plasma_layer if tex_slot is not None:
if not layer_props.anim_auto_start: layer_props = tex_slot.texture.plasma_layer
atc.flags |= plAnimTimeConvert.kStopped if not layer_props.anim_auto_start:
if layer_props.anim_loop: atc.flags |= plAnimTimeConvert.kStopped
if layer_props.anim_loop:
atc.flags |= plAnimTimeConvert.kLoop
atc.loopBegin = atc.begin
atc.loopEnd = atc.end
if layer_props.anim_sdl_var:
layer_animation.varName = layer_props.anim_sdl_var
else:
# Hmm... I wonder what we should do here? A reasonable default might be to just
# run the stupid thing in a loop.
atc.flags |= plAnimTimeConvert.kLoop atc.flags |= plAnimTimeConvert.kLoop
atc.loopBegin = atc.begin atc.loopBegin = atc.begin
atc.loopEnd = atc.end atc.loopEnd = atc.end
if layer_props.anim_sdl_var:
layer_animation.varName = layer_props.anim_sdl_var
return layer_animation return layer_animation
# Well, we had some FCurves but they were garbage... Too bad. # Well, we had some FCurves but they were garbage... Too bad.
return base_layer return base_layer
def _export_layer_opacity_animation(self, tex_slot, base_layer, fcurves): def _export_layer_diffuse_animation(self, bo, bm, tex_slot, base_layer, fcurves, converter):
assert converter is not None
def translate_color(color_sequence):
# See things like get_material_preshade
result = converter(bo, bm, mathutils.Color(color_sequence))
return result.red, result.green, result.blue
ctrl = self._exporter().animation.make_pos_controller(fcurves, "diffuse_color", bm.diffuse_color, translate_color)
return ctrl
def _export_layer_opacity_animation(self, bo, bm, tex_slot, base_layer, fcurves):
for i in fcurves: for i in fcurves:
if i.data_path == "plasma_layer.opacity": if i.data_path == "plasma_layer.opacity":
base_layer.state.blendFlags |= hsGMatState.kBlendAlpha base_layer.state.blendFlags |= hsGMatState.kBlendAlpha
@ -561,14 +592,16 @@ class MaterialConverter:
return ctrl return ctrl
return None return None
def _export_layer_transform_animation(self, tex_slot, base_layer, fcurves): def _export_layer_transform_animation(self, bo, bm, tex_slot, base_layer, fcurves):
path = tex_slot.path_from_id() if tex_slot is not None:
pos_path = "{}.offset".format(path) path = tex_slot.path_from_id()
scale_path = "{}.scale".format(path) pos_path = "{}.offset".format(path)
scale_path = "{}.scale".format(path)
# Plasma uses the controller to generate a matrix44... so we have to produce a leaf controller # Plasma uses the controller to generate a matrix44... so we have to produce a leaf controller
ctrl = self._exporter().animation.make_matrix44_controller(fcurves, pos_path, scale_path, tex_slot.offset, tex_slot.scale) ctrl = self._exporter().animation.make_matrix44_controller(fcurves, pos_path, scale_path, tex_slot.offset, tex_slot.scale)
return ctrl return ctrl
return None
def _export_texture_type_environment_map(self, bo, layer, slot): def _export_texture_type_environment_map(self, bo, layer, slot):
"""Exports a Blender EnvironmentMapTexture to a plLayer""" """Exports a Blender EnvironmentMapTexture to a plLayer"""
@ -1164,24 +1197,26 @@ class MaterialConverter:
def get_bump_layer(self, bo): def get_bump_layer(self, bo):
return self._bump_mats.get(bo, None) return self._bump_mats.get(bo, None)
def get_material_ambient(self, bo, bm) -> hsColorRGBA: def get_material_ambient(self, bo, bm, color : Union[None, mathutils.Color]=None) -> hsColorRGBA:
emit_scale = bm.emit * 0.5 emit_scale = bm.emit * 0.5
if emit_scale > 0.0: if emit_scale > 0.0:
return hsColorRGBA(bm.diffuse_color.r * emit_scale, if color is None:
bm.diffuse_color.g * emit_scale, color = bm.diffuse_color
bm.diffuse_color.b * emit_scale, return hsColorRGBA(color.r * emit_scale,
color.g * emit_scale,
color.b * emit_scale,
1.0) 1.0)
else: else:
return utils.color(bpy.context.scene.world.ambient_color) return utils.color(bpy.context.scene.world.ambient_color)
def get_material_preshade(self, bo, bm, color=None) -> hsColorRGBA: def get_material_preshade(self, bo, bm, color : Union[None, mathutils.Color]=None) -> hsColorRGBA:
if bo.plasma_modifiers.lighting.rt_lights: if bo.plasma_modifiers.lighting.rt_lights:
return hsColorRGBA.kBlack return hsColorRGBA.kBlack
if color is None: if color is None:
color = bm.diffuse_color color = bm.diffuse_color
return utils.color(color) return utils.color(color)
def get_material_runtime(self, bo, bm, color=None) -> hsColorRGBA: def get_material_runtime(self, bo, bm, color : Union[None, mathutils.Color]=None) -> hsColorRGBA:
if not bo.plasma_modifiers.lighting.preshade: if not bo.plasma_modifiers.lighting.preshade:
return hsColorRGBA.kBlack return hsColorRGBA.kBlack
if color is None: if color is None:
@ -1191,19 +1226,18 @@ class MaterialConverter:
def get_texture_animation_key(self, bo, bm, texture): def get_texture_animation_key(self, bo, bm, texture):
"""Finds or creates the appropriate key for sending messages to an animated Texture""" """Finds or creates the appropriate key for sending messages to an animated Texture"""
tex_name = texture.name tex_name = texture.name if texture is not None else "AutoLayer"
if bo.type == "LAMP": if bo.type == "LAMP":
assert bm is None assert bm is None
bm_name = bo.name bm_name = bo.name
else: else:
assert bm is not None assert bm is not None
bm_name = bm.name bm_name = bm.name
if not tex_name in bm.texture_slots: if texture is not None and not tex_name in bm.texture_slots:
raise ExportError("Texture '{}' not used in Material '{}'".format(bm_name, tex_name)) raise ExportError("Texture '{}' not used in Material '{}'".format(bm_name, tex_name))
name = "{}_{}_LayerAnim".format(bm_name, tex_name) name = "{}_{}_LayerAnim".format(bm_name, tex_name)
layer = texture.plasma_layer pClass = plLayerSDLAnimation if texture is not None and texture.plasma_layer.anim_sdl_var else plLayerAnimation
pClass = plLayerSDLAnimation if layer.anim_sdl_var else plLayerAnimation
return self._mgr.find_create_key(pClass, bl=bo, name=name) return self._mgr.find_create_key(pClass, bl=bo, name=name)
@property @property

Loading…
Cancel
Save