diff --git a/korman/exporter/camera.py b/korman/exporter/camera.py
index 9e315a7..420ed79 100644
--- a/korman/exporter/camera.py
+++ b/korman/exporter/camera.py
@@ -140,7 +140,8 @@ class CameraConverter:
return brain
def _export_fixed_camera(self, so, bo, props):
- self._exporter().animation.convert_object_animations(bo, so)
+ if props.anim_enabled:
+ self._exporter().animation.convert_object_animations(bo, so)
brain = self._mgr.find_create_object(plCameraBrain1_Fixed, so=so)
self._convert_brain(so, bo, props, brain)
return brain
@@ -185,6 +186,8 @@ class CameraConverter:
else:
# The animation is a loop
path.flags |= plAnimPath.kWrap
+ if props.rail_pos == "farthest":
+ path.flags |= plAnimPath.kFarthest
path.length = end / bpy.context.scene.render.fps
rail.path = path
brain.rail = rail.key
diff --git a/korman/properties/prop_camera.py b/korman/properties/prop_camera.py
index 6b88549..93d814a 100644
--- a/korman/properties/prop_camera.py
+++ b/korman/properties/prop_camera.py
@@ -159,8 +159,8 @@ class PlasmaCameraProperties(bpy.types.PropertyGroup):
options=set())
circle_pos = EnumProperty(name="Position on Circle",
description="The point on the circle the camera moves to",
- items=[("closest", "Closest Point", "The camera moves to point on the circle closest to the Point of Attention"),
- ("farthest", "Farthest Point", "The point farthest from the Point of Attention")],
+ items=[("closest", "Closest Point", "The camera moves to the point on the circle closest to the Point of Attention"),
+ ("farthest", "Farthest Point", "The camera moves to the point on the circle farthest from the Point of Attention")],
options=set())
circle_velocity = FloatProperty(name="Velocity",
description="Velocity of the circle camera in degrees per second",
@@ -174,16 +174,29 @@ class PlasmaCameraProperties(bpy.types.PropertyGroup):
min=0.0, default=8.5, options={"HIDDEN"})
# Animation
+ anim_enabled = BoolProperty(name="Animation Enabled",
+ description="Export the camera's animation",
+ default=True,
+ options=set())
start_on_push = BoolProperty(name="Start on Push",
description="Start playing the camera's animation when the camera is activated",
+ default=True,
options=set())
stop_on_pop = BoolProperty(name="Pause on Pop",
description="Pauses the camera's animation when the camera is no longer activated",
+ default=True,
options=set())
reset_on_pop = BoolProperty(name="Reset on Pop",
description="Reset the camera's animation to the beginning when the camera is no longer activated",
options=set())
+ # Rail
+ rail_pos = EnumProperty(name="Position on Rail",
+ description="The point on the rail the camera moves to",
+ items=[("closest", "Closest Point", "The camera moves to the point on the rail closest to the Point of Attention"),
+ ("farthest", "Farthest Point", "The camera moves to the point on the rail farthest from the Point of Attention")],
+ options=set())
+
def get_circle_radius(self, bo):
"""Gets the circle camera radius for this camera when it is attached to the given Object"""
assert bo is not None
diff --git a/korman/render.py b/korman/render.py
index e51304e..393b9eb 100644
--- a/korman/render.py
+++ b/korman/render.py
@@ -36,10 +36,6 @@ properties_material.MATERIAL_PT_transp.COMPAT_ENGINES.add("PLASMA_GAME")
properties_material.MATERIAL_PT_shadow.COMPAT_ENGINES.add("PLASMA_GAME")
del properties_material
-from bl_ui import properties_data_camera
-properties_data_camera.DATA_PT_context_camera.COMPAT_ENGINES.add("PLASMA_GAME")
-del properties_data_camera
-
from bl_ui import properties_data_mesh
properties_data_mesh.DATA_PT_uv_texture.COMPAT_ENGINES.add("PLASMA_GAME")
properties_data_mesh.DATA_PT_vertex_colors.COMPAT_ENGINES.add("PLASMA_GAME")
diff --git a/korman/ui/modifiers/region.py b/korman/ui/modifiers/region.py
index bbf3a07..2b18446 100644
--- a/korman/ui/modifiers/region.py
+++ b/korman/ui/modifiers/region.py
@@ -14,14 +14,33 @@
# along with Korman. If not, see .
import bpy
-from ..ui_camera import draw_camera_properties
+from .. import ui_camera
def camera_rgn(modifier, layout, context):
layout.prop(modifier, "camera_type")
if modifier.camera_type == "manual":
layout.prop(modifier, "camera_object", icon="CAMERA_DATA")
else:
- draw_camera_properties("follow", modifier.auto_camera, layout, context, True)
+ cam_type = modifier.camera_type[5:]
+ cam_props = modifier.auto_camera
+
+ def _draw_props(layout, cb):
+ for i in cb:
+ layout.separator()
+ i(layout, cam_type, cam_props)
+ def _draw_circle_cam_props(layout, cam_type, props):
+ # needs a sublayout that we can deactivate because the ui_camera
+ # version assumes we are most definitely a circle camera...
+ col = layout.column()
+ col.active = cam_type == "circle"
+ col.label("Circle Camera:")
+ ui_camera.draw_circle_camera_props(col, props)
+
+ _draw_props(layout, (ui_camera.draw_camera_mode_props,
+ ui_camera.draw_camera_poa_props,
+ ui_camera.draw_camera_pos_props,
+ ui_camera.draw_camera_manipulation_props,
+ _draw_circle_cam_props))
def footstep(modifier, layout, context):
layout.prop(modifier, "bounds")
diff --git a/korman/ui/ui_camera.py b/korman/ui/ui_camera.py
index e4ef144..56179c9 100644
--- a/korman/ui/ui_camera.py
+++ b/korman/ui/ui_camera.py
@@ -14,69 +14,45 @@
# along with Korman. If not, see .
import bpy
+from .. import helpers
+
+def _draw_alert_prop(layout, props, the_prop, cam_type, alert_cam="", min=None, max=None, **kwargs):
+ can_alert = not alert_cam or alert_cam == cam_type
+ if can_alert:
+ value = getattr(props, the_prop)
+ if min is not None and value < min:
+ layout.alert = True
+ if max is not None and value > max:
+ layout.alert = True
+ layout.prop(props, the_prop, **kwargs)
+ layout.alert = False
+ else:
+ layout.prop(props, the_prop, **kwargs)
+
+def _draw_gated_prop(layout, props, gate_prop, actual_prop):
+ row = layout.row(align=True)
+ row.prop(props, gate_prop, text="")
+ row = row.row(align=True)
+ row.active = getattr(props, gate_prop)
+ row.prop(props, actual_prop)
+
+def draw_camera_manipulation_props(layout, cam_type, props):
+ # Camera Panning
+ split = layout.split()
+ col = split.column()
+ col.label("Limit Panning:")
+ col.prop(props, "x_pan_angle")
+ col.prop(props, "y_pan_angle")
-class CameraButtonsPanel:
- bl_space_type = "PROPERTIES"
- bl_region_type = "WINDOW"
- bl_context = "data"
-
- @classmethod
- def poll(cls, context):
- return (context.camera and context.scene.render.engine == "PLASMA_GAME")
-
-
-class PlasmaCameraPanel(CameraButtonsPanel, bpy.types.Panel):
- bl_label = "Plasma Camera"
-
- def draw(self, context):
- camera = context.camera.plasma_camera
- layout = self.layout
-
- layout.prop(camera, "camera_type")
- layout.separator()
- draw_camera_properties(camera.camera_type, camera.settings, layout, context)
-
-
-class PlasmaCameraTransitionPanel(CameraButtonsPanel, bpy.types.Panel):
- bl_label = "Plasma Transitions"
-
- def draw(self, context):
- pass
-
-
-def draw_camera_properties(cam_type, props, layout, context, force_no_anim=False):
- trans = props.transition
-
- def _draw_alert_prop(layout, props, the_prop, cam="", min=None, max=None, **kwargs):
- can_alert = not cam or cam == cam_type
- if can_alert:
- value = getattr(props, the_prop)
- if min is not None and value < min:
- layout.alert = True
- if max is not None and value > max:
- layout.alert = True
- layout.prop(props, the_prop, **kwargs)
- layout.alert = False
- else:
- layout.prop(props, the_prop, **kwargs)
- def _draw_gated_prop(layout, props, gate_prop, actual_prop):
- row = layout.row(align=True)
- row.prop(props, gate_prop, text="")
- row = row.row(align=True)
- row.active = getattr(props, gate_prop)
- row.prop(props, actual_prop)
- def _is_camera_animated(cam_type, props, context, force_no_anim):
- if force_no_anim or cam_type == "rail":
- return False
- # Check for valid animation data on either the object or the camera
- # TODO: Should probably check for valid FCurve channels at some point???
- for i in (props.id_data, context.object):
- if i.animation_data is None:
- continue
- if i.animation_data.action is not None:
- return True
- return False
+ # Camera Zoom
+ col = split.column()
+ col.label("Field of View:")
+ col.prop(props, "fov")
+ _draw_gated_prop(col, props, "limit_zoom", "zoom_min")
+ _draw_gated_prop(col, props, "limit_zoom", "zoom_max")
+ _draw_gated_prop(col, props, "limit_zoom", "zoom_rate")
+def draw_camera_mode_props(layout, cam_type, props):
# Point of Attention
split = layout.split()
col = split.column()
@@ -99,8 +75,10 @@ def draw_camera_properties(cam_type, props, layout, context, force_no_anim=False
col.prop(props, "fast_run")
col.prop(props, "ignore_subworld")
+def draw_camera_poa_props(layout, cam_type, props):
+ trans = props.transition
+
# PoA Tracking
- layout.separator()
split = layout.split()
col = split.column()
col.label("Default Tracking Transition:")
@@ -115,17 +93,22 @@ def draw_camera_properties(cam_type, props, layout, context, force_no_anim=False
col.prop(props, "poa_offset", text="")
col.prop(props, "poa_worldspace")
+def draw_camera_pos_props(layout, cam_type, props):
+ trans = props.transition
+
# Position Tracking (only for follow cams)
- layout.separator()
split = layout.split()
col = split.column()
# Position Transitions
col.active = cam_type != "circle"
col.label("Default Position Transition:")
- _draw_alert_prop(col, trans, "pos_acceleration", cam="rail", max=10.0, text="Acceleration")
- _draw_alert_prop(col, trans, "pos_deceleration", cam="rail", max=10.0, text="Deceleration")
- _draw_alert_prop(col, trans, "pos_velocity", cam="rail", max=10.0, text="Maximum Velocity")
+ _draw_alert_prop(col, trans, "pos_acceleration", cam_type,
+ alert_cam="rail", max=10.0, text="Acceleration")
+ _draw_alert_prop(col, trans, "pos_deceleration", cam_type,
+ alert_cam="rail", max=10.0, text="Deceleration")
+ _draw_alert_prop(col, trans, "pos_velocity", cam_type,
+ alert_cam="rail", max=10.0, text="Maximum Velocity")
col.prop(trans, "pos_cut")
# Position Offsets
@@ -135,39 +118,116 @@ def draw_camera_properties(cam_type, props, layout, context, force_no_anim=False
col.prop(props, "pos_offset", text="")
col.prop(props, "pos_worldspace")
- # Camera Panning
- layout.separator()
- split = layout.split()
- col = split.column()
- col.label("Limit Panning:")
- col.prop(props, "x_pan_angle")
- col.prop(props, "y_pan_angle")
-
- # Camera Zoom
- col = split.column()
- col.label("Field of View:")
- col.prop(props, "fov")
- _draw_gated_prop(col, props, "limit_zoom", "zoom_min")
- _draw_gated_prop(col, props, "limit_zoom", "zoom_max")
- _draw_gated_prop(col, props, "limit_zoom", "zoom_rate")
-
+def draw_circle_camera_props(layout, props):
# Circle Camera Stuff
- layout.separator()
- split = layout.split()
- col = split.column()
- col.active = cam_type == "circle"
- col.label("Circle Camera:")
- col.prop(props, "circle_center", text="")
- col.prop(props, "circle_pos", text="")
- col.prop(props, "circle_velocity")
- row = col.row(align=True)
+ layout.prop(props, "circle_center")
+ layout.prop(props, "circle_pos")
+ layout.prop(props, "circle_velocity")
+ row = layout.row(align=True)
row.active = props.circle_center is None
row.prop(props, "circle_radius_ui")
- # Animated Camera Stuff
- col = split.column()
- col.active = _is_camera_animated(cam_type, props, context, force_no_anim)
- col.label("Animation:")
- col.prop(props, "start_on_push")
- col.prop(props, "stop_on_pop")
- col.prop(props, "reset_on_pop")
+class CameraButtonsPanel:
+ bl_space_type = "PROPERTIES"
+ bl_region_type = "WINDOW"
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.camera and context.scene.render.engine == "PLASMA_GAME")
+
+
+class PlasmaCameraTypePanel(CameraButtonsPanel, bpy.types.Panel):
+ bl_label = ""
+ bl_options = {"HIDE_HEADER"}
+
+ def draw(self, context):
+ camera = context.camera.plasma_camera
+ self.layout.prop(camera, "camera_type")
+
+
+class PlasmaCameraModePanel(CameraButtonsPanel, bpy.types.Panel):
+ bl_label = "Camera Tracking"
+
+ def draw(self, context):
+ camera = context.camera.plasma_camera
+ draw_camera_mode_props(self.layout, camera.camera_type, camera.settings)
+
+
+class PlasmaCameraAttentionPanel(CameraButtonsPanel, bpy.types.Panel):
+ bl_label = "Point of Attention Tracking"
+
+ def draw(self, context):
+ camera = context.camera.plasma_camera
+ draw_camera_poa_props(self.layout, camera.camera_type, camera.settings)
+
+
+class PlasmaCameraPositionPanel(CameraButtonsPanel, bpy.types.Panel):
+ bl_label = "Position Tracking"
+
+ def draw(self, context):
+ camera = context.camera.plasma_camera
+ draw_camera_pos_props(self.layout, camera.camera_type, camera.settings)
+
+
+class PlasmaCameraCirclePanel(CameraButtonsPanel, bpy.types.Panel):
+ bl_label = "Circle Camera"
+
+ def draw(self, context):
+ camera = context.camera.plasma_camera
+ draw_circle_camera_props(self.layout, camera.settings)
+
+ @classmethod
+ def poll(cls, context):
+ return super().poll(context) and context.camera.plasma_camera.camera_type == "circle"
+
+
+class PlasmaCameraAnimationPanel(CameraButtonsPanel, bpy.types.Panel):
+ bl_label = "Camera Animation"
+ bl_options = {"DEFAULT_CLOSED"}
+
+ def draw(self, context):
+ layout = self.layout
+ camera = context.camera.plasma_camera
+ props = camera.settings
+
+ split = layout.split()
+ col = split.column()
+ col.label("Animation:")
+ col.active = props.anim_enabled and any(helpers.fetch_fcurves(context.object))
+ col.prop(props, "start_on_push")
+ col.prop(props, "stop_on_pop")
+ col.prop(props, "reset_on_pop")
+
+ col = split.column()
+ col.active = camera.camera_type == "rail"
+ col.label("Rail:")
+ col.prop(props, "rail_pos", text="")
+
+ def draw_header(self, context):
+ self.layout.active = any(helpers.fetch_fcurves(context.object))
+ self.layout.prop(context.camera.plasma_camera.settings, "anim_enabled", text="")
+
+
+class PlasmaCameraViewPanel(CameraButtonsPanel, bpy.types.Panel):
+ bl_label = "Camera Lens"
+
+ def draw(self, context):
+ camera = context.camera.plasma_camera
+ draw_camera_manipulation_props(self.layout, camera.camera_type, camera.settings)
+
+
+class TransitionListUI(bpy.types.UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_property, index=0, flt_flag=0):
+ if item.camera is None:
+ layout.label("[Default Transition]")
+ else:
+ layout.label(item.camera.name, icon="CAMERA_DATA")
+ layout.prop(item, "enabled", text="")
+
+
+class PlasmaCameraTransitionPanel(CameraButtonsPanel, bpy.types.Panel):
+ bl_label = "Transitions"
+
+ def draw(self, context):
+ pass