*** empty log message ***

This commit is contained in:
Mark Mine 2001-01-20 02:03:27 +00:00
parent cda6f2be96
commit e5ab222f36
8 changed files with 220 additions and 122 deletions

View File

@ -15,7 +15,7 @@ class DirectCameraControl(PandaObject):
self.coaMarker = loader.loadModel('models/misc/sphere')
self.coaMarker.setName('DirectCameraCOAMarker')
self.coaMarker.setColor(1,0,0)
self.coaMarker.setPos(0,0,0)
self.coaMarker.setPos(0,100,0)
useDirectRenderStyle(self.coaMarker)
self.coaMarkerPos = Point3(0)
self.camManipRef = direct.group.attachNewNode('camManipRef')
@ -56,27 +56,15 @@ class DirectCameraControl(PandaObject):
self.coaMarker.hide()
# Check for a hit point based on
# current mouse position
# Allow intersection with unpickable objects
# And then spawn task to determine mouse mode
numEntries = direct.iRay.pickGeom(
render,direct.dr.mouseX,direct.dr.mouseY)
# Then filter out hidden nodes from entry list
indexList = []
for i in range(0,numEntries):
entry = direct.iRay.cq.getEntry(i)
node = entry.getIntoNode()
if node.isHidden():
pass
else:
# Not one of the widgets, use it
indexList.append(i)
node, hitPt, hitPtDist = direct.iRay.pickGeom(
fIntersectUnpickable = 1)
coa = Point3(0)
if(indexList):
# Grab first point (it should be the closest)
minPt = indexList[0]
# Find hit point in camera's space
hitPt = direct.iRay.camToHitPt(minPt)
coa.set(hitPt[0],hitPt[1],hitPt[2])
coaDist = Vec3(coa - ZERO_POINT).length()
if node:
# Set center of action
coa.assign(hitPt)
coaDist = hitPtDist
# Handle case of bad coa point (too close or too far)
if ((coaDist < (1.1 * direct.dr.near)) |
(coaDist > direct.dr.far)):

View File

@ -2,8 +2,6 @@ from PandaObject import *
from DirectGeometry import *
MANIPULATION_MOVE_DELAY = 0.65
UNPICKABLE = ['x-disc-visible', 'y-disc-visible', 'z-disc-visible',
'GridBack']
class DirectManipulationControl(PandaObject):
def __init__(self):
@ -24,7 +22,6 @@ class DirectManipulationControl(PandaObject):
self.fWidgetTop = 0
self.fFreeManip = 1
self.fScaling = 0
self.unpickable = UNPICKABLE
self.mode = None
self.actionEvents = [
['handleMouse1', self.manipulationStart],
@ -35,26 +32,19 @@ class DirectManipulationControl(PandaObject):
[',', self.objectHandles.multiplyScalingFactorBy, 0.5],
['<', self.objectHandles.multiplyScalingFactorBy, 0.5],
['F', self.objectHandles.growToFit],
['p', self.plantSelectedNodePath],
]
def manipulationStart(self):
# Start out in select mode
self.mode = 'select'
# Check for a widget hit point
numEntries = direct.iRay.pickWidget(
render,direct.dr.mouseX,direct.dr.mouseY)
node, hitPt, hitPtDist = direct.iRay.pickWidget()
# Did we hit a widget?
if(numEntries):
if node:
# Yes!
# Entry 0 is the closest hit point if multiple hits
minPt = 0
# Find hit point in camera's space
self.hitPt = direct.iRay.camToHitPt(minPt)
self.hitPtDist = Vec3(self.hitPt - ZERO_POINT).length()
# Get the associated collision queue object
entry = direct.iRay.cq.getEntry(minPt)
# Extract the node
node = entry.getIntoNode()
self.hitPt.assign(hitPt)
self.hitPtDist = hitPtDist
# Constraint determined by nodes name
self.constraint = node.getName()
else:
@ -97,32 +87,11 @@ class DirectManipulationControl(PandaObject):
# depending on flag.....
if self.mode == 'select':
# Check for object under mouse
numEntries = direct.iRay.pickGeom(
render,direct.dr.mouseX,direct.dr.mouseY)
# Pick out the closest object that isn't a widget
index = -1
for i in range(0,numEntries):
entry = direct.iRay.cq.getEntry(i)
node = entry.getIntoNode()
if node.isHidden():
pass
# Is it a named node?, If so, see if it has a name
elif issubclass(node.__class__, NamedNode):
name = node.getName()
if name in self.unpickable:
pass
else:
index = i
break
else:
# Not hidden and not one of the widgets, use it
index = i
# Did we hit an object?
if(index >= 0):
# Yes!
# Find hit point in camera's space
self.hitPt = direct.iRay.camToHitPt(index)
self.hitPtDist = Vec3(self.hitPt - ZERO_POINT).length()
node, hitPt, hitPtDist = direct.iRay.pickGeom()
if node:
# Record hit point information
self.hitPt.assign(hitPt)
self.hitPtDist = hitPtDist
# Find the node path from the node found above
nodePath = render.findPathDownTo(node)
# Select it
@ -479,15 +448,32 @@ class DirectManipulationControl(PandaObject):
self.initScaleMag)
)
direct.widget.setScale(currScale)
## Utility functions ##
def plantSelectedNodePath(self):
""" Move selected object to intersection point of cursor on scene """
# Check for intersection
node, hitPt, hitPtDist = direct.iRay.pickGeom(
fIntersectUnpickable = 1)
# MRM: Need to handle moving COA
if (node != None) & (direct.selected.last != None):
# Record undo point
direct.pushUndo(direct.selected)
# Record wrt matrix
direct.selected.getWrtAll()
# Move selected
direct.widget.setPos(direct.camera, hitPt)
# Move all the selected objects with widget
# Move the objects with the widget
direct.selected.moveWrtWidgetAll()
# Let everyone know that something was moved
messenger.send('manipulateObjectCleanup')
class ObjectHandles(NodePath,PandaObject):
def __init__(self):
# Initialize the superclass
NodePath.__init__(self)
# Starts off deactivated
self.fActive = 0
# Load up object handles model and assign it to self
self.assign(loader.loadModel('models/misc/objectHandles'))
self.node().setName('objectHandles')
@ -540,6 +526,10 @@ class ObjectHandles(NodePath,PandaObject):
self.createGuideLines()
self.hideGuides()
# Start with widget handles hidden
self.fActive = 1
self.toggleWidget()
# Make sure object handles are never lit or drawn in wireframe
useDirectRenderStyle(self)
@ -551,10 +541,10 @@ class ObjectHandles(NodePath,PandaObject):
def toggleWidget(self):
if self.fActive:
self.reparentTo(hidden)
self.scalingNode.reparentTo(hidden)
self.fActive = 0
else:
self.reparentTo(direct.group)
self.scalingNode.reparentTo(self)
self.fActive = 1
def showWidgetIfActive(self):

View File

@ -2,6 +2,9 @@ from PandaObject import *
from DirectGeometry import *
from DirectSelection import *
UNPICKABLE = ['x-disc-visible', 'y-disc-visible', 'z-disc-visible',
'GridBack']
# MRM: To do: handle broken node paths in selected and deselected dicts
class DirectNodePath(NodePath):
# A node path augmented with info, bounding box, and utility methods
@ -394,14 +397,70 @@ class SelectionRay:
self.ct = CollisionTraverser( RenderRelation.getClassType() )
# Let the traverser know about the queue and the collision node
self.ct.addCollider(self.rayCollisionNode, self.cq )
# List of objects that can't be selected
self.unpickable = UNPICKABLE
def pickGeom(self, targetNodePath, mouseX, mouseY):
def pickGeom(self, targetNodePath = render, fIntersectUnpickable = 0):
self.collideWithGeom()
return self.pick(targetNodePath, mouseX, mouseY)
numEntries = self.pick(targetNodePath,
direct.dr.mouseX,
direct.dr.mouseY)
# Init index
index = -1
# Pick out the closest object that isn't a widget
for i in range(0,numEntries):
entry = direct.iRay.cq.getEntry(i)
node = entry.getIntoNode()
# Don't pick hidden nodes
if node.isHidden():
pass
# Can pick unpickable, use the first visible node
elif fIntersectUnpickable:
index = i
break
# Is it a named node?, If so, see if it has a name
elif issubclass(node.__class__, NamedNode):
name = node.getName()
if name in self.unpickable:
pass
else:
index = i
break
# Not hidden and not one of the widgets, use it
else:
index = i
break
# Did we hit an object?
if(index >= 0):
# Yes!
# Find hit point in camera's space
hitPt = direct.iRay.camToHitPt(index)
hitPtDist = Vec3(hitPt - ZERO_POINT).length()
return (node, hitPt, hitPtDist)
else:
return (None, ZERO_POINT, 0)
def pickWidget(self, targetNodePath, mouseX, mouseY):
def pickWidget(self, targetNodePath = render):
self.collideWithWidget()
return self.pick(targetNodePath, mouseX, mouseY)
numEntries = self.pick(targetNodePath,
direct.dr.mouseX,
direct.dr.mouseY)
# Did we hit a widget?
if numEntries:
# Yes!
# Entry 0 is the closest hit point if multiple hits
minPt = 0
# Find hit point in camera's space
hitPt = direct.iRay.camToHitPt(minPt)
hitPtDist = Vec3(hitPt).length()
# Get the associated collision queue object
entry = direct.iRay.cq.getEntry(minPt)
# Extract the node
node = entry.getIntoNode()
# Return info
return (node, hitPt, hitPtDist)
else:
return (None, ZERO_POINT, 0)
def pick(self, targetNodePath, mouseX, mouseY):
# Determine ray direction based upon the mouse coordinates

View File

@ -79,9 +79,8 @@ class DirectSession(PandaObject):
['SGENodePath_Delete', self.removeNodePath],
]
self.keyEvents = ['left', 'right', 'up', 'down',
'escape', 'space', 'delete',
'escape', 'delete', 'control', 'control-up',
'shift', 'shift-up', 'alt', 'alt-up',
'control', 'control-up',
'page_up', 'page_down', 'tab',
'[', '{', ']', '}',
'b', 'c', 'f', 'l', 's', 't', 'v', 'w']
@ -213,8 +212,8 @@ class DirectSession(PandaObject):
elif (input == ']') | (input == '}'):
self.redo()
def select(self, nodePath, fMultiselect = 0, fResetAncestry = 1):
dnp = self.selected.select(nodePath, fMultiselect)
def select(self, nodePath, fMultiSelect = 0, fResetAncestry = 1):
dnp = self.selected.select(nodePath, fMultiSelect)
if dnp:
messenger.send('preSelectNodePath', [dnp])
if fResetAncestry:
@ -465,6 +464,7 @@ class DirectSession(PandaObject):
# UTILITY FUNCTIONS
def useObjectHandles(self):
self.widget = self.manipulationControl.objectHandles
self.widget.reparentTo(direct.group)
def hideReadout(self):
self.readout.reparentTo(hidden)

View File

@ -60,6 +60,7 @@ classRenameDictionary = {
'LVecBase2f' : 'VBase2',
'LVector2f' : 'Vec2',
'LPoint2f' : 'Point2',
'LQuaternionf' : 'Quat',
'LMatrix4d' : 'Mat4D',
'LMatrix3d' : 'Mat3D',
'LVecBase4d' : 'VBase4D',
@ -71,6 +72,7 @@ classRenameDictionary = {
'LVecBase2d' : 'VBase2D',
'LVector2d' : 'Vec2D',
'LPoint2d' : 'Point2D',
'LQuaterniond' : 'QuatD',
'Plane' : 'PlaneBase',
'Planef' : 'Plane',
'Planed' : 'PlaneD',

View File

@ -59,23 +59,23 @@ class ParticlePanel(AppShell):
## SYSTEM PAGE ##
# Create system floaters
systemFloaterDefs = (
('System Pool size',
('System Pool Size',
'Size of particle pool',
self.setSystemPoolSize,
1.0, 1.0),
('System Birth rate',
('System Birth Rate',
'Seconds between particle births',
self.setSystemBirthRate,
0.0, None),
('System Litter size',
('System Litter Size',
'Number of particle created at each birth',
self.setSystemLitterSize,
1.0, 1.0),
('System Litter spread',
('System Litter Spread',
'Variation in litter size',
self.setSystemLitterSpread,
0.0, 1.0),
('System lifespan',
('System Lifespan',
'Age in seconds at which system should die',
self.setSystemLifespan,
0.0, None)
@ -83,17 +83,17 @@ class ParticlePanel(AppShell):
self.createFloaters(systemPage, systemFloaterDefs)
# Checkboxes
self.systemLocalVelocity = self.createCheckbutton(
systemPage, 'Local velocity',
systemPage, 'System Local Velocity',
self.toggleSystemLocalVelocity, 0)
self.systemGrowsOlder = self.createCheckbutton(
systemPage, 'System grows older',
systemPage, 'System Grows Older',
self.toggleSystemGrowsOlder, 0)
# Vector widgets
pos = self.createVector3Entry(systemPage, 'Pos',
pos = self.createVector3Entry(systemPage, 'System Pos',
'Particle system position',
command = self.setSystemPos)
pos.addMenuItem('Popup Placer Panel', Placer.Placer)
hpr = self.createVector3Entry(systemPage, 'Hpr',
hpr = self.createVector3Entry(systemPage, 'System Hpr',
'Particle system orientation',
fGroup_labels = ('H', 'P', 'R'),
command = self.setSystemHpr)
@ -107,27 +107,27 @@ class ParticlePanel(AppShell):
('Point', 'Z Spin', 'Oriented'),
self.selectFactoryType)
factoryWidgets = (
('Life span',
('Factory Life Span',
'Average lifespan in seconds',
self.setFactoryLifeSpan,
0.0, None),
('Life span spread',
('Factory Life Span Spread',
'Variation in lifespan',
self.setFactoryLifeSpanSpread,
0.0, None),
('Mass',
('Factory Mass',
'Average particle mass',
self.setFactoryParticleMass,
0.0, None),
('Mass spread',
('Factory Mass Spread',
'Variation in particle mass',
self.setFactoryParticleMassSpread,
0.0, None),
('Terminal velocity',
('Factory Terminal Velocity',
'Average particle terminal velocity',
self.setFactoryTerminalVelocity,
0.0, None),
('Terminal vel. spread',
('Factory Terminal Vel. Spread',
'Variation in terminal velocity',
self.setFactoryTerminalVelocitySpread,
0.0, None))
@ -138,13 +138,13 @@ class ParticlePanel(AppShell):
factoryPointPage = self.factoryNotebook.add('Point')
# Z spin page #
zSpinPage = self.factoryNotebook.add('Z Spin')
self.createAngleDial(zSpinPage, 'Initial angle',
self.createAngleDial(zSpinPage, 'Z Spin Initial Angle',
'Starting angle in degrees',
command = self.setFactoryZSpinInitialAngle)
self.createAngleDial(zSpinPage, 'Final angle',
self.createAngleDial(zSpinPage, 'Z Spin Final Angle',
'Final angle in degrees',
command = self.setFactoryZSpinFinalAngle)
self.createAngleDial(zSpinPage, 'Angle spread',
self.createAngleDial(zSpinPage, 'Z Spin Angle Spread',
'Spread of the final angle',
command = self.setFactoryZSpinAngleSpread)
# Oriented page #
@ -164,18 +164,19 @@ class ParticlePanel(AppShell):
self.emitterNotebook = Pmw.NoteBook(emitterPage, tabpos = None)
# Box page #
boxPage = self.emitterNotebook.add('Box')
self.createVector3Entry(boxPage, 'Point 1',
'Point defining emitter box',
self.createVector3Entry(boxPage, 'Box Emitter Min',
'Min point defining emitter box',
command = self.setEmitterBoxPoint1)
self.createVector3Entry(boxPage, 'Point 2',
'Point defining emitter box',
self.createVector3Entry(boxPage, 'Box Emitter Max',
'Max point defining emitter box',
command = self.setEmitterBoxPoint2,
initialValue = (1.0, 1.0, 1.0))
self.createVector3Entry(boxPage, 'Velocity vector',
'Initial particle velocity vector',
'Initial particle velocity vector',
command = self.setEmitterBoxVelocityVector)
# Disc page #
discPage = self.emitterNotebook.add('Disc')
self.emitter
self.createFloater(discPage, 'Radius', 'Radius of disc',
command = self.setEmitterDiscRadius)
self.createAngleDial(discPage, 'Inner angle',
@ -195,23 +196,24 @@ class ParticlePanel(AppShell):
self.toggleEmitterDiscCubicLerping, 0)
# Line page #
linePage = self.emitterNotebook.add('Line')
self.createVector3Entry(linePage, 'Point 1',
'Point defining emitter line',
self.createVector3Entry(linePage, 'Line Emitter Min',
'Min point defining emitter line',
command = self.setEmitterLinePoint1)
self.createVector3Entry(linePage, 'Point 2',
'Point defining emitter line',
self.createVector3Entry(linePage, 'Line Emitter Max',
'Max point defining emitter line',
command = self.setEmitterLinePoint2,
initialValue = (1.0, 0.0, 0.0))
self.createVector3Entry(linePage, 'Velocity Vector',
self.createVector3Entry(linePage, 'Line Emitter Velocity',
'Initial particle velocity vector',
command = self.setEmitterLineVelocityVector,
initialValue = (0.0, 0.0, 1.0))
# Point page #
emitterPointPage = self.emitterNotebook.add('Point')
self.createVector3Entry(emitterPointPage, 'Position',
self.createVector3Entry(emitterPointPage, 'Point Emitter Position',
'Position of emitter point',
command = self.setEmitterPointPosition)
self.createVector3Entry(emitterPointPage, 'Velocity vector',
self.createVector3Entry(emitterPointPage,
'Point Emitter Velocity',
'Initial particle velocity vector',
command = self.setEmitterPointVelocityVector,
initialValue = (0.0, 0.0, 1.0))
@ -374,11 +376,12 @@ class ParticlePanel(AppShell):
def createCheckbutton(self, parent, text, command, initialState):
bool = BooleanVar()
bool.set(initialState)
cb = Checkbutton(parent, text = text, anchor = W,
widget = Checkbutton(parent, text = text, anchor = W,
variable = bool)
# Do this after the widget so command isn't called on creation
cb.command = command
cb.pack(fill = X)
widget['command'] = command
widget.pack(fill = X)
self.widgetDict['text'] = widget
return bool
def createFloaters(self, parent, widgetDefinitions):
@ -412,6 +415,7 @@ class ParticlePanel(AppShell):
widget['command'] = command
widget.pack(fill = X)
self.bind(widget, balloonHelp)
self.widgetDict['text'] = widget
return widget
def createVector3Entry(self, parent, text, balloonHelp,
@ -423,6 +427,7 @@ class ParticlePanel(AppShell):
widget['command'] = command
widget.pack(fill = X)
self.bind(widget, balloonHelp)
self.widgetDict['text'] = widget
return widget
def createColorEntry(self, parent, text, balloonHelp,
@ -434,6 +439,7 @@ class ParticlePanel(AppShell):
widget['command'] = command
widget.pack(fill = X)
self.bind(widget, balloonHelp)
self.widgetDict['text'] = widget
return widget
def createOptionMenu(self, parent, text, balloonHelp, items, command):
@ -447,6 +453,7 @@ class ParticlePanel(AppShell):
widget['command'] = command
widget.pack(fill = X)
self.bind(widget.component('menubutton'), balloonHelp)
self.widgetDict['text'] = widget
return optionVar
### PARTICLE SYSTEM COMMANDS ###
@ -500,6 +507,39 @@ class ParticlePanel(AppShell):
def selectEmitterType(self, type):
self.emitterNotebook.selectpage(type)
self.particles.setEmitter(type)
self.updateEmitterWidgets()
def updateEmitterWidgets(self):
emitter = self.particles.emitter
if isinstance(emitter, BoxEmitter):
min = emitter.getMinBound()
self.emitterBoxPoint1VectorEntry.set(
[min[0], min[1], min[2]])
max = emitter.getMaxBound()
self.emitterBoxPoint2VectorEntry.set(
[max[0], max[1], max[2]])
elif isinstance(emitter, DiscEmitter):
radius = emitter.getRadius()
cubicLerping = emitter.getCubicLerping()
innerAngle = emitter.getInnerAngle()
getInnerMagnitude
getOuterAngle
getOuterMagnitude
elif isinstance(emitter, LineEmitter):
pass
elif isinstance(emitter, PointEmitter):
pass
elif isinstance(emitter, RectangleEmitter):
pass
elif isinstance(emitter, RingEmitter):
pass
elif isinstance(emitter, SphereVolumeEmitter):
pass
elif isinstance(emitter, SphereSurfaceEmitter):
pass
elif isinstance(emitter, TangentRingEmitter):
pass
# Box #
def setEmitterBoxPoint1(self, point):
self.particles.emitter.setMinBound(Point3(point[0],

View File

@ -64,6 +64,7 @@ class Placer(AppShell):
self.initPos = Vec3(0)
self.initHpr = Vec3(0)
self.initScale = Vec3(1)
self.deltaHpr = Vec3(0)
# Offset for orbital mode
self.posOffset = Vec3(0)
@ -450,7 +451,7 @@ class Placer(AppShell):
else:
if name == 'widget':
# Record relationship between selected nodes and widget
direct.selected.getWrtAll()
direct.selected.getWrtAll()
# Update active node path
self.setActiveNodePath(nodePath)
@ -459,10 +460,19 @@ class Placer(AppShell):
if self['nodePath']:
self.nodePathMenuEntry.configure(
background = self.nodePathMenuBG)
# Check to see if node path and ref node path are the same
if ((self.refCS != None) &
(self.refCS.id() == self['nodePath'].id())):
# Yes they are, use temp CS as ref
# This calls updatePlacer
self.setReferenceNodePath(self.tempCS)
# update listbox accordingly
self.refNodePathMenu.selectitem('self')
else:
# Record initial value and initialize the widgets
self.updatePlacer()
# Record initial position
self.updateResetValues(self['nodePath'])
# Record initial value and initialize the widgets
self.updatePlacer()
else:
# Flash entry
self.nodePathMenuEntry.configure(background = 'Pink')
@ -494,7 +504,12 @@ class Placer(AppShell):
# Clear bogus entry from listbox
listbox = self.refNodePathMenu.component('scrolledlist')
listbox.setlist(self.refNodePathNames)
# Update ref node path accordingly
# Check to see if node path and ref node path are the same
if (nodePath != None) & (nodePath.id() == self['nodePath'].id()):
# Yes they are, use temp CS and update listbox accordingly
nodePath = self.tempCS
self.refNodePathMenu.selectitem('self')
# Update ref node path
self.setReferenceNodePath(nodePath)
def setReferenceNodePath(self, nodePath):
@ -594,6 +609,8 @@ class Placer(AppShell):
taskMgr.removeTasksNamed('followSelectedNodePath')
# Record relationship between selected nodes and widget
direct.selected.getWrtAll()
# Record initial state
self.deltaHpr = self['nodePath'].getHpr(self.refCS)
# Update placer to reflect new state
self.updatePlacer()
@ -609,7 +626,6 @@ class Placer(AppShell):
def xformRelative(self, value, axis):
nodePath = self['nodePath']
if (nodePath != None) & (self.refCS != None):
if axis == 'x':
nodePath.setX(self.refCS, value)
@ -617,12 +633,15 @@ class Placer(AppShell):
nodePath.setY(self.refCS, value)
elif axis == 'z':
nodePath.setZ(self.refCS, value)
elif axis == 'h':
nodePath.setH(self.refCS, value)
elif axis == 'p':
nodePath.setP(self.refCS, value)
elif axis == 'r':
nodePath.setR(self.refCS, value)
else:
if axis == 'h':
self.deltaHpr.setX(value)
elif axis == 'p':
self.deltaHpr.setY(value)
elif axis == 'r':
self.deltaHpr.setZ(value)
# Put node path at new hpr
nodePath.setHpr(self.refCS, self.deltaHpr)
def xformOrbit(self, value, axis):
nodePath = self['nodePath']

View File

@ -163,11 +163,11 @@ class VectorEntry(Pmw.MegaWidget):
def getAt(self,index):
return self._value[index]
def set(self, value):
def set(self, value, fCommand = 0):
for i in range(self['dim']):
self._value[i] = value[i]
self.variableList[i].set(self.entryFormat % value[i])
self.action()
self.action(fCommand)
def setAt(self, index, value):
self.variableList[index].set(self.entryFormat % value)
@ -207,9 +207,9 @@ class VectorEntry(Pmw.MegaWidget):
if self._floaters:
self._floaters.set(self._value, 0)
def action(self):
def action(self, fCommand = 0):
self._refreshFloaters()
if self['command']:
if fCommand & (self['command'] != None):
self['command'](self._value)
def reset(self):