Browse Source

Fix #76

On the surface, this allows lightmaps to be exported as PNGs. However,
it also includes a light refactor of image exporting to facilitate
requesting export formats and the targeting of plImageLibMod. This
should better enable #96.
pull/103/head
Adam Johnson 6 years ago
parent
commit
554cb31bae
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 125
      korman/exporter/material.py
  2. 4
      korman/properties/modifiers/render.py

125
korman/exporter/material.py

@ -45,10 +45,11 @@ class _Texture:
else:
self.layer = kwargs.get("layer")
self.calc_alpha = False
self.mipmap = False
self.mipmap = kwargs.get("mipmap", False)
if kwargs.get("is_detail_map", False):
self.is_detail_map = True
self.mipmap = True
self.detail_blend = kwargs["detail_blend"]
self.detail_fade_start = kwargs["detail_fade_start"]
self.detail_fade_stop = kwargs["detail_fade_stop"]
@ -56,6 +57,7 @@ class _Texture:
self.detail_opacity_stop = kwargs["detail_opacity_stop"]
self.calc_alpha = False
self.use_alpha = True
self.allowed_formats = {"DDS"}
else:
self.is_detail_map = False
use_alpha = kwargs.get("use_alpha")
@ -66,7 +68,20 @@ class _Texture:
self.use_alpha = (image.channels == 4 and image.use_alpha)
else:
self.use_alpha = use_alpha
self.allowed_formats = kwargs.get("allowed_formats",
{"DDS"} if self.mipmap else {"PNG", "JPG"})
# Basic format sanity
if self.mipmap:
assert "DDS" in self.allowed_formats
if len(self.allowed_formats) == 1:
self.auto_ext = next(iter(self.allowed_formats)).lower()
elif self.mipmap:
self.auto_ext = "dds"
else:
self.auto_ext = "hsm"
self.extension = kwargs.get("extension", self.auto_ext)
self.image = image
def __eq__(self, other):
@ -83,10 +98,10 @@ class _Texture:
return hash(str(self))
def __str__(self):
if self.mipmap:
name = str(Path(self.image.name).with_suffix(".dds"))
if self.extension is None:
name = self.image.name
else:
name = str(Path(self.image.name).with_suffix(".bmp"))
name = str(Path(self.image.name).with_suffix(".{}".format(self.extension)))
if self.calc_alpha:
name = "ALPHAGEN_{}".format(name)
@ -558,6 +573,7 @@ class MaterialConverter:
"""Exports a Blender ImageTexture to a plLayer"""
texture = slot.texture
layer_props = texture.plasma_layer
mipmap = texture.use_mipmap
# Does the image have any alpha at all?
if texture.image is not None:
@ -598,7 +614,7 @@ class MaterialConverter:
layer.texture = dtm.key
else:
detail_blend = TEX_DETAIL_ALPHA
if layer_props.is_detail_map and texture.use_mipmap:
if layer_props.is_detail_map and mipmap:
if slot.blend_type == "ADD":
detail_blend = TEX_DETAIL_ADD
elif slot.blend_type == "MULTIPLY":
@ -608,38 +624,55 @@ class MaterialConverter:
if layer_props.is_detail_map and not state.blendFlags & hsGMatState.kBlendMask:
state.blendFlags |= hsGMatState.kBlendDetail
key = _Texture(texture=texture, use_alpha=has_alpha, force_calc_alpha=slot.use_stencil,
is_detail_map=layer_props.is_detail_map, detail_blend=detail_blend,
detail_fade_start=layer_props.detail_fade_start, detail_fade_stop=layer_props.detail_fade_stop,
detail_opacity_start=layer_props.detail_opacity_start, detail_opacity_stop=layer_props.detail_opacity_stop)
if key not in self._pending:
self._report.msg("Stashing '{}' for conversion as '{}'",
texture.image.name, str(key), indent=3)
self._pending[key] = [layer.key,]
else:
self._report.msg("Found another user of '{}'", texture.image.name, indent=3)
self._pending[key].append(layer.key)
allowed_formats = {"DDS"} if mipmap else {"PNG", "BMP"}
self.export_prepared_image(texture=texture, owner=layer,
use_alpha=has_alpha, force_calc_alpha=slot.use_stencil,
is_detail_map=layer_props.is_detail_map,
detail_blend=detail_blend,
detail_fade_start=layer_props.detail_fade_start,
detail_fade_stop=layer_props.detail_fade_stop,
detail_opacity_start=layer_props.detail_opacity_start,
detail_opacity_stop=layer_props.detail_opacity_stop,
mipmap=mipmap, allowed_formats=allowed_formats,
indent=3)
def _export_texture_type_none(self, bo, layer, texture):
# We'll allow this, just for sanity's sake...
pass
def export_prepared_layer(self, layer, image):
"""This exports an externally prepared layer and image"""
key = _Texture(image=image)
def export_prepared_image(self, **kwargs):
"""This exports an externally prepared image and an optional owning layer.
The following arguments are typical:
- texture: (co-required) the image texture datablock to export
- image: (co-required) the image datablock to export
- owner: (required) the Plasma object using this image
- mipmap: (optional) should the image be mipmapped?
- allowed_formats: (optional) set of string *hints* for desired image export type
valid options: BMP, DDS, JPG, PNG
- extension: (optional) file extension to use for the image object
to use the image datablock extension, set this to None
- indent: (optional) indentation level for log messages
default: 2
"""
owner = kwargs.pop("owner", None)
indent = kwargs.pop("indent", 2)
key = _Texture(**kwargs)
image = key.image
if key not in self._pending:
self._report.msg("Stashing '{}' for conversion as '{}'", image.name, key, indent=2)
self._pending[key] = [layer.key,]
self._report.msg("Stashing '{}' for conversion as '{}'", image.name, key, indent=indent)
self._pending[key] = [owner.key,]
else:
self._report.msg("Found another user of '{}'", key, indent=2)
self._pending[key].append(layer.key)
self._report.msg("Found another user of '{}'", key, indent=indent)
self._pending[key].append(owner.key)
def finalize(self):
self._report.progress_advance()
self._report.progress_range = len(self._pending)
inc_progress = self._report.progress_increment
mgr = self._mgr
for key, layers in self._pending.items():
for key, owners in self._pending.items():
name = str(key)
self._report.msg("\n[Mipmap '{}']", name)
@ -655,14 +688,27 @@ class MaterialConverter:
oWidth, oHeight, eWidth, eHeight, indent=1)
self._resize_image(image, eWidth, eHeight)
# Some basic mipmap settings.
compression = plBitmap.kDirectXCompression if key.mipmap else plBitmap.kUncompressed
dxt = plBitmap.kDXT5 if key.use_alpha or key.calc_alpha else plBitmap.kDXT1
# Now we try to use the pile of hints we were given to figure out what format to use
allowed_formats = key.allowed_formats
if key.mipmap:
compression = plBitmap.kDirectXCompression
dxt = plBitmap.kDXT5 if key.use_alpha or key.calc_alpha else plBitmap.kDXT1
elif "PNG" in allowed_formats and self._mgr.getVer() == pvMoul:
compression = plBitmap.kPNGCompression
elif "DDS" in allowed_formats:
compression = plBitmap.kDirectXCompression
dxt = plBitmap.kDXT5 if key.use_alpha or key.calc_alpha else plBitmap.kDXT1
elif "JPG" in allowed_formats:
compression = plBitmap.kJPEGCompression
elif "BMP" in allowed_formats:
compression = plBitmap.kUncompressed
else:
raise RuntimeError(allowed_formats)
# Grab the image data from OpenGL and stuff it into the plBitmap
helper = GLTexture(key)
with helper as glimage:
if key.mipmap:
if compression == plBitmap.kDirectXCompression:
numLevels = glimage.num_levels
self._report.msg("Generating mip levels", indent=1)
glimage.generate_mipmap()
@ -670,8 +716,8 @@ class MaterialConverter:
numLevels = 1
self._report.msg("Stuffing image data", indent=1)
# Uncompressed bitmaps are BGRA
fmt = compression == plBitmap.kUncompressed
# Non-DXT images are BGRA in Plasma
fmt = compression != plBitmap.kDirectXCompression
# Hold the uncompressed level data for now. We may have to make multiple copies of
# this mipmap for per-page textures :(
@ -684,13 +730,13 @@ class MaterialConverter:
# Now we poke our new bitmap into the pending layers. Note that we have to do some funny
# business to account for per-page textures
mgr = self._mgr
pages = {}
self._report.msg("Adding to Layer(s)", indent=1)
for layer in layers:
self._report.msg(layer.name, indent=2)
page = mgr.get_textures_page(layer) # Layer's page or Textures.prp
self._report.msg("Adding to...", indent=1)
for owner_key in owners:
owner = owner_key.object
self._report.msg("[{} '{}']", owner.ClassName()[2:], owner_key.name, indent=2)
page = mgr.get_textures_page(owner_key) # Layer's page or Textures.prp
# If we haven't created this plMipmap in the page (either layer's page or Textures.prp),
# then we need to do that and stuff the level data. This is a little tedious, but we
@ -703,7 +749,14 @@ class MaterialConverter:
pages[page] = mipmap
else:
mipmap = pages[page]
layer.object.texture = mipmap.key
if isinstance(owner, plLayerInterface):
owner.texture = mipmap.key
elif isinstance(owner, plImageLibMod):
owner.addImage(mipmap.key)
else:
raise RuntimeError(owner.ClassName())
inc_progress()
def get_materials(self, bo):

4
korman/properties/modifiers/render.py

@ -213,7 +213,9 @@ class PlasmaLightMapGen(idprops.IDPropMixin, PlasmaModifierProperties):
mat.addPiggyBack(layer.key)
# Mmm... cheating
mat_mgr.export_prepared_layer(layer, lightmap_im)
mat_mgr.export_prepared_image(owner=layer, image=lightmap_im,
allowed_formats={"PNG", "DDS"},
indent=2)
@classmethod
def _idprop_mapping(cls):

Loading…
Cancel
Save