Browse Source

Fix #5

We now harvest information about texture images throughout the export
process and don't pull the trigger until we're totally done. There are
still some issues with regard to confusing UI, but we'll get to it.
pull/6/head
Adam Johnson 11 years ago
parent
commit
c084a773ad
  1. 7
      korman/exporter/convert.py
  2. 6
      korman/exporter/manager.py
  3. 120
      korman/exporter/material.py

7
korman/exporter/convert.py

@ -58,13 +58,14 @@ class Exporter:
# Step 3: Export all the things! # Step 3: Export all the things!
self._export_scene_objects() self._export_scene_objects()
# Step 3.9: Finalize geometry... # Step 4: Finalize...
self.mesh.material.finalize()
self.mesh.finalize() self.mesh.finalize()
# Step 4: FINALLY. Let's write the PRPs and crap. # Step 5: FINALLY. Let's write the PRPs and crap.
self.mgr.save_age(self._op.filepath) self.mgr.save_age(self._op.filepath)
# Step 4.1: Save out the export report. # Step 5.1: Save out the export report.
# If the export fails and this doesn't save, we have bigger problems than # If the export fails and this doesn't save, we have bigger problems than
# these little warnings and notices. # these little warnings and notices.
self.report.save() self.report.save()

6
korman/exporter/manager.py

@ -159,13 +159,13 @@ class ExportManager:
"""Gets a Plasma Page's plSceneNode key""" """Gets a Plasma Page's plSceneNode key"""
return self._nodes[location].key return self._nodes[location].key
def get_textures_page(self, obj): def get_textures_page(self, layer):
"""Returns the page that Blender Object obj's textures should be exported to""" """Gets the appropriate page for a texture for a given plLayer"""
# The point of this is to account for per-page textures... # The point of this is to account for per-page textures...
if "Textures" in self._pages: if "Textures" in self._pages:
return self._pages["Textures"] return self._pages["Textures"]
else: else:
return self._pages[obj.plasma_object.page] return layer.key.location
def sanity_check_object_pages(self, age, objects): def sanity_check_object_pages(self, age, objects):
"""Ensure all objects are in valid pages and create the Default page if used""" """Ensure all objects are in valid pages and create the Default page if used"""

120
korman/exporter/material.py

@ -16,6 +16,7 @@
import bpy import bpy
import bgl import bgl
import math import math
import os.path
from PyHSPlasma import * from PyHSPlasma import *
import weakref import weakref
@ -71,6 +72,7 @@ class _GLTexture:
""" """
width = self._get_tex_param(bgl.GL_TEXTURE_WIDTH, level) width = self._get_tex_param(bgl.GL_TEXTURE_WIDTH, level)
height = self._get_tex_param(bgl.GL_TEXTURE_HEIGHT, level) height = self._get_tex_param(bgl.GL_TEXTURE_HEIGHT, level)
print(" Level #{}: {}x{}".format(level, width, height))
# Grab the image data # Grab the image data
size = width * height * 4 size = width * height * 4
@ -99,10 +101,56 @@ class _GLTexture:
return int(buf[0]) return int(buf[0])
class _Texture:
def __init__(self, texture):
self.image = texture.image
self.calc_alpha = texture.use_calculate_alpha
self.mipmap = texture.use_mipmap
self.use_alpha = texture.use_alpha
def __eq__(self, other):
if not isinstance(other, _Texture):
return False
if self.image == other.image:
if self.calc_alpha == other.calc_alpha:
self._update(other)
return True
def __hash__(self):
return hash(self.image.name) ^ hash(self.calc_alpha)
def __str__(self):
if self.mipmap:
name = self._change_extension(self.image.name, ".dds")
else:
name = self._change_extension(self.image.name, ".bmp")
if self.calc_alpha:
name = "ALPHAGEN_{}".format(name)
return name
def _change_extension(self, name, newext):
# Blender likes to add faux extensions such as .001 :(
if name.find(".") == -1:
return "{}{}".format(name, newext)
name, end = os.path.splitext(name)
if name.find(".") == -1:
return "{}{}".format(name, newext)
name, oldext = os.path.splitext(name)
return "{}{}{}".format(name, end, newext)
def _update(self, other):
"""Update myself with any props that might be overridable from another copy of myself"""
if other.use_alpha:
self.use_alpha = True
if other.mipmap:
self.mipmap = True
class MaterialConverter: class MaterialConverter:
def __init__(self, exporter): def __init__(self, exporter):
self._exporter = weakref.ref(exporter) self._exporter = weakref.ref(exporter)
self._hsbitmaps = {} self._pending = {}
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"""
@ -161,35 +209,29 @@ class MaterialConverter:
# Now, let's export the plBitmap # Now, let's export the plBitmap
# If the image is None (no image applied in Blender), we assume this is a plDynamicTextMap # If the image is None (no image applied in Blender), we assume this is a plDynamicTextMap
# Otherwise, we create a plMipmap and call into korlib to export the pixel data # Otherwise, we toss this layer and some info into our pending texture dict and process it
# when the exporter tells us to finalize all our shit
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:
# blender likes to create lots of spurious .0000001 objects :/ key = _Texture(texture)
name = texture.image.name if key not in self._pending:
name = name[:name.find('.')] print(" Stashing '{}' for conversion as '{}'".format(texture.image.name, str(key)))
if texture.use_mipmap: self._pending[key] = [layer,]
name = "{}.dds".format(name)
else:
name = "{}.bmp".format(name)
if name in self._hsbitmaps:
# well, that was easy...
print(" Using '{}'".format(name))
layer.texture = self._hsbitmaps[name].key
return
else: else:
location = self._mgr.get_textures_page(bo) print(" Found another user of '{}'".format(texture.image.name))
bitmap = self._TEMP_export_image(bo, name, texture) self._pending[key].append(layer)
# Store the created plBitmap and toss onto the layer def _export_texture_type_none(self, bo, hsgmat, layer, texture):
self._hsbitmaps[name] = bitmap # We'll allow this, just for sanity's sake...
layer.texture = bitmap.key pass
def _TEMP_export_image(self, bo, name, texture): def finalize(self):
print(" Exporting {}".format(name)) for key, layers in self._pending.items():
name = str(key)
print("\n[Mipmap '{}']".format(name))
image = texture.image image = key.image
oWidth, oHeight = image.size oWidth, oHeight = image.size
eWidth = int(round(pow(2, math.log(oWidth, 2)))) eWidth = int(round(pow(2, math.log(oWidth, 2))))
eHeight = int(round(pow(2, math.log(oHeight, 2)))) eHeight = int(round(pow(2, math.log(oHeight, 2))))
@ -197,31 +239,37 @@ class MaterialConverter:
print(" Image is not a POT ({}x{}) resizing to {}x{}".format(oWidth, oHeight, eWidth, eHeight)) print(" Image is not a POT ({}x{}) resizing to {}x{}".format(oWidth, oHeight, eWidth, eHeight))
image.scale(eWidth, eHeight) image.scale(eWidth, eHeight)
# Basic things # Some basic mipmap settings. Could this be done better?
levelHint = 0 if texture.use_mipmap else 1 levelHint = 0 if key.mipmap else 1
compression = plBitmap.kDirectXCompression if texture.use_mipmap else plBitmap.kUncompressed compression = plBitmap.kDirectXCompression if key.mipmap else plBitmap.kUncompressed
dxt = plBitmap.kDXT5 if texture.use_alpha or texture.use_calculate_alpha else plBitmap.kDXT1 dxt = plBitmap.kDXT5 if key.use_alpha or key.calc_alpha else plBitmap.kDXT1
# This wraps the call to plMipmap::Create # This wraps the call to plMipmap::Create
mipmap = plMipmap(name=name, width=eWidth, height=eHeight, numLevels=levelHint, mipmap = plMipmap(name=name, width=eWidth, height=eHeight, numLevels=levelHint,
compType=compression, format=plBitmap.kRGB8888, dxtLevel=dxt) compType=compression, format=plBitmap.kRGB8888, dxtLevel=dxt)
page = self._mgr.get_textures_page(bo)
self._mgr.AddObject(page, mipmap)
# Grab the image data from OpenGL and stuff it into the plBitmap
with _GLTexture(image) as glimage: with _GLTexture(image) as glimage:
if texture.use_mipmap: if key.mipmap:
print(" Generating mip levels")
glimage.generate_mipmap() glimage.generate_mipmap()
else:
print(" Stuffing image data")
stuff_func = mipmap.CompressImage if compression == plBitmap.kDirectXCompression else mipmap.setLevel stuff_func = mipmap.CompressImage if compression == plBitmap.kDirectXCompression else mipmap.setLevel
for i in range(mipmap.numLevels): for i in range(mipmap.numLevels):
data = glimage.get_level_data(i, texture.use_calculate_alpha) data = glimage.get_level_data(i, key.calc_alpha)
stuff_func(i, data) stuff_func(i, data)
return mipmap
# Now we poke our new bitmap into the pending layers. Note that we have to do some funny
def _export_texture_type_none(self, bo, hsgmat, layer, texture): # business to account for per-page textures
# We'll allow this, just for sanity's sake... print(" Adding to Layer(s)")
pass mgr = self._mgr
for layer in layers:
print(" {}".format(layer.key.name))
page = mgr.get_textures_page(layer)
mgr.AddObject(page, mipmap)
layer.texture = mipmap.key
@property @property
def _mgr(self): def _mgr(self):

Loading…
Cancel
Save