예제 #1
0
//-----------------------------------------------------------------------------
// 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 );
	}
}
예제 #2
0
//-----------------------------------------------------------------------------
// 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
}
예제 #3
0
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;
}
예제 #6
0
파일: collision.cpp 프로젝트: Ryozuki/ddnet
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;
}
예제 #7
0
int Tile::GetSolidH()
{
    for (int i=MAXMAT-1;i>=0;i--)
        if (mats[i])
            if (IsSolid(i))
                return i;
    return -1;
}
예제 #8
0
bool Tile::IsSolid()
{
    int top=GetHeight();
    if (top<0)
        return false;
    return IsSolid(top);
    //return (temp<=mymat->MeltTemp);
};
예제 #9
0
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;
}
예제 #11
0
// 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);
				}
			}
		}
	}
}
예제 #12
0
//-----------------------------------------------------------------------------
// 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;
}
예제 #14
0
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");
}
예제 #15
0
//-----------------------------------------------------------------------------
// 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 );
}
예제 #16
0
//-----------------------------------------------------------------------------
// 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
}
예제 #17
0
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 ' ';
}
예제 #18
0
//-----------------------------------------------------------------------------
// 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() );
			}
		}
	}
}
예제 #19
0
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];
	}
}
예제 #20
0
// **************************************************************************** //
__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;
}
예제 #21
0
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;
					}
				}
			}
		}
	}
}
예제 #22
0
bool Block::CheckSolidAndAdjust(float xDiff, float zDiff, float &x, float &z) const
{
	return IsSolid();
}
예제 #23
0
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;
    }
}
예제 #24
0
// 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);
        }
      }
    }
  }
}
예제 #25
0
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;
}
예제 #26
0
/*
===============
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( );
			}
		}
	}
}
예제 #27
0
//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;
	}
}
예제 #28
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
	}
}