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:
Lynix
2016-08-23 12:52:34 +02:00
parent d7a10031d7
commit bdedd05032
132 changed files with 6300 additions and 12587 deletions

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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
}
}

View File

@@ -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;
}
}

View File

@@ -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

View 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;
}

View File

@@ -1,13 +0,0 @@
#version 140
/********************Sortant********************/
out vec4 RenderTarget0;
/********************Uniformes********************/
uniform vec4 Color;
/********************Fonctions********************/
void main()
{
RenderTarget0 = Color;
}

View File

@@ -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,

View File

@@ -1,13 +0,0 @@
#version 140
/********************Entrant********************/
in vec3 VertexPosition;
/********************Uniformes********************/
uniform mat4 WorldViewProjMatrix;
/********************Fonctions********************/
void main()
{
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
}

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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é
}
}

View File

@@ -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;
}
}

View File

@@ -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