void Item::setTransform(const MatrixF& mat) { Point3F pos; mat.getColumn(3,&pos); MatrixF tmat; if (!mRotate) { // Forces all rotation to be around the z axis VectorF vec; mat.getColumn(1,&vec); tmat.set(EulerF(0,0,-mAtan2(-vec.x,vec.y))); } else tmat.identity(); tmat.setColumn(3,pos); Parent::setTransform(tmat); if (!mStatic) { mAtRest = false; mAtRestCounter = 0; } if ( mPhysicsRep ) mPhysicsRep->setTransform( getTransform() ); setMaskBits(RotationMask | PositionMask | NoWarpMask); }
void FlyingVehicle::updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 idx,S32 count) { if (!emitter) return; for (S32 j = idx; j < idx + count; j++) if (active) { if (mDataBlock->jetNode[j] != -1) { if (!bool(mJetEmitter[j])) { mJetEmitter[j] = new ParticleEmitter; mJetEmitter[j]->onNewDataBlock(emitter,false); mJetEmitter[j]->registerObject(); } MatrixF mat; Point3F pos,axis; mat.mul(getRenderTransform(), mShapeInstance->mNodeTransforms[mDataBlock->jetNode[j]]); mat.getColumn(1,&axis); mat.getColumn(3,&pos); mJetEmitter[j]->emitParticles(pos,true,axis,getVelocity(),(U32)(dt * 1000)); } } else { for (S32 j = idx; j < idx + count; j++) if (bool(mJetEmitter[j])) { mJetEmitter[j]->deleteWhenEmpty(); mJetEmitter[j] = 0; } } }
MatrixF PlaneReflector::getCameraReflection( const MatrixF &camTrans ) { Point3F normal = refplane; // Figure out new cam position Point3F camPos = camTrans.getPosition(); F32 dist = refplane.distToPlane( camPos ); Point3F newCamPos = camPos - normal * dist * 2.0; // Figure out new look direction Point3F i, j, k; camTrans.getColumn( 0, &i ); camTrans.getColumn( 1, &j ); camTrans.getColumn( 2, &k ); i = MathUtils::reflect( i, normal ); j = MathUtils::reflect( j, normal ); k = MathUtils::reflect( k, normal ); //mCross( i, j, &k ); MatrixF newTrans(true); newTrans.setColumn( 0, i ); newTrans.setColumn( 1, j ); newTrans.setColumn( 2, k ); newTrans.setPosition( newCamPos ); return newTrans; }
void SFXXAudioVoice::setTransform( const MatrixF& transform ) { transform.getColumn( 3, (Point3F*)&mEmitter.Position ); transform.getColumn( 1, (Point3F*)&mEmitter.OrientFront ); transform.getColumn( 2, (Point3F*)&mEmitter.OrientTop ); // XAudio and Torque use opposite handedness, so // flip the z coord to account for that. mEmitter.Position.z *= -1.0f; mEmitter.OrientFront.z *= -1.0f; mEmitter.OrientTop.z *= -1.0f; }
void BoxConvex::emitFace(S32 fi,const MatrixF& mat,ConvexFeature* cf) { Face& face = sFace[fi]; // Emit vertices S32 vc = cf->mVertexList.size(); cf->mVertexList.increment(4); Point3F *vp = cf->mVertexList.begin(); for (S32 v = 0; v < 4; v++) mat.mulP(getVertex(face.vertex[v]),&vp[vc + v]); // Emit edges cf->mEdgeList.increment(4); ConvexFeature::Edge* edge = cf->mEdgeList.end() - 4; for (S32 e = 0; e < 4; e++) { edge[e].vertex[0] = vc + e; edge[e].vertex[1] = vc + ((e + 1) & 3); } // Emit 2 triangle faces cf->mFaceList.increment(2); ConvexFeature::Face* ef = cf->mFaceList.end() - 2; mat.getColumn(face.axis,&ef->normal); if (face.flip) ef[0].normal.neg(); ef[1].normal = ef[0].normal; ef[1].vertex[0] = ef[0].vertex[0] = vc; ef[1].vertex[1] = ef[0].vertex[2] = vc + 2; ef[0].vertex[1] = vc + 1; ef[1].vertex[2] = vc + 3; }
void WorldEditorSelection::offset( const Point3F& offset, F32 gridSnap ) { for( iterator iter = begin(); iter != end(); ++ iter ) { SceneObject* obj = dynamic_cast<SceneObject*>( *iter ); if( !obj ) continue; MatrixF mat = obj->getTransform(); Point3F wPos; mat.getColumn(3, &wPos); // adjust wPos += offset; if( gridSnap != 0.f ) { wPos.x -= mFmod( wPos.x, gridSnap ); wPos.y -= mFmod( wPos.y, gridSnap ); wPos.z -= mFmod( wPos.z, gridSnap ); } mat.setColumn(3, wPos); obj->setTransform(mat); } mCentroidValid = false; }
void Rigid::setTransform(const MatrixF& mat) { angPosition.set(mat); mat.getColumn(3,&linPosition); // Update center of mass angPosition.mulP(centerOfMass,&worldCenterOfMass); worldCenterOfMass += linPosition; }
void Item::processTick(const Move* move) { Parent::processTick(move); // if (mCollisionObject && !--mCollisionTimeout) mCollisionObject = 0; // Warp to catch up to server if (delta.warpTicks > 0) { delta.warpTicks--; // Set new pos. MatrixF mat = mObjToWorld; mat.getColumn(3,&delta.pos); delta.pos += delta.warpOffset; mat.setColumn(3,delta.pos); Parent::setTransform(mat); // Backstepping delta.posVec.x = -delta.warpOffset.x; delta.posVec.y = -delta.warpOffset.y; delta.posVec.z = -delta.warpOffset.z; } else { if (isServerObject() && mAtRest && (mStatic == false && mDataBlock->sticky == false)) { if (++mAtRestCounter > csmAtRestTimer) { mAtRest = false; mAtRestCounter = 0; setMaskBits(PositionMask); } } if (!mStatic && !mAtRest && isHidden() == false) { updateVelocity(TickSec); updateWorkingCollisionSet(isGhost() ? sClientCollisionMask : sServerCollisionMask, TickSec); updatePos(isGhost() ? sClientCollisionMask : sServerCollisionMask, TickSec); } else { // Need to clear out last updatePos or warp interpolation delta.posVec.set(0,0,0); } } }
void SFXDSVoice::setTransform( const MatrixF& transform ) { if ( !mDSBuffer3D ) return; Point3F pos, dir; transform.getColumn( 3, &pos ); transform.getColumn( 1, &dir ); DSAssert( mDSBuffer3D->SetPosition( pos.x, pos.z, pos.y, DS3D_DEFERRED ), "SFXDSVoice::setTransform - couldn't set position of the buffer." ); DSAssert( mDSBuffer3D->SetConeOrientation( dir.x, dir.z, dir.y, DS3D_DEFERRED ), "SFXDSVoice::setTransform - couldn't set cone orientation of the buffer." ); }
void WorldEditorSelection::setRotate(const EulerF & rot) { for( iterator iter = begin(); iter != end(); ++ iter ) { SceneObject* object = dynamic_cast< SceneObject* >( *iter ); if( !object ) continue; MatrixF mat = object->getTransform(); Point3F pos; mat.getColumn(3, &pos); MatrixF rmat(rot); rmat.setPosition(pos); object->setTransform(rmat); } }
void GameTSCtrl::onMouseMove(const GuiEvent &evt) { if(gSnapLine) return; MatrixF mat; Point3F vel; if ( GameGetCameraTransform(&mat, &vel) ) { Point3F pos; mat.getColumn(3,&pos); Point3F screenPoint((F32)evt.mousePoint.x, (F32)evt.mousePoint.y, 1.0f); Point3F worldPoint; if (unproject(screenPoint, &worldPoint)) { Point3F vec = worldPoint - pos; lineTestStart = pos; vec.normalizeSafe(); lineTestEnd = pos + vec * 500; static U32 losMask = VehicleObjectType | StaticShapeObjectType; RayInfo ri; bool hit = gClientContainer.castRay( lineTestStart, lineTestEnd, losMask, &ri); if (!hit) { //Con::printf("no hit!"); if (mCursorObject != NULL) mCursorObject->setHighlighted(false); mCursorObject = NULL; } else { if (ri.object != mCursorObject && mCursorObject != NULL) mCursorObject->setHighlighted(false); mCursorObject = (ShapeBase*)ri.object; mCursorObject->setHighlighted(true); } } } }
void WorldEditorSelection::setScale(const VectorF & scale, const Point3F & center) { for( iterator iter = begin(); iter != end(); ++ iter ) { SceneObject* object = dynamic_cast< SceneObject* >( *iter ); if( !object ) continue; MatrixF mat = object->getTransform(); Point3F pos; mat.getColumn(3, &pos); Point3F offset = pos - center; offset *= scale; object->setPosition(offset + center); object->setScale(scale); } }
/** * Sets the correct aim for the bot to the target */ void AIPlayer::getMuzzleVector(U32 imageSlot,VectorF* vec) { MatrixF mat; getMuzzleTransform(imageSlot,&mat); MountedImage& image = mMountedImageList[imageSlot]; if (image.dataBlock->correctMuzzleVector) { disableHeadZCalc(); if (getCorrectedAim(mat, vec)) { enableHeadZCalc(); return; } enableHeadZCalc(); } mat.getColumn(1,vec); }
void GameTSCtrl::onMouseMove(const GuiEvent &evt) { if(gSnapLine) return; MatrixF mat; Point3F vel; if ( GameGetCameraTransform(&mat, &vel) ) { Point3F pos; mat.getColumn(3,&pos); Point3F screenPoint((F32)evt.mousePoint.x, (F32)evt.mousePoint.y, -1.0f); Point3F worldPoint; if (unproject(screenPoint, &worldPoint)) { Point3F vec = worldPoint - pos; lineTestStart = pos; vec.normalizeSafe(); lineTestEnd = pos + vec * 1000; } } }
void WorldEditorSelection::scale(const VectorF & scale, const Point3F & center) { for( iterator iter = begin(); iter != end(); ++ iter ) { SceneObject* object = dynamic_cast< SceneObject* >( *iter ); if( !object ) continue; VectorF current = object->getScale(); current.convolve(scale); // clamp scale to sensible limits current.setMax( Point3F( 0.01f ) ); current.setMin( Point3F( 1000.0f ) ); // Apply the scale first. If the object's scale doesn't change with // this operation then this object doesn't scale. In this case // we don't want to continue with the offset operation. VectorF prevScale = object->getScale(); object->setScale(current); if( !object->getScale().equal(current) ) continue; // determine the actual scale factor to apply to the object offset // need to account for the scale limiting above to prevent offsets // being reduced to 0 which then cannot be restored by unscaling VectorF adjustedScale = current / prevScale; MatrixF mat = object->getTransform(); Point3F pos; mat.getColumn(3, &pos); Point3F offset = pos - center; offset *= adjustedScale; object->setPosition(offset + center); } }
void Lightning::scheduleThunder(Strike* newStrike) { AssertFatal(isClientObject(), "Lightning::scheduleThunder: server objects should not enter this version of the function"); // If no thunder sounds, don't schedule anything! if (mDataBlock->numThunders == 0) return; GameConnection* connection = GameConnection::getConnectionToServer(); if (connection) { MatrixF cameraMatrix; if (connection->getControlCameraTransform(0, &cameraMatrix)) { Point3F worldPos; cameraMatrix.getColumn(3, &worldPos); worldPos.x -= newStrike->xVal; worldPos.y -= newStrike->yVal; worldPos.z = 0.0f; F32 dist = worldPos.len(); F32 t = dist / 330.0f; // Ok, we need to schedule a random strike sound t secs in the future... // if (t <= 0.03f) { // If it's really close, just play it... U32 thunder = sgLightningRand.randI(0, mDataBlock->numThunders - 1); SFX->playOnce(mDataBlock->thunderSounds[thunder]); } else { Thunder* pThunder = new Thunder; pThunder->tRemaining = t; pThunder->next = mThunderListHead; mThunderListHead = pThunder; } } } }
void AITurretShape::_renderScanner( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) { GFXStateBlockDesc desc; desc.setBlend(false, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); desc.setZReadWrite(false,true); desc.fillMode = GFXFillWireframe; // Render the scan box GFX->getDrawUtil()->drawCube(desc, mTransformedScanBox.getExtents(), mTransformedScanBox.getCenter(), ColorI(255, 0, 0)); // Render a line from the scan node to the max scan distance MatrixF nodeMat; if (getNodeTransform(mDataBlock->scanNode, nodeMat)) { Point3F start; nodeMat.getColumn(3, &start); Point3F end(0.0f, mScanDistance, 0.0f); nodeMat.mulP(end); GFX->getDrawUtil()->drawLine(start, end, ColorI(255, 255, 0)); } }
void Etherform::updateTrailEmitter(F32 dt) { if(mDamageState == Destroyed) return; if(!mDataBlock->jetEmitter[EtherformData::TrailEmitter]) return; ParticleEmitter* emitter = mJetEmitter[EtherformData::TrailEmitter]; // Particle trail emitter F32 speed = this->getVelocity().len(); if(speed > mDataBlock->minTrailSpeed) { if(!bool(emitter)) { emitter = new ParticleEmitter; emitter->onNewDataBlock(mDataBlock->jetEmitter[EtherformData::TrailEmitter], false); emitter->registerObject(); mJetEmitter[EtherformData::TrailEmitter] = emitter; } MatrixF mat = this->getRenderTransform(); Point3F pos,axis; //mat.getColumn(1,&axis); axis = this->getVelocity(); axis.normalize(); mat.getColumn(3,&pos); emitter->emitParticles(pos,true,axis,getVelocity(),(U32)(dt * 1000)); } else { if(bool(emitter)) { emitter->deleteWhenEmpty(); mJetEmitter[EtherformData::TrailEmitter] = 0; } } }
void SFXSource::_updateVolume( const MatrixF& listener ) { const F32 volume = mVolume * mModulativeVolume; if ( !mIs3D ) { mDistToListener = 0.0f; mAttenuatedVolume = volume; return; } Point3F pos, lpos; mTransform.getColumn( 3, &pos ); listener.getColumn( 3, &lpos ); mDistToListener = ( pos - lpos ).len(); mAttenuatedVolume = SFXDistanceAttenuation( SFX->getDistanceModel(), mMinDistance, mMaxDistance, mDistToListener, volume, SFX->getRolloffFactor() ); }
void WorldEditorSelection::rotate(const EulerF & rot, const Point3F & center) { // single selections will rotate around own axis, multiple about world if(size() == 1) { SceneObject* object = dynamic_cast< SceneObject* >( at( 0 ) ); if( object ) { MatrixF mat = object->getTransform(); Point3F pos; mat.getColumn(3, &pos); // get offset in obj space Point3F offset = pos - center; MatrixF wMat = object->getWorldTransform(); wMat.mulV(offset); // MatrixF transform(EulerF(0,0,0), -offset); transform.mul(MatrixF(rot)); transform.mul(MatrixF(EulerF(0,0,0), offset)); mat.mul(transform); object->setTransform(mat); } } else { for( iterator iter = begin(); iter != end(); ++ iter ) { SceneObject* object = dynamic_cast< SceneObject* >( *iter ); if( !object ) continue; MatrixF mat = object->getTransform(); Point3F pos; mat.getColumn(3, &pos); // get offset in obj space Point3F offset = pos - center; MatrixF transform(rot); Point3F wOffset; transform.mulV(offset, &wOffset); MatrixF wMat = object->getWorldTransform(); wMat.mulV(offset); // transform.set(EulerF(0,0,0), -offset); mat.setColumn(3, Point3F(0,0,0)); wMat.setColumn(3, Point3F(0,0,0)); transform.mul(wMat); transform.mul(MatrixF(rot)); transform.mul(mat); mat.mul(transform); mat.normalize(); mat.setColumn(3, wOffset + center); object->setTransform(mat); } } mCentroidValid = false; }
void TurretShape::getCameraTransform(F32* pos,MatrixF* mat) { // Returns camera to world space transform // Handles first person / third person camera position if (isServerObject() && mShapeInstance) mShapeInstance->animateNodeSubtrees(true); if (*pos == 0) { getRenderEyeTransform(mat); return; } // Get the shape's camera parameters. F32 min,max; MatrixF rot; Point3F offset; getCameraParameters(&min,&max,&offset,&rot); // Start with the current eye position MatrixF eye; getRenderEyeTransform(&eye); // Build a transform that points along the eye axis // but where the Z axis is always up. { MatrixF cam(1); VectorF x,y,z(0,0,1); eye.getColumn(1, &y); mCross(y, z, &x); x.normalize(); mCross(x, y, &z); z.normalize(); cam.setColumn(0,x); cam.setColumn(1,y); cam.setColumn(2,z); mat->mul(cam,rot); } // Camera is positioned straight back along the eye's -Y axis. // A ray is cast to make sure the camera doesn't go through // anything solid. VectorF vp,vec; vp.x = vp.z = 0; vp.y = -(max - min) * *pos; eye.mulV(vp,&vec); // Use the camera node as the starting position if it exists. Point3F osp,sp; if (mDataBlock->cameraNode != -1) { mShapeInstance->mNodeTransforms[mDataBlock->cameraNode].getColumn(3,&osp); getRenderTransform().mulP(osp,&sp); } else eye.getColumn(3,&sp); // Make sure we don't hit ourself... disableCollision(); if (isMounted()) getObjectMount()->disableCollision(); // Cast the ray into the container database to see if we're going // to hit anything. RayInfo collision; Point3F ep = sp + vec + offset; if (mContainer->castRay(sp, ep, ~(WaterObjectType | GameBaseObjectType | DefaultObjectType | sTriggerMask), &collision) == true) { // Shift the collision point back a little to try and // avoid clipping against the front camera plane. F32 t = collision.t - (-mDot(vec, collision.normal) / vec.len()) * 0.1; if (t > 0.0f) ep = sp + offset + (vec * t); else eye.getColumn(3,&ep); } mat->setColumn(3,ep); // Re-enable our collision. if (isMounted()) getObjectMount()->enableCollision(); enableCollision(); // Apply Camera FX. mat->mul( gCamFXMgr.getTrans() ); }
//----------------------------------------------------------------------------- // // VActorPhysicsController::postTickUpdate( pDelta ); // // ... // //----------------------------------------------------------------------------- void VActorPhysicsController::postTickUpdate( const F32 &pDelta ) { switch( mControlState ) { case k_PathControlState : { AssertFatal( isPathing(), "VActorPhysicsController::postTickUpdate() - Invalid Path State." ); // Fetch Mount Transform. MatrixF transform; mMountedPath->getMountTransform( mObject->getMountNode(), getTransform(), &transform ); // Fetch Mount Position. const Point3F &mountPosition = transform.getPosition(); // Update X & Y Position. Point3F position = getPosition(); position.x = mountPosition.x; position.y = mountPosition.y; // In Water? bool underWater = false; if ( isInWater() ) { // Fetch Body of Water. WaterObject *waterBody = getWaterObject(); // Fetch Surface Position. const F32 &waterSurfacePosition = waterBody->getSurfaceHeight( Point2F( position.x, position.y ) ); // Fetch Submersion Position. const F32 sumbersionPosition = waterSurfacePosition - ( mObject->getWorldBox().len_z() * mObject->getDataBlock()->getSumbergeCoverage() ); // Choose a Z Value. // Note: This is done so that the Actor will either path under the // water, or it will swim along the water's surface. position.z = getMin( mountPosition.z, sumbersionPosition ); // Under Water? underWater = ( position.z < sumbersionPosition ); } // Under Water? if ( !underWater ) { // Fetch Y Column. VectorF forwardVector; transform.getColumn( 1, &forwardVector ); // Determine Angle. const F32 &angle = -mAtan2( -forwardVector.x, forwardVector.y ); // Reset Transform. transform.set( EulerF( 0.f, 0.f, angle ) ); // In the air? if ( !isOnGround() ) { // Apply z-axis force. position.z += ( getVelocity().z * pDelta ); } } // Update Transform. transform.setPosition( position ); // Apply Update. setTransform( transform ); } break; default : { // Fetch Transform. MatrixF transform = getTransform(); // Determine the Post-Tick Position. Point3F postTickPosition = getPosition() + ( getVelocity() * pDelta ); // Set the Post Tick Position. transform.setPosition( postTickPosition ); // Apply the Transform. setTransform( transform ); } break; } // Push Delta. mInterpController.pushDelta( getTransform() ); }
void FlyingVehicle::updateForces(F32 /*dt*/) { PROFILE_SCOPE( FlyingVehicle_UpdateForces ); MatrixF currPosMat; mRigid.getTransform(&currPosMat); mRigid.atRest = false; Point3F massCenter; currPosMat.mulP(mDataBlock->massCenter,&massCenter); Point3F xv,yv,zv; currPosMat.getColumn(0,&xv); currPosMat.getColumn(1,&yv); currPosMat.getColumn(2,&zv); F32 speed = mRigid.linVelocity.len(); Point3F force = Point3F(0, 0, sFlyingVehicleGravity * mRigid.mass * mGravityMod); Point3F torque = Point3F(0, 0, 0); // Drag at any speed force -= mRigid.linVelocity * mDataBlock->minDrag; torque -= mRigid.angMomentum * mDataBlock->rotationalDrag; // Auto-stop at low speeds if (speed < mDataBlock->maxAutoSpeed) { F32 autoScale = 1 - speed / mDataBlock->maxAutoSpeed; // Gyroscope F32 gf = mDataBlock->autoAngularForce * autoScale; torque -= xv * gf * mDot(yv,Point3F(0,0,1)); // Manuevering jets F32 sf = mDataBlock->autoLinearForce * autoScale; force -= yv * sf * mDot(yv, mRigid.linVelocity); force -= xv * sf * mDot(xv, mRigid.linVelocity); } // Hovering Jet F32 vf = -sFlyingVehicleGravity * mRigid.mass * mGravityMod; F32 h = getHeight(); if (h <= 1) { if (h > 0) { vf -= vf * h * 0.1; } else { vf += mDataBlock->jetForce * -h; } } force += zv * vf; // Damping "surfaces" force -= xv * mDot(xv,mRigid.linVelocity) * mDataBlock->horizontalSurfaceForce; force -= zv * mDot(zv,mRigid.linVelocity) * mDataBlock->verticalSurfaceForce; // Turbo Jet if (mJetting) { if (mThrustDirection == ThrustForward) force += yv * mDataBlock->jetForce * mCeilingFactor; else if (mThrustDirection == ThrustBackward) force -= yv * mDataBlock->jetForce * mCeilingFactor; else force += zv * mDataBlock->jetForce * mDataBlock->vertThrustMultiple * mCeilingFactor; } // Maneuvering jets force += yv * (mThrust.y * mDataBlock->maneuveringForce * mCeilingFactor); force += xv * (mThrust.x * mDataBlock->maneuveringForce * mCeilingFactor); // Steering Point2F steering; steering.x = mSteering.x / mDataBlock->maxSteeringAngle; steering.x *= mFabs(steering.x); steering.y = mSteering.y / mDataBlock->maxSteeringAngle; steering.y *= mFabs(steering.y); torque -= xv * steering.y * mDataBlock->steeringForce; torque -= zv * steering.x * mDataBlock->steeringForce; // Roll torque += yv * steering.x * mDataBlock->steeringRollForce; F32 ar = mDataBlock->autoAngularForce * mDot(xv,Point3F(0,0,1)); ar -= mDataBlock->rollForce * mDot(xv, mRigid.linVelocity); torque += yv * ar; // Add in force from physical zones... force += mAppliedForce; // Container buoyancy & drag force -= Point3F(0, 0, 1) * (mBuoyancy * sFlyingVehicleGravity * mRigid.mass * mGravityMod); force -= mRigid.linVelocity * mDrag; // mRigid.force = force; mRigid.torque = torque; }
void GuiRiverEditorCtrl::renderScene(const RectI & updateRect) { //GFXDrawUtil *drawer = GFX->getDrawUtil(); GFX->setStateBlock( mZDisableSB ); // get the projected size... GameConnection* connection = GameConnection::getConnectionToServer(); if(!connection) return; // Grab the camera's transform MatrixF mat; connection->getControlCameraTransform(0, &mat); // Get the camera position Point3F camPos; mat.getColumn(3,&camPos); if ( mHoverRiver && mHoverRiver != mSelRiver ) { _drawRiverSpline( mHoverRiver, mHoverSplineColor ); } if ( mSelRiver ) { _drawRiverSpline( mSelRiver, mSelectedSplineColor ); // Render Gizmo for selected node if were in either of the three transform modes if ( mSelNode != -1 && ( mMode == mMovePointMode || mMode == mScalePointMode || mMode == mRotatePointMode ) ) { if( mMode == mMovePointMode ) { mGizmo->getProfile()->mode = MoveMode; } else if( mMode == mScalePointMode ) { mGizmo->getProfile()->mode = ScaleMode; } else if( mMode == mRotatePointMode ) { mGizmo->getProfile()->mode = RotateMode; } const RiverNode &node = mSelRiver->mNodes[mSelNode]; MatrixF objMat = mSelRiver->getNodeTransform(mSelNode); Point3F objScale( node.width, 1.0f, node.depth ); Point3F worldPos = node.point; mGizmo->set( objMat, worldPos, objScale ); mGizmo->renderGizmo(mLastCameraQuery.cameraMatrix); } } // Now draw all the 2d stuff! GFX->setClipRect(updateRect); // Render Gizmo text if ( mSelRiver && mSelNode != -1 ) { // mGizmo->setPosition(mSelRiver->mNodes[mSelNode].point); // mGizmo->renderText( mSaveViewport, mSaveModelview, mSaveProjection ); } // Draw Control nodes for selecting and highlighted rivers if ( mHoverRiver ) _drawRiverControlNodes( mHoverRiver, mHoverSplineColor ); if ( mSelRiver ) _drawRiverControlNodes( mSelRiver, mSelectedSplineColor ); }
/** * This method calculates the moves for the AI player * * @param movePtr Pointer to move the move list into */ bool AIPlayer::getAIMove(Move *movePtr) { *movePtr = NullMove; // Use the eye as the current position. MatrixF eye; getEyeTransform(&eye); Point3F location = eye.getPosition(); Point3F rotation = getRotation(); // Orient towards the aim point, aim object, or towards // our destination. if (mAimObject || mAimLocationSet || mMoveState != ModeStop) { // Update the aim position if we're aiming for an object if (mAimObject) mAimLocation = mAimObject->getPosition() + mAimOffset; else if (!mAimLocationSet) mAimLocation = mMoveDestination; F32 xDiff = mAimLocation.x - location.x; F32 yDiff = mAimLocation.y - location.y; if (!mIsZero(xDiff) || !mIsZero(yDiff)) { // First do Yaw // use the cur yaw between -Pi and Pi F32 curYaw = rotation.z; while (curYaw > M_2PI_F) curYaw -= M_2PI_F; while (curYaw < -M_2PI_F) curYaw += M_2PI_F; // find the yaw offset F32 newYaw = mAtan2( xDiff, yDiff ); F32 yawDiff = newYaw - curYaw; // make it between 0 and 2PI if( yawDiff < 0.0f ) yawDiff += M_2PI_F; else if( yawDiff >= M_2PI_F ) yawDiff -= M_2PI_F; // now make sure we take the short way around the circle if( yawDiff > M_PI_F ) yawDiff -= M_2PI_F; else if( yawDiff < -M_PI_F ) yawDiff += M_2PI_F; movePtr->yaw = yawDiff; // Next do pitch. if (!mAimObject && !mAimLocationSet) { // Level out if were just looking at our next way point. Point3F headRotation = getHeadRotation(); movePtr->pitch = -headRotation.x; } else { // This should be adjusted to run from the // eye point to the object's center position. Though this // works well enough for now. F32 vertDist = mAimLocation.z - location.z; F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff); F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f ); if (mFabs(newPitch) > 0.01f) { Point3F headRotation = getHeadRotation(); movePtr->pitch = newPitch - headRotation.x; } } } } else { // Level out if we're not doing anything else Point3F headRotation = getHeadRotation(); movePtr->pitch = -headRotation.x; } // Move towards the destination if (mMoveState != ModeStop) { F32 xDiff = mMoveDestination.x - location.x; F32 yDiff = mMoveDestination.y - location.y; // Check if we should mMove, or if we are 'close enough' if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) { mMoveState = ModeStop; throwCallback("onReachDestination"); } else { // Build move direction in world space if (mIsZero(xDiff)) movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f; else if (mIsZero(yDiff)) movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f; else if (mFabs(xDiff) > mFabs(yDiff)) { F32 value = mFabs(yDiff / xDiff); movePtr->y = (location.y > mMoveDestination.y) ? -value : value; movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f; } else { F32 value = mFabs(xDiff / yDiff); movePtr->x = (location.x > mMoveDestination.x) ? -value : value; movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f; } // Rotate the move into object space (this really only needs // a 2D matrix) Point3F newMove; MatrixF moveMatrix; moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw))); moveMatrix.mulV( Point3F( movePtr->x, movePtr->y, 0.0f ), &newMove ); movePtr->x = newMove.x; movePtr->y = newMove.y; // Set movement speed. We'll slow down once we get close // to try and stop on the spot... if (mMoveSlowdown) { F32 speed = mMoveSpeed; F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff); F32 maxDist = 5.0f; if (dist < maxDist) speed *= dist / maxDist; movePtr->x *= speed; movePtr->y *= speed; mMoveState = ModeSlowing; } else { movePtr->x *= mMoveSpeed; movePtr->y *= mMoveSpeed; mMoveState = ModeMove; } if (mMoveStuckTestCountdown > 0) --mMoveStuckTestCountdown; else { // We should check to see if we are stuck... F32 locationDelta = (location - mLastLocation).len(); if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled) { // If we are slowing down, then it's likely that our location delta will be less than // our move stuck tolerance. Because we can be both slowing and stuck // we should TRY to check if we've moved. This could use better detection. if ( mMoveState != ModeSlowing || locationDelta == 0 ) { mMoveState = ModeStuck; throwCallback("onMoveStuck"); } } } } } // Test for target location in sight if it's an object. The LOS is // run from the eye position to the center of the object's bounding, // which is not very accurate. if (mAimObject) { MatrixF eyeMat; getEyeTransform(&eyeMat); eyeMat.getColumn(3,&location); Point3F targetLoc = mAimObject->getBoxCenter(); // This ray ignores non-static shapes. Cast Ray returns true // if it hit something. RayInfo dummy; if (getContainer()->castRay( location, targetLoc, StaticShapeObjectType | StaticObjectType | TerrainObjectType, &dummy)) { if (mTargetInLOS) { throwCallback( "onTargetExitLOS" ); mTargetInLOS = false; } } else if (!mTargetInLOS) { throwCallback( "onTargetEnterLOS" ); mTargetInLOS = true; } } // Replicate the trigger state into the move so that // triggers can be controlled from scripts. for( int i = 0; i < MaxTriggerKeys; i++ ) movePtr->trigger[i] = getImageTriggerState(i); mLastLocation = location; return true; }
void Polytope::buildBox(const MatrixF& transform,const Box3F& box) { // Box is assumed to be axis aligned in the source space. // Transform into geometry space Point3F xvec,yvec,zvec,min; transform.getColumn(0,&xvec); xvec *= box.len_x(); transform.getColumn(1,&yvec); yvec *= box.len_y(); transform.getColumn(2,&zvec); zvec *= box.len_z(); transform.mulP(box.minExtents,&min); // Initial vertices mVertexList.setSize(8); mVertexList[0].point = min; mVertexList[1].point = min + yvec; mVertexList[2].point = min + xvec + yvec; mVertexList[3].point = min + xvec; mVertexList[4].point = mVertexList[0].point + zvec; mVertexList[5].point = mVertexList[1].point + zvec; mVertexList[6].point = mVertexList[2].point + zvec; mVertexList[7].point = mVertexList[3].point + zvec; S32 i; for (i = 0; i < 8; i++) mVertexList[i].side = 0; // Initial faces mFaceList.setSize(6); for (S32 f = 0; f < 6; f++) { Face& face = mFaceList[f]; face.original = true; face.vertex = 0; } mFaceList[0].plane.set(mVertexList[0].point,xvec); mFaceList[0].plane.invert(); mFaceList[1].plane.set(mVertexList[2].point,yvec); mFaceList[2].plane.set(mVertexList[2].point,xvec); mFaceList[3].plane.set(mVertexList[0].point,yvec); mFaceList[3].plane.invert(); mFaceList[4].plane.set(mVertexList[0].point,zvec); mFaceList[4].plane.invert(); mFaceList[5].plane.set(mVertexList[4].point,zvec); // Initial edges mEdgeList.setSize(12); Edge* edge = mEdgeList.begin(); S32 nextEdge = 0; for (i = 0; i < 4; i++) { S32 n = (i == 3)? 0: i + 1; S32 p = (i == 0)? 3: i - 1; edge->vertex[0] = i; edge->vertex[1] = n; edge->face[0] = i; edge->face[1] = 4; edge->next = ++nextEdge; edge++; edge->vertex[0] = 4 + i; edge->vertex[1] = 4 + n; edge->face[0] = i; edge->face[1] = 5; edge->next = ++nextEdge; edge++; edge->vertex[0] = i; edge->vertex[1] = 4 + i; edge->face[0] = i; edge->face[1] = p; edge->next = ++nextEdge; edge++; } edge[-1].next = -1; // Volume mVolumeList.setSize(1); Volume& volume = mVolumeList.last(); volume.edgeList = 0; volume.material = -1; volume.object = 0; sideCount = 0; }
void GuiObjectView::renderWorld( const RectI& updateRect ) { if( !mModel ) return; GFXTransformSaver _saveTransforms; // Determine the camera position, and store off render state. MatrixF modelview; MatrixF mv; Point3F cp; modelview = GFX->getWorldMatrix(); mv = modelview; mv.inverse(); mv.getColumn( 3, &cp ); RenderPassManager* renderPass = gClientSceneGraph->getDefaultRenderPass(); S32 time = Platform::getVirtualMilliseconds(); S32 dt = time - mLastRenderTime; mLastRenderTime = time; LIGHTMGR->unregisterAllLights(); LIGHTMGR->setSpecialLight( LightManager::slSunLightType, mLight ); GFX->setStateBlock( mDefaultGuiSB ); F32 left, right, top, bottom, nearPlane, farPlane; bool isOrtho; GFX->getFrustum( &left, &right, &bottom, &top, &nearPlane, &farPlane, &isOrtho ); Frustum frust( false, left, right, top, bottom, nearPlane, farPlane, MatrixF::Identity ); SceneRenderState state ( gClientSceneGraph, SPT_Diffuse, SceneCameraState( GFX->getViewport(), frust, GFX->getWorldMatrix(), GFX->getProjectionMatrix() ), renderPass, false ); // Set up our TS render state here. TSRenderState rdata; rdata.setSceneState( &state ); // We might have some forward lit materials // so pass down a query to gather lights. LightQuery query; query.init( SphereF( Point3F::Zero, 1.0f ) ); rdata.setLightQuery( &query ); // Render primary model. if( mModel ) { if( mRunThread ) { mModel->advanceTime( dt / 1000.f, mRunThread ); mModel->animate(); } mModel->render( rdata ); } // Render mounted model. if( mMountedModel && mMountNode != -1 ) { GFX->pushWorldMatrix(); GFX->multWorld( mModel->mNodeTransforms[ mMountNode ] ); GFX->multWorld( mMountTransform ); mMountedModel->render( rdata ); GFX->popWorldMatrix(); } renderPass->renderPass( &state ); // Make sure to remove our fake sun. LIGHTMGR->unregisterAllLights(); }
void EditTSCtrl::renderCameraAxis() { GFXDEBUGEVENT_SCOPE( Editor_renderCameraAxis, ColorI::WHITE ); static MatrixF sRotMat(EulerF( (M_PI_F / -2.0f), 0.0f, 0.0f)); MatrixF camMat = mLastCameraQuery.cameraMatrix; camMat.mul(sRotMat); camMat.inverse(); MatrixF axis; axis.setColumn(0, Point3F(1, 0, 0)); axis.setColumn(1, Point3F(0, 0, 1)); axis.setColumn(2, Point3F(0, -1, 0)); axis.mul(camMat); Point3F forwardVec, upVec, rightVec; axis.getColumn( 2, &forwardVec ); axis.getColumn( 1, &upVec ); axis.getColumn( 0, &rightVec ); Point2I pos = getPosition(); F32 offsetx = pos.x + 20.0; F32 offsety = pos.y + getExtent().y - 42.0; // Take the status bar into account F32 scale = 15.0; // Generate correct drawing order ColorI c1(255,0,0); ColorI c2(0,255,0); ColorI c3(0,0,255); ColorI tc; Point3F *p1, *p2, *p3, *tp; p1 = &rightVec; p2 = &upVec; p3 = &forwardVec; if(p3->y > p2->y) { tp = p2; tc = c2; p2 = p3; c2 = c3; p3 = tp; c3 = tc; } if(p2->y > p1->y) { tp = p1; tc = c1; p1 = p2; c1 = c2; p2 = tp; c2 = tc; } PrimBuild::begin( GFXLineList, 6 ); //*** Axis 1 PrimBuild::color(c1); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p1->x*scale, offsety-p1->z*scale, 0); //*** Axis 2 PrimBuild::color(c2); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p2->x*scale, offsety-p2->z*scale, 0); //*** Axis 3 PrimBuild::color(c3); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p3->x*scale, offsety-p3->z*scale, 0); PrimBuild::end(); }
void AITurretShape::_trackTarget(F32 dt) { // Only on server if (isClientObject()) return; // We can only track a target if we have one if (!mTarget.isValid()) return; Point3F targetPos = mTarget.target->getBoxCenter(); // Can we see the target? MatrixF aimMat; getAimTransform(aimMat); Point3F start; aimMat.getColumn(3, &start); RayInfo ri; Point3F sightPoint; disableCollision(); bool los = _testTargetLineOfSight(start, mTarget.target, sightPoint); enableCollision(); if (!los) { // Target is blocked. Should we try to track from its last // known position and velocity? SimTime curTime = Sim::getCurrentTime(); if ( (curTime - mTarget.lastSightTime) > (mDataBlock->trackLostTargetTime * 1000.0f) ) { // Time's up. Stop tracking. _cleanupTargetAndTurret(); return; } // Use last known information to attempt to // continue to track target for a while. targetPos = mTarget.lastPos + mTarget.lastVel * F32(curTime - mTarget.lastSightTime) / 1000.0f; } else { // Target is visible // We only track targets that are alive if (mTarget.target->getDamageState() != Enabled) { // We can't track any more _cleanupTargetAndTurret(); return; } targetPos = sightPoint; // Store latest target info mTarget.lastPos = targetPos; mTarget.lastVel = mTarget.target->getVelocity(); mTarget.lastSightTime = Sim::getCurrentTime(); } // Calculate angles to face the target, specifically the part that we can see VectorF toTarget; MatrixF mat; S32 node = mDataBlock->aimNode; if (node != -1) { // Get the current position of our node MatrixF* nodeTrans = &mShapeInstance->mNodeTransforms[node]; Point3F currentPos; nodeTrans->getColumn(3, ¤tPos); // Turn this into a matrix we can use to put the target // position into our space. MatrixF nodeMat(true); nodeMat.setColumn(3, currentPos); mat.mul(mObjToWorld, nodeMat); mat.affineInverse(); } else { mat = mWorldToObj; } mat.mulP(targetPos, &toTarget); // lead the target F32 timeToTargetSquared = (mWeaponLeadVelocitySquared > 0) ? toTarget.lenSquared() / mWeaponLeadVelocitySquared : 0; if (timeToTargetSquared > 1.0) { targetPos = targetPos + (mTarget.lastVel * mSqrt(timeToTargetSquared)); mat.mulP(targetPos, &toTarget); } F32 yaw, pitch; MathUtils::getAnglesFromVector(toTarget, yaw, pitch); if (yaw > M_PI_F) yaw = yaw - M_2PI_F; //if (pitch > M_PI_F) // pitch = -(pitch - M_2PI_F); Point3F rot(-pitch, 0.0f, yaw); // If we have a rotation rate make sure we follow it if (mHeadingRate > 0) { F32 rate = mHeadingRate * dt; F32 rateCheck = mFabs(rot.z - mRot.z); if (rateCheck > rate) { // This will clamp the new value to the rate regardless if it // is increasing or decreasing. rot.z = mClampF(rot.z, mRot.z-rate, mRot.z+rate); } } if (mPitchRate > 0) { F32 rate = mPitchRate * dt; F32 rateCheck = mFabs(rot.x - mRot.x); if (rateCheck > rate) { // This will clamp the new value to the rate regardless if it // is increasing or decreasing. rot.x = mClampF(rot.x, mRot.x-rate, mRot.x+rate); } } // Test if the rotation to the target is outside of our limits if (_outsideLimits(rot)) { // We can't track any more _cleanupTargetAndTurret(); return; } // Test if the target is out of weapons range if (toTarget.lenSquared() > mWeaponRangeSquared) { // We can't track any more _cleanupTargetAndTurret(); return; } mRot = rot; _setRotation( mRot ); setMaskBits(TurretUpdateMask); }
bool Box3F::collideOrientedBox(const Point3F & bRadii, const MatrixF & toA) const { Point3F p; toA.getColumn(3,&p); Point3F aCenter = minExtents + maxExtents; aCenter *= 0.5f; p -= aCenter; // this essentially puts origin of toA target space on the center of the current box Point3F aRadii = maxExtents - minExtents; aRadii *= 0.5f; F32 absXX,absXY,absXZ; F32 absYX,absYY,absYZ; F32 absZX,absZY,absZZ; const F32 * f = toA; absXX = mFabs(f[0]); absYX = mFabs(f[1]); absZX = mFabs(f[2]); if (aRadii.x + bRadii.x * absXX + bRadii.y * absYX + bRadii.z * absZX - mFabs(p.x)<0.0f) return false; absXY = mFabs(f[4]); absYY = mFabs(f[5]); absZY = mFabs(f[6]); if (aRadii.y + bRadii.x * absXY + bRadii.y * absYY + bRadii.z * absZY - mFabs(p.y)<0.0f) return false; absXZ = mFabs(f[8]); absYZ = mFabs(f[9]); absZZ = mFabs(f[10]); if (aRadii.z + bRadii.x * absXZ + bRadii.y * absYZ + bRadii.z * absZZ - mFabs(p.z)<0.0f) return false; if (aRadii.x*absXX + aRadii.y*absXY + aRadii.z*absXZ + bRadii.x - mFabs(p.x*f[0] + p.y*f[4] + p.z*f[8])<0.0f) return false; if (aRadii.x*absYX + aRadii.y*absYY + aRadii.z*absYZ + bRadii.y - mFabs(p.x*f[1] + p.y*f[5] + p.z*f[9])<0.0f) return false; if (aRadii.x*absZX + aRadii.y*absZY + aRadii.z*absZZ + bRadii.z - mFabs(p.x*f[2] + p.y*f[6] + p.z*f[10])<0.0f) return false; if (mFabs(p.z*f[4] - p.y*f[8]) > aRadii.y * absXZ + aRadii.z * absXY + bRadii.y * absZX + bRadii.z * absYX) return false; if (mFabs(p.z*f[5] - p.y*f[9]) > aRadii.y * absYZ + aRadii.z * absYY + bRadii.x * absZX + bRadii.z * absXX) return false; if (mFabs(p.z*f[6] - p.y*f[10]) > aRadii.y * absZZ + aRadii.z * absZY + bRadii.x * absYX + bRadii.y * absXX) return false; if (mFabs(p.x*f[8] - p.z*f[0]) > aRadii.x * absXZ + aRadii.z * absXX + bRadii.y * absZY + bRadii.z * absYY) return false; if (mFabs(p.x*f[9] - p.z*f[1]) > aRadii.x * absYZ + aRadii.z * absYX + bRadii.x * absZY + bRadii.z * absXY) return false; if (mFabs(p.x*f[10] - p.z*f[2]) > aRadii.x * absZZ + aRadii.z * absZX + bRadii.x * absYY + bRadii.y * absXY) return false; if (mFabs(p.y*f[0] - p.x*f[4]) > aRadii.x * absXY + aRadii.y * absXX + bRadii.y * absZZ + bRadii.z * absYZ) return false; if (mFabs(p.y*f[1] - p.x*f[5]) > aRadii.x * absYY + aRadii.y * absYX + bRadii.x * absZZ + bRadii.z * absXZ) return false; if (mFabs(p.y*f[2] - p.x*f[6]) > aRadii.x * absZY + aRadii.y * absZX + bRadii.x * absYZ + bRadii.y * absXZ) return false; return true; }