diff --git a/korlib/texture.cpp b/korlib/texture.cpp index af4f0f6..63d3975 100644 --- a/korlib/texture.cpp +++ b/korlib/texture.cpp @@ -266,14 +266,19 @@ static int _generate_detail_map(pyGLTexture* self, uint8_t* buf, size_t bufsz, G return 0; } -static _LevelData _get_level_data(pyGLTexture* self, GLint level, bool bgra, bool quiet) { +static _LevelData _get_level_data(pyGLTexture* self, GLint level, bool bgra, PyObject* report) { GLint width, height; glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_HEIGHT, &height); GLenum fmt = bgra ? GL_BGRA_EXT : GL_RGBA; - if (!quiet) - PySys_WriteStdout(" Level #%i: %ix%i\n", level, width, height); + // Print out the debug message + if (report && report != Py_None) { + PyObjectRef msg_func = PyObject_GetAttrString(report, "msg"); + PyObjectRef args = Py_BuildValue("siii", "Level #{}: {}x{}", level, width, height); + PyObjectRef kwargs = Py_BuildValue("{s:i}", "indent", 2); + PyObjectRef result = PyObject_Call(msg_func, args, kwargs); + } size_t bufsz; bufsz = (width * height * 4); @@ -284,18 +289,18 @@ static _LevelData _get_level_data(pyGLTexture* self, GLint level, bool bgra, boo static PyObject* pyGLTexture_get_level_data(pyGLTexture* self, PyObject* args, PyObject* kwargs) { static char* kwlist[] = { _pycs("level"), _pycs("calc_alpha"), _pycs("bgra"), - _pycs("quiet"), _pycs("fast"), NULL }; + _pycs("report"), _pycs("fast"), NULL }; GLint level = 0; bool calc_alpha = false; bool bgra = false; - bool quiet = false; + PyObject* report = nullptr; bool fast = false; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ibbbb", kwlist, &level, &calc_alpha, &bgra, &quiet, &fast)) { - PyErr_SetString(PyExc_TypeError, "get_level_data expects an optional int, bool, bool, bool, bool"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ibbOb", kwlist, &level, &calc_alpha, &bgra, &report, &fast)) { + PyErr_SetString(PyExc_TypeError, "get_level_data expects an optional int, bool, bool, obejct, bool"); return NULL; } - _LevelData data = _get_level_data(self, level, bgra, quiet); + _LevelData data = _get_level_data(self, level, bgra, report); if (fast) return pyBuffer_Steal(data.m_data, data.m_dataSize); @@ -372,7 +377,7 @@ static PyMethodDef pyGLTexture_Methods[] = { }; static PyObject* pyGLTexture_get_has_alpha(pyGLTexture* self, void*) { - _LevelData data = _get_level_data(self, 0, false, true); + _LevelData data = _get_level_data(self, 0, false, nullptr); for (size_t i = 3; i < data.m_dataSize; i += 4) { if (data.m_data[i] != 255) { delete[] data.m_data; diff --git a/korman/exporter/convert.py b/korman/exporter/convert.py index 4e26fe0..9416588 100644 --- a/korman/exporter/convert.py +++ b/korman/exporter/convert.py @@ -42,14 +42,13 @@ class Exporter: return Path(self._op.filepath).stem def run(self): - with logger.ExportLogger(self._op.filepath) as _log: - print("Exporting '{}.age'".format(self.age_name)) + with logger.ExportLogger(self._op.filepath) as self.report: + self.report.msg("Exporting '{}.age'", self.age_name) start = time.perf_counter() # Step 0: Init export resmgr and stuff self.mgr = manager.ExportManager(self) self.mesh = mesh.MeshConverter(self) - self.report = logger.ExportAnalysis() self.physics = physics.PhysicsConverter(self) self.light = rtlight.LightConverter(self) self.animation = animation.AnimationConverter(self) @@ -95,10 +94,10 @@ class Exporter: # And finally we crow about how awesomely fast we are... end = time.perf_counter() - print("\nExported {}.age in {:.2f} seconds".format(self.age_name, end-start)) + self.report.msg("\nExported {}.age in {:.2f} seconds", self.age_name, end-start) def _bake_static_lighting(self): - oven = etlight.LightBaker() + oven = etlight.LightBaker(self.report) oven.bake_static_lighting(self._objects) def _collect_objects(self): @@ -163,7 +162,7 @@ class Exporter: parent = bo.parent if parent is not None: if parent.plasma_object.enabled: - print(" Attaching to parent SceneObject '{}'".format(parent.name)) + self.report.msg("Attaching to parent SceneObject '{}'", parent.name, indent=1) parent_ci = self._export_coordinate_interface(None, parent) parent_ci.addChild(so.key) else: @@ -187,8 +186,9 @@ class Exporter: return so.coord.object def _export_scene_objects(self): + log_msg = self.report.msg for bl_obj in self._objects: - print("\n[SceneObject '{}']".format(bl_obj.name)) + log_msg("\n[SceneObject '{}']".format(bl_obj.name)) # First pass: do things specific to this object type. # note the function calls: to export a MESH, it's _export_mesh_blobj @@ -196,10 +196,10 @@ class Exporter: 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.") + self.report.warn("""'{}' is a Plasma Object of Blender type '{}' + ... And I have NO IDEA what to do with that! Tossing.""".format(bl_obj.name, bl_obj.type)) continue - print(" Blender Object '{}' of type '{}'".format(bl_obj.name, bl_obj.type)) + log_msg("Blender Object '{}' of type '{}'".format(bl_obj.name, bl_obj.type), indent=1) # 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 @@ -211,7 +211,7 @@ class Exporter: # And now we puke out the modifiers... for mod in bl_obj.plasma_modifiers.modifiers: - print(" Exporting '{}' modifier as '{}'".format(mod.bl_label, mod.key_name)) + log_msg("Exporting '{}' modifier".format(mod.bl_label), indent=1) mod.export(self, bl_obj, sceneobject) def _export_empty_blobj(self, so, bo): @@ -227,14 +227,14 @@ class Exporter: if bo.data.materials: self.mesh.export_object(bo) else: - print(" No material(s) on the ObData, so no drawables") + self.report.msg("No material(s) on the ObData, so no drawables", indent=1) def _export_referenced_node_trees(self): - print("\nChecking Logic Trees...") + self.report.msg("\nChecking Logic Trees...") need_to_export = ((name, bo, so) for name, (bo, so) in self.want_node_trees.items() if name not in self.node_trees_exported) for tree, bo, so in need_to_export: - print(" NodeTree '{}'".format(tree)) + self.report.msg("NodeTree '{}'", tree, indent=1) bpy.data.node_groups[tree].export(self, bo, so) def _harvest_actors(self): @@ -269,8 +269,6 @@ class Exporter: return False def _post_process_scene_objects(self): - print("\nPostprocessing SceneObjects...") - mat_mgr = self.mesh.material for bl_obj in self._objects: sceneobject = self.mgr.find_object(plSceneObject, bl=bl_obj) @@ -292,5 +290,4 @@ class Exporter: for mod in bl_obj.plasma_modifiers.modifiers: proc = getattr(mod, "post_export", None) if proc is not None: - print(" '{}' modifier '{}'".format(bl_obj.name, mod.key_name)) proc(self, bl_obj, sceneobject) diff --git a/korman/exporter/etlight.py b/korman/exporter/etlight.py index ab93089..c938520 100644 --- a/korman/exporter/etlight.py +++ b/korman/exporter/etlight.py @@ -16,6 +16,7 @@ import bpy from bpy.app.handlers import persistent +from .logger import ExportLogger from .mesh import _VERTEX_COLOR_LAYERS from ..helpers import * @@ -24,8 +25,9 @@ _NUM_RENDER_LAYERS = 20 class LightBaker: """ExportTime Lighting""" - def __init__(self): + def __init__(self, report=None): self._lightgroups = {} + self._report = report if report is not None else ExportLogger() self._uvtexs = {} def _apply_render_settings(self, toggle, vcols): @@ -63,7 +65,7 @@ class LightBaker: def bake_static_lighting(self, objs): """Bakes all static lighting for Plasma geometry""" - print("\nBaking Static Lighting...") + self._report.msg("\nBaking Static Lighting...") bake = self._harvest_bakable_objects(objs) with GoodNeighbor() as toggle: @@ -82,24 +84,26 @@ class LightBaker: bpy.context.scene.layers = (True,) * _NUM_RENDER_LAYERS # Step 1: Prepare... Apply UVs, etc, etc, etc - print(" Preparing to bake...") + self._report.msg("Preparing to bake...", indent=1) for key in bake.keys(): if key[0] == "lightmap": for i in range(len(bake[key])-1, -1, -1): obj = bake[key][i] if not self._prep_for_lightmap(obj, toggle): - print(" Lightmap '{}' will not be baked -- no applicable lights".format(obj.name)) + self._report.msg("Lightmap '{}' will not be baked -- no applicable lights", + obj.name, indent=2) bake[key].pop(i) elif key[0] == "vcol": for i in range(len(bake[key])-1, -1, -1): obj = bake[key][i] if not self._prep_for_vcols(obj, toggle): if self._has_valid_material(obj): - print(" VCols '{}' will not be baked -- no applicable lights".format(obj.name)) + self._report.msg("VCols '{}' will not be baked -- no applicable lights", + obj.name, indent=2) bake[key].pop(i) else: raise RuntimeError(key[0]) - print(" ...") + self._report.msg(" ...") # Step 2: BAKE! for key, value in bake.items(): @@ -107,10 +111,10 @@ class LightBaker: continue if key[0] == "lightmap": - print(" {} Lightmap(s) [H:{:X}]".format(len(value), hash(key))) + self._report.msg("{} Lightmap(s) [H:{:X}]", len(value), hash(key), indent=1) self._bake_lightmaps(value, key[1:]) elif key[0] == "vcol": - print(" {} Crap Light(s)".format(len(value))) + self._report.msg("{} Crap Light(s)", len(value), indent=1) self._bake_vcols(value) else: raise RuntimeError(key[0]) diff --git a/korman/exporter/logger.py b/korman/exporter/logger.py index e8dc566..b12d8d2 100644 --- a/korman/exporter/logger.py +++ b/korman/exporter/logger.py @@ -16,61 +16,62 @@ from pathlib import Path 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. - """ - - _porting = [] - _warnings = [] - - def save(self): - # TODO - pass - - def port(self, message, indent=0): - self._porting.append(message) - print(" " * indent, end="") - print("PORTING: {}".format(message)) - - def warn(self, message, indent=0): - self._warnings.append(message) - print(" " * indent, end="") - print("WARNING: {}".format(message)) - - class ExportLogger: - """Yet Another Logger(TM)""" + def __init__(self, age_path=None): + self._porting = [] + self._warnings = [] + self._age_path = age_path + self._file = None + + def __enter__(self): + assert self._age_path is not None - def __init__(self, ageFile): # Make the log file name from the age file path -- this ensures we're not trying to write # the log file to the same directory Blender.exe is in, which might be a permission error - my_path = Path(ageFile) + my_path = Path(self._age_path) my_path = my_path.with_name("{}_export".format(my_path.stem)).with_suffix(".log") self._file = open(str(my_path), "w") - - for i in dir(self._file): - if not hasattr(self, i): - setattr(self, i, getattr(self._file, i)) - - def __enter__(self): - self._stdout, sys.stdout = sys.stdout, self._file - self._stderr, sys.stderr = sys.stderr, self._file + return self def __exit__(self, type, value, traceback): - sys.stdout = self._stdout - sys.stderr = self._stderr + self._file.close() + return False - def flush(self): - self._file.flush() - self._stdout.flush() - self._stderr.flush() + def msg(self, *args, **kwargs): + assert args + indent = kwargs.get("indent", 0) + msg = "{}{}".format(" " * indent, args[0]) + if len(args) > 1: + msg = msg.format(*args[1:], **kwargs) + if self._file is None: + print(msg) + else: + self._file.writelines((msg, "\n")) - def write(self, str): - self._file.write(str) - self._stdout.write(str) + def port(self, *args, **kwargs): + assert args + indent = kwargs.get("indent", 0) + msg = "{}PORTING: {}".format(" " * indent, args[0]) + if len(args) > 1: + msg = msg.format(*args[1:], **kwargs) + if self._file is None: + print(msg) + else: + self._file.writelines((msg, "\n")) + self._porting.append(args[0]) + + def save(self): + # TODO + pass - def writelines(self, seq): - self._file.writelines(seq) - self._stdout.writelines(seq) + def warn(self, *args, **kwargs): + assert args + indent = kwargs.get("indent", 0) + msg = "{}WARNING: {}".format(" " * indent, args[0]) + if len(args) > 1: + msg = msg.format(*args[1:], **kwargs) + if self._file is None: + print(msg) + else: + self._file.writelines((msg, "\n")) + self._warnings.append(args[0]) diff --git a/korman/exporter/material.py b/korman/exporter/material.py index edeb1b6..43d769b 100644 --- a/korman/exporter/material.py +++ b/korman/exporter/material.py @@ -125,7 +125,7 @@ class MaterialConverter: def export_material(self, bo, bm): """Exports a Blender Material as an hsGMaterial""" - print(" Exporting Material '{}'".format(bm.name)) + self._report.msg("Exporting Material '{}'", bm.name, indent=1) hsgmat = self._mgr.add_object(hsGMaterial, name=bm.name, bl=bo) slots = [(idx, slot) for idx, slot in enumerate(bm.texture_slots) if slot is not None and slot.use \ @@ -198,7 +198,7 @@ class MaterialConverter: return hsgmat.key def export_waveset_material(self, bo, bm): - print(" Exporting WaveSet Material '{}'".format(bm.name)) + self._report.msg("Exporting WaveSet Material '{}'", bm.name, indent=1) # WaveSets MUST have their own material unique_name = "{}_WaveSet7".format(bm.name) @@ -215,7 +215,7 @@ class MaterialConverter: def export_bumpmap_slot(self, bo, bm, hsgmat, slot, idx): name = "{}_{}".format(bm.name if bm is not None else bo.name, slot.name) - print(" Exporting Plasma Bumpmap Layers for '{}'".format(name)) + self._report.msg("Exporting Plasma Bumpmap Layers for '{}'", name, indent=2) # Okay, now we need to make 3 layers for the Du, Dw, and Dv du_layer = self._mgr.add_object(plLayer, name="{}_DU_BumpLut".format(name), bl=bo) @@ -264,7 +264,7 @@ class MaterialConverter: def export_texture_slot(self, bo, bm, hsgmat, slot, idx, name=None, blend_flags=True): if name is None: name = "{}_{}".format(bm.name if bm is not None else bo.name, slot.name) - print(" Exporting Plasma Layer '{}'".format(name)) + self._report.msg("Exporting Plasma Layer '{}'", name, indent=2) layer = self._mgr.add_object(plLayer, name=name, bl=bo) if bm is not None and not slot.use_map_normal: self._propagate_material_settings(bm, layer) @@ -274,10 +274,10 @@ class MaterialConverter: for i, uvchan in enumerate(bo.data.uv_layers): if uvchan.name == slot.uv_layer: layer.UVWSrc = i - print(" Using UV Map #{} '{}'".format(i, name)) + self._report.msg("Using UV Map #{} '{}'", i, name, indent=3) break else: - print(" No UVMap specified... Blindly using the first one, maybe it exists :|") + self._report.msg("No UVMap specified... Blindly using the first one, maybe it exists :|", indent=3) # Transform xform = hsMatrix44() @@ -447,7 +447,8 @@ class MaterialConverter: name = "{}_DynEnvMap".format(viewpt.name) pl_env = self._mgr.find_object(pl_class, bl=bo, name=name) if pl_env is not None: - print(" EnvMap for viewpoint {} already exported... NOTE: Your settings here will be overridden by the previous object!".format(viewpt.name)) + self._report.msg("EnvMap for viewpoint {} already exported... NOTE: Your settings here will be overridden by the previous object!", + viewpt.name, indent=3) if isinstance(pl_env, plDynamicCamMap): pl_env.addTargetNode(self._mgr.find_key(plSceneObject, bl=bo)) pl_env.addMatLayer(layer.key) @@ -457,7 +458,7 @@ class MaterialConverter: oRes = bl_env.resolution eRes = helpers.ensure_power_of_two(oRes) if oRes != eRes: - print(" Overriding EnvMap size to ({}x{}) -- POT".format(eRes, eRes)) + self._report.msg("Overriding EnvMap size to ({}x{}) -- POT", eRes, eRes, indent=3) # And now for the general ho'hum-ness pl_env = self._mgr.add_object(pl_class, bl=bo, name=name) @@ -595,10 +596,11 @@ class MaterialConverter: 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: - print(" Stashing '{}' for conversion as '{}'".format(texture.image.name, str(key))) + self._report.msg("Stashing '{}' for conversion as '{}'", + texture.image.name, str(key), indent=3) self._pending[key] = [layer.key,] else: - print(" Found another user of '{}'".format(texture.image.name)) + self._report.msg("Found another user of '{}'", texture.image.name, indent=3) self._pending[key].append(layer.key) def _export_texture_type_none(self, bo, layer, texture): @@ -609,16 +611,16 @@ class MaterialConverter: """This exports an externally prepared layer and image""" key = _Texture(image=image) if key not in self._pending: - print(" Stashing '{}' for conversion as '{}'".format(image.name, str(key))) + self._report.msg("Stashing '{}' for conversion as '{}'", image.name, key, indent=2) self._pending[key] = [layer.key,] else: - print(" Found another user of '{}'".format(key)) + self._report.msg("Found another user of '{}'", key, indent=2) self._pending[key].append(layer.key) def finalize(self): for key, layers in self._pending.items(): name = str(key) - print("\n[Mipmap '{}']".format(name)) + self._report.msg("\n[Mipmap '{}']", name) image = key.image oWidth, oHeight = image.size @@ -628,7 +630,8 @@ class MaterialConverter: eWidth = helpers.ensure_power_of_two(oWidth) eHeight = helpers.ensure_power_of_two(oHeight) if (eWidth != oWidth) or (eHeight != oHeight): - print(" Image is not a POT ({}x{}) resizing to {}x{}".format(oWidth, oHeight, eWidth, eHeight)) + self._report.msg("Image is not a POT ({}x{}) resizing to {}x{}", + oWidth, oHeight, eWidth, eHeight, indent=1) self._resize_image(image, eWidth, eHeight) # Some basic mipmap settings. @@ -640,11 +643,11 @@ class MaterialConverter: with helper as glimage: if key.mipmap: numLevels = glimage.num_levels - print(" Generating mip levels") + self._report.msg("Generating mip levels", indent=1) glimage.generate_mipmap() else: numLevels = 1 - print(" Stuffing image data") + self._report.msg("Stuffing image data", indent=1) # Uncompressed bitmaps are BGRA fmt = compression == plBitmap.kUncompressed @@ -653,7 +656,7 @@ class MaterialConverter: # this mipmap for per-page textures :( data = [] for i in range(numLevels): - data.append(glimage.get_level_data(i, key.calc_alpha, fmt)) + data.append(glimage.get_level_data(i, key.calc_alpha, fmt, report=self._report)) # Be a good citizen and reset the Blender Image to pre-futzing state image.reload() @@ -663,9 +666,9 @@ class MaterialConverter: mgr = self._mgr pages = {} - print(" Adding to Layer(s)") + self._report.msg("Adding to Layer(s)", indent=1) for layer in layers: - print(" {}".format(layer.name)) + self._report.msg(layer.name, indent=2) page = mgr.get_textures_page(layer) # Layer's page or Textures.prp # If we haven't created this plMipmap in the page (either layer's page or Textures.prp), @@ -722,6 +725,10 @@ class MaterialConverter: layer.runtime = utils.color(bm.diffuse_color) layer.specular = utils.color(bm.specular_color) + @property + def _report(self): + return self._exporter().report + def _resize_image(self, image, width, height): image.scale(width, height) image.update() diff --git a/korman/exporter/mesh.py b/korman/exporter/mesh.py index 98fb63c..2aa2692 100644 --- a/korman/exporter/mesh.py +++ b/korman/exporter/mesh.py @@ -177,8 +177,8 @@ class MeshConverter: for loc in self._dspans.values(): for dspan in loc.values(): - print("\n[DrawableSpans '{}']".format(dspan.key.name)) - print(" Composing geometry data") + self._report.msg("\n[DrawableSpans '{}']", dspan.key.name) + self._report.msg("Composing geometry data", indent=1) # This mega-function does a lot: # 1. Converts SourceSpans (geospans) to Icicles and bakes geometry into plGBuffers @@ -189,7 +189,7 @@ class MeshConverter: # Might as well say something else just to fascinate anyone who is playing along # at home (and actually enjoys reading these lawgs) - print(" Bounds and SpaceTree in the saddle") + self._report.msg("Bounds and SpaceTree in the saddle", indent=1) def _export_geometry(self, bo, mesh, materials, geospans): geodata = [_GeoData(len(mesh.vertices)) for i in materials] @@ -422,7 +422,8 @@ class MeshConverter: _diindices = {} for geospan, pass_index in geospans: dspan = self._find_create_dspan(bo, geospan.material.object, pass_index) - print(" Exported hsGMaterial '{}' geometry into '{}'".format(geospan.material.name, dspan.key.name)) + self._report.msg("Exported hsGMaterial '{}' geometry into '{}'", + geospan.material.name, dspan.key.name, indent=1) idx = dspan.addSourceSpan(geospan) if dspan not in _diindices: _diindices[dspan] = [idx,] @@ -497,3 +498,7 @@ class MeshConverter: @property def _mgr(self): return self._exporter().mgr + + @property + def _report(self): + return self._exporter().report diff --git a/korman/exporter/rtlight.py b/korman/exporter/rtlight.py index d1790ce..c249218 100644 --- a/korman/exporter/rtlight.py +++ b/korman/exporter/rtlight.py @@ -43,19 +43,19 @@ class LightConverter: # If you change these calculations, be sure to update the AnimationConverter! intens, attenEnd = self.convert_attenuation(bl) if bl.falloff_type == "CONSTANT": - print(" Attenuation: No Falloff") + self._report.msg("Attenuation: No Falloff", indent=2) pl.attenConst = intens pl.attenLinear = 0.0 pl.attenQuadratic = 0.0 pl.attenCutoff = attenEnd elif bl.falloff_type == "INVERSE_LINEAR": - print(" Attenuation: Inverse Linear") + self._report.msg("Attenuation: Inverse Linear", indent=2) pl.attenConst = 1.0 pl.attenLinear = self.convert_attenuation_linear(intens, attenEnd) pl.attenQuadratic = 0.0 pl.attenCutoff = attenEnd elif bl.falloff_type == "INVERSE_SQUARE": - print(" Attenuation: Inverse Square") + self._report.msg("Attenuation: Inverse Square", indent=2) pl.attenConst = 1.0 pl.attenLinear = 0.0 pl.attenQuadratic = self.convert_attenuation_quadratic(intens, attenEnd) @@ -75,18 +75,18 @@ class LightConverter: return max(0.0, (intensity * _FAR_POWER - 1.0) / pow(end, 2)) def _convert_area_lamp(self, bl, pl): - print(" [LimitedDirLightInfo '{}']".format(bl.name)) + self._report.msg("[LimitedDirLightInfo '{}']", bl.name, indent=1) pl.width = bl.size pl.depth = bl.size if bl.shape == "SQUARE" else bl.size_y pl.height = bl.plasma_lamp.size_height def _convert_point_lamp(self, bl, pl): - print(" [OmniLightInfo '{}']".format(bl.name)) + self._report.msg("[OmniLightInfo '{}']", bl.name, indent=1) self._convert_attenuation(bl, pl) def _convert_spot_lamp(self, bl, pl): - print(" [SpotLightInfo '{}']".format(bl.name)) + self._report.msg("[SpotLightInfo '{}']", bl.name, indent=1) self._convert_attenuation(bl, pl) # Spot lights have a few more things... @@ -102,7 +102,7 @@ class LightConverter: pl.falloff = 1.0 def _convert_sun_lamp(self, bl, pl): - print(" [DirectionalLightInfo '{}']".format(bl.name)) + self._report.msg("[DirectionalLightInfo '{}']", bl.name, indent=1) def export_rtlight(self, so, bo): bl_light = bo.data @@ -132,18 +132,18 @@ class LightConverter: # Apply the colors if bl_light.use_diffuse and not shadow_only: - print(" Diffuse: {}".format(diff_str)) + self._report.msg("Diffuse: {}", diff_str, indent=2) pl_light.diffuse = hsColorRGBA(*diff_color) else: - print(" Diffuse: OFF") + self._report.msg("Diffuse: OFF", indent=2) pl_light.diffuse = hsColorRGBA(0.0, 0.0, 0.0, energy) if bl_light.use_specular and not shadow_only: - print(" Specular: {}".format(spec_str)) + self._report.msg("Specular: {}", spec_str, indent=2) pl_light.setProperty(plLightInfo.kLPHasSpecular, True) pl_light.specular = hsColorRGBA(*spec_color) else: - print(" Specular: OFF") + self._report.msg("Specular: OFF", indent=2) pl_light.specular = hsColorRGBA(0.0, 0.0, 0.0, energy) rtlamp = bl_light.plasma_lamp @@ -202,7 +202,7 @@ class LightConverter: # projection Lamp with our own faux Material. Unfortunately, Plasma only supports projecting # one layer. We could exploit the fUnderLay and fOverLay system to export everything, but meh. if len(tex_slots) > 1: - self._exporter().warn("Only one texture slot can be exported per Lamp. Picking the first one: '{}'".format(slot.name), indent=3) + self._report.warn("Only one texture slot can be exported per Lamp. Picking the first one: '{}'".format(slot.name), indent=3) layer = mat.export_texture_slot(bo, None, None, slot, 0, blend_flags=False) state = layer.state @@ -243,7 +243,7 @@ class LightConverter: def find_material_light_keys(self, bo, bm): """Given a blender material, we find the keys of all matching Plasma RT Lights. NOTE: We return a tuple of lists: ([permaLights], [permaProjs])""" - print(" Searching for runtime lights...") + self._report.msg("Searching for runtime lights...", indent=1) permaLights = [] permaProjs = [] @@ -272,16 +272,17 @@ class LightConverter: break else: # didn't find a layer where both lamp and object were, skip it. - print(" [{}] '{}': not in same layer, skipping...".format(lamp.type, obj.name)) + self._report.msg("[{}] '{}': not in same layer, skipping...", + lamp.type, obj.name, indent=2) continue # This is probably where PermaLight vs PermaProj should be sorted out... pl_light = self.get_light_key(obj, lamp, None) if self._is_projection_lamp(lamp): - print(" [{}] PermaProj '{}'".format(lamp.type, obj.name)) + self._report.msg("[{}] PermaProj '{}'", lamp.type, obj.name, indent=2) permaProjs.append(pl_light) else: - print(" [{}] PermaLight '{}'".format(lamp.type, obj.name)) + self._report.msg("[{}] PermaLight '{}'", lamp.type, obj.name, indent=2) permaLights.append(pl_light) return (permaLights, permaProjs) @@ -308,3 +309,7 @@ class LightConverter: @property def mgr(self): return self._exporter().mgr + + @property + def _report(self): + return self._exporter().report diff --git a/korman/korlib/texture.py b/korman/korlib/texture.py index 11a289e..194add9 100644 --- a/korman/korlib/texture.py +++ b/korman/korlib/texture.py @@ -76,14 +76,14 @@ class GLTexture: # It will simplify our state tracking a bit. bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_GENERATE_MIPMAP, 1) - def get_level_data(self, level=0, calc_alpha=False, bgra=False, quiet=False, fast=False): + def get_level_data(self, level=0, calc_alpha=False, bgra=False, report=None, fast=False): """Gets the uncompressed pixel data for a requested mip level, optionally calculating the alpha channel from the image color data """ width = self._get_tex_param(bgl.GL_TEXTURE_WIDTH, level) height = self._get_tex_param(bgl.GL_TEXTURE_HEIGHT, level) - if not quiet: - print(" Level #{}: {}x{}".format(level, width, height)) + if report is not None: + report.msg("Level #{}: {}x{}", level, width, height, indent=2) # Grab the image data size = width * height * 4 @@ -138,7 +138,7 @@ class GLTexture: @property def has_alpha(self): - data = self.get_level_data(quiet=True, fast=True) + data = self.get_level_data(report=None, fast=True) for i in range(3, len(data), 4): if data[i] != 255: return True diff --git a/korman/nodes/node_conditions.py b/korman/nodes/node_conditions.py index 43c078e..d4fec71 100644 --- a/korman/nodes/node_conditions.py +++ b/korman/nodes/node_conditions.py @@ -427,18 +427,18 @@ class PlasmaVolumeSensorNode(PlasmaNodeBase, bpy.types.Node): suffix = "Exit" theName = "{}_{}_{}".format(self.id_data.name, self.name, suffix) - print(" [LogicModifier '{}']".format(theName)) + exporter.report.msg("[LogicModifier '{}']", theName, indent=2) logicKey = exporter.mgr.find_create_key(plLogicModifier, name=theName, so=so) logicmod = logicKey.object logicmod.setLogicFlag(plLogicModifier.kMultiTrigger, True) logicmod.notify = self.generate_notify_msg(exporter, so, "satisfies") # Now, the detector objects - print(" [ObjectInVolumeDetector '{}']".format(theName)) + exporter.report.msg("[ObjectInVolumeDetector '{}']", theName, indent=2) detKey = exporter.mgr.find_create_key(plObjectInVolumeDetector, name=theName, so=so) det = detKey.object - print(" [VolumeSensorConditionalObject '{}']".format(theName)) + exporter.report.msg("[VolumeSensorConditionalObject '{}']", theName, indent=2) volKey = exporter.mgr.find_create_key(plVolumeSensorConditionalObject, name=theName, so=so) volsens = volKey.object diff --git a/korman/properties/modifiers/render.py b/korman/properties/modifiers/render.py index 97a7715..dcad670 100644 --- a/korman/properties/modifiers/render.py +++ b/korman/properties/modifiers/render.py @@ -427,10 +427,10 @@ class PlasmaVisControl(PlasmaModifierProperties): else: this_sv = bo.plasma_modifiers.softvolume if this_sv.enabled: - print(" [VisRegion] I'm a SoftVolume myself :)") + exporter.report.msg("[VisRegion] I'm a SoftVolume myself :)", indent=1) rgn.region = this_sv.get_key(exporter, so) else: - print(" [VisRegion] SoftVolume '{}'".format(self.softvolume)) + exporter.report.msg("[VisRegion] SoftVolume '{}'", self.softvolume, indent=1) sv_bo = bpy.data.objects.get(self.softvolume, None) if sv_bo is None: raise ExportError("'{}': Invalid object '{}' for VisControl soft volume".format(bo.name, self.softvolume)) diff --git a/korman/properties/modifiers/sound.py b/korman/properties/modifiers/sound.py index 4ed90cf..cce45b3 100644 --- a/korman/properties/modifiers/sound.py +++ b/korman/properties/modifiers/sound.py @@ -173,7 +173,7 @@ class PlasmaSound(bpy.types.PropertyGroup): name = "Sfx-{}_{}".format(so.key.name, self.sound_data) else: name = "Sfx-{}_{}:{}".format(so.key.name, self.sound_data, channel) - print(" [{}] {}".format(pClass.__name__[2:], name)) + exporter.report.msg("[{}] {}", pClass.__name__[2:], name, indent=1) sound = exporter.mgr.find_create_object(pClass, so=so, name=name) # If this object is a soft volume itself, we will use our own soft region.