Browse Source

Fix issue with corrupted texture cache

If the texture cache doesn't return images in exactly the order or way
that libHSPlasma is expecting, it raises a RuntimeError. We can detect
that we used a cached image and regenerate the data in that case...
instead of just outright failing with "image data size mismatch".
pull/133/head
Adam Johnson 6 years ago
parent
commit
febfb3dd42
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 117
      korman/exporter/material.py

117
korman/exporter/material.py

@ -781,62 +781,79 @@ class MaterialConverter:
cached_image = texcache.get_from_texture(key, compression) cached_image = texcache.get_from_texture(key, compression)
if cached_image is None: if cached_image is None:
if key.is_cube_map: numLevels, width, height, data = self._finalize_cache(texcache, key, image, name, compression, dxt)
numLevels, width, height, data = self._finalize_cube_map(key, image, name, compression, dxt) self._finalize_bitmap(key, owners, name, numLevels, width, height, compression, dxt, data)
else:
numLevels, width, height, data = self._finalize_single_image(key, image, name, compression, dxt)
texcache.add_texture(key, numLevels, (width, height), compression, data)
else: else:
width, height = cached_image.export_size width, height = cached_image.export_size
data = cached_image.image_data data = cached_image.image_data
numLevels = cached_image.mip_levels numLevels = cached_image.mip_levels
# Now we poke our new bitmap into the pending layers. Note that we have to do some funny # If the cached image data is junk, PyHSPlasma will raise a RuntimeError,
# business to account for per-page textures # so we'll attempt a recache...
pages = {} try:
self._finalize_bitmap(key, owners, name, numLevels, width, height, compression, dxt, data)
self._report.msg("Adding to...", indent=1) except RuntimeError:
for owner_key in owners: self._report.warn("Cached image is corrupted! Recaching image...", indent=1)
owner = owner_key.object numLevels, width, height, data = self._finalize_cache(texcache, key, image, name, compression, dxt)
self._report.msg("[{} '{}']", owner.ClassName()[2:], owner_key.name, indent=2) self._finalize_bitmap(key, owners, name, numLevels, width, height, compression, dxt, data)
page = mgr.get_textures_page(owner_key) # Layer's page or Textures.prp
# If we haven't created this texture 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
# need to be careful to manage our resources correctly
if page not in pages:
mipmap = plMipmap(name=name, width=width, height=height, numLevels=numLevels,
compType=compression, format=plBitmap.kRGB8888, dxtLevel=dxt)
if key.is_cube_map:
assert len(data) == 6
texture = plCubicEnvironmap(name)
for face_name, face_data in zip(BLENDER_CUBE_MAP, data):
for i in range(numLevels):
mipmap.setLevel(i, face_data[i])
setattr(texture, face_name, mipmap)
else:
assert len(data) == 1
for i in range(numLevels):
mipmap.setLevel(i, data[0][i])
texture = mipmap
mgr.AddObject(page, texture)
pages[page] = texture
else:
texture = pages[page]
# The object that references this image can be either a layer (will appear
# in the 3d world) or an image library (will appear in a journal or in another
# dynamic manner in game)
if isinstance(owner, plLayerInterface):
owner.texture = texture.key
elif isinstance(owner, plImageLibMod):
owner.addImage(texture.key)
else:
raise RuntimeError(owner.ClassName())
inc_progress() inc_progress()
def _finalize_bitmap(self, key, owners, name, numLevels, width, height, compression, dxt, data):
mgr = self._mgr
# 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
pages = {}
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 texture 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
# need to be careful to manage our resources correctly
if page not in pages:
mipmap = plMipmap(name=name, width=width, height=height, numLevels=numLevels,
compType=compression, format=plBitmap.kRGB8888, dxtLevel=dxt)
if key.is_cube_map:
assert len(data) == 6
texture = plCubicEnvironmap(name)
for face_name, face_data in zip(BLENDER_CUBE_MAP, data):
for i in range(numLevels):
mipmap.setLevel(i, face_data[i])
setattr(texture, face_name, mipmap)
else:
assert len(data) == 1
for i in range(numLevels):
mipmap.setLevel(i, data[0][i])
texture = mipmap
mgr.AddObject(page, texture)
pages[page] = texture
else:
texture = pages[page]
# The object that references this image can be either a layer (will appear
# in the 3d world) or an image library (will appear in a journal or in another
# dynamic manner in game)
if isinstance(owner, plLayerInterface):
owner.texture = texture.key
elif isinstance(owner, plImageLibMod):
owner.addImage(texture.key)
else:
raise NotImplementedError(owner.ClassName())
def _finalize_cache(self, texcache, key, image, name, compression, dxt):
if key.is_cube_map:
numLevels, width, height, data = self._finalize_cube_map(key, image, name, compression, dxt)
else:
numLevels, width, height, data = self._finalize_single_image(key, image, name, compression, dxt)
texcache.add_texture(key, numLevels, (width, height), compression, data)
return numLevels, width, height, data
def _finalize_cube_map(self, key, image, name, compression, dxt): def _finalize_cube_map(self, key, image, name, compression, dxt):
oWidth, oHeight = image.size oWidth, oHeight = image.size
if oWidth == 0 and oHeight == 0: if oWidth == 0 and oHeight == 0:

Loading…
Cancel
Save