Browse Source

Implement blend texture generator.

pull/164/head
Adam Johnson 5 years ago
parent
commit
b8baf8b538
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 5
      korman/exporter/explosions.py
  2. 107
      korman/exporter/material.py

5
korman/exporter/explosions.py

@ -32,6 +32,11 @@ class ExportError(Exception):
super(Exception, self).__init__(args[0]) super(Exception, self).__init__(args[0])
class BlendNotSupported(ExportError):
def __init__(self, progression, axis):
super(ExportError, self).__init__("Alpha Blend not supported: {}, {}", progression, axis)
class BlenderOptionNotSupportedError(ExportError): class BlenderOptionNotSupportedError(ExportError):
def __init__(self, opt): def __init__(self, opt):
super(ExportError, self).__init__("Unsupported Blender Option: '{}'".format(opt)) super(ExportError, self).__init__("Unsupported Blender Option: '{}'".format(opt))

107
korman/exporter/material.py

@ -136,6 +136,7 @@ class MaterialConverter:
self._pending = {} self._pending = {}
self._alphatest = {} self._alphatest = {}
self._tex_exporters = { self._tex_exporters = {
"BLEND": self._export_texture_type_blend,
"ENVIRONMENT_MAP": self._export_texture_type_environment_map, "ENVIRONMENT_MAP": self._export_texture_type_environment_map,
"IMAGE": self._export_texture_type_image, "IMAGE": self._export_texture_type_image,
"NONE": self._export_texture_type_none, "NONE": self._export_texture_type_none,
@ -715,6 +716,112 @@ class MaterialConverter:
# We'll allow this, just for sanity's sake... # We'll allow this, just for sanity's sake...
pass pass
def _export_texture_type_blend(self, bo, layer, slot):
# This has been separated out because other things may need alpha blend textures.
texture = slot.texture
self.export_alpha_blend(texture.progression, texture.use_flip_axis, layer)
def export_alpha_blend(self, progression, axis, owner, indent=2):
"""This exports an alpha blend texture as exposed by bpy.types.BlendTexture.
The following arguments are expected:
- progression: (required)
- axis: (required)
- owner: (required) the Plasma object using this image
- indent: (optional) indentation level for log messages
default: 2
"""
# Certain blend types don't use an axis...
progression_axes = {"EASING", "LINEAR", "RADIAL", "QUADRATIC"}
if progression in progression_axes:
filename = "ALPHA_BLEND_{}_{}".format(progression, axis)
else:
filename = "ALPHA_BLEND_{}".format(progression)
axis = ""
image = bpy.data.images.get(filename)
if image is None:
def _calc_diagonal(x, y, width, height):
distance = math.sqrt(pow(x, 2) + pow(y, 2))
total = math.sqrt(pow(width, 2) + pow(height, 2))
return distance / total
def _calc_radial(x, y, width, height, horizontal=None):
if horizontal is True:
relative = (y - height / 2, x - width / 2)
elif horizontal is False:
relative = (x - width / 2, y - height / 2)
else:
raise RuntimeError()
angle = math.atan2(*relative) + math.pi
# PyPRP had some weird code that looked like an infinite loop for clamping from
# zero through 2pi. atan2 is documented to return in the range of -pi through pi.
two_pi = math.pi * 2
if angle < 0.0:
angle += two_pi
return max(0.0, angle / two_pi)
def _calc_lin_sphere(x, y, width, height):
half_width, half_height = width / 2, height / 2
distance = math.sqrt(pow(x - half_width, 2) + pow(y - half_height, 2))
value = math.cos(distance / half_width * 0.5 * math.pi)
if value < 0.0 or distance > half_width:
return 0.0
else:
return min(1.0, value)
def _calc_quad_sphere(x, y, width, height):
half_width, half_height = width / 2, height / 2
distance = math.sqrt(pow(x - half_width, 2) + pow(y - half_height, 2))
value = 0.5 + (0.5 * math.cos(distance / half_width * math.pi))
if value < 0.0 or distance > half_width:
return 0.0
else:
return min(1.0, value)
dimensions = {
("EASING", "HORIZONTAL"): (64, 4),
("EASING", "VERTICAL"): (4, 64),
("LINEAR", "HORIZONTAL"): (64, 4),
("LINEAR", "VERTICAL"): (4, 64),
("QUADRATIC", "HORIZONTAL"): (64, 4),
("QUADRATIC", "VERTICAL"): (4, 64),
}
funcs = {
("DIAGONAL", ""): _calc_diagonal,
("EASING", "HORIZONTAL"): lambda x, y, width, height: 0.5 - math.cos(x / width * math.pi) * 0.5,
("EASING", "VERTICAL"): lambda x, y, width, height: 0.5 - math.cos(y / height * math.pi) * 0.5,
("LINEAR", "HORIZONTAL"): lambda x, y, width, height: x / width,
("LINEAR", "VERTICAL"): lambda x, y, width, height: y / height,
("QUADRATIC", "HORIZONTAL"): lambda x, y, width, height: pow(x / width, 2),
("QUADRATIC", "VERTICAL"): lambda x, y, width, height: pow(y / height, 2),
("QUADRATIC_SPHERE", ""): _calc_quad_sphere,
("RADIAL", "HORIZONTAL"): functools.partial(_calc_radial, horizontal=True),
("RADIAL", "VERTICAL"): functools.partial(_calc_radial, horizontal=False),
("SPHERICAL", ""): _calc_lin_sphere,
}
blend_type = (progression, axis)
width, height = dimensions.get(blend_type, (64, 64))
pixels = [None] * (width * height * 4)
func = funcs.get(blend_type)
if func is None:
raise BlendNotSupported(progression, axis)
# This is slower than a custom writer for each blend texture, but that would be uglier
# and less maintainable. Running this function in the Blender console is nearly instant,
# so I think this is the best option, really.
for x in range(width):
for y in range(height):
offset = (y * width * 4) + (x * 4)
value = func(x, y, width, height)
pixels[offset:offset+4] = (value,) * 4
image = bpy.data.images.new(filename, width=width, height=height, alpha=True)
image.pixels = pixels
self.export_prepared_image(image=image, owner=owner, allowed_formats={"BMP"},
alpha_type=TextureAlpha.full, indent=2, ephemeral=True)
def export_prepared_image(self, **kwargs): def export_prepared_image(self, **kwargs):
"""This exports an externally prepared image and an optional owning layer. """This exports an externally prepared image and an optional owning layer.
The following arguments are typical: The following arguments are typical:

Loading…
Cancel
Save