mirror of https://github.com/H-uru/korman.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
6.6 KiB
162 lines
6.6 KiB
# 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 <http://www.gnu.org/licenses/>. |
|
|
|
import bpy |
|
import os.path |
|
from PyHSPlasma import * |
|
|
|
from . import explosions |
|
from . import logger |
|
from . import manager |
|
from . import mesh |
|
from . import utils |
|
|
|
class Exporter: |
|
def __init__(self, op): |
|
self._op = op # Blender export operator |
|
self._objects = [] |
|
|
|
@property |
|
def age_name(self): |
|
return os.path.splitext(os.path.split(self._op.filepath)[1])[0] |
|
|
|
def run(self): |
|
with logger.ExportLogger("{}_export.log".format(self.age_name)) as _log: |
|
print("Exporting '{}.age'".format(self.age_name)) |
|
|
|
# Step 0: Init export resmgr and stuff |
|
self.mgr = manager.ExportManager(globals()[self._op.version]) |
|
self.mesh = mesh.MeshConverter(self) |
|
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 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 3: Export all the things! |
|
self._export_scene_objects() |
|
|
|
# Step 3.9: Finalize geometry... |
|
self.mesh.finalize() |
|
|
|
# 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: |
|
if obj.plasma_object.enabled: |
|
self._objects.append(obj) |
|
|
|
def _export_age_info(self): |
|
# Make life slightly easier... |
|
age_info = bpy.context.scene.world.plasma_age |
|
age_name = self.age_name |
|
mgr = self.mgr |
|
|
|
# Generate the plAgeInfo |
|
mgr.AddAge(age_info.export(self)) |
|
|
|
# Create all the pages we need |
|
for page in age_info.pages: |
|
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(" Attaching 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("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 |
|
|
|
# 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: |
|
print("\n=== 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(" Blender 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) |
|
|
|
# And now we puke out the modifiers... |
|
for mod in bl_obj.plasma_modifiers.modifiers: |
|
print(" Exporting '{}' modifier as '{}'".format(mod.bl_label, mod.display_name)) |
|
mod.export(self, bl_obj, sceneobject) |
|
|
|
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): |
|
if bo.data.materials: |
|
so.draw = self.mesh.export_object(bo) |
|
else: |
|
print(" No material(s) on the ObData, so no drawables")
|
|
|