// 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 { static NzShader* s_shader = nullptr; static NzColor s_primaryColor; static NzColor s_secondaryColor; static NzRenderStates s_renderStates; static NzVertexBuffer s_vertexBuffer; static bool s_initialized = false; static int s_colorLocation = -1; } void NzDebugDrawer::Draw(const NzBoundingVolumef& volume) { if (!Initialize()) { NazaraError("Failed to initialize Debug Drawer"); return; } if (!volume.IsFinite()) return; NzColor oldPrimaryColor = s_primaryColor; Draw(volume.aabb); s_primaryColor = s_secondaryColor; Draw(volume.obb); s_primaryColor = oldPrimaryColor; } void NzDebugDrawer::Draw(const NzBoxi& box) { Draw(NzBoxf(box)); } void NzDebugDrawer::Draw(const NzBoxf& box) { if (!Initialize()) { NazaraError("Failed to initialize Debug Drawer"); return; } NzBufferMapper mapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, 24); NzVertexStruct_XYZ* vertex = reinterpret_cast(mapper.GetPointer()); NzVector3f 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(); NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, 24); } void NzDebugDrawer::Draw(const NzBoxui& box) { Draw(NzBoxf(box)); } void NzDebugDrawer::Draw(const NzFrustumf& frustum) { if (!Initialize()) { NazaraError("Failed to initialize Debug Drawer"); return; } NzBufferMapper mapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, 24); NzVertexStruct_XYZ* vertex = reinterpret_cast(mapper.GetPointer()); vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightTop)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; mapper.Unmap(); NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, 24); } void NzDebugDrawer::Draw(const NzOrientedBoxf& orientedBox) { if (!Initialize()) { NazaraError("Failed to initialize Debug Drawer"); return; } NzBufferMapper mapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, 24); NzVertexStruct_XYZ* vertex = reinterpret_cast(mapper.GetPointer()); vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightTop)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; mapper.Unmap(); NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, 24); } void NzDebugDrawer::Draw(const NzSkeleton* 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; } NzBufferMapper mapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, jointCount*2); NzVertexStruct_XYZ* vertex = reinterpret_cast(mapper.GetPointer()); unsigned int vertexCount = 0; for (unsigned int i = 0; i < jointCount; ++i) { const NzNode* joint = skeleton->GetJoint(i); const NzNode* parent = joint->GetParent(); if (parent) { vertex->position = joint->GetPosition(); vertex++; vertex->position = parent->GetPosition(); vertex++; vertexCount += 2; } } mapper.Unmap(); if (vertexCount > 0) { NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, vertexCount); s_shader->SendColor(s_colorLocation, s_secondaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_PointList, 0, vertexCount); } } void NzDebugDrawer::Draw(const NzVector3f& position, float size) { Draw(NzBoxf(position.x - size*0.5f, position.y - size*0.5f, position.z - size*0.5f, size, size, size)); } void NzDebugDrawer::DrawAxes(const NzVector3f& position, float size) { NzColor oldPrimaryColor = s_primaryColor; s_primaryColor = NzColor::Red; DrawLine(position, position + NzVector3f::UnitX() * 3.f * size / 4.f); s_primaryColor = NzColor::Green; DrawLine(position, position + NzVector3f::UnitY() * 3.f * size / 4.f); s_primaryColor = NzColor::Blue; DrawLine(position, position + NzVector3f::UnitZ() * 3.f * size / 4.f); s_primaryColor = NzColor::Red; DrawCone(position + NzVector3f::UnitX() * size, NzEulerAnglesf(0.f, 90.f, 0.f), 15, size / 4.f); s_primaryColor = NzColor::Green; DrawCone(position + NzVector3f::UnitY() * size, NzEulerAnglesf(-90.f, 0.f, 0.f), 15, size / 4.f); s_primaryColor = NzColor::Blue; DrawCone(position + NzVector3f::UnitZ() * size, NzEulerAnglesf(0.f, 0.f, 0.f), 15, size / 4.f); s_primaryColor = oldPrimaryColor; } void NzDebugDrawer::DrawBinormals(const NzStaticMesh* 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; } NzBufferMapper inputMapper(subMesh->GetVertexBuffer(), nzBufferAccess_ReadOnly); NzBufferMapper outputMapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, vertexCount); NzMeshVertex* inputVertex = reinterpret_cast(inputMapper.GetPointer()); NzVertexStruct_XYZ* outputVertex = reinterpret_cast(outputMapper.GetPointer()); for (unsigned int i = 0; i < normalCount; ++i) { outputVertex->position = inputVertex->position; outputVertex++; outputVertex->position = inputVertex->position + NzVector3f::CrossProduct(inputVertex->normal, inputVertex->tangent)*0.01f; outputVertex++; inputVertex++; } inputMapper.Unmap(); outputMapper.Unmap(); if (vertexCount > 0) { NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, vertexCount); } } void NzDebugDrawer::DrawCone(const NzVector3f& origin, const NzQuaternionf& rotation, float angle, float length) { if (!Initialize()) { NazaraError("Failed to initialize Debug Drawer"); return; } NzMatrix4f transformMatrix; transformMatrix.MakeIdentity(); transformMatrix.SetRotation(rotation); transformMatrix.SetTranslation(origin); NzBufferMapper mapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, 16); NzVertexStruct_XYZ* vertex = reinterpret_cast(mapper.GetPointer()); // On calcule le reste des points NzVector3f base(NzVector3f::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(NzDegreeToRadian(angle)); NzVector3f lExtend = NzVector3f::Left()*radius; NzVector3f uExtend = NzVector3f::Up()*radius; vertex->position.Set(transformMatrix * NzVector3f::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 * NzVector3f::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 * NzVector3f::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 * NzVector3f::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(); NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, 16); } void NzDebugDrawer::DrawLine(const NzVector3f& p1, const NzVector3f& p2) { if (!s_initialized && !Initialize()) { NazaraError("Failed to initialize Debug Drawer"); return; } NzVertexStruct_XYZ buffer[2]; buffer[0].position = p1; buffer[1].position = p2; s_vertexBuffer.Fill(&buffer[0], 0, 2); NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, 2); } void NzDebugDrawer::DrawPoints(const NzVector3f* ptr, unsigned int pointCount) { static_assert(sizeof(NzVertexStruct_XYZ) == sizeof(NzVector3f), "NzVertexStruct_XYZ is no longer equal to NzVector3f, please rewrite this"); if (!s_initialized && !Initialize()) { NazaraError("Failed to initialize Debug Drawer"); return; } if (pointCount > 0) { s_vertexBuffer.Fill(ptr, 0, pointCount); NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_PointList, 0, pointCount); } } void NzDebugDrawer::DrawNormals(const NzStaticMesh* 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; } NzBufferMapper inputMapper(subMesh->GetVertexBuffer(), nzBufferAccess_ReadOnly); NzBufferMapper outputMapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, vertexCount); NzMeshVertex* inputVertex = reinterpret_cast(inputMapper.GetPointer()); NzVertexStruct_XYZ* outputVertex = reinterpret_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) { NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, vertexCount); } } void NzDebugDrawer::DrawTangents(const NzStaticMesh* 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; } NzBufferMapper inputMapper(subMesh->GetVertexBuffer(), nzBufferAccess_ReadOnly); NzBufferMapper outputMapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, vertexCount); NzMeshVertex* inputVertex = reinterpret_cast(inputMapper.GetPointer()); NzVertexStruct_XYZ* outputVertex = reinterpret_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) { NzRenderer::SetRenderStates(s_renderStates); NzRenderer::SetShader(s_shader); NzRenderer::SetVertexBuffer(&s_vertexBuffer); s_shader->SendColor(s_colorLocation, s_primaryColor); NzRenderer::DrawPrimitives(nzPrimitiveMode_LineList, 0, vertexCount); } } void NzDebugDrawer::EnableDepthBuffer(bool depthBuffer) { s_renderStates.parameters[nzRendererParameter_DepthBuffer] = depthBuffer; } float NzDebugDrawer::GetLineWidth() { return s_renderStates.lineWidth; } float NzDebugDrawer::GetPointSize() { return s_renderStates.pointSize; } NzColor NzDebugDrawer::GetPrimaryColor() { return s_primaryColor; } NzColor NzDebugDrawer::GetSecondaryColor() { return s_secondaryColor; } bool NzDebugDrawer::Initialize() { if (!s_initialized) { // s_shader s_shader = NzShaderLibrary::Get("DebugSimple"); s_colorLocation = s_shader->GetUniformLocation("Color"); // s_vertexBuffer try { NzErrorFlags flags(nzErrorFlag_ThrowException, true); s_vertexBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ), 65365, nzDataStorage_Hardware, nzBufferUsage_Dynamic); } catch (const std::exception& e) { NazaraError("Failed to create buffer: " + NzString(e.what())); Uninitialize(); return false; } s_primaryColor = NzColor::Red; s_renderStates.parameters[nzRendererParameter_DepthBuffer] = true; s_secondaryColor = NzColor::Green; s_initialized = true; } return true; } bool NzDebugDrawer::IsDepthBufferEnabled() { return s_renderStates.parameters[nzRendererParameter_DepthBuffer]; } void NzDebugDrawer::SetLineWidth(float width) { s_renderStates.lineWidth = width; } void NzDebugDrawer::SetPointSize(float size) { s_renderStates.pointSize = size; } void NzDebugDrawer::SetPrimaryColor(const NzColor& color) { s_primaryColor = color; } void NzDebugDrawer::SetSecondaryColor(const NzColor& color) { s_secondaryColor = color; } void NzDebugDrawer::Uninitialize() { s_shader = nullptr; s_vertexBuffer.Reset(); s_initialized = false; }