mirror of
https://github.com/H-uru/korman.git
synced 2025-07-14 22:36:52 +00:00
Implement stencil layers
This commit is contained in:
@ -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,43 +207,64 @@ 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))
|
||||||
layer = self._mgr.add_object(plLayer, name=name, bl=bo)
|
layer = self._mgr.add_object(plLayer, name=name, bl=bo)
|
||||||
self._propagate_material_settings(bm, layer)
|
self._propagate_material_settings(bm, layer)
|
||||||
|
|
||||||
# UVW Channel
|
# UVW Channel
|
||||||
for i, uvchan in enumerate(bo.data.tessface_uv_textures):
|
for i, uvchan in enumerate(bo.data.tessface_uv_textures):
|
||||||
if uvchan.name == slot.uv_layer:
|
if uvchan.name == slot.uv_layer:
|
||||||
layer.UVWSrc = i
|
layer.UVWSrc = i
|
||||||
print(" Using UV Map #{} '{}'".format(i, name))
|
print(" Using UV Map #{} '{}'".format(i, name))
|
||||||
break
|
break
|
||||||
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":
|
||||||
state.blendFlags |= hsGMatState.kBlendMult
|
state.blendFlags |= hsGMatState.kBlendMult
|
||||||
|
|
||||||
# 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):
|
hsgmat.addLayer(layer.key)
|
||||||
raise explosions.UnsupportedTextureError(texture, bm)
|
return num_exported
|
||||||
getattr(self, export_fn)(bo, hsgmat, layer, texture)
|
|
||||||
hsgmat.addLayer(layer.key)
|
|
||||||
|
|
||||||
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,]
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user