""" NodePath for Jam-o-Drum model @author: Ben Buchwald Last Updated: 11/29/2005 @var DRUMPAD_RADIUS: constant representing the radius of the drumpad as a percentage of the radius of the table @type DRUMPAD_RADIUS: float @var SPINNER_RADIUS: constant representing the radius of the spinner as a percentage of the radius of the table @type SPINNER_RADIUS: float """ from direct.showbase.DirectObject import DirectObject from direct.showbase.Audio3DManager import Audio3DManager from direct.gui.DirectGui import * from direct.task import Task import math from pandac.PandaModules import NodePath from pandac.PandaModules import Texture, CardMaker, DepthOffsetAttrib, OrthographicLens DRUMPAD_RADIUS = .167 SPINNER_RADIUS = .254 class JamoDrumNodePath(NodePath): """ A C{NodePath} of a heirarchy of a Jam-o-Drum. Creating one of these sets up the camera as well for displaying an orthographic view of this Jam-o-drum @ivar stations: list of 4 L{Station} objects representing each Jam-o-Drum station @type stations: L{Station}[] """ def __init__(self,table=None,mask=None): """ @keyword table: filename of a table texture. See table_template.psd. Either paint anywhere inside the mask for a complete background or turn off the pads and spinner and paint in the table circle for just a table texture that will have spinners and pads put on top of it. @type mask: str @keyword mask: filename of a mask texture of the non-Jam-o-Drum area. probably jod_mask.png that comes with the Jam-o-Drum library. @type mask: str """ NodePath.__init__(self,"JamoDrum") totalHeight = max(1.0,math.sqrt(2)/4.0+SPINNER_RADIUS)*2 cm = CardMaker("card") cm.setFrame(-1,1,-1,1) self.tableCard = self.attachNewNode(cm.generate()) self.tableCard.setP(-90) self.tableCard.setScale(4.0/3.0) self.tableCard.setLightOff() self.tableCard.setBin("background",0) self.tableCard.setDepthTest(0) self.tableCard.setDepthWrite(0) self.tableCard.hide() if (table): self.setTableTexture(loader.loadTexture(table)) if (mask): cm = CardMaker("JOD Mask") cm.setFrame(-4.0/3.0,4.0/3.0,-4.0/3.0,4.0/3.0) self.mask = aspect2d.attachNewNode(cm.generate()) #self.mask.setP(-90) self.mask.setTexture(loader.loadTexture(mask),1) self.mask.setTransparency(1) self.mask.setDepthTest(0) else: self.mask = None self.stations = [] for i in range(4): station = Station(self,i) station.reparentTo(self) self.stations.append(station) self.reparentTo(render) base.disableMouse() self.lens = OrthographicLens() self.lens.setFilmSize(totalHeight*base.getAspectRatio(),totalHeight) base.cam.node().setLens(self.lens) camera.setPosHpr(0,0,10.0, 0,-90,0) base.setBackgroundColor(0,0,0) self.audio3d = Audio3DManager(base.sfxManagerList[0],self) self.audio3d.setDropOffFactor(0) # end __init__ def setTableTexture(self,texture,scale=None): """ sets the background texture on the table @param texture: C{Texture} or image file to show on the table @type texture: C{Texture} or string @keyword scale: scale of the texture. Default is set for the table_template.psd @type scale: float """ if (not isinstance(texture,Texture)): texture = loader.loadTexture(texture) self.tableCard.setTexture(texture) if (scale): self.tableCard.setScale(scale) self.showTable() # end setTableTexture def showTable(self): """ displays the table's background texture """ self.tableCard.show() # end showTable def hideTable(self): """ hides the table's background texture """ self.tableCard.hide() # end hideSpinner def loadSfx(self,file,object=None): """ load a sound with positional audio support @param file: wav file to load. Must be mono. @type file: string @keyword object: object to attach sound to @type object: C{NodePath} @return: a Panda sound object @rtype: C{AudioSound} """ sfx = self.audio3d.loadSfx(file) if (object): self.attachSoundToObject(sfx,object) return sfx # loadSfx def attachSoundToObject(self,sound,object): """ attach a positional sound to an object it will come from @param sound: positional sound object to attach @type sound: C{AudioSound} @param object: object sound should come from @type object: C{NodePath} """ self.audio3d.attachSoundToObject(sound,object) # end attachSoundToObject def detachSound(self,sound): """ detach a positional sound from it's object. It will no longer move. @param sound: positional sound object to detach @type sound: C{AudioSound} """ self.audio3d.detachSound(sound) # end detachSound # end class JamoDrum class Station(NodePath): """ A C{NodePath} to a specific Jam-o-Drum station. This C{NodePath} should contain subparts call pad and spinner. This is automatically created by L{JamoDrumNodePath} and should not be created by hand. @ivar index: index of this station (0-3) @type index: int @ivar pad: C{NodePath} to the pad subpart @type pad: C{NodePath} @ivar spinner: C{NodePath} to the spinner subpart @type spinner: C{NodePath} """ def __init__(self,jod,index): """ @param jod: containing Jam-o-Drum @type jod: L{JamoDrumNodePath} @param index: index of the station @type index: int """ NodePath.__init__(self,"station%02d"%index) self.jod = jod self.index = index angle = 45.0-self.index*90.0 self.setPos(math.cos((angle-90.0)*math.pi/180.0),math.sin((angle-90.0)*math.pi/180.0),0) self.setH(angle) cm = CardMaker("card") cm.setFrame(-1,1,-1,1) self.spinner = self.attachNewNode("spinner") self.spinnerCard = self.spinner.attachNewNode(cm.generate()) self.spinnerCard.setTransparency(1) self.spinnerCard.setBin("background",1) self.spinnerCard.node().setAttrib(DepthOffsetAttrib.make(1)) self.spinnerCard.setScale(1.0/3.0) self.spinnerCard.setP(-90) self.spinnerCard.setLightOff() self.spinnerCard.hide() self.pad = self.attachNewNode("pad") self.padCard = self.pad.attachNewNode(cm.generate()) self.padCard.setTransparency(1) self.padCard.setBin("background",2) self.padCard.node().setAttrib(DepthOffsetAttrib.make(2)) self.padCard.setScale(1.0/3.0) self.padCard.setP(-90) self.padCard.setLightOff() self.padCard.hide() # end __init__ def getParent(self): """ get the containing L{JamoDrumNodePath} @return: the containing Jam-o-Drum @rtype: L{JamoDrumNodePath} """ return self.jod # end getParent def setSpinnerTexture(self,texture,scale=None): """ sets the background texture on the spinner @param texture: C{Texture} or image file to show on the spinner @type texture: C{Texture} or string @keyword scale: scale of the texture. Default is set for the spinner_template.psd @type scale: float """ if (not isinstance(texture,Texture)): texture = loader.loadTexture(texture) self.spinnerCard.setTexture(texture) if (scale): self.spinnerCard.setScale(scale) self.showSpinner() # end setSpinnerTexture def setPadTexture(self,texture,scale=None): """ sets the background texture on the pad @param texture: C{Texture} or image file to show on the pad @type texture: C{Texture} or string @keyword scale: scale of the texture. Default is set for the spinner_template.psd @type scale: float """ if (not isinstance(texture,Texture)): texture = loader.loadTexture(texture) self.padCard.setTexture(texture) if (scale): self.padCard.setScale(scale) self.showPad() # end setPadTexture def showSpinner(self): """ displays the spinner's background texture """ self.spinnerCard.show() # end showSpinner def showPad(self): """ displays the pad's background texture """ self.padCard.show() # end showPad def hideSpinner(self): """ hides the spinner's background texture """ self.spinnerCard.hide() # end hideSpinner def hidePad(self): """ hide the pad's background texture """ self.padCard.hide() # end hidePad def loadSfx(self,file,object=None): """ load a sound with positional audio support and attach it to this station @param file: wav file to load. Must be mono. @type file: string @keyword object: object to attach sound to. default: this station @type object: C{NodePath} @return: a Panda sound object @rtype: C{AudioSound} """ return self.jod.loadSfx(file,object or self) #end loadSfx def attachSound(self,sound,object=None): """ attach a positional sound to this station @param sound: positional sound object to attach @type sound: C{AudioSound} @keyword object: object sound should come from. default: this station @type object: C{NodePath} """ self.jod.attachSoundToObject(sound,object or self) # end attachSound # end class Station