void GFXDrawUtil::drawArrow( const GFXStateBlockDesc &desc, const Point3F &start, const Point3F &end, const ColorI &color ) { GFXTransformSaver saver; // Direction and length of the arrow. VectorF dir = end - start; F32 len = dir.len(); dir.normalize(); len *= 0.2f; // Base of the cone will be a distance back from the end of the arrow // proportional to the total distance of the arrow... 0.3f looks about right. Point3F coneBase = end - dir * len * 0.3f; // Calculate the radius of the cone given that we want the cone to have // an angle of 25 degrees (just because it looks good). F32 coneLen = ( end - coneBase ).len(); F32 coneDiameter = mTan( mDegToRad(25.0f) ) * coneLen; // Draw the cone on at the arrow's tip. drawCone( desc, coneBase, end, coneDiameter / 2.0f, color ); // Get the difference in length from // the start of the cone to the end // of the cylinder so we can put the // end of the cylinder right against where // the cone starts. Point3F coneDiff = end - coneBase; // Draw the cylinder. F32 stickRadius = len * 0.025f; drawCylinder( desc, start, end - coneDiff, stickRadius, color ); }
void LineArtist::drawLine(f32 x1, f32 y1, f32 x2, f32 y2, const Color& color) { sf::Vertex vtxList[4]; VectorF begin = { x1, y1 }; VectorF end = { x2, y2 }; VectorF direction = end - begin; direction.normalize(); VectorF perpendicularVec = { -direction.y, direction.x }; VectorF offset = (m_thickness / 2.0f) * perpendicularVec; VectorF tempVtxList[4] = { { begin + offset }, { end + offset }, { end - offset }, { begin - offset } }; const sf::Color sfColor = sf::Color(color.getRgba()); for (i32 i = 0; i < 4; ++i) { vtxList[i].position = { tempVtxList[i].x, tempVtxList[i].y }; vtxList[i].color = sfColor; } m_sharedWin.getObject()->draw(vtxList, 4, sf::Quads, m_renderStates); }
void HoverVehicle::updateDustTrail( F32 dt ) { // Check to see if we're moving. VectorF velocityVector = getVelocity(); F32 velocity = velocityVector.len(); if( velocity > 2.0 ) { velocityVector.normalize(); emitDust( mDustTrailEmitter, mDataBlock->triggerTrailHeight, mDataBlock->dustTrailOffset, ( U32 )( dt * 1000 * ( velocity / mDataBlock->dustTrailFreqMod ) ), velocityVector ); } }
void TerrainCellMaterial::setTransformAndEye( const MatrixF &modelXfm, const MatrixF &viewXfm, const MatrixF &projectXfm, F32 farPlane ) { PROFILE_SCOPE( TerrainCellMaterial_SetTransformAndEye ); MatrixF modelViewProj = projectXfm * viewXfm * modelXfm; MatrixF invViewXfm( viewXfm ); invViewXfm.inverse(); Point3F eyePos = invViewXfm.getPosition(); MatrixF invModelXfm( modelXfm ); invModelXfm.inverse(); Point3F objEyePos = eyePos; invModelXfm.mulP( objEyePos ); VectorF vEye = invViewXfm.getForwardVector(); vEye.normalize( 1.0f / farPlane ); for ( U32 i=0; i < mPasses.size(); i++ ) { Pass &pass = mPasses[i]; pass.consts->setSafe( pass.modelViewProjConst, modelViewProj ); if( pass.viewToObj->isValid() || pass.worldViewOnly->isValid() ) { MatrixF worldViewOnly = viewXfm * modelXfm; pass.consts->setSafe( pass.worldViewOnly, worldViewOnly ); if( pass.viewToObj->isValid() ) { worldViewOnly.affineInverse(); pass.consts->set( pass.viewToObj, worldViewOnly); } } pass.consts->setSafe( pass.eyePosWorldConst, eyePos ); pass.consts->setSafe( pass.eyePosConst, objEyePos ); pass.consts->setSafe( pass.objTransConst, modelXfm ); pass.consts->setSafe( pass.worldToObjConst, invModelXfm ); pass.consts->setSafe( pass.vEyeConst, vEye ); } }
void ScatterSky::_conformLights() { _initCurves(); F32 val = mCurves[0].getVal( mTimeOfDay ); mNightInterpolant = 1.0f - val; VectorF lightDirection; F32 brightness; // Build the light direction from the azimuth and elevation. F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359)); F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360)); MathUtils::getVectorFromAngles(lightDirection, yaw, pitch); lightDirection.normalize(); mSunDir = -lightDirection; yaw = mDegToRad(mClampF(mMoonAzimuth,0,359)); pitch = mDegToRad(mClampF(mMoonElevation,-360,+360)); MathUtils::getVectorFromAngles( mMoonLightDir, yaw, pitch ); mMoonLightDir.normalize(); mMoonLightDir = -mMoonLightDir; brightness = mCurves[2].getVal( mTimeOfDay ); if ( mNightInterpolant >= 1.0f ) lightDirection = -mMoonLightDir; mLight->setDirection( -lightDirection ); mLight->setBrightness( brightness * mBrightness ); mLightDir = lightDirection; // Have to do interpolation // after the light direction is set // otherwise the sun color will be invalid. _interpolateColors(); mLight->setAmbient( mAmbientColor ); mLight->setColor( mSunColor ); mLight->setCastShadows( mCastShadows ); FogData fog = getSceneManager()->getFogData(); fog.color = mFogColor; getSceneManager()->setFogData( fog ); }
void GFXDrawUtil::drawCylinder( const GFXStateBlockDesc &desc, const Point3F &basePnt, const Point3F &tipPnt, F32 radius, const ColorI &color ) { VectorF uvec = tipPnt - basePnt; F32 height = uvec.len(); uvec.normalize(); MatrixF mat( true ); MathUtils::getMatrixFromUpVector( uvec, &mat ); mat.setPosition(basePnt); Point3F scale( radius, radius, height * 2 ); mat.scale(scale); GFXTransformSaver saver; mDevice->pushWorldMatrix(); mDevice->multWorld(mat); S32 numPoints = sizeof(circlePoints)/sizeof(Point2F); GFXVertexBufferHandle<GFXVertexPC> verts(mDevice, numPoints * 4 + 4, GFXBufferTypeVolatile); verts.lock(); for (S32 i=0; i<numPoints + 1; i++) { S32 imod = i % numPoints; verts[i].point = Point3F(circlePoints[imod].x,circlePoints[imod].y, 0.5f); verts[i].color = color; verts[i + numPoints + 1].point = Point3F(circlePoints[imod].x,circlePoints[imod].y, 0); verts[i + numPoints + 1].color = color; verts[2*numPoints + 2 + 2 * i].point = Point3F(circlePoints[imod].x,circlePoints[imod].y, 0.5f); verts[2*numPoints + 2 + 2 * i].color = color; verts[2*numPoints + 2 + 2 * i + 1].point = Point3F(circlePoints[imod].x,circlePoints[imod].y, 0); verts[2*numPoints + 2 + 2 * i + 1].color = color; } verts.unlock(); mDevice->setStateBlockByDesc( desc ); mDevice->setVertexBuffer( verts ); mDevice->setupGenericShaders( GFXDevice::GSModColorTexture ); mDevice->drawPrimitive( GFXTriangleFan, 0, numPoints ); mDevice->drawPrimitive( GFXTriangleFan, numPoints + 1, numPoints ); mDevice->drawPrimitive( GFXTriangleStrip, 2 * numPoints + 2, 2 * numPoints); mDevice->popWorldMatrix(); }
void Sun::_conformLights() { // Build the light direction from the azimuth and elevation. F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359)); F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360)); VectorF lightDirection; MathUtils::getVectorFromAngles(lightDirection, yaw, pitch); lightDirection.normalize(); mLight->setDirection( -lightDirection ); mLight->setBrightness( mBrightness ); // Now make sure the colors are within range. mLightColor.clamp(); mLight->setColor( mLightColor ); mLightAmbient.clamp(); mLight->setAmbient( mLightAmbient ); // Optimization... disable shadows if the ambient and // directional color are the same. bool castShadows = mLightColor != mLightAmbient && mCastShadows; mLight->setCastShadows( castShadows ); }
void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState, const MatrixF &worldViewOnly ) { MaterialParameters *matParams = matInstance->getMaterialParameters(); // Set color in the right format, set alpha to the luminance value for the color. ColorF col = lightInfo->getColor(); // TODO: The specularity control of the light // is being scaled by the overall lumiance. // // Not sure if this may be the source of our // bad specularity results maybe? // const Point3F colorToLumiance( 0.3576f, 0.7152f, 0.1192f ); F32 lumiance = mDot(*((const Point3F *)&lightInfo->getColor()), colorToLumiance ); col.alpha *= lumiance; matParams->setSafe( lightColor, col ); matParams->setSafe( lightBrightness, lightInfo->getBrightness() ); switch( lightInfo->getType() ) { case LightInfo::Vector: { VectorF lightDir = lightInfo->getDirection(); worldViewOnly.mulV(lightDir); lightDir.normalize(); matParams->setSafe( lightDirection, lightDir ); // Set small number for alpha since it represents existing specular in // the vector light. This prevents a divide by zero. ColorF ambientColor = renderState->getAmbientLightColor(); ambientColor.alpha = 0.00001f; matParams->setSafe( lightAmbient, ambientColor ); // If no alt color is specified, set it to the average of // the ambient and main color to avoid artifacts. // // TODO: Trilight disabled until we properly implement it // in the light info! // //ColorF lightAlt = lightInfo->getAltColor(); ColorF lightAlt( ColorF::BLACK ); // = lightInfo->getAltColor(); if ( lightAlt.red == 0.0f && lightAlt.green == 0.0f && lightAlt.blue == 0.0f ) lightAlt = (lightInfo->getColor() + renderState->getAmbientLightColor()) / 2.0f; ColorF trilightColor = lightAlt; matParams->setSafe(lightTrilight, trilightColor); } break; case LightInfo::Spot: { const F32 outerCone = lightInfo->getOuterConeAngle(); const F32 innerCone = getMin( lightInfo->getInnerConeAngle(), outerCone ); const F32 outerCos = mCos( mDegToRad( outerCone / 2.0f ) ); const F32 innerCos = mCos( mDegToRad( innerCone / 2.0f ) ); Point4F spotParams( outerCos, innerCos - outerCos, mCos( mDegToRad( outerCone ) ), 0.0f ); matParams->setSafe( lightSpotParams, spotParams ); VectorF lightDir = lightInfo->getDirection(); worldViewOnly.mulV(lightDir); lightDir.normalize(); matParams->setSafe( lightDirection, lightDir ); } // Fall through case LightInfo::Point: { const F32 radius = lightInfo->getRange().x; matParams->setSafe( lightRange, radius ); Point3F lightPos; worldViewOnly.mulP(lightInfo->getPosition(), &lightPos); matParams->setSafe( lightPosition, lightPos ); // Get the attenuation falloff ratio and normalize it. Point3F attenRatio = lightInfo->getExtended<ShadowMapParams>()->attenuationRatio; F32 total = attenRatio.x + attenRatio.y + attenRatio.z; if ( total > 0.0f ) attenRatio /= total; Point2F attenParams( ( 1.0f / radius ) * attenRatio.y, ( 1.0f / ( radius * radius ) ) * attenRatio.z ); matParams->setSafe( lightAttenuation, attenParams ); break; } default: AssertFatal( false, "Bad light type!" ); break; } }
void DecalRoad::_captureVerts() { PROFILE_SCOPE( DecalRoad_captureVerts ); //Con::warnf( "%s - captureVerts", isServerObject() ? "server" : "client" ); if ( isServerObject() ) { //Con::errorf( "DecalRoad::_captureVerts - called on the server side!" ); return; } if ( mEdges.size() == 0 ) return; // // Construct ClippedPolyList objects for each pair // of roadEdges. // Use them to capture Terrain verts. // SphereF sphere; RoadEdge *edge = NULL; RoadEdge *nextEdge = NULL; mTriangleCount = 0; mVertCount = 0; Vector<ClippedPolyList> clipperList; for ( U32 i = 0; i < mEdges.size() - 1; i++ ) { Box3F box; edge = &mEdges[i]; nextEdge = &mEdges[i+1]; box.minExtents = edge->p1; box.maxExtents = edge->p1; box.extend( edge->p0 ); box.extend( edge->p2 ); box.extend( nextEdge->p0 ); box.extend( nextEdge->p1 ); box.extend( nextEdge->p2 ); box.minExtents.z -= 5.0f; box.maxExtents.z += 5.0f; sphere.center = ( nextEdge->p1 + edge->p1 ) * 0.5f; sphere.radius = 100.0f; // NOTE: no idea how to calculate this ClippedPolyList clipper; clipper.mNormal.set(0.0f, 0.0f, 0.0f); VectorF n; PlaneF plane0, plane1; // Construct Back Plane n = edge->p2 - edge->p0; n.normalize(); n = mCross( n, edge->uvec ); plane0.set( edge->p0, n ); clipper.mPlaneList.push_back( plane0 ); // Construct Front Plane n = nextEdge->p2 - nextEdge->p0; n.normalize(); n = -mCross( edge->uvec, n ); plane1.set( nextEdge->p0, -n ); //clipper.mPlaneList.push_back( plane1 ); // Test if / where the planes intersect. bool discardLeft = false; bool discardRight = false; Point3F iPos; VectorF iDir; if ( plane0.intersect( plane1, iPos, iDir ) ) { Point2F iPos2F( iPos.x, iPos.y ); Point2F cPos2F( edge->p1.x, edge->p1.y ); Point2F rVec2F( edge->rvec.x, edge->rvec.y ); Point2F iVec2F = iPos2F - cPos2F; F32 iLen = iVec2F.len(); iVec2F.normalize(); if ( iLen < edge->width * 0.5f ) { F32 dot = mDot( rVec2F, iVec2F ); // The clipping planes intersected on the right side, // discard the right side clipping plane. if ( dot > 0.0f ) discardRight = true; // The clipping planes intersected on the left side, // discard the left side clipping plane. else discardLeft = true; } } // Left Plane if ( !discardLeft ) { n = ( nextEdge->p0 - edge->p0 ); n.normalize(); n = mCross( edge->uvec, n ); clipper.mPlaneList.push_back( PlaneF(edge->p0, n) ); } else { nextEdge->p0 = edge->p0; } // Right Plane if ( !discardRight ) { n = ( nextEdge->p2 - edge->p2 ); n.normalize(); n = -mCross( n, edge->uvec ); clipper.mPlaneList.push_back( PlaneF(edge->p2, -n) ); } else { nextEdge->p2 = edge->p2; } n = nextEdge->p2 - nextEdge->p0; n.normalize(); n = -mCross( edge->uvec, n ); plane1.set( nextEdge->p0, -n ); clipper.mPlaneList.push_back( plane1 ); // We have constructed the clipping planes, // now grab/clip the terrain geometry getContainer()->buildPolyList( PLC_Decal, box, TerrainObjectType, &clipper ); clipper.cullUnusedVerts(); clipper.triangulate(); clipper.generateNormals(); // If we got something, add it to the ClippedPolyList Vector if ( !clipper.isEmpty() && !( smDiscardAll && ( discardRight || discardLeft ) ) ) { clipperList.push_back( clipper ); mVertCount += clipper.mVertexList.size(); mTriangleCount += clipper.mPolyList.size(); } } // // Set the roadEdge height to be flush with terrain // This is not really necessary but makes the debug spline rendering better. // for ( U32 i = 0; i < mEdges.size() - 1; i++ ) { edge = &mEdges[i]; _getTerrainHeight( edge->p0.x, edge->p0.y, edge->p0.z ); _getTerrainHeight( edge->p2.x, edge->p2.y, edge->p2.z ); } // // Allocate the RoadBatch(s) // // If we captured no verts, then we can return here without // allocating any RoadBatches or the Vert/Index Buffers. // PreprenderImage will not allocate a render instance while // mBatches.size() is zero. U32 numClippers = clipperList.size(); if ( numClippers == 0 ) return; mBatches.clear(); // Allocate the VertexBuffer and PrimitiveBuffer mVB.set( GFX, mVertCount, GFXBufferTypeStatic ); mPB.set( GFX, mTriangleCount * 3, 0, GFXBufferTypeStatic ); // Lock the VertexBuffer GFXVertexPNTBT *vertPtr = mVB.lock(); if(!vertPtr) return; U32 vertIdx = 0; // // Fill the VertexBuffer and vertex data for the RoadBatches // Loop through the ClippedPolyList Vector // RoadBatch *batch = NULL; F32 texStart = 0.0f; F32 texEnd; for ( U32 i = 0; i < clipperList.size(); i++ ) { ClippedPolyList *clipper = &clipperList[i]; RoadEdge &edge = mEdges[i]; RoadEdge &nextEdge = mEdges[i+1]; VectorF segFvec = nextEdge.p1 - edge.p1; F32 segLen = segFvec.len(); segFvec.normalize(); F32 texLen = segLen / mTextureLength; texEnd = texStart + texLen; BiQuadToSqr quadToSquare( Point2F( edge.p0.x, edge.p0.y ), Point2F( edge.p2.x, edge.p2.y ), Point2F( nextEdge.p2.x, nextEdge.p2.y ), Point2F( nextEdge.p0.x, nextEdge.p0.y ) ); // if ( i % mSegmentsPerBatch == 0 ) { mBatches.increment(); batch = &mBatches.last(); batch->bounds.minExtents = clipper->mVertexList[0].point; batch->bounds.maxExtents = clipper->mVertexList[0].point; batch->startVert = vertIdx; } // Loop through each ClippedPolyList for ( U32 j = 0; j < clipper->mVertexList.size(); j++ ) { // Add each vert to the VertexBuffer Point3F pos = clipper->mVertexList[j].point; vertPtr[vertIdx].point = pos; vertPtr[vertIdx].normal = clipper->mNormalList[j]; Point2F uv = quadToSquare.transform( Point2F(pos.x,pos.y) ); vertPtr[vertIdx].texCoord.x = uv.x; vertPtr[vertIdx].texCoord.y = -(( texEnd - texStart ) * uv.y + texStart); vertPtr[vertIdx].tangent = mCross( segFvec, clipper->mNormalList[j] ); vertPtr[vertIdx].binormal = segFvec; vertIdx++; // Expand the RoadBatch bounds to contain this vertex batch->bounds.extend( pos ); } batch->endVert = vertIdx - 1; texStart = texEnd; } // Unlock the VertexBuffer, we are done filling it. mVB.unlock(); // Lock the PrimitiveBuffer U16 *idxBuff; mPB.lock(&idxBuff); U32 curIdx = 0; U16 vertOffset = 0; batch = NULL; S32 batchIdx = -1; // Fill the PrimitiveBuffer // Loop through each ClippedPolyList in the Vector for ( U32 i = 0; i < clipperList.size(); i++ ) { ClippedPolyList *clipper = &clipperList[i]; if ( i % mSegmentsPerBatch == 0 ) { batchIdx++; batch = &mBatches[batchIdx]; batch->startIndex = curIdx; } for ( U32 j = 0; j < clipper->mPolyList.size(); j++ ) { // Write indices for each Poly ClippedPolyList::Poly *poly = &clipper->mPolyList[j]; AssertFatal( poly->vertexCount == 3, "Got non-triangle poly!" ); idxBuff[curIdx] = clipper->mIndexList[poly->vertexStart] + vertOffset; curIdx++; idxBuff[curIdx] = clipper->mIndexList[poly->vertexStart + 1] + vertOffset; curIdx++; idxBuff[curIdx] = clipper->mIndexList[poly->vertexStart + 2] + vertOffset; curIdx++; } batch->endIndex = curIdx - 1; vertOffset += clipper->mVertexList.size(); } // Unlock the PrimitiveBuffer, we are done filling it. mPB.unlock(); // Generate the object/world bounds // Is the union of all batch bounding boxes. Box3F box; for ( U32 i = 0; i < mBatches.size(); i++ ) { const RoadBatch &batch = mBatches[i]; if ( i == 0 ) box = batch.bounds; else box.intersect( batch.bounds ); } Point3F pos = getPosition(); mWorldBox = box; resetObjectBox(); // Make sure we are in the correct bins given our world box. if( getSceneManager() != NULL ) getSceneManager()->notifyObjectDirty( this ); }
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; }
//---------------------------------------------------------------------------- /// 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(); }