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); }
static U32 mSolveQuadratic_c(F32 a, F32 b, F32 c, F32 * x) { // really linear? if(mIsZero(a)) return(mSolveLinear(b, c, x)); // get the descriminant: (b^2 - 4ac) F32 desc = (b * b) - (4.f * a * c); // solutions: // desc < 0: two imaginary solutions // desc > 0: two real solutions (b +- sqrt(desc)) / 2a // desc = 0: one real solution (b / 2a) if(mIsZero(desc)) { x[0] = b / (2.f * a); return(1); } else if(desc > 0.f) { F32 sqrdesc = mSqrt(desc); F32 den = (2.f * a); x[0] = (-b + sqrdesc) / den; x[1] = (-b - sqrdesc) / den; if(x[1] < x[0]) swap(x[0], x[1]); return(2); } else return(0); }
//-------------------------------------- static void m_point3F_normalize_f_C(F32 *p, F32 val) { F32 factor = val / mSqrt(p[0]*p[0] + p[1]*p[1] + p[2]*p[2] ); p[0] *= factor; p[1] *= factor; p[2] *= factor; }
Box3F PSSMLightShadowMap::_calcClipSpaceAABB(const Frustum& f, const MatrixF& transform, F32 farDist) { // Calculate frustum center Point3F center(0,0,0); for (U32 i = 0; i < 8; i++) { const Point3F& pt = f.getPoints()[i]; center += pt; } center /= 8; // Calculate frustum bounding sphere radius F32 radius = 0.0f; for (U32 i = 0; i < 8; i++) radius = getMax(radius, (f.getPoints()[i] - center).lenSquared()); radius = mFloor( mSqrt(radius) ); // Now build box for sphere Box3F result; Point3F radiusBox(radius, radius, radius); result.minExtents = center - radiusBox; result.maxExtents = center + radiusBox; // Transform to light projection space transform.mul(result); return result; }
Point2F BiQuadToSqr::transform( const Point2F &p ) const { Point2F kA = m_kP00 - p; F32 fAB = mDotPerp( kA, m_kB ); F32 fAC = mDotPerp( kA, m_kC); // 0 = ac*bc+(bc^2+ac*bd-ab*cd)*s+bc*bd*s^2 = k0 + k1*s + k2*s^2 F32 fK0 = fAC*m_fBC; F32 fK1 = m_fBC*m_fBC + fAC*m_fBD - fAB*m_fCD; F32 fK2 = m_fBC*m_fBD; if (mFabs(fK2) > POINT_EPSILON) { // s-equation is quadratic F32 fInv = 0.5f/fK2; F32 fDiscr = fK1*fK1 - 4.0f*fK0*fK2; F32 fRoot = mSqrt( mFabs(fDiscr) ); Point2F kResult0( 0, 0 ); kResult0.x = (-fK1 - fRoot)*fInv; kResult0.y = fAB/(m_fBC + m_fBD*kResult0.x); F32 fDeviation0 = deviation(kResult0); if ( fDeviation0 == 0.0f ) return kResult0; Point2F kResult1( 0, 0 ); kResult1.x = (-fK1 + fRoot)*fInv; kResult1.y = fAB/(m_fBC + m_fBD*kResult1.x); F32 fDeviation1 = deviation(kResult1); if ( fDeviation1 == 0.0f ) return kResult1; if (fDeviation0 <= fDeviation1) { if ( fDeviation0 < POINT_EPSILON ) return kResult0; } else { if ( fDeviation1 < POINT_EPSILON ) return kResult1; } } else { // s-equation is linear Point2F kResult( 0, 0 ); kResult.x = -fK0/fK1; kResult.y = fAB/(m_fBC + m_fBD*kResult.x); F32 fDeviation = deviation(kResult); if ( fDeviation < POINT_EPSILON ) return kResult; } // point is outside the quadrilateral, return invalid return Point2F(F32_MAX,F32_MAX); }
QuatF & QuatF::set( const MatrixF & mat ) { PROFILE_SCOPE( QuatF_set_MatrixF ); F32 const *m = mat; F32 trace = m[idx(0, 0)] + m[idx(1, 1)] + m[idx(2, 2)]; if (trace > 0.0f) { F32 s = mSqrt(trace + F32(1)); w = s * 0.5f; s = 0.5f / s; x = (m[idx(1,2)] - m[idx(2,1)]) * s; y = (m[idx(2,0)] - m[idx(0,2)]) * s; z = (m[idx(0,1)] - m[idx(1,0)]) * s; } else { F32* q = &x; U32 i = 0; if (m[idx(1, 1)] > m[idx(0, 0)]) i = 1; if (m[idx(2, 2)] > m[idx(i, i)]) i = 2; U32 j = (i + 1) % 3; U32 k = (j + 1) % 3; F32 s = mSqrt((m[idx(i, i)] - (m[idx(j, j)] + m[idx(k, k)])) + 1.0f); q[i] = s * 0.5f; s = 0.5f / s; q[j] = (m[idx(i,j)] + m[idx(j,i)]) * s; q[k] = (m[idx(i,k)] + m[idx(k, i)]) * s; w = (m[idx(j,k)] - m[idx(k, j)]) * s; } // Added to resolve issue #2230 normalize(); return *this; }
QuatF & QuatF::normalize() { F32 l = mSqrt( x*x + y*y + z*z + w*w ); if( l == 0.0f ) identity(); else { x /= l; y /= l; z /= l; w /= l; } return *this; }
QuatF & QuatF::shortestArc( const VectorF &a, const VectorF &b ) { // From Game Programming Gems pg. 217 VectorF c = mCross( a, b ); F32 d = mDot( a, b ); F32 s = mSqrt( ( 1 + d ) * 2 ); x = c.x / s; y = c.y / s; z = c.z / s; w = s / 2.f; return *this; }
//-------------------------------------- static void m_point3F_normalize_C(F32 *p) { F32 squared = p[0]*p[0] + p[1]*p[1] + p[2]*p[2]; // This can happen in Container::castRay -> ForceFieldBare::castRay //AssertFatal(squared != 0.0, "Error, zero length vector normalized!"); if (squared != 0.0f) { F32 factor = 1.0f / mSqrt(squared); p[0] *= factor; p[1] *= factor; p[2] *= factor; } else { p[0] = 0.0f; p[1] = 0.0f; p[2] = 1.0f; } }
void TSPartInstance::updateBounds() { // run through meshes and brute force it? Box3F bounds; mBounds.minExtents.set( 10E30f, 10E30f, 10E30f); mBounds.maxExtents.set(-10E30f,-10E30f,-10E30f); for (S32 i=0; i<mMeshObjects.size(); i++) { if (mMeshObjects[i]->getMesh(0)) mMeshObjects[i]->getMesh(0)->computeBounds(mMeshObjects[i]->getTransform(),bounds,mMeshObjects[i]->frame); mBounds.minExtents.setMin(bounds.minExtents); mBounds.maxExtents.setMax(bounds.maxExtents); } mCenter = mBounds.minExtents + mBounds.maxExtents; mCenter *= 0.5f; Point3F r = mBounds.maxExtents-mCenter; mRadius = mSqrt(mDot(r,r)); }
void ConvexFeature::testEdge(ConvexFeature* cf,const Point3F& s1, const Point3F& e1, CollisionList* cList, F32 tol) { F32 tolSquared = tol*tol; // Test edges against edges const Edge* edge = mEdgeList.begin(); const Edge* end = mEdgeList.end(); for (; edge != end; edge++) { if (cList->getCount() >= CollisionList::MaxCollisions) return; const Point3F& s2 = mVertexList[edge->vertex[0]]; const Point3F& e2 = mVertexList[edge->vertex[1]]; // Get the distance and closest points Point3F i1,i2; F32 distance = sqrDistanceEdges(s1, e1, s2, e2, &i1, &i2); if (distance > tolSquared) continue; distance = mSqrt(distance); // Need to figure out how to orient the collision normal. // The current test involves checking to see whether the collision // points are contained within the convex volumes, which is slow. if (inVolume(i1) || cf->inVolume(i2)) distance = -distance; // Contact normal VectorF normal = i1 - i2; if ( mIsZero( distance ) ) normal.zero(); else normal *= 1 / distance; // Return a collision Collision& info = cList->increment(); info.point = i1; info.normal = normal; info.distance = distance; info.material = material; info.object = object; } }
static void _scopeCallback( SceneObject* object, void* data ) { if( !object->isScopeable() ) return; ScopingInfo* info = reinterpret_cast< ScopingInfo* >( data ); NetConnection* connection = info->connection; F32 difSq = ( object->getWorldSphere().center - info->scopePoint ).lenSquared(); if( difSq < info->scopeDistSquared ) { // Not even close, it's in... connection->objectInScope( object ); } else { // Check a little more closely... F32 realDif = mSqrt( difSq ); if( realDif - object->getWorldSphere().radius < info->scopeDist) connection->objectInScope( object ); } }
/** * 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(); #ifdef TORQUE_NAVIGATION_ENABLED if(mDamageState == Enabled) { if(mMoveState != ModeStop) updateNavMesh(); if(!mFollowData.object.isNull()) { if(mPathData.path.isNull()) { if((getPosition() - mFollowData.object->getPosition()).len() > mFollowData.radius) followObject(mFollowData.object, mFollowData.radius); } else { if((mPathData.path->mTo - mFollowData.object->getPosition()).len() > mFollowData.radius) repath(); else if((getPosition() - mFollowData.object->getPosition()).len() < mFollowData.radius) { clearPath(); mMoveState = ModeStop; throwCallback("onTargetInRange"); } else if((getPosition() - mFollowData.object->getPosition()).len() < mAttackRadius) { throwCallback("onTargetInFiringRange"); } } } } #endif // TORQUE_NAVIGATION_ENABLED // 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; 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 = mMoveTolerance*2; 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; onStuck(); } } } } } // 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) { if (checkInLos(mAimObject.getPointer())) { if (!mTargetInLOS) { throwCallback( "onTargetEnterLOS" ); mTargetInLOS = true; } } else if (mTargetInLOS) { throwCallback( "onTargetExitLOS" ); mTargetInLOS = false; } } Pose desiredPose = mPose; if ( mSwimming ) desiredPose = SwimPose; else if ( mAiPose == 1 && canCrouch() ) desiredPose = CrouchPose; else if ( mAiPose == 2 && canProne() ) desiredPose = PronePose; else if ( mAiPose == 3 && canSprint() ) desiredPose = SprintPose; else if ( canStand() ) desiredPose = StandPose; setPose( desiredPose ); // Replicate the trigger state into the move so that // triggers can be controlled from scripts. for( U32 i = 0; i < MaxTriggerKeys; i++ ) movePtr->trigger[ i ] = getImageTriggerState( i ); #ifdef TORQUE_NAVIGATION_ENABLED if(mJump == Now) { movePtr->trigger[2] = true; mJump = None; } else if(mJump == Ledge) { // If we're not touching the ground, jump! RayInfo info; if(!getContainer()->castRay(getPosition(), getPosition() - Point3F(0, 0, 0.4f), StaticShapeObjectType, &info)) { movePtr->trigger[2] = true; mJump = None; } } #endif // TORQUE_NAVIGATION_ENABLED mLastLocation = location; return true; }
void LightFlareData::prepRender( SceneState *state, LightFlareState *flareState ) { PROFILE_SCOPE( LightFlareData_prepRender ); // No elements then nothing to render. if ( mElementCount == 0 ) return; // We need these all over the place later. const Point3F &camPos = state->getCameraPosition(); const RectI &viewport = GFX->getViewport(); const Point3F &lightPos = flareState->lightMat.getPosition(); LightInfo *lightInfo = flareState->lightInfo; bool isVectorLight = lightInfo->getType() == LightInfo::Vector; // Perform visibility testing on the light... // Project the light position from world to screen space, we need this // position later, and it tells us if it is actually onscreen. Point3F lightPosSS; bool onscreen = MathUtils::mProjectWorldToScreen( lightPos, &lightPosSS, viewport, GFX->getWorldMatrix(), gClientSceneGraph->getNonClipProjection() ); U32 visDelta = U32_MAX; U32 fadeOutTime = 20; U32 fadeInTime = 125; // Fade factor based on amount of occlusion. F32 occlusionFade = 1.0f; bool lightVisible = true; if ( !state->isReflectPass() ) { // It is onscreen, so raycast as a simple occlusion test. U32 losMask = STATIC_COLLISION_MASK | ShapeBaseObjectType | StaticTSObjectType | ItemObjectType | PlayerObjectType; GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return; bool needsRaycast = true; // NOTE: if hardware does not support HOQ it will return NULL // and we will retry every time but there is not currently a good place // for one-shot initialization of LightFlareState if ( flareState->occlusionQuery == NULL ) flareState->occlusionQuery = GFX->createOcclusionQuery(); if ( flareState->fullPixelQuery == NULL ) flareState->fullPixelQuery = GFX->createOcclusionQuery(); if ( flareState->occlusionQuery && ( ( isVectorLight && flareState->worldRadius > 0.0f ) || ( !isVectorLight && mOcclusionRadius > 0.0f ) ) ) { // Always treat light as onscreen if using HOQ // it will be faded out if offscreen anyway. onscreen = true; U32 pixels = -1; GFXOcclusionQuery::OcclusionQueryStatus status = flareState->occlusionQuery->getStatus( true, &pixels ); String str = flareState->occlusionQuery->statusToString( status ); Con::setVariable( "$Flare::OcclusionStatus", str.c_str() ); Con::setIntVariable( "$Flare::OcclusionVal", pixels ); if ( status == GFXOcclusionQuery::Occluded ) occlusionFade = 0.0f; if ( status != GFXOcclusionQuery::Unset ) needsRaycast = false; RenderPassManager *pass = state->getRenderPass(); OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>(); Point3F scale( Point3F::One ); if ( isVectorLight && flareState->worldRadius > 0.0f ) scale *= flareState->worldRadius; else scale *= mOcclusionRadius; ri->type = RenderPassManager::RIT_Occluder; ri->query = flareState->occlusionQuery; ri->query2 = flareState->fullPixelQuery; ri->position = lightPos; ri->scale = scale; ri->orientation = pass->allocUniqueXform( lightInfo->getTransform() ); ri->isSphere = true; state->getRenderPass()->addInst( ri ); if ( status == GFXOcclusionQuery::NotOccluded ) { U32 fullPixels; flareState->fullPixelQuery->getStatus( true, &fullPixels ); occlusionFade = (F32)pixels / (F32)fullPixels; // Approximation of the full pixel count rather than doing // two queries, but it is not very accurate. /* F32 dist = ( camPos - lightPos ).len(); F32 radius = scale.x; radius = ( radius / dist ) * state->getWorldToScreenScale().y; occlusionFade = (F32)pixels / (4.0f * radius * radius); occlusionFade = mClampF( occlusionFade, 0.0f, 1.0f ); */ } } Con::setFloatVariable( "$Flare::OcclusionFade", occlusionFade ); if ( needsRaycast ) { // Use a raycast to determine occlusion. bool fps = conn->isFirstPerson(); GameBase *control = conn->getControlObject(); if ( control && fps ) control->disableCollision(); RayInfo rayInfo; if ( gClientContainer.castRayRendered( camPos, lightPos, losMask, &rayInfo ) ) occlusionFade = 0.0f; if ( control && fps ) control->enableCollision(); } lightVisible = onscreen && occlusionFade > 0.0f; // To perform a fade in/out when we gain or lose visibility // we must update/store the visibility state and time. U32 currentTime = Sim::getCurrentTime(); if ( lightVisible != flareState->visible ) { flareState->visible = lightVisible; flareState->visChangedTime = currentTime; } // Save this in the state so that we have it during the reflect pass. flareState->occlusion = occlusionFade; visDelta = currentTime - flareState->visChangedTime; } else // state->isReflectPass() { occlusionFade = flareState->occlusion; lightVisible = flareState->visible; visDelta = Sim::getCurrentTime() - flareState->visChangedTime; } // We can only skip rendering if the light is not visible, and it // has elapsed the fadeOutTime. if ( !lightVisible && visDelta > fadeOutTime ) return; // In a reflection we only render the elements with zero distance. U32 elementCount = mElementCount; if ( state->isReflectPass() ) { elementCount = 0; for ( ; elementCount < mElementCount; elementCount++ ) { if ( mElementDist[elementCount] > 0.0f ) break; } } if ( elementCount == 0 ) return; // A bunch of preparatory math before generating verts... const Point2I &vpExtent = viewport.extent; Point3F viewportExtent( vpExtent.x, vpExtent.y, 1.0f ); Point2I halfViewportExtentI( viewport.extent / 2 ); Point3F halfViewportExtentF( (F32)halfViewportExtentI.x * 0.5f, (F32)halfViewportExtentI.y, 0.0f ); Point3F screenCenter( 0,0,0 ); Point3F oneOverViewportExtent( 1.0f / viewportExtent.x, 1.0f / viewportExtent.y, 1.0f ); lightPosSS.y -= viewport.point.y; lightPosSS *= oneOverViewportExtent; lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One; lightPosSS.y = -lightPosSS.y; lightPosSS.z = 0.0f; Point3F flareVec( screenCenter - lightPosSS ); F32 flareLength = flareVec.len(); flareVec.normalizeSafe(); Point3F basePoints[4]; basePoints[0] = Point3F( -0.5, 0.5, 0.0 ); basePoints[1] = Point3F( -0.5, -0.5, 0.0 ); basePoints[2] = Point3F( 0.5, -0.5, 0.0 ); basePoints[3] = Point3F( 0.5, 0.5, 0.0 ); Point3F rotatedBasePoints[4]; rotatedBasePoints[0] = basePoints[0]; rotatedBasePoints[1] = basePoints[1]; rotatedBasePoints[2] = basePoints[2]; rotatedBasePoints[3] = basePoints[3]; Point3F fvec( -1, 0, 0 ); F32 rot = mAcos( mDot( fvec, flareVec ) ); Point3F rvec( 0, -1, 0 ); rot *= mDot( rvec, flareVec ) > 0.0f ? 1.0f : -1.0f; vectorRotateZAxis( rotatedBasePoints[0], rot ); vectorRotateZAxis( rotatedBasePoints[1], rot ); vectorRotateZAxis( rotatedBasePoints[2], rot ); vectorRotateZAxis( rotatedBasePoints[3], rot ); // Here we calculate a the light source's influence on the effect's size // and brightness... // Scale based on the current light brightness compared to its normal output. F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness; // Scale based on world space distance from camera to light source. F32 lightSourceWSDistanceScale = ( isVectorLight ) ? 1.0f : getMin( 10.0f / ( lightPos - camPos ).len(), 1.5f ); // Scale based on screen space distance from screen position of light source to the screen center. F32 lightSourceSSDistanceScale = ( 1.5f - ( lightPosSS - screenCenter ).len() ) / 1.5f; // Scale based on recent visibility changes, fading in or out. F32 fadeInOutScale = 1.0f; if ( lightVisible && visDelta < fadeInTime && flareState->occlusion ) fadeInOutScale = (F32)visDelta / (F32)fadeInTime; else if ( !lightVisible && visDelta < fadeOutTime ) fadeInOutScale = 1.0f - (F32)visDelta / (F32)fadeOutTime; // This combined scale influences the size of all elements this effect renders. // Note we also add in a scale that is user specified in the Light. F32 lightSourceIntensityScale = lightSourceBrightnessScale * lightSourceWSDistanceScale * lightSourceSSDistanceScale * fadeInOutScale * flareState->scale * occlusionFade; // The baseColor which modulates the color of all elements. ColorF baseColor; if ( flareState->fullBrightness == 0.0f ) baseColor = ColorF::BLACK; else // These are the factors which affect the "alpha" of the flare effect. // Modulate more in as appropriate. baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade; // Fill in the vertex buffer... const U32 vertCount = 4 * elementCount; if ( flareState->vertBuffer.isNull() || flareState->vertBuffer->mNumVerts != vertCount ) flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic ); GFXVertexPCT *pVert = flareState->vertBuffer.lock(); const Point2I &widthHeightI = mFlareTexture.getWidthHeight(); Point2F oneOverTexSize( 1.0f / (F32)widthHeightI.x, 1.0f / (F32)widthHeightI.y ); for ( U32 i = 0; i < elementCount; i++ ) { Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : basePoints; ColorF elementColor( baseColor * mElementTint[i] ); if ( mElementUseLightColor[i] ) elementColor *= lightInfo->getColor(); Point3F elementPos; elementPos = lightPosSS + flareVec * mElementDist[i] * flareLength; elementPos.z = 0.0f; F32 maxDist = 1.5f; F32 elementDist = mSqrt( ( elementPos.x * elementPos.x ) + ( elementPos.y * elementPos.y ) ); F32 distanceScale = ( maxDist - elementDist ) / maxDist; distanceScale = 1.0f; const RectF &elementRect = mElementRect[i]; Point3F elementSize( elementRect.extent.x, elementRect.extent.y, 1.0f ); elementSize *= mElementScale[i] * distanceScale * mScale * lightSourceIntensityScale; if ( elementSize.x < 100.0f ) { F32 alphaScale = mPow( elementSize.x / 100.0f, 2 ); elementColor *= alphaScale; } elementColor.clamp(); Point2F texCoordMin, texCoordMax; texCoordMin = elementRect.point * oneOverTexSize; texCoordMax = ( elementRect.point + elementRect.extent ) * oneOverTexSize; pVert->color = elementColor; pVert->point = ( basePos[0] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[1] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[2] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMin.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[3] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMin.y ); pVert++; } flareState->vertBuffer.unlock(); // Create and submit the render instance... RenderPassManager *renderManager = state->getRenderPass(); ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>(); ri->vertBuff = &flareState->vertBuffer; ri->primBuff = &mFlarePrimBuffer; ri->translucentSort = true; ri->type = RenderPassManager::RIT_Particle; ri->sortDistSq = ( lightPos - camPos ).lenSquared(); ri->modelViewProj = &MatrixF::Identity; ri->bbModelViewProj = ri->modelViewProj; ri->count = elementCount; // Only draw the light flare in high-res mode, never off-screen mode ri->systemState = ParticleRenderInst::AwaitingHighResDraw; ri->blendStyle = ParticleRenderInst::BlendGreyscale; ri->diffuseTex = &*(mFlareTexture); ri->softnessDistance = 1.0f; // Sort by texture too. ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; renderManager->addInst( ri ); }
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); }
void ScatterSky::_initVBIB() { // Vertex Buffer... U32 vertStride = 50; U32 strideMinusOne = vertStride - 1; mVertCount = vertStride * vertStride; mPrimCount = strideMinusOne * strideMinusOne * 2; Point3F vertScale( 16.0f, 16.0f, 4.0f ); F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f ); mVB.set( GFX, mVertCount, GFXBufferTypeStatic ); ScatterSkyVertex *pVert = mVB.lock(); for ( U32 y = 0; y < vertStride; y++ ) { F32 v = ( (F32)y / (F32)strideMinusOne - 0.5f ) * 2.0f; for ( U32 x = 0; x < vertStride; x++ ) { F32 u = ( (F32)x / (F32)strideMinusOne - 0.5f ) * 2.0f; F32 sx = u; F32 sy = v; F32 sz = (mCos( mSqrt( sx*sx + sy*sy ) ) * 1.0f) + zOffset; //F32 sz = 1.0f; pVert->point.set( sx, sy, sz ); pVert->point *= vertScale; pVert->point.normalize(); pVert->point *= 200000.0f; pVert++; } } mVB.unlock(); // Primitive Buffer... mPrimBuffer.set( GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic ); U16 *pIdx = NULL; mPrimBuffer.lock(&pIdx); U32 curIdx = 0; for ( U32 y = 0; y < strideMinusOne; y++ ) { for ( U32 x = 0; x < strideMinusOne; x++ ) { U32 offset = x + y * vertStride; pIdx[curIdx] = offset; curIdx++; pIdx[curIdx] = offset + 1; curIdx++; pIdx[curIdx] = offset + vertStride + 1; curIdx++; pIdx[curIdx] = offset; curIdx++; pIdx[curIdx] = offset + vertStride + 1; curIdx++; pIdx[curIdx] = offset + vertStride; curIdx++; } } mPrimBuffer.unlock(); }
/** * 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 ForestWindMgr::updateWind( const Point3F &camPos, const TreePlacementInfo &info, F32 timeDelta ) { PROFILE_SCOPE(ForestWindMgr_updateWind); // See if we have the blended source available. ForestWindAccumulator *blendDest = NULL; { IdToWindMap::Iterator iter = mPrevSources->find( info.itemKey ); if ( iter != mPrevSources->end() ) { blendDest = iter->value; mPrevSources->erase( iter ); } } // Get some stuff we'll need for finding the emitters. F32 treeHeight = info.scale * info.dataBlock->getObjBox().len_z(); Point3F top = info.pos; top.z += treeHeight; if ( blendDest ) top += ( 1.0f / info.scale ) * blendDest->getDirection(); // Go thru the emitters to accumulate the total wind force. VectorF windForce( 0, 0, 0 ); F32 time = Sim::getCurrentTime() / 1000.0f; ForestWindEmitterList::iterator iter = mEmitters.begin(); for ( ; iter != mEmitters.end(); iter++ ) { ForestWindEmitter *emitter = (*iter); // If disabled or no wind object... skip it. if ( !emitter->isEnabled() || !emitter->getWind() ) continue; ForestWind *wind = emitter->getWind(); F32 strength = wind->getStrength(); if ( emitter->isRadialEmitter() ) { Point3F closest = MathUtils::mClosestPointOnSegment( info.pos, top, emitter->getPosition() ); Point3F dir = closest - emitter->getPosition(); F32 lenSquared = dir.lenSquared(); if ( lenSquared > emitter->getWindRadiusSquared() ) continue; dir *= 1.0f / mSqrt( lenSquared ); F32 att = lenSquared / emitter->getWindRadiusSquared(); strength *= 1.0f - att; windForce += dir * strength; } else { F32 d = mDot( info.pos, Point3F::One ); //PlaneF( Point3F::Zero, wind->getDirection() ).distToPlane( Point3F( info.pos.x, info.pos.y, 0 ) ); //F32 d = PlaneF( Point3F::Zero, wind->getDirection() ).distToPlane( Point3F( info.pos.x, info.pos.y, 0 ) ); F32 scale = 1.0f + ( mSin( d + ( time / 10.0 ) ) * 0.5f ); windForce += wind->getDirection() * strength * scale; } } // If we need a accumulator then we also need to presimulate. if ( !blendDest ) { blendDest = new ForestWindAccumulator( info ); blendDest->presimulate( windForce, 4.0f / TickSec ); } else blendDest->updateWind( windForce, timeDelta ); mSources->insertUnique( info.itemKey, blendDest ); }
//-------------------------------------------------------------------------- // from Graphics Gems I: pp 738-742 U32 mSolveQuartic_c(F32 a, F32 b, F32 c, F32 d, F32 e, F32 * x) { if(mIsZero(a)) return(mSolveCubic(b, c, d, e, x)); // normal form: x^4 + ax^3 + bx^2 + cx + d = 0 F32 A = b / a; F32 B = c / a; F32 C = d / a; F32 D = e / a; // substitue x = y - A/4 to eliminate cubic term: // x^4 + px^2 + qx + r = 0 F32 A2 = A * A; F32 A3 = A2 * A; F32 A4 = A2 * A2; F32 p = ((-3.f/8.f) * A2) + B; F32 q = ((1.f/8.f) * A3) - ((1.f/2.f) * A * B) + C; F32 r = ((-3.f/256.f) * A4) + ((1.f/16.f) * A2 * B) - ((1.f/4.f) * A * C) + D; U32 num = 0; if(mIsZero(r)) // no absolute term: y(y^3 + py + q) = 0 { num = mSolveCubic(1.f, 0.f, p, q, x); x[num++] = 0.f; } else { // solve the resolvent cubic F32 q2 = q * q; a = 1.f; b = (-1.f/2.f) * p; c = -r; d = ((1.f/2.f) * r * p) - ((1.f/8.f) * q2); mSolveCubic(a, b, c, d, x); F32 z = x[0]; // build 2 quadratic equations from the one solution F32 u = (z * z) - r; F32 v = (2.f * z) - p; if(mIsZero(u)) u = 0.f; else if(u > 0.f) u = mSqrt(u); else return(0); if(mIsZero(v)) v = 0.f; else if(v > 0.f) v = mSqrt(v); else return(0); // solve the two quadratics a = 1.f; b = v; c = z - u; num = mSolveQuadratic(a, b, c, x); a = 1.f; b = -v; c = z + u; num += mSolveQuadratic(a, b, c, x + num); } // resubstitute F32 sub = (1.f/4.f) * A; for(U32 i = 0; i < num; i++) x[i] -= sub; // sort the roots for(S32 j = 0; j < (num - 1); j++) for(S32 k = j + 1; k < num; k++) if(x[k] < x[j]) swap(x[k], x[j]); return(num); }
//-------------------------------------------------------------------------- // from Graphics Gems I: pp 738-742 U32 mSolveCubic_c(F32 a, F32 b, F32 c, F32 d, F32 * x) { if(mIsZero(a)) return(mSolveQuadratic(b, c, d, x)); // normal form: x^3 + Ax^2 + BX + C = 0 F32 A = b / a; F32 B = c / a; F32 C = d / a; // substitute x = y - A/3 to eliminate quadric term and depress // the cubic equation to (x^3 + px + q = 0) F32 A2 = A * A; F32 A3 = A2 * A; F32 p = (1.f/3.f) * (((-1.f/3.f) * A2) + B); F32 q = (1.f/2.f) * (((2.f/27.f) * A3) - ((1.f/3.f) * A * B) + C); // use Cardano's fomula to solve the depressed cubic F32 p3 = p * p * p; F32 q2 = q * q; F32 D = q2 + p3; U32 num = 0; if(mIsZero(D)) // 1 or 2 solutions { if(mIsZero(q)) // 1 triple solution { x[0] = 0.f; num = 1; } else // 1 single and 1 double { F32 u = mCbrt(-q); x[0] = 2.f * u; x[1] = -u; num = 2; } } else if(D < 0.f) // 3 solutions: casus irreducibilis { F32 phi = (1.f/3.f) * mAcos(-q / mSqrt(-p3)); F32 t = 2.f * mSqrt(-p); x[0] = t * mCos(phi); x[1] = -t * mCos(phi + (M_PI / 3.f)); x[2] = -t * mCos(phi - (M_PI / 3.f)); num = 3; } else // 1 solution { F32 sqrtD = mSqrt(D); F32 u = mCbrt(sqrtD - q); F32 v = -mCbrt(sqrtD + q); x[0] = u + v; num = 1; } // resubstitute F32 sub = (1.f/3.f) * A; for(U32 i = 0; i < num; i++) x[i] -= sub; // sort the roots for(S32 j = 0; j < (num - 1); j++) for(S32 k = j + 1; k < num; k++) if(x[k] < x[j]) swap(x[k], x[j]); return(num); }
bool SphereF::intersectsRay( const Point3F &start, const Point3F &end ) const { MatrixF worldToObj( true ); worldToObj.setPosition( center ); worldToObj.inverse(); VectorF dir = end - start; dir.normalize(); Point3F tmpStart = start; worldToObj.mulP( tmpStart ); //Compute A, B and C coefficients F32 a = mDot(dir, dir); F32 b = 2 * mDot(dir, tmpStart); F32 c = mDot(tmpStart, tmpStart) - (radius * radius); //Find discriminant F32 disc = b * b - 4 * a * c; // if discriminant is negative there are no real roots, so return // false as ray misses sphere if ( disc < 0 ) return false; // compute q as described above F32 distSqrt = mSqrt( disc ); F32 q; if ( b < 0 ) q = (-b - distSqrt)/2.0; else q = (-b + distSqrt)/2.0; // compute t0 and t1 F32 t0 = q / a; F32 t1 = c / q; // make sure t0 is smaller than t1 if ( t0 > t1 ) { // if t0 is bigger than t1 swap them around F32 temp = t0; t0 = t1; t1 = temp; } // This function doesn't use it // but t would be the interpolant // value for getting the exact // intersection point, by interpolating // start to end by t. /* F32 t = 0; TORQUE_UNUSED(t); */ // if t1 is less than zero, the object is in the ray's negative direction // and consequently the ray misses the sphere if ( t1 < 0 ) return false; // if t0 is less than zero, the intersection point is at t1 if ( t0 < 0 ) // t = t1; return true; else // else the intersection point is at t0 return true; // t = t0; }
void CloudLayer::_initBuffers() { // Vertex Buffer... Point3F vertScale( 16.0f, 16.0f, mHeight ); F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f ); mVB.set( GFX, smVertCount, GFXBufferTypeStatic ); GFXCloudVertex *pVert = mVB.lock(); if(!pVert) return; for ( U32 y = 0; y < smVertStride; y++ ) { F32 v = ( (F32)y / (F32)smStrideMinusOne - 0.5f ) * 2.0f; for ( U32 x = 0; x < smVertStride; x++ ) { F32 u = ( (F32)x / (F32)smStrideMinusOne - 0.5f ) * 2.0f; F32 sx = u; F32 sy = v; F32 sz = mCos( mSqrt( sx*sx + sy*sy ) ) + zOffset; //F32 sz = 1.0f; pVert->point.set( sx, sy, sz ); pVert->point *= vertScale; // The vert to our right. Point3F rpnt; F32 ru = ( (F32)( x + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f; F32 rv = v; rpnt.x = ru; rpnt.y = rv; rpnt.z = mCos( mSqrt( rpnt.x*rpnt.x + rpnt.y*rpnt.y ) ) + zOffset; rpnt *= vertScale; // The vert to our front. Point3F fpnt; F32 fu = u; F32 fv = ( (F32)( y + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f; fpnt.x = fu; fpnt.y = fv; fpnt.z = mCos( mSqrt( fpnt.x*fpnt.x + fpnt.y*fpnt.y ) ) + zOffset; fpnt *= vertScale; Point3F fvec = fpnt - pVert->point; fvec.normalize(); Point3F rvec = rpnt - pVert->point; rvec.normalize(); pVert->normal = mCross( fvec, rvec ); pVert->normal.normalize(); pVert->binormal = fvec; pVert->tangent = rvec; pVert->texCoord.set( u, v ); pVert++; } } mVB.unlock(); // Primitive Buffer... mPB.set( GFX, smTriangleCount * 3, smTriangleCount, GFXBufferTypeStatic ); U16 *pIdx = NULL; mPB.lock(&pIdx); U32 curIdx = 0; for ( U32 y = 0; y < smStrideMinusOne; y++ ) { for ( U32 x = 0; x < smStrideMinusOne; x++ ) { U32 offset = x + y * smVertStride; pIdx[curIdx] = offset; curIdx++; pIdx[curIdx] = offset + 1; curIdx++; pIdx[curIdx] = offset + smVertStride + 1; curIdx++; pIdx[curIdx] = offset; curIdx++; pIdx[curIdx] = offset + smVertStride + 1; curIdx++; pIdx[curIdx] = offset + smVertStride; curIdx++; } } mPB.unlock(); }
void HifiClientProcessList::clientCatchup(GameConnection * connection) { #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("client catching up... (%i)%s", mCatchup, mForceHifiReset ? " reset" : ""); #endif if (connection->getControlObject() && connection->getControlObject()->isGhostUpdated()) // if control object is reset, make sure moves are reset too connection->mMoveList->resetCatchup(); const F32 maxVel = mSqrt(gMaxHiFiVelSq) * 1.25f; F32 dt = F32(mCatchup+1) * TickSec; Point3F bigDelta(maxVel*dt,maxVel*dt,maxVel*dt); // walk through all process objects looking for ones which were updated // -- during first pass merely collect neighbors which need to be reset and updated in unison ProcessObject * pobj; if (mCatchup && !mForceHifiReset) { for (pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next) { GameBase *obj = getGameBase( pobj ); static SimpleQueryList nearby; nearby.mList.clear(); // check for nearby objects which need to be reset and then caught up // note the funky loop logic -- first time through obj is us, then // we start iterating through nearby list (to look for objects nearby // the nearby objects), which is why index starts at -1 // [objects nearby the nearby objects also get added to the nearby list] for (S32 i=-1; obj; obj = ++i<nearby.mList.size() ? (GameBase*)nearby.mList[i] : NULL) { if (obj->isGhostUpdated() && (obj->getTypeMask() & GameBaseHiFiObjectType) && !obj->isNetNearbyAdded()) { Point3F start = obj->getWorldSphere().center; Point3F end = start + 1.1f * dt * obj->getVelocity(); F32 rad = 1.5f * obj->getWorldSphere().radius; // find nearby items not updated but are hi fi, mark them as updated (and restore old loc) // check to see if added items have neighbors that need updating Box3F box; Point3F rads(rad,rad,rad); box.minExtents = box.maxExtents = start; box.minExtents -= bigDelta + rads; box.maxExtents += bigDelta + rads; // CodeReview - this is left in for MBU, but also so we can deal with the issue later. // add marble blast hack so hifi networking can see hidden objects // (since hidden is under control of hifi networking) // gForceNotHidden = true; S32 j = nearby.mList.size(); gClientContainer.findObjects(box, GameBaseHiFiObjectType, SimpleQueryList::insertionCallback, &nearby); // CodeReview - this is left in for MBU, but also so we can deal with the issue later. // disable above hack // gForceNotHidden = false; // drop anyone not heading toward us or already checked for (; j<nearby.mList.size(); j++) { GameBase * obj2 = (GameBase*)nearby.mList[j]; // if both passive, these guys don't interact with each other bool passive = obj->isHifiPassive() && obj2->isHifiPassive(); if (!obj2->isGhostUpdated() && !passive) { // compare swept spheres of obj and obj2 // if collide, reset obj2, setGhostUpdated(true), and continue Point3F end2 = obj2->getWorldSphere().center; Point3F start2 = end2 - 1.1f * dt * obj2->getVelocity(); F32 rad2 = 1.5f * obj->getWorldSphere().radius; if (MathUtils::capsuleCapsuleOverlap(start,end,rad,start2,end2,rad2)) { // better add obj2 obj2->getTickCache().beginCacheList(); TickCacheEntry * tce = obj2->getTickCache().incCacheList(); BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj2->readPacketData(connection,&bs); obj2->setGhostUpdated(true); // continue so we later add the neighbors too continue; } } // didn't pass above test...so don't add it or nearby objects nearby.mList[j] = nearby.mList.last(); nearby.mList.decrement(); j--; } obj->setNetNearbyAdded(true); } } } } // save water mark -- for game base list FrameAllocatorMarker mark; // build ordered list of client objects which need to be caught up GameBaseListNode list; for (pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next) { GameBase *obj = getGameBase( pobj ); //GameBase *obj = dynamic_cast<GameBase*>( pobj ); //GameBase *obj = (GameBase*)pobj; // Not a GameBase object so nothing to do. if ( !obj ) continue; if (obj->isGhostUpdated() && (obj->getTypeMask() & GameBaseHiFiObjectType)) { // construct process object and add it to the list // hold pointer to our object in mAfterObject GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); // begin iterating through tick list (skip first tick since that is the state we've been reset to) obj->getTickCache().beginCacheList(); obj->getTickCache().incCacheList(); } else if (mForceHifiReset && (obj->getTypeMask() & GameBaseHiFiObjectType)) { // add all hifi objects obj->getTickCache().beginCacheList(); TickCacheEntry * tce = obj->getTickCache().incCacheList(); BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj->readPacketData(connection,&bs); obj->setGhostUpdated(true); // construct process object and add it to the list // hold pointer to our object in mAfterObject GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); } else if (obj == connection->getControlObject() && obj->isGhostUpdated()) { // construct process object and add it to the list // hold pointer to our object in mAfterObject // .. but this is not a hi fi object, so don't mess with tick cache GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); } else if (obj->isGhostUpdated()) { // not hifi but we were updated, so perform net smooth now obj->computeNetSmooth(mLastDelta); } // clear out work flags obj->setNetNearbyAdded(false); obj->setGhostUpdated(false); } // run through all the moves in the move list so we can play them with our control object Move* movePtr; U32 numMoves; connection->mMoveList->resetClientMoves(); connection->mMoveList->getMoves(&movePtr, &numMoves); AssertFatal(mCatchup<=numMoves,"doh"); // tick catchup time for (U32 m=0; m<mCatchup; m++) { for (GameBaseListNode * walk = list.mNext; walk != &list; walk = walk->mNext) { // note that we get object from after object not getGameBase function // this is because we are an on the fly linked list which uses mAfterObject // rather than the linked list embedded in GameBase (clean this up?) GameBase * obj = walk->mObject; // it's possible for a non-hifi object to get in here, but // only if it is a control object...make sure we don't do any // of the tick cache stuff if we are not hifi. bool hifi = obj->getTypeMask() & GameBaseHiFiObjectType; TickCacheEntry * tce = hifi ? obj->getTickCache().incCacheList() : NULL; // tick object if (obj==connection->getControlObject()) { obj->processTick(movePtr); movePtr->checksum = obj->getPacketDataChecksum(connection); movePtr++; } else { AssertFatal(tce && hifi,"Should not get in here unless a hi fi object!!!"); obj->processTick(tce->move); } if (hifi) { BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj->writePacketData(connection,&bs); } } if (connection->getControlObject() == NULL) movePtr++; } connection->mMoveList->clearMoves(mCatchup); // Handle network error smoothing here...but only for control object GameBase * control = connection->getControlObject(); if (control && !control->isNewGhost()) { control->computeNetSmooth(mLastDelta); control->setNewGhost(false); } if (moveSync.doAction() && moveSync.moveDiff>0) { S32 moveDiff = moveSync.moveDiff; #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("client timewarping to catchup %i moves",moveDiff); #endif while (moveDiff--) advanceObjects(); moveSync.reset(); } #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("---------"); #endif // all caught up mCatchup = 0; }
void BasicClouds::_initBuffers() { // Primitive Buffer... Is shared for all Layers. mPB.set( GFX, smTriangleCount * 3, smTriangleCount, GFXBufferTypeStatic ); U16 *pIdx = NULL; mPB.lock(&pIdx); U32 curIdx = 0; for ( U32 y = 0; y < smStrideMinusOne; y++ ) { for ( U32 x = 0; x < smStrideMinusOne; x++ ) { U32 offset = x + y * smVertStride; pIdx[curIdx] = offset; curIdx++; pIdx[curIdx] = offset + 1; curIdx++; pIdx[curIdx] = offset + smVertStride + 1; curIdx++; pIdx[curIdx] = offset; curIdx++; pIdx[curIdx] = offset + smVertStride + 1; curIdx++; pIdx[curIdx] = offset + smVertStride; curIdx++; } } mPB.unlock(); // Vertex Buffer... // Each layer has their own so they can be at different heights. for ( U32 i = 0; i < TEX_COUNT; i++ ) { Point3F vertScale( 16.0f, 16.0f, mHeight[i] ); F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f ); mVB[i].set( GFX, smVertCount, GFXBufferTypeStatic ); GFXVertexPT *pVert = mVB[i].lock(); for ( U32 y = 0; y < smVertStride; y++ ) { F32 v = ( (F32)y / (F32)smStrideMinusOne - 0.5f ) * 2.0f; for ( U32 x = 0; x < smVertStride; x++ ) { F32 u = ( (F32)x / (F32)smStrideMinusOne - 0.5f ) * 2.0f; F32 sx = u; F32 sy = v; F32 sz = mCos( mSqrt( sx*sx + sy*sy ) ) + zOffset; pVert->point.set( sx, sy, sz ); pVert->point *= vertScale; pVert->texCoord.set( u, v ); pVert++; } } mVB[i].unlock(); } }
//-------------------------------------- static void m_point2F_normalize_C(F32 *p) { F32 factor = 1.0f / mSqrt(p[0]*p[0] + p[1]*p[1] ); p[0] *= factor; p[1] *= factor; }
//---------------------------------------------------------------------------- /// Core rendering method for this control. /// /// This method scans through all the current client ShapeBase objects. /// If one is named, it displays the name and damage information for it. /// /// Information is offset from the center of the object's bounding box, /// unless the object is a PlayerObjectType, in which case the eye point /// is used. /// /// @param updateRect Extents of control. void afxGuiTextHud::onRender( Point2I, const RectI &updateRect) { // Background fill first if (mShowFill) GFX->getDrawUtil()->drawRectFill(updateRect, mFillColor.toColorI()); // Must be in a TS Control GuiTSCtrl *parent = dynamic_cast<GuiTSCtrl*>(getParent()); if (!parent) return; // Must have a connection and control object GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) return; GameBase * control = dynamic_cast<GameBase*>(conn->getControlObject()); if (!control) return; // Get control camera info MatrixF cam; Point3F camPos; VectorF camDir; conn->getControlCameraTransform(0,&cam); cam.getColumn(3, &camPos); cam.getColumn(1, &camDir); F32 camFovCos; conn->getControlCameraFov(&camFovCos); camFovCos = mCos(mDegToRad(camFovCos) / 2); // Visible distance info & name fading F32 visDistance = gClientSceneGraph->getVisibleDistance(); F32 visDistanceSqr = visDistance * visDistance; F32 fadeDistance = visDistance * mDistanceFade; // Collision info. We're going to be running LOS tests and we // don't want to collide with the control object. static U32 losMask = TerrainObjectType | TerrainLikeObjectType | ShapeBaseObjectType; if (!mEnableControlObjectOcclusion) control->disableCollision(); if (mLabelAllShapes) { // This section works just like GuiShapeNameHud and renders labels for // all the shapes. // All ghosted objects are added to the server connection group, // so we can find all the shape base objects by iterating through // our current connection. for (SimSetIterator itr(conn); *itr; ++itr) { ///if ((*itr)->getTypeMask() & ShapeBaseObjectType) ///{ ShapeBase* shape = dynamic_cast<ShapeBase*>(*itr); if ( shape ) { if (shape != control && shape->getShapeName()) { // Target pos to test, if it's a player run the LOS to his eye // point, otherwise we'll grab the generic box center. Point3F shapePos; if (shape->getTypeMask() & PlayerObjectType) { MatrixF eye; // Use the render eye transform, otherwise we'll see jittering shape->getRenderEyeTransform(&eye); eye.getColumn(3, &shapePos); } else { // Use the render transform instead of the box center // otherwise it'll jitter. MatrixF srtMat = shape->getRenderTransform(); srtMat.getColumn(3, &shapePos); } VectorF shapeDir = shapePos - camPos; // Test to see if it's in range F32 shapeDist = shapeDir.lenSquared(); if (shapeDist == 0 || shapeDist > visDistanceSqr) continue; shapeDist = mSqrt(shapeDist); // Test to see if it's within our viewcone, this test doesn't // actually match the viewport very well, should consider // projection and box test. shapeDir.normalize(); F32 dot = mDot(shapeDir, camDir); if (dot < camFovCos) continue; // Test to see if it's behind something, and we want to // ignore anything it's mounted on when we run the LOS. RayInfo info; shape->disableCollision(); SceneObject *mount = shape->getObjectMount(); if (mount) mount->disableCollision(); bool los = !gClientContainer.castRay(camPos, shapePos,losMask, &info); shape->enableCollision(); if (mount) mount->enableCollision(); if (!los) continue; // Project the shape pos into screen space and calculate // the distance opacity used to fade the labels into the // distance. Point3F projPnt; shapePos.z += mVerticalOffset; if (!parent->project(shapePos, &projPnt)) continue; F32 opacity = (shapeDist < fadeDistance)? 1.0: 1.0 - (shapeDist - fadeDistance) / (visDistance - fadeDistance); // Render the shape's name drawName(Point2I((S32)projPnt.x, (S32)projPnt.y),shape->getShapeName(),opacity); } } } } // This section renders all text added by afxGuiText effects. for (S32 i = 0; i < text_items.size(); i++) { HudTextSpec* spec = &text_items[i]; if (spec->text && spec->text[0] != '\0') { VectorF shapeDir = spec->pos - camPos; // do range test F32 shapeDist = shapeDir.lenSquared(); if (shapeDist == 0 || shapeDist > visDistanceSqr) continue; shapeDist = mSqrt(shapeDist); // Test to see if it's within our viewcone, this test doesn't // actually match the viewport very well, should consider // projection and box test. shapeDir.normalize(); F32 dot = mDot(shapeDir, camDir); if (dot < camFovCos) continue; // Test to see if it's behind something, and we want to // ignore anything it's mounted on when we run the LOS. RayInfo info; if (spec->obj) spec->obj->disableCollision(); bool los = !gClientContainer.castRay(camPos, spec->pos, losMask, &info); if (spec->obj) spec->obj->enableCollision(); if (!los) continue; // Project the shape pos into screen space. Point3F projPnt; if (!parent->project(spec->pos, &projPnt)) continue; // Calculate the distance opacity used to fade text into the distance. F32 opacity = (shapeDist < fadeDistance)? 1.0 : 1.0 - (shapeDist - fadeDistance) / (25.0f); if (opacity > 0.01f) drawName(Point2I((S32)projPnt.x, (S32)projPnt.y), spec->text, opacity, &spec->text_clr); } } // Restore control object collision if (!mEnableControlObjectOcclusion) control->enableCollision(); // Border last if (mShowFrame) GFX->getDrawUtil()->drawRect(updateRect, mFrameColor.toColorI()); reset(); }