View Single Post
  #5  
Old 08-14-2008, 07:00 PM
John P John P is offline
Member
 
Join Date: Jun 2006
Posts: 8
I have some code that you can feel free to use. It might be overkill but it should do the job.

It uses an action to build a billboard like behavior. eg. the billboard node looks directly at the camera position rather than matching the camera alignment. It was useful in a cave scenario. It also deals with Z order and depth write to ensure the text is visible.

Otherwise you just call AttachSpeechBubble to float some text above an object.

Code:
import viz

viz.go()

#########Utility Class and Functions for Speech Bubble############
# all you need to call is AttachSpeechBubble
#code is based upon worldviz avatar lookat tutorial
MAXLINELENGTH = 60
class BillboardToNodeAction(viz.ActionClass):	
	def begin(self,object):
		"""Called once when action starts"""
		self.nodeToLookAt = self._actiondata_.data[0]
		self.nodeToModify = self._actiondata_.data[1]
		self.duration = self._actiondata_.data[2]        
		self.blendIn = self._actiondata_.data[3]
		self.timeElapsed = 0
		self.startQuat = self.nodeToModify.getQuat()
	def update(self,elapsed,object):
		self.timeElapsed += elapsed     
		p = 1
		if self.blendIn <> 0.0:
			p = self.timeElapsed / self.blendIn
			
		positionToLookAt = self.nodeToLookAt.getPosition()
		for ix in range(3):
			positionToLookAt[ix] = self.nodeToModify.getPosition()[ix] + self.nodeToModify.getPosition()[ix] - positionToLookAt[ix]
		if self.duration > 0.0 and self.timeElapsed > self.duration:
			self.nodeToModify.lookat(positionToLookAt, 0, viz.ABS_GLOBAL)
			self.end(object) 
		elif p < 1.0:
			self.nodeToModify.lookat( positionToLookAt, 0, viz.ABS_GLOBAL )
			targetQuat = self.nodeToModify.getQuat()
			nextQuad = vizmat.slerp(self.startQuat,targetQuat,p)
			self.nodeToModify.setQuat(nextQuad)
		else:
			self.nodeToModify.lookat(positionToLookAt, 0, viz.ABS_GLOBAL)
	def end(self,object):
		viz.ActionClass.end(self,object)

#Function to construct the action instance
def billboardNode( nodeToLookAt, nodeToModify, duration = viz.FOREVER, blendIn = 0.0):
    action = viz.ActionData()
    action.data = [ nodeToLookAt, nodeToModify, duration, blendIn ]
    action.actionclass = BillboardToNodeAction
    return action

def FormatTextbox(msg):
	length = len(msg)
			
	lastspace = 0	
	while lastspace + MAXLINELENGTH < length and lastspace <> -1:
		lastspace = msg.rfind(' ',lastspace, lastspace + MAXLINELENGTH)
		if lastspace > 0 and lastspace < length:
			msg = msg[:lastspace] + '\n' + msg[lastspace+1:]
		else:
			lastspace = -1
			
	lines = msg.splitlines()
						
	return lines

def AttachSpeechBubble(dest,message, height = 1.8):
	
	lines = FormatTextbox(message)
	
	rootline = 0
	parentline = 0
	for lineix in range(len(lines),0,-1):
		speechline = viz.addText(lines[lineix-1])
		speechline.alignment(viz.TEXT_CENTER_BOTTOM)
		if not rootline:
			rootline = speechline
			parentline = speechline
		else:
			speechline.parent(parentline)		
			parentline = speechline
			speechline.translate([0,1.0,0])
		speechline.draworder(13)
		speechline.depthFunc(viz.GL_ALWAYS)
		speechline.disable(viz.DEPTH_WRITE)
		
	speechtext = rootline

	speechbox = speechtext.getBoundingBox()
	speechtext.setScale([0.12,0.12,0.12])

	viz.startlayer(viz.QUADS)
	viz.vertex(speechbox.xmin-0.1,speechbox.ymax+0.1,0)
	viz.vertex(speechbox.xmax+0.1,speechbox.ymax+0.1,0)
	viz.vertex(speechbox.xmax+0.1,speechbox.ymin-0.1,0)
	viz.vertex(speechbox.xmin-0.1,speechbox.ymin-0.1,0)
	speechquad = viz.endlayer()
	speechquad.color([0,0,0])
	speechquad.disable(viz.CULL_FACE)
	speechquad.parent(speechtext)
	speechquad.draworder(12)
	speechquad.alpha(0.5)
	speechquad.depthFunc(viz.GL_ALWAYS)
	speechquad.disable(viz.DEPTH_WRITE)
	
	if type(dest) == list:
		speechtext.translate(dest)
	else:
		linkposition = viz.link(dest, speechtext)
		linkposition.setMask(viz.LINK_POS)
		linkposition.preTrans([0, height, 0])

	speechtext.addAction(billboardNode(viz.MainView,speechtext))
	
	return speechtext
#################################	
	
viz.clearcolor(0,0,0.5)
box = viz.add("box.wrl")
box.setPosition(0,2,7)

AttachSpeechBubble(dest = box,message = "This text floats above the box",height = 1.0)
Reply With Quote