// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Graphics module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include NzView::NzView() : m_targetRegion(0.f, 0.f, 1.f, 1.f), m_size(0.f), m_target(nullptr), m_frustumUpdated(false), m_invViewProjMatrixUpdated(false), m_projectionMatrixUpdated(false), m_viewMatrixUpdated(false), m_viewProjMatrixUpdated(false), m_viewportUpdated(false), m_zFar(1.f), m_zNear(-1.f) { } NzView::NzView(const NzVector2f& size) : NzView() // On délègue { SetSize(size); } void NzView::EnsureFrustumUpdate() const { if (!m_frustumUpdated) UpdateFrustum(); } void NzView::EnsureProjectionMatrixUpdate() const { if (!m_projectionMatrixUpdated) UpdateProjectionMatrix(); } void NzView::EnsureViewMatrixUpdate() const { if (!m_viewMatrixUpdated) UpdateViewMatrix(); } void NzView::EnsureViewportUpdate() const { if (!m_viewportUpdated) UpdateViewport(); } float NzView::GetAspectRatio() const { return 1.f; } NzVector3f NzView::GetEyePosition() const { return GetPosition(nzCoordSys_Global); } NzVector3f NzView::GetForward() const { return NzNode::GetForward(); } const NzFrustumf& NzView::GetFrustum() const { if (!m_frustumUpdated) UpdateFrustum(); return m_frustum; } NzVector3f NzView::GetGlobalForward() const { return NzVector3f::UnitZ(); } NzVector3f NzView::GetGlobalRight() const { return NzVector3f::UnitX(); } NzVector3f NzView::GetGlobalUp() const { return -NzVector3f::UnitY(); } const NzMatrix4f& NzView::GetInvViewProjMatrix() const { if (!m_invViewProjMatrixUpdated) UpdateInvViewProjMatrix(); return m_invViewProjMatrix; } const NzMatrix4f& NzView::GetProjectionMatrix() const { if (!m_projectionMatrixUpdated) UpdateProjectionMatrix(); return m_projectionMatrix; } const NzVector2f& NzView::GetSize() const { return m_size; } const NzRenderTarget* NzView::GetTarget() const { return m_target; } const NzRectf& NzView::GetTargetRegion() const { return m_targetRegion; } const NzMatrix4f& NzView::GetViewMatrix() const { if (!m_viewMatrixUpdated) UpdateViewMatrix(); return m_viewMatrix; } const NzMatrix4f& NzView::GetViewProjMatrix() const { if (!m_viewProjMatrixUpdated) UpdateViewProjMatrix(); return m_viewProjMatrix; } const NzRecti& NzView::GetViewport() const { #if NAZARA_GRAPHICS_SAFE if (!m_target) { NazaraError("Camera has no render target"); return m_viewport; } #endif if (!m_viewportUpdated) UpdateViewport(); return m_viewport; } float NzView::GetZFar() const { return m_zFar; } float NzView::GetZNear() const { return m_zNear; } NzVector2f NzView::MapPixelToWorld(const NzVector2i& pixel) { if (!m_invViewProjMatrixUpdated) UpdateInvViewProjMatrix(); if (!m_viewportUpdated) UpdateViewport(); // Conversion du viewport en flottant NzRectf viewport(m_viewport); NzVector2f normalized; normalized.x = -1.f + 2.f * (pixel.x - viewport.x) / viewport.width; normalized.y = 1.f - 2.f * (pixel.y - viewport.y) / viewport.height; return m_invViewProjMatrix.Transform(normalized); } NzVector2i NzView::MapWorldToPixel(const NzVector2f& coords) { if (!m_viewProjMatrixUpdated) UpdateViewProjMatrix(); if (!m_viewportUpdated) UpdateViewport(); // Conversion du viewport en flottant NzRectf viewport(m_viewport); NzVector2f normalized = m_viewProjMatrix.Transform(coords); NzVector2i pixel; pixel.x = static_cast(( normalized.x + 1.f) * viewport.width / 2.f + viewport.x); pixel.y = static_cast((-normalized.y + 1.f) * viewport.width / 2.f + viewport.y); return pixel; } void NzView::SetSize(const NzVector2f& size) { SetSize(size.x, size.y); } void NzView::SetSize(float width, float height) { m_size.Set(width, height); m_projectionMatrixUpdated = false; } void NzView::SetTarget(const NzRenderTarget* renderTarget) { m_target = renderTarget; if (m_target) { m_targetReleaseSlot.Connect(m_target->OnRenderTargetRelease, this, &NzView::OnRenderTargetRelease); m_targetResizeSlot.Connect(m_target->OnRenderTargetSizeChange, this, &NzView::OnRenderTargetSizeChange); } else { m_targetReleaseSlot.Disconnect(); m_targetResizeSlot.Disconnect(); } } void NzView::SetTarget(const NzRenderTarget& renderTarget) { SetTarget(&renderTarget); } void NzView::SetTargetRegion(const NzRectf& region) { m_targetRegion = region; m_frustumUpdated = false; m_invViewProjMatrixUpdated = false; m_projectionMatrixUpdated = false; m_viewProjMatrixUpdated = false; m_viewportUpdated = false; } void NzView::SetViewport(const NzRecti& viewport) { #if NAZARA_GRAPHICS_SAFE if (!m_target) { NazaraError("Camera has no render target"); return; } #endif // On calcule la région nécessaire pour produire ce viewport avec la taille actuelle de la cible float invWidth = 1.f/m_target->GetWidth(); float invHeight = 1.f/m_target->GetHeight(); SetTargetRegion(NzRectf(invWidth * viewport.x, invHeight * viewport.y, invWidth * viewport.width, invHeight * viewport.height)); } void NzView::SetZFar(float zFar) { m_zFar = zFar; m_frustumUpdated = false; m_invViewProjMatrixUpdated = false; m_projectionMatrixUpdated = false; m_viewProjMatrixUpdated = false; } void NzView::SetZNear(float zNear) { m_zNear = zNear; m_frustumUpdated = false; m_invViewProjMatrixUpdated = false; m_projectionMatrixUpdated = false; m_viewProjMatrixUpdated = false; } void NzView::ApplyView() const { #if NAZARA_GRAPHICS_SAFE if (!m_target) { NazaraError("Camera has no render target"); return; } #endif if (!m_projectionMatrixUpdated) UpdateProjectionMatrix(); if (!m_viewMatrixUpdated) UpdateViewMatrix(); if (!m_viewportUpdated) UpdateViewport(); NzRenderer::SetMatrix(nzMatrixType_Projection, m_projectionMatrix); NzRenderer::SetMatrix(nzMatrixType_View, m_viewMatrix); NzRenderer::SetTarget(m_target); NzRenderer::SetViewport(m_viewport); } void NzView::InvalidateNode() { NzNode::InvalidateNode(); // Le frustum et la view matrix dépendent des paramètres du node, invalidons-les m_frustumUpdated = false; m_invViewProjMatrixUpdated = false; m_viewMatrixUpdated = false; m_viewProjMatrixUpdated = false; } void NzView::OnRenderTargetRelease(const NzRenderTarget* renderTarget) { if (renderTarget == m_target) m_target = nullptr; else NazaraInternalError("Not listening to " + NzString::Pointer(renderTarget)); } void NzView::OnRenderTargetSizeChange(const NzRenderTarget* renderTarget) { if (renderTarget == m_target) { m_frustumUpdated = false; m_projectionMatrixUpdated = false; m_viewportUpdated = false; } else NazaraInternalError("Not listening to " + NzString::Pointer(renderTarget)); } void NzView::UpdateFrustum() const { if (!m_projectionMatrixUpdated) UpdateProjectionMatrix(); if (!m_viewMatrixUpdated) UpdateViewMatrix(); m_frustum.Extract(m_viewMatrix, m_projectionMatrix); m_frustumUpdated = true; } void NzView::UpdateInvViewProjMatrix() const { if (!m_viewProjMatrixUpdated) UpdateViewProjMatrix(); m_viewProjMatrix.GetInverseAffine(&m_invViewProjMatrix); m_invViewProjMatrixUpdated = true; } void NzView::UpdateProjectionMatrix() const { if (m_size.x <= 0.f || m_size.y <= 0.f) // Si la taille est nulle, on prendra la taille du viewport { if (!m_viewportUpdated) UpdateViewport(); m_projectionMatrix.MakeOrtho(0.f, static_cast(m_viewport.width), 0.f, static_cast(m_viewport.height), m_zNear, m_zFar); } else m_projectionMatrix.MakeOrtho(0.f, m_size.x, 0.f, m_size.y, m_zNear, m_zFar); m_projectionMatrixUpdated = true; } void NzView::UpdateViewMatrix() const { if (!m_derivedUpdated) UpdateDerived(); m_viewMatrix.MakeViewMatrix(m_derivedPosition, m_derivedRotation); m_viewMatrixUpdated = true; } void NzView::UpdateViewProjMatrix() const { if (!m_projectionMatrixUpdated) UpdateProjectionMatrix(); if (!m_viewMatrixUpdated) UpdateViewMatrix(); // La matrice de projection orthogonale est affine m_viewProjMatrix = NzMatrix4f::ConcatenateAffine(m_viewMatrix, m_projectionMatrix); m_viewProjMatrixUpdated = true; } void NzView::UpdateViewport() const { unsigned int width = m_target->GetWidth(); unsigned int height = std::max(m_target->GetHeight(), 1U); m_viewport.x = static_cast(width * m_targetRegion.x); m_viewport.y = static_cast(height * m_targetRegion.y); m_viewport.width = static_cast(width * m_targetRegion.width); m_viewport.height = static_cast(height * m_targetRegion.height); m_viewportUpdated = true; }