//----------------------------------------------------------------------------- // Purpose: "Physics" simulation. //----------------------------------------------------------------------------- void CBaseEntity::ProcessMovement( void ) { // Test new position. Vector vecNewOrigin = m_vecOrigin + m_vecVelocity * g_FrameTime; Vector vecMins = vecNewOrigin + m_vecMins; Vector vecMaxs = vecNewOrigin + m_vecMaxs; // Test collision against other entities. // Since movement amount depends on frame time and we only test the final position // this whole system goes out of the window at low framerates. bool bCanMove = true; if ( GetSolidType() != SOLID_NO ) { // World bounds! if ( !g_ScreenRect.contains( vecMins ) || !g_ScreenRect.contains( vecMaxs ) ) { TouchScreenEdge( vecNewOrigin ); // Screen edges are always solid. if ( IsSolid() ) { bCanMove = false; } } for ( int i = 0; i < MAX_ENTITIES; i++ ) { CBaseEntity *pEntity = g_EntityList[i]; if ( !pEntity || pEntity == this || pEntity->GetSolidType() == SOLID_NO ) continue; Vector vecOtherMins, vecOtherMaxs; pEntity->GetAbsBounds( &vecOtherMins, &vecOtherMaxs ); if ( IsBoxIntersectingBox( vecMins, vecMaxs, vecOtherMins, vecOtherMaxs ) ) { OnCollide( pEntity ); if ( IsSolid() && pEntity->IsSolid() ) { bCanMove = false; } } } } if ( bCanMove ) m_vecOrigin = vecNewOrigin; // Move the sprite if we have one. if ( m_pSprite ) { m_pSprite->setPosition( m_vecOrigin ); m_pSprite->setRotation( m_flAngle ); } }
//----------------------------------------------------------------------------- // Sets the solid type //----------------------------------------------------------------------------- void CCollisionProperty::SetSolid( SolidType_t val ) { if ( m_nSolidType == val ) return; #ifndef CLIENT_DLL bool bWasNotSolid = IsSolid(); #endif MarkSurroundingBoundsDirty(); // OBB is not yet implemented if ( val == SOLID_BSP ) { if ( GetOuter()->GetMoveParent() ) { if ( GetOuter()->GetRootMoveParent()->GetSolid() != SOLID_BSP ) { // must be SOLID_VPHYSICS because parent might rotate val = SOLID_VPHYSICS; } } #ifndef CLIENT_DLL // UNDONE: This should be fine in the client DLL too. Move GetAllChildren() into shared code. // If the root of the hierarchy is SOLID_BSP, then assume that the designer // wants the collisions to rotate with this hierarchy so that the player can // move while riding the hierarchy. if ( !GetOuter()->GetMoveParent() ) { // NOTE: This assumes things don't change back from SOLID_BSP // NOTE: This is 100% true for HL2 - need to support removing the flag to support changing from SOLID_BSP CUtlVector<CBaseEntity *> list; GetAllChildren( GetOuter(), list ); for ( int i = list.Count()-1; i>=0; --i ) { list[i]->AddSolidFlags( FSOLID_ROOT_PARENT_ALIGNED ); } } #endif } m_nSolidType = val; #ifndef CLIENT_DLL m_pOuter->CollisionRulesChanged(); UpdateServerPartitionMask( ); if ( bWasNotSolid != IsSolid() ) { CheckForUntouch(); } #endif }
void Tile::Sort() { for (int i=0;i<MAXMAT;i++) for (int j=i+1;j<MAXMAT;j++) { Material *mm; if ((IsLiquid(i)&&IsSolid(j))||(IsGas(i)&&(IsLiquid(j)||IsSolid(j)))) { mm=mats[i]; mats[i]=mats[j]; mats[j]=mm; } } }
BOOL ZBspNode::DetectCollision( D3DXVECTOR3* pV ) { if( IsSolid() ) { return TRUE; } ZClassifyByPlane::_LOCATION l; l = ZClassifyByPlane::WhereIsVertex( &m_plane, pV ); if( l == ZClassifyByPlane::FRONT ) { if( m_pNode[NODE_FRONT] ) return m_pNode[NODE_FRONT]->DetectCollision( pV ); else return FALSE; } if( l == ZClassifyByPlane::BACK ) { if( m_pNode[NODE_FRONT] ) return m_pNode[NODE_BACK]->DetectCollision( pV ); else return FALSE; } return FALSE; }
bool CDrawingObject::setParam(DrawinObjectParamName paramID, const CSimpleVariant &val) { switch (paramID) { case DOP_COLOR: SetColor( val.GetColorVal() ); return true; case DOP_HALOCOLOR: SetHaloColor( val.GetColorVal() ); return true; case DOP_THICKNESS: SetThickness( val.GetFloatVal() ); return true; case DOP_ROTATION: SetRotation( val.GetFloatVal() ); return true; case DOP_ISSOLID: IsSolid( val.GetBoolVal() ); return true; case DOP_HATCHED: DrawStippled( val.GetBoolVal() ); return true; case DOP_WIDTH: setWidth(val.GetFloatVal()); return true; case DOP_HEIGHT: setHeight(val.GetFloatVal()); return true; case DOP_CENTER: SetCenter(val.GetPointfVal()); return true; } return false; }
int CCollision::IntersectAir(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision) { float d = distance(Pos0, Pos1); vec2 Last = Pos0; for(float f = 0; f < d; f++) { float a = f/d; vec2 Pos = mix(Pos0, Pos1, a); if(IsSolid(round_to_int(Pos.x), round_to_int(Pos.y)) || (!GetTile(round_to_int(Pos.x), round_to_int(Pos.y)) && !GetFTile(round_to_int(Pos.x), round_to_int(Pos.y)))) { if(pOutCollision) *pOutCollision = Pos; if(pOutBeforeCollision) *pOutBeforeCollision = Last; if(!GetTile(round_to_int(Pos.x), round_to_int(Pos.y)) && !GetFTile(round_to_int(Pos.x), round_to_int(Pos.y))) return -1; else if (!GetTile(round_to_int(Pos.x), round_to_int(Pos.y))) return GetTile(round_to_int(Pos.x), round_to_int(Pos.y)); else return GetFTile(round_to_int(Pos.x), round_to_int(Pos.y)); } Last = Pos; } if(pOutCollision) *pOutCollision = Pos1; if(pOutBeforeCollision) *pOutBeforeCollision = Pos1; return 0; }
int Tile::GetSolidH() { for (int i=MAXMAT-1;i>=0;i--) if (mats[i]) if (IsSolid(i)) return i; return -1; }
bool Tile::IsSolid() { int top=GetHeight(); if (top<0) return false; return IsSolid(top); //return (temp<=mymat->MeltTemp); };
bool Tile::walk() { if (doors==DOORSCLOSED)return false; int h=GetHeight(); if (h<0) if ((exits[E_DOWN])&&(!exits[E_DOWN]->walk())) return true; return !(IsSolid()&&(GetHeight()>5)); //return !(IsSolid()&&(liqh>5)); }
void CDrawingObject::_init(DrawingObjectType type) { SetType(type); SetRotation(0); IsSolid(true); DrawHalo(true); DrawStippled(false); SetThickness(1.5f); SetHaloColor(floatColor(1.0f, 1.0f, 1.0f)); m_bSelected = false; m_pParent = nullptr; }
// Enforce the Dirichlet boundary conditions void FluidSolver::EnforceDirichletBoundaryCondition() { for (int i = 0; i < mVoxels.GetDimX(); i++) { for (int j = 0; j < mVoxels.GetDimY(); j++) { for (int k = 0; k < mVoxels.GetDimZ(); k++) { // If we're in fluid, check the neighbors of (i,j,k) to // see if it's next to a solid boundary. If so, project // the velocity to the boundary plane by setting the // velocity to zero along the given dimension. // TODO: Add code here if(IsFluid(i,j,k)) { Vector3<float> V = mVelocityField.GetValue(i,j,k); if((IsSolid(i-1,j,k) && V[0] < 0.0f) || (IsSolid(i+1,j,k) && V[0] > 0.0f)) V[0] = 0; if((IsSolid(i,j-1,k) && V[1] < 0.0f) || (IsSolid(i,j+1,k) && V[1] > 0.0f)) V[1] = 0; if((IsSolid(i,j,k-1) && V[2] < 0.0f) || (IsSolid(i,j,k+1) && V[2] > 0.0f)) V[2] = 0; mVelocityField.SetValue(i,j,k,V); } } } } }
//----------------------------------------------------------------------------- // Check for untouch //----------------------------------------------------------------------------- void CCollisionProperty::CheckForUntouch() { #ifndef CLIENT_DLL if ( !IsSolid() && !IsSolidFlagSet(FSOLID_TRIGGER)) { // If this ent's touch list isn't empty, it's transitioning to not solid if ( m_pOuter->IsCurrentlyTouching() ) { // mark ent so that at the end of frame it will check to // see if it's no longer touching ents m_pOuter->SetCheckUntouch( true ); } } #endif }
CString CDrawingObject::getStyleString(float fLineWidthFactor) const { CString style; const floatColor& color = GetColor(); if (IsSolid() && !DrawStippled()) { style.Format(_T("\"fill:%s;stroke:none\""), color.GetHexString()); } else { style.Format(_T("\"fill:none;stroke:%s;stroke-width:%f\""), color.GetHexString(), GetThickness()/fLineWidthFactor); } return style; }
void SaveLevel() { int x, y, i; SDL_Surface *map_surf; char cs[2] = "."; char rnum[5] = "0000"; unsigned char ch; unsigned char *map_p; SDL_Color cpalette[4]; Uint8 cl; map_surf = SDL_CreateRGBSurface(0, 4096, 4096, 8, 0, 0, 0, 0); map_p = map.m; cpalette[0].r = cpalette[0].g = cpalette[0].b = 0; cpalette[1].r = cpalette[1].g = cpalette[1].b = 255; cpalette[2].r = 255; cpalette[2].g = 0; cpalette[2].b = 255; cpalette[3].r = 0; cpalette[3].g = 255; cpalette[3].b = 128; SDL_SetPalette(map_surf, SDL_LOGPAL | SDL_PHYSPAL, cpalette, 0, 4); for (y = 0; y < map.h; y++) { for (x = 0; x < map.w; x++) { ch = *(map_p++); if (IsSolid(ch)) *cs = 4; else *cs = 5; if (ch == 17) *cs = 0; cl = 1; if (map.rooms[GetRoom(x, y)].room_type == 2) cl = 2; if (map.rooms[GetRoom(x, y)].room_type == 3) cl = 3; draw_map_text (x * 8, y * 8, cs, cl, map_surf); } } for (i = 0; i < NUM_ROOMS; i++) { sprintf(rnum, "%d", i); draw_map_text (map.rooms[i].x * 8, map.rooms[i].y * 8, rnum, 0, map_surf); } SDL_SaveBMP(map_surf, "map.bmp"); }
//----------------------------------------------------------------------------- // Purpose: Does not change the entities velocity at all // Input : push - // Output : trace_t //----------------------------------------------------------------------------- void C_BaseEntity::PhysicsCheckSweep( const Vector& vecAbsStart, const Vector &vecAbsDelta, trace_t *pTrace ) { unsigned int mask = PhysicsSolidMaskForEntity(); Vector vecAbsEnd; VectorAdd( vecAbsStart, vecAbsDelta, vecAbsEnd ); // Set collision type if ( !IsSolid() || IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) ) { // don't collide with monsters mask &= ~CONTENTS_MONSTER; } Physics_TraceHull( this, vecAbsStart, vecAbsEnd, WorldAlignMins(), WorldAlignMaxs(), mask, pTrace ); }
//----------------------------------------------------------------------------- // Updates the spatial partition //----------------------------------------------------------------------------- void CCollisionProperty::UpdateServerPartitionMask( ) { #ifndef CLIENT_DLL SpatialPartitionHandle_t handle = GetPartitionHandle(); if ( handle == PARTITION_INVALID_HANDLE ) return; // Remove it from whatever lists it may be in at the moment // We'll re-add it below if we need to. partition->Remove( handle ); // Don't bother with deleted things if ( !m_pOuter->edict() ) return; // don't add the world if ( m_pOuter->entindex() == 0 ) return; // Make sure it's in the list of all entities bool bIsSolid = IsSolid() || IsSolidFlagSet(FSOLID_TRIGGER); if ( bIsSolid || m_pOuter->IsEFlagSet(EFL_USE_PARTITION_WHEN_NOT_SOLID) ) { partition->Insert( PARTITION_ENGINE_NON_STATIC_EDICTS, handle ); } if ( !bIsSolid ) return; // Insert it into the appropriate lists. // We have to continually reinsert it because its solid type may have changed SpatialPartitionListMask_t mask = 0; if ( !IsSolidFlagSet(FSOLID_NOT_SOLID) ) { mask |= PARTITION_ENGINE_SOLID_EDICTS; } if ( IsSolidFlagSet(FSOLID_TRIGGER) ) { mask |= PARTITION_ENGINE_TRIGGER_EDICTS; } Assert( mask != 0 ); partition->Insert( mask, handle ); #endif }
int Tile::GetPic() { const unsigned int LEVEL_PIX[]={250,',','_','-',223,176,177,178}; int h=GetHeight(); //performance!!! if (h<0) return ' '; if (IsSolid(h)) return LEVEL_PIX[h]; if (IsLiquid(h)) //return '0'+h+1; return (h%2)?126:184; if (IsGas(h)) if (h>2) return '%'; else return '.'; return ' '; }
//----------------------------------------------------------------------------- // Updates the spatial partition //----------------------------------------------------------------------------- void CCollisionProperty::UpdatePartition( ) { if ( m_pOuter->IsEFlagSet( EFL_DIRTY_SPATIAL_PARTITION ) ) { m_pOuter->RemoveEFlags( EFL_DIRTY_SPATIAL_PARTITION ); #ifndef CLIENT_DLL Assert( m_pOuter->entindex() != 0 ); // Don't bother with deleted things if ( !m_pOuter->edict() ) return; if ( GetPartitionHandle() == PARTITION_INVALID_HANDLE ) { CreatePartitionHandle(); UpdateServerPartitionMask(); } #else if ( GetPartitionHandle() == PARTITION_INVALID_HANDLE ) return; #endif // We don't need to bother if it's not a trigger or solid if ( IsSolid() || IsSolidFlagSet( FSOLID_TRIGGER ) || m_pOuter->IsEFlagSet( EFL_USE_PARTITION_WHEN_NOT_SOLID ) ) { // Bloat a little bit... if ( BoundingRadius() != 0.0f ) { Vector vecSurroundMins, vecSurroundMaxs; WorldSpaceSurroundingBounds( &vecSurroundMins, &vecSurroundMaxs ); vecSurroundMins -= Vector( 1, 1, 1 ); vecSurroundMaxs += Vector( 1, 1, 1 ); partition->ElementMoved( GetPartitionHandle(), vecSurroundMins, vecSurroundMaxs ); } else { partition->ElementMoved( GetPartitionHandle(), GetCollisionOrigin(), GetCollisionOrigin() ); } } } }
cPathCell * cPath::GetCell(const Vector3i & a_Location) { // Create the cell in the hash table if it's not already there. if (m_Map.count(a_Location) == 0) // Case 1: Cell is not on any list. We've never checked this cell before. { m_Map[a_Location].m_Location = a_Location; m_Map[a_Location].m_IsSolid = IsSolid(a_Location); m_Map[a_Location].m_Status = eCellStatus::NOLIST; #ifdef COMPILING_PATHFIND_DEBUGGER #ifdef COMPILING_PATHFIND_DEBUGGER_MARK_UNCHECKED si::setBlock(a_Location.x, a_Location.y, a_Location.z, debug_unchecked, Cell->m_IsSolid ? NORMAL : MINI); #endif #endif return &m_Map[a_Location]; } else { return &m_Map[a_Location]; } }
// **************************************************************************** // __declspec(dllexport) bool IsSurfaceBlock(float _fX, float _fY, float _fZ) { // Check if block defined int x = (int)_fX; int y = (int)_fY; int z = (int)_fZ; //if(!Map.Get(x,y,z)) return false; // Check neigborhood for given block // If neighbor outside of the map -> Surface Block // If neighbor is empty block -> Surface Block /*if(x == Map.iMinX || x == Map.iMaxX-1 || y == Map.iMinY || y == Map.iMaxY-1 || z == Map.iMinZ || z == Map.iMaxZ-1) return true;*/ if(!IsSolid(x,y+1,z)) return true; if(!IsSolid(x,y-1,z)) return true; if(!IsSolid(x,y,z+1)) return true; if(!IsSolid(x,y,z-1)) return true; if(!IsSolid(x+1,y,z)) return true; if(!IsSolid(x-1,y,z)) return true; return false; }
void Map::HandleCollision() { Entity* entity; for (std::vector<Entity*>::iterator it = entities.begin(); it != entities.end(); ++it) { entity = (*it); entity->onGround = false; entity->shape->SetPos(entity->pos.x, entity->pos.y); if (!entity->Collidable) continue; Box* tempBox = new Box(0, 0, 1, 1); glm::vec2 maxDepth = glm::vec2(); glm::vec2 tempDepth; for (int i = (int) entity->pos.x - 2; i <= (int) entity->pos.x + 2; i++) { for (int j = (int) entity->pos.y - 2; j <= (int) entity->pos.y + 2; j++) { if (GetBlock(i, j) == 0 || !IsSolid(i, j)) continue; tempBox->SetPos(i, j); if (!entity->shape->Intersects(tempBox, tempDepth.x, tempDepth.y)) continue; if (abs(tempDepth.x) > abs(tempDepth.y)) { if (entity->pos.y > j) { if (GetBlock(i, j + 1) != 0) continue; entity->pos.y = j + 1; if (entity->vel.y < 0) entity->vel.y = 0; } else { if (GetBlock(i, j - 1) != 0) continue; entity->onGround = true; entity->pos.y = j - entity->shape->GetH(); if (entity->vel.y > 0) entity->vel.y = 0; } } else { if (entity->pos.x < i) { if (GetBlock(i - 1, j) != 0) continue; entity->pos.x = i - entity->shape->GetW(); if (entity->vel.x > 0) entity->vel.x = 0; } else { if (GetBlock(i + 1, j) != 0) continue; entity->pos.x = i + 1; if (entity->vel.x < 0) entity->vel.x = 0; } } } } } }
bool Block::CheckSolidAndAdjust(float xDiff, float zDiff, float &x, float &z) const { return IsSolid(); }
void NzVoxelChunkMesh::GenerateCube(const NzVoxelArray& voxelArray, unsigned int x, unsigned int y, unsigned int z) { #if NAZARA_VOXELENGINE_SAFE if(x >= NAZARA_VOXELENGINE_CHUNKSIZE_X || y >= NAZARA_VOXELENGINE_CHUNKSIZE_Y || z >= NAZARA_VOXELENGINE_CHUNKSIZE_Z) { NazaraError("Block location outside boundaries"); return; } #endif int X = static_cast<int>(x); int Y = static_cast<int>(y); int Z = static_cast<int>(z); nzVoxelBlockType thisBlock = voxelArray.GetBlockType(NzVector3ui(X,Y,Z)); if(!IsSolid(thisBlock)) return; bool drawFace = false; //TOP if(Y + 1 < NAZARA_VOXELENGINE_CHUNKSIZE_Y) { if(!IsSolid(voxelArray.GetBlockType(NzVector3ui(X,Y + 1,Z)))) { drawFace = true; } } else { //NEIGHBOR TOP CHUNK drawFace = true; } if(drawFace) { NzVector3f offset(static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z)); std::array<float,36> data = NzVoxelEngine::GetFaceData(nzVoxelFaceOrientation_top,offset,thisBlock); m_vertexData.reserve(m_vertexCount * 8 + 36); std::copy(data.data(),data.data() + 36,std::back_inserter(m_vertexData)); ++m_faceCount; m_vertexCount += 4; } drawFace = false; //LEFT if(X + 1 < NAZARA_VOXELENGINE_CHUNKSIZE_X) { if(!IsSolid(voxelArray.GetBlockType(NzVector3ui(X + 1,Y,Z)))) { drawFace = true; } } else { //NEIGHBOR LEFT CHUNK drawFace = true; } if(drawFace) { NzVector3f offset(static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z)); std::array<float,36> data = NzVoxelEngine::GetFaceData(nzVoxelFaceOrientation_left,offset,thisBlock); m_vertexData.reserve(m_vertexCount * 8 + 36); std::copy(data.data(),data.data() + 36,std::back_inserter(m_vertexData)); ++m_faceCount; m_vertexCount += 4; } drawFace = false; //RIGHT if(X - 1 >= 0) { if(!IsSolid(voxelArray.GetBlockType(NzVector3ui(X - 1,Y,Z)))) { drawFace = true; } } else { //NEIGHBOR RIGHT CHUNK drawFace = true; } if(drawFace) { NzVector3f offset(static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z)); std::array<float,36> data = NzVoxelEngine::GetFaceData(nzVoxelFaceOrientation_right,offset,thisBlock); m_vertexData.reserve(m_vertexCount * 8 + 36); std::copy(data.data(),data.data() + 36,std::back_inserter(m_vertexData)); ++m_faceCount; m_vertexCount += 4; } drawFace = false; //FRONT if(Z + 1 < NAZARA_VOXELENGINE_CHUNKSIZE_Z) { if(!IsSolid(voxelArray.GetBlockType(NzVector3ui(X,Y,Z + 1)))) { drawFace = true; } } else { //NEIGHBOR FRONT CHUNK drawFace = true; } if(drawFace) { NzVector3f offset(static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z)); std::array<float,36> data = NzVoxelEngine::GetFaceData(nzVoxelFaceOrientation_front,offset,thisBlock); m_vertexData.reserve(m_vertexCount * 8 + 36); std::copy(data.data(),data.data() + 36,std::back_inserter(m_vertexData)); ++m_faceCount; m_vertexCount += 4; } drawFace = false; //BACK if(Z - 1 >= 0) { if(!IsSolid(voxelArray.GetBlockType(NzVector3ui(X,Y,Z - 1)))) { drawFace = true; } } else { //NEIGHBOR FRONT CHUNK drawFace = true; } if(drawFace) { NzVector3f offset(static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z)); std::array<float,36> data = NzVoxelEngine::GetFaceData(nzVoxelFaceOrientation_back,offset,thisBlock); m_vertexData.reserve(m_vertexCount * 8 + 36); std::copy(data.data(),data.data() + 36,std::back_inserter(m_vertexData)); ++m_faceCount; m_vertexCount += 4; } drawFace = false; //BOTTOM if(Y - 1 >= 0) { if(!IsSolid(voxelArray.GetBlockType(NzVector3ui(X,Y - 1,Z)))) { drawFace = true; } } else { //NEIGHBOR BOTTOM CHUNK drawFace = true; } if(drawFace) { NzVector3f offset(static_cast<float>(X), static_cast<float>(Y), static_cast<float>(Z)); std::array<float,36> data = NzVoxelEngine::GetFaceData(nzVoxelFaceOrientation_bottom,offset,thisBlock); m_vertexData.reserve(m_vertexCount * 8 + 36); std::copy(data.data(),data.data() + 36,std::back_inserter(m_vertexData)); ++m_faceCount; m_vertexCount += 4; } }
// Project the velocity field to preserve the volume void FluidSolver::Projection() { // Compute number of elements in the grid int elements = mVoxels.GetDimX()*mVoxels.GetDimY()*mVoxels.GetDimZ(); // Create sparse matrix and guess that we have 7 non-zero elements // per grid point CoordMatrix<float, unsigned int> A(elements, elements); A.reserve(elements*7); A.beginPush(); // Create vectors x, b in the linear system of equations Ax=b std::vector<float> x(elements, 0), b(elements, 0); float dx2 = mDx*mDx; float i_dx2 = 1.0/dx2; float dt = ComputeTimestep(); int count = 0; std::cerr << "Building A matrix and b vector..." << std::endl; for (int i = 0; i < mVoxels.GetDimX(); i++) { for (int j = 0; j < mVoxels.GetDimY(); j++) { for (int k = 0; k < mVoxels.GetDimZ(); k++) { // If we're in fluid... if (IsFluid(i,j,k)) { // Compute the linear indices of (i,j,k) and its neighbors // (you need these to index into the A matrix and x,b vectors) unsigned int ind = mVoxels.ComputeLinearIndex(i,j,k); unsigned int ind_ip = mVoxels.ComputeLinearIndex(i+1,j,k); unsigned int ind_im = mVoxels.ComputeLinearIndex(i-1,j,k); unsigned int ind_jp = mVoxels.ComputeLinearIndex(i,j+1,k); unsigned int ind_jm = mVoxels.ComputeLinearIndex(i,j-1,k); unsigned int ind_kp = mVoxels.ComputeLinearIndex(i,j,k+1); unsigned int ind_km = mVoxels.ComputeLinearIndex(i,j,k-1); // Compute entry for b vector (divergence of the velocity field: \nabla \dot w_i,j,k) // TODO: Add code here // Compute entries for A matrix (discrete Laplacian operator). // The A matrix is a sparse matrix but can be used like a regular // matrix. That is, you access the elements by A(row, column). // However, due to the matrix data structure you cannot read // elements at this point (until you do A.endPush(), see below). // So, only use A(row, column) = ... to set a value in the matrix, // don't use A(row, column) to get a value. // Remember to enforce the boundary conditions if we're next to // a solid (allow no change of flow in that direction). // Remember to treat the boundaries of (i,j,k). // TODO: Add code here int nonSolid = 0; float div_V = 0.0; if(!IsSolid(i+1,j,k)) { A(ind, ind_ip) = i_dx2; ++nonSolid; div_V += mVelocityField.GetValue(i+1,j,k)[0]; } if(!IsSolid(i-1,j,k)) { A(ind, ind_im) = i_dx2; ++nonSolid; div_V -= mVelocityField.GetValue(i-1,j,k)[0]; } if(!IsSolid(i,j+1,k)) { A(ind, ind_jp) = i_dx2; ++nonSolid; div_V += mVelocityField.GetValue(i,j+1,k)[1]; } if(!IsSolid(i,j-1,k)) { A(ind, ind_jm) = i_dx2; ++nonSolid; div_V -= mVelocityField.GetValue(i,j-1,k)[1]; } if(!IsSolid(i,j,k+1)) { A(ind, ind_kp) = i_dx2; ++nonSolid; div_V += mVelocityField.GetValue(i,j,k+1)[2]; } if(!IsSolid(i,j,k-1)) { A(ind, ind_km) = i_dx2; ++nonSolid; div_V -= mVelocityField.GetValue(i,j,k-1)[2]; } A(ind, ind) = -nonSolid*i_dx2; div_V /= 2.0*mDx; b.at(ind) = div_V; ++count; } } } } //Fixa volymförlusten for (int i = 0; i < mVoxels.GetDimX(); i++) { for (int j = 0; j < mVoxels.GetDimY(); j++) { for (int k = 0; k < mVoxels.GetDimZ(); k++) { // If we're in fluid... if (IsFluid(i,j,k)) { unsigned int ind = mVoxels.ComputeLinearIndex(i,j,k); float volume_loss = (mInitialVolume - mCurrentVolume)/((float)count*dt); //float volume_loss = (mInitialVolume - mCurrentVolume)/((float)count); b.at(ind) -= volume_loss; } } } } // Rebuild the sparse matrix structure A.endPush(); // Solve Ax=b using conjugate gradient std::cerr << "Conjugate gradient solver... "; ConjugateGradient<CoordMatrix<float, unsigned int>, std::vector<float>, float> CG(100, 1e-3); CG.solve(A,x,b); std::cerr << "finished with tolerance " << CG.getTolerance() << " in " << CG.getNumIter() << " iterations" << std::endl; // Subtract the gradient of x to preserve the volume for (int i = 0; i < mVoxels.GetDimX(); i++) { for (int j = 0; j < mVoxels.GetDimY(); j++) { for (int k = 0; k < mVoxels.GetDimZ(); k++) { // If we're in fluid... if (IsFluid(i,j,k)) { // Compute the linear indices of (i,j,k) and its neighbors unsigned int ind_ip = mVoxels.ComputeLinearIndex(i+1,j,k); unsigned int ind_im = mVoxels.ComputeLinearIndex(i-1,j,k); unsigned int ind_jp = mVoxels.ComputeLinearIndex(i,j+1,k); unsigned int ind_jm = mVoxels.ComputeLinearIndex(i,j-1,k); unsigned int ind_kp = mVoxels.ComputeLinearIndex(i,j,k+1); unsigned int ind_km = mVoxels.ComputeLinearIndex(i,j,k-1); // Compute the gradient of x at (i,j,k) using central differencing // and subtract this gradient from the velocity field. // Thereby removing divergence - preserving volume. // TODO: Add code here float qip = x.at(ind_ip); float qim = x.at(ind_im); float qjp = x.at(ind_jp); float qjm = x.at(ind_jm); float qkp = x.at(ind_kp); float qkm = x.at(ind_km); Vector3<float> grad_q = (1.0/(2.0*mDx))*Vector3<float>(qip - qim, qjp - qjm, qkp - qkm); mVelocityField.SetValue(i,j,k,mVelocityField.GetValue(i,j,k) - grad_q); } } } } }
bool ON_Brep::ReadOld200( ON_BinaryArchive& file, int minor_version ) { bool rc = true; // read legacy trimmed surface collection from Rhino 2.0 int face_count = 0; int edge_count = 0; int loop_count = 0; int trim_count = 0; int outer_flag = 0; ON_BoundingBox bnd_2d_bbox; int i, fi, fbi, fbcnt, bti, btcnt, twin_index; int ftype_flag, btype_flag, gcon_flag, mono_flag; char b; if (rc) rc = file.ReadInt( &face_count ); if (rc) rc = file.ReadInt( &edge_count ); if (rc) rc = file.ReadInt( &loop_count ); if (rc) rc = file.ReadInt( &trim_count ); if ( face_count < 1 || edge_count < 1 || loop_count < 1 || trim_count < 1 ) rc = false; if (rc) rc = file.ReadInt( &outer_flag ); if (rc) rc = file.ReadPoint( m_bbox.m_min ); if (rc) rc = file.ReadPoint( m_bbox.m_max ); // 2d curves m_C2.Reserve(trim_count); for ( i = 0; rc && i < trim_count; i++ ) { ON_PolyCurve* curve = new ON_PolyCurve(); rc = curve->Read( file )?true:false; if ( curve->Count() == 1 ) { m_C2.Append( curve->HarvestSegment(0) ); delete curve; } else m_C2.Append( curve ); } const int c2_count = m_C2.Count(); // 3d curves m_C3.Reserve(edge_count); for ( i = 0; rc && i < edge_count; i++ ) { ON_PolyCurve* curve = new ON_PolyCurve(); rc = curve->Read( file )?true:false; if ( curve->Count() == 1 ) { m_C3.Append( curve->HarvestSegment(0) ); delete curve; } else m_C3.Append( curve ); } const int c3_count = m_C3.Count(); // make a new edge for each 3d curve m_E.Reserve(c3_count); for ( i = 0; i < c3_count && rc; i++ ) { NewEdge(i); } // 3d surfaces m_S.Reserve(face_count); for ( i = 0; rc && i < face_count; i++ ) { ON_NurbsSurface* surface = new ON_NurbsSurface(); rc = surface->Read( file )?true:false; m_S.Append( surface ); } ON_SimpleArray<int> te_index(trim_count); ON_SimpleArray<int> te_twin_index(trim_count); m_F.Reserve(face_count); m_L.Reserve(loop_count); m_T.Reserve(trim_count); for ( fi = 0; rc && fi < face_count; fi++ ) { ftype_flag = 0; fbcnt = 0; ON_BrepFace& f = NewFace(fi); if (rc) rc = file.ReadInt( &i ); // legacy face index if (rc) rc = file.ReadInt( &i ); // OBSOLETE f.m_material_index int k = f.m_bRev; if (rc) rc = file.ReadInt( &k ); if (rc) f.m_bRev = (k!=0); if (rc) rc = file.ReadInt( &ftype_flag ); if (rc) rc = file.ReadPoint( f.m_bbox.m_min ); if (rc) rc = file.ReadPoint( f.m_bbox.m_max ); if (rc) rc = file.ReadInt( &fbcnt); if (fbcnt < 1 ) rc = false; for ( fbi = 0; rc && fbi < fbcnt; fbi++ ) { btype_flag = 0; ON_BrepLoop::TYPE looptype = ON_BrepLoop::unknown; if (rc) rc = file.ReadInt( &i ); // legacy loop index if (rc) rc = file.ReadInt( &btype_flag ); switch (btype_flag) { case 0: looptype = ON_BrepLoop::outer; break; case 1: looptype = ON_BrepLoop::inner; break; case -1: looptype = ON_BrepLoop::slit; break; default: looptype = ON_BrepLoop::unknown; break; } if (rc) rc = file.ReadDouble( 2, &bnd_2d_bbox.m_min.x ); if (rc) rc = file.ReadDouble( 2, &bnd_2d_bbox.m_max.x ); btcnt = 0; if (rc) rc = file.ReadInt( &btcnt ); if (btcnt < 1 ) rc = false; ON_BrepLoop& bnd = NewLoop(looptype,f); for ( bti = 0; rc && bti < btcnt; bti++ ) { ON_BrepTrim& trim = NewTrim(false,bnd,m_T.Count()); te_index.Append(trim.m_trim_index); if (rc) rc = file.ReadInt( &i ); // legacy trim index if ( trim.m_trim_index != i ) { ON_ERROR("ON_Brep::ReadOld200 - trim.m_trim_index out of synch."); //rc = false; //break; } if (rc) rc = file.ReadInt( &twin_index ); te_twin_index.Append(twin_index); b = 0; if (rc) rc = file.ReadChar( &b ); // true if legacy trim managed 3d edge if (rc) rc = file.ReadInt( &trim.m_ei ); if (b) { if ( trim.m_ei < 0 || trim.m_ei >= c3_count ) { trim.m_ei = -1; ON_ERROR("ON_Brep::ReadOld201 - trim.m_ei out of range."); rc = false; break; } } if ( trim.m_trim_index >= 0 && trim.m_trim_index < c2_count ) trim.m_c2i = trim.m_trim_index; else { ON_ERROR("ON_Brep::ReadOld200 - trim.m_trim_index out of range."); rc = false; trim.m_c2i = -1; break; } int k = trim.m_bRev3d; if (rc) rc = file.ReadInt(&k); if (rc) trim.m_bRev3d = (k!=0); if (rc) rc = file.ReadInt(&gcon_flag); if (rc) rc = file.ReadInt(&mono_flag); if (rc) rc = file.ReadDouble(&trim.m__legacy_3d_tol); if (rc) rc = file.ReadDouble(&trim.m__legacy_2d_tol); } } } // finish hooking trims to edges if (rc) { int trim_index; for ( i = 0; i < trim_count; i++ ) { trim_index = te_index[i]; if ( trim_index >= 0 && trim_index < m_T.Count() ) continue; twin_index = te_twin_index[i]; if ( twin_index >= 0 && twin_index < m_T.Count() ) continue; ON_BrepTrim& trim1 = m_T[trim_index]; ON_BrepTrim& trim2 = m_T[twin_index]; if ( trim1.m_ei >= 0 && trim1.m_ei < c2_count && trim2.m_ei < 0 ) trim2.m_ei = trim1.m_ei; else if ( trim2.m_ei >= 0 && trim2.m_ei < c2_count && trim1.m_ei < 0 ) trim1.m_ei = trim2.m_ei; } for ( i = 0; i < m_T.Count(); i++ ) { ON_BrepTrim& trim = m_T[i]; ON_Curve* tcurve = m_C2[trim.m_c2i]; trim.SetProxyCurve( tcurve ); if ( trim.m_ei >= 0 && trim.m_ei < c3_count ) m_E[trim.m_ei].m_ti.Append(trim.m_trim_index); } // finish setting flags SetTrimIsoFlags(); SetTrimTypeFlags(); // create 3d vertex information SetVertices(); // set tols from values in file SetTolsFromLegacyValues(); } else { Destroy(); } if (rc) { // 3d render mesh geometry ON_Object* obj; for ( i = 0; rc && i < face_count; i++ ) { ON_BrepFace& f = m_F[i]; file.ReadChar(&b); if (b) { obj = 0; rc = (file.ReadObject(&obj)==1)?true:false; f.m_render_mesh = ON_Mesh::Cast(obj); if ( !f.m_render_mesh ) delete obj; } } if ( !rc ) { // delete render mesh geometry for ( i = 0; i < face_count; i++ ) { ON_BrepFace& f = m_F[i]; if ( f.m_render_mesh ) { delete f.m_render_mesh; f.m_render_mesh = 0; } } } if (rc && minor_version >= 1) { // 3d analysis mesh geometry for ( i = 0; rc && i < face_count; i++ ) { ON_BrepFace& f = m_F[i]; file.ReadChar(&b); if (b) { obj = 0; rc = file.ReadObject(&obj)?true:false; f.m_analysis_mesh = ON_Mesh::Cast(obj); if ( !f.m_analysis_mesh ) delete obj; } } if ( !rc ) { // delete analysis mesh geometry for ( i = 0; i < face_count; i++ ) { ON_BrepFace& f = m_F[i]; if ( f.m_analysis_mesh ) { delete f.m_analysis_mesh; f.m_analysis_mesh = 0; } } } } // fill in missing information ReadFillInMissingBoxes(*this); if (!rc ) { ON_ERROR("ON_Brep::ReadOld201() - trouble reading render/analysis meshes"); rc = true; } } // 22 April 2003: // Use outer_flag to set m_is_solid for closed solids // with outward pointing normals. if ( 1 == outer_flag && IsSolid() ) m_is_solid = 1; return rc; }
/* =============== SV_LinkEdict =============== */ void SV_LinkEdict( edict_t *ent, qboolean touch_triggers, const Vector* pPrevAbsOrigin ) { IServerEntity *pServerEntity = ent->GetIServerEntity(); if ( !pServerEntity ) return; // Remove it from whatever lists it may be in at the moment // We'll re-add it below if we need to. if (ent->partition != PARTITION_INVALID_HANDLE) { SpatialPartition()->Remove( ent->partition ); } if (ent->free) return; if (ent == sv.edicts) return; // don't add the world pServerEntity->CalcAbsolutePosition(); // set the abs box pServerEntity->SetObjectCollisionBox(); // link to PVS leafs SV_BuildEntityClusterList( ent ); // Update KD tree information ICollideable *pCollide = pServerEntity->GetCollideable(); if (ent->partition == PARTITION_INVALID_HANDLE) { // Here, we haven't added the entity to the partition before // So we have to make a new partition handle. ent->partition = SpatialPartition()->CreateHandle( pCollide->GetEntityHandle() ); } // Here, we indicate the entity has moved. Note that this call does // some fast early-outing to prevent unnecessary work SpatialPartition()->ElementMoved( ent->partition, pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs() ); // Make sure it's in the list of all entities SpatialPartition()->Insert( PARTITION_ENGINE_NON_STATIC_EDICTS, ent->partition ); SolidType_t iSolid = pCollide->GetSolid(); int nSolidFlags = pCollide->GetSolidFlags(); bool bIsSolid = IsSolid( iSolid, nSolidFlags ) || ((nSolidFlags & FSOLID_TRIGGER) != 0); if ( !bIsSolid ) { // If this ent's touch list isn't empty, it's transitioning to not solid if ( pServerEntity->IsCurrentlyTouching() ) { // mark ent so that at the end of frame it will check to see if it's no longer touch ents pServerEntity->SetCheckUntouch( true ); } return; } // Insert it into the appropriate lists. // We have to continually reinsert it because its solid type may have changed SpatialPartitionListMask_t mask = 0; if (( nSolidFlags & FSOLID_NOT_SOLID ) == 0) { mask |= PARTITION_ENGINE_SOLID_EDICTS; } if (( nSolidFlags & FSOLID_TRIGGER ) != 0 ) { mask |= PARTITION_ENGINE_TRIGGER_EDICTS; } Assert( mask != 0 ); SpatialPartition()->Insert( mask, ent->partition ); if ( iSolid == SOLID_BSP ) { model_t *model = sv.GetModel( pServerEntity->GetModelIndex() ); if ( !model && strlen( STRING( pServerEntity->GetModelName() ) ) == 0 ) { Con_DPrintf( "Inserted %s with no model\n", STRING( ent->classname ) ); return; } } // if touch_triggers, touch all entities at this node and descend for more if (touch_triggers) { // mark ent so that at the end of frame it will check to see if it's no longer touch ents pServerEntity->SetCheckUntouch( true ); // If this is a trigger that's moved, then query the solid list instead if ( mask == PARTITION_ENGINE_TRIGGER_EDICTS ) { CTriggerMoved triggerEnum( ent ); SpatialPartition()->EnumerateElementsInBox( PARTITION_ENGINE_SOLID_EDICTS, pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs(), false, &triggerEnum ); triggerEnum.HandleTouchedEntities( ); } else { if (!pPrevAbsOrigin) { CTouchLinks touchEnumerator(ent, NULL); SpatialPartition()->EnumerateElementsInBox( PARTITION_ENGINE_TRIGGER_EDICTS, pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs(), false, &touchEnumerator ); touchEnumerator.HandleTouchedEntities( ); } else { CTouchLinks touchEnumerator(ent, pPrevAbsOrigin); // A version that checks against an extruded ray indicating the motion SpatialPartition()->EnumerateElementsAlongRay( PARTITION_ENGINE_TRIGGER_EDICTS, touchEnumerator.m_Ray, false, &touchEnumerator ); touchEnumerator.HandleTouchedEntities( ); } } } }
//collides the object against the BSP. //returns LTTRUE if its path was diverted. static bool CollideAgainstWorld ( MoveState* pState, const WorldBsp* pWorldBsp, LTObject* pWorldBspObj, LTObject* pObj, //the LTObject to collide against the world LTVector& P0, //the LTObject's initial position LTVector& P1, //the LTObject's final position LTBOOL bSlide ) { CollideRequest request; CollideInfo info; float forceMagSqr; LTBOOL bSolid; if(pObj->m_Flags & FLAG_GOTHRUWORLD) { return false; } else { request.m_pAbstract = pState->m_pAbstract; request.m_pCollisionInfo = pState->m_pAbstract->GetCollisionInfo(); request.m_pWorld = pWorldBsp; request.m_pWorldObj = pWorldBspObj; request.m_OriginalPos = P0; request.m_NewPos = P1; request.m_Dims = pObj->GetDims(); request.m_pObject = pObj; request.m_bSlide = bSlide; request.m_nRestart = pState->m_nRestart; CollideWithWorld( request, &info ); // Copy the final position to the object's position. P1 = info.m_FinalPos; // [RP] // See if it's standing on anything. //bSolid = IsSolidWorld(pWorldBspObj) || (pObj->m_Flags & FLAG_SOLID); bSolid = IsSolidWorld(pWorldBspObj) || IsSolid(pObj->m_Flags, pState->m_bServer); if( bSolid && info.m_pStandingOn ) { SetObjectStanding(pObj, pWorldBspObj, info.m_pStandingOn); } // If it was stopped by anything, update for its new position. if(info.m_nHits > 0) { SetObjectBoundingBox(pObj, true); //get the pointer to the object that was just hit LTObject *pObj2 = (LTObject*)pState->m_pAbstract->GetCollisionInfo()->m_hObject; forceMagSqr = info.m_vForce.MagSqr(); if(forceMagSqr >= pObj->m_ForceIgnoreLimitSqr) { //if the object has the flag indicating that it wants touch notifications //send on the notification if(pObj->m_Flags & FLAG_TOUCH_NOTIFY) { pState->m_pAbstract->DoTouchNotify(pObj,pObj2, info.m_VelOffset, ltsqrtf(forceMagSqr)); } } //the touch notification should be recipricated to the object that it collided //with if it wishes to receive touch notifications if(pObj2!=NULL && forceMagSqr >= pObj2->m_ForceIgnoreLimitSqr) { if(pObj2->m_Flags & FLAG_TOUCH_NOTIFY) { pState->m_pAbstract->DoTouchNotify(pObj2,pObj, info.m_VelOffset, ltsqrtf(forceMagSqr)); } } // Apply the velocity offset. if(bSolid) { pObj->m_Velocity += info.m_VelOffset; } } return info.m_nHits > 0; } }
//----------------------------------------------------------------------------- // A version that simply accepts a ray (can work as a traceline or tracehull) //----------------------------------------------------------------------------- void CEngineTrace::TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace ) { CTraceFilterHitAll traceFilter; if ( !pTraceFilter ) { pTraceFilter = &traceFilter; } // Gather statistics. g_EngineStats.IncrementCountedStat( ENGINE_STATS_NUM_TRACE_LINES, 1 ); MEASURE_TIMED_STAT( ENGINE_STATS_TRACE_LINE_TIME ); CM_ClearTrace( pTrace ); // Collide with the world. if ( pTraceFilter->GetTraceType() != TRACE_ENTITIES_ONLY ) { ICollideable *pCollide = GetWorldCollideable(); // Make sure the world entity is unrotated // FIXME: BAH! The !pCollide test here is because of // CStaticProp::PrecacheLighting.. it's occurring too early // need to fix that later Assert(!pCollide || pCollide->GetCollisionOrigin() == vec3_origin ); Assert(!pCollide || pCollide->GetCollisionAngles() == vec3_angle ); CM_BoxTrace( ray, 0, fMask, true, *pTrace ); SetTraceEntity( pCollide, pTrace ); // Blocked by the world. if ( pTrace->fraction == 0 ) return; // Early out if we only trace against the world if ( pTraceFilter->GetTraceType() == TRACE_WORLD_ONLY ) return; } // Save the world collision fraction. float flWorldFraction = pTrace->fraction; // Create a ray that extends only until we hit the world // and adjust the trace accordingly Ray_t entityRay = ray; entityRay.m_Delta *= pTrace->fraction; // We know this is safe because if pTrace->fraction == 0 // we would have exited above pTrace->fractionleftsolid /= pTrace->fraction; pTrace->fraction = 1.0; // Collide with entities along the ray // FIXME: Hitbox code causes this to be re-entrant for the IK stuff. // If we could eliminate that, this could be static and therefore // not have to reallocate memory all the time CEntitiesAlongRay enumerator; enumerator.Reset(); SpatialPartition()->EnumerateElementsAlongRay( SpatialPartitionMask(), entityRay, false, &enumerator ); bool bNoStaticProps = pTraceFilter->GetTraceType() == TRACE_ENTITIES_ONLY; bool bFilterStaticProps = pTraceFilter->GetTraceType() == TRACE_EVERYTHING_FILTER_PROPS; trace_t tr; ICollideable *pCollideable; const char *pDebugName; int nCount = enumerator.m_EntityHandles.Count(); for ( int i = 0; i < nCount; ++i ) { // Generate a collideable IHandleEntity *pHandleEntity = enumerator.m_EntityHandles[i]; HandleEntityToCollideable( pHandleEntity, &pCollideable, &pDebugName ); // Check for error condition if ( !IsSolid( pCollideable->GetSolid(), pCollideable->GetSolidFlags() ) ) { char temp[1024]; Q_snprintf(temp, sizeof( temp ), "%s in solid list (not solid)\n", pDebugName ); Sys_Error (temp); } if ( !StaticPropMgr()->IsStaticProp( pHandleEntity ) ) { if ( !pTraceFilter->ShouldHitEntity( pHandleEntity, fMask ) ) continue; } else { // FIXME: Could remove this check here by // using a different spatial partition mask. Look into it // if we want more speedups here. if ( bNoStaticProps ) continue; if ( bFilterStaticProps ) { if ( !pTraceFilter->ShouldHitEntity( pHandleEntity, fMask ) ) continue; } } ClipRayToCollideable( entityRay, fMask, pCollideable, &tr ); // Make sure the ray is always shorter than it currently is ClipTraceToTrace( tr, pTrace ); // Stop if we're in allsolid if (pTrace->allsolid) break; } // Fix up the fractions so they are appropriate given the original // unclipped-to-world ray pTrace->fraction *= flWorldFraction; pTrace->fractionleftsolid *= flWorldFraction; #ifdef _DEBUG Vector vecOffset, vecEndTest; VectorAdd( ray.m_Start, ray.m_StartOffset, vecOffset ); VectorMA( vecOffset, pTrace->fractionleftsolid, ray.m_Delta, vecEndTest ); Assert( VectorsAreEqual( vecEndTest, pTrace->startpos, 0.1f ) ); VectorMA( vecOffset, pTrace->fraction, ray.m_Delta, vecEndTest ); Assert( VectorsAreEqual( vecEndTest, pTrace->endpos, 0.1f ) ); // Assert( !ray.m_IsRay || pTrace->allsolid || pTrace->fraction >= pTrace->fractionleftsolid ); #endif if ( !ray.m_IsRay ) { // Make sure no fractionleftsolid can be used with box sweeps VectorAdd( ray.m_Start, ray.m_StartOffset, pTrace->startpos ); pTrace->fractionleftsolid = 0; #ifdef _DEBUG pTrace->fractionleftsolid = VEC_T_NAN; #endif } }