bool ConvexShape::protectedSetSurface( void *object, const char *index, const char *data ) { ConvexShape *shape = static_cast< ConvexShape* >( object ); QuatF quat; Point3F pos; //MatrixF mat; /* dSscanf( data, "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", &mat[0], &mat[1], &mat[2], &mat[3], &mat[4], &mat[5], &mat[6], &mat[7], &mat[8], &mat[9], &mat[10], &mat[11], &mat[12], &mat[13], &mat[14], &mat[15] ); */ dSscanf( data, "%g %g %g %g %g %g %g", &quat.x, &quat.y, &quat.z, &quat.w, &pos.x, &pos.y, &pos.z ); MatrixF surface; quat.setMatrix( &surface ); surface.setPosition( pos ); shape->mSurfaces.push_back( surface ); return false; }
void VPathNode::updateWorldData( void ) { if ( !mPath ) { setWorldPosition( getLocalPosition() ); setWorldRotation( getLocalRotation() ); return; } // Fetch Path Details. const MatrixF &pathTransform = mPath->getTransform(); const QuatF &pathRotation( pathTransform ); // Calculate the World Position. Point3F newPosition = getLocalPosition(); newPosition.convolve( mPath->getScale() ); pathTransform.mulP( newPosition ); // Calculate the new Rotation. QuatF newRotation; newRotation.mul( getLocalRotation(), pathRotation ); // Apply. setWorldPosition( newPosition ); setWorldRotation( newRotation ); }
void Sim3DAudioEvent::unpack(NetConnection *con, BitStream *bstream) { SimObjectId id = bstream->readInt(DataBlockObjectIdBitSize) + DataBlockObjectIdFirst; Sim::findObject(id, mProfile); if (bstream->readFlag()) { QuatF q; q.x = bstream->readFloat(SoundRotBits); q.y = bstream->readFloat(SoundRotBits); q.z = bstream->readFloat(SoundRotBits); F32 value = ((q.x * q.x) + (q.y * q.y) + (q.z * q.z)); // #ifdef __linux // Hmm, this should never happen, but it does... if ( value > 1.f ) value = 1.f; // #endif q.w = mSqrt(1.f - value); if (bstream->readFlag()) q.w = -q.w; q.setMatrix(&mTransform); } else mTransform.identity(); Point3F pos; bstream->readCompressedPoint(&pos,SoundPosAccuracy); mTransform.setColumn(3, pos); }
//----------------------------------------------------------------------------- void Rigid::integrate(F32 delta) { // Update Angular position F32 angle = angVelocity.len(); if (angle != 0.0f) { QuatF dq; F32 sinHalfAngle; mSinCos(angle * delta * -0.5f, sinHalfAngle, dq.w); sinHalfAngle *= 1.0f / angle; dq.x = angVelocity.x * sinHalfAngle; dq.y = angVelocity.y * sinHalfAngle; dq.z = angVelocity.z * sinHalfAngle; QuatF tmp = angPosition; angPosition.mul(tmp, dq); angPosition.normalize(); // Rotate the position around the center of mass Point3F lp = linPosition - worldCenterOfMass; dq.mulP(lp,&linPosition); linPosition += worldCenterOfMass; } // Update angular momentum angMomentum = angMomentum + torque * delta; // Update linear position, momentum linPosition = linPosition + linVelocity * delta; linMomentum = linMomentum + force * delta; linVelocity = linMomentum * oneOverMass; // Update dependent state variables updateInertialTensor(); updateVelocity(); updateCenterOfMass(); }
Point3F & QuatF::mulP(const Point3F& p, Point3F* r) { QuatF qq; QuatF qi = *this; QuatF qv( p.x, p.y, p.z, 0.0f); qi.inverse(); qq.mul(qi, qv); qv.mul(qq, *this); r->set(qv.x, qv.y, qv.z); return *r; }
F32 Rigid::getKineticEnergy() { Point3F w; QuatF qmat = angPosition; qmat.inverse(); qmat.mulP(angVelocity,&w); const F32* f = invObjectInertia; return 0.5f * ((mass * mDot(linVelocity,linVelocity)) + w.x * w.x / f[0] + w.y * w.y / f[5] + w.z * w.z / f[10]); }
Point3F& m_mul( const Point3F &p, const QuatF &q, Point3F *r ) { QuatF qq; QuatF qi = q; QuatF qv( p.x, p.y, p.z, 0.0f); qi.inverse(); m_mul(qi, qv, &qq ); m_mul(qq, q, &qv ); r->set(qv.x, qv.y, qv.z); return ( *r ); }
void TSShapeLoader::generateNodeTransform(AppNode* node, F32 t, bool blend, F32 referenceTime, QuatF& rot, Point3F& trans, QuatF& srot, Point3F& scale) { MatrixF m1 = getLocalNodeMatrix(node, t); if (blend) { MatrixF m0 = getLocalNodeMatrix(node, referenceTime); m1 = m0.inverse() * m1; } rot.set(m1); trans = m1.getPosition(); srot.identity(); //@todo: srot not supported yet scale = m1.getScale(); }
Point3F& m_mul( const Point3F &p, const TQuatF &q, Point3F *r ) { //rotate a point by a Quaternion QuatF a; QuatF i = q; QuatF v( p.x, p.y, p.z, 0.0f); i.inverse(); m_mul(i, v, &a ); m_mul(a, q, &v ); v.normalize(); r->set(v.x, v.y, v.z); *r += q.p; return ( *r ); }
void PhysShape::setRotation(const QuatF& rot) { MatrixF tr; rot.setMatrix(&tr); tr.setPosition(getPosition()); setTransform(tr); }
void RigidBody::setRenderPosition(const Point3F& pos, const QuatF& rot) { MatrixF mat; rot.setMatrix(&mat); mat.setColumn(3,pos); setRenderTransform(mat); }
void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream ) { Parent::unpackUpdate( conn, stream ); if ( stream->readFlag() ) // TransformMask { mathRead(*stream, &mObjToWorld); mathRead(*stream, &mObjScale); setTransform( mObjToWorld ); setScale( mObjScale ); } if ( stream->readFlag() ) // UpdateMask { stream->read( &mMaterialName ); if ( isProperlyAdded() ) _updateMaterial(); mSurfaces.clear(); const U32 surfCount = stream->readInt( 32 ); for ( S32 i = 0; i < surfCount; i++ ) { mSurfaces.increment(); MatrixF &mat = mSurfaces.last(); QuatF quat; Point3F pos; mathRead( *stream, &quat ); mathRead( *stream, &pos ); quat.setMatrix( &mat ); mat.setPosition( pos ); } if ( isProperlyAdded() ) _updateGeometry( true ); } }
void PxSingleActor::interpolateTick( F32 delta ) { Point3F interpPos; QuatF interpRot; // Interpolate the position based on the delta. interpPos.interpolate( mNextPos, mLastPos, delta ); // Interpolate the rotation based on the delta. interpRot.interpolate( mNextRot, mLastRot, delta ); // Set up the interpolated transform. MatrixF interpMat; // Set the interpolated position and rotation. interpRot.setMatrix( &interpMat ); interpMat.setPosition( interpPos ); // Set the transform to the interpolated transform. Parent::setTransform( interpMat ); }
void RigidBody::interpolateTick(F32 dt) { Parent::interpolateTick(dt); //setRenderPosition(mDelta.pos, mDelta.rot[1]); if(dt == 0.0f) { setRenderPosition(mDelta.pos, mDelta.rot[1]); } else { QuatF rot; rot.interpolate(mDelta.rot[1], mDelta.rot[0], dt); Point3F pos = mDelta.pos + mDelta.posVec * dt; setRenderPosition(pos,rot); } mDelta.dt = dt; }
void ProximityMine::unpackUpdate( NetConnection* connection, BitStream* stream ) { Parent::unpackUpdate( connection, stream ); // Item::RotationMask if ( stream->readFlag() ) { QuatF rot; mathRead( *stream, &rot ); Point3F pos = mObjToWorld.getPosition(); rot.setMatrix( &mObjToWorld ); mObjToWorld.setPosition( pos ); } // !mStatic && ( mask & DeployedMask ) && ( mState > Thrown ) if ( stream->readFlag() ) { mathRead( *stream, &mStickyCollisionPos ); mathRead( *stream, &mStickyCollisionNormal ); mAtRest = true; setDeployedPos( mStickyCollisionPos, mStickyCollisionNormal ); } // ( mask & ExplosionMask ) && ( mState == Exploded ) if ( stream->readFlag() ) { // start the explosion visuals on the client explode(); } if ( mStatic && mState <= Deployed ) { // static mines are armed immediately mState = Deployed; mStateTimeout = 0; } }
void TurretShape::unpackUpdate(NetConnection *connection, BitStream *stream) { Parent::unpackUpdate(connection,stream); // InitialUpdateMask if (stream->readFlag()) { mRespawn = stream->readFlag(); } // Item::RotationMask if ( stream->readFlag() ) { QuatF rot; mathRead( *stream, &rot ); Point3F pos = mObjToWorld.getPosition(); rot.setMatrix( &mObjToWorld ); mObjToWorld.setPosition( pos ); } // controlled by the client? if(stream->readFlag()) return; // TurretUpdateMask if (stream->readFlag()) { Point3F rot(0.0f, 0.0f, 0.0f); stream->read(&rot.x); stream->read(&rot.z); _setRotation(rot); // New delta for client side interpolation mTurretDelta.rot = rot; mTurretDelta.rotVec = VectorF(0.0f, 0.0f, 0.0f); stream->read(&allowManualRotation); stream->read(&allowManualFire); } }
void fxShapeReplicator::CreateShapes(void) { F32 HypX, HypY; F32 Angle; U32 RelocationRetry; Point3F ShapePosition; Point3F ShapeStart; Point3F ShapeEnd; Point3F ShapeScale; EulerF ShapeRotation; QuatF QRotation; bool CollisionResult; RayInfo RayEvent; TSShape* pShape; // Don't create shapes if we are hiding replications. if (mFieldData.mHideReplications) return; // Cannot continue without shapes! if (dStrcmp(mFieldData.mShapeFile, "") == 0) return; // Check that we can position somewhere! if (!( mFieldData.mAllowOnTerrain || mFieldData.mAllowStatics || mFieldData.mAllowOnWater)) { // Problem ... Con::warnf(ConsoleLogEntry::General, "[%s] - Could not place object, All alloweds are off!", getName()); // Return here. return; } // Check Shapes. AssertFatal(mCurrentShapeCount==0,"Shapes already present, this should not be possible!") // Check that we have a shape... if (!mFieldData.mShapeFile) return; // Set Seed. RandomGen.setSeed(mFieldData.mSeed); // Set shape vector. mReplicatedShapes.clear(); // Add shapes. for (U32 idx = 0; idx < mFieldData.mShapeCount; idx++) { fxShapeReplicatedStatic* fxStatic; // Create our static shape. fxStatic = new fxShapeReplicatedStatic(); // Set the 'shapeName' field. fxStatic->setField("shapeName", mFieldData.mShapeFile); // Is this Replicator on the Server? if (isServerObject()) // Yes, so stop it from Ghosting. (Hack, Hack, Hack!) fxStatic->touchNetFlags(Ghostable, false); else // No, so flag as ghost object. (Another damn Hack!) fxStatic->touchNetFlags(IsGhost, true); // Register the Object. if (!fxStatic->registerObject()) { // Problem ... Con::warnf(ConsoleLogEntry::General, "[%s] - Could not load shape file '%s'!", getName(), mFieldData.mShapeFile); // Destroy Shape. delete fxStatic; // Destroy existing hapes. DestroyShapes(); // Quit. return; } // Get Allocated Shape. pShape = fxStatic->getShape(); // Reset Relocation Retry. RelocationRetry = mFieldData.mShapeRetries; // Find it a home ... do { // Get the Replicator Position. ShapePosition = getPosition(); // Calculate a random offset HypX = RandomGen.randF(mFieldData.mInnerRadiusX, mFieldData.mOuterRadiusX); HypY = RandomGen.randF(mFieldData.mInnerRadiusY, mFieldData.mOuterRadiusY); Angle = RandomGen.randF(0, (F32)M_2PI); // Calcualte the new position. ShapePosition.x += HypX * mCos(Angle); ShapePosition.y += HypY * mSin(Angle); // Initialise RayCast Search Start/End Positions. ShapeStart = ShapeEnd = ShapePosition; ShapeStart.z = 2000.f; ShapeEnd.z= -2000.f; // Is this the Server? if (isServerObject()) // Perform Ray Cast Collision on Server Terrain. CollisionResult = gServerContainer.castRay(ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent); else // Perform Ray Cast Collision on Client Terrain. CollisionResult = gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent); // Did we hit anything? if (CollisionResult) { // For now, let's pretend we didn't get a collision. CollisionResult = false; // Yes, so get it's type. U32 CollisionType = RayEvent.object->getTypeMask(); // Check Illegal Placements. if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain) || ((CollisionType & StaticShapeObjectType) && !mFieldData.mAllowStatics) || ((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue; // If we collided with water and are not allowing on the water surface then let's find the // terrain underneath and pass this on as the original collision else fail. // // NOTE:- We need to do this on the server/client as appropriate. if ((CollisionType & WaterObjectType) && !mFieldData.mAllowWaterSurface) { // Is this the Server? if (isServerObject()) { // Yes, so do it on the server container. if (!gServerContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue; } else { // No, so do it on the client container. if (!gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue; } } // We passed with flying colours so carry on. CollisionResult = true; } // Invalidate if we are below Allowed Terrain Angle. if (RayEvent.normal.z < mSin(mDegToRad(90.0f-mFieldData.mAllowedTerrainSlope))) CollisionResult = false; // Wait until we get a collision. } while(!CollisionResult && --RelocationRetry); // Check for Relocation Problem. if (RelocationRetry > 0) { // Adjust Impact point. RayEvent.point.z += mFieldData.mOffsetZ; // Set New Position. ShapePosition = RayEvent.point; } else { // Warning. Con::warnf(ConsoleLogEntry::General, "[%s] - Could not find satisfactory position for shape '%s' on %s!", getName(), mFieldData.mShapeFile,isServerObject()?"Server":"Client"); // Unregister Object. fxStatic->unregisterObject(); // Destroy Shape. delete fxStatic; // Skip to next. continue; } // Get Shape Transform. MatrixF XForm = fxStatic->getTransform(); // Are we aligning to Terrain? if (mFieldData.mAlignToTerrain) { // Yes, so set rotation to Terrain Impact Normal. ShapeRotation = RayEvent.normal * mFieldData.mTerrainAlignment; } else { // No, so choose a new Rotation (in Radians). ShapeRotation.set( mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.x, mFieldData.mShapeRotateMax.x)), mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.y, mFieldData.mShapeRotateMax.y)), mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.z, mFieldData.mShapeRotateMax.z))); } // Set Quaternion Roation. QRotation.set(ShapeRotation); // Set Transform Rotation. QRotation.setMatrix(&XForm); // Set Position. XForm.setColumn(3, ShapePosition); // Set Shape Position / Rotation. fxStatic->setTransform(XForm); // Choose a new Scale. ShapeScale.set( RandomGen.randF(mFieldData.mShapeScaleMin.x, mFieldData.mShapeScaleMax.x), RandomGen.randF(mFieldData.mShapeScaleMin.y, mFieldData.mShapeScaleMax.y), RandomGen.randF(mFieldData.mShapeScaleMin.z, mFieldData.mShapeScaleMax.z)); // Set Shape Scale. fxStatic->setScale(ShapeScale); // Lock it. fxStatic->setLocked(true); // Store Shape in Replicated Shapes Vector. //mReplicatedShapes[mCurrentShapeCount++] = fxStatic; mReplicatedShapes.push_back(fxStatic); } mCurrentShapeCount = mReplicatedShapes.size(); // Take first Timestamp. mLastRenderTime = Platform::getVirtualMilliseconds(); }
QuatF& QuatF::operator /=( const QuatF & c ) { QuatF temp = c; return ( (*this) *= temp.inverse() ); }
void SFXEmitter::_renderCone( F32 radialIncrements, F32 sweepIncrements, F32 pointDistance, F32 startAngle, F32 stopAngle, F32 startVolume, F32 stopVolume, const ColorI& color ) { if( startAngle == stopAngle ) return; const F32 startAngleRadians = mDegToRad( startAngle ); const F32 stopAngleRadians = mDegToRad( stopAngle ); const F32 radialIncrementsRadians = mDegToRad( radialIncrements ); // Unit quaternions representing the start and end angle so we // can interpolate between the two without flipping. QuatF rotateZStart( EulerF( 0.f, 0.f, startAngleRadians / 2.f ) ); QuatF rotateZEnd( EulerF( 0.f, 0.f, stopAngleRadians / 2.f ) ); // Do an angular sweep on one side of our XY disc. Since we do a full 360 radial sweep // around Y for each angle, we only need to sweep over one side. const F32 increment = 1.f / ( ( ( startAngle / 2.f ) - ( stopAngle / 2.f ) ) / sweepIncrements ); for( F32 t = 0.f; t < 1.0f; t += increment ) { // Quaternion to rotate point into place on XY disc. QuatF rotateZ; rotateZ.interpolate( rotateZStart, rotateZEnd, t ); // Quaternion to rotate one position around Y axis. Used for radial sweep. QuatF rotateYOne( EulerF( 0.f, radialIncrementsRadians, 0.f ) ); // Do a radial sweep each step along the distance axis. For each step, volume is // the same for any point on the sweep circle. for( F32 y = pointDistance; y <= mDescription.mMaxDistance; y += pointDistance ) { ColorI c = color; // Compute volume at current point. First off, find the interpolated volume // in the cone. Only for the outer cone will this actually result in // interpolation. For the remaining angles, the cone volume is constant. F32 volume = mLerp( startVolume, stopVolume, t ); if( volume == 0.f ) c.alpha = 0; else { // Apply distance attenuation. F32 attenuatedVolume = SFXDistanceAttenuation( SFX->getDistanceModel(), mDescription.mMinDistance, mDescription.mMaxDistance, y, volume, SFX->getRolloffFactor() ); //RDTODO // Fade alpha according to how much volume we // have left at the current point. c.alpha = F32( c.alpha ) * ( attenuatedVolume / 1.f ); } PrimBuild::color( c ); // Create points by doing a full 360 degree radial sweep around Y. Point3F p( 0.f, y, 0.f ); rotateZ.mulP( p, &p ); for( F32 radialAngle = 0.f; radialAngle < 360.f; radialAngle += radialIncrements ) { PrimBuild::vertex3f( p.x, p.y, p.z ); rotateYOne.mulP( p, &p ); } } } }
void RigidBody::unpackUpdate(NetConnection *con, BitStream *stream) { //Con::printf("RigidBody::unpackUpdate: %p isServer :%d tick: %d",this,isServerObject(),isServerObject()? gServerProcessList.getTotalTicks():gClientProcessList.getTotalTicks()); Parent::unpackUpdate(con,stream); // Initial update if (stream->readFlag()) { if (stream->readFlag()) { mHasServerPhysic = true; PhysShape* serverShape = NULL; stream->readBits(8*sizeof(serverShape),&serverShape); mPhysShape = serverShape; } else { MatrixF tr; mathRead(*stream,&tr); setTransform(tr); } mDelta.dt = 0; } if (stream->readFlag()) return; if (!mHasServerPhysic && !mDataBlock->mOnlyOnClient && stream->readFlag()) { // Read in new position and momentum values if (!mPhysShape) createPhysShape(); { mPhysShape->unpack(stream); mPhysPosition = mPhysShape->getPosition(); mPhysRotation = mPhysShape->getRotation(); mForce = mPhysShape->getForce(); mTorque = mPhysShape->getTorque(); mLinVelocity = mPhysShape->getLinVelocity(); mAngVelocity = mPhysShape->getAngVelocity(); } /* Con::printf("Unpack vel: %f %f %f momentum: %f %f %f ",mLinVelocity.x,mLinVelocity.y,mLinVelocity.z, mForce.x, mForce.y, mForce.z);*/ if (mDelta.dt > 0.f) { Point3F curPos = mDelta.pos + mDelta.posVec * mDelta.dt; QuatF curRotate; curRotate.interpolate(mDelta.rot[1],mDelta.rot[0],mDelta.dt); mDelta.pos = mPhysPosition; mDelta.posVec = (curPos - mDelta.pos) / mDelta.dt; mDelta.rot[0] = curRotate; mDelta.rot[1] = mPhysRotation; } else { //Con::printf("Unpack pos dt0:"); mDelta.pos = mPhysPosition; mDelta.posVec.set(0,0,0); mDelta.rot[1] = mDelta.rot[0] = mPhysRotation; } } }
//----------------------------------------------------------------------------- void CameraSpline::value(F32 t, CameraSpline::Knot *result, bool skip_rotation) { // Do some easing in and out for t. if(!gBuilding) { F32 oldT = t; if(oldT < 0.5f) { t = 0.5f - (mSin( (0.5 - oldT) * M_PI ) / 2.f); } if((F32(size()) - 1.5f) > 0.f && oldT - (F32(size()) - 1.5f) > 0.f) { oldT -= (F32(size()) - 1.5f); t = (F32(size()) - 1.5f) + (mCos( (0.5f - oldT) * F32(M_PI) ) / 2.f); } } // Verify that t is in range [0 >= t > size] // AssertFatal(t >= 0.0f && t < (F32)size(), "t out of range"); Knot *p1 = getKnot((S32)mFloor(t)); Knot *p2 = next(p1); F32 i = t - mFloor(t); // adjust t to 0 to 1 on p1-p2 interval if (p1->mPath == Knot::SPLINE) { Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1); Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2); result->mPosition.x = mCatmullrom(i, p0->mPosition.x, p1->mPosition.x, p2->mPosition.x, p3->mPosition.x); result->mPosition.y = mCatmullrom(i, p0->mPosition.y, p1->mPosition.y, p2->mPosition.y, p3->mPosition.y); result->mPosition.z = mCatmullrom(i, p0->mPosition.z, p1->mPosition.z, p2->mPosition.z, p3->mPosition.z); } else { // Linear result->mPosition.interpolate(p1->mPosition, p2->mPosition, i); } if (skip_rotation) return; buildTimeMap(); // find the two knots to interpolate rotation and velocity through since some // knots are only positional S32 start = (S32)mFloor(t); S32 end = (p2 == p1) ? start : (start + 1); while (p1->mType == Knot::POSITION_ONLY && p1 != front()) { p1 = prev(p1); start--; } while (p2->mType == Knot::POSITION_ONLY && p2 != back()) { p2 = next(p2); end++; } if (start == end) { result->mRotation = p1->mRotation; result->mSpeed = p1->mSpeed; } else { F32 c = getDistance(t); F32 d1 = getDistance((F32)start); F32 d2 = getDistance((F32)end); if (d1 == d2) { result->mRotation = p2->mRotation; result->mSpeed = p2->mSpeed; } else { i = (c-d1)/(d2-d1); if(p1->mPath == Knot::SPLINE) { Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1); Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2); F32 q,w,e; q = mCatmullrom(i, 0, 1, 1, 1); w = mCatmullrom(i, 0, 0, 0, 1); e = mCatmullrom(i, 0, 0, 1, 1); QuatF a; a.interpolate(p0->mRotation, p1->mRotation, q); QuatF b; b.interpolate(p2->mRotation, p3->mRotation, w); result->mRotation.interpolate(a, b, e); result->mSpeed = mCatmullrom(i, p0->mSpeed, p1->mSpeed, p2->mSpeed, p3->mSpeed); } else { result->mRotation.interpolate(p1->mRotation, p2->mRotation, i); result->mSpeed = (p1->mSpeed * (1.0f-i)) + (p2->mSpeed * i); } } } }
void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect) { // Save the current transforms so we can restore // it for child control rendering below. GFXTransformSaver saver; bool renderingToTarget = false; if(!processCameraQuery(&mLastCameraQuery)) { // We have no camera, but render the GUI children // anyway. This makes editing GuiTSCtrl derived // controls easier in the GuiEditor. renderChildControls( offset, updateRect ); return; } GFXTargetRef origTarget = GFX->getActiveRenderTarget(); // Set up the appropriate render style U32 prevRenderStyle = GFX->getCurrentRenderStyle(); Point2F prevProjectionOffset = GFX->getCurrentProjectionOffset(); Point2I renderSize = getExtent(); if(mRenderStyle == RenderStyleStereoSideBySide) { GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSideBySide); GFX->setCurrentProjectionOffset(mLastCameraQuery.projectionOffset); GFX->setStereoEyeOffsets(mLastCameraQuery.eyeOffset); if (!mLastCameraQuery.hasStereoTargets) { // Need to calculate our current viewport here mLastCameraQuery.stereoViewports[0] = updateRect; mLastCameraQuery.stereoViewports[0].extent.x /= 2; mLastCameraQuery.stereoViewports[1] = mLastCameraQuery.stereoViewports[0]; mLastCameraQuery.stereoViewports[1].point.x += mLastCameraQuery.stereoViewports[1].extent.x; } if (!mLastCameraQuery.hasFovPort) { // Need to make our own fovPort mLastCameraQuery.fovPort[0] = CalculateFovPortForCanvas(mLastCameraQuery.stereoViewports[0], mLastCameraQuery); mLastCameraQuery.fovPort[1] = CalculateFovPortForCanvas(mLastCameraQuery.stereoViewports[1], mLastCameraQuery); } GFX->setStereoFovPort(mLastCameraQuery.fovPort); // NOTE: this specifies fov for BOTH eyes GFX->setSteroViewports(mLastCameraQuery.stereoViewports); GFX->setStereoTargets(mLastCameraQuery.stereoTargets); MatrixF myTransforms[2]; if (smUseLatestDisplayTransform) { // Use the view matrix determined from the display device myTransforms[0] = mLastCameraQuery.eyeTransforms[0]; myTransforms[1] = mLastCameraQuery.eyeTransforms[1]; } else { // Use the view matrix determined from the control object myTransforms[0] = mLastCameraQuery.cameraMatrix; myTransforms[1] = mLastCameraQuery.cameraMatrix; QuatF qrot = mLastCameraQuery.cameraMatrix; Point3F pos = mLastCameraQuery.cameraMatrix.getPosition(); Point3F rotEyePos; myTransforms[0].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[0], &rotEyePos)); myTransforms[1].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[1], &rotEyePos)); } GFX->setStereoEyeTransforms(myTransforms); // Allow render size to originate from the render target if (mLastCameraQuery.stereoTargets[0]) { renderSize = mLastCameraQuery.stereoViewports[0].extent; renderingToTarget = true; } } else { GFX->setCurrentRenderStyle(GFXDevice::RS_Standard); } if ( mReflectPriority > 0 ) { // Get the total reflection priority. F32 totalPriority = 0; for ( U32 i=0; i < smAwakeTSCtrls.size(); i++ ) if ( smAwakeTSCtrls[i]->isVisible() ) totalPriority += smAwakeTSCtrls[i]->mReflectPriority; REFLECTMGR->update( mReflectPriority / totalPriority, getExtent(), mLastCameraQuery ); } if(mForceFOV != 0) mLastCameraQuery.fov = mDegToRad(mForceFOV); if(mCameraZRot) { MatrixF rotMat(EulerF(0, 0, mDegToRad(mCameraZRot))); mLastCameraQuery.cameraMatrix.mul(rotMat); } Frustum frustum; if(mRenderStyle == RenderStyleStereoSideBySide) { // NOTE: these calculations are essentially overridden later by the fov port settings when rendering each eye. MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[0]); } else { // set up the camera and viewport stuff: F32 wwidth; F32 wheight; F32 renderWidth = F32(renderSize.x); F32 renderHeight = F32(renderSize.y); F32 aspectRatio = renderWidth / renderHeight; // Use the FOV to calculate the viewport height scale // then generate the width scale from the aspect ratio. if(!mLastCameraQuery.ortho) { wheight = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2.0f); wwidth = aspectRatio * wheight; } else { wheight = mLastCameraQuery.fov; wwidth = aspectRatio * wheight; } F32 hscale = wwidth * 2.0f / renderWidth; F32 vscale = wheight * 2.0f / renderHeight; F32 left = (updateRect.point.x - offset.x) * hscale - wwidth; F32 right = (updateRect.point.x + updateRect.extent.x - offset.x) * hscale - wwidth; F32 top = wheight - vscale * (updateRect.point.y - offset.y); F32 bottom = wheight - vscale * (updateRect.point.y + updateRect.extent.y - offset.y); frustum.set( mLastCameraQuery.ortho, left, right, top, bottom, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane ); } // Manipulate the frustum for tiled screenshots const bool screenShotMode = gScreenShot && gScreenShot->isPending(); if ( screenShotMode ) { gScreenShot->tileFrustum( frustum ); GFX->setViewMatrix(MatrixF::Identity); } RectI tempRect = updateRect; if (!renderingToTarget) { #ifdef TORQUE_OS_MAC Point2I screensize = getRoot()->getWindowSize(); tempRect.point.y = screensize.y - (tempRect.point.y + tempRect.extent.y); #endif GFX->setViewport( tempRect ); } else { // Activate stereo RT GFX->activateStereoTarget(-1); } // Clear the zBuffer so GUI doesn't hose object rendering accidentally GFX->clear( GFXClearZBuffer , ColorI(20,20,20), 1.0f, 0 ); //GFX->clear( GFXClearTarget, ColorI(255,0,0), 1.0f, 0); GFX->setFrustum( frustum ); if(mLastCameraQuery.ortho) { mOrthoWidth = frustum.getWidth(); mOrthoHeight = frustum.getHeight(); } // We're going to be displaying this render at size of this control in // pixels - let the scene know so that it can calculate e.g. reflections // correctly for that final display result. gClientSceneGraph->setDisplayTargetResolution(renderSize); // Set the GFX world matrix to the world-to-camera transform, but don't // change the cameraMatrix in mLastCameraQuery. This is because // mLastCameraQuery.cameraMatrix is supposed to contain the camera-to-world // transform. In-place invert would save a copy but mess up any GUIs that // depend on that value. MatrixF worldToCamera = mLastCameraQuery.cameraMatrix; worldToCamera.inverse(); GFX->setWorldMatrix( worldToCamera ); mSaveProjection = GFX->getProjectionMatrix(); mSaveModelview = GFX->getWorldMatrix(); mSaveViewport = updateRect; mSaveWorldToScreenScale = GFX->getWorldToScreenScale(); mSaveFrustum = GFX->getFrustum(); mSaveFrustum.setTransform( mLastCameraQuery.cameraMatrix ); // Set the default non-clip projection as some // objects depend on this even in non-reflect cases. gClientSceneGraph->setNonClipProjection( mSaveProjection ); // Give the post effect manager the worldToCamera, and cameraToScreen matrices PFXMGR->setFrameMatrices( mSaveModelview, mSaveProjection ); renderWorld(updateRect); DebugDrawer::get()->render(); // Render the canvas overlay if its available if (mRenderStyle == RenderStyleStereoSideBySide && mStereoGuiTarget.getPointer()) { GFXDEBUGEVENT_SCOPE( StereoGui_Render, ColorI( 255, 0, 0 ) ); MatrixF proj(1); Frustum originalFrustum = GFX->getFrustum(); GFXTextureObject *texObject = mStereoGuiTarget->getTexture(0); const FovPort *currentFovPort = GFX->getStereoFovPort(); const MatrixF *eyeTransforms = GFX->getStereoEyeTransforms(); const Point3F *eyeOffset = GFX->getStereoEyeOffsets(); Frustum gfxFrustum = originalFrustum; for (U32 i=0; i<2; i++) { GFX->activateStereoTarget(i); MathUtils::makeFovPortFrustum(&gfxFrustum, true, gfxFrustum.getNearDist(), gfxFrustum.getFarDist(), currentFovPort[i], eyeTransforms[i]); GFX->setFrustum(gfxFrustum); MatrixF eyeWorldTrans(1); eyeWorldTrans.setPosition(Point3F(eyeOffset[i].x,eyeOffset[i].y,eyeOffset[i].z)); MatrixF eyeWorld(1); eyeWorld.mul(eyeWorldTrans); eyeWorld.inverse(); GFX->setWorldMatrix(eyeWorld); GFX->setViewMatrix(MatrixF::Identity); if (!mStereoOverlayVB.getPointer()) { mStereoOverlayVB.set(GFX, 4, GFXBufferTypeStatic); GFXVertexPCT *verts = mStereoOverlayVB.lock(0, 4); F32 texLeft = 0.0f; F32 texRight = 1.0f; F32 texTop = 1.0f; F32 texBottom = 0.0f; F32 rectRatio = gfxFrustum.getWidth() / gfxFrustum.getHeight(); F32 rectWidth = gfxFrustum.getWidth() * TS_OVERLAY_SCREEN_WIDTH; F32 rectHeight = rectWidth * rectRatio; F32 screenLeft = -rectWidth * 0.5; F32 screenRight = rectWidth * 0.5; F32 screenTop = -rectHeight * 0.5; F32 screenBottom = rectHeight * 0.5; const F32 fillConv = 0.0f; const F32 frustumDepthAdjusted = gfxFrustum.getNearDist() + 0.012; verts[0].point.set( screenLeft - fillConv, frustumDepthAdjusted, screenTop - fillConv ); verts[1].point.set( screenRight - fillConv, frustumDepthAdjusted, screenTop - fillConv ); verts[2].point.set( screenLeft - fillConv, frustumDepthAdjusted, screenBottom - fillConv ); verts[3].point.set( screenRight - fillConv, frustumDepthAdjusted, screenBottom - fillConv ); verts[0].color = verts[1].color = verts[2].color = verts[3].color = ColorI(255,255,255,255); verts[0].texCoord.set( texLeft, texTop ); verts[1].texCoord.set( texRight, texTop ); verts[2].texCoord.set( texLeft, texBottom ); verts[3].texCoord.set( texRight, texBottom ); mStereoOverlayVB.unlock(); } if (!mStereoGuiSB.getPointer()) { // DrawBitmapStretchSR GFXStateBlockDesc bitmapStretchSR; bitmapStretchSR.setCullMode(GFXCullNone); bitmapStretchSR.setZReadWrite(false, false); bitmapStretchSR.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); bitmapStretchSR.samplersDefined = true; bitmapStretchSR.samplers[0] = GFXSamplerStateDesc::getClampLinear(); bitmapStretchSR.samplers[0].minFilter = GFXTextureFilterPoint; bitmapStretchSR.samplers[0].mipFilter = GFXTextureFilterPoint; bitmapStretchSR.samplers[0].magFilter = GFXTextureFilterPoint; mStereoGuiSB = GFX->createStateBlock(bitmapStretchSR); } GFX->setVertexBuffer(mStereoOverlayVB); GFX->setStateBlock(mStereoGuiSB); GFX->setTexture( 0, texObject ); GFX->setupGenericShaders( GFXDevice::GSModColorTexture ); GFX->drawPrimitive( GFXTriangleStrip, 0, 2 ); } } // Restore the previous matrix state before // we begin rendering the child controls. saver.restore(); // Restore the render style and any stereo parameters GFX->setActiveRenderTarget(origTarget); GFX->setCurrentRenderStyle(prevRenderStyle); GFX->setCurrentProjectionOffset(prevProjectionOffset); if(mRenderStyle == RenderStyleStereoSideBySide && gLastStereoTexture) { GFX->setClipRect(updateRect); GFX->getDrawUtil()->drawBitmapStretch(gLastStereoTexture, updateRect); } // Allow subclasses to render 2D elements. GFX->setClipRect(updateRect); renderGui( offset, updateRect ); if (shouldRenderChildControls()) { renderChildControls(offset, updateRect); } smFrameCount++; }