AsteroidFieldChunkServer::AsteroidFieldChunkServer(int asteroidNumber, float chunkSideLength, float astMinSize, float astMaxSize, uint32_t ownerId, osg::Vec3i chunk, GameInstanceServer* ctx, PhysicsEngine* engine) :
GameObject(ownerId, ctx)
{
    m_chunkCoord = chunk;
    m_physicsEngine = engine;
    std::random_device randDevice;

    //Generate Asteroid Field
    //step 1: scatter asteroids. save to AsteroidField
    m_asteroids = std::make_shared<AsteroidField>();
    float astSizeDif = astMaxSize - astMinSize;
    float asteroidCubeMaxSidelength = astMaxSize * 2;
    float radius;
    osg::Vec3f pos;
    for (int i = 0; i < asteroidNumber; i++)
    {
        pos.set(
            randDevice()*1.0f / randDevice.max() * chunkSideLength,
            randDevice()*1.0f / randDevice.max() * chunkSideLength,
            randDevice()*1.0f / randDevice.max() * chunkSideLength);
        radius = ( ( randDevice() * 1.0f / randDevice.max() ) * ( randDevice() * 1.0f / randDevice.max() ) * astSizeDif + astMinSize ) * 0.5f;
        m_asteroids->addAsteroid(pos, radius);
    }

    //step 2: move asteroids to avoid overlappings (heuristic). save to Level::asteroidField
    int accuracy = 10; //how often d'you wanna apply heuristic?
    for (int iterations = 0; iterations < accuracy; iterations++)
    {
        std::shared_ptr<AsteroidField> previousScattering = m_asteroids;
        m_asteroids = std::make_shared<AsteroidField>();
        for (int i = 0; i < asteroidNumber; i++)
        {
            float favoredDistance = (asteroidCubeMaxSidelength - astMaxSize) / 2 + previousScattering->getAsteroid(i)->getRadius();
            float boundingBoxRadius = favoredDistance + astMaxSize / 2;
            std::list<Asteroid*> candidates = previousScattering->getAsteroidsInBlock(previousScattering->getAsteroid(i)->getPosition(), osg::Vec3f(boundingBoxRadius, boundingBoxRadius, boundingBoxRadius));
            osg::Vec3f shift(0, 0, 0);
            int numberOfCloseAsteroids = 0;
            for (std::list<Asteroid*>::iterator it = candidates.begin(); it != candidates.end(); it++) {
                if (*it != previousScattering->getAsteroid(i)) {
                    osg::Vec3f d = previousScattering->getAsteroid(i)->getPosition() - (*it)->getPosition();
                    float scale = -((d.length() - (*it)->getRadius()) - favoredDistance);
                    if (scale > 0) {
                        d.normalize();
                        shift += shift + (d * scale *0.5f); //push away from other close asteroids
                        numberOfCloseAsteroids++;
                    }
                }
            }
            m_asteroids->addAsteroid(previousScattering->getAsteroid(i)->getPosition() + shift, previousScattering->getAsteroid(i)->getRadius());
        }
    }

    // Add asteroids as collision bodies to the engine
    for (unsigned int i = 0; i < m_asteroids->getLength(); ++i)
    {
        Asteroid* currentAst = m_asteroids->getAsteroid(i);
        unsigned int id = engine->addCollisionSphere(currentAst->getPosition() + GameInstanceServer::chunkToPosition(m_chunkCoord), currentAst->getRadius());
        m_physicsIds.push_back(id);
    }
}
bool LaserPhysicsComponent::testIntersectionWithAsteroid(Laser &laser, Asteroid &asteroid)
{
    D3DXVECTOR3 currLaserPos = laser.getPosition(), lastLaserPos = laser.getLastPosition(), 
        laserDir = laser.getDirection(), asteroidPosition = asteroid.getPosition();
    float asteroidRadius = getAsteroidBoundingSphereRadius(asteroid);
    float asteroidPosToLaserEnd;

    //check if the laser ray intersects a rough bounding sphere of the asteroid
    if (!D3DXSphereBoundProbe(&asteroidPosition, asteroidRadius, &lastLaserPos, &laserDir)) {
        return false;
    }

    asteroidPosToLaserEnd = D3DXVec3LengthSq(&(currLaserPos - asteroidPosition));

    //if this is true then the laser's current position does not fall within the sphere, and a ray starting at the laser's
    //current point crosses the circle. A ray starting at the last point already crosses the sphere, so this means both
    //points are "before" the sphere, along the ray in the direction the laser is travelling.
    if (asteroidRadius * asteroidRadius < asteroidPosToLaserEnd && 
        D3DXSphereBoundProbe(&asteroidPosition, asteroidRadius, &currLaserPos, &laserDir)) {
        return false;
    }

    //it may have collided. Now check ray against mesh
    shared_ptr<GraphicsComponent> gfx = asteroid.getGraphicsComponent();
    AsteroidGraphicsComponent *asteroidGraphicsComponent = dynamic_cast<AsteroidGraphicsComponent*>(gfx.get());
    
    if (asteroidGraphicsComponent == NULL) {
        throw "Asteroid didn't have a valid asteroid graphics component!";
    }

    BOOL hit;
    float dist;
    D3DXVECTOR3 laserPosRelativeToAsteroid = lastLaserPos - asteroidPosition;
    D3DXVECTOR3 asteroidScale = asteroid.getScale();
    D3DXQUATERNION rotationQuat = asteroid.getRotationQuat();
    D3DXMATRIX rot, scale;
    D3DXMatrixScaling(&scale, 0.8f/asteroidScale.x, 0.8f/asteroidScale.y, 0.8f/asteroidScale.z);
    D3DXMatrixRotationQuaternion(&rot, &rotationQuat);
    D3DXVec3TransformCoord(&laserPosRelativeToAsteroid, &laserPosRelativeToAsteroid, &(scale * rot));

    D3DXIntersect(asteroidGraphicsComponent->getMesh(),
        &laserPosRelativeToAsteroid,
        &laserDir,
        &hit,
        NULL,
        NULL,
        NULL,
        &dist,
        NULL,
        NULL);

    float distTravelledSq = D3DXVec3LengthSq(&(currLaserPos - lastLaserPos));
    if (!hit || dist * dist > D3DXVec3LengthSq(&(currLaserPos - lastLaserPos))) {
        return false;
    }

    return true;
}