Merge remote-tracking branch 'origin/master' into Resource-Update

Conflicts:
	include/Nazara/Audio/Music.hpp
	include/Nazara/Audio/SoundBuffer.hpp
	include/Nazara/Core/Resource.hpp
	include/Nazara/Core/ResourceListener.hpp
	include/Nazara/Graphics/Material.hpp
	include/Nazara/Renderer/Context.hpp
	include/Nazara/Renderer/RenderBuffer.hpp
	include/Nazara/Renderer/Shader.hpp
	include/Nazara/Renderer/Texture.hpp
	include/Nazara/Renderer/UberShader.hpp
	include/Nazara/Utility/Animation.hpp
	include/Nazara/Utility/Buffer.hpp
	include/Nazara/Utility/Image.hpp
	include/Nazara/Utility/IndexBuffer.hpp
	include/Nazara/Utility/Mesh.hpp
	include/Nazara/Utility/SkeletalMesh.hpp
	include/Nazara/Utility/Skeleton.hpp
	include/Nazara/Utility/StaticMesh.hpp
	include/Nazara/Utility/SubMesh.hpp
	include/Nazara/Utility/VertexBuffer.hpp
	include/Nazara/Utility/VertexDeclaration.hpp
	src/Nazara/Core/Resource.cpp
	src/Nazara/Core/ResourceListener.cpp
	src/Nazara/Graphics/DeferredRenderQueue.cpp
	src/Nazara/Graphics/ForwardRenderQueue.cpp
	src/Nazara/Graphics/SkinningManager.cpp
	src/Nazara/Renderer/RenderTexture.cpp
	src/Nazara/Renderer/Renderer.cpp
	src/Nazara/Utility/Mesh.cpp

Former-commit-id: 99b5ad26a19fe9c9f8118da7b5920bffe89f60f8
This commit is contained in:
Lynix
2015-01-25 19:29:55 +01:00
579 changed files with 11958 additions and 3706 deletions

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -61,7 +61,7 @@ namespace
sf_count_t Tell(void* user_data)
{
NzInputStream* stream = reinterpret_cast<NzInputStream*>(user_data);
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
return stream->GetCursorPos();
}
@@ -106,13 +106,21 @@ namespace
bool Open(const NzString& filePath, bool forceMono)
{
if (!m_file.Open(filePath, NzFile::ReadOnly))
std::unique_ptr<NzFile> file(new NzFile);
if (!file->Open(filePath, NzFile::ReadOnly))
{
NazaraError("Failed to open stream from file: " + NzError::GetLastError());
return false;
}
m_ownedStream = std::move(file);
return Open(m_file, forceMono);
return Open(*m_ownedStream, forceMono);
}
bool Open(const void* data, std::size_t size, bool forceMono)
{
m_ownedStream.reset(new NzMemoryStream(data, size));
return Open(*m_ownedStream, forceMono);
}
bool Open(NzInputStream& stream, bool forceMono)
@@ -185,8 +193,8 @@ namespace
private:
std::vector<nzInt16> m_mixBuffer;
std::unique_ptr<NzInputStream> m_ownedStream;
nzAudioFormat m_format;
NzFile m_file;
SNDFILE* m_handle;
bool m_mixToMono;
unsigned int m_duration;
@@ -243,6 +251,28 @@ namespace
return true;
}
bool LoadMusicMemory(NzMusic* music, const void* data, std::size_t size, const NzMusicParams& parameters)
{
NazaraUnused(parameters);
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
if (!musicStream->Open(data, size, parameters.forceMono))
{
NazaraError("Failed to open music stream");
return false;
}
if (!music->Create(musicStream.get()))
{
NazaraError("Failed to create music");
return false;
}
musicStream.release();
return true;
}
bool LoadMusicStream(NzMusic* music, NzInputStream& stream, const NzMusicParams& parameters)
{
NazaraUnused(parameters);
@@ -342,12 +372,12 @@ namespace
void NzLoaders_sndfile_Register()
{
NzMusicLoader::RegisterLoader(IsSupported, CheckMusic, LoadMusicStream, LoadMusicFile);
NzMusicLoader::RegisterLoader(IsSupported, CheckMusic, LoadMusicStream, LoadMusicFile, LoadMusicMemory);
NzSoundBufferLoader::RegisterLoader(IsSupported, CheckSoundBuffer, LoadSoundBuffer);
}
void NzLoaders_sndfile_Unregister()
{
NzMusicLoader::UnregisterLoader(IsSupported, CheckMusic, LoadMusicStream, LoadMusicFile);
NzMusicLoader::UnregisterLoader(IsSupported, CheckMusic, LoadMusicStream, LoadMusicFile, LoadMusicMemory);
NzSoundBufferLoader::UnregisterLoader(IsSupported, CheckSoundBuffer, LoadSoundBuffer);
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -7,6 +7,7 @@
#include <Nazara/Audio/OpenAL.hpp>
#include <Nazara/Audio/SoundStream.hpp>
#include <Nazara/Core/Thread.hpp>
#include <memory>
#include <vector>
#include <Nazara/Audio/Debug.hpp>
@@ -18,8 +19,8 @@ bool NzMusicParams::IsValid() const
struct NzMusicImpl
{
ALenum audioFormat;
std::unique_ptr<NzSoundStream> stream;
std::vector<nzInt16> chunkSamples;
NzSoundStream* stream;
NzThread thread;
bool loop = false;
bool paused = false;
@@ -50,7 +51,7 @@ bool NzMusic::Create(NzSoundStream* soundStream)
m_impl->sampleRate = soundStream->GetSampleRate();
m_impl->audioFormat = NzOpenAL::AudioFormat[format];
m_impl->chunkSamples.resize(format * m_impl->sampleRate); // Une seconde de samples
m_impl->stream = soundStream;
m_impl->stream.reset(soundStream);
return true;
}
@@ -61,7 +62,6 @@ void NzMusic::Destroy()
{
Stop();
delete m_impl->stream;
delete m_impl;
m_impl = nullptr;
}
@@ -116,6 +116,7 @@ nzUInt32 NzMusic::GetPlayingOffset() const
}
#endif
///TODO
return 0;
}
@@ -131,6 +132,7 @@ nzSoundStatus NzMusic::GetStatus() const
nzSoundStatus status = GetInternalStatus();
// Pour compenser les éventuels retards (ou le laps de temps entre Play() et la mise en route du thread)
if (m_impl->streaming && status == nzSoundStatus_Stopped)
status = nzSoundStatus_Playing;
@@ -180,14 +182,17 @@ void NzMusic::Play()
}
#endif
// Nous sommes déjà en train de jouer
if (m_impl->streaming)
{
// Peut-être sommes-nous en pause
if (GetStatus() != nzSoundStatus_Playing)
alSourcePlay(m_source);
return;
}
// Lancement du thread de streaming
m_impl->stream->Seek(0);
m_impl->streaming = true;
m_impl->thread = NzThread(&NzMusic::MusicThread, this);
@@ -195,6 +200,19 @@ void NzMusic::Play()
return;
}
void NzMusic::SetPlayingOffset(nzUInt32 offset)
{
#if NAZARA_AUDIO_SAFE
if (!m_impl)
{
NazaraError("Music not created");
return;
}
#endif
///TODO
}
void NzMusic::Stop()
{
#if NAZARA_AUDIO_SAFE
@@ -217,39 +235,44 @@ bool NzMusic::FillAndQueueBuffer(unsigned int buffer)
unsigned int sampleCount = m_impl->chunkSamples.size();
unsigned int sampleRead = 0;
// Lecture depuis le stream pour remplir le buffer
for (;;)
{
sampleRead += m_impl->stream->Read(&m_impl->chunkSamples[sampleRead], sampleCount - sampleRead);
if (sampleRead < sampleCount && m_impl->loop)
m_impl->stream->Seek(0);
else
break;
if (sampleRead < sampleCount && !m_impl->loop)
break; // Fin du stream (On ne boucle pas)
m_impl->stream->Seek(0); // On boucle au début du stream et on remplit à nouveau
}
// Mise à jour du buffer (envoi à OpenAL) et placement dans la file d'attente
if (sampleRead > 0)
{
alBufferData(buffer, m_impl->audioFormat, &m_impl->chunkSamples[0], sampleRead*sizeof(nzInt16), m_impl->sampleRate);
alSourceQueueBuffers(m_source, 1, &buffer);
}
return sampleRead != sampleCount; // Fin du fichier (N'arrive pas en cas de loop)
return sampleRead != sampleCount; // Fin du stream (N'arrive pas en cas de loop)
}
void NzMusic::MusicThread()
{
// Allocation des buffers de streaming
ALuint buffers[NAZARA_AUDIO_STREAMED_BUFFER_COUNT];
alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
for (unsigned int i = 0; i < NAZARA_AUDIO_STREAMED_BUFFER_COUNT; ++i)
{
if (FillAndQueueBuffer(buffers[i])) // Fin du fichier ?
break; // Nous avons atteint la fin du fichier, inutile de rajouter des buffers
if (FillAndQueueBuffer(buffers[i]))
break; // Nous avons atteint la fin du stream, inutile de rajouter des buffers
}
alSourcePlay(m_source);
// Boucle de lecture (remplissage de nouveaux buffers au fur et à mesure)
while (m_impl->streaming)
{
// La lecture s'est arrêtée, nous avons atteint la fin du stream
nzSoundStatus status = GetInternalStatus();
if (status == nzSoundStatus_Stopped)
{
@@ -257,6 +280,7 @@ void NzMusic::MusicThread()
break;
}
// On traite les buffers lus
ALint processedCount = 0;
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount);
@@ -268,11 +292,14 @@ void NzMusic::MusicThread()
break;
}
// On retourne dormir un peu
NzThread::Sleep(50);
}
// Arrêt de la lecture du son (dans le cas où ça ne serait pas déjà fait)
alSourceStop(m_source);
// On supprime les buffers du stream
ALint queuedBufferCount;
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -8,6 +8,7 @@
#include <Nazara/Audio/OpenAL.hpp>
#include <Nazara/Core/Error.hpp>
#include <cstring>
#include <memory>
#include <stdexcept>
#include <Nazara/Audio/Debug.hpp>
@@ -23,7 +24,7 @@ struct NzSoundBufferImpl
ALuint buffer;
nzAudioFormat format;
nzUInt32 duration;
nzInt16* samples;
std::unique_ptr<nzInt16[]> samples;
unsigned int sampleCount;
unsigned int sampleRate;
};
@@ -104,7 +105,7 @@ bool NzSoundBuffer::Create(nzAudioFormat format, unsigned int sampleCount, unsig
m_impl->format = format;
m_impl->sampleCount = sampleCount;
m_impl->sampleRate = sampleRate;
m_impl->samples = new nzInt16[sampleCount];
m_impl->samples.reset(new nzInt16[sampleCount]);
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(nzInt16));
NotifyCreated();
@@ -117,7 +118,6 @@ void NzSoundBuffer::Destroy()
{
NotifyDestroy();
delete[] m_impl->samples;
delete m_impl;
m_impl = nullptr;
}
@@ -159,7 +159,7 @@ const nzInt16* NzSoundBuffer::GetSamples() const
}
#endif
return m_impl->samples;
return m_impl->samples.get();
}
unsigned int NzSoundBuffer::GetSampleCount() const

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,10 +1,10 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/ByteArray.hpp>
#include <Nazara/Core/AbstractHash.hpp>
#include <Nazara/Math/Basic.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <algorithm>
#include <cstring>
#include <limits>
@@ -404,11 +404,14 @@ nzUInt8 NzByteArray::operator[](unsigned int pos) const
NzByteArray& NzByteArray::operator=(const NzByteArray& array)
{
ReleaseArray();
if (this != &array)
{
ReleaseArray();
m_sharedArray = array.m_sharedArray;
if (m_sharedArray != &emptyArray)
m_sharedArray->refCount++;
m_sharedArray = array.m_sharedArray;
if (m_sharedArray != &emptyArray)
m_sharedArray->refCount++;
}
return *this;
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,16 +1,16 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Config.hpp>
#if NAZARA_CORE_MANAGE_MEMORY
#define NAZARA_DEBUG_NEWREDEFINITION_DISABLE_REDEFINITION
#include <Nazara/Core/Debug/NewRedefinition.hpp>
#include <Nazara/Core/MemoryManager.hpp>
#include <new> // Nécessaire ?
#define NAZARA_DEBUG_NEWREDEFINITION_DISABLE_REDEFINITION
#include <Nazara/Core/Debug/NewRedefinition.hpp>
void* operator new(std::size_t size, const char* file, unsigned int line)
{
return NzMemoryManager::Allocate(size, false, file, line);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -733,7 +733,7 @@ bool NzFile::FillHash(NzAbstractHash* hash) const
unsigned int size;
while (remainingSize > 0)
{
size = (remainingSize >= NAZARA_CORE_FILE_BUFFERSIZE) ? NAZARA_CORE_FILE_BUFFERSIZE : static_cast<unsigned int>(remainingSize);
size = std::min(remainingSize, static_cast<nzUInt64>(NAZARA_CORE_FILE_BUFFERSIZE));
if (file.Read(&buffer[0], sizeof(char), size) != sizeof(char)*size)
{
NazaraError("Unable to read file");

View File

@@ -0,0 +1,446 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
// Implémentation originale de Jukka Jylänki (Merci de sa contribution au domaine public)
// http://clb.demon.fi/projects/even-more-rectangle-bin-packing
// Je n'ai vraiment fait qu'adapter le code au moteur (Avec quelques améliorations), je n'ai aucun mérite sur le code ci-dessous
#include <Nazara/Core/GuillotineBinPack.hpp>
#include <Nazara/Core/Config.hpp>
#include <algorithm>
#include <cmath>
#include <limits>
#include <Nazara/Core/Debug.hpp>
namespace
{
int ScoreBestAreaFit(int width, int height, const NzRectui& freeRectSize)
{
return freeRectSize.width * freeRectSize.height - width * height;
}
int ScoreBestLongSideFit(int width, int height, const NzRectui& freeRectSize)
{
int leftoverHoriz = std::abs(freeRectSize.width - width);
int leftoverVert = std::abs(freeRectSize.height - height);
int leftover = std::max(leftoverHoriz, leftoverVert);
return leftover;
}
int ScoreBestShortSideFit(int width, int height, const NzRectui& freeRectSize)
{
int leftoverHoriz = std::abs(freeRectSize.width - width);
int leftoverVert = std::abs(freeRectSize.height - height);
int leftover = std::min(leftoverHoriz, leftoverVert);
return leftover;
}
int ScoreWorstAreaFit(int width, int height, const NzRectui& freeRectSize)
{
return -ScoreBestAreaFit(width, height, freeRectSize);
}
int ScoreWorstLongSideFit(int width, int height, const NzRectui& freeRectSize)
{
return -ScoreBestLongSideFit(width, height, freeRectSize);
}
int ScoreWorstShortSideFit(int width, int height, const NzRectui& freeRectSize)
{
return -ScoreBestShortSideFit(width, height, freeRectSize);
}
}
NzGuillotineBinPack::NzGuillotineBinPack()
{
Reset();
}
NzGuillotineBinPack::NzGuillotineBinPack(unsigned int width, unsigned int height)
{
Reset(width, height);
}
NzGuillotineBinPack::NzGuillotineBinPack(const NzVector2ui& size)
{
Reset(size);
}
void NzGuillotineBinPack::Clear()
{
m_freeRectangles.clear();
m_freeRectangles.push_back(NzRectui(0, 0, m_width, m_height));
m_usedArea = 0;
}
void NzGuillotineBinPack::Expand(unsigned int newWidth, unsigned newHeight)
{
unsigned int oldWidth = m_width;
unsigned int oldHeight = m_height;
m_width = std::max(newWidth, m_width);
m_height = std::max(newHeight, m_height);
if (m_width > oldWidth)
m_freeRectangles.push_back(NzRectui(oldWidth, 0, m_width - oldWidth, oldHeight));
if (m_height > oldHeight)
m_freeRectangles.push_back(NzRectui(0, oldHeight, m_width, m_height - oldHeight));
// On va ensuite fusionner les rectangles tant que possible
while (MergeFreeRectangles());
}
void NzGuillotineBinPack::Expand(const NzVector2ui& newSize)
{
Expand(newSize.x, newSize.y);
}
void NzGuillotineBinPack::FreeRectangle(const NzRectui& rect)
{
///DOC: Cette méthode ne devrait recevoir que des rectangles calculés par la méthode Insert et peut provoquer de la fragmentation
m_freeRectangles.push_back(rect);
m_usedArea -= rect.width * rect.height;
}
unsigned int NzGuillotineBinPack::GetHeight() const
{
return m_height;
}
float NzGuillotineBinPack::GetOccupancy() const
{
return static_cast<float>(m_usedArea)/(m_width*m_height);
}
NzVector2ui NzGuillotineBinPack::GetSize() const
{
return NzVector2ui(m_width, m_height);
}
unsigned int NzGuillotineBinPack::GetWidth() const
{
return m_width;
}
bool NzGuillotineBinPack::Insert(NzRectui* rects, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
{
return Insert(rects, nullptr, nullptr, count, merge, rectChoice, splitMethod);
}
bool NzGuillotineBinPack::Insert(NzRectui* rects, bool* flipped, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
{
return Insert(rects, flipped, nullptr, count, merge, rectChoice, splitMethod);
}
bool NzGuillotineBinPack::Insert(NzRectui* rects, bool* flipped, bool* inserted, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
{
std::vector<NzRectui*> remainingRects(count); // La position du rectangle
for (unsigned int i = 0; i < count; ++i)
remainingRects[i] = &rects[i];
// Pack rectangles one at a time until we have cleared the rects array of all rectangles.
while (!remainingRects.empty())
{
// Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better.
bool bestFlipped;
int bestFreeRect;
int bestRect;
int bestScore = std::numeric_limits<int>::max();
for (std::size_t i = 0; i < m_freeRectangles.size(); ++i)
{
NzRectui& freeRect = m_freeRectangles[i];
for (std::size_t j = 0; j < remainingRects.size(); ++j)
{
NzRectui& rect = *remainingRects[j];
// If this rectangle is a perfect match, we pick it instantly.
if (rect.width == freeRect.width && rect.height == freeRect.height)
{
bestFreeRect = i;
bestRect = j;
bestFlipped = false;
bestScore = std::numeric_limits<int>::min();
i = m_freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
break;
}
// If flipping this rectangle is a perfect match, pick that then.
else if (rect.height == freeRect.width && rect.width == freeRect.height)
{
bestFreeRect = i;
bestRect = j;
bestFlipped = true;
bestScore = std::numeric_limits<int>::min();
i = m_freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
break;
}
// Try if we can fit the rectangle upright.
else if (rect.width <= freeRect.width && rect.height <= freeRect.height)
{
int score = ScoreByHeuristic(rect.width, rect.height, freeRect, rectChoice);
if (score < bestScore)
{
bestFreeRect = i;
bestRect = j;
bestFlipped = false;
bestScore = score;
}
}
// If not, then perhaps flipping sideways will make it fit?
else if (rect.height <= freeRect.width && rect.width <= freeRect.height)
{
int score = ScoreByHeuristic(rect.height, rect.width, freeRect, rectChoice);
if (score < bestScore)
{
bestFreeRect = i;
bestRect = j;
bestFlipped = true;
bestScore = score;
}
}
}
}
// If we didn't manage to find any rectangle to pack, abort.
if (bestScore == std::numeric_limits<int>::max())
{
// Si nous le pouvons, on marque les rectangles n'ayant pas pu être insérés
if (inserted)
{
for (NzRectui* rect : remainingRects)
{
unsigned int position = rect - rects;
inserted[position] = false;
}
}
return false;
}
// Otherwise, we're good to go and do the actual packing.
unsigned int position = remainingRects[bestRect] - rects;
NzRectui& rect = *remainingRects[bestRect];
rect.x = m_freeRectangles[bestFreeRect].x;
rect.y = m_freeRectangles[bestFreeRect].y;
if (bestFlipped)
std::swap(rect.width, rect.height);
if (flipped)
flipped[position] = bestFlipped;
if (inserted)
inserted[position] = true;
// Remove the free space we lost in the bin.
SplitFreeRectByHeuristic(m_freeRectangles[bestFreeRect], rect, splitMethod);
m_freeRectangles.erase(m_freeRectangles.begin() + bestFreeRect);
// Remove the rectangle we just packed from the input list.
remainingRects.erase(remainingRects.begin() + bestRect);
// Perform a Rectangle Merge step if desired.
if (merge)
MergeFreeRectangles();
m_usedArea += rect.width * rect.height;
}
return true;
}
bool NzGuillotineBinPack::MergeFreeRectangles()
{
///DOC: Renvoie true s'il y a eu fusion (et donc si une fusion est encore possible)
std::size_t oriSize = m_freeRectangles.size();
// Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one.
// Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that)
for (std::size_t i = 0; i < m_freeRectangles.size(); ++i)
{
NzRectui& firstRect = m_freeRectangles[i];
for (std::size_t j = i+1; j < m_freeRectangles.size(); ++j)
{
NzRectui& secondRect = m_freeRectangles[j];
if (firstRect.width == secondRect.width && firstRect.x == secondRect.x)
{
if (firstRect.y == secondRect.y + secondRect.height)
{
firstRect.y -= secondRect.height;
firstRect.height += secondRect.height;
m_freeRectangles.erase(m_freeRectangles.begin() + j);
--j;
}
else if (firstRect.y + firstRect.height == secondRect.y)
{
firstRect.height += secondRect.height;
m_freeRectangles.erase(m_freeRectangles.begin() + j);
--j;
}
}
else if (firstRect.height == secondRect.height && firstRect.y == secondRect.y)
{
if (firstRect.x == secondRect.x + secondRect.width)
{
firstRect.x -= secondRect.width;
firstRect.width += secondRect.width;
m_freeRectangles.erase(m_freeRectangles.begin() + j);
--j;
}
else if (firstRect.x + firstRect.width == secondRect.x)
{
firstRect.width += secondRect.width;
m_freeRectangles.erase(m_freeRectangles.begin() + j);
--j;
}
}
}
}
return m_freeRectangles.size() < oriSize;
}
void NzGuillotineBinPack::Reset()
{
m_height = 0;
m_width = 0;
Clear();
}
void NzGuillotineBinPack::Reset(unsigned int width, unsigned int height)
{
m_height = height;
m_width = width;
Clear();
}
void NzGuillotineBinPack::Reset(const NzVector2ui& size)
{
Reset(size.x, size.y);
}
void NzGuillotineBinPack::SplitFreeRectAlongAxis(const NzRectui& freeRect, const NzRectui& placedRect, bool splitHorizontal)
{
// Form the two new rectangles.
NzRectui bottom;
bottom.x = freeRect.x;
bottom.y = freeRect.y + placedRect.height;
bottom.height = freeRect.height - placedRect.height;
NzRectui right;
right.x = freeRect.x + placedRect.width;
right.y = freeRect.y;
right.width = freeRect.width - placedRect.width;
if (splitHorizontal)
{
bottom.width = freeRect.width;
right.height = placedRect.height;
}
else // Split vertically
{
bottom.width = placedRect.width;
right.height = freeRect.height;
}
// Add the new rectangles into the free rectangle pool if they weren't degenerate.
if (bottom.width > 0 && bottom.height > 0)
m_freeRectangles.push_back(bottom);
if (right.width > 0 && right.height > 0)
m_freeRectangles.push_back(right);
}
void NzGuillotineBinPack::SplitFreeRectByHeuristic(const NzRectui& freeRect, const NzRectui& placedRect, GuillotineSplitHeuristic method)
{
// Compute the lengths of the leftover area.
const int w = freeRect.width - placedRect.width;
const int h = freeRect.height - placedRect.height;
// Placing placedRect into freeRect results in an L-shaped free area, which must be split into
// two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line.
// We have two choices: horizontal or vertical.
// Use the given heuristic to decide which choice to make.
bool splitHorizontal;
switch (method)
{
case SplitLongerAxis:
// Split along the longer total axis.
splitHorizontal = (freeRect.width > freeRect.height);
break;
case SplitLongerLeftoverAxis:
// Split along the longer leftover axis.
splitHorizontal = (w > h);
break;
case SplitMaximizeArea:
// Maximize the smaller area == minimize the larger area.
// Tries to make the rectangles more even-sized.
splitHorizontal = (placedRect.width * h <= w * placedRect.height);
break;
case SplitMinimizeArea:
// Maximize the larger area == minimize the smaller area.
// Tries to make the single bigger rectangle.
splitHorizontal = (placedRect.width * h > w * placedRect.height);
break;
case SplitShorterAxis:
// Split along the shorter total axis.
splitHorizontal = (freeRect.width <= freeRect.height);
break;
case SplitShorterLeftoverAxis:
// Split along the shorter leftover axis.
splitHorizontal = (w <= h);
break;
default:
NazaraError("Split heuristic out of enum (0x" + NzString::Number(method, 16) + ')');
splitHorizontal = true;
}
// Perform the actual split.
SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
}
int NzGuillotineBinPack::ScoreByHeuristic(int width, int height, const NzRectui& freeRect, FreeRectChoiceHeuristic rectChoice)
{
switch (rectChoice)
{
case RectBestAreaFit:
return ScoreBestAreaFit(width, height, freeRect);
case RectBestLongSideFit:
return ScoreBestLongSideFit(width, height, freeRect);
case RectBestShortSideFit:
return ScoreBestShortSideFit(width, height, freeRect);
case RectWorstAreaFit:
return ScoreWorstAreaFit(width, height, freeRect);
case RectWorstLongSideFit:
return ScoreWorstLongSideFit(width, height, freeRect);
case RectWorstShortSideFit:
return ScoreWorstShortSideFit(width, height, freeRect);
}
NazaraError("Rect choice heuristic out of enum (0x" + NzString::Number(rectChoice, 16) + ')');
return std::numeric_limits<int>::max();
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -770,14 +770,6 @@ void SHA224_Init(SHA_CTX* context)
SHA256_Internal_Init(context, sha224_initial_hash_value);
}
namespace
{
void SHA224_Internal_Transform(SHA_CTX* context, const nzUInt32* data)
{
SHA256_Internal_Transform(context, data);
}
}
void SHA224_Update(SHA_CTX* context, const nzUInt8 *data, std::size_t len)
{
SHA256_Update(context, data, len);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -6,7 +6,6 @@
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <Nazara/Math/Basic.hpp>
#include <ctime>
#include <cstring>

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,12 +1,10 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
// Notre utilisation du placement new n'est pas (encore ?) compatible avec les définitions du MLT
#define NAZARA_DEBUG_NEWREDEFINITION_DISABLE_REDEFINITION
#include <Nazara/Core/ParameterList.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/MemoryHelper.hpp>
#include <cstring>
#include <limits>
#include <new>
@@ -309,7 +307,7 @@ void NzParameterList::SetParameter(const NzString& name, const NzString& value)
parameter.type = nzParameterType_String;
new (&parameter.value.stringVal) NzString(value);
NzPlacementNew<NzString>(&parameter.value.stringVal, value);
}
void NzParameterList::SetParameter(const NzString& name, const char* value)
@@ -322,7 +320,7 @@ void NzParameterList::SetParameter(const NzString& name, const char* value)
parameter.type = nzParameterType_String;
new (&parameter.value.stringVal) NzString(value);
NzPlacementNew<NzString>(&parameter.value.stringVal, value);
}
void NzParameterList::SetParameter(const NzString& name, void* value)
@@ -405,7 +403,7 @@ NzParameterList& NzParameterList::operator=(const NzParameterList& list)
case nzParameterType_String:
parameter.type = nzParameterType_String;
new (&parameter.value.stringVal) NzString(it->second.value.stringVal);
NzPlacementNew<NzString>(&parameter.value.stringVal, it->second.value.stringVal);
break;
case nzParameterType_Userdata:

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -19,7 +19,7 @@ class NzDynLibImpl : NzNonCopyable
NzDynLibImpl(NzDynLib* m_parent);
~NzDynLibImpl() = default;
NzDynLibFunc GetSymbol(const NzString& symbol, NzString& errorMessage) const;
NzDynLibFunc GetSymbol(const NzString& symbol, NzString* errorMessage) const;
bool Load(const NzString& libraryPath, NzString* errorMessage);
void Unload();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -71,7 +71,11 @@ void NzRefCounted::RemoveObjectListener(NzObjectListener* listener) const
{
ObjectListenerMap::iterator it = m_objectListeners.find(listener);
if (it != m_objectListeners.end())
RemoveObjectListenerIterator(it);
{
unsigned int& referenceCount = it->second.second;
if (--referenceCount == 0)
m_objectListeners.erase(it);
}
}
}
@@ -119,7 +123,7 @@ void NzRefCounted::NotifyCreated()
while (it != m_objectListeners.end())
{
if (!it->first->OnObjectCreated(this, it->second.first))
RemoveObjectListenerIterator(it++);
m_objectListeners.erase(it++);
else
++it;
}
@@ -137,7 +141,7 @@ void NzRefCounted::NotifyDestroy()
while (it != m_objectListeners.end())
{
if (!it->first->OnObjectDestroy(this, it->second.first))
RemoveObjectListenerIterator(it++);
m_objectListeners.erase(it++);
else
++it;
}
@@ -155,19 +159,10 @@ void NzRefCounted::NotifyModified(unsigned int code)
while (it != m_objectListeners.end())
{
if (!it->first->OnObjectModified(this, it->second.first, code))
RemoveObjectListenerIterator(it++);
m_objectListeners.erase(it++);
else
++it;
}
m_objectListenersLocked = false;
}
void NzRefCounted::RemoveObjectListenerIterator(ObjectListenerMap::iterator iterator) const
{
unsigned int& referenceCount = iterator->second.second;
if (referenceCount == 1)
m_objectListeners.erase(iterator);
else
referenceCount--;
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -7,7 +7,7 @@
NzResource::~NzResource() = default;
NzString NzResource::GetFilePath() const
const NzString& NzResource::GetFilePath() const
{
return m_filePath;
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -9,7 +9,7 @@
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Unicode.hpp>
#include <Nazara/Math/Basic.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <algorithm>
#include <cstdio>
#include <cstring>
@@ -2785,35 +2785,19 @@ NzString& NzString::Set(const char* string, unsigned int length)
NzString& NzString::Set(const std::string& string)
{
if (string.size() > 0)
{
if (m_sharedString->capacity >= string.size())
EnsureOwnership(true);
else
{
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = string.size();
m_sharedString->string = new char[string.size()+1];
}
m_sharedString->size = string.size();
std::memcpy(m_sharedString->string, string.c_str(), string.size()+1);
}
else
ReleaseString();
return *this;
return Set(string.data(), string.size());
}
NzString& NzString::Set(const NzString& string)
{
ReleaseString();
if (this != &string)
{
ReleaseString();
m_sharedString = string.m_sharedString;
if (m_sharedString != &emptyString)
m_sharedString->refCount++;
m_sharedString = string.m_sharedString;
if (m_sharedString != &emptyString)
m_sharedString->refCount++;
}
return *this;
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@@ -18,34 +18,348 @@ struct Character
#include <Nazara/Core/UnicodeData.hpp>
#else // Implémentation bidon
#else // Implémentation supportant la table ASCII
NzUnicode::Category NzUnicode::GetCategory(char32_t character)
{
NazaraUnused(character);
switch (character)
{
case '\x00':
case '\x01':
case '\x02':
case '\x03':
case '\x04':
case '\x05':
case '\x06':
case '\x07':
case '\x08':
case '\x09':
case '\x0A':
case '\x0B':
case '\x0C':
case '\x0D':
case '\x0E':
case '\x0F':
case '\x10':
case '\x11':
case '\x12':
case '\x13':
case '\x14':
case '\x15':
case '\x16':
case '\x17':
case '\x18':
case '\x19':
case '\x1A':
case '\x1B':
case '\x1C':
case '\x1D':
case '\x1E':
case '\x1F':
case '\x7F':
return Category_Other_Control;
case ' ':
return Category_Separator_Space;
case '!':
case '"':
case '#':
case '$':
case '%':
case '&':
case '\'':
case '*':
case ',':
case '.':
case '/':
case ':':
case ';':
case '?':
case '@':
case '\\':
return Category_Punctuation_Other;
case '(':
case '[':
case '{':
return Category_Punctuation_Open;
case ')':
case '}':
case ']':
return Category_Punctuation_Close;
case '+':
case '<':
case '=':
case '>':
case '|':
case '~':
return Category_Symbol_Math;
case '-':
return Category_Punctuation_Dash;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return Category_Number_DecimalDigit;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
return Category_Number_DecimalDigit;
case '_':
return Category_Punctuation_Connector;
case '^':
case '`':
return Category_Symbol_Modifier;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
return Category_Number_DecimalDigit;
default:
break;
}
return Category_NoCategory;
}
NzUnicode::Direction NzUnicode::GetDirection(char32_t character)
{
NazaraUnused(character);
switch (character)
{
case '\x00':
case '\x01':
case '\x02':
case '\x03':
case '\x04':
case '\x05':
case '\x06':
case '\x07':
case '\x08':
case '\x0E':
case '\x0F':
case '\x10':
case '\x11':
case '\x12':
case '\x13':
case '\x14':
case '\x15':
case '\x16':
case '\x17':
case '\x18':
case '\x19':
case '\x1A':
case '\x1B':
case '\x7F':
return Direction_Boundary_Neutral;
case '\x09':
case '\x0B':
case '\x1F':
return Direction_Segment_Separator;
case '\x0A':
case '\x0D':
case '\x1C':
case '\x1D':
case '\x1E':
return Direction_Paragraph_Separator;
case '\x0C':
case ' ':
return Direction_White_Space;
case '!':
case '"':
case '&':
case '\'':
case '(':
case ')':
case '*':
case ';':
case '<':
case '=':
case '>':
case '?':
case '@':
case '[':
case '\\':
case ']':
case '^':
case '_':
case '`':
case '{':
case '|':
case '}':
case '~':
return Direction_Other_Neutral;
case '#':
case '$':
case '%':
return Direction_European_Terminator;
case '+':
case '-':
return Direction_European_Separator;
case ',':
case '.':
case '/':
case ':':
return Direction_Common_Separator;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return Direction_European_Number;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
return Direction_Left_To_Right;
default:
break;
}
return Direction_Boundary_Neutral;
}
char32_t NzUnicode::GetLowercase(char32_t character)
{
return character;
if (character >= 'A' && character <= 'Z')
return character + ('a' - 'A');
else
return character;
}
char32_t NzUnicode::GetTitlecase(char32_t character)
{
return character;
return GetUppercase(character);
}
char32_t NzUnicode::GetUppercase(char32_t character)
{
return character;
if (character >= 'a' && character <= 'z')
return character + ('A' - 'a');
else
return character;
}
#endif

View File

@@ -0,0 +1,8 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Updatable.hpp>
#include <Nazara/Core/Debug.hpp>
NzUpdatable::~NzUpdatable() = default;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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
@@ -80,6 +80,21 @@ const NzFrustumf& NzCamera::GetFrustum() const
return m_frustum;
}
NzVector3f NzCamera::GetGlobalForward() const
{
return NzVector3f::Forward();
}
NzVector3f NzCamera::GetGlobalRight() const
{
return NzVector3f::Right();
}
NzVector3f NzCamera::GetGlobalUp() const
{
return NzVector3f::Up();
}
const NzMatrix4f& NzCamera::GetProjectionMatrix() const
{
if (!m_projectionMatrixUpdated)

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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
@@ -10,9 +10,9 @@
NzDeferredBloomPass::NzDeferredBloomPass() :
m_uniformUpdated(false),
m_brightLuminance(0.8),
m_brightMiddleGrey(0.5),
m_brightThreshold(0.8),
m_brightLuminance(0.8f),
m_brightMiddleGrey(0.5f),
m_brightThreshold(0.8f),
m_blurPassCount(5)
{
m_bilinearSampler.SetAnisotropyLevel(1);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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
@@ -125,6 +125,7 @@ NzDeferredFogPass::NzDeferredFogPass()
m_pointSampler.SetWrapMode(nzSamplerWrap_Clamp);
m_shader = BuildFogShader();
m_shaderEyePositionLocation = m_shader->GetUniformLocation("EyePosition");
m_states.parameters[nzRendererParameter_DepthBuffer] = false;
}
@@ -138,7 +139,7 @@ bool NzDeferredFogPass::Process(const NzScene* scene, unsigned int firstWorkText
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetShader(m_shader);
m_shader->SendVector(m_shader->GetUniformLocation(nzShaderUniform_EyePosition), scene->GetViewer()->GetEyePosition());
m_shader->SendVector(m_shaderEyePositionLocation, scene->GetViewer()->GetEyePosition());
NzRenderer::SetRenderStates(m_states);
NzRenderer::SetTexture(0, m_workTextures[secondWorkTexture]);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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
@@ -51,23 +51,21 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
NzRenderer::SetMatrix(nzMatrixType_View, viewer->GetViewMatrix());
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
for (auto& matIt : m_renderQueue->opaqueModels)
{
bool& used = std::get<0>(matIt.second);
if (used)
auto& matEntry = matIt.second;
if (matEntry.enabled)
{
bool& renderQueueInstancing = std::get<1>(matIt.second);
NzDeferredRenderQueue::MeshInstanceContainer& meshInstances = std::get<2>(matIt.second);
NzDeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
if (!meshInstances.empty())
{
const NzMaterial* material = matIt.first;
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches
// (Le deferred shading n'a pas ce problème)
bool useInstancing = instancingEnabled && renderQueueInstancing;
bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
// On commence par récupérer le programme du matériau
nzUInt32 flags = nzShaderFlags_Deferred;
@@ -79,10 +77,13 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
@@ -91,28 +92,29 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
for (auto& meshIt : meshInstances)
{
const NzMeshData& meshData = meshIt.first;
std::vector<NzMatrix4f>& instances = meshIt.second;
auto& meshEntry = meshIt.second;
std::vector<NzMatrix4f>& instances = meshEntry.instances;
if (!instances.empty())
{
const NzIndexBuffer* indexBuffer = meshData.indexBuffer;
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> DrawFunc;
std::function<void(unsigned int, nzPrimitiveMode, unsigned int, unsigned int)> InstancedDrawFunc;
NzRenderer::DrawCall drawFunc;
NzRenderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount;
if (indexBuffer)
{
DrawFunc = NzRenderer::DrawIndexedPrimitives;
InstancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
drawFunc = NzRenderer::DrawIndexedPrimitives;
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
indexCount = indexBuffer->GetIndexCount();
}
else
{
DrawFunc = NzRenderer::DrawPrimitives;
InstancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
drawFunc = NzRenderer::DrawPrimitives;
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
indexCount = vertexBuffer->GetVertexCount();
}
@@ -140,18 +142,18 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
instanceMatrices += renderedInstanceCount;
// Et on affiche
InstancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
}
}
else
{
// Sans instancing, on doit effectuer un drawcall pour chaque instance
// Sans instancing, on doit effectuer un draw call pour chaque instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
// À cause du temps de modification du buffer d'instancing
for (const NzMatrix4f& matrix : instances)
{
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
DrawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
}
@@ -161,8 +163,8 @@ bool NzDeferredGeometryPass::Process(const NzScene* scene, unsigned int firstWor
}
// Et on remet à zéro les données
renderQueueInstancing = false;
used = false;
matEntry.enabled = false;
matEntry.instancingEnabled = false;
}
}
@@ -228,7 +230,23 @@ bool NzDeferredGeometryPass::Resize(const NzVector2ui& dimensions)
}
catch (const std::exception& e)
{
NazaraError("Failed to create G-Buffer RTT");
NazaraError("Failed to create G-Buffer RTT: " + NzString(e.what()));
return false;
}
}
const NzDeferredGeometryPass::ShaderUniforms* NzDeferredGeometryPass::GetShaderUniforms(const NzShader* shader) const
{
auto it = m_shaderUniforms.find(shader);
if (it == m_shaderUniforms.end())
{
ShaderUniforms uniforms;
uniforms.eyePosition = shader->GetUniformLocation("EyePosition");
uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient");
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
it = m_shaderUniforms.emplace(shader, uniforms).first;
}
return &it->second;
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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
@@ -17,6 +17,8 @@ NzDeferredPhongLightingPass::NzDeferredPhongLightingPass() :
m_lightMeshesDrawing(false)
{
m_directionalLightShader = NzShaderLibrary::Get("DeferredDirectionnalLight");
m_directionalLightShaderEyePositionLocation = m_directionalLightShader->GetUniformLocation("EyePosition");
m_directionalLightShaderSceneAmbientLocation = m_directionalLightShader->GetUniformLocation("SceneAmbient");
m_directionalLightUniforms.ubo = false;
m_directionalLightUniforms.locations.type = -1; // Type déjà connu
@@ -28,6 +30,8 @@ m_lightMeshesDrawing(false)
m_pointSpotLightShader = NzShaderLibrary::Get("DeferredPointSpotLight");
m_pointSpotLightShaderDiscardLocation = m_pointSpotLightShader->GetUniformLocation("Discard");
m_pointSpotLightShaderEyePositionLocation = m_pointSpotLightShader->GetUniformLocation("EyePosition");
m_pointSpotLightShaderSceneAmbientLocation = m_pointSpotLightShader->GetUniformLocation("SceneAmbient");
m_pointSpotLightUniforms.ubo = false;
m_pointSpotLightUniforms.locations.type = m_pointSpotLightShader->GetUniformLocation("LightType");
@@ -96,8 +100,8 @@ bool NzDeferredPhongLightingPass::Process(const NzScene* scene, unsigned int fir
{
NzRenderer::SetRenderStates(lightStates);
NzRenderer::SetShader(m_directionalLightShader);
m_directionalLightShader->SendColor(m_directionalLightShader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
m_directionalLightShader->SendVector(m_directionalLightShader->GetUniformLocation(nzShaderUniform_EyePosition), scene->GetViewer()->GetEyePosition());
m_directionalLightShader->SendColor(m_directionalLightShaderSceneAmbientLocation, scene->GetAmbientColor());
m_directionalLightShader->SendVector(m_directionalLightShaderEyePositionLocation, scene->GetViewer()->GetEyePosition());
for (const NzLight* light : m_renderQueue->directionalLights)
{
@@ -126,8 +130,8 @@ bool NzDeferredPhongLightingPass::Process(const NzScene* scene, unsigned int fir
NzRenderer::SetRenderStates(lightStates);
NzRenderer::SetShader(m_pointSpotLightShader);
m_pointSpotLightShader->SendColor(m_pointSpotLightShader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
m_pointSpotLightShader->SendVector(m_pointSpotLightShader->GetUniformLocation(nzShaderUniform_EyePosition), scene->GetViewer()->GetEyePosition());
m_pointSpotLightShader->SendColor(m_pointSpotLightShaderEyePositionLocation, scene->GetAmbientColor());
m_pointSpotLightShader->SendVector(m_pointSpotLightShaderSceneAmbientLocation, scene->GetViewer()->GetEyePosition());
NzMatrix4f lightMatrix;
lightMatrix.MakeIdentity();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,16 +1,15 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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/DeferredRenderQueue.hpp>
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/ForwardRenderQueue.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Graphics/Debug.hpp>
///TODO: Rendre les billboards via Deferred Shading si possible
namespace
{
enum ObjectType
@@ -26,9 +25,49 @@ m_forwardQueue(forwardQueue)
{
}
NzDeferredRenderQueue::~NzDeferredRenderQueue()
void NzDeferredRenderQueue::AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos, const NzColor& color)
{
Clear(true);
m_forwardQueue->AddBillboard(material, position, size, sinCos, color);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
}
void NzDeferredRenderQueue::AddDrawable(const NzDrawable* drawable)
@@ -46,6 +85,7 @@ void NzDeferredRenderQueue::AddLight(const NzLight* light)
}
#endif
// On trie la lumière (elles sont traitées différement selon leur type)
switch (light->GetLightType())
{
case nzLightType_Directional:
@@ -61,71 +101,55 @@ void NzDeferredRenderQueue::AddLight(const NzLight* light)
break;
}
// On envoie également la lumière au forward-shading
///TODO: Possibilité pour une lumière de se réserver au Deferred Shading
m_forwardQueue->AddLight(light);
}
void NzDeferredRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix)
{
if (material->IsEnabled(nzRendererParameter_Blend))
// Un matériau transparent ? J'aime pas, va voir dans la forward queue si j'y suis
m_forwardQueue->AddMesh(material, meshData, meshAABB, transformMatrix);
else
{
ModelBatches::iterator it = opaqueModels.find(material);
auto it = opaqueModels.find(material);
if (it == opaqueModels.end())
{
it = opaqueModels.insert(std::make_pair(material, ModelBatches::mapped_type())).first;
material->AddObjectListener(this, ObjectType_Material);
BatchedModelEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
}
bool& used = std::get<0>(it->second);
bool& enableInstancing = std::get<1>(it->second);
MeshInstanceContainer& meshMap = std::get<2>(it->second);
BatchedModelEntry& entry = it->second;
entry.enabled = true;
used = true;
auto& meshMap = entry.meshMap;
MeshInstanceContainer::iterator it2 = meshMap.find(meshData);
auto it2 = meshMap.find(meshData);
if (it2 == meshMap.end())
{
it2 = meshMap.insert(std::make_pair(meshData, MeshInstanceContainer::mapped_type())).first;
MeshInstanceEntry instanceEntry(this, ObjectType_IndexBuffer, ObjectType_VertexBuffer);
instanceEntry.indexBufferListener = meshData.indexBuffer;
instanceEntry.vertexBufferListener = meshData.vertexBuffer;
if (meshData.indexBuffer)
meshData.indexBuffer->AddObjectListener(this, ObjectType_IndexBuffer);
meshData.vertexBuffer->AddObjectListener(this, ObjectType_VertexBuffer);
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
}
std::vector<NzMatrix4f>& instances = it2->second;
// On ajoute la matrice à la liste des instances de cet objet
std::vector<NzMatrix4f>& instances = it2->second.instances;
instances.push_back(transformMatrix);
// Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ?
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
enableInstancing = true; // Apparemment oui, activons l'instancing avec ce matériau
entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau
}
}
void NzDeferredRenderQueue::AddSprite(const NzSprite* sprite)
void NzDeferredRenderQueue::AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay)
{
#if NAZARA_GRAPHICS_SAFE
if (!sprite)
{
NazaraError("Invalid sprite");
return;
}
if (!sprite->IsDrawable())
{
NazaraError("Sprite is not drawable");
return;
}
#endif
/*NzMaterial* material = sprite->GetMaterial();
if (!material->IsLightingEnabled() || material->IsEnabled(nzRendererParameter_Blend))
m_forwardQueue->AddSprite(sprite);
else
sprites[material].push_back(sprite);*/
m_forwardQueue->AddSprite(sprite);
m_forwardQueue->AddSprites(material, vertices, spriteCount, overlay);
}
void NzDeferredRenderQueue::Clear(bool fully)
@@ -135,27 +159,7 @@ void NzDeferredRenderQueue::Clear(bool fully)
spotLights.clear();
if (fully)
{
for (auto& matIt : opaqueModels)
{
const NzMaterial* material = matIt.first;
material->RemoveObjectListener(this);
MeshInstanceContainer& instances = std::get<2>(matIt.second);
for (auto& instanceIt : instances)
{
const NzMeshData& renderData = instanceIt.first;
if (renderData.indexBuffer)
renderData.indexBuffer->RemoveObjectListener(this);
renderData.vertexBuffer->RemoveObjectListener(this);
}
}
opaqueModels.clear();
sprites.clear();
}
m_forwardQueue->Clear(fully);
}
@@ -168,7 +172,7 @@ bool NzDeferredRenderQueue::OnObjectDestroy(const NzRefCounted* object, int inde
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -182,14 +186,18 @@ bool NzDeferredRenderQueue::OnObjectDestroy(const NzRefCounted* object, int inde
}
case ObjectType_Material:
opaqueModels.erase(static_cast<const NzMaterial*>(object));
{
const NzMaterial* material = static_cast<const NzMaterial*>(object);
opaqueModels.erase(material);
break;
}
case ObjectType_VertexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -217,7 +225,7 @@ void NzDeferredRenderQueue::OnObjectReleased(const NzRefCounted* object, int ind
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -247,7 +255,7 @@ void NzDeferredRenderQueue::OnObjectReleased(const NzRefCounted* object, int ind
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -282,26 +290,6 @@ bool NzDeferredRenderQueue::BatchedModelMaterialComparator::operator()(const NzM
return mat1 < mat2;
}
bool NzDeferredRenderQueue::BatchedSpriteMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
{
const NzUberShader* uberShader1 = mat1->GetShader();
const NzUberShader* uberShader2 = mat2->GetShader();
if (uberShader1 != uberShader2)
return uberShader1 < uberShader2;
const NzShader* shader1 = mat1->GetShaderInstance(nzShaderFlags_Deferred)->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance(nzShaderFlags_Deferred)->GetShader();
if (shader1 != shader2)
return shader1 < shader2;
const NzTexture* diffuseMap1 = mat1->GetDiffuseMap();
const NzTexture* diffuseMap2 = mat2->GetDiffuseMap();
if (diffuseMap1 != diffuseMap2)
return diffuseMap1 < diffuseMap2;
return mat1 < mat2;
}
bool NzDeferredRenderQueue::MeshDataComparator::operator()(const NzMeshData& data1, const NzMeshData& data2)
{
const NzBuffer* buffer1;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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
@@ -21,6 +21,7 @@
#include <Nazara/Graphics/Drawable.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/OpenGL.hpp>
@@ -35,6 +36,34 @@
namespace
{
const nzUInt8 r_fragmentSource_BloomBright[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/BloomBright.frag.h>
};
const nzUInt8 r_fragmentSource_BloomFinal[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/BloomFinal.frag.h>
};
const nzUInt8 r_fragmentSource_DirectionalLight[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/DirectionalLight.frag.h>
};
const nzUInt8 r_fragmentSource_FXAA[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/FXAA.frag.h>
};
const nzUInt8 r_fragmentSource_GBufferClear[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/GBufferClear.frag.h>
};
const nzUInt8 r_fragmentSource_GaussianBlur[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/GaussianBlur.frag.h>
};
const nzUInt8 r_fragmentSource_PointSpotLight[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/PointSpotLight.frag.h>
};
unsigned int RenderPassPriority[] =
{
6, // nzRenderPassType_AA
@@ -412,34 +441,6 @@ bool NzDeferredRenderTechnique::Resize(const NzVector2ui& dimensions) const
bool NzDeferredRenderTechnique::Initialize()
{
const nzUInt8 fragmentSource_BloomBright[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/BloomBright.frag.h>
};
const nzUInt8 fragmentSource_BloomFinal[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/BloomFinal.frag.h>
};
const nzUInt8 fragmentSource_DirectionalLight[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/DirectionalLight.frag.h>
};
const nzUInt8 fragmentSource_FXAA[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/FXAA.frag.h>
};
const nzUInt8 fragmentSource_GBufferClear[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/GBufferClear.frag.h>
};
const nzUInt8 fragmentSource_GaussianBlur[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/GaussianBlur.frag.h>
};
const nzUInt8 fragmentSource_PointSpotLight[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/PointSpotLight.frag.h>
};
const char vertexSource_Basic[] =
"#version 140\n"
@@ -497,7 +498,7 @@ bool NzDeferredRenderTechnique::Initialize()
NzShader* shader;
// Shaders critiques (Nécessaires pour le Deferred Shading minimal)
shader = RegisterDeferredShader("DeferredGBufferClear", fragmentSource_GBufferClear, sizeof(fragmentSource_GBufferClear), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredGBufferClear", r_fragmentSource_GBufferClear, sizeof(r_fragmentSource_GBufferClear), ppVertexStage, &error);
if (!shader)
{
NazaraError("Failed to register critical shader: " + error);
@@ -505,7 +506,7 @@ bool NzDeferredRenderTechnique::Initialize()
}
shader = RegisterDeferredShader("DeferredDirectionnalLight", fragmentSource_DirectionalLight, sizeof(fragmentSource_DirectionalLight), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredDirectionnalLight", r_fragmentSource_DirectionalLight, sizeof(r_fragmentSource_DirectionalLight), ppVertexStage, &error);
if (!shader)
{
NazaraError("Failed to register critical shader: " + error);
@@ -517,7 +518,7 @@ bool NzDeferredRenderTechnique::Initialize()
shader->SendInteger(shader->GetUniformLocation("GBuffer2"), 2);
shader = RegisterDeferredShader("DeferredPointSpotLight", fragmentSource_PointSpotLight, sizeof(fragmentSource_PointSpotLight), basicVertexStage, &error);
shader = RegisterDeferredShader("DeferredPointSpotLight", r_fragmentSource_PointSpotLight, sizeof(r_fragmentSource_PointSpotLight), basicVertexStage, &error);
if (!shader)
{
NazaraError("Failed to register critical shader: " + error);
@@ -530,7 +531,7 @@ bool NzDeferredRenderTechnique::Initialize()
// Shaders optionnels (S'ils ne sont pas présents, le rendu minimal sera quand même assuré)
shader = RegisterDeferredShader("DeferredBloomBright", fragmentSource_BloomBright, sizeof(fragmentSource_BloomBright), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredBloomBright", r_fragmentSource_BloomBright, sizeof(r_fragmentSource_BloomBright), ppVertexStage, &error);
if (shader)
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
else
@@ -539,7 +540,7 @@ bool NzDeferredRenderTechnique::Initialize()
}
shader = RegisterDeferredShader("DeferredBloomFinal", fragmentSource_BloomFinal, sizeof(fragmentSource_BloomFinal), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredBloomFinal", r_fragmentSource_BloomFinal, sizeof(r_fragmentSource_BloomFinal), ppVertexStage, &error);
if (shader)
{
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
@@ -551,7 +552,7 @@ bool NzDeferredRenderTechnique::Initialize()
}
shader = RegisterDeferredShader("DeferredFXAA", fragmentSource_FXAA, sizeof(fragmentSource_FXAA), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredFXAA", r_fragmentSource_FXAA, sizeof(r_fragmentSource_FXAA), ppVertexStage, &error);
if (shader)
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
else
@@ -560,7 +561,7 @@ bool NzDeferredRenderTechnique::Initialize()
}
shader = RegisterDeferredShader("DeferredGaussianBlur", fragmentSource_GaussianBlur, sizeof(fragmentSource_GaussianBlur), ppVertexStage, &error);
shader = RegisterDeferredShader("DeferredGaussianBlur", r_fragmentSource_GaussianBlur, sizeof(r_fragmentSource_GaussianBlur), ppVertexStage, &error);
if (shader)
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
else

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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

View File

@@ -1,30 +1,360 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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/ForwardRenderQueue.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Utility/SkeletalMesh.hpp>
#include <Nazara/Utility/StaticMesh.hpp>
#include <Nazara/Graphics/Debug.hpp>
///TODO: Remplacer les sinus/cosinus par une lookup table (va booster les perfs d'un bon x10)
namespace
{
enum ResourceType
enum ObjectType
{
ResourceType_IndexBuffer,
ResourceType_Material,
ResourceType_VertexBuffer
ObjectType_IndexBuffer,
ObjectType_Material,
ObjectType_Texture,
ObjectType_VertexBuffer
};
}
NzForwardRenderQueue::~NzForwardRenderQueue()
void NzForwardRenderQueue::AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos, const NzColor& color)
{
Clear(true);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
billboardVector.push_back(BillboardData{color, position, size, sinCos});
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos = *sinCosPtr++;
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
float defaultAlpha = 1.f;
if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = NzColor(255, 255, 255, static_cast<nzUInt8>(255.f * (*alphaPtr++)));
billboardData->sinCos = *sinCosPtr++;
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f;
if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
float sin = std::sin(NzToRadians(*anglePtr));
float cos = std::cos(NzToRadians(*anglePtr));
anglePtr++;
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos.Set(sin, cos);
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f;
if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
float defaultAlpha = 1.f;
if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
float sin = std::sin(NzToRadians(*anglePtr));
float cos = std::cos(NzToRadians(*anglePtr));
anglePtr++;
billboardData->center = *positionPtr++;
billboardData->color = NzColor(255, 255, 255, static_cast<nzUInt8>(255.f * (*alphaPtr++)));
billboardData->sinCos.Set(sin, cos);
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos = *sinCosPtr++;
billboardData->size.Set(*sizePtr++);
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
float defaultAlpha = 1.f;
if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = NzColor(255, 255, 255, static_cast<nzUInt8>(255.f * (*alphaPtr++)));
billboardData->sinCos = *sinCosPtr++;
billboardData->size.Set(*sizePtr++);
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f;
if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
float sin = std::sin(NzToRadians(*anglePtr));
float cos = std::cos(NzToRadians(*anglePtr));
anglePtr++;
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos.Set(sin, cos);
billboardData->size.Set(*sizePtr++);
billboardData++;
}
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f;
if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
float defaultAlpha = 1.f;
if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
float sin = std::sin(NzToRadians(*anglePtr));
float cos = std::cos(NzToRadians(*anglePtr));
anglePtr++;
billboardData->center = *positionPtr++;
billboardData->color = NzColor(255, 255, 255, static_cast<nzUInt8>(255.f * (*alphaPtr++)));
billboardData->sinCos.Set(sin, cos);
billboardData->size.Set(*sizePtr++);
billboardData++;
}
}
void NzForwardRenderQueue::AddDrawable(const NzDrawable* drawable)
@@ -72,72 +402,81 @@ void NzForwardRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData&
{
if (material->IsEnabled(nzRendererParameter_Blend))
{
// Le matériau est transparent, nous devons rendre ce mesh d'une autre façon (après le rendu des objets opaques et en les triant)
unsigned int index = transparentModelData.size();
transparentModelData.resize(index+1);
TransparentModelData& data = transparentModelData.back();
data.boundingSphere = NzSpheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
data.material = material;
data.meshData = meshData;
data.squaredBoundingSphere = NzSpheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
data.transformMatrix = transformMatrix;
transparentModels.push_back(index);
}
else
{
ModelBatches::iterator it = opaqueModels.find(material);
auto it = opaqueModels.find(material);
if (it == opaqueModels.end())
{
it = opaqueModels.insert(std::make_pair(material, ModelBatches::mapped_type())).first;
material->AddObjectListener(this, ResourceType_Material);
BatchedModelEntry entry(this, ObjectType_Material);
entry.materialListener = material;
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
}
bool& used = std::get<0>(it->second);
bool& enableInstancing = std::get<1>(it->second);
MeshInstanceContainer& meshMap = std::get<2>(it->second);
BatchedModelEntry& entry = it->second;
entry.enabled = true;
used = true;
auto& meshMap = entry.meshMap;
MeshInstanceContainer::iterator it2 = meshMap.find(meshData);
auto it2 = meshMap.find(meshData);
if (it2 == meshMap.end())
{
it2 = meshMap.insert(std::make_pair(meshData, MeshInstanceContainer::mapped_type())).first;
MeshInstanceEntry instanceEntry(this, ObjectType_IndexBuffer, ObjectType_VertexBuffer);
instanceEntry.indexBufferListener = meshData.indexBuffer;
instanceEntry.squaredBoundingSphere = meshAABB.GetSquaredBoundingSphere();
instanceEntry.vertexBufferListener = meshData.vertexBuffer;
NzSpheref& squaredBoundingSphere = it2->second.first;
squaredBoundingSphere.Set(meshAABB.GetSquaredBoundingSphere());
if (meshData.indexBuffer)
meshData.indexBuffer->AddObjectListener(this, ResourceType_IndexBuffer);
meshData.vertexBuffer->AddObjectListener(this, ResourceType_VertexBuffer);
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
}
std::vector<NzMatrix4f>& instances = it2->second.second;
std::vector<NzMatrix4f>& instances = it2->second.instances;
instances.push_back(transformMatrix);
// Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ?
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
enableInstancing = true; // Apparemment oui, activons l'instancing avec ce matériau
entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau
}
}
void NzForwardRenderQueue::AddSprite(const NzSprite* sprite)
void NzForwardRenderQueue::AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay)
{
#if NAZARA_GRAPHICS_SAFE
if (!sprite)
auto matIt = basicSprites.find(material);
if (matIt == basicSprites.end())
{
NazaraError("Invalid sprite");
return;
BatchedBasicSpriteEntry entry(this, ObjectType_Material);
entry.materialListener = material;
matIt = basicSprites.insert(std::make_pair(material, std::move(entry))).first;
}
if (!sprite->IsDrawable())
{
NazaraError("Sprite is not drawable");
return;
}
#endif
BatchedBasicSpriteEntry& entry = matIt->second;
entry.enabled = true;
sprites[sprite->GetMaterial()].push_back(sprite);
auto& overlayMap = entry.overlayMap;
auto overlayIt = overlayMap.find(overlay);
if (overlayIt == overlayMap.end())
{
BatchedSpriteEntry overlayEntry(this, ObjectType_Texture);
overlayEntry.textureListener = overlay;
overlayIt = overlayMap.insert(std::make_pair(overlay, std::move(overlayEntry))).first;
}
auto& spriteVector = overlayIt->second.spriteChains;
spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount}));
}
void NzForwardRenderQueue::Clear(bool fully)
@@ -150,53 +489,55 @@ void NzForwardRenderQueue::Clear(bool fully)
if (fully)
{
for (auto& matIt : opaqueModels)
{
const NzMaterial* material = matIt.first;
material->RemoveObjectListener(this);
MeshInstanceContainer& instances = std::get<2>(matIt.second);
for (auto& instanceIt : instances)
{
const NzMeshData& renderData = instanceIt.first;
if (renderData.indexBuffer)
renderData.indexBuffer->RemoveObjectListener(this);
renderData.vertexBuffer->RemoveObjectListener(this);
}
}
basicSprites.clear();
billboards.clear();
opaqueModels.clear();
sprites.clear();
}
}
void NzForwardRenderQueue::Sort(const NzAbstractViewer* viewer)
{
NzPlanef nearPlane = viewer->GetFrustum().GetPlane(nzFrustumPlane_Near);
NzVector3f viewerPos = viewer->GetEyePosition();
NzVector3f viewerNormal = viewer->GetForward();
std::sort(transparentModels.begin(), transparentModels.end(), [this, &nearPlane, &viewerNormal](unsigned int index1, unsigned int index2)
{
const NzSpheref& sphere1 = transparentModelData[index1].boundingSphere;
const NzSpheref& sphere2 = transparentModelData[index2].boundingSphere;
const NzSpheref& sphere1 = transparentModelData[index1].squaredBoundingSphere;
const NzSpheref& sphere2 = transparentModelData[index2].squaredBoundingSphere;
NzVector3f position1 = sphere1.GetNegativeVertex(viewerNormal);
NzVector3f position2 = sphere2.GetNegativeVertex(viewerNormal);
return nearPlane.Distance(position1) > nearPlane.Distance(position2);
});
for (auto& pair : billboards)
{
const NzMaterial* mat = pair.first;
if (mat->IsDepthSortingEnabled())
{
BatchedBillboardEntry& entry = pair.second;
auto& billboardVector = entry.billboards;
std::sort(billboardVector.begin(), billboardVector.end(), [&viewerPos](const BillboardData& data1, const BillboardData& data2)
{
return viewerPos.SquaredDistance(data1.center) > viewerPos.SquaredDistance(data2.center);
});
}
}
}
bool NzForwardRenderQueue::OnObjectDestroy(const NzRefCounted* object, int index)
{
switch (index)
{
case ResourceType_IndexBuffer:
case ObjectType_IndexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -209,15 +550,21 @@ bool NzForwardRenderQueue::OnObjectDestroy(const NzRefCounted* object, int index
break;
}
case ResourceType_Material:
opaqueModels.erase(static_cast<const NzMaterial*>(object));
break;
case ObjectType_Material:
{
const NzMaterial* material = static_cast<const NzMaterial*>(object);
case ResourceType_VertexBuffer:
basicSprites.erase(material);
billboards.erase(material);
opaqueModels.erase(material);
break;
}
case ObjectType_VertexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -241,11 +588,11 @@ void NzForwardRenderQueue::OnObjectReleased(const NzRefCounted* object, int inde
switch (index)
{
case ResourceType_IndexBuffer:
case ObjectType_IndexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -258,8 +605,26 @@ void NzForwardRenderQueue::OnObjectReleased(const NzRefCounted* object, int inde
break;
}
case ResourceType_Material:
case ObjectType_Material:
{
for (auto it = basicSprites.begin(); it != basicSprites.end(); ++it)
{
if (it->first == object)
{
basicSprites.erase(it);
break;
}
}
for (auto it = billboards.begin(); it != billboards.end(); ++it)
{
if (it->first == object)
{
billboards.erase(it);
break;
}
}
for (auto it = opaqueModels.begin(); it != opaqueModels.end(); ++it)
{
if (it->first == object)
@@ -268,14 +633,33 @@ void NzForwardRenderQueue::OnObjectReleased(const NzRefCounted* object, int inde
break;
}
}
break;
}
case ResourceType_VertexBuffer:
case ObjectType_Texture:
{
for (auto matIt = basicSprites.begin(); matIt != basicSprites.end(); ++matIt)
{
auto& overlayMap = matIt->second.overlayMap;
for (auto overlayIt = overlayMap.begin(); overlayIt != overlayMap.end(); ++overlayIt)
{
if (overlayIt->first == object)
{
overlayMap.erase(overlayIt);
break;
}
}
}
break;
}
case ObjectType_VertexBuffer:
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = std::get<2>(modelPair.second);
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const NzMeshData& renderData = it->first;
@@ -290,6 +674,26 @@ void NzForwardRenderQueue::OnObjectReleased(const NzRefCounted* object, int inde
}
}
bool NzForwardRenderQueue::BatchedBillboardComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
{
const NzUberShader* uberShader1 = mat1->GetShader();
const NzUberShader* uberShader2 = mat2->GetShader();
if (uberShader1 != uberShader2)
return uberShader1 < uberShader2;
const NzShader* shader1 = mat1->GetShaderInstance(nzShaderFlags_Billboard | nzShaderFlags_VertexColor)->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance(nzShaderFlags_Billboard | nzShaderFlags_VertexColor)->GetShader();
if (shader1 != shader2)
return shader1 < shader2;
const NzTexture* diffuseMap1 = mat1->GetDiffuseMap();
const NzTexture* diffuseMap2 = mat2->GetDiffuseMap();
if (diffuseMap1 != diffuseMap2)
return diffuseMap1 < diffuseMap2;
return mat1 < mat2;
}
bool NzForwardRenderQueue::BatchedModelMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
{
const NzUberShader* uberShader1 = mat1->GetShader();
@@ -299,7 +703,6 @@ bool NzForwardRenderQueue::BatchedModelMaterialComparator::operator()(const NzMa
const NzShader* shader1 = mat1->GetShaderInstance()->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance()->GetShader();
if (shader1 != shader2)
return shader1 < shader2;
@@ -320,7 +723,6 @@ bool NzForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const NzM
const NzShader* shader1 = mat1->GetShaderInstance()->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance()->GetShader();
if (shader1 != shader2)
return shader1 < shader2;

View File

@@ -1,13 +1,16 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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/ForwardRenderTechnique.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/OffsetOf.hpp>
#include <Nazara/Graphics/AbstractBackground.hpp>
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/Drawable.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Renderer.hpp>
@@ -22,46 +25,29 @@
namespace
{
static NzIndexBuffer* s_indexBuffer = nullptr;
unsigned int s_maxSprites = 8192;
NzIndexBuffer* BuildIndexBuffer()
struct BillboardPoint
{
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(false, s_maxSprites*6, nzBufferStorage_Hardware, nzBufferUsage_Static));
indexBuffer->SetPersistent(false);
NzColor color;
NzVector3f position;
NzVector2f size;
NzVector2f sinCos; // doit suivre size
NzVector2f uv;
};
NzBufferMapper<NzIndexBuffer> mapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
nzUInt16* indices = static_cast<nzUInt16*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxSprites; ++i)
{
*indices++ = i*4 + 0;
*indices++ = i*4 + 2;
*indices++ = i*4 + 1;
*indices++ = i*4 + 2;
*indices++ = i*4 + 3;
*indices++ = i*4 + 1;
}
return indexBuffer.release();
}
unsigned int s_maxQuads = std::numeric_limits<nzUInt16>::max()/6;
unsigned int s_vertexBufferSize = 4*1024*1024; // 4 MiB
}
NzForwardRenderTechnique::NzForwardRenderTechnique() :
m_spriteBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ_UV), s_maxSprites*4, nzBufferStorage_Hardware, nzBufferUsage_Dynamic),
m_vertexBuffer(nzBufferType_Vertex),
m_maxLightPassPerObject(3)
{
if (!s_indexBuffer)
s_indexBuffer = BuildIndexBuffer();
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
m_indexBuffer = s_indexBuffer;
}
m_vertexBuffer.Create(s_vertexBufferSize, nzDataStorage_Hardware, nzBufferUsage_Dynamic);
NzForwardRenderTechnique::~NzForwardRenderTechnique()
{
if (m_indexBuffer.Reset())
s_indexBuffer = nullptr;
m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer);
m_spriteBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Color_UV), &m_vertexBuffer);
}
void NzForwardRenderTechnique::Clear(const NzScene* scene) const
@@ -87,59 +73,17 @@ bool NzForwardRenderTechnique::Draw(const NzScene* scene) const
if (!m_renderQueue.transparentModels.empty())
DrawTransparentModels(scene);
if (!m_renderQueue.sprites.empty())
DrawSprites(scene);
if (!m_renderQueue.basicSprites.empty())
DrawBasicSprites(scene);
if (!m_renderQueue.billboards.empty())
DrawBillboards(scene);
// Les autres drawables (Exemple: Terrain)
for (const NzDrawable* drawable : m_renderQueue.otherDrawables)
drawable->Draw();
return true;
// Les billboards
/*if (!m_renderQueue.billboards.empty())
{
//NzRenderer::SetIndexBuffer(m_billboardIndexBuffer);
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
NzRenderer::SetShader(m_billboardShader);
NzRenderer::SetVertexBuffer(m_billboardVertexBuffer);
m_billboardShader->SendVector(s_cameraForwardLocation, camera->GetForward());
m_billboardShader->SendVector(s_cameraUpLocation, camera->GetUp());
m_billboardShader->SendVector(s_worldUpLocation, NzVector3f::Up());
// Couleur ambiante de la scène
m_billboardShader->SendColor(m_billboardShader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
m_billboardShader->SendVector(m_billboardShader->GetUniformLocation(nzShaderUniform_CameraPosition), camera->GetPosition());
lightCount = 0;
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
m_renderQueue.lights[0]->Apply(m_billboardShader, 0);
for (auto& matIt : m_renderQueue.billboards)
{
const NzMaterial* material = matIt.first;
auto& billboards = matIt.second;
material->Apply(m_billboardShader);
unsigned int billboardCount = billboards.size();
const NzForwardRenderQueue::BillboardData* data = &billboards[0];
while (billboardCount > 0)
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboards);
billboardCount -= renderedBillboardCount;
m_billboardVertexBuffer->FillVertices(data, 0, renderedBillboardCount, true);
data += renderedBillboardCount;
NzRenderer::DrawPrimitives(nzPrimitiveMode_PointList, 0, renderedBillboardCount);
}
billboards.clear();
}
}*/
}
unsigned int NzForwardRenderTechnique::GetMaxLightPassPerObject() const
@@ -162,19 +106,329 @@ void NzForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int passCount)
m_maxLightPassPerObject = passCount;
}
void NzForwardRenderTechnique::DrawBasicSprites(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
NzRenderer::SetIndexBuffer(&s_quadIndexBuffer);
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
NzRenderer::SetVertexBuffer(&m_spriteBuffer);
for (auto& matIt : m_renderQueue.basicSprites)
{
const NzMaterial* material = matIt.first;
auto& matEntry = matIt.second;
if (matEntry.enabled)
{
auto& overlayMap = matEntry.overlayMap;
for (auto& overlayIt : overlayMap)
{
const NzTexture* overlay = overlayIt.first;
auto& spriteChainVector = overlayIt.second.spriteChains;
unsigned int spriteChainCount = spriteChainVector.size();
if (spriteChainCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
nzUInt32 flags = nzShaderFlags_VertexColor;
if (overlay)
flags |= nzShaderFlags_TextureOverlay;
nzUInt8 overlayUnit;
const NzShader* shader = material->Apply(flags, 0, &overlayUnit);
if (overlay)
{
overlayUnit++;
NzRenderer::SetTexture(overlayUnit, overlay);
NzRenderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
}
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Overlay
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous
unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés
do
{
// On ouvre le buffer en écriture
NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite);
NzVertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
unsigned int spriteCount = 0;
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount()/4);
do
{
NzForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(NzVertexStruct_XYZ_Color_UV));
vertices += count*4;
spriteCount += count;
spriteChainOffset += count;
// Avons-nous traité la chaîne entière ?
if (spriteChainOffset == currentChain.spriteCount)
{
spriteChain++;
spriteChainOffset = 0;
}
}
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, spriteCount*6);
}
while (spriteChain < spriteChainCount);
spriteChainVector.clear();
}
}
// On remet à zéro
matEntry.enabled = false;
}
}
}
bool NzForwardRenderTechnique::Initialize()
{
try
{
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
s_quadIndexBuffer.Reset(false, s_maxQuads*6, nzDataStorage_Hardware, nzBufferUsage_Static);
NzBufferMapper<NzIndexBuffer> mapper(s_quadIndexBuffer, nzBufferAccess_WriteOnly);
nzUInt16* indices = static_cast<nzUInt16*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxQuads; ++i)
{
*indices++ = i*4 + 0;
*indices++ = i*4 + 2;
*indices++ = i*4 + 1;
*indices++ = i*4 + 2;
*indices++ = i*4 + 3;
*indices++ = i*4 + 1;
}
mapper.Unmap(); // Inutile de garder le buffer ouvert plus longtemps
// Quad buffer (utilisé pour l'instancing de billboard et de sprites)
//Note: Les UV sont calculés dans le shader
s_quadVertexBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XY), 4, nzDataStorage_Hardware, nzBufferUsage_Static);
float vertices[2*4] = {
-0.5f, -0.5f,
0.5f, -0.5f,
-0.5f, 0.5f,
0.5f, 0.5f,
};
s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices));
// Déclaration lors du rendu des billboards par sommet
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(BillboardPoint, color));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(BillboardPoint, position));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_TexCoord, nzComponentType_Float2, NzOffsetOf(BillboardPoint, uv));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Userdata0, nzComponentType_Float4, NzOffsetOf(BillboardPoint, size)); // Englobe sincos
// Declaration utilisée lors du rendu des billboards par instancing
// L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData0, nzComponentType_Float3, NzOffsetOf(NzForwardRenderQueue::BillboardData, center));
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData1, nzComponentType_Float4, NzOffsetOf(NzForwardRenderQueue::BillboardData, size)); // Englobe sincos
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData2, nzComponentType_Color, NzOffsetOf(NzForwardRenderQueue::BillboardData, color));
}
catch (const std::exception& e)
{
NazaraError("Failed to initialise: " + NzString(e.what()));
return false;
}
return true;
}
void NzForwardRenderTechnique::Uninitialize()
{
s_quadIndexBuffer.Reset();
s_quadVertexBuffer.Reset();
}
void NzForwardRenderTechnique::DrawBillboards(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
if (NzRenderer::HasCapability(nzRendererCap_Instancing))
{
NzVertexBuffer* instanceBuffer = NzRenderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration);
NzRenderer::SetVertexBuffer(&s_quadVertexBuffer);
for (auto& matIt : m_renderQueue.billboards)
{
const NzMaterial* material = matIt.first;
auto& entry = matIt.second;
auto& billboardVector = entry.billboards;
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply(nzShaderFlags_Billboard | nzShaderFlags_Instancing | nzShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
const NzForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
do
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
data += renderedBillboardCount;
NzRenderer::DrawPrimitivesInstanced(renderedBillboardCount, nzPrimitiveMode_TriangleStrip, 0, 4);
}
while (billboardCount > 0);
billboardVector.clear();
}
}
}
else
{
NzRenderer::SetIndexBuffer(&s_quadIndexBuffer);
NzRenderer::SetVertexBuffer(&m_billboardPointBuffer);
for (auto& matIt : m_renderQueue.billboards)
{
const NzMaterial* material = matIt.first;
auto& entry = matIt.second;
auto& billboardVector = entry.billboards;
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply(nzShaderFlags_Billboard | nzShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
const NzForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount()/4);
do
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
NzBufferMapper<NzVertexBuffer> vertexMapper(m_billboardPointBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4);
BillboardPoint* vertices = reinterpret_cast<BillboardPoint*>(vertexMapper.GetPointer());
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
{
const NzForwardRenderQueue::BillboardData& billboard = *data++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(0.f, 1.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(1.f, 1.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(0.f, 0.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(1.f, 0.f);
vertices++;
}
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedBillboardCount*6);
}
while (billboardCount > 0);
billboardVector.clear();
}
}
}
}
void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const LightUniforms* lightUniforms = nullptr;
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
for (auto& matIt : m_renderQueue.opaqueModels)
{
bool& used = std::get<0>(matIt.second);
if (used)
auto& matEntry = matIt.second;
if (matEntry.enabled)
{
bool& renderQueueInstancing = std::get<1>(matIt.second);
NzForwardRenderQueue::MeshInstanceContainer& meshInstances = std::get<2>(matIt.second);
NzForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
if (!meshInstances.empty())
{
@@ -183,7 +437,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches
// (Le deferred shading n'a pas ce problème)
bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || m_lights.IsEmpty()) && renderQueueInstancing;
bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || m_lights.IsEmpty()) && matEntry.instancingEnabled;
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply((instancing) ? nzShaderFlags_Instancing : 0);
@@ -191,23 +445,25 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Index des uniformes d'éclairage dans le shader
lightUniforms = GetLightUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
lastShader = shader;
}
// Meshes
for (auto& subMeshIt : meshInstances)
for (auto& meshIt : meshInstances)
{
const NzMeshData& meshData = subMeshIt.first;
const NzSpheref& boundingSphere = subMeshIt.second.first;
std::vector<NzMatrix4f>& instances = subMeshIt.second.second;
const NzMeshData& meshData = meshIt.first;
auto& meshEntry = meshIt.second;
const NzSpheref& squaredBoundingSphere = meshEntry.squaredBoundingSphere;
std::vector<NzMatrix4f>& instances = meshEntry.instances;
if (!instances.empty())
{
@@ -215,20 +471,20 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> DrawFunc;
std::function<void(unsigned int, nzPrimitiveMode, unsigned int, unsigned int)> InstancedDrawFunc;
NzRenderer::DrawCall drawFunc;
NzRenderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount;
if (indexBuffer)
{
DrawFunc = NzRenderer::DrawIndexedPrimitives;
InstancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
drawFunc = NzRenderer::DrawIndexedPrimitives;
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
indexCount = indexBuffer->GetIndexCount();
}
else
{
DrawFunc = NzRenderer::DrawPrimitives;
InstancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
drawFunc = NzRenderer::DrawPrimitives;
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
indexCount = vertexBuffer->GetVertexCount();
}
@@ -250,7 +506,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
for (unsigned int pass = 0; pass < passCount; ++pass)
{
if (lightUniforms->exists)
if (shaderUniforms->hasLightUniforms)
{
unsigned int renderedLightCount = std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
lightCount -= renderedLightCount;
@@ -267,15 +523,15 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
}
for (unsigned int i = 0; i < renderedLightCount; ++i)
m_directionalLights.GetLight(lightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
m_directionalLights.GetLight(lightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
for (unsigned int i = renderedLightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
}
const NzMatrix4f* instanceMatrices = &instances[0];
unsigned int instanceCount = instances.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing)
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre maximum d'instances en une fois
while (instanceCount > 0)
{
@@ -288,7 +544,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
instanceMatrices += renderedInstanceCount;
// Et on affiche
InstancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
}
}
@@ -298,12 +554,12 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
}
else
{
if (lightUniforms->exists)
if (shaderUniforms->hasLightUniforms)
{
for (const NzMatrix4f& matrix : instances)
{
unsigned int directionalLightCount = m_directionalLights.GetLightCount();
unsigned int otherLightCount = m_lights.ComputeClosestLights(matrix.GetTranslation() + boundingSphere.GetPosition(), boundingSphere.radius, m_maxLightPassPerObject*NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - directionalLightCount);
unsigned int otherLightCount = m_lights.ComputeClosestLights(matrix.GetTranslation() + squaredBoundingSphere.GetPosition(), squaredBoundingSphere.radius, m_maxLightPassPerObject*NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - directionalLightCount);
unsigned int lightCount = directionalLightCount + otherLightCount;
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
@@ -332,17 +588,17 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
for (unsigned int i = 0; i < renderedLightCount; ++i)
{
if (directionalLightIndex >= directionalLightCount)
m_lights.GetResult(otherLightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
m_lights.GetResult(otherLightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
else
m_directionalLights.GetLight(directionalLightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
m_directionalLights.GetLight(directionalLightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
}
// On désactive l'éventuel surplus
for (unsigned int i = renderedLightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
// Et on passe à l'affichage
DrawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
NzRenderer::Enable(nzRendererParameter_Blend, false);
@@ -351,13 +607,13 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
}
else
{
// Sans instancing, on doit effectuer un drawcall pour chaque instance
// Sans instancing, on doit effectuer un draw call pour chaque instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
// À cause du temps de modification du buffer d'instancing
for (const NzMatrix4f& matrix : instances)
{
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
DrawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
}
}
@@ -367,84 +623,8 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
}
// Et on remet à zéro les données
renderQueueInstancing = false;
used = false;
}
}
}
void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShader* lastShader = nullptr;
NzRenderer::SetIndexBuffer(m_indexBuffer);
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
NzRenderer::SetVertexBuffer(&m_spriteBuffer);
for (auto& matIt : m_renderQueue.sprites)
{
const NzMaterial* material = matIt.first;
auto& spriteVector = matIt.second;
unsigned int spriteCount = spriteVector.size();
if (spriteCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply();
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
lastShader = shader;
}
const NzSprite** spritePtr = &spriteVector[0];
do
{
unsigned int renderedSpriteCount = std::min(spriteCount, 64U);
spriteCount -= renderedSpriteCount;
NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedSpriteCount*4);
NzVertexStruct_XYZ_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_UV*>(vertexMapper.GetPointer());
for (unsigned int i = 0; i < renderedSpriteCount; ++i)
{
const NzSprite* sprite = *spritePtr++;
const NzRectf& textureCoords = sprite->GetTextureCoords();
const NzVector2f& halfSize = sprite->GetSize()*0.5f;
NzVector3f center = sprite->GetPosition();
NzQuaternionf rotation = sprite->GetRotation();
vertices->position = center + rotation * NzVector3f(-halfSize.x, -halfSize.y, 0.f);
vertices->uv.Set(textureCoords.x, textureCoords.y + textureCoords.height);
vertices++;
vertices->position = center + rotation * NzVector3f(halfSize.x, -halfSize.y, 0.f);
vertices->uv.Set(textureCoords.width, textureCoords.y + textureCoords.height);
vertices++;
vertices->position = center + rotation * NzVector3f(-halfSize.x, halfSize.y, 0.f);
vertices->uv.Set(textureCoords.x, textureCoords.y);
vertices++;
vertices->position = center + rotation * NzVector3f(halfSize.x, halfSize.y, 0.f);
vertices->uv.Set(textureCoords.width, textureCoords.y);
vertices++;
}
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedSpriteCount*6);
}
while (spriteCount > 0);
spriteVector.clear();
matEntry.enabled = false;
matEntry.instancingEnabled = false;
}
}
}
@@ -452,8 +632,8 @@ void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const
void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const LightUniforms* lightUniforms = nullptr;
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
unsigned int lightCount = 0;
for (unsigned int index : m_renderQueue.transparentModels)
@@ -469,18 +649,18 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Index des uniformes d'éclairage dans le shader
lightUniforms = GetLightUniforms(shader);
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, viewer->GetEyePosition());
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
lightCount = std::min(m_directionalLights.GetLightCount(), NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
for (unsigned int i = 0; i < lightCount; ++i)
m_directionalLights.GetLight(i)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
m_directionalLights.GetLight(i)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
lastShader = shader;
}
@@ -493,17 +673,17 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> DrawFunc;
NzRenderer::DrawCall drawFunc;
unsigned int indexCount;
if (indexBuffer)
{
DrawFunc = NzRenderer::DrawIndexedPrimitives;
drawFunc = NzRenderer::DrawIndexedPrimitives;
indexCount = indexBuffer->GetIndexCount();
}
else
{
DrawFunc = NzRenderer::DrawPrimitives;
drawFunc = NzRenderer::DrawPrimitives;
indexCount = vertexBuffer->GetVertexCount();
}
@@ -513,47 +693,58 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
// Calcul des lumières les plus proches
if (lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS && !m_lights.IsEmpty())
{
unsigned int count = std::min(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - lightCount, m_lights.ComputeClosestLights(matrix.GetTranslation() + modelData.boundingSphere.GetPosition(), modelData.boundingSphere.radius, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS));
NzVector3f position = matrix.GetTranslation() + modelData.squaredBoundingSphere.GetPosition();
float radius = modelData.squaredBoundingSphere.radius;
unsigned int closestLightCount = m_lights.ComputeClosestLights(position, radius, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS);
unsigned int count = std::min(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - lightCount, closestLightCount);
for (unsigned int i = 0; i < count; ++i)
m_lights.GetResult(i)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*(lightCount++));
m_lights.GetResult(i)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*(lightCount++));
}
for (unsigned int i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i);
NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i);
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
DrawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
}
const NzForwardRenderTechnique::LightUniforms* NzForwardRenderTechnique::GetLightUniforms(const NzShader* shader) const
const NzForwardRenderTechnique::ShaderUniforms* NzForwardRenderTechnique::GetShaderUniforms(const NzShader* shader) const
{
auto it = m_lightUniforms.find(shader);
if (it != m_lightUniforms.end())
return &(it->second);
else
auto it = m_shaderUniforms.find(shader);
if (it == m_shaderUniforms.end())
{
ShaderUniforms uniforms;
uniforms.eyePosition = shader->GetUniformLocation("EyePosition");
uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient");
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
int type0Location = shader->GetUniformLocation("Lights[0].type");
int type1Location = shader->GetUniformLocation("Lights[1].type");
LightUniforms lightUniforms;
if (type0Location > 0 && type1Location > 0)
{
lightUniforms.exists = true;
lightUniforms.offset = type1Location - type0Location;
lightUniforms.uniforms.ubo = false;
lightUniforms.uniforms.locations.type = type0Location;
lightUniforms.uniforms.locations.color = shader->GetUniformLocation("Lights[0].color");
lightUniforms.uniforms.locations.factors = shader->GetUniformLocation("Lights[0].factors");
lightUniforms.uniforms.locations.parameters1 = shader->GetUniformLocation("Lights[0].parameters1");
lightUniforms.uniforms.locations.parameters2 = shader->GetUniformLocation("Lights[0].parameters2");
lightUniforms.uniforms.locations.parameters3 = shader->GetUniformLocation("Lights[0].parameters3");
uniforms.hasLightUniforms = true;
uniforms.lightOffset = type1Location - type0Location;
uniforms.lightUniforms.ubo = false;
uniforms.lightUniforms.locations.type = type0Location;
uniforms.lightUniforms.locations.color = shader->GetUniformLocation("Lights[0].color");
uniforms.lightUniforms.locations.factors = shader->GetUniformLocation("Lights[0].factors");
uniforms.lightUniforms.locations.parameters1 = shader->GetUniformLocation("Lights[0].parameters1");
uniforms.lightUniforms.locations.parameters2 = shader->GetUniformLocation("Lights[0].parameters2");
uniforms.lightUniforms.locations.parameters3 = shader->GetUniformLocation("Lights[0].parameters3");
}
else
lightUniforms.exists = false;
uniforms.hasLightUniforms = false;
auto pair = m_lightUniforms.emplace(shader, lightUniforms);
return &(pair.first->second);
it = m_shaderUniforms.emplace(shader, uniforms).first;
}
return &it->second;
}
NzIndexBuffer NzForwardRenderTechnique::s_quadIndexBuffer;
NzVertexBuffer NzForwardRenderTechnique::s_quadVertexBuffer;
NzVertexDeclaration NzForwardRenderTechnique::s_billboardInstanceDeclaration;
NzVertexDeclaration NzForwardRenderTechnique::s_billboardVertexDeclaration;

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 Jérôme Leclercq
// 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
@@ -9,13 +9,16 @@
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/DeferredRenderTechnique.hpp>
#include <Nazara/Graphics/ForwardRenderTechnique.hpp>
#include <Nazara/Graphics/GuillotineTextureAtlas.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/ParticleDeclaration.hpp>
#include <Nazara/Graphics/RenderTechniques.hpp>
#include <Nazara/Graphics/SkinningManager.hpp>
#include <Nazara/Graphics/Loaders/Mesh.hpp>
#include <Nazara/Graphics/Loaders/OBJ.hpp>
#include <Nazara/Graphics/Loaders/Texture.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Utility/Font.hpp>
#include <Nazara/Graphics/Debug.hpp>
bool NzGraphics::Initialize()
@@ -44,6 +47,12 @@ bool NzGraphics::Initialize()
return false;
}
if (!NzParticleDeclaration::Initialize())
{
NazaraError("Failed to initialize particle declarations");
return false;
}
if (!NzSkinningManager::Initialize())
{
NazaraError("Failed to initialize skinning manager");
@@ -58,14 +67,26 @@ bool NzGraphics::Initialize()
NzLoaders_Texture_Register();
// RenderTechniques
if (!NzForwardRenderTechnique::Initialize())
{
NazaraError("Failed to initialize Forward Rendering");
return false;
}
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_BasicForward), 0, []() -> NzAbstractRenderTechnique* { return new NzForwardRenderTechnique; });
if (NzDeferredRenderTechnique::IsSupported())
{
NzDeferredRenderTechnique::Initialize();
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_DeferredShading), 20, []() -> NzAbstractRenderTechnique* { return new NzDeferredRenderTechnique; });
if (NzDeferredRenderTechnique::Initialize())
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_DeferredShading), 20, []() -> NzAbstractRenderTechnique* { return new NzDeferredRenderTechnique; });
else
{
NazaraWarning("Failed to initialize Deferred Rendering");
}
}
NzFont::SetDefaultAtlas(std::make_shared<NzGuillotineTextureAtlas>());
onExit.Reset();
NazaraNotice("Initialized: Graphics module");
@@ -91,13 +112,40 @@ void NzGraphics::Uninitialize()
// Libération du module
s_moduleReferenceCounter = 0;
// Libération de l'atlas s'il vient de nous
std::shared_ptr<NzAbstractAtlas> defaultAtlas = NzFont::GetDefaultAtlas();
if (defaultAtlas && defaultAtlas->GetStorage() & nzDataStorage_Hardware)
{
NzFont::SetDefaultAtlas(nullptr);
// La police par défaut peut faire vivre un atlas hardware après la libération du module (ce qui va être problématique)
// du coup, si la police par défaut utilise un atlas hardware, on lui enlève.
// Je n'aime pas cette solution mais je n'en ai pas de meilleure sous la main pour l'instant
if (!defaultAtlas.unique())
{
// Encore au moins une police utilise l'atlas
NzFont* defaultFont = NzFont::GetDefault();
defaultFont->SetAtlas(nullptr);
if (!defaultAtlas.unique())
{
// Toujours pas seuls propriétaires ? Ah ben zut.
NazaraWarning("Default font atlas uses hardware storage and is still used");
}
}
}
defaultAtlas.reset();
// Loaders
NzLoaders_Mesh_Unregister();
NzLoaders_OBJ_Unregister();
NzLoaders_Texture_Unregister();
NzDeferredRenderTechnique::Uninitialize();
NzForwardRenderTechnique::Uninitialize();
NzMaterial::Uninitialize();
NzParticleDeclaration::Uninitialize();
NzSkinningManager::Uninitialize();
NazaraNotice("Uninitialized: Graphics module");

Some files were not shown because too many files have changed in this diff Show More