223 lines
5.7 KiB
C++
223 lines
5.7 KiB
C++
// Copyright (C) 2017 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 <Nazara/Graphics/SkyboxBackground.hpp>
|
|
#include <Nazara/Core/ErrorFlags.hpp>
|
|
#include <Nazara/Graphics/AbstractViewer.hpp>
|
|
#include <Nazara/Renderer/Renderer.hpp>
|
|
#include <Nazara/Renderer/RenderStates.hpp>
|
|
#include <Nazara/Renderer/RenderTarget.hpp>
|
|
#include <Nazara/Renderer/Shader.hpp>
|
|
#include <Nazara/Utility/IndexBuffer.hpp>
|
|
#include <Nazara/Utility/VertexBuffer.hpp>
|
|
#include <Nazara/Utility/VertexDeclaration.hpp>
|
|
#include <Nazara/Graphics/Debug.hpp>
|
|
|
|
namespace Nz
|
|
{
|
|
namespace
|
|
{
|
|
static IndexBufferRef s_indexBuffer;
|
|
static RenderStates s_renderStates;
|
|
static ShaderRef s_shader;
|
|
static VertexBufferRef s_vertexBuffer;
|
|
}
|
|
|
|
/*!
|
|
* \ingroup graphics
|
|
* \class Nz::SkyboxBackground
|
|
* \brief Graphics class that represents a background with a cubemap texture
|
|
*/
|
|
|
|
/*!
|
|
* \brief Constructs a SkyboxBackground object with a cubemap texture
|
|
*
|
|
* \param cubemapTexture Cubemap texture
|
|
*/
|
|
|
|
SkyboxBackground::SkyboxBackground(TextureRef cubemapTexture) :
|
|
m_movementOffset(Vector3f::Zero()),
|
|
m_movementScale(0.f)
|
|
{
|
|
m_sampler.SetWrapMode(SamplerWrap_Clamp); // We don't want to see any beam
|
|
|
|
SetTexture(std::move(cubemapTexture));
|
|
}
|
|
|
|
/*!
|
|
* \brief Draws this relatively to the viewer
|
|
*
|
|
* \param viewer Viewer for the background
|
|
*/
|
|
|
|
void SkyboxBackground::Draw(const AbstractViewer* viewer) const
|
|
{
|
|
const Nz::RenderTarget* target = viewer->GetTarget();
|
|
Nz::Vector2ui targetSize = target->GetSize();
|
|
|
|
Matrix4f projectionMatrix = Nz::Matrix4f::Perspective(45.f, float(targetSize.x) / targetSize.y, viewer->GetZNear(), viewer->GetZFar());
|
|
|
|
Matrix4f skyboxMatrix(viewer->GetViewMatrix());
|
|
skyboxMatrix.SetTranslation(Vector3f::Zero());
|
|
|
|
float zNear = viewer->GetZNear();
|
|
|
|
constexpr float movementLimit = 0.05f;
|
|
|
|
Vector3f offset = (viewer->GetEyePosition() - m_movementOffset) * -m_movementScale;
|
|
offset.x = Clamp(offset.x, -movementLimit, movementLimit);
|
|
offset.y = Clamp(offset.y, -movementLimit, movementLimit);
|
|
offset.z = Clamp(offset.z, -movementLimit, movementLimit);
|
|
offset *= zNear;
|
|
|
|
Matrix4f world;
|
|
world.MakeIdentity();
|
|
world.SetScale(Vector3f(zNear));
|
|
world.SetTranslation(offset);
|
|
|
|
Renderer::SetIndexBuffer(s_indexBuffer);
|
|
Renderer::SetMatrix(MatrixType_Projection, projectionMatrix);
|
|
Renderer::SetMatrix(MatrixType_View, skyboxMatrix);
|
|
Renderer::SetMatrix(MatrixType_World, world);
|
|
Renderer::SetRenderStates(s_renderStates);
|
|
Renderer::SetShader(s_shader);
|
|
Renderer::SetTexture(0, m_texture);
|
|
Renderer::SetTextureSampler(0, m_sampler);
|
|
Renderer::SetVertexBuffer(s_vertexBuffer);
|
|
|
|
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, 36);
|
|
|
|
Renderer::SetMatrix(MatrixType_Projection, viewer->GetProjectionMatrix());
|
|
Renderer::SetMatrix(MatrixType_View, viewer->GetViewMatrix());
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the background type
|
|
* \return Type of background
|
|
*/
|
|
|
|
BackgroundType SkyboxBackground::GetBackgroundType() const
|
|
{
|
|
return BackgroundType_Skybox;
|
|
}
|
|
|
|
/*!
|
|
* \brief Initializes the skybox
|
|
* \return true If successful
|
|
*
|
|
* \remark Produces a NazaraError if initialization failed
|
|
*/
|
|
|
|
bool SkyboxBackground::Initialize()
|
|
{
|
|
const UInt16 indices[6 * 6] =
|
|
{
|
|
0, 1, 2, 0, 2, 3,
|
|
3, 2, 6, 3, 6, 7,
|
|
7, 6, 5, 7, 5, 4,
|
|
4, 5, 1, 4, 1, 0,
|
|
0, 3, 7, 0, 7, 4,
|
|
1, 6, 2, 1, 5, 6
|
|
};
|
|
|
|
const float vertices[8 * 3 * sizeof(float)] =
|
|
{
|
|
-1.0, 1.0, 1.0,
|
|
-1.0, -1.0, 1.0,
|
|
1.0, -1.0, 1.0,
|
|
1.0, 1.0, 1.0,
|
|
-1.0, 1.0, -1.0,
|
|
-1.0, -1.0, -1.0,
|
|
1.0, -1.0, -1.0,
|
|
1.0, 1.0, -1.0,
|
|
};
|
|
|
|
///TODO: Replace by ShaderNode (probably after Vulkan)
|
|
const char* fragmentShaderSource =
|
|
"#version 140\n"
|
|
|
|
"in vec3 vTexCoord;\n"
|
|
|
|
"out vec4 RenderTarget0;\n"
|
|
|
|
"uniform samplerCube Skybox;\n"
|
|
"uniform float VertexDepth;\n"
|
|
|
|
"void main()\n"
|
|
"{\n"
|
|
" RenderTarget0 = texture(Skybox, vTexCoord);\n"
|
|
" gl_FragDepth = VertexDepth;\n"
|
|
"}\n";
|
|
|
|
const char* vertexShaderSource =
|
|
"#version 140\n"
|
|
|
|
"in vec3 VertexPosition;\n"
|
|
|
|
"out vec3 vTexCoord;\n"
|
|
|
|
"uniform mat4 WorldViewProjMatrix;\n"
|
|
|
|
"void main()\n"
|
|
"{\n"
|
|
" vec4 WVPVertex = WorldViewProjMatrix * vec4(VertexPosition, 1.0);\n"
|
|
" gl_Position = WVPVertex.xyww;\n"
|
|
" vTexCoord = VertexPosition;\n"
|
|
"}\n";
|
|
|
|
try
|
|
{
|
|
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
|
|
|
// Index buffer
|
|
IndexBufferRef indexBuffer = IndexBuffer::New(false, 36, DataStorage_Hardware, 0);
|
|
indexBuffer->Fill(indices, 0, 36);
|
|
|
|
// Vertex buffer
|
|
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ), 8, DataStorage_Hardware, 0);
|
|
vertexBuffer->Fill(vertices, 0, 8);
|
|
|
|
// Shader
|
|
ShaderRef shader = Shader::New();
|
|
shader->Create();
|
|
shader->AttachStageFromSource(ShaderStageType_Fragment, fragmentShaderSource);
|
|
shader->AttachStageFromSource(ShaderStageType_Vertex, vertexShaderSource);
|
|
shader->Link();
|
|
|
|
shader->SendInteger(shader->GetUniformLocation("Skybox"), 0);
|
|
shader->SendFloat(shader->GetUniformLocation("VertexDepth"), 1.f);
|
|
|
|
// Renderstates
|
|
s_renderStates.depthFunc = RendererComparison_Equal;
|
|
s_renderStates.cullingSide = FaceSide_Front;
|
|
s_renderStates.depthBuffer = true;
|
|
s_renderStates.depthWrite = false;
|
|
s_renderStates.faceCulling = true;
|
|
|
|
// Exception-free zone
|
|
s_indexBuffer = std::move(indexBuffer);
|
|
s_shader = std::move(shader);
|
|
s_vertexBuffer = std::move(vertexBuffer);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
NazaraError("Failed to initialise: " + String(e.what()));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
* \brief Uninitializes the skybox
|
|
*/
|
|
|
|
void SkyboxBackground::Uninitialize()
|
|
{
|
|
s_indexBuffer.Reset();
|
|
s_shader.Reset();
|
|
s_vertexBuffer.Reset();
|
|
}
|
|
}
|