Browse Source

Implement stencil layers

pull/8/head
Adam Johnson 10 years ago
parent
commit
8ba4d8287f
  1. 76
      korman/exporter/material.py
  2. 10
      korman/exporter/mesh.py

76
korman/exporter/material.py

@ -107,7 +107,7 @@ class _GLTexture:
class _Texture: class _Texture:
def __init__(self, texture=None, image=None, use_alpha=None): def __init__(self, texture=None, image=None, use_alpha=None, force_calc_alpha=False):
assert (texture or image) assert (texture or image)
if texture is not None: if texture is not None:
@ -119,7 +119,10 @@ class _Texture:
self.calc_alpha = False self.calc_alpha = False
self.mipmap = False self.mipmap = False
if use_alpha is None: if force_calc_alpha or self.calc_alpha:
self.calc_alpha = True
self.use_alpha = True
elif use_alpha is None:
self.use_alpha = (image.channels == 4 and image.use_alpha) self.use_alpha = (image.channels == 4 and image.use_alpha)
else: else:
self.use_alpha = use_alpha self.use_alpha = use_alpha
@ -168,13 +171,25 @@ class MaterialConverter:
self._exporter = weakref.ref(exporter) self._exporter = weakref.ref(exporter)
self._pending = {} self._pending = {}
self._alphatest = {} self._alphatest = {}
self._tex_exporters = {
"ENVRIONMENT_MAP": self._export_texture_type_environment_map,
"IMAGE": self._export_texture_type_image,
"NONE": self._export_texture_type_none,
}
def export_material(self, bo, bm): def export_material(self, bo, bm):
"""Exports a Blender Material as an hsGMaterial""" """Exports a Blender Material as an hsGMaterial"""
print(" Exporting Material '{}'".format(bm.name)) print(" Exporting Material '{}'".format(bm.name))
hsgmat = self._mgr.add_object(hsGMaterial, name=bm.name, bl=bo) hsgmat = self._mgr.add_object(hsGMaterial, name=bm.name, bl=bo)
self._export_texture_slots(bo, bm, hsgmat) slots = [slot for slot in bm.texture_slots if slot is not None and slot.use and
slot.texture is not None and slot.texture.type in self._tex_exporters]
# Okay, I know this isn't Pythonic... But we're doing it this way because we might actually
# export many slots in one go. Think stencils.
i = 0
while i < len(slots):
i += self._export_texture_slot(bo, bm, hsgmat, slots, i)
# Plasma makes several assumptions that every hsGMaterial has at least one layer. If this # 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 # material had no Textures, we will need to initialize a default layer
@ -192,10 +207,9 @@ class MaterialConverter:
# Looks like we're done... # Looks like we're done...
return hsgmat.key return hsgmat.key
def _export_texture_slots(self, bo, bm, hsgmat): def _export_texture_slot(self, bo, bm, hsgmat, slots, idx):
for slot in bm.texture_slots: slot = slots[idx]
if slot is None or not slot.use: num_exported = 1
continue
name = "{}_{}".format(bm.name, slot.name) name = "{}_{}".format(bm.name, slot.name)
print(" Exporting Plasma Layer '{}'".format(name)) print(" Exporting Plasma Layer '{}'".format(name))
@ -211,8 +225,31 @@ class MaterialConverter:
else: else:
print(" No UVMap specified... Blindly using the first one, maybe it exists :|") print(" No UVMap specified... Blindly using the first one, maybe it exists :|")
# General texture flags and such
state = layer.state state = layer.state
if slot.use_stencil:
hsgmat.compFlags |= hsGMaterial.kCompNeedsBlendChannel
state.blendFlags |= hsGMatState.kBlendAlpha | hsGMatState.kBlendAlphaMult | hsGMatState.kBlendNoTexColor
state.clampFlags |= hsGMatState.kClampTexture
state.ZFlags |= hsGMatState.kZNoZWrite
layer.ambient = hsColorRGBA(1.0, 1.0, 1.0, 1.0)
# Plasma actually wants the next layer first, so let's export him
nextIdx = idx + 1
if len(slots) == nextIdx:
raise ExportError("Texture Slot '{}' wants to be a stencil, but there are no more TextureSlots.".format(slot.name))
print(" --- BEGIN STENCIL ---")
self._export_texture_slot(bo, bm, hsgmat, slots, nextIdx)
print(" --- END STENCIL ---")
num_exported += 1
# Now that we've exported the bugger, flag him as binding with this texture
prev_layer = hsgmat.layers[-1].object
prev_state = prev_layer.state
prev_state.miscFlags |= hsGMatState.kMiscBindNext | hsGMatState.kMiscRestartPassHere
if not prev_state.blendFlags & hsGMatState.kBlendMask:
prev_state.blendFlags |= hsGMatState.kBlendAlpha
else:
# Standard layer flags ahoy
if slot.blend_type == "ADD": if slot.blend_type == "ADD":
state.blendFlags |= hsGMatState.kBlendAdd state.blendFlags |= hsGMatState.kBlendAdd
elif slot.blend_type == "MULTIPLY": elif slot.blend_type == "MULTIPLY":
@ -220,15 +257,14 @@ class MaterialConverter:
# Export the specific texture type # Export the specific texture type
texture = slot.texture texture = slot.texture
export_fn = "_export_texture_type_{}".format(texture.type.lower()) self._tex_exporters[texture.type](bo, hsgmat, layer, slot)
if not hasattr(self, export_fn):
raise explosions.UnsupportedTextureError(texture, bm)
getattr(self, export_fn)(bo, hsgmat, layer, texture)
hsgmat.addLayer(layer.key) hsgmat.addLayer(layer.key)
return num_exported
def _export_texture_type_environment_map(self, bo, hsgmat, layer, texture): def _export_texture_type_environment_map(self, bo, hsgmat, layer, slot):
"""Exports a Blender EnvironmentMapTexture to a plLayer""" """Exports a Blender EnvironmentMapTexture to a plLayer"""
texture = slot.texture
bl_env = texture.environment_map bl_env = texture.environment_map
if bl_env.source in {"STATIC", "ANIMATED"}: if bl_env.source in {"STATIC", "ANIMATED"}:
if bl_env.mapping == "PLANE" and self._mgr.getVer() >= pvMoul: if bl_env.mapping == "PLANE" and self._mgr.getVer() >= pvMoul:
@ -323,21 +359,25 @@ class MaterialConverter:
return pl_env.key return pl_env.key
def _export_texture_type_image(self, bo, hsgmat, layer, texture): def _export_texture_type_image(self, bo, hsgmat, layer, slot):
"""Exports a Blender ImageTexture to a plLayer""" """Exports a Blender ImageTexture to a plLayer"""
texture = slot.texture
# Does the image have any alpha at all? # Does the image have any alpha at all?
has_alpha = texture.use_calculate_alpha or self._test_image_alpha(texture.image) has_alpha = texture.use_calculate_alpha or slot.use_stencil or self._test_image_alpha(texture.image)
if (texture.image.use_alpha and texture.use_alpha) and not has_alpha: if (texture.image.use_alpha and texture.use_alpha) and not has_alpha:
warning = "'{}' wants to use alpha, but '{}' is opaque".format(texture.name, texture.image.name) warning = "'{}' wants to use alpha, but '{}' is opaque".format(texture.name, texture.image.name)
self._exporter().report.warn(warning, indent=3) self._exporter().report.warn(warning, indent=3)
# First, let's apply any relevant flags # First, let's apply any relevant flags
state = layer.state state = layer.state
if texture.invert_alpha and has_alpha: if not slot.use_stencil:
state.blendFlags |= hsGMatState.kBlendInvertAlpha # mutually exclusive blend flags
if texture.use_alpha and has_alpha: if texture.use_alpha and has_alpha:
state.blendFlags |= hsGMatState.kBlendAlpha state.blendFlags |= hsGMatState.kBlendAlpha
if texture.invert_alpha and has_alpha:
state.blendFlags |= hsGMatState.kBlendInvertAlpha
if texture.extension == "CLIP": if texture.extension == "CLIP":
state.clampFlags |= hsGMatState.kClampTexture state.clampFlags |= hsGMatState.kClampTexture
@ -348,7 +388,7 @@ class MaterialConverter:
if texture.image is None: if texture.image is None:
bitmap = self.add_object(plDynamicTextMap, name="{}_DynText".format(layer.key.name), bl=bo) bitmap = self.add_object(plDynamicTextMap, name="{}_DynText".format(layer.key.name), bl=bo)
else: else:
key = _Texture(texture=texture, use_alpha=has_alpha) key = _Texture(texture=texture, use_alpha=has_alpha, force_calc_alpha=slot.use_stencil)
if key not in self._pending: if key not in self._pending:
print(" Stashing '{}' for conversion as '{}'".format(texture.image.name, str(key))) print(" Stashing '{}' for conversion as '{}'".format(texture.image.name, str(key)))
self._pending[key] = [layer.key,] self._pending[key] = [layer.key,]

10
korman/exporter/mesh.py

@ -42,7 +42,7 @@ class _RenderLevel:
# Naive... BlendSpans (any blending on the first layer) are MAJOR_BLEND # Naive... BlendSpans (any blending on the first layer) are MAJOR_BLEND
if blendSpan: if blendSpan:
self.major = self.MAJOR_BLEND self.major = self.MAJOR_DEFAULT
# We use the blender material's pass index (which we stashed in the hsGMaterial) to increment # We use the blender material's pass index (which we stashed in the hsGMaterial) to increment
# the render pass, just like it says... # the render pass, just like it says...
@ -69,8 +69,12 @@ class _RenderLevel:
class _DrawableCriteria: class _DrawableCriteria:
def __init__(self, hsgmat, pass_index): def __init__(self, hsgmat, pass_index):
_layer = hsgmat.layers[0].object # better doggone well have a layer... for layer in hsgmat.layers:
self.blend_span = bool(_layer.state.blendFlags & hsGMatState.kBlendMask) if layer.object.state.blendFlags & hsGMatState.kBlendMask:
self.blend_span = True
break
else:
self.blend_span = False
self.criteria = 0 # TODO self.criteria = 0 # TODO
self.render_level = _RenderLevel(hsgmat, pass_index, self.blend_span) self.render_level = _RenderLevel(hsgmat, pass_index, self.blend_span)

Loading…
Cancel
Save