NazaraEngine/src/Nazara/Graphics/LightManager.cpp

161 lines
3.6 KiB
C++

// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/LightManager.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzLightManager::NzLightManager() :
m_lightCount(0)
{
}
NzLightManager::NzLightManager(const NzLight** lights, unsigned int lightCount)
{
SetLights(lights, lightCount);
}
void NzLightManager::AddLights(const NzLight** lights, unsigned int lightCount)
{
m_lights.push_back(std::make_pair(lights, lightCount));
m_lightCount += lightCount;
}
void NzLightManager::Clear()
{
m_lights.clear();
m_lightCount = 0;
}
unsigned int NzLightManager::ComputeClosestLights(const NzVector3f& position, float squaredRadius, unsigned int maxResults)
{
m_results.resize(maxResults);
for (Light& light : m_results)
{
light.light = nullptr;
light.score = std::numeric_limits<unsigned int>::max(); // Nous jouons au Golf
}
for (auto it = m_lights.begin(); it != m_lights.end(); ++it)
{
const NzLight** lights = it->first;
unsigned int lightCount = it->second;
for (unsigned int j = 0; j < lightCount; ++j)
{
const NzLight* light = *lights++;
unsigned int score = std::numeric_limits<unsigned int>::max();
switch (light->GetLightType())
{
case nzLightType_Directional:
score = 0; // Lumière choisie d'office
break;
case nzLightType_Point:
{
float lightRadius = light->GetRadius();
float squaredDistance = position.SquaredDistance(light->GetPosition());
if (squaredDistance - squaredRadius <= lightRadius*lightRadius)
score = static_cast<unsigned int>(squaredDistance*1000.f);
break;
}
case nzLightType_Spot:
{
float lightRadius = light->GetRadius();
///TODO: Attribuer bonus/malus selon l'angle du spot ?
float squaredDistance = position.SquaredDistance(light->GetPosition());
if (squaredDistance - squaredRadius <= lightRadius*lightRadius)
score = static_cast<unsigned int>(squaredDistance*1000.f);
break;
}
}
if (score < m_results[0].score)
{
unsigned int k;
for (k = 1; k < maxResults; ++k)
{
if (score > m_results[k].score)
break;
}
k--; // Position de la nouvelle lumière
// Décalage
std::memcpy(&m_results[0], &m_results[1], k*sizeof(Light));
m_results[k].light = light;
m_results[k].score = score;
}
}
}
unsigned int i;
for (i = 0; i < maxResults; ++i)
{
if (m_results[i].light)
break;
}
return maxResults-i;
}
const NzLight* NzLightManager::GetLight(unsigned int index) const
{
#if NAZARA_GRAPHICS_SAFE
if (index >= m_lightCount)
{
NazaraError("Light index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_lightCount) + ')');
return nullptr;
}
#endif
for (unsigned int i = 0; i < m_lights.size(); ++i)
{
unsigned int lightCount = m_lights[i].second;
if (index > lightCount)
index -= lightCount;
else
{
const NzLight** lights = m_lights[i].first;
return lights[i];
}
}
#if NAZARA_GRAPHICS_SAFE
NazaraInternalError("Light not found");
#else
NazaraError("Light not found");
#endif
return nullptr;
}
unsigned int NzLightManager::GetLightCount() const
{
return m_lightCount;
}
const NzLight* NzLightManager::GetResult(unsigned int i) const
{
return m_results[m_results.size()-i-1].light;
}
bool NzLightManager::IsEmpty() const
{
return m_lightCount == 0;
}
void NzLightManager::SetLights(const NzLight** lights, unsigned int lightCount)
{
Clear();
AddLights(lights, lightCount);
}