Browse Source

Export dynamic environment maps

This means we now export BOTH plDyanmicEnvMap and plDynamicCamMap. The
latter will only be exported on MOUL+, sadly. The former is "cube" mapping
and the latter is "plane" mapping. Instead of manually specifying the
refresh rate, I decided that Blender's "static" option means that it only
refreshes once (and never again) and animated means we refresh every 0.01
second, which seems to be the Cyan standard for "update every frame, blast
it!" NOTE: when cameras are exporting, we need to support Camera based
DCMs.

Static image based CEMs coming soon...
pull/8/head
Adam Johnson 9 years ago
parent
commit
fc9407a332
  1. 11
      korman/exporter/convert.py
  2. 2
      korman/exporter/manager.py
  3. 100
      korman/exporter/material.py
  4. 2
      korman/exporter/mesh.py
  5. 4
      korman/helpers.py

11
korman/exporter/convert.py

@ -130,7 +130,7 @@ class Exporter:
def _export_actor(self, so, bo):
"""Exports a Coordinate Interface if we need one"""
if self.mgr.has_coordiface(bo):
self._export_coordinate_interface(so, bo)
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.
@ -148,16 +148,15 @@ class Exporter:
The object may not appear in the correct location or animate properly.".format(
bo.name, parent.name))
def _export_coordinate_interface(self, so, bo):
def export_coordinate_interface(self, so, bl, name=None):
"""Ensures that the SceneObject has a CoordinateInterface"""
if not so.coord:
print(" Exporting CoordinateInterface")
ci = self.mgr.find_create_key(plCoordinateInterface, bl=bo, so=so).object
ci = self.mgr.find_create_key(plCoordinateInterface, bl=bl, so=so, name=name).object
# Now we have the "fun" work of filling in the CI
ci.localToWorld = utils.matrix44(bo.matrix_basis)
ci.localToWorld = utils.matrix44(bl.matrix_basis)
ci.worldToLocal = ci.localToWorld.inverse()
ci.localToParent = utils.matrix44(bo.matrix_local)
ci.localToParent = utils.matrix44(bl.matrix_local)
ci.parentToLocal = ci.localToParent.inverse()
def _export_scene_objects(self):

2
korman/exporter/manager.py

@ -93,7 +93,7 @@ class ExportManager:
if isinstance(pl, plObjInterface):
if so is None:
key = self.find_key(plSceneObject, bl)
key = self.find_key(plSceneObject, bl, name)
# prevent race conditions
if key is None:
so = self.add_object(plSceneObject, name=name, loc=location)

100
korman/exporter/material.py

@ -21,6 +21,7 @@ from PyHSPlasma import *
import weakref
from . import explosions
from .. import helpers
from . import utils
# BGL doesn't know about this as of Blender 2.74
@ -226,6 +227,101 @@ class MaterialConverter:
getattr(self, export_fn)(bo, hsgmat, layer, texture)
hsgmat.addLayer(layer.key)
def _export_texture_type_environment_map(self, bo, hsgmat, layer, texture):
"""Exports a Blender EnvironmentMapTexture to a plLayer"""
bl_env = texture.environment_map
if bl_env.source in {"STATIC", "ANIMATED"}:
if bl_env.mapping == "PLANE" and self._mgr.getVer() >= pvMoul:
pl_env = plDynamicCamMap
else:
pl_env = plDynamicEnvMap
pl_env = self._export_dynamic_env(bo, hsgmat, layer, bl_env, pl_env)
else:
raise NotSupportedError()
layer.texture = pl_env
def _export_dynamic_env(self, bo, hsgmat, layer, bl_env, pl_class):
# To protect the user from themselves, let's check to make sure that a DEM/DCM matching this
# viewpoint object has not already been exported...
viewpt = bl_env.viewpoint_object
name = "{}_DynEnvMap".format(viewpt.name)
pl_env = self._mgr.find_key(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))
pl_env_obj = pl_env.object
if isinstance(pl_env_obj, plDynamicCamMap):
dcm.addTargetNode(self._mgr.find_key(plSceneObject, bl=bo))
dcm.addMatLayer(layer.key)
return pl_env
# It matters not whether or not the viewpoint object is a Plasma Object, it is exported as at
# least a SceneObject and CoordInterface so that we can touch it...
root = self._mgr.find_create_key(plSceneObject, bl=bo, name=viewpt.name)
self._exporter().export_coordinate_interface(root.object, bl=bo, name=viewpt.name)
# FIXME: DynamicCamMap Camera
# Ensure POT
oRes = bl_env.resolution
eRes = helpers.ensure_power_of_two(oRes)
if oRes != eRes:
print(" Overriding EnvMap size to ({}x{}) -- POT".format(eRes, eRes))
# And now for the general ho'hum-ness
pl_env = self._mgr.add_object(pl_class, bl=bo, name=name)
pl_env.hither = bl_env.clip_start
pl_env.yon = bl_env.clip_end
pl_env.refreshRate = 0.01 if bl_env.source == "ANIMATED" else 0.0
pl_env.incCharacters = True
pl_env.rootNode = root # FIXME: DCM camera
# Perhaps the DEM/DCM fog should be separately configurable at some point?
pl_fog = bpy.context.scene.world.plasma_fni
pl_env.color = utils.color(pl_fog.fog_color)
pl_env.fogStart = pl_fog.fog_start
if isinstance(pl_env, plDynamicCamMap):
faces = (pl_env,)
pl_env.addTargetNode(self._mgr.find_key(plSceneObject, bl=bo))
pl_env.addMatLayer(layer.key)
# This is really just so we don't raise any eyebrows if anyone is looking at the files.
# If you're disabling DCMs, then you're obviuously trolling!
# Cyan generates a single color image, but we'll just set the layer colors and go away.
fake_layer = self._mgr.add_object(plLayer, bl=bo, name="{}_DisabledDynEnvMap".format(viewpt.name))
fake_layer.ambient = layer.ambient
fake_layer.preshade = layer.preshade
fake_layer.runtime = layer.runtime
fake_layer.specular = layer.specular
pl_env.disableTexture = fake_layer.key
if pl_env.camera is None:
layer.UVWSrc = plLayerInterface.kUVWPosition
layer.state.miscFlags |= (hsGMatState.kMiscCam2Screen | hsGMatState.kMiscPerspProjection)
else:
faces = pl_env.faces + (pl_env,)
layer.UVWSrc = plLayerInterface.kUVWReflect
layer.state.miscFlags |= hsGMatState.kMiscUseRefractionXform
# Because we might be working with a multi-faced env map. It's even worse than have two faces...
for i in faces:
i.setConfig(plBitmap.kRGB8888)
i.flags |= plBitmap.kIsTexture
i.flags &= ~plBitmap.kAlphaChannelFlag
i.width = eRes
i.height = eRes
i.proportionalViewport = False
i.viewportLeft = 0
i.viewportTop = 0
i.viewportRight = eRes
i.viewportBottom = eRes
i.ZDepth = 24
return pl_env.key
def _export_texture_type_image(self, bo, hsgmat, layer, texture):
"""Exports a Blender ImageTexture to a plLayer"""
@ -280,8 +376,8 @@ class MaterialConverter:
image = key.image
oWidth, oHeight = image.size
eWidth = pow(2, math.floor(math.log(oWidth, 2)))
eHeight = pow(2, math.floor(math.log(oHeight, 2)))
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._resize_image(image, eWidth, eHeight)

2
korman/exporter/mesh.py

@ -143,7 +143,7 @@ class MeshConverter:
for dspan in loc.values():
print("\n[DrawableSpans '{}']".format(dspan.key.name))
print(" Composing geometry data")
# This mega-function does a lot:
# 1. Converts SourceSpans (geospans) to Icicles and bakes geometry into plGBuffers
# 2. Calculates the Icicle bounds

4
korman/helpers.py

@ -14,6 +14,7 @@
# along with Korman. If not, see <http://www.gnu.org/licenses/>.
import bpy
import math
class GoodNeighbor:
"""Leave Things the Way You Found Them! (TM)"""
@ -31,6 +32,9 @@ class GoodNeighbor:
setattr(cls, attr, value)
def ensure_power_of_two(value):
return pow(2, math.floor(math.log(value, 2)))
def make_active_selection(bo):
"""Selects a single Blender Object and makes it active"""
for i in bpy.data.objects:

Loading…
Cancel
Save