Switch from Nz prefix to namespace Nz

What a huge commit


Former-commit-id: 38ac5eebf70adc1180f571f6006192d28fb99897
This commit is contained in:
Lynix
2015-09-25 19:20:05 +02:00
parent c214251ecf
commit df8da275c4
609 changed files with 68265 additions and 66534 deletions

View File

@@ -23,351 +23,354 @@
#include <Nazara/Renderer/Debug.hpp>
namespace
namespace Nz
{
thread_local const NzContext* s_currentContext = nullptr;
thread_local const NzContext* s_threadContext = nullptr;
void CALLBACK DebugCallback(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char* message, const void* userParam)
namespace
{
NazaraUnused(length);
thread_local const Context* s_currentContext = nullptr;
thread_local const Context* s_threadContext = nullptr;
NzStringStream ss;
ss << "OpenGL debug message (ID: 0x" << NzString::Number(id, 16) << "):\n";
ss << "Sent by context: " << userParam;
ss << "\n-Source: ";
switch (source)
void CALLBACK DebugCallback(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char* message, const void* userParam)
{
case GL_DEBUG_SOURCE_API:
ss << "OpenGL API";
break;
NazaraUnused(length);
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
ss << "Operating system";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
ss << "Shader compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
ss << "Third party";
break;
case GL_DEBUG_SOURCE_APPLICATION:
ss << "Application";
break;
case GL_DEBUG_SOURCE_OTHER:
ss << "Other";
break;
default:
// Peut être rajouté par une extension
ss << "Unknown";
break;
}
ss << '\n';
ss << "-Type: ";
switch (type)
{
case GL_DEBUG_TYPE_ERROR:
ss << "Error";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
ss << "Deprecated behavior";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
ss << "Undefined behavior";
break;
case GL_DEBUG_TYPE_PORTABILITY:
ss << "Portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE:
ss << "Performance";
break;
case GL_DEBUG_TYPE_OTHER:
ss << "Other";
break;
default:
// Peut être rajouté par une extension
ss << "Unknown";
break;
}
ss << '\n';
ss << "-Severity: ";
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH:
ss << "High";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
ss << "Medium";
break;
case GL_DEBUG_SEVERITY_LOW:
ss << "Low";
break;
default:
// Peut être rajouté par une extension
ss << "Unknown";
break;
}
ss << '\n';
ss << "Message: " << message << '\n';
NazaraNotice(ss);
}
}
NzContext::~NzContext()
{
OnContextRelease(this);
Destroy();
}
bool NzContext::Create(const NzContextParameters& parameters)
{
Destroy();
m_parameters = parameters;
if (m_parameters.shared && !m_parameters.shareContext)
m_parameters.shareContext = s_reference.get();
std::unique_ptr<NzContextImpl> impl(new NzContextImpl);
if (!impl->Create(m_parameters))
{
NazaraError("Failed to create context implementation");
return false;
}
m_impl = impl.release();
NzCallOnExit onExit([this] () { Destroy(); });
if (!SetActive(true))
{
NazaraError("Failed to activate context");
return false;
}
if (m_parameters.antialiasingLevel > 0)
glEnable(GL_MULTISAMPLE);
if (m_parameters.debugMode && NzOpenGL::IsSupported(nzOpenGLExtension_DebugOutput))
{
glDebugMessageCallback(&DebugCallback, this);
#ifdef NAZARA_DEBUG
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
#endif
}
onExit.Reset();
return true;
}
void NzContext::Destroy()
{
if (m_impl)
{
OnContextDestroy(this);
NzOpenGL::OnContextDestruction(this);
SetActive(false);
m_impl->Destroy();
delete m_impl;
m_impl = nullptr;
}
}
void NzContext::EnableVerticalSync(bool enabled)
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return;
}
#endif
m_impl->EnableVerticalSync(enabled);
}
const NzContextParameters& NzContext::GetParameters() const
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
NazaraError("No context has been created");
#endif
return m_parameters;
}
bool NzContext::IsActive() const
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return false;
}
#endif
return s_currentContext == this;
}
bool NzContext::SetActive(bool active) const
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return false;
}
#endif
// Si le contexte est déjà activé/désactivé
if ((s_currentContext == this) == active)
return true;
if (active)
{
if (!m_impl->Activate())
return false;
s_currentContext = this;
}
else
{
if (!NzContextImpl::Desactivate())
return false;
s_currentContext = nullptr;
}
NzOpenGL::OnContextChanged(s_currentContext);
return true;
}
void NzContext::SwapBuffers()
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return;
}
if (!m_parameters.doubleBuffered)
{
NazaraError("Context is not double buffered");
return;
}
#endif
m_impl->SwapBuffers();
}
bool NzContext::EnsureContext()
{
if (!s_currentContext)
{
if (!s_threadContext)
{
std::unique_ptr<NzContext> context(new NzContext);
if (!context->Create())
StringStream ss;
ss << "OpenGL debug message (ID: 0x" << String::Number(id, 16) << "):\n";
ss << "Sent by context: " << userParam;
ss << "\n-Source: ";
switch (source)
{
NazaraError("Failed to create context");
case GL_DEBUG_SOURCE_API:
ss << "OpenGL API";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
ss << "Operating system";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
ss << "Shader compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
ss << "Third party";
break;
case GL_DEBUG_SOURCE_APPLICATION:
ss << "Application";
break;
case GL_DEBUG_SOURCE_OTHER:
ss << "Other";
break;
default:
// Peut être rajouté par une extension
ss << "Unknown";
break;
}
ss << '\n';
ss << "-Type: ";
switch (type)
{
case GL_DEBUG_TYPE_ERROR:
ss << "Error";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
ss << "Deprecated behavior";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
ss << "Undefined behavior";
break;
case GL_DEBUG_TYPE_PORTABILITY:
ss << "Portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE:
ss << "Performance";
break;
case GL_DEBUG_TYPE_OTHER:
ss << "Other";
break;
default:
// Peut être rajouté par une extension
ss << "Unknown";
break;
}
ss << '\n';
ss << "-Severity: ";
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH:
ss << "High";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
ss << "Medium";
break;
case GL_DEBUG_SEVERITY_LOW:
ss << "Low";
break;
default:
// Peut être rajouté par une extension
ss << "Unknown";
break;
}
ss << '\n';
ss << "Message: " << message << '\n';
NazaraNotice(ss);
}
}
Context::~Context()
{
OnContextRelease(this);
Destroy();
}
bool Context::Create(const ContextParameters& parameters)
{
Destroy();
m_parameters = parameters;
if (m_parameters.shared && !m_parameters.shareContext)
m_parameters.shareContext = s_reference.get();
std::unique_ptr<ContextImpl> impl(new ContextImpl);
if (!impl->Create(m_parameters))
{
NazaraError("Failed to create context implementation");
return false;
}
m_impl = impl.release();
CallOnExit onExit([this] () { Destroy(); });
if (!SetActive(true))
{
NazaraError("Failed to activate context");
return false;
}
if (m_parameters.antialiasingLevel > 0)
glEnable(GL_MULTISAMPLE);
if (m_parameters.debugMode && OpenGL::IsSupported(OpenGLExtension_DebugOutput))
{
glDebugMessageCallback(&DebugCallback, this);
#ifdef NAZARA_DEBUG
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
#endif
}
onExit.Reset();
return true;
}
void Context::Destroy()
{
if (m_impl)
{
OnContextDestroy(this);
OpenGL::OnContextDestruction(this);
SetActive(false);
m_impl->Destroy();
delete m_impl;
m_impl = nullptr;
}
}
void Context::EnableVerticalSync(bool enabled)
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return;
}
#endif
m_impl->EnableVerticalSync(enabled);
}
const ContextParameters& Context::GetParameters() const
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
NazaraError("No context has been created");
#endif
return m_parameters;
}
bool Context::IsActive() const
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return false;
}
#endif
return s_currentContext == this;
}
bool Context::SetActive(bool active) const
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return false;
}
#endif
// Si le contexte est déjà activé/désactivé
if ((s_currentContext == this) == active)
return true;
if (active)
{
if (!m_impl->Activate())
return false;
s_currentContext = this;
}
else
{
if (!ContextImpl::Desactivate())
return false;
s_currentContext = nullptr;
}
OpenGL::OnContextChanged(s_currentContext);
return true;
}
void Context::SwapBuffers()
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return;
}
if (!m_parameters.doubleBuffered)
{
NazaraError("Context is not double buffered");
return;
}
#endif
m_impl->SwapBuffers();
}
bool Context::EnsureContext()
{
if (!s_currentContext)
{
if (!s_threadContext)
{
std::unique_ptr<Context> context(new Context);
if (!context->Create())
{
NazaraError("Failed to create context");
return false;
}
s_threadContext = context.get();
s_contexts.emplace_back(std::move(context));
}
s_threadContext = context.get();
s_contexts.emplace_back(std::move(context));
if (!s_threadContext->SetActive(true))
{
NazaraError("Failed to active thread context");
return false;
}
}
if (!s_threadContext->SetActive(true))
return true;
}
const Context* Context::GetCurrent()
{
return s_currentContext;
}
const Context* Context::GetReference()
{
return s_reference.get();
}
const Context* Context::GetThreadContext()
{
EnsureContext();
return s_threadContext;
}
bool Context::Initialize()
{
if (!ContextLibrary::Initialize())
{
NazaraError("Failed to active thread context");
NazaraError("Failed to initialise library");
return false;
}
ContextParameters parameters;
parameters.shared = false; // Difficile de partager le contexte de référence avec lui-même
std::unique_ptr<Context> reference(new Context);
if (!reference->Create(parameters))
{
NazaraError("Failed to create reference context");
return false;
}
// Le contexte de référence doit rester désactivé pour le partage
if (!reference->SetActive(false))
{
NazaraError("Failed to desactive reference context");
return false;
}
s_reference = std::move(reference);
// Le contexte de référence est partagé par défaut avec les autres contextes
ContextParameters::defaultShareContext = s_reference.get();
return true;
}
return true;
}
const NzContext* NzContext::GetCurrent()
{
return s_currentContext;
}
const NzContext* NzContext::GetReference()
{
return s_reference.get();
}
const NzContext* NzContext::GetThreadContext()
{
EnsureContext();
return s_threadContext;
}
bool NzContext::Initialize()
{
if (!NzContextLibrary::Initialize())
void Context::Uninitialize()
{
NazaraError("Failed to initialise library");
return false;
ContextLibrary::Uninitialize();
s_contexts.clear(); // On supprime tous les contextes créés
s_reference.reset();
}
NzContextParameters parameters;
parameters.shared = false; // Difficile de partager le contexte de référence avec lui-même
std::unique_ptr<NzContext> reference(new NzContext);
if (!reference->Create(parameters))
{
NazaraError("Failed to create reference context");
return false;
}
// Le contexte de référence doit rester désactivé pour le partage
if (!reference->SetActive(false))
{
NazaraError("Failed to desactive reference context");
return false;
}
s_reference = std::move(reference);
// Le contexte de référence est partagé par défaut avec les autres contextes
NzContextParameters::defaultShareContext = s_reference.get();
return true;
std::unique_ptr<Context> Context::s_reference;
std::vector<std::unique_ptr<Context>> Context::s_contexts;
ContextLibrary::LibraryMap Context::s_library;
}
void NzContext::Uninitialize()
{
NzContextLibrary::Uninitialize();
s_contexts.clear(); // On supprime tous les contextes créés
s_reference.reset();
}
std::unique_ptr<NzContext> NzContext::s_reference;
std::vector<std::unique_ptr<NzContext>> NzContext::s_contexts;
NzContextLibrary::LibraryMap NzContext::s_library;

View File

@@ -6,27 +6,30 @@
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Debug.hpp>
// Version majeure d'OpenGL, initialisé par NzOpenGL::Initialize()
nzUInt8 NzContextParameters::defaultMajorVersion;
namespace Nz
{
// Version majeure d'OpenGL, initialisé par OpenGL::Initialize()
UInt8 ContextParameters::defaultMajorVersion;
// Version majeure d'OpenGL, initialisé par NzOpenGL::Initialize()
nzUInt8 NzContextParameters::defaultMinorVersion;
// Version majeure d'OpenGL, initialisé par OpenGL::Initialize()
UInt8 ContextParameters::defaultMinorVersion;
// Contexte de partage par défaut, initialisé par NzOpenGL::Initialize()
const NzContext* NzContextParameters::defaultShareContext = nullptr;
// Contexte de partage par défaut, initialisé par OpenGL::Initialize()
const Context* ContextParameters::defaultShareContext = nullptr;
// Si possible, garder la compatibilité avec les fonctionnalités dépréciées
bool NzContextParameters::defaultCompatibilityProfile = false;
// Si possible, garder la compatibilité avec les fonctionnalités dépréciées
bool ContextParameters::defaultCompatibilityProfile = false;
// Mode debug d'OpenGL par défaut
#if NAZARA_RENDERER_OPENGL_DEBUG || defined(NAZARA_DEBUG)
bool NzContextParameters::defaultDebugMode = true;
#else
bool NzContextParameters::defaultDebugMode = false;
#endif
// Mode debug d'OpenGL par défaut
#if NAZARA_RENDERER_OPENGL_DEBUG || defined(NAZARA_DEBUG)
bool ContextParameters::defaultDebugMode = true;
#else
bool ContextParameters::defaultDebugMode = false;
#endif
// Active le double-buffering sur les contextes
bool NzContextParameters::defaultDoubleBuffered = false;
// Active le double-buffering sur les contextes
bool ContextParameters::defaultDoubleBuffered = false;
// Active le partage des ressources entre contextes (Via le defaultShareContext)
bool NzContextParameters::defaultShared = true;
// Active le partage des ressources entre contextes (Via le defaultShareContext)
bool ContextParameters::defaultShared = true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,123 +11,126 @@
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
NzGpuQuery::NzGpuQuery() :
m_id(0)
namespace Nz
{
if (IsSupported())
GpuQuery::GpuQuery() :
m_id(0)
{
NzContext::EnsureContext();
if (IsSupported())
{
Context::EnsureContext();
glGenQueries(1, reinterpret_cast<GLuint*>(&m_id));
}
else
{
NazaraError("Occlusion queries not supported");
return;
glGenQueries(1, reinterpret_cast<GLuint*>(&m_id));
}
else
{
NazaraError("Occlusion queries not supported");
return;
}
#ifdef NAZARA_DEBUG
if (!m_id)
{
NazaraError("Failed to create occlusion query");
throw std::runtime_error("Constructor failed");
}
#endif
}
#ifdef NAZARA_DEBUG
if (!m_id)
GpuQuery::~GpuQuery()
{
NazaraError("Failed to create occlusion query");
throw std::runtime_error("Constructor failed");
}
#endif
}
if (m_id)
{
Context::EnsureContext();
NzGpuQuery::~NzGpuQuery()
{
if (m_id)
{
NzContext::EnsureContext();
GLuint query = static_cast<GLuint>(m_id);
glDeleteQueries(1, &query);
}
}
void NzGpuQuery::Begin(nzGpuQueryMode mode)
{
#ifdef NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
#endif
#if NAZARA_RENDERER_SAFE
if (!IsModeSupported(mode))
{
NazaraError("Mode (0x" + NzString::Number(mode, 16) + ") not supported");
return;
}
#endif
m_mode = mode;
glBeginQuery(NzOpenGL::QueryMode[mode], m_id);
}
void NzGpuQuery::End()
{
#ifdef NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
#endif
glEndQuery(NzOpenGL::QueryMode[m_mode]);
}
unsigned int NzGpuQuery::GetResult() const
{
NzContext::EnsureContext();
GLuint result;
glGetQueryObjectuiv(m_id, GL_QUERY_RESULT, &result);
return result;
}
bool NzGpuQuery::IsResultAvailable() const
{
NzContext::EnsureContext();
GLint available;
glGetQueryObjectiv(m_id, GL_QUERY_RESULT_AVAILABLE, &available);
return available == GL_TRUE;
}
unsigned int NzGpuQuery::GetOpenGLID() const
{
return m_id;
}
bool NzGpuQuery::IsModeSupported(nzGpuQueryMode mode)
{
switch (mode)
{
case nzGpuQueryMode_AnySamplesPassed:
case nzGpuQueryMode_TimeElapsed:
return NzOpenGL::GetVersion() >= 330;
case nzGpuQueryMode_AnySamplesPassedConservative:
return NzOpenGL::GetVersion() >= 430;
case nzGpuQueryMode_PrimitiveGenerated:
case nzGpuQueryMode_SamplesPassed:
case nzGpuQueryMode_TransformFeedbackPrimitivesWritten:
return true;
GLuint query = static_cast<GLuint>(m_id);
glDeleteQueries(1, &query);
}
}
NazaraError("Gpu Query mode not handled (0x" + NzString::Number(mode, 16) + ')');
return false;
}
void GpuQuery::Begin(GpuQueryMode mode)
{
#ifdef NAZARA_DEBUG
if (Context::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
#endif
bool NzGpuQuery::IsSupported()
{
return NzRenderer::HasCapability(nzRendererCap_OcclusionQuery);
#if NAZARA_RENDERER_SAFE
if (!IsModeSupported(mode))
{
NazaraError("Mode (0x" + String::Number(mode, 16) + ") not supported");
return;
}
#endif
m_mode = mode;
glBeginQuery(OpenGL::QueryMode[mode], m_id);
}
void GpuQuery::End()
{
#ifdef NAZARA_DEBUG
if (Context::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
#endif
glEndQuery(OpenGL::QueryMode[m_mode]);
}
unsigned int GpuQuery::GetResult() const
{
Context::EnsureContext();
GLuint result;
glGetQueryObjectuiv(m_id, GL_QUERY_RESULT, &result);
return result;
}
bool GpuQuery::IsResultAvailable() const
{
Context::EnsureContext();
GLint available;
glGetQueryObjectiv(m_id, GL_QUERY_RESULT_AVAILABLE, &available);
return available == GL_TRUE;
}
unsigned int GpuQuery::GetOpenGLID() const
{
return m_id;
}
bool GpuQuery::IsModeSupported(GpuQueryMode mode)
{
switch (mode)
{
case GpuQueryMode_AnySamplesPassed:
case GpuQueryMode_TimeElapsed:
return OpenGL::GetVersion() >= 330;
case GpuQueryMode_AnySamplesPassedConservative:
return OpenGL::GetVersion() >= 430;
case GpuQueryMode_PrimitiveGenerated:
case GpuQueryMode_SamplesPassed:
case GpuQueryMode_TransformFeedbackPrimitivesWritten:
return true;
}
NazaraError("Gpu Query mode not handled (0x" + String::Number(mode, 16) + ')');
return false;
}
bool GpuQuery::IsSupported()
{
return Renderer::HasCapability(RendererCap_OcclusionQuery);
}
}

View File

@@ -11,124 +11,127 @@
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
NzHardwareBuffer::NzHardwareBuffer(NzBuffer* parent, nzBufferType type) :
m_type(type),
m_parent(parent)
namespace Nz
{
}
NzHardwareBuffer::~NzHardwareBuffer() = default;
bool NzHardwareBuffer::Create(unsigned int size, nzBufferUsage usage)
{
NzContext::EnsureContext();
m_buffer = 0;
glGenBuffers(1, &m_buffer);
NzOpenGL::BindBuffer(m_type, m_buffer);
glBufferData(NzOpenGL::BufferTarget[m_type], size, nullptr, NzOpenGL::BufferUsage[usage]);
return true;
}
void NzHardwareBuffer::Destroy()
{
NzContext::EnsureContext();
NzOpenGL::DeleteBuffer(m_type, m_buffer);
}
bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard)
{
NzContext::EnsureContext();
unsigned int totalSize = m_parent->GetSize();
if (!forceDiscard)
forceDiscard = (size == totalSize);
NzOpenGL::BindBuffer(m_type, m_buffer);
// Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil
// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
if (size < 32*1024)
HardwareBuffer::HardwareBuffer(Buffer* parent, BufferType type) :
m_type(type),
m_parent(parent)
{
// http://www.opengl.org/wiki/Buffer_Object_Streaming
if (forceDiscard)
glBufferData(NzOpenGL::BufferTarget[m_type], totalSize, nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
glBufferSubData(NzOpenGL::BufferTarget[m_type], offset, size, data);
}
else
HardwareBuffer::~HardwareBuffer() = default;
bool HardwareBuffer::Create(unsigned int size, BufferUsage usage)
{
void* ptr = Map((forceDiscard) ? nzBufferAccess_DiscardAndWrite : nzBufferAccess_WriteOnly, offset, size);
if (!ptr)
Context::EnsureContext();
m_buffer = 0;
glGenBuffers(1, &m_buffer);
OpenGL::BindBuffer(m_type, m_buffer);
glBufferData(OpenGL::BufferTarget[m_type], size, nullptr, OpenGL::BufferUsage[usage]);
return true;
}
void HardwareBuffer::Destroy()
{
Context::EnsureContext();
OpenGL::DeleteBuffer(m_type, m_buffer);
}
bool HardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard)
{
Context::EnsureContext();
unsigned int totalSize = m_parent->GetSize();
if (!forceDiscard)
forceDiscard = (size == totalSize);
OpenGL::BindBuffer(m_type, m_buffer);
// Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil
// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
if (size < 32*1024)
{
NazaraError("Failed to map buffer");
// http://www.opengl.org/wiki/Buffer_Object_Streaming
if (forceDiscard)
glBufferData(OpenGL::BufferTarget[m_type], totalSize, nullptr, OpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
glBufferSubData(OpenGL::BufferTarget[m_type], offset, size, data);
}
else
{
void* ptr = Map((forceDiscard) ? BufferAccess_DiscardAndWrite : BufferAccess_WriteOnly, offset, size);
if (!ptr)
{
NazaraError("Failed to map buffer");
return false;
}
std::memcpy(ptr, data, size);
Unmap();
}
return true;
}
bool HardwareBuffer::IsHardware() const
{
return true;
}
void* HardwareBuffer::Map(BufferAccess access, unsigned int offset, unsigned int size)
{
Context::EnsureContext();
OpenGL::BindBuffer(m_type, m_buffer);
if (glMapBufferRange)
return glMapBufferRange(OpenGL::BufferTarget[m_type], offset, size, OpenGL::BufferLockRange[access]);
else
{
// http://www.opengl.org/wiki/Buffer_Object_Streaming
if (access == BufferAccess_DiscardAndWrite)
glBufferData(OpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, OpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
UInt8* ptr = static_cast<UInt8*>(glMapBuffer(OpenGL::BufferTarget[m_type], OpenGL::BufferLock[access]));
if (ptr)
ptr += offset;
return ptr;
}
}
bool HardwareBuffer::Unmap()
{
Context::EnsureContext();
OpenGL::BindBuffer(m_type, m_buffer);
if (glUnmapBuffer(OpenGL::BufferTarget[m_type]) != GL_TRUE)
{
glBufferData(OpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, OpenGL::BufferUsage[m_parent->GetUsage()]);
// Une erreur rare est survenue, nous devons réinitialiser le buffer
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + String::Number(glGetError(), 16) + ')');
return false;
}
std::memcpy(ptr, data, size);
Unmap();
return true;
}
return true;
}
bool NzHardwareBuffer::IsHardware() const
{
return true;
}
void* NzHardwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int size)
{
NzContext::EnsureContext();
NzOpenGL::BindBuffer(m_type, m_buffer);
if (glMapBufferRange)
return glMapBufferRange(NzOpenGL::BufferTarget[m_type], offset, size, NzOpenGL::BufferLockRange[access]);
else
void HardwareBuffer::Bind() const
{
// http://www.opengl.org/wiki/Buffer_Object_Streaming
if (access == nzBufferAccess_DiscardAndWrite)
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
nzUInt8* ptr = static_cast<nzUInt8*>(glMapBuffer(NzOpenGL::BufferTarget[m_type], NzOpenGL::BufferLock[access]));
if (ptr)
ptr += offset;
return ptr;
OpenGL::BindBuffer(m_type, m_buffer);
}
}
bool NzHardwareBuffer::Unmap()
{
NzContext::EnsureContext();
NzOpenGL::BindBuffer(m_type, m_buffer);
if (glUnmapBuffer(NzOpenGL::BufferTarget[m_type]) != GL_TRUE)
unsigned int HardwareBuffer::GetOpenGLID() const
{
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]);
// Une erreur rare est survenue, nous devons réinitialiser le buffer
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
return false;
}
return true;
return m_buffer;
}
void NzHardwareBuffer::Bind() const
{
NzOpenGL::BindBuffer(m_type, m_buffer);
}
unsigned int NzHardwareBuffer::GetOpenGLID() const
{
return m_buffer;
}

View File

@@ -11,30 +11,33 @@
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Utility/AbstractBuffer.hpp>
class NzHardwareBuffer : public NzAbstractBuffer
namespace Nz
{
public:
NzHardwareBuffer(NzBuffer* parent, nzBufferType type);
~NzHardwareBuffer();
class HardwareBuffer : public AbstractBuffer
{
public:
HardwareBuffer(Buffer* parent, BufferType type);
~HardwareBuffer();
bool Create(unsigned int size, nzBufferUsage usage = nzBufferUsage_Static);
void Destroy();
bool Create(unsigned int size, BufferUsage usage = BufferUsage_Static);
void Destroy();
bool Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard);
bool Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard);
bool IsHardware() const;
bool IsHardware() const;
void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int size = 0);
bool Unmap();
void* Map(BufferAccess access, unsigned int offset = 0, unsigned int size = 0);
bool Unmap();
// Fonctions OpenGL
void Bind() const;
unsigned int GetOpenGLID() const;
// Fonctions OpenGL
void Bind() const;
unsigned int GetOpenGLID() const;
private:
GLuint m_buffer;
nzBufferType m_type;
NzBuffer* m_parent;
};
private:
GLuint m_buffer;
BufferType m_type;
Buffer* m_parent;
};
}
#endif // NAZARA_HARDWAREBUFFER_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -9,127 +9,130 @@
#include <Nazara/Utility/PixelFormat.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzRenderBuffer::NzRenderBuffer() :
m_id(0)
namespace Nz
{
}
NzRenderBuffer::~NzRenderBuffer()
{
OnRenderBufferRelease(this);
Destroy();
}
bool NzRenderBuffer::Create(nzPixelFormat format, unsigned int width, unsigned int height)
{
Destroy();
#if NAZARA_RENDERER_SAFE
if (width == 0 || height == 0)
RenderBuffer::RenderBuffer() :
m_id(0)
{
NazaraError("Invalid size");
return false;
}
if (!NzPixelFormat::IsValid(format))
RenderBuffer::~RenderBuffer()
{
NazaraError("Invalid pixel format");
return false;
}
#endif
OnRenderBufferRelease(this);
NzOpenGL::Format openglFormat;
if (!NzOpenGL::TranslateFormat(format, &openglFormat, NzOpenGL::FormatType_RenderBuffer))
{
NazaraError("Failed to translate pixel format \"" + NzPixelFormat::ToString(format) + "\" into OpenGL format");
return false;
Destroy();
}
GLuint renderBuffer = 0;
glGenRenderbuffers(1, &renderBuffer);
if (!renderBuffer)
bool RenderBuffer::Create(PixelFormatType format, unsigned int width, unsigned int height)
{
NazaraError("Failed to create renderbuffer");
return false;
Destroy();
#if NAZARA_RENDERER_SAFE
if (width == 0 || height == 0)
{
NazaraError("Invalid size");
return false;
}
if (!NzPixelFormat::IsValid(format))
{
NazaraError("Invalid pixel format");
return false;
}
#endif
OpenGL::Format openglFormat;
if (!OpenGL::TranslateFormat(format, &openglFormat, OpenGL::FormatType_RenderBuffer))
{
NazaraError("Failed to translate pixel format \"" + NzPixelFormat::ToString(format) + "\" into OpenGL format");
return false;
}
GLuint renderBuffer = 0;
glGenRenderbuffers(1, &renderBuffer);
if (!renderBuffer)
{
NazaraError("Failed to create renderbuffer");
return false;
}
GLint previous;
glGetIntegerv(GL_RENDERBUFFER_BINDING, &previous);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, openglFormat.internalFormat, width, height);
if (previous != 0)
glBindRenderbuffer(GL_RENDERBUFFER, previous);
m_pixelFormat = format;
m_height = height;
m_id = renderBuffer;
m_width = width;
return true;
}
GLint previous;
glGetIntegerv(GL_RENDERBUFFER_BINDING, &previous);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, openglFormat.internalFormat, width, height);
if (previous != 0)
glBindRenderbuffer(GL_RENDERBUFFER, previous);
m_pixelFormat = format;
m_height = height;
m_id = renderBuffer;
m_width = width;
return true;
}
void NzRenderBuffer::Destroy()
{
if (m_id)
void RenderBuffer::Destroy()
{
OnRenderBufferDestroy(this);
if (m_id)
{
OnRenderBufferDestroy(this);
NzContext::EnsureContext();
Context::EnsureContext();
GLuint renderBuffer = m_id;
glDeleteRenderbuffers(1, &renderBuffer); // Les Renderbuffers sont partagés entre les contextes: Ne posera pas de problème
m_id = 0;
}
}
unsigned int NzRenderBuffer::GetHeight() const
{
return m_height;
}
nzPixelFormat NzRenderBuffer::GetFormat() const
{
return m_pixelFormat;
}
unsigned int NzRenderBuffer::GetWidth() const
{
return m_width;
}
unsigned int NzRenderBuffer::GetOpenGLID() const
{
return m_id;
}
bool NzRenderBuffer::IsValid() const
{
return m_id != 0;
}
bool NzRenderBuffer::IsSupported()
{
return NzOpenGL::IsSupported(nzOpenGLExtension_FrameBufferObject);
}
bool NzRenderBuffer::Initialize()
{
if (!NzRenderBufferLibrary::Initialize())
{
NazaraError("Failed to initialise library");
return false;
GLuint renderBuffer = m_id;
glDeleteRenderbuffers(1, &renderBuffer); // Les Renderbuffers sont partagés entre les contextes: Ne posera pas de problème
m_id = 0;
}
}
return true;
}
unsigned int RenderBuffer::GetHeight() const
{
return m_height;
}
void NzRenderBuffer::Uninitialize()
{
NzRenderBufferLibrary::Uninitialize();
}
PixelFormatType RenderBuffer::GetFormat() const
{
return m_pixelFormat;
}
NzRenderBufferLibrary::LibraryMap NzRenderBuffer::s_library;
unsigned int RenderBuffer::GetWidth() const
{
return m_width;
}
unsigned int RenderBuffer::GetOpenGLID() const
{
return m_id;
}
bool RenderBuffer::IsValid() const
{
return m_id != 0;
}
bool RenderBuffer::IsSupported()
{
return OpenGL::IsSupported(OpenGLExtension_FrameBufferObject);
}
bool RenderBuffer::Initialize()
{
if (!RenderBufferLibrary::Initialize())
{
NazaraError("Failed to initialise library");
return false;
}
return true;
}
void RenderBuffer::Uninitialize()
{
RenderBufferLibrary::Uninitialize();
}
RenderBufferLibrary::LibraryMap RenderBuffer::s_library;
}

View File

@@ -6,27 +6,30 @@
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzRenderTarget::~NzRenderTarget()
namespace Nz
{
OnRenderTargetRelease(this);
}
RenderTarget::~RenderTarget()
{
OnRenderTargetRelease(this);
}
bool NzRenderTarget::IsActive() const
{
return NzRenderer::GetTarget() == this;
}
bool RenderTarget::IsActive() const
{
return Renderer::GetTarget() == this;
}
bool NzRenderTarget::SetActive(bool active)
{
if (active)
return NzRenderer::SetTarget(this);
else if (NzRenderer::GetTarget() == this)
return NzRenderer::SetTarget(nullptr);
bool RenderTarget::SetActive(bool active)
{
if (active)
return Renderer::SetTarget(this);
else if (Renderer::GetTarget() == this)
return Renderer::SetTarget(nullptr);
return true;
}
return true;
}
void NzRenderTarget::Desactivate() const
{
// Seuls les target sans contextes (ex: NzRenderTexture) nécessitent une désactivation
void RenderTarget::Desactivate() const
{
// Seuls les target sans contextes (ex: RenderTexture) nécessitent une désactivation
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -13,277 +13,279 @@
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
NzRenderWindow::NzRenderWindow(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters) :
NzRenderTarget(), NzWindow()
namespace Nz
{
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
Create(mode, title, style, parameters);
}
NzRenderWindow::NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters) :
NzRenderTarget(), NzWindow()
{
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
Create(handle, parameters);
}
NzRenderWindow::~NzRenderWindow()
{
// Nécessaire si NzWindow::Destroy est appelé par son destructeur
OnWindowDestroy();
}
bool NzRenderWindow::CopyToImage(NzAbstractImage* image, const NzVector3ui& dstPos) const
{
#if NAZARA_RENDERER_SAFE
if (!m_context)
RenderWindow::RenderWindow(VideoMode mode, const String& title, UInt32 style, const ContextParameters& parameters) :
RenderTarget(), Window()
{
NazaraError("Window has not been created");
return false;
}
#endif
return CopyToImage(image, NzRectui(NzVector2ui(0U), GetSize()), dstPos);
}
bool NzRenderWindow::CopyToImage(NzAbstractImage* image, const NzRectui& rect, const NzVector3ui& dstPos) const
{
#if NAZARA_RENDERER_SAFE
if (!m_context)
{
NazaraError("Window has not been created");
return false;
}
#endif
NzVector2ui windowSize = GetSize();
#if NAZARA_RENDERER_SAFE
if (!image)
{
NazaraError("Image must be valid");
return false;
ErrorFlags flags(ErrorFlag_ThrowException, true);
Create(mode, title, style, parameters);
}
if (image->GetFormat() != nzPixelFormat_RGBA8)
RenderWindow::RenderWindow(WindowHandle handle, const ContextParameters& parameters) :
RenderTarget(), Window()
{
// Pour plus de facilité, évidemment on peut faire sauter cette règle avec un peu de gestion
NazaraError("Image must be RGBA8-formatted");
return false;
ErrorFlags flags(ErrorFlag_ThrowException, true);
Create(handle, parameters);
}
if (rect.x + rect.width > windowSize.x || rect.y + rect.height > windowSize.y)
RenderWindow::~RenderWindow()
{
NazaraError("Rectangle dimensions are out of window's bounds");
return false;
// Nécessaire si Window::Destroy est appelé par son destructeur
OnWindowDestroy();
}
NzVector3ui imageSize = image->GetSize();
if (dstPos.x + rect.width > imageSize.x || dstPos.y + rect.height > imageSize.y || dstPos.z > imageSize.z)
bool RenderWindow::CopyToImage(AbstractImage* image, const Vector3ui& dstPos) const
{
NazaraError("Cube dimensions are out of image's bounds");
return false;
}
#endif
const NzContext* currentContext = NzContext::GetCurrent();
if (m_context != currentContext)
{
if (!m_context->SetActive(true))
#if NAZARA_RENDERER_SAFE
if (!m_context)
{
NazaraError("Failed to activate context");
NazaraError("Window has not been created");
return false;
}
#endif
return CopyToImage(image, Rectui(Vector2ui(0U), GetSize()), dstPos);
}
bool RenderWindow::CopyToImage(AbstractImage* image, const Rectui& rect, const Vector3ui& dstPos) const
{
#if NAZARA_RENDERER_SAFE
if (!m_context)
{
NazaraError("Window has not been created");
return false;
}
#endif
Vector2ui windowSize = GetSize();
#if NAZARA_RENDERER_SAFE
if (!image)
{
NazaraError("Image must be valid");
return false;
}
if (image->GetFormat() != PixelFormatType_RGBA8)
{
// Pour plus de facilité, évidemment on peut faire sauter cette règle avec un peu de gestion
NazaraError("Image must be RGBA8-formatted");
return false;
}
if (rect.x + rect.width > windowSize.x || rect.y + rect.height > windowSize.y)
{
NazaraError("Rectangle dimensions are out of window's bounds");
return false;
}
Vector3ui imageSize = image->GetSize();
if (dstPos.x + rect.width > imageSize.x || dstPos.y + rect.height > imageSize.y || dstPos.z > imageSize.z)
{
NazaraError("Cube dimensions are out of image's bounds");
return false;
}
#endif
const Context* currentContext = Context::GetCurrent();
if (m_context != currentContext)
{
if (!m_context->SetActive(true))
{
NazaraError("Failed to activate context");
return false;
}
}
///TODO: Fast-path pour les images en cas de copie du buffer entier
m_buffer.resize(rect.width*rect.height*4);
glReadPixels(rect.x, windowSize.y - rect.height - rect.y, rect.width, rect.height, GL_RGBA, GL_UNSIGNED_BYTE, m_buffer.data());
// Les pixels sont retournés, nous devons envoyer les pixels par rangée
for (unsigned int i = 0; i < rect.height; ++i)
image->Update(&m_buffer[rect.width*4*i], Boxui(dstPos.x, rect.height - i - 1, dstPos.z, rect.width, 1, 1), rect.width);
if (m_context != currentContext)
{
if (currentContext)
{
if (!currentContext->SetActive(true))
NazaraWarning("Failed to reset old context");
}
else
m_context->SetActive(false);
}
return true;
}
bool RenderWindow::Create(VideoMode mode, const String& title, UInt32 style, const ContextParameters& parameters)
{
m_parameters = parameters;
return Window::Create(mode, title, style);
}
bool RenderWindow::Create(WindowHandle handle, const ContextParameters& parameters)
{
m_parameters = parameters;
return Window::Create(handle);
}
void RenderWindow::Display()
{
if (m_framerateLimit > 0)
{
int remainingTime = 1000/static_cast<int>(m_framerateLimit) - static_cast<int>(m_clock.GetMilliseconds());
if (remainingTime > 0)
Thread::Sleep(remainingTime);
m_clock.Restart();
}
if (m_context && m_parameters.doubleBuffered)
m_context->SwapBuffers();
}
void RenderWindow::EnableVerticalSync(bool enabled)
{
if (m_context)
{
if (!m_context->SetActive(true))
{
NazaraError("Failed to activate context");
return;
}
m_context->EnableVerticalSync(enabled);
}
else
NazaraError("No context");
}
unsigned int RenderWindow::GetHeight() const
{
return Window::GetHeight();
}
RenderTargetParameters RenderWindow::GetParameters() const
{
if (m_context)
{
const ContextParameters& parameters = m_context->GetParameters();
return RenderTargetParameters(parameters.antialiasingLevel, parameters.depthBits, parameters.stencilBits);
}
else
{
NazaraError("Window not created/context not initialized");
return RenderTargetParameters();
}
}
unsigned int RenderWindow::GetWidth() const
{
return Window::GetWidth();
}
bool RenderWindow::IsRenderable() const
{
return m_impl != nullptr; // Si m_impl est valide, alors m_context l'est aussi
}
bool RenderWindow::IsValid() const
{
return m_impl != nullptr;
}
void RenderWindow::SetFramerateLimit(unsigned int limit)
{
m_framerateLimit = limit;
}
ContextParameters RenderWindow::GetContextParameters() const
{
if (m_context)
return m_context->GetParameters();
else
{
NazaraError("Window not created/context not initialized");
return ContextParameters();
}
}
bool RenderWindow::HasContext() const
{
return true;
}
bool RenderWindow::Activate() const
{
if (m_context->SetActive(true))
{
glDrawBuffer((m_parameters.doubleBuffered) ? GL_BACK : GL_FRONT);
return true;
}
else
{
NazaraError("Failed to activate window's context");
return false;
}
}
///TODO: Fast-path pour les images en cas de copie du buffer entier
m_buffer.resize(rect.width*rect.height*4);
glReadPixels(rect.x, windowSize.y - rect.height - rect.y, rect.width, rect.height, GL_RGBA, GL_UNSIGNED_BYTE, m_buffer.data());
// Les pixels sont retournés, nous devons envoyer les pixels par rangée
for (unsigned int i = 0; i < rect.height; ++i)
image->Update(&m_buffer[rect.width*4*i], NzBoxui(dstPos.x, rect.height - i - 1, dstPos.z, rect.width, 1, 1), rect.width);
if (m_context != currentContext)
void RenderWindow::EnsureTargetUpdated() const
{
if (currentContext)
{
if (!currentContext->SetActive(true))
NazaraWarning("Failed to reset old context");
}
else
m_context->SetActive(false);
// Rien à faire
}
return true;
}
bool NzRenderWindow::Create(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters)
{
m_parameters = parameters;
return NzWindow::Create(mode, title, style);
}
bool NzRenderWindow::Create(NzWindowHandle handle, const NzContextParameters& parameters)
{
m_parameters = parameters;
return NzWindow::Create(handle);
}
void NzRenderWindow::Display()
{
if (m_framerateLimit > 0)
bool RenderWindow::OnWindowCreated()
{
int remainingTime = 1000/static_cast<int>(m_framerateLimit) - static_cast<int>(m_clock.GetMilliseconds());
if (remainingTime > 0)
NzThread::Sleep(remainingTime);
m_parameters.doubleBuffered = true;
m_parameters.window = GetHandle();
std::unique_ptr<Context> context(new Context);
if (!context->Create(m_parameters))
{
NazaraError("Failed to create context");
return false;
}
m_context = context.release();
if (!SetActive(true)) // Les fenêtres s'activent à la création
NazaraWarning("Failed to activate window");
EnableVerticalSync(false);
Vector2ui size = GetSize();
// Le scissorBox/viewport (à la création) est de la taille de la fenêtre
// https://www.opengl.org/sdk/docs/man/xhtml/glGet.xml
OpenGL::SetScissorBox(Recti(0, 0, size.x, size.y));
OpenGL::SetViewport(Recti(0, 0, size.x, size.y));
OnRenderTargetParametersChange(this);
OnRenderTargetSizeChange(this);
m_clock.Restart();
}
if (m_context && m_parameters.doubleBuffered)
m_context->SwapBuffers();
}
void NzRenderWindow::EnableVerticalSync(bool enabled)
{
if (m_context)
{
if (!m_context->SetActive(true))
{
NazaraError("Failed to activate context");
return;
}
m_context->EnableVerticalSync(enabled);
}
else
NazaraError("No context");
}
unsigned int NzRenderWindow::GetHeight() const
{
return NzWindow::GetHeight();
}
NzRenderTargetParameters NzRenderWindow::GetParameters() const
{
if (m_context)
{
const NzContextParameters& parameters = m_context->GetParameters();
return NzRenderTargetParameters(parameters.antialiasingLevel, parameters.depthBits, parameters.stencilBits);
}
else
{
NazaraError("Window not created/context not initialized");
return NzRenderTargetParameters();
}
}
unsigned int NzRenderWindow::GetWidth() const
{
return NzWindow::GetWidth();
}
bool NzRenderWindow::IsRenderable() const
{
return m_impl != nullptr; // Si m_impl est valide, alors m_context l'est aussi
}
bool NzRenderWindow::IsValid() const
{
return m_impl != nullptr;
}
void NzRenderWindow::SetFramerateLimit(unsigned int limit)
{
m_framerateLimit = limit;
}
NzContextParameters NzRenderWindow::GetContextParameters() const
{
if (m_context)
return m_context->GetParameters();
else
{
NazaraError("Window not created/context not initialized");
return NzContextParameters();
}
}
bool NzRenderWindow::HasContext() const
{
return true;
}
bool NzRenderWindow::Activate() const
{
if (m_context->SetActive(true))
{
glDrawBuffer((m_parameters.doubleBuffered) ? GL_BACK : GL_FRONT);
return true;
}
else
void RenderWindow::OnWindowDestroy()
{
NazaraError("Failed to activate window's context");
return false;
}
}
if (m_context)
{
if (IsActive())
Renderer::SetTarget(nullptr);
void NzRenderWindow::EnsureTargetUpdated() const
{
// Rien à faire
}
bool NzRenderWindow::OnWindowCreated()
{
m_parameters.doubleBuffered = true;
m_parameters.window = GetHandle();
std::unique_ptr<NzContext> context(new NzContext);
if (!context->Create(m_parameters))
{
NazaraError("Failed to create context");
return false;
delete m_context;
m_context = nullptr;
}
}
m_context = context.release();
if (!SetActive(true)) // Les fenêtres s'activent à la création
NazaraWarning("Failed to activate window");
EnableVerticalSync(false);
NzVector2ui size = GetSize();
// Le scissorBox/viewport (à la création) est de la taille de la fenêtre
// https://www.opengl.org/sdk/docs/man/xhtml/glGet.xml
NzOpenGL::SetScissorBox(NzRecti(0, 0, size.x, size.y));
NzOpenGL::SetViewport(NzRecti(0, 0, size.x, size.y));
OnRenderTargetParametersChange(this);
OnRenderTargetSizeChange(this);
m_clock.Restart();
return true;
}
void NzRenderWindow::OnWindowDestroy()
{
if (m_context)
void RenderWindow::OnWindowResized()
{
if (IsActive())
NzRenderer::SetTarget(nullptr);
delete m_context;
m_context = nullptr;
OnRenderTargetSizeChange(this);
}
}
void NzRenderWindow::OnWindowResized()
{
OnRenderTargetSizeChange(this);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,227 +7,230 @@
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzShaderStage::NzShaderStage() :
m_compiled(false),
m_id(0)
namespace Nz
{
}
NzShaderStage::NzShaderStage(nzShaderStage stage) :
NzShaderStage()
{
Create(stage);
}
NzShaderStage::NzShaderStage(NzShaderStage&& stage) :
m_stage(stage.m_stage),
m_compiled(stage.m_compiled),
m_id(stage.m_id)
{
stage.m_id = 0;
}
NzShaderStage::~NzShaderStage()
{
Destroy();
}
bool NzShaderStage::Compile()
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
ShaderStage::ShaderStage() :
m_compiled(false),
m_id(0)
{
NazaraError("Shader stage is not initialized");
return false;
}
#endif
glCompileShader(m_id);
GLint success;
glGetShaderiv(m_id, GL_COMPILE_STATUS, &success);
m_compiled = (success == GL_TRUE);
if (m_compiled)
return true;
else
{
NazaraError("Failed to compile shader stage: " + GetLog());
return false;
}
}
bool NzShaderStage::Create(nzShaderStage stage)
{
Destroy();
m_id = glCreateShader(NzOpenGL::ShaderStage[stage]);
m_stage = stage;
return (m_id != 0);
}
void NzShaderStage::Destroy()
{
m_compiled = false;
if (m_id)
{
glDeleteShader(m_id);
m_id = 0;
}
}
NzString NzShaderStage::GetLog() const
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return NzString();
}
#endif
NzString log;
GLint length = 0;
glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &length);
if (length > 1) // Le caractère de fin faisant partie du compte
{
log.Set(length - 1, '\0'); // La taille retournée est celle du buffer (Avec caractère de fin)
glGetShaderInfoLog(m_id, length, nullptr, &log[0]);
}
else
log = "No log.";
return log;
}
NzString NzShaderStage::GetSource() const
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return NzString();
}
#endif
NzString source;
GLint length = 0;
glGetShaderiv(m_id, GL_SHADER_SOURCE_LENGTH, &length);
if (length > 1) // Le caractère de fin compte
{
source.Set(length - 1, '\0'); // La taille retournée est celle du buffer (Avec caractère de fin)
glGetShaderSource(m_id, length, nullptr, &source[0]);
}
return source;
}
bool NzShaderStage::IsCompiled() const
{
return m_compiled;
}
bool NzShaderStage::IsValid() const
{
return m_id != 0;
}
void NzShaderStage::SetSource(const char* source, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
ShaderStage::ShaderStage(ShaderStageType stage) :
ShaderStage()
{
NazaraError("Shader stage is not initialized");
return;
}
#endif
glShaderSource(m_id, 1, &source, reinterpret_cast<const GLint*>(&length));
}
void NzShaderStage::SetSource(const NzString& source)
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return;
}
#endif
const char* tmp = source.GetConstBuffer();
GLint length = source.GetSize();
glShaderSource(m_id, 1, &tmp, &length);
}
bool NzShaderStage::SetSourceFromFile(const NzString& filePath)
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return false;
}
#endif
NzFile file(filePath);
if (!file.Open(nzOpenMode_ReadOnly | nzOpenMode_Text))
{
NazaraError("Failed to open \"" + filePath + '"');
return false;
Create(stage);
}
unsigned int length = static_cast<unsigned int>(file.GetSize());
NzString source(length, '\0');
if (file.Read(&source[0], length) != length)
ShaderStage::ShaderStage(ShaderStage&& stage) :
m_stage(stage.m_stage),
m_compiled(stage.m_compiled),
m_id(stage.m_id)
{
NazaraError("Failed to read program file");
return false;
stage.m_id = 0;
}
file.Close();
SetSource(source);
return true;
}
NzShaderStage& NzShaderStage::operator=(NzShaderStage&& shader)
{
Destroy();
m_compiled = shader.m_compiled;
m_id = shader.m_id;
m_stage = shader.m_stage;
shader.m_id = 0;
return *this;
}
// Fonctions OpenGL
unsigned int NzShaderStage::GetOpenGLID() const
{
return m_id;
}
bool NzShaderStage::IsSupported(nzShaderStage stage)
{
switch (stage)
ShaderStage::~ShaderStage()
{
case nzShaderStage_Fragment:
case nzShaderStage_Vertex:
return true;
Destroy();
}
case nzShaderStage_Geometry:
return NzOpenGL::GetVersion() >= 320;
default:
NazaraError("Shader stage not handled (0x" + NzString::Number(stage, 16) + ')');
bool ShaderStage::Compile()
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return false;
}
#endif
glCompileShader(m_id);
GLint success;
glGetShaderiv(m_id, GL_COMPILE_STATUS, &success);
m_compiled = (success == GL_TRUE);
if (m_compiled)
return true;
else
{
NazaraError("Failed to compile shader stage: " + GetLog());
return false;
}
}
bool ShaderStage::Create(ShaderStageType stage)
{
Destroy();
m_id = glCreateShader(OpenGL::ShaderStage[stage]);
m_stage = stage;
return (m_id != 0);
}
void ShaderStage::Destroy()
{
m_compiled = false;
if (m_id)
{
glDeleteShader(m_id);
m_id = 0;
}
}
String ShaderStage::GetLog() const
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return String();
}
#endif
String log;
GLint length = 0;
glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &length);
if (length > 1) // Le caractère de fin faisant partie du compte
{
log.Set(length - 1, '\0'); // La taille retournée est celle du buffer (Avec caractère de fin)
glGetShaderInfoLog(m_id, length, nullptr, &log[0]);
}
else
log = "No log.";
return log;
}
String ShaderStage::GetSource() const
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return String();
}
#endif
String source;
GLint length = 0;
glGetShaderiv(m_id, GL_SHADER_SOURCE_LENGTH, &length);
if (length > 1) // Le caractère de fin compte
{
source.Set(length - 1, '\0'); // La taille retournée est celle du buffer (Avec caractère de fin)
glGetShaderSource(m_id, length, nullptr, &source[0]);
}
return source;
}
bool ShaderStage::IsCompiled() const
{
return m_compiled;
}
bool ShaderStage::IsValid() const
{
return m_id != 0;
}
void ShaderStage::SetSource(const char* source, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return;
}
#endif
glShaderSource(m_id, 1, &source, reinterpret_cast<const GLint*>(&length));
}
void ShaderStage::SetSource(const String& source)
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return;
}
#endif
const char* tmp = source.GetConstBuffer();
GLint length = source.GetSize();
glShaderSource(m_id, 1, &tmp, &length);
}
bool ShaderStage::SetSourceFromFile(const String& filePath)
{
#if NAZARA_RENDERER_SAFE
if (!m_id)
{
NazaraError("Shader stage is not initialized");
return false;
}
#endif
File file(filePath);
if (!file.Open(OpenMode_ReadOnly | OpenMode_Text))
{
NazaraError("Failed to open \"" + filePath + '"');
return false;
}
unsigned int length = static_cast<unsigned int>(file.GetSize());
String source(length, '\0');
if (file.Read(&source[0], length) != length)
{
NazaraError("Failed to read program file");
return false;
}
file.Close();
SetSource(source);
return true;
}
ShaderStage& ShaderStage::operator=(ShaderStage&& shader)
{
Destroy();
m_compiled = shader.m_compiled;
m_id = shader.m_id;
m_stage = shader.m_stage;
shader.m_id = 0;
return *this;
}
// Fonctions OpenGL
unsigned int ShaderStage::GetOpenGLID() const
{
return m_id;
}
bool ShaderStage::IsSupported(ShaderStageType stage)
{
switch (stage)
{
case ShaderStageType_Fragment:
case ShaderStageType_Vertex:
return true;
case ShaderStageType_Geometry:
return OpenGL::GetVersion() >= 320;
default:
NazaraError("Shader stage not handled (0x" + String::Number(stage, 16) + ')');
return false;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,379 +12,382 @@
#include <unordered_map>
#include <Nazara/Renderer/Debug.hpp>
namespace
namespace Nz
{
std::unordered_map<nzUInt32, GLuint> s_samplers;
nzUInt8 s_maxAnisotropyLevel;
bool s_useAnisotropicFilter;
}
NzTextureSampler::NzTextureSampler() :
m_filterMode(nzSamplerFilter_Default),
m_wrapMode(nzSamplerWrap_Default),
m_anisotropicLevel(0),
m_mipmaps(true),
m_samplerId(0)
{
}
nzUInt8 NzTextureSampler::GetAnisotropicLevel() const
{
return m_anisotropicLevel;
}
nzSamplerFilter NzTextureSampler::GetFilterMode() const
{
return m_filterMode;
}
nzSamplerWrap NzTextureSampler::GetWrapMode() const
{
return m_wrapMode;
}
void NzTextureSampler::SetAnisotropyLevel(nzUInt8 anisotropyLevel)
{
#ifdef NAZARA_DEBUG
if (!NzRenderer::IsInitialized())
namespace
{
NazaraError("Renderer module must be initialized");
return;
std::unordered_map<UInt32, GLuint> s_samplers;
UInt8 s_maxAnisotropyLevel;
bool s_useAnisotropicFilter;
}
#endif
if (m_anisotropicLevel != anisotropyLevel)
TextureSampler::TextureSampler() :
m_filterMode(SamplerFilter_Default),
m_wrapMode(SamplerWrap_Default),
m_anisotropicLevel(0),
m_mipmaps(true),
m_samplerId(0)
{
}
UInt8 TextureSampler::GetAnisotropicLevel() const
{
return m_anisotropicLevel;
}
SamplerFilter TextureSampler::GetFilterMode() const
{
return m_filterMode;
}
SamplerWrap TextureSampler::GetWrapMode() const
{
return m_wrapMode;
}
void TextureSampler::SetAnisotropyLevel(UInt8 anisotropyLevel)
{
#ifdef NAZARA_DEBUG
if (!Renderer::IsInitialized())
{
NazaraError("Renderer module must be initialized");
return;
}
#endif
if (m_anisotropicLevel != anisotropyLevel)
{
if (anisotropyLevel > s_maxAnisotropyLevel)
{
NazaraWarning("Anisotropy level is over maximum anisotropy level (" + String::Number(anisotropyLevel) + " > " + String::Number(s_maxAnisotropyLevel) + ')');
anisotropyLevel = s_maxAnisotropyLevel;
}
m_anisotropicLevel = anisotropyLevel;
m_samplerId = 0;
}
}
void TextureSampler::SetFilterMode(SamplerFilter filterMode)
{
if (m_filterMode != filterMode)
{
m_filterMode = filterMode;
m_samplerId = 0;
}
}
void TextureSampler::SetWrapMode(SamplerWrap wrapMode)
{
if (m_wrapMode != wrapMode)
{
m_wrapMode = wrapMode;
m_samplerId = 0;
}
}
UInt8 TextureSampler::GetDefaultAnisotropicLevel()
{
return s_defaultAnisotropyLevel;
}
SamplerFilter TextureSampler::GetDefaultFilterMode()
{
return s_defaultFilterMode;
}
SamplerWrap TextureSampler::GetDefaultWrapMode()
{
return s_defaultWrapMode;
}
void TextureSampler::SetDefaultAnisotropyLevel(UInt8 anisotropyLevel)
{
#if NAZARA_RENDERER_SAFE
if (anisotropyLevel == 0)
{
NazaraError("Default anisotropy level mode cannot be set to default value (0)");
return;
}
#endif
#ifdef NAZARA_DEBUG
if (!Renderer::IsInitialized())
{
NazaraError("Renderer module must be initialized");
return;
}
#endif
if (anisotropyLevel > s_maxAnisotropyLevel)
{
NazaraWarning("Anisotropy level is over maximum anisotropy level (" + NzString::Number(anisotropyLevel) + " > " + NzString::Number(s_maxAnisotropyLevel) + ')');
NazaraWarning("Anisotropy level is over maximum anisotropy level (" + String::Number(anisotropyLevel) + " > " + String::Number(s_maxAnisotropyLevel));
anisotropyLevel = s_maxAnisotropyLevel;
}
m_anisotropicLevel = anisotropyLevel;
m_samplerId = 0;
}
}
void NzTextureSampler::SetFilterMode(nzSamplerFilter filterMode)
{
if (m_filterMode != filterMode)
{
m_filterMode = filterMode;
m_samplerId = 0;
}
}
void NzTextureSampler::SetWrapMode(nzSamplerWrap wrapMode)
{
if (m_wrapMode != wrapMode)
{
m_wrapMode = wrapMode;
m_samplerId = 0;
}
}
nzUInt8 NzTextureSampler::GetDefaultAnisotropicLevel()
{
return s_defaultAnisotropyLevel;
}
nzSamplerFilter NzTextureSampler::GetDefaultFilterMode()
{
return s_defaultFilterMode;
}
nzSamplerWrap NzTextureSampler::GetDefaultWrapMode()
{
return s_defaultWrapMode;
}
void NzTextureSampler::SetDefaultAnisotropyLevel(nzUInt8 anisotropyLevel)
{
#if NAZARA_RENDERER_SAFE
if (anisotropyLevel == 0)
{
NazaraError("Default anisotropy level mode cannot be set to default value (0)");
return;
}
#endif
#ifdef NAZARA_DEBUG
if (!NzRenderer::IsInitialized())
{
NazaraError("Renderer module must be initialized");
return;
}
#endif
if (anisotropyLevel > s_maxAnisotropyLevel)
{
NazaraWarning("Anisotropy level is over maximum anisotropy level (" + NzString::Number(anisotropyLevel) + " > " + NzString::Number(s_maxAnisotropyLevel));
anisotropyLevel = s_maxAnisotropyLevel;
}
s_defaultAnisotropyLevel = anisotropyLevel;
if (s_useAnisotropicFilter)
{
for (const std::pair<nzUInt32, GLuint>& pair : s_samplers)
{
if (((pair.first >> 5) & 0xFF) == 0)
glSamplerParameterf(pair.second, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
}
}
}
void NzTextureSampler::SetDefaultFilterMode(nzSamplerFilter filterMode)
{
#if NAZARA_RENDERER_SAFE
if (filterMode == nzSamplerFilter_Default)
{
NazaraError("Default filter mode cannot be set to default enum value (nzSamplerFilter_Default)");
return;
}
#endif
s_defaultFilterMode = filterMode;
for (const std::pair<nzUInt32, GLuint>& pair : s_samplers)
{
if (((pair.first >> 1) & 0x3) == nzSamplerFilter_Default)
{
bool mipmaps = pair.first & 0x1;
switch (filterMode)
{
case nzSamplerFilter_Bilinear:
if (mipmaps)
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
else
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case nzSamplerFilter_Nearest:
if (mipmaps)
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
else
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case nzSamplerFilter_Trilinear:
if (mipmaps)
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
default:
NazaraError("Texture filter not handled (0x" + NzString::Number(filterMode, 16) + ')');
break;
}
}
}
}
void NzTextureSampler::SetDefaultWrapMode(nzSamplerWrap wrapMode)
{
#if NAZARA_RENDERER_SAFE
if (wrapMode == nzSamplerWrap_Default)
{
NazaraError("Default wrap mode cannot be set to default enum value (nzSamplerWrap_Default)");
return;
}
#endif
s_defaultWrapMode = wrapMode;
GLenum wrapEnum = NzOpenGL::SamplerWrapMode[wrapMode];
for (const std::pair<nzUInt32, GLuint>& pair : s_samplers)
{
if (((pair.first >> 3) & 0x3) == nzSamplerWrap_Default)
{
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_R, wrapEnum);
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_T, wrapEnum);
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_S, wrapEnum);
}
}
}
void NzTextureSampler::Apply(const NzTexture* texture) const
{
nzImageType type = texture->GetType();
GLenum target = NzOpenGL::TextureTarget[type];
NzOpenGL::BindTexture(type, texture->GetOpenGLID());
if (s_useAnisotropicFilter)
{
nzUInt8 anisotropyLevel = (m_anisotropicLevel == 0) ? s_defaultAnisotropyLevel : m_anisotropicLevel;
glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
}
nzSamplerFilter filterMode = (m_filterMode == nzSamplerFilter_Default) ? s_defaultFilterMode : m_filterMode;
switch (filterMode)
{
case nzSamplerFilter_Bilinear:
if (m_mipmaps)
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
else
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case nzSamplerFilter_Nearest:
if (m_mipmaps)
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
else
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case nzSamplerFilter_Trilinear:
if (m_mipmaps)
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
default:
NazaraError("Texture filter not handled (0x" + NzString::Number(filterMode, 16) + ')');
break;
}
GLenum wrapMode = NzOpenGL::SamplerWrapMode[(m_wrapMode == nzSamplerWrap_Default) ? s_defaultWrapMode : m_wrapMode];
switch (type)
{
// Notez l'absence de "break" ici
case nzImageType_3D:
glTexParameteri(target, GL_TEXTURE_WRAP_R, wrapMode);
case nzImageType_2D:
case nzImageType_2D_Array:
case nzImageType_Cubemap:
glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode);
case nzImageType_1D:
case nzImageType_1D_Array:
glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode);
break;
}
}
void NzTextureSampler::Bind(unsigned int unit) const
{
static_assert(nzSamplerFilter_Max < 0x4, "Maximum sampler filter mode takes more than 2 bits");
static_assert(nzSamplerWrap_Max < 0x4, "Maximum sampler wrap mode takes more than 2 bits");
if (!m_samplerId)
UpdateSamplerId();
NzOpenGL::BindSampler(unit, m_samplerId);
}
unsigned int NzTextureSampler::GetOpenGLID() const
{
if (!m_samplerId)
UpdateSamplerId();
return m_samplerId;
}
void NzTextureSampler::UpdateSamplerId() const
{
nzUInt32 key = (((m_mipmaps) ? 1 : 0) << 0) | // 1 bit
(m_filterMode << 1) | // 2 bits
(m_wrapMode << 3) | // 2 bits
(m_anisotropicLevel << 5); // 8 bits
auto it = s_samplers.find(key);
if (it == s_samplers.end())
{
GLuint sampler;
glGenSamplers(1, &sampler);
s_defaultAnisotropyLevel = anisotropyLevel;
if (s_useAnisotropicFilter)
{
nzUInt8 anisotropyLevel = (m_anisotropicLevel == 0) ? s_defaultAnisotropyLevel : m_anisotropicLevel;
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
for (const std::pair<UInt32, GLuint>& pair : s_samplers)
{
if (((pair.first >> 5) & 0xFF) == 0)
glSamplerParameterf(pair.second, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
}
}
}
void TextureSampler::SetDefaultFilterMode(SamplerFilter filterMode)
{
#if NAZARA_RENDERER_SAFE
if (filterMode == SamplerFilter_Default)
{
NazaraError("Default filter mode cannot be set to default enum value (SamplerFilter_Default)");
return;
}
#endif
s_defaultFilterMode = filterMode;
for (const std::pair<UInt32, GLuint>& pair : s_samplers)
{
if (((pair.first >> 1) & 0x3) == SamplerFilter_Default)
{
bool mipmaps = pair.first & 0x1;
switch (filterMode)
{
case SamplerFilter_Bilinear:
if (mipmaps)
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
else
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case SamplerFilter_Nearest:
if (mipmaps)
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
else
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case SamplerFilter_Trilinear:
if (mipmaps)
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
default:
NazaraError("Texture filter not handled (0x" + String::Number(filterMode, 16) + ')');
break;
}
}
}
}
void TextureSampler::SetDefaultWrapMode(SamplerWrap wrapMode)
{
#if NAZARA_RENDERER_SAFE
if (wrapMode == SamplerWrap_Default)
{
NazaraError("Default wrap mode cannot be set to default enum value (SamplerWrap_Default)");
return;
}
#endif
s_defaultWrapMode = wrapMode;
GLenum wrapEnum = OpenGL::SamplerWrapMode[wrapMode];
for (const std::pair<UInt32, GLuint>& pair : s_samplers)
{
if (((pair.first >> 3) & 0x3) == SamplerWrap_Default)
{
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_R, wrapEnum);
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_T, wrapEnum);
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_S, wrapEnum);
}
}
}
void TextureSampler::Apply(const Texture* texture) const
{
ImageType type = texture->GetType();
GLenum target = OpenGL::TextureTarget[type];
OpenGL::BindTexture(type, texture->GetOpenGLID());
if (s_useAnisotropicFilter)
{
UInt8 anisotropyLevel = (m_anisotropicLevel == 0) ? s_defaultAnisotropyLevel : m_anisotropicLevel;
glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
}
nzSamplerFilter filterMode = (m_filterMode == nzSamplerFilter_Default) ? s_defaultFilterMode : m_filterMode;
SamplerFilter filterMode = (m_filterMode == SamplerFilter_Default) ? s_defaultFilterMode : m_filterMode;
switch (filterMode)
{
case nzSamplerFilter_Bilinear:
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
case SamplerFilter_Bilinear:
if (m_mipmaps)
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
else
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case nzSamplerFilter_Nearest:
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
case SamplerFilter_Nearest:
if (m_mipmaps)
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
else
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case nzSamplerFilter_Trilinear:
// Équivalent au filtrage bilinéaire si les mipmaps sont absentes
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
case SamplerFilter_Trilinear:
if (m_mipmaps)
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
default:
NazaraError("Texture filter not handled (0x" + NzString::Number(filterMode, 16) + ')');
NazaraError("Texture filter not handled (0x" + String::Number(filterMode, 16) + ')');
break;
}
GLenum wrapMode = NzOpenGL::SamplerWrapMode[(m_wrapMode == nzSamplerWrap_Default) ? s_defaultWrapMode : m_wrapMode];
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, wrapMode);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, wrapMode);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, wrapMode);
s_samplers[key] = sampler;
m_samplerId = sampler;
GLenum wrapMode = OpenGL::SamplerWrapMode[(m_wrapMode == SamplerWrap_Default) ? s_defaultWrapMode : m_wrapMode];
switch (type)
{
// Notez l'absence de "break" ici
case ImageType_3D:
glTexParameteri(target, GL_TEXTURE_WRAP_R, wrapMode);
case ImageType_2D:
case ImageType_2D_Array:
case ImageType_Cubemap:
glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode);
case ImageType_1D:
case ImageType_1D_Array:
glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode);
break;
}
}
else
m_samplerId = it->second;
}
bool NzTextureSampler::UseMipmaps(bool mipmaps)
{
if (m_mipmaps != mipmaps)
void TextureSampler::Bind(unsigned int unit) const
{
m_mipmaps = mipmaps;
m_samplerId = 0;
static_assert(SamplerFilter_Max < 0x4, "Maximum sampler filter mode takes more than 2 bits");
static_assert(SamplerWrap_Max < 0x4, "Maximum sampler wrap mode takes more than 2 bits");
return true; // Renvoie true si la valeur a été changée (Donc s'il faut réappliquer le sampler)
if (!m_samplerId)
UpdateSamplerId();
OpenGL::BindSampler(unit, m_samplerId);
}
else
return false;
}
bool NzTextureSampler::Initialize()
{
s_maxAnisotropyLevel = NzRenderer::GetMaxAnisotropyLevel();
s_useAnisotropicFilter = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter);
return true;
}
void NzTextureSampler::Uninitialize()
{
if (!s_samplers.empty())
unsigned int TextureSampler::GetOpenGLID() const
{
NzContext::EnsureContext();
for (const std::pair<nzUInt32, GLuint>& pair : s_samplers)
NzOpenGL::DeleteSampler(pair.second);
if (!m_samplerId)
UpdateSamplerId();
s_samplers.clear();
return m_samplerId;
}
}
nzUInt8 NzTextureSampler::s_defaultAnisotropyLevel = 1;
nzSamplerFilter NzTextureSampler::s_defaultFilterMode = nzSamplerFilter_Trilinear;
nzSamplerWrap NzTextureSampler::s_defaultWrapMode = nzSamplerWrap_Repeat;
void TextureSampler::UpdateSamplerId() const
{
UInt32 key = (((m_mipmaps) ? 1 : 0) << 0) | // 1 bit
(m_filterMode << 1) | // 2 bits
(m_wrapMode << 3) | // 2 bits
(m_anisotropicLevel << 5); // 8 bits
auto it = s_samplers.find(key);
if (it == s_samplers.end())
{
GLuint sampler;
glGenSamplers(1, &sampler);
if (s_useAnisotropicFilter)
{
UInt8 anisotropyLevel = (m_anisotropicLevel == 0) ? s_defaultAnisotropyLevel : m_anisotropicLevel;
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
}
SamplerFilter filterMode = (m_filterMode == SamplerFilter_Default) ? s_defaultFilterMode : m_filterMode;
switch (filterMode)
{
case SamplerFilter_Bilinear:
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case SamplerFilter_Nearest:
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case SamplerFilter_Trilinear:
// Équivalent au filtrage bilinéaire si les mipmaps sont absentes
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
default:
NazaraError("Texture filter not handled (0x" + String::Number(filterMode, 16) + ')');
break;
}
GLenum wrapMode = OpenGL::SamplerWrapMode[(m_wrapMode == SamplerWrap_Default) ? s_defaultWrapMode : m_wrapMode];
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, wrapMode);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, wrapMode);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, wrapMode);
s_samplers[key] = sampler;
m_samplerId = sampler;
}
else
m_samplerId = it->second;
}
bool TextureSampler::UseMipmaps(bool mipmaps)
{
if (m_mipmaps != mipmaps)
{
m_mipmaps = mipmaps;
m_samplerId = 0;
return true; // Renvoie true si la valeur a été changée (Donc s'il faut réappliquer le sampler)
}
else
return false;
}
bool TextureSampler::Initialize()
{
s_maxAnisotropyLevel = Renderer::GetMaxAnisotropyLevel();
s_useAnisotropicFilter = OpenGL::IsSupported(OpenGLExtension_AnisotropicFilter);
return true;
}
void TextureSampler::Uninitialize()
{
if (!s_samplers.empty())
{
Context::EnsureContext();
for (const std::pair<UInt32, GLuint>& pair : s_samplers)
OpenGL::DeleteSampler(pair.second);
s_samplers.clear();
}
}
UInt8 TextureSampler::s_defaultAnisotropyLevel = 1;
SamplerFilter TextureSampler::s_defaultFilterMode = SamplerFilter_Trilinear;
SamplerWrap TextureSampler::s_defaultWrapMode = SamplerWrap_Repeat;
}

View File

@@ -5,25 +5,28 @@
#include <Nazara/Renderer/UberShader.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzUberShader::~NzUberShader()
namespace Nz
{
OnUberShaderRelease(this);
}
bool NzUberShader::Initialize()
{
if (!NzUberShaderLibrary::Initialize())
UberShader::~UberShader()
{
NazaraError("Failed to initialise library");
return false;
OnUberShaderRelease(this);
}
return true;
}
bool UberShader::Initialize()
{
if (!UberShaderLibrary::Initialize())
{
NazaraError("Failed to initialise library");
return false;
}
void NzUberShader::Uninitialize()
{
NzUberShaderLibrary::Uninitialize();
}
return true;
}
NzUberShaderLibrary::LibraryMap NzUberShader::s_library;
void UberShader::Uninitialize()
{
UberShaderLibrary::Uninitialize();
}
UberShaderLibrary::LibraryMap UberShader::s_library;
}

View File

@@ -6,14 +6,17 @@
#include <algorithm>
#include <Nazara/Renderer/Debug.hpp>
NzUberShaderInstance::NzUberShaderInstance(const NzShader* shader) :
m_shader(shader)
namespace Nz
{
}
UberShaderInstance::UberShaderInstance(const Shader* shader) :
m_shader(shader)
{
}
NzUberShaderInstance::~NzUberShaderInstance() = default;
UberShaderInstance::~UberShaderInstance() = default;
const NzShader* NzUberShaderInstance::GetShader() const
{
return m_shader;
const Shader* UberShaderInstance::GetShader() const
{
return m_shader;
}
}

View File

@@ -6,16 +6,19 @@
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzUberShaderInstancePreprocessor::NzUberShaderInstancePreprocessor(const NzShader* shader) :
NzUberShaderInstance(shader)
namespace Nz
{
}
NzUberShaderInstancePreprocessor::~NzUberShaderInstancePreprocessor() = default;
bool NzUberShaderInstancePreprocessor::Activate() const
{
NzRenderer::SetShader(m_shader);
return true;
UberShaderInstancePreprocessor::UberShaderInstancePreprocessor(const Shader* shader) :
UberShaderInstance(shader)
{
}
UberShaderInstancePreprocessor::~UberShaderInstancePreprocessor() = default;
bool UberShaderInstancePreprocessor::Activate() const
{
Renderer::SetShader(m_shader);
return true;
}
}

View File

@@ -10,175 +10,178 @@
#include <memory>
#include <Nazara/Renderer/Debug.hpp>
NzUberShaderPreprocessor::~NzUberShaderPreprocessor()
namespace Nz
{
OnUberShaderPreprocessorRelease(this);
}
NzUberShaderInstance* NzUberShaderPreprocessor::Get(const NzParameterList& parameters) const
{
// Première étape, transformer les paramètres en un flag
nzUInt32 flags = 0;
for (auto it = m_flags.begin(); it != m_flags.end(); ++it)
UberShaderPreprocessor::~UberShaderPreprocessor()
{
if (parameters.HasParameter(it->first))
{
bool value;
if (parameters.GetBooleanParameter(it->first, &value) && value)
flags |= it->second;
}
OnUberShaderPreprocessorRelease(this);
}
// Le shader fait-il partie du cache ?
auto shaderIt = m_cache.find(flags);
// Si non, il nous faut le construire
if (shaderIt == m_cache.end())
UberShaderInstance* UberShaderPreprocessor::Get(const ParameterList& parameters) const
{
try
// Première étape, transformer les paramètres en un flag
UInt32 flags = 0;
for (auto it = m_flags.begin(); it != m_flags.end(); ++it)
{
// Une exception sera lancée à la moindre erreur et celle-ci ne sera pas enregistrée dans le log (car traitée dans le bloc catch)
NzErrorFlags errFlags(nzErrorFlag_Silent | nzErrorFlag_ThrowException, true);
NzShaderRef shader = NzShader::New();
shader->Create();
for (unsigned int i = 0; i <= nzShaderStage_Max; ++i)
if (parameters.HasParameter(it->first))
{
const Shader& shaderStage = m_shaders[i];
// Le shader stage est-il activé dans cette version du shader ?
if (shaderStage.present && (flags & shaderStage.requiredFlags) == shaderStage.requiredFlags)
{
nzUInt32 stageFlags = 0;
for (auto it = shaderStage.flags.begin(); it != shaderStage.flags.end(); ++it)
{
if (parameters.HasParameter(it->first))
{
bool value;
if (parameters.GetBooleanParameter(it->first, &value) && value)
stageFlags |= it->second;
}
}
auto stageIt = shaderStage.cache.find(stageFlags);
if (stageIt == shaderStage.cache.end())
{
NzShaderStage stage;
stage.Create(static_cast<nzShaderStage>(i));
unsigned int glslVersion = NzOpenGL::GetGLSLVersion();
NzStringStream code;
code << "#version " << glslVersion << "\n\n";
code << "#define GLSL_VERSION " << glslVersion << "\n\n";
code << "#define EARLY_FRAGMENT_TEST " << (glslVersion >= 420 || NzOpenGL::IsSupported(nzOpenGLExtension_Shader_ImageLoadStore)) << "\n\n";
for (auto it = shaderStage.flags.begin(); it != shaderStage.flags.end(); ++it)
code << "#define " << it->first << ' ' << ((stageFlags & it->second) ? '1' : '0') << '\n';
code << "\n#line 1\n"; // Pour que les éventuelles erreurs du shader se réfèrent à la bonne ligne
code << shaderStage.source;
stage.SetSource(code);
stage.Compile();
stageIt = shaderStage.cache.emplace(flags, std::move(stage)).first;
}
shader->AttachStage(static_cast<nzShaderStage>(i), stageIt->second);
}
bool value;
if (parameters.GetBooleanParameter(it->first, &value) && value)
flags |= it->second;
}
shader->Link();
// On construit l'instant
shaderIt = m_cache.emplace(flags, shader.Get()).first;
}
catch (const std::exception&)
// Le shader fait-il partie du cache ?
auto shaderIt = m_cache.find(flags);
// Si non, il nous faut le construire
if (shaderIt == m_cache.end())
{
NzErrorFlags errFlags(nzErrorFlag_ThrowExceptionDisabled);
try
{
// Une exception sera lancée à la moindre erreur et celle-ci ne sera pas enregistrée dans le log (car traitée dans le bloc catch)
ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowException, true);
NazaraError("Failed to build UberShader instance: " + NzError::GetLastError());
throw;
ShaderRef shader = Shader::New();
shader->Create();
for (unsigned int i = 0; i <= ShaderStageType_Max; ++i)
{
const CachedShader& shaderStage = m_shaders[i];
// Le shader stage est-il activé dans cette version du shader ?
if (shaderStage.present && (flags & shaderStage.requiredFlags) == shaderStage.requiredFlags)
{
UInt32 stageFlags = 0;
for (auto it = shaderStage.flags.begin(); it != shaderStage.flags.end(); ++it)
{
if (parameters.HasParameter(it->first))
{
bool value;
if (parameters.GetBooleanParameter(it->first, &value) && value)
stageFlags |= it->second;
}
}
auto stageIt = shaderStage.cache.find(stageFlags);
if (stageIt == shaderStage.cache.end())
{
ShaderStage stage;
stage.Create(static_cast<ShaderStageType>(i));
unsigned int glslVersion = OpenGL::GetGLSLVersion();
StringStream code;
code << "#version " << glslVersion << "\n\n";
code << "#define GLSL_VERSION " << glslVersion << "\n\n";
code << "#define EARLY_FRAGMENT_TEST " << (glslVersion >= 420 || OpenGL::IsSupported(OpenGLExtension_Shader_ImageLoadStore)) << "\n\n";
for (auto it = shaderStage.flags.begin(); it != shaderStage.flags.end(); ++it)
code << "#define " << it->first << ' ' << ((stageFlags & it->second) ? '1' : '0') << '\n';
code << "\n#line 1\n"; // Pour que les éventuelles erreurs du shader se réfèrent à la bonne ligne
code << shaderStage.source;
stage.SetSource(code);
stage.Compile();
stageIt = shaderStage.cache.emplace(flags, std::move(stage)).first;
}
shader->AttachStage(static_cast<ShaderStageType>(i), stageIt->second);
}
}
shader->Link();
// On construit l'instant
shaderIt = m_cache.emplace(flags, shader.Get()).first;
}
catch (const std::exception&)
{
ErrorFlags errFlags(ErrorFlag_ThrowExceptionDisabled);
NazaraError("Failed to build UberShader instance: " + Error::GetLastError());
throw;
}
}
return &shaderIt->second;
}
return &shaderIt->second;
}
void NzUberShaderPreprocessor::SetShader(nzShaderStage stage, const NzString& source, const NzString& shaderFlags, const NzString& requiredFlags)
{
Shader& shader = m_shaders[stage];
shader.present = true;
shader.source = source;
// On extrait les flags de la chaîne
std::vector<NzString> flags;
shaderFlags.Split(flags, ' ');
for (NzString& flag : flags)
void UberShaderPreprocessor::SetShader(ShaderStageType stage, const String& source, const String& shaderFlags, const String& requiredFlags)
{
auto it = m_flags.find(flag);
if (it == m_flags.end())
m_flags[flag] = 1U << m_flags.size();
CachedShader& shader = m_shaders[stage];
shader.present = true;
shader.source = source;
auto it2 = shader.flags.find(flag);
if (it2 == shader.flags.end())
shader.flags[flag] = 1U << shader.flags.size();
}
// On extrait les flags de la chaîne
std::vector<String> flags;
shaderFlags.Split(flags, ' ');
// On construit les flags requis pour l'activation du shader
shader.requiredFlags = 0;
flags.clear();
requiredFlags.Split(flags, ' ');
for (NzString& flag : flags)
{
nzUInt32 flagVal;
auto it = m_flags.find(flag);
if (it == m_flags.end())
for (String& flag : flags)
{
flagVal = 1U << m_flags.size();
m_flags[flag] = flagVal;
auto it = m_flags.find(flag);
if (it == m_flags.end())
m_flags[flag] = 1U << m_flags.size();
auto it2 = shader.flags.find(flag);
if (it2 == shader.flags.end())
shader.flags[flag] = 1U << shader.flags.size();
}
else
flagVal = it->second;
shader.requiredFlags |= flagVal;
// On construit les flags requis pour l'activation du shader
shader.requiredFlags = 0;
flags.clear();
requiredFlags.Split(flags, ' ');
for (String& flag : flags)
{
UInt32 flagVal;
auto it = m_flags.find(flag);
if (it == m_flags.end())
{
flagVal = 1U << m_flags.size();
m_flags[flag] = flagVal;
}
else
flagVal = it->second;
shader.requiredFlags |= flagVal;
}
}
}
bool NzUberShaderPreprocessor::SetShaderFromFile(nzShaderStage stage, const NzString& filePath, const NzString& shaderFlags, const NzString& requiredFlags)
{
NzFile file(filePath);
if (!file.Open(nzOpenMode_ReadOnly | nzOpenMode_Text))
bool UberShaderPreprocessor::SetShaderFromFile(ShaderStageType stage, const String& filePath, const String& shaderFlags, const String& requiredFlags)
{
NazaraError("Failed to open \"" + filePath + '"');
return false;
File file(filePath);
if (!file.Open(OpenMode_ReadOnly | OpenMode_Text))
{
NazaraError("Failed to open \"" + filePath + '"');
return false;
}
unsigned int length = static_cast<unsigned int>(file.GetSize());
String source(length, '\0');
if (file.Read(&source[0], length) != length)
{
NazaraError("Failed to read program file");
return false;
}
file.Close();
SetShader(stage, source, shaderFlags, requiredFlags);
return true;
}
unsigned int length = static_cast<unsigned int>(file.GetSize());
NzString source(length, '\0');
if (file.Read(&source[0], length) != length)
bool UberShaderPreprocessor::IsSupported()
{
NazaraError("Failed to read program file");
return false;
return true; // Forcément supporté
}
file.Close();
SetShader(stage, source, shaderFlags, requiredFlags);
return true;
}
bool NzUberShaderPreprocessor::IsSupported()
{
return true; // Forcément supporté
}

View File

@@ -14,232 +14,235 @@
#include <cstring>
#include <Nazara/Renderer/Debug.hpp>
NzContextImpl::NzContextImpl()
namespace Nz
{
}
bool NzContextImpl::Activate()
{
return wglMakeCurrent(m_deviceContext, m_context) == TRUE;
}
bool NzContextImpl::Create(NzContextParameters& parameters)
{
if (parameters.window)
ContextImpl::ContextImpl()
{
m_window = static_cast<HWND>(parameters.window);
m_ownsWindow = false;
}
else
bool ContextImpl::Activate()
{
m_window = CreateWindowA("STATIC", nullptr, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
if (!m_window)
return wglMakeCurrent(m_deviceContext, m_context) == TRUE;
}
bool ContextImpl::Create(ContextParameters& parameters)
{
if (parameters.window)
{
NazaraError("Failed to create window");
return false;
}
ShowWindow(m_window, SW_HIDE);
m_ownsWindow = true;
}
// En cas d'exception, la ressource sera quand même libérée
NzCallOnExit onExit([this] ()
{
Destroy();
});
m_deviceContext = GetDC(m_window);
if (!m_deviceContext)
{
NazaraError("Failed to get device context");
return false;
}
int pixelFormat = 0;
if (parameters.antialiasingLevel > 0)
{
if (wglChoosePixelFormat)
{
bool valid;
UINT numFormats;
int attributes[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_COLOR_BITS_ARB, (parameters.bitsPerPixel == 32) ? 24 : parameters.bitsPerPixel,
WGL_ALPHA_BITS_ARB, (parameters.bitsPerPixel == 32) ? 8 : 0,
WGL_DEPTH_BITS_ARB, parameters.depthBits,
WGL_STENCIL_BITS_ARB, parameters.stencilBits,
WGL_DOUBLE_BUFFER_ARB, (parameters.doubleBuffered) ? GL_TRUE : GL_FALSE,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, parameters.antialiasingLevel,
0, 0
};
do
{
valid = (wglChoosePixelFormat(m_deviceContext, attributes, nullptr, 1, &pixelFormat, &numFormats) == TRUE);
}
while ((!valid || numFormats == 0) && --attributes[19] > 0);
if (!valid)
{
NazaraWarning("Could not find a format matching requirements, disabling antialiasing...");
pixelFormat = 0;
}
parameters.antialiasingLevel = attributes[19];
m_window = static_cast<HWND>(parameters.window);
m_ownsWindow = false;
}
else
{
NazaraWarning("Antialiasing is not supported");
parameters.antialiasingLevel = 0;
m_window = CreateWindowA("STATIC", nullptr, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
if (!m_window)
{
NazaraError("Failed to create window");
return false;
}
ShowWindow(m_window, SW_HIDE);
m_ownsWindow = true;
}
}
PIXELFORMATDESCRIPTOR descriptor;
ZeroMemory(&descriptor, sizeof(PIXELFORMATDESCRIPTOR));
descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
descriptor.nVersion = 1;
if (pixelFormat == 0)
{
descriptor.cColorBits = parameters.bitsPerPixel;
descriptor.cDepthBits = parameters.depthBits;
descriptor.cStencilBits = parameters.stencilBits;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
descriptor.iPixelType = PFD_TYPE_RGBA;
if (parameters.bitsPerPixel == 32)
descriptor.cAlphaBits = 8;
if (parameters.doubleBuffered)
descriptor.dwFlags |= PFD_DOUBLEBUFFER;
pixelFormat = ChoosePixelFormat(m_deviceContext, &descriptor);
if (pixelFormat == 0)
// En cas d'exception, la ressource sera quand même libérée
CallOnExit onExit([this] ()
{
NazaraError("Failed to choose pixel format");
Destroy();
});
m_deviceContext = GetDC(m_window);
if (!m_deviceContext)
{
NazaraError("Failed to get device context");
return false;
}
}
if (!SetPixelFormat(m_deviceContext, pixelFormat, &descriptor))
{
NazaraError("Failed to set pixel format");
return false;
}
// Arrivé ici, le format de pixel est choisi, nous récupérons donc les paramètres réels du futur contexte
if (DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0)
{
parameters.bitsPerPixel = descriptor.cColorBits + descriptor.cAlphaBits;
parameters.depthBits = descriptor.cDepthBits;
parameters.stencilBits = descriptor.cDepthBits;
}
else
NazaraWarning("Failed to get context's parameters");
HGLRC shareContext = (parameters.shared) ? static_cast<NzContextImpl*>(parameters.shareContext->m_impl)->m_context : nullptr;
m_context = nullptr;
if (wglCreateContextAttribs)
{
int attributes[4*2+1];
int* attrib = attributes;
*attrib++ = WGL_CONTEXT_MAJOR_VERSION_ARB;
*attrib++ = parameters.majorVersion;
*attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB;
*attrib++ = parameters.minorVersion;
if (parameters.majorVersion >= 3)
int pixelFormat = 0;
if (parameters.antialiasingLevel > 0)
{
*attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB;
*attrib++ = (parameters.compatibilityProfile) ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
if (wglChoosePixelFormat)
{
bool valid;
UINT numFormats;
// Les contextes forward-compatible ne sont plus utilisés pour cette raison :
// http://www.opengl.org/discussion_boards/showthread.php/175052-Forward-compatible-vs-Core-profile
int attributes[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_COLOR_BITS_ARB, (parameters.bitsPerPixel == 32) ? 24 : parameters.bitsPerPixel,
WGL_ALPHA_BITS_ARB, (parameters.bitsPerPixel == 32) ? 8 : 0,
WGL_DEPTH_BITS_ARB, parameters.depthBits,
WGL_STENCIL_BITS_ARB, parameters.stencilBits,
WGL_DOUBLE_BUFFER_ARB, (parameters.doubleBuffered) ? GL_TRUE : GL_FALSE,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, parameters.antialiasingLevel,
0, 0
};
do
{
valid = (wglChoosePixelFormat(m_deviceContext, attributes, nullptr, 1, &pixelFormat, &numFormats) == TRUE);
}
while ((!valid || numFormats == 0) && --attributes[19] > 0);
if (!valid)
{
NazaraWarning("Could not find a format matching requirements, disabling antialiasing...");
pixelFormat = 0;
}
parameters.antialiasingLevel = attributes[19];
}
else
{
NazaraWarning("Antialiasing is not supported");
parameters.antialiasingLevel = 0;
}
}
if (parameters.debugMode)
PIXELFORMATDESCRIPTOR descriptor;
ZeroMemory(&descriptor, sizeof(PIXELFORMATDESCRIPTOR));
descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
descriptor.nVersion = 1;
if (pixelFormat == 0)
{
*attrib++ = WGL_CONTEXT_FLAGS_ARB;
*attrib++ = WGL_CONTEXT_DEBUG_BIT_ARB;
descriptor.cColorBits = parameters.bitsPerPixel;
descriptor.cDepthBits = parameters.depthBits;
descriptor.cStencilBits = parameters.stencilBits;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
descriptor.iPixelType = PFD_TYPE_RGBA;
if (parameters.bitsPerPixel == 32)
descriptor.cAlphaBits = 8;
if (parameters.doubleBuffered)
descriptor.dwFlags |= PFD_DOUBLEBUFFER;
pixelFormat = ChoosePixelFormat(m_deviceContext, &descriptor);
if (pixelFormat == 0)
{
NazaraError("Failed to choose pixel format");
return false;
}
}
*attrib++ = 0;
m_context = wglCreateContextAttribs(m_deviceContext, shareContext, attributes);
}
if (!m_context)
{
m_context = wglCreateContext(m_deviceContext);
if (shareContext)
if (!SetPixelFormat(m_deviceContext, pixelFormat, &descriptor))
{
// wglShareLists n'est pas thread-safe (source: SFML)
static NzMutex mutex;
NzLockGuard lock(mutex);
if (!wglShareLists(shareContext, m_context))
NazaraWarning("Failed to share the context: " + NzError::GetLastSystemError());
NazaraError("Failed to set pixel format");
return false;
}
}
if (!m_context)
{
NazaraError("Failed to create context");
return false;
}
// Arrivé ici, le format de pixel est choisi, nous récupérons donc les paramètres réels du futur contexte
if (DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0)
{
parameters.bitsPerPixel = descriptor.cColorBits + descriptor.cAlphaBits;
parameters.depthBits = descriptor.cDepthBits;
parameters.stencilBits = descriptor.cDepthBits;
}
else
NazaraWarning("Failed to get context's parameters");
onExit.Reset();
HGLRC shareContext = (parameters.shared) ? static_cast<ContextImpl*>(parameters.shareContext->m_impl)->m_context : nullptr;
return true;
}
void NzContextImpl::Destroy()
{
if (m_context)
{
if (wglGetCurrentContext() == m_context)
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(m_context);
m_context = nullptr;
if (wglCreateContextAttribs)
{
int attributes[4*2+1];
int* attrib = attributes;
*attrib++ = WGL_CONTEXT_MAJOR_VERSION_ARB;
*attrib++ = parameters.majorVersion;
*attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB;
*attrib++ = parameters.minorVersion;
if (parameters.majorVersion >= 3)
{
*attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB;
*attrib++ = (parameters.compatibilityProfile) ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
// Les contextes forward-compatible ne sont plus utilisés pour cette raison :
// http://www.opengl.org/discussion_boards/showthread.php/175052-Forward-compatible-vs-Core-profile
}
if (parameters.debugMode)
{
*attrib++ = WGL_CONTEXT_FLAGS_ARB;
*attrib++ = WGL_CONTEXT_DEBUG_BIT_ARB;
}
*attrib++ = 0;
m_context = wglCreateContextAttribs(m_deviceContext, shareContext, attributes);
}
if (!m_context)
{
m_context = wglCreateContext(m_deviceContext);
if (shareContext)
{
// wglShareLists n'est pas thread-safe (source: SFML)
static Mutex mutex;
LockGuard lock(mutex);
if (!wglShareLists(shareContext, m_context))
NazaraWarning("Failed to share the context: " + Error::GetLastSystemError());
}
}
if (!m_context)
{
NazaraError("Failed to create context");
return false;
}
onExit.Reset();
return true;
}
if (m_deviceContext)
void ContextImpl::Destroy()
{
ReleaseDC(m_window, m_deviceContext);
m_deviceContext = nullptr;
if (m_context)
{
if (wglGetCurrentContext() == m_context)
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(m_context);
m_context = nullptr;
}
if (m_deviceContext)
{
ReleaseDC(m_window, m_deviceContext);
m_deviceContext = nullptr;
}
if (m_ownsWindow)
{
DestroyWindow(m_window);
m_window = nullptr;
}
}
if (m_ownsWindow)
void ContextImpl::EnableVerticalSync(bool enabled)
{
DestroyWindow(m_window);
m_window = nullptr;
if (wglSwapInterval)
wglSwapInterval(enabled ? 1 : 0);
else
NazaraError("Vertical sync not supported");
}
void ContextImpl::SwapBuffers()
{
::SwapBuffers(m_deviceContext);
}
bool ContextImpl::Desactivate()
{
return wglMakeCurrent(nullptr, nullptr) == TRUE;
}
}
void NzContextImpl::EnableVerticalSync(bool enabled)
{
if (wglSwapInterval)
wglSwapInterval(enabled ? 1 : 0);
else
NazaraError("Vertical sync not supported");
}
void NzContextImpl::SwapBuffers()
{
::SwapBuffers(m_deviceContext);
}
bool NzContextImpl::Desactivate()
{
return wglMakeCurrent(nullptr, nullptr) == TRUE;
}

View File

@@ -11,28 +11,31 @@
#include <Nazara/Renderer/ContextParameters.hpp>
#include <windows.h>
class NzContextImpl
namespace Nz
{
public:
NzContextImpl();
class ContextImpl
{
public:
ContextImpl();
bool Activate();
bool Activate();
bool Create(NzContextParameters& parameters);
bool Create(ContextParameters& parameters);
void Destroy();
void Destroy();
void EnableVerticalSync(bool enabled);
void EnableVerticalSync(bool enabled);
void SwapBuffers();
void SwapBuffers();
static bool Desactivate();
static bool Desactivate();
private:
HDC m_deviceContext;
HGLRC m_context;
HWND m_window;
bool m_ownsWindow;
};
private:
HDC m_deviceContext;
HGLRC m_context;
HWND m_window;
bool m_ownsWindow;
};
}
#endif // NAZARA_CONTEXTIMPL_HPP