bool Rect3DRay3DIntersection(const glm::vec3 & base,
                             const glm::vec3 & right,
                             const glm::vec3 & up,
                             const glm::vec3 & origin,
                             const glm::vec3 & dir,
                             float & t)
{
    auto plane = Rect3D(base, right, up).plane();
    auto valid = PlaneRay3DIntersection(plane.normal(), plane.d(),
                                      origin, dir, t);
    if (!valid)
    {
        return false;
    }

    auto point = origin + t * dir;
    point -= base;

    // Project point on right and up
    // Projection on r=pr, Projection on u=pu

    auto pr = glm::dot(point, right) / glm::dot(right, right);
    if (pr < 0.0f || pr > 1.0f)
    {
        return false;
    }

    auto pu = glm::dot(point, up) / glm::dot(up, up);
    if (pu < 0.0f || pu > 1.0f)
    {
        return false;
    }

    return true;
}
glm::vec2 Rect3DRay3DIntersectionPoint(
    const glm::vec3 & base,
    const glm::vec3 & right,
    const glm::vec3 & up,
    const glm::vec3 & origin,
    const glm::vec3 & delta,
    bool &            valid)
{
    auto  plane = Rect3D(base, right, up).plane();
    float t;
    valid = Ray3DPlaneIntersection(plane.normal(), plane.d(), origin, delta, t);
    if (!valid)
    {
        return {};
    }

    auto point = origin + t * delta;
    point -= base;

    // Project point on right and up
    // Projection on r=pr, Projection on u=pu

    auto pr = glm::dot(point, right) / glm::dot(right, right);
    if (pr < 0.0f || pr > 1.0f)
    {
        valid = false;
        return {};
    }

    auto pu = glm::dot(point, up) / glm::dot(up, up);
    if (pu < 0.0f || pu > 1.0f)
    {
        valid = false;
        return {};
    }

    valid = true;
    return {pr, pu};
}
bool Toolbar::initialise()
{
	int barPosition;

	// get height of the window
	barPosition = (-WindowManager::getInstance()->getWindowResolution().height * 0.8f) / 2;

	//====================
	// initialise Sprites
	//====================

	// Background
	m_background = new Sprite;
	if (!m_background)
	{
		return false;
	}
	m_result = m_background->initialise(Rect3D(728, 88), "ui_toolbar.dds");
	if (!m_result)
	{
		return false;
	}
	m_background->getTransform()->setY(barPosition);
	m_background->setShader("texture");

	// Toolbar Icons
	m_toolbarIcons = new InstancedSprite;
	if (!m_toolbarIcons)
	{
		return false;
	}
	m_result = m_toolbarIcons->initialise(Rect3D(64, 64), "ui_icons.dds");
	if (!m_result)
	{
		return false;
	}
	m_toolbarIcons->setShader("instancedtexture");
	m_toolbarIcons->setBlendMode(BlendMode::AlphaMasked);

	// Highlighter
	m_highlighter = new Sprite;
	if (!m_highlighter)
	{
		return false;
	}
	m_result = m_highlighter->initialise(Rect3D(92, 92), "ui_toolbar_select.dds");
	if (!m_result)
	{
		return false;
	}
	m_highlighter->setShader("texture");
	m_highlighter->setBlendMode(BlendMode::AlphaMasked);

	//==================
	// initialise Tools
	//==================

	// Add Icon Data
	m_toolData.push_back(InstanceData(D3DXVECTOR3(-320, barPosition, 1), D3DXVECTOR2(31, 17), D3DXVECTOR2(32, 21))); // Pickaxe
	m_toolData.push_back(InstanceData(D3DXVECTOR3(-240, barPosition, 1), D3DXVECTOR2(18, 11), D3DXVECTOR2(32, 21))); // Dirt
	m_toolData.push_back(InstanceData(D3DXVECTOR3(-160, barPosition, 1), D3DXVECTOR2(3, 12),  D3DXVECTOR2(32, 21))); // Sand
	m_toolData.push_back(InstanceData(D3DXVECTOR3(-80,  barPosition, 1), D3DXVECTOR2(10, 8),  D3DXVECTOR2(32, 21))); // Cobblestone
	m_toolData.push_back(InstanceData(D3DXVECTOR3(  0,  barPosition, 1), D3DXVECTOR2(7, 12),  D3DXVECTOR2(32, 21))); // Stone
	m_toolData.push_back(InstanceData(D3DXVECTOR3( 80,  barPosition, 1), D3DXVECTOR2(6, 9),   D3DXVECTOR2(32, 21))); // Wood
	m_toolData.push_back(InstanceData(D3DXVECTOR3(160,  barPosition, 1), D3DXVECTOR2(30, 1),  D3DXVECTOR2(32, 21))); // Water Bucket

	// create Instanced Sprite
	for (unsigned int i = 0; i < m_toolData.size(); i++)
	{
		m_toolbarIcons->addInstance(m_toolData[i]);
	}
	m_toolbarIcons->rebuildInstanceBuffer();

	//=================
	// initialise Vars
	//=================

	m_selectedIndex = 0;
	refresh();

	return true;
}
// Initialising
bool Ocean::initialise(string textureFilename, Rect3D waterResolution)
{
	PrimitiveFactory primitiveFactory;
	Texture* refractionTexture;
	Texture* reflectionTexture;
	
	//==============
	// create Model
	//==============

	m_model = new Model;
	if (!m_model)
	{
		return false;
	}

	// onload Model
	m_result = primitiveFactory.createPlane(waterResolution, Rect3D(1, 1), 1.0f, *m_model);
	if (!m_result)
	{
		return false;
	}

	//=================
	// create Material
	//=================

	// Retrieve refraction and reflection texture pointers
	AssetManager::getInstance()->loadTexture(&refractionTexture, "RefractionTexture");
	AssetManager::getInstance()->loadTexture(&reflectionTexture, "ReflectionTexture");

	// create material
	Material* newMaterial = new Material;
	m_result = newMaterial->setNormalTexture(textureFilename);
	if (!m_result)
	{
		return false;
	}
	newMaterial->setTexture("RefractionTexture", refractionTexture);
	newMaterial->setTexture("ReflectionTexture", reflectionTexture);

	newMaterial->setFloat("WaterHeight", waterResolution.depth);
	newMaterial->setVector2("NormalMapTiling", D3DXVECTOR2(0.01f, 0.02f));
	newMaterial->setFloat("WaterTranslation", 0.0f);
	newMaterial->setFloat("ReflectRefractScale", 0.03f);
	newMaterial->setVector4("RefractionTint", D3DXVECTOR4(0.0f, 0.8f, 1.0f, 1.0f));
	newMaterial->setFloat("WaveHeight", 1.5f);
	newMaterial->setFloat("TessellationAmount", 58.0f);

	m_model->addMaterial(newMaterial);

	//==================
	// create Transform
	//==================

	m_transform = new Transform;
	if (!m_transform)
	{
		return false;
	}

	//=================
	// initialise Vars
	//=================

	m_frame = 0.0f;
	m_waveSpeed = 0.025f;
	m_waterTranslation = 0.0f;

	m_reflective = renderMode::Off;
	m_culled = renderMode::Off;
	m_depth = renderMode::On;
	m_postprocessing = renderMode::On;
	m_blendMode = BlendMode::NoBlending;

	m_isActive = true;

	setShader("ocean");

	// Clean Up
	newMaterial = 0;
	refractionTexture = 0;
	reflectionTexture = 0;

	return true;
}