Browse Source

Merge pull request #210 from Hoikas/render

DSpan Export Improvements
pull/218/head
Adam Johnson 4 years ago committed by GitHub
parent
commit
1a31eafe77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 55
      korman/exporter/material.py
  2. 220
      korman/exporter/mesh.py
  3. 3
      korman/idprops.py
  4. 4
      korman/properties/modifiers/__init__.py
  5. 20
      korman/properties/modifiers/base.py
  6. 94
      korman/properties/modifiers/render.py
  7. 30
      korman/ui/modifiers/render.py

55
korman/exporter/material.py

@ -187,7 +187,9 @@ class MaterialConverter:
self._report.msg("Exporting Material '{}' as single user '{}'", bm.name, mat_name, indent=1)
hgmat = None
else:
mat_name = bm.name
# Ensure that RT-lit objects don't infect the static-lit objects.
mat_prefix = "RTLit_" if bo.plasma_modifiers.lighting.rt_lights else ""
mat_name = "".join((mat_prefix, bm.name))
self._report.msg("Exporting Material '{}'", mat_name, indent=1)
hsgmat = self._mgr.find_key(hsGMaterial, name=mat_name, bl=bo)
if hsgmat is not None:
@ -222,7 +224,8 @@ class MaterialConverter:
if slot.use_stencil:
stencils.append((idx, slot))
else:
tex_layer = self.export_texture_slot(bo, bm, hsgmat, slot, idx)
tex_name = "{}_{}".format(mat_name, slot.name)
tex_layer = self.export_texture_slot(bo, bm, hsgmat, slot, idx, name=tex_name)
if restart_pass_next:
tex_layer.state.miscFlags |= hsGMatState.kMiscRestartPassHere
restart_pass_next = False
@ -249,7 +252,7 @@ class MaterialConverter:
# Plasma makes several assumptions that every hsGMaterial has at least one layer. If this
# material had no Textures, we will need to initialize a default layer
if not hsgmat.layers:
layer = self._mgr.find_create_object(plLayer, name="{}_AutoLayer".format(bm.name), bl=bo)
layer = self._mgr.find_create_object(plLayer, name="{}_AutoLayer".format(mat_name), bl=bo)
self._propagate_material_settings(bo, bm, layer)
hsgmat.addLayer(layer.key)
@ -349,7 +352,7 @@ class MaterialConverter:
return hsgmat.key
def export_bumpmap_slot(self, bo, bm, hsgmat, slot, idx):
name = "{}_{}".format(bm.name if bm is not None else bo.name, slot.name)
name = "{}_{}".format(hsgmat.key.name, slot.name)
self._report.msg("Exporting Plasma Bumpmap Layers for '{}'", name, indent=2)
# Okay, now we need to make 3 layers for the Du, Dw, and Dv
@ -1163,6 +1166,30 @@ class MaterialConverter:
def get_bump_layer(self, bo):
return self._bump_mats.get(bo, None)
def get_material_ambient(self, bo, bm) -> hsColorRGBA:
emit_scale = bm.emit * 0.5
if emit_scale > 0.0:
return hsColorRGBA(bm.diffuse_color.r * emit_scale,
bm.diffuse_color.g * emit_scale,
bm.diffuse_color.b * emit_scale,
1.0)
else:
return utils.color(bpy.context.scene.world.ambient_color)
def get_material_preshade(self, bo, bm, color=None) -> hsColorRGBA:
if bo.plasma_modifiers.lighting.rt_lights:
return hsColorRGBA.kBlack
if color is None:
color = bm.diffuse_color
return utils.color(color)
def get_material_runtime(self, bo, bm, color=None) -> hsColorRGBA:
if not bo.plasma_modifiers.lighting.rt_lights:
return hsColorRGBA.kBlack
if color is None:
color = bm.diffuse_color
return utils.color(color)
def get_texture_animation_key(self, bo, bm, texture):
"""Finds or creates the appropriate key for sending messages to an animated Texture"""
@ -1204,23 +1231,17 @@ class MaterialConverter:
if bm.use_shadeless:
state.shadeFlags |= hsGMatState.kShadeWhite
if bm.emit:
state.shadeFlags |= hsGMatState.kShadeEmissive
# Colors
layer.ambient = utils.color(bpy.context.scene.world.ambient_color)
layer.preshade = utils.color(bm.diffuse_color)
layer.runtime = utils.color(bm.diffuse_color)
layer.ambient = self.get_material_ambient(bo, bm)
layer.preshade = self.get_material_preshade(bo, bm)
layer.runtime = self.get_material_runtime(bo, bm)
layer.specular = utils.color(bm.specular_color)
layer.specularPower = min(100.0, float(bm.specular_hardness))
layer.LODBias = -1.0 # Seems to be the Plasma default
if bm.emit > 0.0:
# Use the diffuse colour as the emit, scaled by the emit amount
# (maximum 2.0, so we'll also scale that by 0.5)
emit_scale = bm.emit * 0.5
layer.ambient = hsColorRGBA(bm.diffuse_color.r * emit_scale,
bm.diffuse_color.g * emit_scale,
bm.diffuse_color.b * emit_scale,
1.0)
layer.LODBias = -1.0
def _requires_single_user(self, bo, bm):
if bo.data.show_double_sided:

220
korman/exporter/mesh.py

@ -14,6 +14,7 @@
# along with Korman. If not, see <http://www.gnu.org/licenses/>.
import bpy
import itertools
from PyHSPlasma import *
from math import fabs
import weakref
@ -29,6 +30,29 @@ _WARN_VERTS_PER_SPAN = 0x8000
_VERTEX_COLOR_LAYERS = {"col", "color", "colour"}
class _GeoSpan:
def __init__(self, bo, bm, geospan, pass_index=None):
self.geospan = geospan
self.pass_index = pass_index if pass_index is not None else 0
self.mult_color = self._determine_mult_color(bo, bm)
def _determine_mult_color(self, bo, bm):
"""Determines the color all vertex colors should be multipled by in this span."""
if self.geospan.props & plGeometrySpan.kDiffuseFoldedIn:
color = bm.diffuse_color
base_layer = self._find_bottom_of_stack()
return (color.r, color.b, color.g, base_layer.opacity)
if not bo.plasma_modifiers.lighting.preshade:
return (0.0, 0.0, 0.0, 0.0)
return (1.0, 1.0, 1.0, 1.0)
def _find_bottom_of_stack(self) -> plLayerInterface:
base_layer = self.geospan.material.object.layers[0].object
while base_layer.underLay is not None:
base_layer = base_layer.underLay.object
return base_layer
class _RenderLevel:
MAJOR_OPAQUE = 0
MAJOR_FRAMEBUF = 1
@ -40,16 +64,12 @@ class _RenderLevel:
_MINOR_MASK = ((1 << _MAJOR_SHIFT) - 1)
def __init__(self, bo, pass_index, blend_span=False):
self.level = 0
if pass_index > 0:
self.major = self.MAJOR_FRAMEBUF
self.minor = pass_index * 4
if blend_span:
self.level = self._determine_level(bo, blend_span)
else:
self.major = self.MAJOR_BLEND if blend_span else self.MAJOR_OPAQUE
# We use the blender material's pass index (which we stashed in the hsGMaterial) to increment
# the render pass, just like it says...
self.level += pass_index
self.level = 0
# Gulp... Hope you know what you're doing...
self.minor += pass_index * 4
def __eq__(self, other):
return self.level == other.level
@ -60,15 +80,38 @@ class _RenderLevel:
def _get_major(self):
return self.level >> self._MAJOR_SHIFT
def _set_major(self, value):
self.level = ((value << self._MAJOR_SHIFT) & 0xFFFFFFFF) | self.minor
self.level = self._calc_level(value, self.minor)
major = property(_get_major, _set_major)
def _get_minor(self):
return self.level & self._MINOR_MASK
def _set_minor(self, value):
self.level = ((self.major << self._MAJOR_SHIFT) & 0xFFFFFFFF) | value
self.level = self._calc_level(self.major, value)
minor = property(_get_minor, _set_minor)
def _calc_level(self, major : int, minor : int=0) -> int:
return ((major << self._MAJOR_SHIFT) & 0xFFFFFFFF) | minor
def _determine_level(self, bo : bpy.types.Object, blend_span : bool) -> int:
mods = bo.plasma_modifiers
if mods.test_property("draw_framebuf"):
return self._calc_level(self.MAJOR_FRAMEBUF)
elif mods.test_property("draw_opaque"):
return self._calc_level(self.MAJOR_OPAQUE)
elif mods.test_property("draw_no_defer"):
blend_span = False
blend_mod = mods.blend
if blend_mod.enabled and blend_mod.has_dependencies:
level = self._calc_level(self.MAJOR_FRAMEBUF)
for i in blend_mod.iter_dependencies():
level = max(level, self._determine_level(i, blend_span))
return level + 4
elif blend_span:
return self._calc_level(self.MAJOR_BLEND)
else:
return self._calc_level(self.MAJOR_DEFAULT)
class _DrawableCriteria:
def __init__(self, bo, geospan, pass_index):
@ -96,12 +139,12 @@ class _DrawableCriteria:
def _face_sort_allowed(self, bo):
# For now, only test the modifiers
# This will need to be tweaked further for GUIs...
return not any((i.no_face_sort for i in bo.plasma_modifiers.modifiers))
return not bo.plasma_modifiers.test_property("no_face_sort")
def _span_sort_allowed(self, bo):
# For now, only test the modifiers
# This will need to be tweaked further for GUIs...
return not any((i.no_face_sort for i in bo.plasma_modifiers.modifiers))
return not bo.plasma_modifiers.test_property("no_face_sort")
@property
def span_type(self):
@ -118,7 +161,6 @@ class _GeoData:
self.vertices = []
class _MeshManager:
def __init__(self, report=None):
if report is not None:
@ -214,15 +256,53 @@ class MeshConverter(_MeshManager):
return (num_user_texs, total_texs, max_user_texs)
def _create_geospan(self, bo, mesh, bm, hsgmatKey):
def _check_vtx_alpha(self, mesh, material_idx):
if material_idx is not None:
polygons = (i for i in mesh.polygons if i.material_index == material_idx)
else:
polygons = mesh.polygons
alpha_layer = self._find_vtx_alpha_layer(mesh.vertex_colors)
if alpha_layer is None:
return False
alpha_loops = (alpha_layer[i.loop_start:i.loop_start+i.loop_total] for i in polygons)
opaque = (sum(i.color) == len(i.color) for i in itertools.chain.from_iterable(alpha_loops))
has_alpha = not all(opaque)
return has_alpha
def _check_vtx_nonpreshaded(self, bo, mesh, material_idx, base_layer):
def check_layer_shading_animation(layer):
if isinstance(layer, plLayerAnimationBase):
return layer.opacityCtl is not None or layer.preshadeCtl is not None or layer.runtimeCtl is not None
if layer.underLay is not None:
return check_layer_shading_animation(layer.underLay.object)
return False
# TODO: if this is an avatar, we can't be non-preshaded.
if check_layer_shading_animation(base_layer):
return False
# Reject emissive and shadeless because the kLiteMaterial equation has lots of options
# that are taken away by VtxNonPreshaded that are useful here.
if material_idx is not None:
bm = mesh.materials[material_idx]
if bm.emit or bm.use_shadeless:
return False
mods = bo.plasma_modifiers
if mods.lighting.rt_lights:
return True
if mods.lightmap.bake_lightmap:
return True
if self._check_vtx_alpha(mesh, material_idx):
return True
return False
def _create_geospan(self, bo, mesh, material_idx, bm, hsgmatKey):
"""Initializes a plGeometrySpan from a Blender Object and an hsGMaterial"""
geospan = plGeometrySpan()
geospan.material = hsgmatKey
# Mark us as needing a BlendSpan if the material require blending
if hsgmatKey.object.layers[0].object.state.blendFlags & hsGMatState.kBlendMask:
geospan.props |= plGeometrySpan.kRequiresBlending
# GeometrySpan format
# For now, we really only care about the number of UVW Channels
user_uvws, total_uvws, max_user_uvws = self._calc_num_uvchans(bo, mesh)
@ -230,10 +310,22 @@ class MeshConverter(_MeshManager):
raise explosions.TooManyUVChannelsError(bo, bm, user_uvws, max_user_uvws)
geospan.format = total_uvws
# Begin total guesswork WRT flags
mods = bo.plasma_modifiers
if mods.lightmap.enabled:
def is_alpha_blended(layer):
if layer.state.blendFlags & hsGMatState.kBlendMask:
return True
if layer.underLay is not None:
return is_alpha_blended(layer.underLay.object)
return False
base_layer = hsgmatKey.object.layers[0].object
if is_alpha_blended(base_layer) or self._check_vtx_alpha(mesh, material_idx):
geospan.props |= plGeometrySpan.kRequiresBlending
if self._check_vtx_nonpreshaded(bo, mesh, material_idx, base_layer):
geospan.props |= plGeometrySpan.kLiteVtxNonPreshaded
if (geospan.props & plGeometrySpan.kLiteMask) != plGeometrySpan.kLiteMaterial:
geospan.props |= plGeometrySpan.kDiffuseFoldedIn
mods = bo.plasma_modifiers
if mods.lighting.rt_lights:
geospan.props |= plGeometrySpan.kPropRunTimeLight
if not bm.use_shadows:
@ -275,7 +367,7 @@ class MeshConverter(_MeshManager):
dspan.composeGeometry(True, True)
inc_progress()
def _export_geometry(self, bo, mesh, materials, geospans):
def _export_geometry(self, bo, mesh, materials, geospans, mat2span_LUT):
# Recall that materials is a mapping of exported materials to blender material indices.
# Therefore, geodata maps blender material indices to working geometry data.
# Maybe the logic is a bit inverted, but it keeps the inner loop simple.
@ -284,16 +376,8 @@ class MeshConverter(_MeshManager):
# Locate relevant vertex color layers now...
lm = bo.plasma_modifiers.lightmap
has_vtx_alpha = False
color, alpha = None, None
for vcol_layer in mesh.tessface_vertex_colors:
name = vcol_layer.name.lower()
if name in _VERTEX_COLOR_LAYERS:
color = vcol_layer.data
elif name == "autocolor" and color is None and not lm.bake_lightmap:
color = vcol_layer.data
elif name == "alpha":
alpha = vcol_layer.data
color = None if lm.bake_lightmap else self._find_vtx_color_layer(mesh.tessface_vertex_colors)
alpha = self._find_vtx_alpha_layer(mesh.tessface_vertex_colors)
# Convert Blender faces into things we can stuff into libHSPlasma
for i, tessface in enumerate(mesh.tessfaces):
@ -323,10 +407,8 @@ class MeshConverter(_MeshManager):
else:
src = alpha[i]
# average color becomes the alpha value
tessface_alphas = (((src.color1[0] + src.color1[1] + src.color1[2]) / 3),
((src.color2[0] + src.color2[1] + src.color2[2]) / 3),
((src.color3[0] + src.color3[1] + src.color3[2]) / 3),
((src.color4[0] + src.color4[1] + src.color4[2]) / 3))
tessface_alphas = ((sum(src.color1) / 3), (sum(src.color2) / 3),
(sum(src.color3) / 3), (sum(src.color4) / 3))
if bumpmap is not None:
gradPass = []
@ -356,10 +438,16 @@ class MeshConverter(_MeshManager):
for j, vertex in enumerate(tessface.vertices):
uvws = tuple([uvw[j] for uvw in tessface_uvws])
# Grab VCols
vertex_color = (int(tessface_colors[j][0] * 255), int(tessface_colors[j][1] * 255),
int(tessface_colors[j][2] * 255), int(tessface_alphas[j] * 255))
has_vtx_alpha |= bool(tessface_alphas[j] < 1.0)
# Calculate vertex colors.
if mat2span_LUT:
mult_color = geospans[mat2span_LUT[tessface.material_index]].mult_color
else:
mult_color = (1.0, 1.0, 1.0, 1.0)
tessface_color, tessface_alpha = tessface_colors[j], tessface_alphas[j]
vertex_color = (int(tessface_color[0] * mult_color[0] * 255),
int(tessface_color[1] * mult_color[1] * 255),
int(tessface_color[2] * mult_color[2] * 255),
int(tessface_alpha * mult_color[0] * 255))
# Now, we'll index into the vertex dict using the per-face elements :(
# We're using tuples because lists are not hashable. The many mathutils and PyHSPlasma
@ -416,7 +504,7 @@ class MeshConverter(_MeshManager):
# Time to finish it up...
for i, data in enumerate(geodata.values()):
geospan = geospans[i][0]
geospan = geospans[i].geospan
numVerts = len(data.vertices)
numUVs = geospan.format & plGeometrySpan.kUVCountMask
@ -437,10 +525,6 @@ class MeshConverter(_MeshManager):
uvMap[numUVs - 1].normalize()
vtx.uvs = uvMap
# Mark us for blending if we have a alpha vertex paint layer
if has_vtx_alpha:
geospan.props |= plGeometrySpan.kRequiresBlending
# If we're still here, let's add our data to the GeometrySpan
geospan.indices = data.triangles
geospan.vertices = data.vertices
@ -523,18 +607,18 @@ class MeshConverter(_MeshManager):
return None
# Step 1: Export all of the doggone materials.
geospans = self._export_material_spans(bo, mesh, materials)
geospans, mat2span_LUT = self._export_material_spans(bo, mesh, materials)
# Step 2: Export Blender mesh data to Plasma GeometrySpans
self._export_geometry(bo, mesh, materials, geospans)
self._export_geometry(bo, mesh, materials, geospans, mat2span_LUT)
# Step 3: Add plGeometrySpans to the appropriate DSpan and create indices
_diindices = {}
for geospan, pass_index in geospans:
dspan = self._find_create_dspan(bo, geospan, pass_index)
for i in geospans:
dspan = self._find_create_dspan(bo, i.geospan, i.pass_index)
self._report.msg("Exported hsGMaterial '{}' geometry into '{}'",
geospan.material.name, dspan.key.name, indent=1)
idx = dspan.addSourceSpan(geospan)
i.geospan.material.name, dspan.key.name, indent=1)
idx = dspan.addSourceSpan(i.geospan)
diidx = _diindices.setdefault(dspan, [])
diidx.append(idx)
@ -554,20 +638,25 @@ class MeshConverter(_MeshManager):
if len(materials) > 1:
msg = "'{}' is a WaveSet -- only one material is supported".format(bo.name)
self._exporter().report.warn(msg, indent=1)
matKey = self.material.export_waveset_material(bo, materials[0][1])
geospan = self._create_geospan(bo, mesh, materials[0][1], matKey)
blmat = materials[0][1]
matKey = self.material.export_waveset_material(bo, blmat)
geospan = self._create_geospan(bo, mesh, None, blmat, matKey)
# FIXME: Can some of this be generalized?
geospan.props |= (plGeometrySpan.kWaterHeight | plGeometrySpan.kLiteVtxNonPreshaded |
plGeometrySpan.kPropReverseSort | plGeometrySpan.kPropNoShadow)
geospan.waterHeight = bo.location[2]
return [(geospan, 0)]
return [_GeoSpan(bo, blmat, geospan)], None
else:
geospans = [None] * len(materials)
for i, (_, blmat) in enumerate(materials):
mat2span_LUT = {}
for i, (blmat_idx, blmat) in enumerate(materials):
matKey = self.material.export_material(bo, blmat)
geospans[i] = (self._create_geospan(bo, mesh, blmat, matKey), blmat.pass_index)
return geospans
geospans[i] = _GeoSpan(bo, blmat,
self._create_geospan(bo, mesh, blmat_idx, blmat, matKey),
blmat.pass_index)
mat2span_LUT[blmat_idx] = i
return geospans, mat2span_LUT
def _find_create_dspan(self, bo, geospan, pass_index):
location = self._mgr.get_location(bo)
@ -603,6 +692,21 @@ class MeshConverter(_MeshManager):
else:
return self._dspans[location][crit]
def _find_vtx_alpha_layer(self, color_collection):
alpha_layer = next((i for i in color_collection if i.name.lower() == "alpha"), None)
if alpha_layer is not None:
return alpha_layer.data
return None
def _find_vtx_color_layer(self, color_collection):
manual_layer = next((i for i in color_collection if i.name.lower() in _VERTEX_COLOR_LAYERS), None)
if manual_layer is not None:
return manual_layer.data
baked_layer = color_collection.get("autocolor")
if baked_layer is not None:
return baked_layer.data
return None
@property
def _mgr(self):
return self._exporter().mgr

3
korman/idprops.py

@ -127,6 +127,9 @@ def poll_animated_objects(self, value):
def poll_camera_objects(self, value):
return value.type == "CAMERA"
def poll_drawable_objects(self, value):
return value.type == "MESH" and any(value.data.materials)
def poll_empty_objects(self, value):
return value.type == "EMPTY"

4
korman/properties/modifiers/__init__.py

@ -66,6 +66,10 @@ class PlasmaModifiers(bpy.types.PropertyGroup):
setattr(cls, i.pl_id, bpy.props.PointerProperty(type=i))
bpy.types.Object.plasma_modifiers = bpy.props.PointerProperty(type=cls)
def test_property(self, property : str) -> bool:
"""Tests a property on all enabled Plasma modifiers"""
return any((getattr(i, property) for i in self.modifiers))
class PlasmaModifierSpec(bpy.types.PropertyGroup):
pass

20
korman/properties/modifiers/base.py

@ -30,10 +30,30 @@ class PlasmaModifierProperties(bpy.types.PropertyGroup):
def destroyed(self):
pass
@property
def draw_opaque(self):
"""Render geometry before the avatar"""
return False
@property
def draw_framebuf(self):
"""Render geometry after the avatar but before other blended geometry"""
return False
@property
def draw_no_defer(self):
"""Disallow geometry being sorted into a blending span"""
return False
@property
def enabled(self):
return self.display_order >= 0
@property
def face_sort(self):
"""Indicates that the geometry's faces should be sorted by the engine"""
return False
def harvest_actors(self):
return ()

94
korman/properties/modifiers/render.py

@ -25,6 +25,98 @@ from ...exporter import utils
from ...exporter.explosions import ExportError
from ... import idprops
class PlasmaBlendOntoObject(bpy.types.PropertyGroup):
blend_onto = PointerProperty(name="Blend Onto",
description="Object to render first",
options=set(),
type=bpy.types.Object,
poll=idprops.poll_drawable_objects)
enabled = BoolProperty(name="Enabled",
default=True,
options=set())
class PlasmaBlendMod(PlasmaModifierProperties):
pl_id = "blend"
bl_category = "Render"
bl_label = "Blending"
bl_description = "Advanced Blending Options"
render_level = EnumProperty(name="Render Pass",
description="Suggested render pass for this object.",
items=[("AUTO", "(Auto)", "Let Korman decide when to render this object."),
("OPAQUE", "Before Avatar", "Prefer for the object to draw before the avatar."),
("FRAMEBUF", "Frame Buffer", "Prefer for the object to draw after the avatar but before other blended objects."),
("BLEND", "Blended", "Prefer for the object to draw after most other geometry in the blended pass.")],
options=set())
sort_faces = EnumProperty(name="Sort Faces",
description="",
items=[("AUTO", "(Auto)", "Let Korman decide if faces should be sorted."),
("ALWAYS", "Always", "Force the object's faces to be sorted."),
("NEVER", "Never", "Force the object's faces to never be sorted.")],
options=set())
dependencies = CollectionProperty(type=PlasmaBlendOntoObject)
active_dependency_index = IntProperty(options={"HIDDEN"})
def export(self, exporter, bo, so):
# What'er you lookin at?
pass
@property
def draw_opaque(self):
return self.render_level == "OPAQUE"
@property
def draw_framebuf(self):
return self.render_level == "FRAMEBUF"
@property
def draw_no_defer(self):
return self.render_level != "BLEND"
@property
def face_sort(self):
return self.sort_faces == "ALWAYS"
@property
def no_face_sort(self):
return self.sort_faces == "NEVER"
@property
def has_dependencies(self):
return bool(self.dependencies)
@property
def has_circular_dependency(self):
return self._check_circular_dependency()
def _check_circular_dependency(self, objects=None):
if objects is None:
objects = set()
elif self.name in objects:
return True
objects.add(self.name)
for i in self.iter_dependencies():
# New deep copy of the set for each dependency, so an object can be reused as a
# dependant's dependant.
this_branch = set(objects)
sub_mod = i.plasma_modifiers.blend
if sub_mod.enabled and sub_mod._check_circular_dependency(this_branch):
return True
return False
def iter_dependencies(self):
for i in (j.blend_onto for j in self.dependencies if j.blend_onto is not None and j.enabled):
yield i
def sanity_check(self):
if self.has_circular_dependency:
raise ExportError("'{}': Circular Render Dependency detected!".format(self.name))
class PlasmaDecalManagerRef(bpy.types.PropertyGroup):
enabled = BoolProperty(name="Enabled",
default=True,
@ -439,6 +531,8 @@ class PlasmaLightingMod(PlasmaModifierProperties):
return True
if self.id_data.plasma_object.has_transform_animation:
return True
if mods.collision.enabled and mods.collision.dynamic:
return True
return False

30
korman/ui/modifiers/render.py

@ -18,6 +18,36 @@ import bpy
from .. import ui_list
from ...exporter.mesh import _VERTEX_COLOR_LAYERS
class BlendOntoListUI(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_property, index=0, flt_flag=0):
if item.blend_onto is None:
layout.label("[No Object Specified]", icon="ERROR")
else:
layout.label(item.blend_onto.name, icon="OBJECT_DATA")
layout.prop(item, "enabled", text="")
def blend(modifier, layout, context):
# Warn if there are render dependencies and a manual render level specification -- this
# could lead to unpredictable results.
layout.alert = modifier.render_level != "AUTO" and bool(modifier.dependencies)
layout.prop(modifier, "render_level")
layout.alert = False
layout.prop(modifier, "sort_faces")
layout.separator()
layout.label("Render Dependencies:")
ui_list.draw_modifier_list(layout, "BlendOntoListUI", modifier, "dependencies",
"active_dependency_index", rows=2, maxrows=4)
try:
dependency_ref = modifier.dependencies[modifier.active_dependency_index]
except:
pass
else:
layout.alert = dependency_ref.blend_onto is None
layout.prop(dependency_ref, "blend_onto")
class DecalMgrListUI(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_property, index=0, flt_flag=0):
if item.name:

Loading…
Cancel
Save