# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Python Computer Graphics Kit.
#
# The Initial Developer of the Original Code is Matthias Baas.
# Portions created by the Initial Developer are Copyright (C) 2004
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
# $Id: camcontrol.py,v 1.4 2005/08/31 14:49:13 mbaas Exp $
## \file camcontrol.py
## Contains the CameraControl class.
import component
import eventmanager
from scene import getScene
from events import *
from keydefs import *
from cgtypes import *
# CameraControl
class CameraControl(component.Component):
"""Camera control component.
This component lets you control a camera interactively with the mouse.
Todo: - About what point rotates the FreeCam?
- Make movement distances customizable (auto configurable?)
"""
def __init__(self,
cam,
name = "CameraControl",
mode = 0,
auto_insert = True):
"""Constructor.
\param cam (\c ...Cam?...) Camera to control
\param name (\c str) Name of the component
\param mode (\c int) 0=Emulate MAX behavior, 1=Emulate Maya behavior
\param auto_insert (\c bool) Insert into scene or not
"""
component.Component.__init__(self, name=name, auto_insert=auto_insert)
# mode: 0=Emulate MAX / 1=Emulate Maya / 2=Emulate Softimage (Navigation tool)
self.mode = mode
self.cam = cam
self.left_down = False
self.middle_down = False
self.right_down = False
self.alt_down = False
self.ctrl_down = False
em = eventmanager.eventManager()
em.connect(KEY_PRESS, self)
em.connect(KEY_RELEASE, self)
em.connect(LEFT_DOWN, self)
em.connect(LEFT_UP, self)
em.connect(MIDDLE_DOWN, self)
em.connect(MIDDLE_UP, self)
em.connect(RIGHT_DOWN, self)
em.connect(RIGHT_UP, self)
em.connect(MOUSE_MOVE, self)
em.connect(MOUSE_WHEEL, self)
em.connect(SPACE_MOTION, self)
def panCondition(self):
"""Return True if the panning mode is active.
"""
if self.mode==0:
# MAX
return self.middle_down and not self.alt_down and not self.ctrl_down
elif self.mode==1:
# Maya
return self.middle_down and self.alt_down
else:
# Softimage
return self.left_down
def rotCondition(self):
"""Return True if rotation mode is active.
"""
if self.mode==0:
# MAX
return self.middle_down and self.alt_down and not self.ctrl_down
elif self.mode==1:
# Maya
return self.left_down and self.alt_down
else:
# Softimage
return self.right_down
def fbCondition(self):
"""Return True if 'forward/backward' movement mode is active.
"""
if self.mode==0:
# MAX
return self.middle_down and self.alt_down and self.ctrl_down
elif self.mode==1:
# Maya
return self.right_down and self.alt_down
else:
# Softimage
return self.middle_down
def translateXYAmount(self, evt):
"""Return the amount of sideways movement."""
if self.mode==0:
# MAX
return 0.003*evt.dx, 0.003*evt.dy
elif self.mode==1:
# Maya
return 0.003*evt.dx, 0.003*evt.dy
else:
# Softimage
return 0.002*evt.dx, 0.002*evt.dy
def translateZAmount(self, evt):
"""Return the amount of 'forward/backward' movement."""
if self.mode==0:
# MAX
return -0.01*evt.dy
elif self.mode==1:
# Maya
return 0.004*(evt.dy+evt.dx)
else:
# Softimage
return 0.008*(evt.dy-evt.dx)
def rotationAmount(self, evt):
"""Return the amount of rotation."""
if self.mode==0:
# MAX
return 0.01*evt.dx, 0.01*evt.dy
elif self.mode==1:
# Maya
return 0.01*evt.dx, 0.01*evt.dy
else:
# Softimage
return 0.015*evt.dx, 0.015*evt.dy
# onKeyPress
def onKeyPress(self, e):
"""Set key flags."""
if e.altKey():
self.alt_down = True
elif e.controlKey():
self.ctrl_down = True
# onKeyRelease
def onKeyRelease(self, e):
"""Unset key flags."""
if e.altKey():
self.alt_down = False
elif e.controlKey():
self.ctrl_down = False
# onMouseMove
def onMouseMove(self, e):
if self.panCondition():
dx, dy = self.translateXYAmount(e)
self.translateXY(dx, dy)
elif self.rotCondition():
dx, dy = self.rotationAmount(e)
self.rotate(dx, dy)
elif self.fbCondition():
f = self.translateZAmount(e)
self.translateZ(f)
def onMouseWheel(self, e):
self.translateZ(0.002*e.delta)
def onLeftDown(self, e):
self.left_down = True
def onLeftUp(self, e):
self.left_down = False
def onMiddleDown(self, e):
self.middle_down = True
def onMiddleUp(self, e):
self.middle_down = False
def onRightDown(self, e):
self.right_down = True
def onRightUp(self, e):
self.right_down = False
# translateXY
def translateXY(self, dx, dy):
"""Translate the camera in local XY.
"""
T = self.cam.transform
bx = vec3(tuple(T.getColumn(0))[:3])
by = vec3(tuple(T.getColumn(1))[:3])
if hasattr(self.cam, "target"):
f = (self.cam.target-self.cam.pos).length()
dx *= f
dy *= f
delta = dx*bx + dy*by
self.cam.pos += delta
if hasattr(self.cam, "target"):
self.cam.target += delta
# rotate
def rotate(self, dx, dy):
"""Rotate around target."""
T = self.cam.transform
if hasattr(self.cam, "target"):
pivot = self.cam.target
else:
pivot = vec3(0)
up = getScene().up
R = mat4(1).rotation(-dx, up)
dp = self.cam.pos-pivot
self.cam.pos = pivot + R*dp
T = self.cam.transform
bx = vec3(tuple(T.getColumn(0))[:3])
R = mat4(1).rotation(dy, bx)
dp = self.cam.pos-pivot
self.cam.pos = pivot + R*dp
# translateZ
def translateZ(self, dz):
"""Move in viewing direction.
"""
T = self.cam.transform
bz = vec3(tuple(T.getColumn(2))[:3])
if hasattr(self.cam, "target"):
f = (self.cam.target-self.cam.pos).length()
else:
f = 1
delta = f*dz*bz
self.cam.pos += delta
# self.cam.target += delta
# onSpaceMotion
def onSpaceMotion(self, e):
"""
this is still somewhat experimental
(should distinguish between the camera types as it's meant to be
used with a FreeCamera)
"""
scene = getScene()
tr = 0.001*e.translation
rot = e.rotation
if scene.handedness=='r':
tr.x = -tr.x
rot.y = -rot.y
rot.z = -rot.z
M = mat4().translation(tr)
if rot!=vec3(0):
a = 0.0002*rot.length()
M = M*mat4().rotation(a, rot)
T = self.cam.transform*M
# Align camera to up direction
R = T.getMat3()
bz = vec3(tuple(T.getColumn(2))[:3])
by = scene.up
bx = by.cross(bz)
by = bz.cross(bx)
try:
R = mat3(bx.normalize(), by.normalize(), bz.normalize())
except:
R = mat3(1)
T.setMat3(R)
self.cam.transform = T
|