// Copyright (c) 2008-2012 Sundog Software, LLC. All rights reserved worldwide.

#include "CloudsDrawable.h"
#include "SilverLining.h"
#include "AtmosphereReference.h"

#include <assert.h>

using namespace SilverLining;

CloudsDrawable::CloudsDrawable()
        : osg::Drawable()
{
//    setDataVariance(osg::Object::DYNAMIC);
    setUseVertexBufferObjects(false);
    setUseDisplayList(false);
}

CloudsDrawable::CloudsDrawable(osgViewer::Viewer* view)
        : osg::Drawable()
        , _view(view)
{
//    setDataVariance(osg::Object::DYNAMIC);
    setUseVertexBufferObjects(false);
    setUseDisplayList(false);
}

bool CloudsDrawable::adjustNearFar( const osg::Vec3 & camPos, double & minDist, double & maxDist )
{
    if ( _view || !_view->getCamera() )
        return false;

    AtmosphereReference *ar = dynamic_cast<AtmosphereReference *>( _view->getCamera()->getUserData() );
    if ( ar && ar->atmosphere )
    {
        double dToOrigin = camPos.length();
        osg::Vec3d up = camPos;
        up.normalize();
        osg::Vec3d down = up * -1.0;

        OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _mutex );

        SilverLining::Atmosphere * atmosphere = ar->atmosphere;            

        SL_VECTOR(SilverLining::ObjectHandle) &objects = atmosphere->GetObjects();
        SL_VECTOR(SilverLining::ObjectHandle)::iterator it;
        for (it = objects.begin(); it != objects.end(); it++)
        {
            float ox, oy, oz;
            atmosphere->GetObjectPosition(*it, ox, oy, oz);
            osg::Vec3d oPos(ox, oy, oz);
            double oHeight = oPos.length();
            osg::Vec3d testVec;
            if (dToOrigin > oHeight)
            {
                testVec = camPos + down * 100.0; // 100 for floating point precision problems
            }
            else
            {
                testVec = camPos + up * 100.0;
            }
            
            const double farFarAway = 500000;

            double dist = atmosphere->GetObjectDistance(*it, testVec.x(), testVec.y(), testVec.z(),
                (float)camPos.x(), (float)camPos.y(), (float)camPos.z());

            if (dist < farFarAway) // an intersection was found
            {
                if (dist < minDist) minDist = dist;
                if (dist > maxDist) maxDist = dist;
            }
        }
        
        return true;
    }
    return false;
}

void CloudsDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
{
	AtmosphereReference *ar = dynamic_cast<AtmosphereReference *>(renderInfo.getCurrentCamera()->getUserData());
	SilverLining::Atmosphere *atmosphere = 0;
	if (ar) atmosphere = ar->atmosphere;

	renderInfo.getState()->disableAllVertexArrays();

    if (atmosphere)
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _mutex );
        atmosphere->DrawObjects(true);
    }

	renderInfo.getState()->dirtyAllVertexArrays();
}
