| accessing |
| addViewingParticipants: someParticipants
|
"when we add viewers in our space, they become viewers of our toPortal space"
| sp |
sp _ toPortal root.
"next test stops direct recursion when toPortal root is not yet installed in a space.
indirect recursion stopped by subsetting of someParticipants
in TSpace method when allparticipants have been added on all paths"
sp isSpace ifTrue: [ sp addViewingParticipants: someParticipants ].
^super addViewingParticipants: someParticipants.
|
| blocked
|
^ blocked.
|
| blocked: bl
|
blocked _ bl.
|
| cameraDistance
|
^ cameraDistance.
|
| cameraDistance: cd
|
cameraDistance _ cd.
|
| hasAlpha
|
^ true.
|
| inside
|
^ inside.
|
| linkPortal: tp
|
self toPortal: tp.
tp isPortal ifTrue:[tp toPortal: self.].
|
| material: mat
|
|
| outVector
|
^ outVector.
|
| outVector: ov
|
outVector _ ov.
|
| portalToScreen: ogl rect: rect
|
| thumbCam ac trans spc rval |
" Put a camera into the proper location in the space. "
spc _ self root.
ac _ ogl camera.
thumbCam _ TCamera new initializeWithViewPort: ac viewPort.
spc addChild: thumbCam.
thumbCam viewAngle: 45.0. "90 degree field of view"
thumbCam inPortal: true.
thumbCam bounds: rect.
trans _ self globalTransform copy. "place it in the same location as the portal"
trans row1: (trans row1 negated).
trans row3: (trans row3 negated).
thumbCam localTransform: trans.
ogl camera: thumbCam.
self visible: false.
thumbCam initFrustum: ogl.
rval _ spc doRender: ogl.
self visible: true.
spc removeChild: thumbCam.
ogl camera: ac.
ac initFrustum: ogl.
^ rval.
|
| testEnter: avatar
|
| delta m1 m2 trans saveFP ray |
"testEnter: is used to determine if the camera moves through the plane of the portal. DAS"
"Croquet world activeCamera isRemoteControl ifTrue:[^ false.]."
blocked ifFalse:[ " The portal is open to enter (assuming the following is true...)"
self = toPortal ifFalse:[ " This is not a mirror"
toPortal = toPortal root ifFalse:[
ray _ TRay new.
ray globalTransform: avatar globalTransform.
ray currentFrame: self.
lastCameraPosition ifNotNil:[ " We have been here before"
lastCameraPosition z > 0 ifTrue: [ " We were somewhere in front of the portal"
delta _ (lastCameraPosition - ray framePosition).
ray framePosition z < 0 ifTrue:[
saveFP _ ray framePosition.
ray framePosition: lastCameraPosition.
(ray portalTest: self at: delta) ifTrue:[
m1 _ self globalTransform.
m2 _ toPortal globalMatrixOut.
trans _ m2 composeWith: m1 orthoNormInverse.
trans _ trans composeWith: avatar globalTransform.
avatar future: 0.0 perform: #goToPortal:transform: withArguments: { toPortal . trans }.
"orient _ trans clone.
orient translation: (B3DVector3 new).
v _ trans row3.
v x > 0 ifTrue:[rotY _ v z arcCos radiansToDegrees negated] ifFalse:
[rotY _ v z arcCos radiansToDegrees.].
ac yaw: rotY."
Croquet world activeCamera killFrame: true.
lastCameraPosition _ nil.
"ac overlay: self."
^ true.
].
ray framePosition: saveFP.
].].].
lastCameraPosition _ ray framePosition.
].].].
^ false.
|
| toPortal
|
^ toPortal.
|
| toPortal: tp
|
"tell target that everyone viewing us is going to be viewing him"
tp root addViewingParticipants: self root viewingParticipants.
toPortal _ tp.
|
| toPortalRoot
|
^ toPortal root.
|
| visible: aBool
|
super visible: aBool.
(self visible and:[locator notNil and:[locator isLoaded not]]) ifTrue:[
CroquetData download: locator whenFinishedSend: #doneLoading: to: self
].
|
| render |
| disableClipPlane: ogl
|
ogl glDisable: GLClipPlane0.
|
| enableClipPlane: ogl
|
"------ enableClipPlane is used to clip the TSpace to the front face of the portal. This ensures that objects don't get rendered in front of the portal, which would look bad and be confusing.------"
| equation |
"equation _ FloatArray ofSize: 4.
equation at:1 put: outVector x.
equation at:2 put: outVector y.
equation at:3 put: outVector z.
equation at:4 put: 0.0."
"------ We need to do it this way, because Squeak does not directly support doubles and gllClipPlane requires an array of same. ------"
true ifTrue:[
equation _ ExternalData fromHandle: (ExternalAddress allocate: 8*4) type:ExternalType double.
equation getHandle doubleAt: 1 put: outVector x.
equation getHandle doubleAt: 9 put: outVector y.
equation getHandle doubleAt: 17 put: outVector z.
equation getHandle doubleAt: 25 put: 0.0.
" equation getHandle doubleAt: 1 put: 0.0.
equation getHandle doubleAt: 9 put: 0.0.
equation getHandle doubleAt: 17 put: 1.0.
equation getHandle doubleAt: 25 put: 0.0."
ogl
glPushMatrix;
glMultMatrixf: self globalTransform transposed;
glClipPlane: GLClipPlane0 with: equation;
glEnable: GLClipPlane0;
glPopMatrix.
equation free.]
|
| render: ogl
|
" Don't do anything ."
|
| render: ogl depth: depth
|
| trans m2 toSpace gt containerPortal portalClip color clipPlanes renderedObjects ac saveSelected saveDoSelect saveMinDistance portalDistance saveForceWire |
" This method is the recursive portal renderer. enter refers to the renderer entering the portal. If you want the camera entering check out TPortal>>testEnter: ac."
renderedObjects _ 1. "We are also rendering the portal."
" ------- We keep track of which portal we are currently working in to avoid a tight recursion error,where the portal re-enters itself to render. It is (somewhat) OK to re-enter from another portal. This is equivalent to a mirror in a mirror situation. Here we need to keep a count of the re-entries.------"
" toPortal visibleTree ifFalse:[ ^0 ]. ""The portal is not visible on the other side."
toSpace _ toPortal root.
toSpace = toPortal ifTrue:[ ^0 ]. "The portal is not installed on the other side!"
containerPortal _ ogl currentPortal.
ogl currentPortal: self.
" ------ For rendering the portal ONLY - we turn off depth testing. We just want to write into the stencil buffer here and set the color of the toSpace. Depth testing is turned back on before we recurse into the connected portal.------"
gt _ self globalTransform.
depth = 1 ifTrue:[ogl glEnable: GLStencilTest.].
ogl glPushMatrix.
ogl glMultMatrixf: gt transposed.
ogl glDisable: GLDepthTest.
" ------ Paint the portal with the color of the TSpace ------ "
ogl glDisable: GLLighting.
color _ B3DVector3 x: toSpace color red y: toSpace color green z: toSpace color blue.
ogl glColor3fv: color.
ogl glStencilFunc:GLEqual with:depth-1 with: -1.
ogl glStencilOp:GLKeep with:GLKeep with:GLIncr.
" ------ Render the stencil here. ------ "
saveForceWire _ ogl forceWire.
ogl forceWire:false.
self renderPortal: ogl.
ogl forceWire: saveForceWire.
ogl glStencilFunc: GLEqual with: depth with: -1.
ogl glStencilOp: GLKeep with: GLKeep with: GLKeep.
ogl glEnable: GLDepthTest.
ogl glEnable: GLLighting.
ogl glPopMatrix.
ogl glPushMatrix.
" m1 _ self globalTransform."
toPortal isPortal ifTrue:[m2 _ toPortal globalMatrixOut.] ifFalse:[m2 _ toPortal globalTransform.].
" ------- For simplicity - and because I can't think of a good reason not to do this - if a portal points back to itself, it is considered to be a mirror. Note that we flip the directions of the polyon tests as well. This is restored at the end. We are inverting the x-coordinate of the matrix here. ------"
self = toPortal ifTrue:[
m2 a11: m2 a11 negated.
m2 a21: m2 a21 negated.
m2 a31: m2 a31 negated.
ogl flipFace.].
ac _ ogl camera.
ac pointer ifNotNil:[
saveSelected _ ac pointer copiedSelection.
saveMinDistance _ ac pointer minDistance.
saveDoSelect _ ac pointer doSelect.
(ac pointer pointerPick: self boundSphere) ifTrue:[
portalDistance _ ac pointer selectedDistance.
ac pointer minDistance: portalDistance.
] ifFalse:[
portalDistance _ Float infinity.
ac pointer doSelect: false.
].
ac pointer selected: saveSelected.
].
portalClip _ac portalClip.
ac portalClip: m2.
" ------ This math is simply:
m1 = trans*m2
m1 * m2**-1 = trans * m2 * m2**-1
m1 * m2**-1 = trans.
We then replace the transform matrix of the TCamera with the appropriate transform, which places the TCamera into the correct position in the new space.------"
clipPlanes _ ac clipPlanes.
ac clipPlanes: (self initClipPlanes: ac globalTransform mirror: ogl isMirror).
self = toPortal ifTrue:[ ogl mirrorFlip.].
trans _ m2 composeWith: gt orthoNormInverse.
ac globalTransform:
(trans composeWith: ac globalTransform).
ac pointer ifNotNil:[
ac pointer globalTransform:
(ac globalTransform composeWith: ac pointer localTransform).
].
renderedObjects _ renderedObjects + (toSpace renderSpace: ogl port: toPortal depth: depth+1). "<------ Render TSpace here! -------"
ac clipPlanes: clipPlanes.
inside _ false.
self = toPortal ifTrue:[ogl flipFace. ogl mirrorFlip.].
ogl glPopMatrix.
" ------ Just in case we jumped into a portal, restore the stencil depth ------"
ogl glStencilFunc: GLLequal with: depth-1 with: -1.
ogl glStencilOp: GLKeep with: GLKeep with: GLKeep.
"------ Render the front face invisibly to set the z-buffer to ensure nothing bleeds into the portal space from our space. ------"
ogl glPushMatrix.
ogl glPolygonOffset: 2.1 with: 4.0.
ogl glEnable: GLPolygonOffsetFill.
ogl glColorMask: GLFalse with: GLFalse with: GLFalse with: GLFalse.
ogl glMultMatrixf: gt transposed.
ogl forceWire: false.
self renderPortal: ogl.
ogl forceWire: saveForceWire.
ogl glColorMask:GLTrue with: GLTrue with:GLTrue with:GLTrue.
ogl glDisable: GLPolygonOffsetFill.
ogl glPopMatrix.
depth = 1 ifTrue:[ogl glDisable: GLStencilTest.].
ogl currentPortal: containerPortal.
ac portalClip: portalClip.
ac pointer ifNotNil:[
ac pointer doSelect: saveDoSelect.
ac pointer minDistance: saveMinDistance.
ac pointer maxDistance: (ac pointer maxDistance min: portalDistance).
].
^ renderedObjects.
|
| renderAlpha: ogl
|
" Don't do anything ."
|
| renderPortal: space
|
^ super renderPrimitive: space.
|