| events |
| blueButtonDown: anEvent
|
| selected |
selected := pointer selectedObject.
(selected notNil and:[selected wantsBlueButton]) ifTrue:[
pointer pointerDown: anEvent.
].
|
| blueButtonUp: anEvent
|
| selected |
selected := pointer selectedObject.
(selected notNil and:[selected wantsBlueButton]) ifTrue:[
pointer pointerUp: anEvent. ]
|
| dropFiles: aFileStream event: evt
|
pointer dropFiles: aFileStream event: evt.
|
| goToSnapshot: item
|
item verifyProperlyVeiled.
avatar future: 50.0 perform: #goToPortal:transform: withArguments: { item root . item globalTransform }.
self killFrame: true.
|
| gotoSpace: aSpace transform: aTransform
|
avatar future: 50.0 perform: #goToPortal:transform: withArguments: { aSpace . aTransform }.
self killFrame: true.
|
| keyDown: anEvent
|
pointer keyDown: anEvent.
|
| keyStroke: anEvent
|
anEvent keyValue = 1 ifTrue: [ thirdPersonDelta _ (thirdPerson cNot)-(thirdPerson cNotNot) * 0.1. ^ self.].
anEvent keyValue = 2 ifTrue: [ self halt. ].
anEvent keyValue = 4 ifTrue:[ self snapshot. ^self].
anEvent keyValue = 18 ifTrue:[ self switchMirror. ^ self.].
anEvent keyValue = 19 ifTrue:[
self root ambientSoundPlaying ifTrue:[
self root stopAmbientSound.] ifFalse:[
self root startAmbientSound].
^ self. ].
(anEvent keyValue = 3) ifTrue:[
"Need some sort of visual indication here...."
self isChatting
ifTrue:[self endChat]
ifFalse:[self startChat].
^ self.
].
anEvent keyValue = 30 ifTrue:[ self translation: self translation + (0@1@0).].
anEvent keyValue = 31 ifTrue:[ self translation: self translation - (0@1@0).].
(pointer wantsKeyboard: anEvent)
ifTrue:[pointer keyStroke: anEvent]
ifFalse:[Croquet world morph consoleMorph keyStroke: anEvent].
|
| keyUp: anEvent
|
pointer keyUp: anEvent.
|
| mouseDown: evt
|
| root |
self pointerXY: evt cursorPoint.
remoteControl ifNotNil:[
root _ remoteControl root.
remoteControl removeChild: self.
root addChild: self.
self localTransform: remoteControl globalTransform.
self downPointer setAutomatic: true.
self setDoRender: true.
remoteControl _ nil.
avatar forwardOnY: 6.
].
mouseDownTime _ evt timeStamp.
(evt controlKeyPressed not and:[evt yellowButtonPressed]) ifTrue:[
yellowButtonPressed _ true.
avatar startDriving: evt shiftPressed.
].
evt redButtonPressed ifTrue:[
redButtonPressed _ true.
(pointer pointerDown: evt) ifFalse:[self makePopup.].
] ifFalse:[
pointer event2D: evt.
].
|
| mouseMove: evt
|
"evt is a MouseMoveEvent"
self pointerXY: evt position.
(evt anyButtonPressed and:[ evt yellowButtonPressed not]) ifTrue:[
self pointer pointerMove: evt asMouseMove.
] ifFalse:[
self pointer event2D: evt asMouseMove.
].
|
| mouseUp: evt
|
yellowButtonPressed ifTrue:[
evt timeStamp - mouseDownTime < 250 ifTrue:[
avatar snapTrans ifNotNil:[avatar snapBack.] ifNil:[
pointer selectedObject ifNotNil:[
pointer selectedObject isWindow ifTrue:[ pointer selectedObject gotoWindow:pointer.].].].
] ifFalse:[ avatar snapTrans: nil.].
yellowButtonPressed_ false.
avatar stopDriving.
].
redButtonPressed ifTrue:[
pointer pointerUp: evt.
redButtonPressed _ false.].
self pointerXY: evt cursorPoint.
|
| openHalo
|
| |
Croquet world morph addHalo.
|
| openHalo: ptr
|
| |
Croquet world morph addHalo.
|
| pointerXY: pxy
|
| xy |
xy _ pxy - viewPort topLeft.
pointer pointerXY: xy.
pointer calcTransform: self bounds z: zScreen.
"avatar speedControl: (self bounds center - xy)/ (self bounds extent *0.5).
avatar pointerTransform: pointer. CHANGED SAVING A MESSAGE:"
avatar speedControl: (self bounds center - xy)/ (self bounds extent *0.5) pointerTransform: pointer.
^ xy.
|
| switchMirror
|
rearCam ifNil:[
rearCam _ TOverlayRearView new initialize: self viewPort.
overlays add: rearCam.
] ifNotNil:[ overlays remove: rearCam. rearCam _ nil.].
|
| morph import |
| makeLinkToProject: projName
|
"import an existing morphic project, creating a window for it in front of the camera"
| win tmorph htp newWorld |
tmorph _ TMorphic new initializeOpaque: true extent: 512@512.
htp _ Croquet world homeTeaParty.
newWorld _ (htp global: #TMorphMonitor) new initializeWithWorld: projName opaque: true extent: tmorph targetExtent.
newWorld eventsTo: tmorph.
win _ self makeWindowInFront.
win contents: tmorph.
^ win.
|
| makeLocalProjectWithMorph: aMorph
|
"put a morph into a new morphic project, creating a window for it in front of the camera"
| win tmorph newWorld |
tmorph _ TMorphic new initializeOpaque: true extent: 512@512.
newWorld _ TMorphMonitor createLocalProjectWithExtent: tmorph extent initialMorph: aMorph.
newWorld eventsTo: tmorph.
win _ self makeWindowInFront.
win contents: tmorph.
^ win.
|
| makePicture: aFile
|
| win image txtr |
[[aFile binary.
image _ Form fromBinaryStream: (RWBinaryOrTextStream with: aFile contents) reset]
ensure: [aFile close].
"make a picture from a form, and put it in a window in front of the camera"
txtr _ TTexture new.
txtr initializeWithForm: image
mipmap: true
shrinkFit: false.]
on: Error do: [ :ex |
txtr _ TTexture new initializeWithForm: TForm defaultTForm mipmap: true shrinkFit: true.
ex return. ].
win _ self makeWindowInFront.
win contents: txtr.
^ win
|
| makePortal: aPortal
|
"make a portal in front of me, linking to another portal"
| win |
win _ self makeWindowInFront.
win contents: (TPortal new linkPortal: aPortal).
^ win.
|
| painter |
| clickOpenAliceFile: filePath
|
| frame trans teaUrl model |
teaUrl := 'http://www.reed.com/TeaLand'.
2 to: filePath size do:[:i| teaUrl := teaUrl,'/', (filePath at: i)].
teaUrl := (teaUrl allButLast: 4), '.tea'.
model := CroquetData loadAliceModel: filePath url: teaUrl.
trans _ self translation - (self lookAt * 10).
frame _ TSpinner new.
frame matNil.
frame translation: trans.
frame contents: model.
avatar root addChild: frame.
frame translation: trans.
avatar root addChild: frame.
|
| makePoohMeshFrom: aForm
|
| list pts subdivision mask |
mask := Form extent: aForm extent*2 depth: 1.
(WarpBlt toForm: mask)
sourceForm: aForm destRect: mask boundingBox;
combinationRule: Form over;
cellSize: 1;
colorMap: (Color maskingMap: aForm depth);
warpBits.
subdivision := PoohSubdivision withSize: (mask boundingBox).
list := mask traceOutlines.
list := list collect:[:poly|
poly collect:[:loop|
pts _ StrokeSimplifier new.
loop do:[:pt| pts add: pt].
pts closeStroke.
pts := pts finalStroke.
pts := StrokeSimplifier smoothen: pts length: 10.
pts := LineIntersections regularize: pts.
pts do:[:pt| subdivision insertPoint: pt].
pts]].
list := list collect:[:poly|
poly collect:[:loop| subdivision constraintOutline: loop].
].
list do:[:poly|
poly keysAndValuesDo:[:index :loop|
subdivision markExteriorEdges: (index = 1) in: loop.
].
].
^subdivision build3DObject: false.
|
| makePoohObjectFrom: aForm player: aPlayer rotateBy: rot replaceOldCostume: aBoolean
|
| aSpace pts bbForm tex mat subdivision b3dMesh mesh pos scale tfm |
"Convert the form"
bbForm := Form extent: aForm extent asSmallerPowerOfTwo depth: 32.
aForm displayScaledOn: bbForm in: (bbForm boundingBox insetBy: 1).
"Smear the borders of the texture a bit to prevent problems in texture mapping"
bbForm smearFill: 10. "pixels - less is faster but more is safer"
aSpace := avatar root.
"Create the texture"
tex := TTexture new initializeWithForm: bbForm mipmap: true shrinkFit: true extension: #colorKeyZero.
"The material"
mat _ TMaterial new.
mat ambientColor: #(1 1 1 1) asFloatArray.
mat diffuseColor: #(1 1 1 1) asFloatArray.
mat texture: tex.
mat textureMode: GLModulate.
"The b3d mesh"
true ifTrue:[
b3dMesh := self makePoohMeshFrom: aForm.
scale := 0.01.
] ifFalse:[
pts _ StrokeSimplifier new.
aForm traceOutline: Color transparent do:[:aPoint| pts add: aPoint].
pts closeStroke.
pts := pts finalStroke.
pts := StrokeSimplifier smoothen: pts length: 10.
pts := LineIntersections regularize: pts.
subdivision _ PoohSubdivision constraintOutline: pts.
b3dMesh _ subdivision build3DObject: false. "single sided textures"
scale := 0.02.
].
tfm := (B3DRotation axis: 1@0@0 angle: 180) asMatrix4x4.
tfm := tfm composeWith: (B3DRotation axis: 0@1@0 angle: rot) asMatrix4x4.
tfm := tfm composeWith: (B3DMatrix4x4 withScale: scale@scale@scale).
tfm := tfm composeWith: (B3DMatrix4x4 withOffset: (aForm width * -0.5) @ (aForm height * -0.5) @ 0).
b3dMesh transformBy: tfm.
"The TMesh"
mesh := TMesh new initializeWithVertices: b3dMesh vertices
alias: nil
norms: b3dMesh vertexNormals
textureUV: b3dMesh texCoords
faceGroups: {1. b3dMesh zeroBasedFaceGroup}
material: mat.
mesh solid: false.
mesh initBounds.
TDragBehavior attachTo: mesh.
aPlayer ifNotNil:[
aBoolean
ifTrue:[aPlayer frame replaceUserCostume: mesh sketch: aForm]
ifFalse:[aPlayer frame addUserCostume: mesh sketch: aForm].
^self].
"Position it"
pos := avatar translation - (avatar lookAt * 10).
mesh translation: pos.
mesh rotationAroundY: avatar yaw + rot.
aSpace addChild: mesh.
"mesh startScript:[mesh turnTo: cWorld activeCamera]."
"self tweakWorld ifNotNil:[
mesh replaceUserCostume: mesh sketch: aForm.
aSpace player signal: #created with: mesh player.
]."
|
| popUpBillboard: aForm player: aPlayer
|
| aSpace bbForm size billboard aPosition txtr mat |
aSpace := self root.
size := aForm extent * 0.01.
bbForm := Form extent: aForm extent asSmallerPowerOfTwo depth: 32.
aForm displayScaledOn: bbForm in: (bbForm boundingBox insetBy: 1).
billboard := TBillboard new.
txtr := TTexture new initializeWithForm: aForm mipmap: true shrinkFit: true extension: #colorKeyZero.
txtr aspect: size y / size x asFloat.
txtr extent: size.
txtr objectOwner: billboard.
mat _ TMaterial new.
mat ambientColor: #(1 1 1 0.99) asFloatArray.
mat diffuseColor: #(1 1 1 0.99) asFloatArray.
mat emissiveColor: #(1 1 1 0.99) asFloatArray.
txtr material: mat.
txtr extent: txtr extent * 3.
TDragBehavior attachTo: billboard.
billboard addChild: txtr.
aPlayer ifNotNil:[
aPlayer frame: billboard.
aPlayer sketch: aForm.
aPlayer icon: nil.
^self].
billboard player sketch: aForm.
aPosition := self translation - (self lookAt * 10).
billboard translation: aPosition.
aSpace addChild: billboard.
"
| pos size aSpace bbForm |
size := aForm extent * 0.01.
bbForm := Form extent: aForm extent asSmallerPowerOfTwo depth: 32.
aForm displayScaledOn: bbForm in: (bbForm boundingBox insetBy: 1).
pos := cWorld activeCamera translation + (cWorld activeCamera lookAt * 10).
aSpace := cWorld activeCamera root.
aSpace popUpBillboard: bbForm extent: size at: pos.
aSpace asyncSend: #popUpBillboard:extent:at: with: bbForm with: size with: pos.
"
|
| render |
| doRender
|
| timeReally |
timeReally _ Croquet getRealTimeAsMilliseconds.
"if we are on time or more than 0.5 sec since last time, render"
(timeReally <= (Croquet deadline + 10.0) or: [lastRenderTime + 500.0 <= timeReally]) ifTrue: [
Croquet world renderer render.
Croquet teaTime commit. "commit the changes we made"
lastRenderTime _ Croquet getRealTimeAsMilliseconds.
timeReally _ lastRenderTime - timeReally.
renderEstimate _ (renderEstimate + timeReally) / 2.0. "update render time estimator"
].
|
| renderFrame: ogl space: space
|
" Only render if we are rendering in a portal - otherwise, we interfere with the user ."
| rval |
doRender ifTrue:[
inPortal ifFalse:[
avatar ifNotNil:[
avatar visibleTree: false.
rval _ super renderFrame: ogl space: space.
avatar visibleTree: true.
^ rval.
].
] ifTrue:[
^ super renderFrame: ogl space: space.
].
].
^ 0.
|
| renderOverlay: ogl
|
overlays ifNotNil:[
overlays do:[:ov |
Croquet renderProtect: ov in: [ :ovx |
"reset the buffers"
ogl glDepthMask: GLTrue;
glDisable: GLBlend;
glClear: (GLDepthBufferBit bitOr: GLStencilBufferBit).
"and render each overlay"
ovx renderOverlay: ogl]]].
|
| renderScheduler
|
"this method runs once per renderInterval, rescheduling itself. It controls the rendering
frequency, responding to load. It measures the load by measuring when it runs.
Actual rendering is done by #renderFromMorph messages sent by this scheduler."
| tardiness |
"experimental code deleted: calculate a new rendering interval"
"nowReally _ Croquet world getRealTimeAsMilliseconds."
"advance _ when - nowReally." "how early were we"
"frames _ (advance / 20.0) floor." "how many integer 50 Hz frames early(+) or late(-)"
"Adjust by that many frame times"
"renderInterval _ ((renderInterval - (frames * 20.0)) min: 500.0) max: 20.0."
"force a target rate of 30 fps for now, unless we are running more than 5 secs. late."
tardiness _ Croquet tardiness.
tardiness < 5000.0 ifTrue: [ tardiness _ 0.0 ].
renderInterval _ 33.0 + tardiness.
self future: renderInterval deadlineRelative: renderInterval + 0.5 deferRelative: renderInterval perform: #renderScheduler.
"schedule rendering after tea time commits for duration."
self future: 0.0 deadlineRelative: 0.5 deferRelative: 0.0 perform: #doRender.
Croquet teaTime commit.
|
| snapshot
|
self morphicOverlay dock addSnapshotItem: (TSnapshot new initializeWithFrame: avatar).
|
| snapshot: ptr
|
self morphicOverlay dock addSnapshotItem: (TSnapshot new initializeWithFrame: avatar).
|
| startRendering
|
"turn on stepping and rendering"
self future: renderInterval deadlineRelative: renderInterval + 0.5 deferRelative: renderInterval perform: #renderScheduler.
|
| testFloor: bnds
|
inPortal ifFalse:[ ^ downPointer pick: bnds].
|