diff --git a/korman/exporter/convert.py b/korman/exporter/convert.py
index 789cce2..720c2b3 100644
--- a/korman/exporter/convert.py
+++ b/korman/exporter/convert.py
@@ -18,7 +18,10 @@ import os.path
from PyHSPlasma import *
from . import explosions
+from . import logger
from . import manager
+from . import mesh
+from . import utils
class Exporter:
# These are objects that we need to export as plSceneObjects
@@ -32,26 +35,34 @@ class Exporter:
return os.path.splitext(os.path.split(self._op.filepath)[1])[0]
def run(self):
- # Step 0: Init export resmgr and stuff
- self.mgr = manager.ExportManager(globals()[self._op.version])
+ with logger.ExportLogger("{}_export.log".format(self.age_name)) as _log:
+ # Step 0: Init export resmgr and stuff
+ self.mgr = manager.ExportManager(globals()[self._op.version])
+ self.mesh = mesh.MeshConverter()
+ self.report = logger.ExportAnalysis()
- # Step 1: Gather a list of objects that we need to export
- # We should do this first so we can sanity check
- # and give accurate progress reports
- self._collect_objects()
+ # Step 1: Gather a list of objects that we need to export
+ # We should do this first so we can sanity check
+ # and give accurate progress reports
+ self._collect_objects()
- # Step 2: Create the age info and the pages
- self._export_age_info()
+ # Step 2: Create the age info and the pages
+ self._export_age_info()
- # Step 2.9: Ensure that all Plasma Objects are in a valid page
- # This creates the default page if it is used
- self.mgr.sanity_check_object_pages(self.age_name, self._objects)
+ # Step 2.9: Ensure that all Plasma Objects are in a valid page
+ # This creates the default page if it is used
+ self.mgr.sanity_check_object_pages(self.age_name, self._objects)
- # Step 3: Export all the things!
- self._export_scene_objects()
+ # Step 3: Export all the things!
+ self._export_scene_objects()
- # Step 4: FINALLY. Let's write the PRPs and crap.
- self.mgr.save_age(self._op.filepath)
+ # Step 4: FINALLY. Let's write the PRPs and crap.
+ self.mgr.save_age(self._op.filepath)
+
+ # Step 4.1: Save out the export report.
+ # If the export fails and this doesn't save, we have bigger problems than
+ # these little warnings and notices.
+ self.report.save()
def _collect_objects(self):
for obj in bpy.data.objects:
@@ -72,9 +83,75 @@ class Exporter:
mgr.create_page(age_name, page.name, page.seq_suffix)
mgr.create_builtins(age_name, self._op.use_texture_page)
+ def _export_actor(self, so, bo):
+ """Exports a Coordinate Interface if we need one"""
+ empty = bo.type in {"CAMERA", "EMPTY", "LAMP"}
+ childobj = bo.parent is not None
+
+ if empty or childobj:
+ self._export_coordinate_interface(so, bo)
+
+ # If this object has a parent, then we will need to go upstream and add ourselves to the
+ # parent's CoordinateInterface... Because life just has to be backwards.
+ if childobj:
+ parent = bo.parent
+ if parent.plasma_object.enabled:
+ print("\tAttaching to parent SceneObject '{}'".format(parent.name))
+
+ # Instead of exporting a skeleton now, we'll just make an orphaned CI.
+ # The bl_obj export will make this work.
+ parent_ci = self.mgr.find_create_key(parent, plCoordinateInterface).object
+ parent_ci.addChild(so.key)
+ else:
+ self.report.warn("oversight",
+ "You have parented Plasma Object '{}' to '{}', which has not been marked for export. \
+ The object may not appear in the correct location or animate properly.".format(
+ bo.name, parent.name))
+
+ def _export_coordinate_interface(self, so, bo):
+ """Ensures that the SceneObject has a CoordinateInterface"""
+ if not so.coord:
+ ci = self.mgr.find_create_key(bo, plCoordinateInterface)
+ so.coord = ci
+ ci = ci.object
+ ci.owner = so.key
+
+ # Now we have the "fun" work of filling in the CI
+ ci.worldToLocal = utils.matrix44(bo.matrix_basis)
+ ci.localToWorld = ci.worldToLocal.inverse()
+ ci.parentToLocal = utils.matrix44(bo.matrix_local)
+ ci.localToParent = ci.parentToLocal.inverse()
+
def _export_scene_objects(self):
for bl_obj in self._objects:
- # Naive export all Plasma Objects. They will be responsible for calling back into the
- # exporter to find/create drawable meshes, materials, etc. Not sure if this design will
- # work well, but we're going to go with it for now.
- bl_obj.plasma_object.export(self, bl_obj)
\ No newline at end of file
+ print("=== Exporting plSceneObject ===")
+
+ # First pass: do things specific to this object type.
+ # note the function calls: to export a MESH, it's _export_mesh_blobj
+ export_fn = "_export_{}_blobj".format(bl_obj.type.lower())
+ try:
+ export_fn = getattr(self, export_fn)
+ except AttributeError:
+ print("WARNING: '{}' is a Plasma Object of Blender type '{}'".format(bl_obj.name, bl_obj.type))
+ print("... And I have NO IDEA what to do with that! Tossing.")
+ continue
+ print("\tBlender Object '{}' of type '{}'".format(bl_obj.name, bl_obj.type))
+
+ # Create a sceneobject if one does not exist.
+ # Before we call the export_fn, we need to determine if this object is an actor of any
+ # sort, and barf out a CI.
+ sceneobject = self.mgr.find_create_key(bl_obj, plSceneObject).object
+ self._export_actor(sceneobject, bl_obj)
+ export_fn(sceneobject, bl_obj)
+
+ # :(
+ print()
+
+ def _export_empty_blobj(self, so, bo):
+ # We don't need to do anything here. This function just makes sure we don't error out
+ # or add a silly special case :(
+ pass
+
+ def _export_mesh_blobj(self, so, bo):
+ # TODO
+ pass
\ No newline at end of file
diff --git a/korman/exporter/logger.py b/korman/exporter/logger.py
new file mode 100644
index 0000000..2145ddb
--- /dev/null
+++ b/korman/exporter/logger.py
@@ -0,0 +1,72 @@
+# This file is part of Korman.
+#
+# Korman is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Korman is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Korman. If not, see .
+
+import sys
+
+class ExportAnalysis:
+ """This is used to collect artist action items from the export process. You can warn about
+ portability issues, possible oversights, etc. The benefit here is that the user doesn't have
+ to look through all of the gobbledygook in the export log.
+ """
+
+ _notices = {}
+ _warnings = {}
+
+ def save(self):
+ # TODO
+ pass
+
+ def _stash(self, _d, category, message):
+ if category not in _d:
+ _d[category] = [message,]
+ else:
+ _d[category].append(message)
+
+ def note(self, category, message):
+ self._stash(self._notices, category, message)
+ print("NOTICE {}: {}".format(category, message))
+
+ def warn(self, category, message):
+ self._stash(self._warnings, category, message)
+ print("WARNING {}: {}".format(category, message))
+
+
+class ExportLogger:
+ """Yet Another Logger(TM)"""
+
+ def __init__(self, fn):
+ self._stdout = sys.stdout
+ self._stderr = sys.stderr
+ self._file = open(fn, "w")
+
+ for i in dir(self._file):
+ if not hasattr(self, i):
+ setattr(self, i, getattr(self._file, i))
+
+ def __enter__(self):
+ sys.stdout = self._file
+ sys.stderr = self._file
+
+ def __exit__(self, type, value, traceback):
+ sys.stdout = self._stdout
+ sys.stderr = self._stderr
+
+ def write(self, str):
+ self._file.write(str)
+ self._stdout.write(str)
+
+ def writelines(self, seq):
+ self._file.writelines(seq)
+ self._stdout.writelines(seq)
diff --git a/korman/exporter/manager.py b/korman/exporter/manager.py
index 6d7705d..2fe7e07 100644
--- a/korman/exporter/manager.py
+++ b/korman/exporter/manager.py
@@ -109,12 +109,17 @@ class ExportManager:
self._nodes[location] = None
return location
- def find_key(self, bl_obj, index):
- """Given a blender Object and a pCre index, find an exported plKey"""
+ def find_create_key(self, bl_obj, pClass):
+ key = self.find_key(bl_obj, pClass)
+ if key is None:
+ key = self.add_object(pl=pClass, bl=bl_obj).key
+ return key
+
+ def find_key(self, bl_obj, pClass):
+ """Given a blender Object and a Plasma class, find (or create) an exported plKey"""
location = self._pages[bl_obj.plasma_object.page]
- # NOTE: may need to replace with a python side dict for faster lookups
- # evaluate when exporter has been fleshed out
+ index = plFactory.ClassIndex(pClass.__name__)
for key in self.mgr.getKeys(location, index):
if bl_obj.name == key.name:
return key
diff --git a/korman/exporter/mesh.py b/korman/exporter/mesh.py
new file mode 100644
index 0000000..21ae4f3
--- /dev/null
+++ b/korman/exporter/mesh.py
@@ -0,0 +1,21 @@
+# This file is part of Korman.
+#
+# Korman is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Korman is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Korman. If not, see .
+
+import bpy
+from PyHSPlasma import *
+
+class MeshConverter:
+ # TODO
+ pass
diff --git a/korman/exporter/utils.py b/korman/exporter/utils.py
new file mode 100644
index 0000000..2feb872
--- /dev/null
+++ b/korman/exporter/utils.py
@@ -0,0 +1,26 @@
+# This file is part of Korman.
+#
+# Korman is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Korman is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Korman. If not, see .
+
+from PyHSPlasma import *
+
+def matrix44(blmat):
+ """Converts a mathutils.Matrix to an hsMatrix44"""
+ hsmat = hsMatrix44()
+ for i in range(4):
+ hsmat[0, i] = blmat[i][0]
+ hsmat[1, i] = blmat[i][1]
+ hsmat[2, i] = blmat[i][2]
+ hsmat[3, i] = blmat[i][3]
+ return hsmat
diff --git a/korman/properties/prop_object.py b/korman/properties/prop_object.py
index f21a468..3a23474 100644
--- a/korman/properties/prop_object.py
+++ b/korman/properties/prop_object.py
@@ -51,14 +51,6 @@ class PlasmaObject(bpy.types.PropertyGroup):
o.plasma_object.page = page.name
break
- def export(self, exporter, bl_obj):
- """Plasma Object Export"""
-
- # This is where the magic happens...
- if self.enabled:
- # TODO: Something more useful than a blank object.
- exporter.mgr.add_object(plSceneObject, bl=bl_obj)
-
enabled = BoolProperty(name="Export",
description="Export this as a discrete object",