Browse Source

Refactor export logging

The export logger and export reporter have been merged together to form
an eventually much more powerful export analysis feature. For now, the
benefit is that general log messages don't have to be so fiddly with
print statements and string formatting. You're welcome.
pull/58/head
Adam Johnson 7 years ago
parent
commit
6a3b09b747
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 23
      korlib/texture.cpp
  2. 31
      korman/exporter/convert.py
  3. 20
      korman/exporter/etlight.py
  4. 95
      korman/exporter/logger.py
  5. 45
      korman/exporter/material.py
  6. 13
      korman/exporter/mesh.py
  7. 37
      korman/exporter/rtlight.py
  8. 8
      korman/korlib/texture.py
  9. 6
      korman/nodes/node_conditions.py
  10. 4
      korman/properties/modifiers/render.py
  11. 2
      korman/properties/modifiers/sound.py

23
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;

31
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)

20
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])

95
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])

45
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()

13
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

37
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

8
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

6
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

4
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))

2
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.

Loading…
Cancel
Save