Add new Renderer architecture (far from complete)
Former-commit-id: 52226793d7a087dfe0523315d3303934daffee49 [formerly 9de1c04df6b371f861a2eee8bba38902ee5041cd] [formerly ecd3099df5498722f6390447f40bd3907b8e40c4 [formerly 3076df585565fc9759ab3e718270f2e5ef620840]] Former-commit-id: 92d52f967d0b088d1271afef26069e08cacd6b0f [formerly 5fe27e2ead104278951c772c2121a7b677f88d4d] Former-commit-id: fb6c2456d8edd3ec022d5d953f79fecdd4f2b8f4
This commit is contained in:
@@ -1,376 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_GLX)
|
||||
#include <Nazara/Renderer/GLX/ContextImpl.hpp>
|
||||
#define CALLBACK
|
||||
#else
|
||||
#error Lack of implementation: Context
|
||||
#endif
|
||||
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
thread_local const Context* s_currentContext = nullptr;
|
||||
thread_local const Context* 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)
|
||||
{
|
||||
NazaraUnused(length);
|
||||
|
||||
StringStream ss;
|
||||
ss << "OpenGL debug message (ID: 0x" << String::Number(id, 16) << "):\n";
|
||||
ss << "Sent by context: " << userParam;
|
||||
ss << "\n-Source: ";
|
||||
switch (source)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
if (!s_threadContext->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to active thread context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
void Context::Uninitialize()
|
||||
{
|
||||
ContextLibrary::Uninitialize();
|
||||
s_contexts.clear(); // On supprime tous les contextes créés
|
||||
s_reference.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> Context::s_reference;
|
||||
std::vector<std::unique_ptr<Context>> Context::s_contexts;
|
||||
ContextLibrary::LibraryMap Context::s_library;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ContextParameters.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
// Version majeure d'OpenGL, initialisé par OpenGL::Initialize()
|
||||
UInt8 ContextParameters::defaultMajorVersion;
|
||||
|
||||
// Version majeure d'OpenGL, initialisé par OpenGL::Initialize()
|
||||
UInt8 ContextParameters::defaultMinorVersion;
|
||||
|
||||
// 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 ContextParameters::defaultCompatibilityProfile = false;
|
||||
|
||||
// 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 ContextParameters::defaultDoubleBuffered = false;
|
||||
|
||||
// Active le partage des ressources entre contextes (Via le defaultShareContext)
|
||||
bool ContextParameters::defaultShared = true;
|
||||
}
|
||||
@@ -1,741 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/DebugDrawer.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderStates.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Utility/BufferMapper.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/Skeleton.hpp>
|
||||
#include <Nazara/Utility/VertexBuffer.hpp>
|
||||
#include <Nazara/Utility/VertexDeclaration.hpp>
|
||||
#include <Nazara/Utility/VertexStruct.hpp>
|
||||
#include <memory>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
///TODO: Améliorer
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static Shader* s_shader = nullptr;
|
||||
static Color s_primaryColor;
|
||||
static Color s_secondaryColor;
|
||||
static RenderStates s_renderStates;
|
||||
static VertexBuffer s_vertexBuffer;
|
||||
static bool s_initialized = false;
|
||||
static int s_colorLocation = -1;
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const BoundingVolumef& volume)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!volume.IsFinite())
|
||||
return;
|
||||
|
||||
Color oldPrimaryColor = s_primaryColor;
|
||||
|
||||
Draw(volume.aabb);
|
||||
|
||||
s_primaryColor = s_secondaryColor;
|
||||
Draw(volume.obb);
|
||||
|
||||
s_primaryColor = oldPrimaryColor;
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Boxi& box)
|
||||
{
|
||||
Draw(Boxf(box));
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Boxf& box)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
Vector3f max, min;
|
||||
max = box.GetMaximum();
|
||||
min = box.GetMinimum();
|
||||
|
||||
vertex->position.Set(min.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, min.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, max.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, min.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, max.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, max.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, max.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, min.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, max.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, max.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, min.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, min.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, min.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, max.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, max.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, max.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, max.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, max.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, max.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, min.y, max.z);
|
||||
vertex++;
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 24);
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Boxui& box)
|
||||
{
|
||||
Draw(Boxf(box));
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Frustumf& frustum)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 24);
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const OrientedBoxf& orientedBox)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 24);
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Skeleton* skeleton)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int jointCount = skeleton->GetJointCount();
|
||||
if (s_vertexBuffer.GetVertexCount() < jointCount*2)
|
||||
{
|
||||
NazaraError("Debug buffer not large enougth to draw object");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, jointCount*2);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
unsigned int vertexCount = 0;
|
||||
for (unsigned int i = 0; i < jointCount; ++i)
|
||||
{
|
||||
const Node* joint = skeleton->GetJoint(i);
|
||||
const Node* parent = joint->GetParent();
|
||||
if (parent)
|
||||
{
|
||||
vertex->position = joint->GetPosition();
|
||||
vertex++;
|
||||
|
||||
vertex->position = parent->GetPosition();
|
||||
vertex++;
|
||||
|
||||
vertexCount += 2;
|
||||
}
|
||||
}
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
if (vertexCount > 0)
|
||||
{
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, vertexCount);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_secondaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_PointList, 0, vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Vector3f& position, float size)
|
||||
{
|
||||
Draw(Boxf(position.x - size*0.5f, position.y - size*0.5f, position.z - size*0.5f, size, size, size));
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawAxes(const Vector3f& position, float size)
|
||||
{
|
||||
Color oldPrimaryColor = s_primaryColor;
|
||||
s_primaryColor = Color::Red;
|
||||
DrawLine(position, position + Vector3f::UnitX() * 3.f * size / 4.f);
|
||||
s_primaryColor = Color::Green;
|
||||
DrawLine(position, position + Vector3f::UnitY() * 3.f * size / 4.f);
|
||||
s_primaryColor = Color::Blue;
|
||||
DrawLine(position, position + Vector3f::UnitZ() * 3.f * size / 4.f);
|
||||
|
||||
s_primaryColor = Color::Red;
|
||||
DrawCone(position + Vector3f::UnitX() * size, EulerAnglesf(0.f, 90.f, 0.f), 15, size / 4.f);
|
||||
s_primaryColor = Color::Green;
|
||||
DrawCone(position + Vector3f::UnitY() * size, EulerAnglesf(-90.f, 0.f, 0.f), 15, size / 4.f);
|
||||
s_primaryColor = Color::Blue;
|
||||
DrawCone(position + Vector3f::UnitZ() * size, EulerAnglesf(0.f, 0.f, 0.f), 15, size / 4.f);
|
||||
s_primaryColor = oldPrimaryColor;
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawBinormals(const StaticMesh* subMesh)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int normalCount = subMesh->GetVertexCount();
|
||||
unsigned int vertexCount = normalCount*2;
|
||||
if (s_vertexBuffer.GetVertexCount() < vertexCount)
|
||||
{
|
||||
NazaraError("Debug buffer not large enougth to draw object");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly);
|
||||
BufferMapper<VertexBuffer> outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount);
|
||||
|
||||
MeshVertex* inputVertex = static_cast<MeshVertex*>(inputMapper.GetPointer());
|
||||
VertexStruct_XYZ* outputVertex = static_cast<VertexStruct_XYZ*>(outputMapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < normalCount; ++i)
|
||||
{
|
||||
outputVertex->position = inputVertex->position;
|
||||
outputVertex++;
|
||||
|
||||
outputVertex->position = inputVertex->position + Vector3f::CrossProduct(inputVertex->normal, inputVertex->tangent)*0.01f;
|
||||
outputVertex++;
|
||||
|
||||
inputVertex++;
|
||||
}
|
||||
|
||||
inputMapper.Unmap();
|
||||
outputMapper.Unmap();
|
||||
|
||||
if (vertexCount > 0)
|
||||
{
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawCone(const Vector3f& origin, const Quaternionf& rotation, float angle, float length)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4f transformMatrix;
|
||||
transformMatrix.MakeIdentity();
|
||||
transformMatrix.SetRotation(rotation);
|
||||
transformMatrix.SetTranslation(origin);
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 16);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
// On calcule le reste des points
|
||||
Vector3f base(Vector3f::Forward()*length);
|
||||
|
||||
// Il nous faut maintenant le rayon du cercle projeté à cette distance
|
||||
// Tangente = Opposé/Adjaçent <=> Opposé = Adjaçent*Tangente
|
||||
float radius = length*std::tan(DegreeToRadian(angle));
|
||||
Vector3f lExtend = Vector3f::Left()*radius;
|
||||
Vector3f uExtend = Vector3f::Up()*radius;
|
||||
|
||||
vertex->position.Set(transformMatrix * Vector3f::Zero());
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base + lExtend + uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * (base + lExtend + uExtend));
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base + lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * Vector3f::Zero());
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base + lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * (base + lExtend - uExtend));
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base - lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * Vector3f::Zero());
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base - lExtend + uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * (base - lExtend + uExtend));
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base - lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * Vector3f::Zero());
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base - lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * (base - lExtend + uExtend));
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base + lExtend + uExtend));
|
||||
vertex++;
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 16);
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawLine(const Vector3f& p1, const Vector3f& p2)
|
||||
{
|
||||
if (!s_initialized && !Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
VertexStruct_XYZ buffer[2];
|
||||
buffer[0].position = p1;
|
||||
buffer[1].position = p2;
|
||||
|
||||
s_vertexBuffer.Fill(&buffer[0], 0, 2);
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 2);
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawPoints(const Vector3f* ptr, unsigned int pointCount)
|
||||
{
|
||||
static_assert(sizeof(VertexStruct_XYZ) == sizeof(Vector3f), "VertexStruct_XYZ is no longer equal to Vector3f, please rewrite this");
|
||||
|
||||
if (!s_initialized && !Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pointCount > 0)
|
||||
{
|
||||
s_vertexBuffer.Fill(ptr, 0, pointCount);
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_PointList, 0, pointCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawNormals(const StaticMesh* subMesh)
|
||||
{
|
||||
if (!s_initialized && !Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int normalCount = subMesh->GetVertexCount();
|
||||
unsigned int vertexCount = normalCount*2;
|
||||
if (s_vertexBuffer.GetVertexCount() < vertexCount)
|
||||
{
|
||||
NazaraError("Debug buffer not large enougth to draw object");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly);
|
||||
BufferMapper<VertexBuffer> outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount);
|
||||
|
||||
MeshVertex* inputVertex = static_cast<MeshVertex*>(inputMapper.GetPointer());
|
||||
VertexStruct_XYZ* outputVertex = static_cast<VertexStruct_XYZ*>(outputMapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < normalCount; ++i)
|
||||
{
|
||||
outputVertex->position = inputVertex->position;
|
||||
outputVertex++;
|
||||
|
||||
outputVertex->position = inputVertex->position + inputVertex->normal*0.01f;
|
||||
outputVertex++;
|
||||
|
||||
inputVertex++;
|
||||
}
|
||||
|
||||
inputMapper.Unmap();
|
||||
outputMapper.Unmap();
|
||||
|
||||
if (vertexCount > 0)
|
||||
{
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawTangents(const StaticMesh* subMesh)
|
||||
{
|
||||
if (!s_initialized && !Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int tangentCount = subMesh->GetVertexCount();
|
||||
unsigned int vertexCount = tangentCount*2;
|
||||
if (s_vertexBuffer.GetVertexCount() < vertexCount)
|
||||
{
|
||||
NazaraError("Debug buffer not large enougth to draw object");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly);
|
||||
BufferMapper<VertexBuffer> outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount);
|
||||
|
||||
MeshVertex* inputVertex = static_cast<MeshVertex*>(inputMapper.GetPointer());
|
||||
VertexStruct_XYZ* outputVertex = static_cast<VertexStruct_XYZ*>(outputMapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < tangentCount; ++i)
|
||||
{
|
||||
outputVertex->position = inputVertex->position;
|
||||
outputVertex++;
|
||||
|
||||
outputVertex->position = inputVertex->position + inputVertex->tangent*0.01f;
|
||||
outputVertex++;
|
||||
|
||||
inputVertex++;
|
||||
}
|
||||
|
||||
inputMapper.Unmap();
|
||||
outputMapper.Unmap();
|
||||
|
||||
if (vertexCount > 0)
|
||||
{
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::EnableDepthBuffer(bool depthBuffer)
|
||||
{
|
||||
s_renderStates.depthBuffer = depthBuffer;
|
||||
}
|
||||
|
||||
float DebugDrawer::GetLineWidth()
|
||||
{
|
||||
return s_renderStates.lineWidth;
|
||||
}
|
||||
|
||||
float DebugDrawer::GetPointSize()
|
||||
{
|
||||
return s_renderStates.pointSize;
|
||||
}
|
||||
|
||||
Color DebugDrawer::GetPrimaryColor()
|
||||
{
|
||||
return s_primaryColor;
|
||||
}
|
||||
|
||||
Color DebugDrawer::GetSecondaryColor()
|
||||
{
|
||||
return s_secondaryColor;
|
||||
}
|
||||
|
||||
bool DebugDrawer::Initialize()
|
||||
{
|
||||
if (!s_initialized)
|
||||
{
|
||||
// s_shader
|
||||
s_shader = ShaderLibrary::Get("DebugSimple");
|
||||
s_colorLocation = s_shader->GetUniformLocation("Color");
|
||||
|
||||
// s_vertexBuffer
|
||||
try
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
s_vertexBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ), 65365, DataStorage_Hardware, BufferUsage_Dynamic);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraError("Failed to create buffer: " + String(e.what()));
|
||||
|
||||
Uninitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
s_primaryColor = Color::Red;
|
||||
s_renderStates.depthBuffer = true;
|
||||
s_secondaryColor = Color::Green;
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugDrawer::IsDepthBufferEnabled()
|
||||
{
|
||||
return s_renderStates.depthBuffer;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetLineWidth(float width)
|
||||
{
|
||||
s_renderStates.lineWidth = width;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetPointSize(float size)
|
||||
{
|
||||
s_renderStates.pointSize = size;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetPrimaryColor(const Color& color)
|
||||
{
|
||||
s_primaryColor = color;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetSecondaryColor(const Color& color)
|
||||
{
|
||||
s_secondaryColor = color;
|
||||
}
|
||||
|
||||
void DebugDrawer::Uninitialize()
|
||||
{
|
||||
s_shader = nullptr;
|
||||
s_vertexBuffer.Reset();
|
||||
s_initialized = false;
|
||||
}
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila
|
||||
|
||||
#include <Nazara/Renderer/GLX/ContextImpl.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
using namespace GLX;
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
Display* m_display;
|
||||
int m_sharedDisplay = 0;
|
||||
|
||||
bool ctxErrorOccurred = false;
|
||||
int ctxErrorHandler( Display* /*dpy*/, XErrorEvent* /*ev*/ )
|
||||
{
|
||||
ctxErrorOccurred = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ContextImpl::ContextImpl() :
|
||||
m_colormap(0),
|
||||
m_context(0),
|
||||
m_window(0),
|
||||
m_ownsWindow(false)
|
||||
{
|
||||
if (m_sharedDisplay == 0)
|
||||
m_display = XOpenDisplay(nullptr);
|
||||
|
||||
++m_sharedDisplay;
|
||||
}
|
||||
|
||||
ContextImpl::~ContextImpl()
|
||||
{
|
||||
Destroy();
|
||||
|
||||
if (--m_sharedDisplay == 0)
|
||||
{
|
||||
XCloseDisplay(m_display);
|
||||
m_display = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ContextImpl::Activate()
|
||||
{
|
||||
return glXMakeCurrent(m_display, m_window, m_context) == true;
|
||||
}
|
||||
|
||||
bool ContextImpl::Create(ContextParameters& parameters)
|
||||
{
|
||||
// En cas d'exception, la ressource sera quand même libérée
|
||||
CallOnExit onExit([this] ()
|
||||
{
|
||||
Destroy();
|
||||
});
|
||||
|
||||
// Get a matching FB config
|
||||
static int visual_attribs[] =
|
||||
{
|
||||
GLX_X_RENDERABLE, True,
|
||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
||||
GLX_BUFFER_SIZE, parameters.bitsPerPixel,
|
||||
GLX_ALPHA_SIZE, (parameters.bitsPerPixel == 32) ? 8 : 0,
|
||||
GLX_DEPTH_SIZE, parameters.depthBits,
|
||||
GLX_STENCIL_SIZE, parameters.stencilBits,
|
||||
GLX_DOUBLEBUFFER, True,
|
||||
GLX_SAMPLE_BUFFERS, (parameters.antialiasingLevel > 0) ? True : False,
|
||||
GLX_SAMPLES, parameters.antialiasingLevel,
|
||||
None
|
||||
};
|
||||
|
||||
int glx_major = 0;
|
||||
int glx_minor = 0;
|
||||
// FBConfigs were added in GLX version 1.3.
|
||||
if (!glXQueryVersion(m_display, &glx_major, &glx_minor) || ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1))
|
||||
{
|
||||
NazaraError("Invalid GLX version, version > 1.3 is required.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int fbcount;
|
||||
GLXFBConfig* fbc = glXChooseFBConfig(m_display, XDefaultScreen(m_display), visual_attribs, &fbcount);
|
||||
if (!fbc)
|
||||
{
|
||||
NazaraError("Failed to retrieve a framebuffer config");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pick the FB config/visual with the most samples per pixel
|
||||
int best_fbc = -1;
|
||||
int worst_fbc = -1;
|
||||
int best_num_samp = -1;
|
||||
int worst_num_samp = 999;
|
||||
|
||||
for (int i = 0; i < fbcount; ++i)
|
||||
{
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, fbc[i]);
|
||||
|
||||
if (vi)
|
||||
{
|
||||
int samp_buf = 0, samples = 0;
|
||||
glXGetFBConfigAttrib(m_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
|
||||
glXGetFBConfigAttrib(m_display, fbc[i], GLX_SAMPLES , &samples );
|
||||
|
||||
if ((best_fbc < 0) || (samp_buf && (samples > best_num_samp)))
|
||||
{
|
||||
best_fbc = i;
|
||||
best_num_samp = samples;
|
||||
}
|
||||
if ((worst_fbc < 0) || !samp_buf || (samples < worst_num_samp))
|
||||
{
|
||||
worst_fbc = i;
|
||||
worst_num_samp = samples;
|
||||
}
|
||||
}
|
||||
XFree(vi);
|
||||
}
|
||||
|
||||
GLXFBConfig bestFbc = fbc[best_fbc];
|
||||
|
||||
// Be sure to free the FBConfig list allocated by glXChooseFBConfig()
|
||||
XFree(fbc);
|
||||
|
||||
// Get a visual
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, bestFbc);
|
||||
if (!vi)
|
||||
{
|
||||
NazaraError("Failed to get best VisualInfo");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If context is shared by multiple windows
|
||||
if (parameters.window)
|
||||
{
|
||||
m_window = parameters.window;
|
||||
m_ownsWindow = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetWindowAttributes swa;
|
||||
swa.colormap = m_colormap = XCreateColormap(
|
||||
m_display,
|
||||
XRootWindow(
|
||||
m_display,
|
||||
vi->screen),
|
||||
vi->visual,
|
||||
AllocNone
|
||||
);
|
||||
|
||||
swa.background_pixmap = None;
|
||||
swa.border_pixel = 0;
|
||||
swa.event_mask = StructureNotifyMask;
|
||||
|
||||
if (!m_colormap)
|
||||
{
|
||||
NazaraError("Failed to create colormap for context");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window = XCreateWindow(
|
||||
m_display,
|
||||
XRootWindow(
|
||||
m_display,
|
||||
vi->screen),
|
||||
0, 0, // X, Y
|
||||
1, 1, // W H
|
||||
0,
|
||||
vi->depth,
|
||||
InputOutput,
|
||||
vi->visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask,
|
||||
&swa
|
||||
);
|
||||
|
||||
m_ownsWindow = true;
|
||||
}
|
||||
|
||||
if (!m_window)
|
||||
{
|
||||
NazaraError("Failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Done with the visual info data
|
||||
XFree(vi);
|
||||
|
||||
// Install an X error handler so the application won't exit if GL 3.0
|
||||
// context allocation fails.
|
||||
//
|
||||
// Note this error handler is global. All display connections in all threads
|
||||
// of a process use the same error handler, so be sure to guard against other
|
||||
// threads issuing X commands while this code is running.
|
||||
ctxErrorOccurred = false;
|
||||
int (*oldHandler)(Display*, XErrorEvent*) =
|
||||
XSetErrorHandler(&ctxErrorHandler);
|
||||
|
||||
// Check for the GLX_ARB_create_context extension string and the function.
|
||||
// If either is not present, use GLX 1.3 context creation method.
|
||||
if (!glXCreateContextAttribs)
|
||||
{
|
||||
NazaraWarning("glXCreateContextAttribs() not found. Using old-style GLX context");
|
||||
m_context = glXCreateNewContext(m_display, bestFbc, GLX_RGBA_TYPE, parameters.shared ? parameters.shareContext->m_impl->m_context : 0, True);
|
||||
}
|
||||
// If it does, try to get a GL 3.0 context!
|
||||
else
|
||||
{
|
||||
int profile = parameters.compatibilityProfile ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
int debug = parameters.debugMode ? GLX_CONTEXT_DEBUG_BIT_ARB : 0;
|
||||
|
||||
int major = 3;//parameters.majorVersion;
|
||||
int minor = 3;//parameters.minorVersion;
|
||||
|
||||
int context_attribs[] =
|
||||
{
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, major,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, minor,
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB, profile,
|
||||
GLX_CONTEXT_FLAGS_ARB, debug,
|
||||
None, None
|
||||
};
|
||||
|
||||
m_context = glXCreateContextAttribs(
|
||||
m_display,
|
||||
bestFbc,
|
||||
parameters.shared ? parameters.shareContext->m_impl->m_context : 0,
|
||||
True,
|
||||
context_attribs
|
||||
);
|
||||
}
|
||||
|
||||
// Sync to ensure any errors generated are processed.
|
||||
XSync(m_display, False);
|
||||
XSetErrorHandler(oldHandler);
|
||||
if (ctxErrorOccurred || !m_context)
|
||||
{
|
||||
NazaraError("Failed to create context, check the version");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextImpl::Destroy()
|
||||
{
|
||||
// Destroy the context
|
||||
if (m_context)
|
||||
{
|
||||
if (glXGetCurrentContext() == m_context)
|
||||
glXMakeCurrent(m_display, None, nullptr);
|
||||
glXDestroyContext(m_display, m_context);
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
||||
// Destroy the window if we own it
|
||||
if (m_ownsWindow && m_window)
|
||||
{
|
||||
XFreeColormap(m_display, m_colormap);
|
||||
XDestroyWindow(m_display, m_window);
|
||||
m_ownsWindow = false;
|
||||
m_window = 0;
|
||||
XFlush(m_display);
|
||||
}
|
||||
}
|
||||
|
||||
void ContextImpl::EnableVerticalSync(bool enabled)
|
||||
{
|
||||
if (glXSwapIntervalEXT)
|
||||
glXSwapIntervalEXT(m_display, glXGetCurrentDrawable(), enabled ? 1 : 0);
|
||||
else if (NzglXSwapIntervalMESA)
|
||||
NzglXSwapIntervalMESA(enabled ? 1 : 0);
|
||||
else if (glXSwapIntervalSGI)
|
||||
glXSwapIntervalSGI(enabled ? 1 : 0);
|
||||
else
|
||||
NazaraError("Vertical sync not supported");
|
||||
}
|
||||
|
||||
void ContextImpl::SwapBuffers()
|
||||
{
|
||||
if (m_window)
|
||||
glXSwapBuffers(m_display, m_window);
|
||||
}
|
||||
|
||||
bool ContextImpl::Desactivate()
|
||||
{
|
||||
return glXMakeCurrent(m_display, None, nullptr) == true;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine".
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_CONTEXTIMPL_HPP
|
||||
#define NAZARA_CONTEXTIMPL_HPP
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class ContextParameters;
|
||||
|
||||
class ContextImpl
|
||||
{
|
||||
public:
|
||||
ContextImpl();
|
||||
~ContextImpl();
|
||||
|
||||
bool Activate();
|
||||
|
||||
bool Create(ContextParameters& parameters);
|
||||
|
||||
void Destroy();
|
||||
|
||||
void EnableVerticalSync(bool enabled);
|
||||
|
||||
void SwapBuffers();
|
||||
|
||||
static bool Desactivate();
|
||||
|
||||
private:
|
||||
GLX::Colormap m_colormap;
|
||||
GLX::GLXContext m_context;
|
||||
GLX::Window m_window;
|
||||
bool m_ownsWindow;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CONTEXTIMPL_HPP
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/GpuQuery.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
GpuQuery::GpuQuery() :
|
||||
m_id(0)
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
m_id = 0;
|
||||
glGenQueries(1, static_cast<GLuint*>(&m_id));
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Failed to create occlusion query");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GpuQuery::~GpuQuery()
|
||||
{
|
||||
if (m_id)
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
GLuint query = static_cast<GLuint>(m_id);
|
||||
glDeleteQueries(1, &query);
|
||||
}
|
||||
}
|
||||
|
||||
void GpuQuery::Begin(GpuQueryMode mode)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (Context::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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_AnySamplesPassedConservative:
|
||||
return OpenGL::GetVersion() >= 430;
|
||||
|
||||
case GpuQueryMode_AnySamplesPassed:
|
||||
case GpuQueryMode_PrimitiveGenerated:
|
||||
case GpuQueryMode_SamplesPassed:
|
||||
case GpuQueryMode_TimeElapsed:
|
||||
case GpuQueryMode_TransformFeedbackPrimitivesWritten:
|
||||
return true;
|
||||
}
|
||||
|
||||
NazaraError("Gpu Query mode not handled (0x" + String::Number(mode, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/HardwareBuffer.hpp>
|
||||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
HardwareBuffer::HardwareBuffer(Buffer* parent, BufferType type) :
|
||||
m_type(type),
|
||||
m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
HardwareBuffer::~HardwareBuffer() = default;
|
||||
|
||||
bool HardwareBuffer::Create(unsigned int size, BufferUsage usage)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HardwareBuffer::Bind() const
|
||||
{
|
||||
OpenGL::BindBuffer(m_type, m_buffer);
|
||||
}
|
||||
|
||||
unsigned int HardwareBuffer::GetOpenGLID() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_HARDWAREBUFFER_HPP
|
||||
#define NAZARA_HARDWAREBUFFER_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Utility/AbstractBuffer.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class HardwareBuffer : public AbstractBuffer
|
||||
{
|
||||
public:
|
||||
HardwareBuffer(Buffer* parent, BufferType type);
|
||||
~HardwareBuffer();
|
||||
|
||||
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 IsHardware() const;
|
||||
|
||||
void* Map(BufferAccess access, unsigned int offset = 0, unsigned int size = 0);
|
||||
bool Unmap();
|
||||
|
||||
// Fonctions OpenGL
|
||||
void Bind() const;
|
||||
unsigned int GetOpenGLID() const;
|
||||
|
||||
private:
|
||||
GLuint m_buffer;
|
||||
BufferType m_type;
|
||||
Buffer* m_parent;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_HARDWAREBUFFER_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,133 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderBuffer.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderBuffer::RenderBuffer() :
|
||||
m_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
RenderBuffer::~RenderBuffer()
|
||||
{
|
||||
OnRenderBufferRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool RenderBuffer::Create(PixelFormatType format, unsigned int width, unsigned int height)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (width == 0 || height == 0)
|
||||
{
|
||||
NazaraError("Invalid size");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PixelFormat::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 \"" + PixelFormat::GetName(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;
|
||||
}
|
||||
|
||||
void RenderBuffer::Destroy()
|
||||
{
|
||||
if (m_id)
|
||||
{
|
||||
OnRenderBufferDestroy(this);
|
||||
|
||||
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 RenderBuffer::GetHeight() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
PixelFormatType RenderBuffer::GetFormat() const
|
||||
{
|
||||
return m_pixelFormat;
|
||||
}
|
||||
|
||||
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::Initialize()
|
||||
{
|
||||
if (!RenderBufferLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderBuffer::Uninitialize()
|
||||
{
|
||||
RenderBufferLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
RenderBufferLibrary::LibraryMap RenderBuffer::s_library;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderTarget::~RenderTarget()
|
||||
{
|
||||
OnRenderTargetRelease(this);
|
||||
}
|
||||
|
||||
bool RenderTarget::IsActive() const
|
||||
{
|
||||
return Renderer::GetTarget() == this;
|
||||
}
|
||||
|
||||
bool RenderTarget::SetActive(bool active)
|
||||
{
|
||||
if (active)
|
||||
return Renderer::SetTarget(this);
|
||||
else if (Renderer::GetTarget() == this)
|
||||
return Renderer::SetTarget(nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTarget::Desactivate() const
|
||||
{
|
||||
// Seuls les target sans contextes (ex: RenderTexture) nécessitent une désactivation
|
||||
}
|
||||
}
|
||||
@@ -1,854 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderTexture.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderBuffer.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct Attachment
|
||||
{
|
||||
NazaraSlot(RenderBuffer, OnRenderBufferDestroy, renderBufferDestroySlot);
|
||||
NazaraSlot(Texture, OnTextureDestroy, textureDestroySlot);
|
||||
|
||||
RenderBufferRef buffer;
|
||||
TextureRef texture;
|
||||
|
||||
AttachmentPoint attachmentPoint;
|
||||
bool isBuffer;
|
||||
bool isUsed = false;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
};
|
||||
|
||||
unsigned int attachmentIndex[AttachmentPoint_Max+1] =
|
||||
{
|
||||
3, // AttachmentPoint_Color
|
||||
0, // AttachmentPoint_Depth
|
||||
1, // AttachmentPoint_DepthStencil
|
||||
2 // AttachmentPoint_Stencil
|
||||
};
|
||||
|
||||
AttachmentPoint FormatTypeToAttachment(PixelFormatType format)
|
||||
{
|
||||
const PixelFormatInfo& info = PixelFormat::GetInfo(format);
|
||||
switch (info.content)
|
||||
{
|
||||
case PixelFormatContent_ColorRGBA:
|
||||
return AttachmentPoint_Color;
|
||||
|
||||
case PixelFormatContent_DepthStencil:
|
||||
return (!info.greenMask.TestAny()) ? AttachmentPoint_Depth : AttachmentPoint_DepthStencil;
|
||||
|
||||
case PixelFormatContent_Stencil:
|
||||
return AttachmentPoint_Stencil;
|
||||
|
||||
case PixelFormatContent_Undefined:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraInternalError("Unexpected pixel format content: 0x" + String::Number(info.content, 16));
|
||||
return AttachmentPoint_Max;
|
||||
}
|
||||
|
||||
GLuint lockedPrevious = 0;
|
||||
UInt8 lockedLevel = 0;
|
||||
}
|
||||
|
||||
struct RenderTextureImpl
|
||||
{
|
||||
NazaraSlot(Context, OnContextDestroy, contextDestroySlot);
|
||||
|
||||
GLuint fbo;
|
||||
std::vector<Attachment> attachments;
|
||||
std::vector<UInt8> colorTargets;
|
||||
mutable std::vector<GLenum> drawBuffers;
|
||||
const Context* context;
|
||||
bool complete = false;
|
||||
bool userDefinedTargets = false;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
};
|
||||
|
||||
bool RenderTexture::AttachBuffer(AttachmentPoint attachmentPoint, UInt8 index, RenderBuffer* buffer)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= Renderer::GetMaxColorAttachments())
|
||||
{
|
||||
NazaraError("Color index is over max color attachments (" + String::Number(index) + " >= " + String::Number(Renderer::GetMaxColorAttachments()) + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer || !buffer->IsValid())
|
||||
{
|
||||
NazaraError("Invalid render buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[AttachmentPoint_DepthStencil];
|
||||
if (m_impl->attachments.size() > depthStencilIndex && m_impl->attachments[depthStencilIndex].isUsed)
|
||||
{
|
||||
if (attachmentPoint == AttachmentPoint_Depth)
|
||||
{
|
||||
NazaraError("Depth target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
else if (attachmentPoint == AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Stencil target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AttachmentPoint targetAttachmentPoint = FormatTypeToAttachment(buffer->GetFormat());
|
||||
if (targetAttachmentPoint != attachmentPoint && targetAttachmentPoint != AttachmentPoint_DepthStencil &&
|
||||
attachmentPoint != AttachmentPoint_Depth && attachmentPoint != AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, buffer->GetOpenGLID());
|
||||
|
||||
Unlock();
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
m_impl->attachments.resize(attachIndex+1);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachIndex];
|
||||
attachment.attachmentPoint = attachmentPoint;
|
||||
attachment.buffer = buffer;
|
||||
attachment.renderBufferDestroySlot.Connect(buffer->OnRenderBufferDestroy, std::bind(&RenderTexture::OnRenderBufferDestroy, this, std::placeholders::_1, attachIndex));
|
||||
attachment.isBuffer = true;
|
||||
attachment.isUsed = true;
|
||||
attachment.height = buffer->GetHeight();
|
||||
attachment.width = buffer->GetWidth();
|
||||
|
||||
InvalidateSize();
|
||||
InvalidateTargets();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::AttachBuffer(AttachmentPoint attachmentPoint, UInt8 index, PixelFormatType format, unsigned int width, unsigned int height)
|
||||
{
|
||||
RenderBufferRef renderBuffer = RenderBuffer::New();
|
||||
if (!renderBuffer->Create(format, width, height))
|
||||
{
|
||||
NazaraError("Failed to create RenderBuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AttachBuffer(attachmentPoint, index, renderBuffer))
|
||||
{
|
||||
NazaraError("Failed to attach buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::AttachTexture(AttachmentPoint attachmentPoint, UInt8 index, Texture* texture, unsigned int z)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= Renderer::GetMaxColorAttachments())
|
||||
{
|
||||
NazaraError("Color index is over max color attachments (" + String::Number(index) + " >= " + String::Number(Renderer::GetMaxColorAttachments()) + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (attachmentPoint == AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Targeting stencil-only textures is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[AttachmentPoint_DepthStencil];
|
||||
if (attachmentPoint == AttachmentPoint_Depth && m_impl->attachments.size() > depthStencilIndex &&
|
||||
m_impl->attachments[depthStencilIndex].isUsed)
|
||||
{
|
||||
NazaraError("Depth target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!texture || !texture->IsValid())
|
||||
{
|
||||
NazaraError("Invalid texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depth = (texture->GetType() == ImageType_Cubemap) ? 6 : texture->GetDepth();
|
||||
if (z >= depth)
|
||||
{
|
||||
NazaraError("Z value exceeds depth (" + String::Number(z) + " >= (" + String::Number(depth) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachmentPoint targetAttachmentPoint = FormatTypeToAttachment(texture->GetFormat());
|
||||
if (targetAttachmentPoint != attachmentPoint && targetAttachmentPoint != AttachmentPoint_DepthStencil &&
|
||||
attachmentPoint != AttachmentPoint_Depth && attachmentPoint != AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
switch (texture->GetType())
|
||||
{
|
||||
case ImageType_1D:
|
||||
glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_1D, texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
|
||||
case ImageType_1D_Array:
|
||||
case ImageType_2D_Array:
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, texture->GetOpenGLID(), 0, z);
|
||||
break;
|
||||
|
||||
case ImageType_2D:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_2D, texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
|
||||
case ImageType_3D:
|
||||
glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_3D, texture->GetOpenGLID(), 0, z);
|
||||
break;
|
||||
|
||||
case ImageType_Cubemap:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, OpenGL::CubemapFace[z], texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
m_impl->attachments.resize(attachIndex+1);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachIndex];
|
||||
attachment.attachmentPoint = attachmentPoint;
|
||||
attachment.isBuffer = false;
|
||||
attachment.isUsed = true;
|
||||
attachment.height = texture->GetHeight();
|
||||
attachment.texture = texture;
|
||||
attachment.textureDestroySlot.Connect(texture->OnTextureDestroy, std::bind(&RenderTexture::OnTextureDestroy, this, std::placeholders::_1, attachIndex));
|
||||
attachment.width = texture->GetWidth();
|
||||
|
||||
InvalidateSize();
|
||||
InvalidateTargets();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::Create(bool lock)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<RenderTextureImpl> impl(new RenderTextureImpl);
|
||||
|
||||
impl->fbo = 0;
|
||||
glGenFramebuffers(1, &impl->fbo);
|
||||
|
||||
if (!impl->fbo)
|
||||
{
|
||||
NazaraError("Failed to create framebuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
m_impl->context = Context::GetCurrent();
|
||||
m_impl->contextDestroySlot.Connect(m_impl->context->OnContextDestroy, this, &RenderTexture::OnContextDestroy);
|
||||
|
||||
m_checked = false;
|
||||
m_drawBuffersUpdated = true;
|
||||
m_sizeUpdated = false;
|
||||
m_targetsUpdated = true;
|
||||
|
||||
if (lock)
|
||||
{
|
||||
// En cas d'exception, la ressource sera quand même libérée
|
||||
CallOnExit onExit([this] ()
|
||||
{
|
||||
Destroy();
|
||||
});
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
}
|
||||
|
||||
OnRenderTargetParametersChange(this);
|
||||
OnRenderTargetSizeChange(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
if (IsActive())
|
||||
Renderer::SetTarget(nullptr);
|
||||
|
||||
// Le FBO devant être supprimé dans son contexte d'origine, nous déléguons sa suppression à la classe OpenGL
|
||||
// Celle-ci va libérer le FBO dès que possible (la prochaine fois que son contexte d'origine sera actif)
|
||||
OpenGL::DeleteFrameBuffer(m_impl->context, m_impl->fbo);
|
||||
|
||||
delete m_impl; // Enlève également une références sur les Texture/RenderBuffer
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTexture::Detach(AttachmentPoint attachmentPoint, UInt8 index)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color && index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
return;
|
||||
|
||||
Attachment& attachement = m_impl->attachments[attachIndex];
|
||||
if (!attachement.isUsed)
|
||||
return;
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return;
|
||||
}
|
||||
|
||||
attachement.isUsed = false;
|
||||
|
||||
if (attachement.isBuffer)
|
||||
{
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, 0);
|
||||
|
||||
attachement.buffer = nullptr;
|
||||
attachement.renderBufferDestroySlot.Disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (glFramebufferTexture)
|
||||
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, 0, 0);
|
||||
else
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, 0, 0, 0);
|
||||
|
||||
attachement.texture = nullptr;
|
||||
attachement.textureDestroySlot.Disconnect();
|
||||
}
|
||||
|
||||
InvalidateSize();
|
||||
|
||||
if (attachement.attachmentPoint == AttachmentPoint_Color)
|
||||
InvalidateTargets();
|
||||
|
||||
Unlock();
|
||||
|
||||
m_checked = false;
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetHeight() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return m_impl->height;
|
||||
}
|
||||
|
||||
RenderTargetParameters RenderTexture::GetParameters() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
///TODO
|
||||
return RenderTargetParameters();
|
||||
}
|
||||
|
||||
Vector2ui RenderTexture::GetSize() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return Vector2ui(m_impl->width, m_impl->height);
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetWidth() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return m_impl->width;
|
||||
}
|
||||
|
||||
bool RenderTexture::IsComplete() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_checked)
|
||||
{
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
|
||||
Unlock();
|
||||
|
||||
m_impl->complete = false;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
m_impl->complete = true;
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
NazaraError("Incomplete attachment");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
NazaraInternalError("Incomplete draw buffer");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
NazaraInternalError("Incomplete read buffer");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
NazaraError("Incomplete missing attachment");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
NazaraError("Incomplete multisample");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||
NazaraError("Incomplete layer targets");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
NazaraError("Render texture has unsupported attachments");
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Unknown error");
|
||||
}
|
||||
|
||||
m_checked = true;
|
||||
}
|
||||
|
||||
return m_impl->complete;
|
||||
}
|
||||
|
||||
bool RenderTexture::IsRenderable() const
|
||||
{
|
||||
return IsComplete() && !m_impl->attachments.empty();
|
||||
}
|
||||
|
||||
bool RenderTexture::Lock() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lockedLevel++ == 0)
|
||||
{
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous);
|
||||
|
||||
lockedPrevious = previous;
|
||||
|
||||
if (lockedPrevious != m_impl->fbo)
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::SetColorTargets(const UInt8* targets, unsigned int targetCount) const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
for (unsigned int i = 0; i < targetCount; ++i)
|
||||
{
|
||||
unsigned int index = attachmentIndex[AttachmentPoint_Color] + targets[i];
|
||||
if (index >= m_impl->attachments.size() || !m_impl->attachments[index].isUsed)
|
||||
{
|
||||
NazaraError("Target " + String::Number(targets[i]) + " not attached");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->colorTargets.resize(targetCount);
|
||||
std::memcpy(&m_impl->colorTargets[0], targets, targetCount*sizeof(UInt8));
|
||||
|
||||
m_impl->userDefinedTargets = true;
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::SetColorTargets(const std::initializer_list<UInt8>& targets) const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
for (UInt8 target : targets)
|
||||
{
|
||||
unsigned int index = attachmentIndex[AttachmentPoint_Color] + target;
|
||||
if (index >= m_impl->attachments.size() || !m_impl->attachments[index].isUsed)
|
||||
{
|
||||
NazaraError("Target " + String::Number(target) + " not attached");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->colorTargets.resize(targets.size());
|
||||
|
||||
UInt8* ptr = &m_impl->colorTargets[0];
|
||||
for (UInt8 index : targets)
|
||||
*ptr++ = index;
|
||||
|
||||
m_impl->userDefinedTargets = true;
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::Unlock() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lockedLevel == 0)
|
||||
{
|
||||
NazaraWarning("Unlock called on non-locked texture");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--lockedLevel == 0 && lockedPrevious != m_impl->fbo) // Ici, il est important qu'un FBO soit débindé si l'ancien était 0
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lockedPrevious);
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetOpenGLID() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->fbo;
|
||||
}
|
||||
|
||||
bool RenderTexture::HasContext() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderTexture::Blit(RenderTexture* src, Rectui srcRect, RenderTexture* dst, Rectui dstRect, UInt32 buffers, bool bilinearFilter)
|
||||
{
|
||||
NazaraAssert(src && src->IsValid(), "Invalid source render texture");
|
||||
NazaraAssert(dst && dst->IsValid(), "Invalid destination render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (srcRect.x+srcRect.width > src->GetWidth() || srcRect.y+srcRect.height > src->GetHeight())
|
||||
{
|
||||
NazaraError("Source rectangle dimensions are out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dstRect.x+dstRect.width > dst->GetWidth() || dstRect.y+dstRect.height > dst->GetHeight())
|
||||
{
|
||||
NazaraError("Destination rectangle dimensions are out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bilinearFilter && (buffers & RendererBuffer_Depth || buffers & RendererBuffer_Stencil))
|
||||
{
|
||||
NazaraError("Filter cannot be bilinear when blitting depth/stencil buffers");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
GLbitfield mask = 0;
|
||||
if (buffers & RendererBuffer_Color)
|
||||
mask |= GL_COLOR_BUFFER_BIT;
|
||||
|
||||
if (buffers & RendererBuffer_Depth)
|
||||
mask |= GL_DEPTH_BUFFER_BIT;
|
||||
|
||||
if (buffers & RendererBuffer_Stencil)
|
||||
mask |= GL_STENCIL_BUFFER_BIT;
|
||||
|
||||
GLint previousDrawBuffer, previousReadBuffer;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previousDrawBuffer);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &previousReadBuffer);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->GetOpenGLID());
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->GetOpenGLID());
|
||||
|
||||
glBlitFramebuffer(srcRect.x, srcRect.y, srcRect.x + srcRect.width, srcRect.y + srcRect.height,
|
||||
dstRect.x, dstRect.y, dstRect.x + dstRect.width, dstRect.y + dstRect.height,
|
||||
mask, (bilinearFilter) ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, previousDrawBuffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, previousReadBuffer);
|
||||
}
|
||||
|
||||
bool RenderTexture::Activate() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
|
||||
|
||||
m_drawBuffersUpdated = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::Desactivate() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glFlush();
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void RenderTexture::EnsureTargetUpdated() const
|
||||
{
|
||||
if (!m_drawBuffersUpdated)
|
||||
UpdateDrawBuffers();
|
||||
|
||||
for (UInt8 index : m_impl->colorTargets)
|
||||
{
|
||||
Attachment& attachment = m_impl->attachments[attachmentIndex[AttachmentPoint_Color] + index];
|
||||
if (!attachment.isBuffer)
|
||||
attachment.texture->InvalidateMipmaps();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTexture::OnContextDestroy(const Context* context)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraUnused(context);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (m_impl->context != context)
|
||||
{
|
||||
NazaraInternalError("Not listening to " + String::Pointer(context));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void RenderTexture::OnRenderBufferDestroy(const RenderBuffer* renderBuffer, unsigned int attachmentIndex)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraAssert(attachmentIndex < m_impl->attachments.size(), "Invalid attachment index");
|
||||
NazaraAssert(m_impl->attachments[attachmentIndex].isBuffer, "Invalid attachment state");
|
||||
NazaraUnused(renderBuffer);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachmentIndex];
|
||||
attachment.buffer = nullptr;
|
||||
attachment.isUsed = false;
|
||||
attachment.renderBufferDestroySlot.Disconnect();
|
||||
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::OnTextureDestroy(const Texture* texture, unsigned int attachmentIndex)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraAssert(attachmentIndex < m_impl->attachments.size(), "Invalid attachment index");
|
||||
NazaraAssert(!m_impl->attachments[attachmentIndex].isBuffer, "Invalid attachment state");
|
||||
NazaraUnused(texture);
|
||||
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateDrawBuffers() const
|
||||
{
|
||||
if (!m_targetsUpdated)
|
||||
UpdateTargets();
|
||||
|
||||
glDrawBuffers(m_impl->drawBuffers.size(), &m_impl->drawBuffers[0]);
|
||||
|
||||
m_drawBuffersUpdated = true;
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateSize() const
|
||||
{
|
||||
m_impl->width = 0;
|
||||
m_impl->height = 0;
|
||||
for (Attachment& attachment : m_impl->attachments)
|
||||
{
|
||||
if (attachment.isUsed)
|
||||
{
|
||||
m_impl->height = std::max(m_impl->height, attachment.height);
|
||||
m_impl->width = std::max(m_impl->width, attachment.width);
|
||||
}
|
||||
}
|
||||
|
||||
m_sizeUpdated = true;
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateTargets() const
|
||||
{
|
||||
if (!m_impl->userDefinedTargets)
|
||||
{
|
||||
m_impl->colorTargets.clear();
|
||||
|
||||
unsigned int colorIndex = 0;
|
||||
for (unsigned int index = attachmentIndex[AttachmentPoint_Color]; index < m_impl->attachments.size(); ++index)
|
||||
m_impl->colorTargets.push_back(colorIndex++);
|
||||
}
|
||||
|
||||
if (m_impl->colorTargets.empty())
|
||||
{
|
||||
m_impl->drawBuffers.resize(1);
|
||||
m_impl->drawBuffers[0] = GL_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_impl->drawBuffers.resize(m_impl->colorTargets.size());
|
||||
GLenum* ptr = &m_impl->drawBuffers[0];
|
||||
for (UInt8 index : m_impl->colorTargets)
|
||||
*ptr++ = GL_COLOR_ATTACHMENT0 + index;
|
||||
}
|
||||
|
||||
m_targetsUpdated = true;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
/*
|
||||
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
@@ -289,3 +289,4 @@ namespace Nz
|
||||
OnRenderTargetSizeChange(this);
|
||||
}
|
||||
}
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
11
src/Nazara/Renderer/RendererImpl.cpp
Normal file
11
src/Nazara/Renderer/RendererImpl.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RendererImpl.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RendererImpl::~RendererImpl() = default;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#version 140
|
||||
|
||||
/********************Sortant********************/
|
||||
out vec4 RenderTarget0;
|
||||
|
||||
/********************Uniformes********************/
|
||||
uniform vec4 Color;
|
||||
|
||||
/********************Fonctions********************/
|
||||
void main()
|
||||
{
|
||||
RenderTarget0 = Color;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
35,118,101,114,115,105,111,110,32,49,52,48,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,67,111,108,111,114,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,67,111,108,111,114,59,13,10,125,
|
||||
@@ -1,13 +0,0 @@
|
||||
#version 140
|
||||
|
||||
/********************Entrant********************/
|
||||
in vec3 VertexPosition;
|
||||
|
||||
/********************Uniformes********************/
|
||||
uniform mat4 WorldViewProjMatrix;
|
||||
|
||||
/********************Fonctions********************/
|
||||
void main()
|
||||
{
|
||||
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
35,118,101,114,115,105,111,110,32,49,52,48,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,80,111,115,105,116,105,111,110,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,125,13,10,
|
||||
@@ -1,841 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/ShaderStage.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
Shader::Shader() :
|
||||
m_linked(false),
|
||||
m_program(0)
|
||||
{
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
OnShaderRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Shader::AttachStage(ShaderStageType stage, const ShaderStage& shaderStage)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_program)
|
||||
{
|
||||
NazaraError("Invalid program");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shaderStage.IsValid())
|
||||
{
|
||||
NazaraError("Invalid shader stage");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shaderStage.IsCompiled())
|
||||
{
|
||||
NazaraError("Shader stage must be compiled");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int shader = shaderStage.GetOpenGLID();
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (std::find(m_attachedShaders[stage].begin(), m_attachedShaders[stage].end(), shader) != m_attachedShaders[stage].end())
|
||||
{
|
||||
NazaraError("Shader stage is already attached");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glAttachShader(m_program, shader);
|
||||
m_attachedShaders[stage].push_back(shader);
|
||||
}
|
||||
|
||||
bool Shader::AttachStageFromFile(ShaderStageType stage, const String& filePath)
|
||||
{
|
||||
ShaderStage shaderStage(stage);
|
||||
if (!shaderStage.IsValid())
|
||||
{
|
||||
NazaraError("Failed to create shader stage");
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderStage.SetSourceFromFile(filePath);
|
||||
|
||||
if (!shaderStage.Compile())
|
||||
{
|
||||
NazaraError("Failed to compile stage: " + shaderStage.GetLog());
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachStage(stage, shaderStage);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Shader::AttachStageFromSource(ShaderStageType stage, const char* source, unsigned int length)
|
||||
{
|
||||
ShaderStage shaderStage(stage);
|
||||
if (!shaderStage.IsValid())
|
||||
{
|
||||
NazaraError("Failed to create shader stage");
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderStage.SetSource(source, length);
|
||||
|
||||
if (!shaderStage.Compile())
|
||||
{
|
||||
NazaraError("Failed to compile stage: " + shaderStage.GetLog());
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachStage(stage, shaderStage);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Shader::AttachStageFromSource(ShaderStageType stage, const String& source)
|
||||
{
|
||||
ShaderStage shaderStage(stage);
|
||||
if (!shaderStage.IsValid())
|
||||
{
|
||||
NazaraError("Failed to create shader stage");
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderStage.SetSource(source);
|
||||
|
||||
if (!shaderStage.Compile())
|
||||
{
|
||||
NazaraError("Failed to compile stage: " + shaderStage.GetLog());
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachStage(stage, shaderStage);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shader::Bind() const
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
}
|
||||
|
||||
bool Shader::Create()
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
m_program = glCreateProgram();
|
||||
if (!m_program)
|
||||
{
|
||||
NazaraError("Failed to create program");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_linked = false;
|
||||
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData0], "InstanceData0");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData1], "InstanceData1");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData2], "InstanceData2");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData3], "InstanceData3");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData4], "InstanceData4");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData5], "InstanceData5");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Color], "VertexColor");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Normal], "VertexNormal");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Position], "VertexPosition");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Tangent], "VertexTangent");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_TexCoord], "VertexTexCoord");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata0], "VertexUserdata0");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata1], "VertexUserdata1");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata2], "VertexUserdata2");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata3], "VertexUserdata3");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata4], "VertexUserdata4");
|
||||
|
||||
String uniform;
|
||||
uniform = "RenderTarget";
|
||||
|
||||
unsigned int maxRenderTargets = Renderer::GetMaxRenderTargets();
|
||||
for (unsigned int i = 0; i < maxRenderTargets; ++i)
|
||||
{
|
||||
String uniformName = uniform + String::Number(i);
|
||||
glBindFragDataLocation(m_program, i, uniformName.GetConstBuffer());
|
||||
}
|
||||
|
||||
if (OpenGL::IsSupported(OpenGLExtension_GetProgramBinary))
|
||||
glProgramParameteri(m_program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shader::Destroy()
|
||||
{
|
||||
if (m_program)
|
||||
{
|
||||
OnShaderDestroy(this);
|
||||
|
||||
Context::EnsureContext();
|
||||
OpenGL::DeleteProgram(m_program);
|
||||
m_program = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ByteArray Shader::GetBinary() const
|
||||
{
|
||||
ByteArray byteArray;
|
||||
|
||||
Context::EnsureContext();
|
||||
|
||||
GLint binaryLength = 0;
|
||||
glGetProgramiv(m_program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||
|
||||
if (binaryLength > 0)
|
||||
{
|
||||
byteArray.Reserve(sizeof(UInt64) + binaryLength);
|
||||
|
||||
UInt8* buffer = byteArray.GetBuffer();
|
||||
|
||||
GLenum binaryFormat;
|
||||
glGetProgramBinary(m_program, binaryLength, nullptr, &binaryFormat, &buffer[sizeof(UInt64)]);
|
||||
|
||||
// On stocke le format au début du binaire
|
||||
*reinterpret_cast<UInt64*>(&buffer[0]) = binaryFormat;
|
||||
}
|
||||
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
String Shader::GetLog() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_program)
|
||||
{
|
||||
NazaraError("Shader is not initialized");
|
||||
return String();
|
||||
}
|
||||
#endif
|
||||
|
||||
String log;
|
||||
|
||||
GLint length = 0;
|
||||
glGetProgramiv(m_program, 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)
|
||||
glGetProgramInfoLog(m_program, length, nullptr, &log[0]);
|
||||
}
|
||||
else
|
||||
log = "No log.";
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
String Shader::GetSourceCode(ShaderStageType stage) const
|
||||
{
|
||||
if (!HasStage(stage))
|
||||
return String();
|
||||
|
||||
Context::EnsureContext();
|
||||
|
||||
static const char sep[] = "\n////////////////////////////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
unsigned int totalLength = 0;
|
||||
for (unsigned int shader : m_attachedShaders[stage])
|
||||
{
|
||||
GLint length;
|
||||
glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &length);
|
||||
|
||||
totalLength += length - 1;
|
||||
}
|
||||
|
||||
totalLength += (m_attachedShaders[stage].size()-1) * (sizeof(sep)/sizeof(char));
|
||||
|
||||
String source(totalLength, '\0');
|
||||
|
||||
unsigned int offset = 0;
|
||||
for (unsigned int shader : m_attachedShaders[stage])
|
||||
{
|
||||
if (offset > 0)
|
||||
{
|
||||
std::memcpy(&source[offset], sep, sizeof(sep));
|
||||
offset += sizeof(sep)/sizeof(char);
|
||||
}
|
||||
|
||||
GLint length;
|
||||
glGetShaderSource(shader, totalLength, &length, &source[offset]);
|
||||
|
||||
offset += length;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
int Shader::GetUniformLocation(const String& name) const
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
return glGetUniformLocation(m_program, name.GetConstBuffer());
|
||||
}
|
||||
|
||||
int Shader::GetUniformLocation(ShaderUniform shaderUniform) const
|
||||
{
|
||||
return m_uniformLocations[shaderUniform];
|
||||
}
|
||||
|
||||
bool Shader::HasStage(ShaderStageType stage) const
|
||||
{
|
||||
return !m_attachedShaders[stage].empty();
|
||||
}
|
||||
|
||||
bool Shader::IsBinaryRetrievable() const
|
||||
{
|
||||
return OpenGL::IsSupported(OpenGLExtension_GetProgramBinary);
|
||||
}
|
||||
|
||||
bool Shader::IsLinked() const
|
||||
{
|
||||
return m_linked;
|
||||
}
|
||||
|
||||
bool Shader::IsValid() const
|
||||
{
|
||||
return m_program != 0;
|
||||
}
|
||||
|
||||
bool Shader::Link()
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
glLinkProgram(m_program);
|
||||
|
||||
return PostLinkage();
|
||||
}
|
||||
|
||||
bool Shader::LoadFromBinary(const void* buffer, unsigned int size)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!glProgramBinary)
|
||||
{
|
||||
NazaraError("GL_ARB_get_program_binary not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!buffer || size < sizeof(UInt64))
|
||||
{
|
||||
NazaraError("Invalid buffer");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
Context::EnsureContext();
|
||||
|
||||
const UInt8* ptr = reinterpret_cast<const UInt8*>(buffer);
|
||||
|
||||
// On récupère le format au début du binaire
|
||||
///TODO: ByteStream ?
|
||||
GLenum binaryFormat = static_cast<GLenum>(*reinterpret_cast<const UInt64*>(&ptr[0]));
|
||||
ptr += sizeof(UInt64);
|
||||
|
||||
glProgramBinary(m_program, binaryFormat, ptr, size - sizeof(UInt64));
|
||||
|
||||
return PostLinkage();
|
||||
}
|
||||
|
||||
bool Shader::LoadFromBinary(const ByteArray& byteArray)
|
||||
{
|
||||
return LoadFromBinary(byteArray.GetConstBuffer(), byteArray.GetSize());
|
||||
}
|
||||
|
||||
void Shader::SendBoolean(int location, bool value) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1i)
|
||||
glProgramUniform1i(m_program, location, value);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1i(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendColor(int location, const Color& color) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
Vector4f vecColor(color.r/255.f, color.g/255.f, color.b/255.f, color.a/255.f);
|
||||
|
||||
if (glProgramUniform4fv)
|
||||
glProgramUniform4fv(m_program, location, 1, vecColor);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4fv(location, 1, vecColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendDouble(int location, double value) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1d)
|
||||
glProgramUniform1d(m_program, location, value);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1d(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendDoubleArray(int location, const double* values, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1dv)
|
||||
glProgramUniform1dv(m_program, location, count, values);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1dv(location, count, values);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendFloat(int location, float value) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1f)
|
||||
glProgramUniform1f(m_program, location, value);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1f(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendFloatArray(int location, const float* values, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1fv)
|
||||
glProgramUniform1fv(m_program, location, count, values);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1fv(location, count, values);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendInteger(int location, int value) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1i)
|
||||
glProgramUniform1i(m_program, location, value);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1i(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendIntegerArray(int location, const int* values, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1iv)
|
||||
glProgramUniform1iv(m_program, location, count, values);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1iv(location, count, values);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendMatrix(int location, const Matrix4d& matrix) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniformMatrix4dv)
|
||||
glProgramUniformMatrix4dv(m_program, location, 1, GL_FALSE, matrix);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniformMatrix4dv(location, 1, GL_FALSE, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendMatrix(int location, const Matrix4f& matrix) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniformMatrix4fv)
|
||||
glProgramUniformMatrix4fv(m_program, location, 1, GL_FALSE, matrix);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector2d& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2dv)
|
||||
glProgramUniform2dv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2dv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector2f& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2fv)
|
||||
glProgramUniform2fv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2fv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector2i& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2fv)
|
||||
glProgramUniform2iv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2iv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector3d& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3dv)
|
||||
glProgramUniform3dv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3dv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector3f& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3fv)
|
||||
glProgramUniform3fv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3fv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector3i& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3iv)
|
||||
glProgramUniform3iv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3iv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector4d& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4dv)
|
||||
glProgramUniform4dv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4dv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector4f& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4fv)
|
||||
glProgramUniform4fv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4fv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector4i& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4iv)
|
||||
glProgramUniform4iv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4iv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector2d* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2dv)
|
||||
glProgramUniform2dv(m_program, location, count, reinterpret_cast<const double*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2dv(location, count, reinterpret_cast<const double*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector2f* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2fv)
|
||||
glProgramUniform2fv(m_program, location, count, reinterpret_cast<const float*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2fv(location, count, reinterpret_cast<const float*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector2i* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2iv)
|
||||
glProgramUniform2iv(m_program, location, count, reinterpret_cast<const int*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2iv(location, count, reinterpret_cast<const int*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector3d* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3dv)
|
||||
glProgramUniform3dv(m_program, location, count, reinterpret_cast<const double*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3dv(location, count, reinterpret_cast<const double*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector3f* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3fv)
|
||||
glProgramUniform3fv(m_program, location, count, reinterpret_cast<const float*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3fv(location, count, reinterpret_cast<const float*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector3i* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3iv)
|
||||
glProgramUniform3iv(m_program, location, count, reinterpret_cast<const int*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3iv(location, count, reinterpret_cast<const int*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector4d* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4dv)
|
||||
glProgramUniform4dv(m_program, location, count, reinterpret_cast<const double*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4dv(location, count, reinterpret_cast<const double*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector4f* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4fv)
|
||||
glProgramUniform4fv(m_program, location, count, reinterpret_cast<const float*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4fv(location, count, reinterpret_cast<const float*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector4i* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4iv)
|
||||
glProgramUniform4iv(m_program, location, count, reinterpret_cast<const int*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4iv(location, count, reinterpret_cast<const int*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::Validate() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_program)
|
||||
{
|
||||
NazaraError("Shader is not initialized");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
glValidateProgram(m_program);
|
||||
|
||||
GLint success;
|
||||
glGetProgramiv(m_program, GL_VALIDATE_STATUS, &success);
|
||||
|
||||
if (success == GL_TRUE)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to validate shader: " + GetLog());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int Shader::GetOpenGLID() const
|
||||
{
|
||||
return m_program;
|
||||
}
|
||||
|
||||
bool Shader::IsStageSupported(ShaderStageType stage)
|
||||
{
|
||||
return ShaderStage::IsSupported(stage);
|
||||
}
|
||||
|
||||
bool Shader::PostLinkage()
|
||||
{
|
||||
GLint success;
|
||||
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
|
||||
|
||||
m_linked = (success == GL_TRUE);
|
||||
if (m_linked)
|
||||
{
|
||||
// Pour éviter de se tromper entre le nom et la constante
|
||||
#define CacheUniform(name) m_uniformLocations[ShaderUniform_##name] = glGetUniformLocation(m_program, #name)
|
||||
|
||||
CacheUniform(InvProjMatrix);
|
||||
CacheUniform(InvTargetSize);
|
||||
CacheUniform(InvViewMatrix);
|
||||
CacheUniform(InvViewProjMatrix);
|
||||
CacheUniform(InvWorldMatrix);
|
||||
CacheUniform(InvWorldViewMatrix);
|
||||
CacheUniform(InvWorldViewProjMatrix);
|
||||
CacheUniform(ProjMatrix);
|
||||
CacheUniform(TargetSize);
|
||||
CacheUniform(ViewMatrix);
|
||||
CacheUniform(ViewProjMatrix);
|
||||
CacheUniform(WorldMatrix);
|
||||
CacheUniform(WorldViewMatrix);
|
||||
CacheUniform(WorldViewProjMatrix);
|
||||
|
||||
#undef CacheUniform
|
||||
|
||||
OnShaderUniformInvalidated(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to link shader: " + GetLog());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::Initialize()
|
||||
{
|
||||
if (!ShaderLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shader::Uninitialize()
|
||||
{
|
||||
ShaderLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
ShaderLibrary::LibraryMap Shader::s_library;
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderStage.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
ShaderStage::ShaderStage() :
|
||||
m_compiled(false),
|
||||
m_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
ShaderStage::ShaderStage(ShaderStageType stage) :
|
||||
ShaderStage()
|
||||
{
|
||||
Create(stage);
|
||||
}
|
||||
|
||||
ShaderStage::ShaderStage(ShaderStage&& stage) :
|
||||
m_stage(stage.m_stage),
|
||||
m_compiled(stage.m_compiled),
|
||||
m_id(stage.m_id)
|
||||
{
|
||||
stage.m_id = 0;
|
||||
}
|
||||
|
||||
ShaderStage::~ShaderStage()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
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_Geometry:
|
||||
case ShaderStageType_Vertex:
|
||||
return true;
|
||||
|
||||
default:
|
||||
NazaraError("Shader stage not handled (0x" + String::Number(stage, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,393 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/TextureSampler.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <unordered_map>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<UInt32, GLuint> s_samplers;
|
||||
UInt8 s_maxAnisotropyLevel;
|
||||
bool s_useAnisotropicFilter;
|
||||
}
|
||||
|
||||
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 (" + String::Number(anisotropyLevel) + " > " + String::Number(s_maxAnisotropyLevel));
|
||||
anisotropyLevel = s_maxAnisotropyLevel;
|
||||
}
|
||||
|
||||
s_defaultAnisotropyLevel = anisotropyLevel;
|
||||
|
||||
if (s_useAnisotropicFilter)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
SamplerFilter filterMode = (m_filterMode == SamplerFilter_Default) ? s_defaultFilterMode : m_filterMode;
|
||||
switch (filterMode)
|
||||
{
|
||||
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 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 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" + String::Number(filterMode, 16) + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSampler::Bind(unsigned int unit) const
|
||||
{
|
||||
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");
|
||||
|
||||
if (!m_samplerId)
|
||||
UpdateSamplerId();
|
||||
|
||||
OpenGL::BindSampler(unit, m_samplerId);
|
||||
}
|
||||
|
||||
unsigned int TextureSampler::GetOpenGLID() const
|
||||
{
|
||||
if (!m_samplerId)
|
||||
UpdateSamplerId();
|
||||
|
||||
return m_samplerId;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/UberShader.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShader::~UberShader()
|
||||
{
|
||||
OnUberShaderRelease(this);
|
||||
}
|
||||
|
||||
bool UberShader::Initialize()
|
||||
{
|
||||
if (!UberShaderLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UberShader::Uninitialize()
|
||||
{
|
||||
UberShaderLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
UberShaderLibrary::LibraryMap UberShader::s_library;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/UberShaderInstance.hpp>
|
||||
#include <algorithm>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShaderInstance::UberShaderInstance(const Shader* shader) :
|
||||
m_shader(shader)
|
||||
{
|
||||
}
|
||||
|
||||
UberShaderInstance::~UberShaderInstance() = default;
|
||||
|
||||
const Shader* UberShaderInstance::GetShader() const
|
||||
{
|
||||
return m_shader;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/UberShaderInstancePreprocessor.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShaderInstancePreprocessor::UberShaderInstancePreprocessor(const Shader* shader) :
|
||||
UberShaderInstance(shader)
|
||||
{
|
||||
}
|
||||
|
||||
UberShaderInstancePreprocessor::~UberShaderInstancePreprocessor() = default;
|
||||
|
||||
bool UberShaderInstancePreprocessor::Activate() const
|
||||
{
|
||||
Renderer::SetShader(m_shader);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/UberShaderPreprocessor.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShaderPreprocessor::~UberShaderPreprocessor()
|
||||
{
|
||||
OnUberShaderPreprocessorRelease(this);
|
||||
}
|
||||
|
||||
UberShaderInstance* UberShaderPreprocessor::Get(const ParameterList& parameters) const
|
||||
{
|
||||
// Première étape, transformer les paramètres en un flag
|
||||
UInt32 flags = 0;
|
||||
for (auto it = m_flags.begin(); it != m_flags.end(); ++it)
|
||||
{
|
||||
if (parameters.HasParameter(it->first))
|
||||
{
|
||||
bool value;
|
||||
if (parameters.GetBooleanParameter(it->first, &value) && value)
|
||||
flags |= it->second;
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
{
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void UberShaderPreprocessor::SetShader(ShaderStageType stage, const String& source, const String& shaderFlags, const String& requiredFlags)
|
||||
{
|
||||
CachedShader& shader = m_shaders[stage];
|
||||
shader.present = true;
|
||||
shader.source = source;
|
||||
|
||||
// On extrait les flags de la chaîne
|
||||
std::vector<String> flags;
|
||||
shaderFlags.Split(flags, ' ');
|
||||
|
||||
for (String& flag : flags)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
// 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 UberShaderPreprocessor::SetShaderFromFile(ShaderStageType stage, const String& filePath, const String& shaderFlags, const String& requiredFlags)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool UberShaderPreprocessor::IsSupported()
|
||||
{
|
||||
return true; // Forcément supporté
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila
|
||||
|
||||
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/LockGuard.hpp>
|
||||
#include <Nazara/Core/Mutex.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <cstring>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
ContextImpl::ContextImpl()
|
||||
{
|
||||
}
|
||||
|
||||
bool ContextImpl::Activate()
|
||||
{
|
||||
return wglMakeCurrent(m_deviceContext, m_context) == TRUE;
|
||||
}
|
||||
|
||||
bool ContextImpl::Create(ContextParameters& parameters)
|
||||
{
|
||||
if (parameters.window)
|
||||
{
|
||||
m_window = static_cast<HWND>(parameters.window);
|
||||
m_ownsWindow = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// En cas d'exception, la ressource sera quand même libérée
|
||||
CallOnExit 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];
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraWarning("Antialiasing is not supported");
|
||||
parameters.antialiasingLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
NazaraError("Failed to choose pixel format");
|
||||
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<ContextImpl*>(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)
|
||||
{
|
||||
*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;
|
||||
}
|
||||
|
||||
void ContextImpl::Destroy()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void ContextImpl::EnableVerticalSync(bool enabled)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine".
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_CONTEXTIMPL_HPP
|
||||
#define NAZARA_CONTEXTIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Renderer/ContextParameters.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class ContextImpl
|
||||
{
|
||||
public:
|
||||
ContextImpl();
|
||||
|
||||
bool Activate();
|
||||
|
||||
bool Create(ContextParameters& parameters);
|
||||
|
||||
void Destroy();
|
||||
|
||||
void EnableVerticalSync(bool enabled);
|
||||
|
||||
void SwapBuffers();
|
||||
|
||||
static bool Desactivate();
|
||||
|
||||
private:
|
||||
HDC m_deviceContext;
|
||||
HGLRC m_context;
|
||||
HWND m_window;
|
||||
bool m_ownsWindow;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CONTEXTIMPL_HPP
|
||||
Reference in New Issue
Block a user