// 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 #include #include #include #include #include #include #include #include #include #include #include #include #include ///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 mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24); VertexStruct_XYZ* vertex = static_cast(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 mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24); VertexStruct_XYZ* vertex = static_cast(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 mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24); VertexStruct_XYZ* vertex = static_cast(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 mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, jointCount*2); VertexStruct_XYZ* vertex = static_cast(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 inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly); BufferMapper outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount); MeshVertex* inputVertex = static_cast(inputMapper.GetPointer()); VertexStruct_XYZ* outputVertex = static_cast(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 mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 16); VertexStruct_XYZ* vertex = static_cast(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 inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly); BufferMapper outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount); MeshVertex* inputVertex = static_cast(inputMapper.GetPointer()); VertexStruct_XYZ* outputVertex = static_cast(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 inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly); BufferMapper outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount); MeshVertex* inputVertex = static_cast(inputMapper.GetPointer()); VertexStruct_XYZ* outputVertex = static_cast(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; } }