293 lines
10 KiB
Python
293 lines
10 KiB
Python
import bpy
|
|
import typing, math
|
|
from . import UTIL_functions, UTIL_virtools_types
|
|
|
|
# Raw Data
|
|
|
|
class RawVirtoolsCamera():
|
|
# Class Member
|
|
|
|
mProjectionType: UTIL_virtools_types.CK_CAMERA_PROJECTION
|
|
|
|
mOrthographicZoom: float
|
|
|
|
mFrontPlane: float
|
|
mBackPlane: float
|
|
mFov: float
|
|
|
|
mAspectRatio: tuple[int, int]
|
|
|
|
# Class member default value
|
|
|
|
cDefaultProjectionType: typing.ClassVar[UTIL_virtools_types.CK_CAMERA_PROJECTION] = UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_PERSPECTIVEPROJECTION
|
|
|
|
cDefaultOrthographicZoom: typing.ClassVar[float] = 1.0
|
|
|
|
cDefaultFrontPlane: typing.ClassVar[float] = 1.0
|
|
cDefaultBackPlane: typing.ClassVar[float] = 4000.0
|
|
cDefaultFov: typing.ClassVar[float] = 0.5
|
|
|
|
cDefaultAspectRatio: typing.ClassVar[tuple[int, int]] = (4, 3)
|
|
|
|
def __init__(self, **kwargs):
|
|
# assign default value for each component
|
|
self.mProjectionType = kwargs.get("mProjectionType", RawVirtoolsCamera.cDefaultProjectionType)
|
|
|
|
self.mOrthographicZoom = kwargs.get("mOrthographicZoom", RawVirtoolsCamera.cDefaultOrthographicZoom)
|
|
|
|
self.mFrontPlane = kwargs.get("mFrontPlane", RawVirtoolsCamera.cDefaultFrontPlane)
|
|
self.mBackPlane = kwargs.get("mBackPlane", RawVirtoolsCamera.cDefaultBackPlane)
|
|
self.mFov = kwargs.get("mFov", RawVirtoolsCamera.cDefaultFov)
|
|
|
|
self.mAspectRatio = kwargs.get("mAspectRatio", RawVirtoolsCamera.cDefaultAspectRatio)
|
|
|
|
def regulate(self) -> None:
|
|
# everything should be positive
|
|
self.mOrthographicZoom = max(0.0, self.mOrthographicZoom)
|
|
self.mFrontPlane = max(0.0, self.mFrontPlane)
|
|
self.mBackPlane = max(0.0, self.mBackPlane)
|
|
self.mFov = max(0.0, self.mFov)
|
|
|
|
# aspect ratio should be positive and at least 1
|
|
(w, h) = self.mAspectRatio
|
|
w = max(1, w)
|
|
h = max(1, h)
|
|
self.mAspectRatio = (w, h)
|
|
|
|
# Blender Property Group
|
|
|
|
_g_Helper_CK_CAMERA_PROJECTION = UTIL_virtools_types.EnumPropHelper(UTIL_virtools_types.CK_CAMERA_PROJECTION)
|
|
|
|
class BBP_PG_virtools_camera(bpy.types.PropertyGroup):
|
|
projection_type: bpy.props.EnumProperty(
|
|
name = "Type",
|
|
description = "The type of this camera.",
|
|
items = _g_Helper_CK_CAMERA_PROJECTION.generate_items(),
|
|
default = _g_Helper_CK_CAMERA_PROJECTION.to_selection(RawVirtoolsCamera.cDefaultProjectionType),
|
|
translation_context = 'BBP_PG_virtools_camera/property'
|
|
) # type: ignore
|
|
|
|
orthographic_zoom: bpy.props.FloatProperty(
|
|
name = "Orthographic Zoom",
|
|
description = "Defines the orthographic zoom.",
|
|
min = 0.0,
|
|
soft_min = 0.0,
|
|
soft_max = 0.5,
|
|
step = 5,
|
|
default = RawVirtoolsCamera.cDefaultOrthographicZoom,
|
|
translation_context = 'BBP_PG_virtools_camera/property'
|
|
) # type: ignore
|
|
|
|
front_plane: bpy.props.FloatProperty(
|
|
name = "Front Plane",
|
|
description = "Defines the front plane.",
|
|
min = 0.0,
|
|
soft_min = 0.0,
|
|
soft_max = 5000.0,
|
|
step = 100,
|
|
default = RawVirtoolsCamera.cDefaultFrontPlane,
|
|
translation_context = 'BBP_PG_virtools_camera/property'
|
|
) # type: ignore
|
|
|
|
back_plane: bpy.props.FloatProperty(
|
|
name = "Back Plane",
|
|
description = "Defines the back plane.",
|
|
min = 0.0,
|
|
soft_min = 0.0,
|
|
soft_max = 5000.0,
|
|
step = 100,
|
|
default = RawVirtoolsCamera.cDefaultBackPlane,
|
|
translation_context = 'BBP_PG_virtools_camera/property'
|
|
) # type: ignore
|
|
|
|
fov: bpy.props.FloatProperty(
|
|
name = "Field of View",
|
|
description = "Defines the field of view.",
|
|
subtype = 'ANGLE',
|
|
min = 0.0,
|
|
max = math.radians(180.0),
|
|
step = 100,
|
|
precision = 100,
|
|
default = RawVirtoolsCamera.cDefaultFov,
|
|
translation_context = 'BBP_PG_virtools_camera/property'
|
|
) # type: ignore
|
|
|
|
aspect_ratio_w: bpy.props.IntProperty(
|
|
name = "Aspect Ratio Width",
|
|
description = "Defines the width of aspect ratio.",
|
|
min = 1,
|
|
soft_min = 1,
|
|
soft_max = 40,
|
|
step = 1,
|
|
default = RawVirtoolsCamera.cDefaultAspectRatio[0],
|
|
translation_context = 'BBP_PG_virtools_camera/property'
|
|
) # type: ignore
|
|
|
|
aspect_ratio_h: bpy.props.IntProperty(
|
|
name = "Aspect Ratio Height",
|
|
description = "Defines the height of aspect ratio.",
|
|
min = 1,
|
|
soft_min = 1,
|
|
soft_max = 40,
|
|
step = 1,
|
|
default = RawVirtoolsCamera.cDefaultAspectRatio[1],
|
|
translation_context = 'BBP_PG_virtools_camera/property'
|
|
) # type: ignore
|
|
|
|
# Getter Setter and Applyer
|
|
|
|
def get_virtools_camera(cam: bpy.types.Camera) -> BBP_PG_virtools_camera:
|
|
return cam.virtools_camera
|
|
|
|
def get_raw_virtools_camera(cam: bpy.types.Camera) -> RawVirtoolsCamera:
|
|
props: BBP_PG_virtools_camera = get_virtools_camera(cam)
|
|
rawdata: RawVirtoolsCamera = RawVirtoolsCamera()
|
|
|
|
rawdata.mProjectionType = _g_Helper_CK_CAMERA_PROJECTION.get_selection(props.projection_type)
|
|
|
|
rawdata.mOrthographicZoom = props.orthographic_zoom
|
|
|
|
rawdata.mFrontPlane = props.front_plane
|
|
rawdata.mBackPlane = props.back_plane
|
|
rawdata.mFov = props.fov
|
|
|
|
rawdata.mAspectRatio = (props.aspect_ratio_w, props.aspect_ratio_h)
|
|
|
|
rawdata.regulate()
|
|
return rawdata
|
|
|
|
def set_raw_virtools_camera(cam: bpy.types.Camera, rawdata: RawVirtoolsCamera) -> None:
|
|
props: BBP_PG_virtools_camera = get_virtools_camera(cam)
|
|
|
|
props.projection_type = _g_Helper_CK_CAMERA_PROJECTION.to_selection(rawdata.mProjectionType)
|
|
|
|
props.orthographic_zoom = rawdata.mOrthographicZoom
|
|
|
|
props.front_plane = rawdata.mFrontPlane
|
|
props.back_plane = rawdata.mBackPlane
|
|
props.fov = rawdata.mFov
|
|
|
|
(props.aspect_ratio_w, props.aspect_ratio_h) = rawdata.mAspectRatio
|
|
|
|
def apply_to_blender_camera(cam: bpy.types.Camera) -> None:
|
|
# get raw data first
|
|
rawdata: RawVirtoolsCamera = get_raw_virtools_camera(cam)
|
|
|
|
# set camera type
|
|
match(rawdata.mProjectionType):
|
|
case UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_PERSPECTIVEPROJECTION:
|
|
cam.type = 'PERSP'
|
|
case UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_ORTHOGRAPHICPROJECTION:
|
|
cam.type = 'ORTHO'
|
|
|
|
# set orthographic zoom
|
|
cam.ortho_scale = rawdata.mOrthographicZoom
|
|
|
|
# front and back plane
|
|
cam.clip_start = rawdata.mFrontPlane
|
|
cam.clip_end = rawdata.mBackPlane
|
|
|
|
# fov
|
|
cam.lens_unit = 'FOV'
|
|
cam.angle = rawdata.mFov
|
|
|
|
# Operators
|
|
|
|
class BBP_OT_apply_virtools_camera(bpy.types.Operator):
|
|
"""Apply Virtools Camera to Blender Camera."""
|
|
bl_idname = "bbp.apply_virtools_camera"
|
|
bl_label = "Apply to Blender Camera"
|
|
bl_options = {'UNDO'}
|
|
bl_translation_context = 'BBP_OT_apply_virtools_camera'
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.camera is not None
|
|
|
|
def execute(self, context):
|
|
cam: bpy.types.Camera = context.camera
|
|
apply_to_blender_camera(cam)
|
|
return {'FINISHED'}
|
|
|
|
# Display Panel
|
|
|
|
class BBP_PT_virtools_camera(bpy.types.Panel):
|
|
"""Show Virtools Camera Properties"""
|
|
bl_label = "Virtools Camera"
|
|
bl_idname = "BBP_PT_virtools_camera"
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "data" # idk why blender use `data` as the camera tab same as mesh.
|
|
bl_translation_context = 'BBP_PT_virtools_camera'
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.camera is not None
|
|
|
|
def draw(self, context):
|
|
# get layout and target
|
|
layout = self.layout
|
|
cam: bpy.types.Camera = context.camera
|
|
props: BBP_PG_virtools_camera = get_virtools_camera(cam)
|
|
rawdata: RawVirtoolsCamera = get_raw_virtools_camera(cam)
|
|
|
|
# draw operator
|
|
layout.operator(
|
|
BBP_OT_apply_virtools_camera.bl_idname, text='Apply', icon='NODETREE',
|
|
text_ctxt='BBP_PT_virtools_camera/draw')
|
|
|
|
# draw data
|
|
layout.separator()
|
|
# show camera type first
|
|
layout.prop(props, 'projection_type')
|
|
# all camera has front and back plane
|
|
layout.label(text='Clipping', text_ctxt='BBP_PT_virtools_camera/draw')
|
|
sublayout = layout.column()
|
|
sublayout.use_property_split = True
|
|
sublayout.prop(props, 'front_plane')
|
|
sublayout.prop(props, 'back_plane')
|
|
|
|
# only perspective camera has fov setting
|
|
if rawdata.mProjectionType == UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_PERSPECTIVEPROJECTION:
|
|
layout.separator()
|
|
layout.label(text='Perspective Parameters', text_ctxt='BBP_PT_virtools_camera/draw')
|
|
sublayout = layout.column()
|
|
sublayout.use_property_split = True
|
|
sublayout.prop(props, 'fov')
|
|
|
|
# only orthographic camera has orthographic zoom setting
|
|
if rawdata.mProjectionType == UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_ORTHOGRAPHICPROJECTION:
|
|
layout.separator()
|
|
layout.label(text='Orthographic Parameters', text_ctxt='BBP_PT_virtools_camera/draw')
|
|
sublayout = layout.column()
|
|
sublayout.use_property_split = True
|
|
sublayout.prop(props, 'orthographic_zoom')
|
|
|
|
# aspect ratio
|
|
layout.separator()
|
|
layout.label(text='Aspect Ratio', text_ctxt='BBP_PT_virtools_camera/draw')
|
|
sublayout = layout.row()
|
|
sublayout.use_property_split = False
|
|
sublayout.prop(props, 'aspect_ratio_w', text = '', expand = True)
|
|
sublayout.prop(props, 'aspect_ratio_h', text = '', expand = True)
|
|
|
|
# Register
|
|
|
|
def register() -> None:
|
|
bpy.utils.register_class(BBP_PG_virtools_camera)
|
|
bpy.utils.register_class(BBP_OT_apply_virtools_camera)
|
|
bpy.utils.register_class(BBP_PT_virtools_camera)
|
|
|
|
# add into camera metadata
|
|
bpy.types.Camera.virtools_camera = bpy.props.PointerProperty(type = BBP_PG_virtools_camera)
|
|
|
|
def unregister() -> None:
|
|
# remove from metadata
|
|
del bpy.types.Camera.virtools_camera
|
|
|
|
bpy.utils.unregister_class(BBP_PT_virtools_camera)
|
|
bpy.utils.unregister_class(BBP_OT_apply_virtools_camera)
|
|
bpy.utils.unregister_class(BBP_PG_virtools_camera)
|
|
|
|
|