// Copyright (C) 2014 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 #ifndef NAZARA_RENDERER_OPENGL #define NAZARA_RENDERER_OPENGL // Nécessaire pour inclure les headers OpenGL #endif #include #include #include #include #include #include #include #include #include #include namespace { NzIndexBuffer* BuildIndexBuffer() { std::unique_ptr indexBuffer(new NzIndexBuffer(false, 36, nzDataStorage_Hardware, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); nzUInt16 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 }; if (!indexBuffer->Fill(indices, 0, 36)) { NazaraError("Failed to create index buffer"); return nullptr; } return indexBuffer.release(); } NzShader* BuildShader() { const char* fragmentSource110 = "#version 110\n" "varying vec3 vTexCoord;\n" "uniform samplerCube Skybox;\n" "uniform float VertexDepth;\n" "void main()\n" "{\n" " gl_FragColor = textureCube(Skybox, vTexCoord);\n" " gl_FragDepth = VertexDepth;\n" "}\n"; const char* fragmentSource140 = "#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* vertexSource110 = "#version 110\n" "attribute vec3 VertexPosition;\n" "varying vec3 vTexCoord;\n" "uniform mat4 WorldViewProjMatrix;\n" "void main()\n" "{\n" " gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);\n" " vTexCoord = vec3(VertexPosition.x, VertexPosition.y, -VertexPosition.z);\n" "}\n"; const char* vertexSource140 = "#version 140\n" "in vec3 VertexPosition;\n" "out vec3 vTexCoord;\n" "uniform mat4 WorldViewProjMatrix;\n" "void main()\n" "{\n" " gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);\n" " vTexCoord = vec3(VertexPosition.x, VertexPosition.y, -VertexPosition.z);\n" "}\n"; ///TODO: Remplacer ça par des ShaderNode std::unique_ptr shader(new NzShader); shader->SetPersistent(false); if (!shader->Create()) { NazaraError("Failed to create shader"); return nullptr; } bool useGLSL140 = (NzOpenGL::GetVersion() >= 310); if (!shader->AttachStageFromSource(nzShaderStage_Fragment, (useGLSL140) ? fragmentSource140 : fragmentSource110)) { NazaraError("Failed to load fragment shader"); return nullptr; } if (!shader->AttachStageFromSource(nzShaderStage_Vertex, (useGLSL140) ? vertexSource140 : vertexSource110)) { NazaraError("Failed to load vertex shader"); return nullptr; } if (!shader->Link()) { NazaraError("Failed to link shader"); return nullptr; } shader->SendInteger(shader->GetUniformLocation("Skybox"), 0); shader->SendFloat(shader->GetUniformLocation("VertexDepth"), 1.f); return shader.release(); } NzRenderStates BuildRenderStates() { NzRenderStates states; states.depthFunc = nzRendererComparison_Equal; states.faceCulling = nzFaceSide_Front; states.parameters[nzRendererParameter_DepthBuffer] = true; states.parameters[nzRendererParameter_DepthWrite] = false; states.parameters[nzRendererParameter_FaceCulling] = true; return states; } NzVertexBuffer* BuildVertexBuffer() { std::unique_ptr vertexBuffer(new NzVertexBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ), 8, nzDataStorage_Hardware, nzBufferUsage_Static)); vertexBuffer->SetPersistent(false); float vertices[8*(sizeof(float)*3)] = { -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, }; if (!vertexBuffer->Fill(vertices, 0, 8)) { NazaraError("Failed to create vertex buffer"); return nullptr; } return vertexBuffer.release(); } static NzIndexBuffer* s_indexBuffer = nullptr; static NzShader* s_shader = nullptr; static NzVertexBuffer* s_vertexBuffer = nullptr; } NzSkyboxBackground::NzSkyboxBackground() { if (!s_indexBuffer) s_indexBuffer = BuildIndexBuffer(); if (!s_shader) s_shader = BuildShader(); if (!s_vertexBuffer) s_vertexBuffer = BuildVertexBuffer(); m_indexBuffer = s_indexBuffer; m_sampler.SetWrapMode(nzSamplerWrap_Clamp); // Nécessaire pour ne pas voir les côtés m_shader = s_shader; m_vertexBuffer = s_vertexBuffer; } NzSkyboxBackground::NzSkyboxBackground(NzTexture* cubemapTexture) : NzSkyboxBackground() { SetTexture(cubemapTexture); } NzSkyboxBackground::~NzSkyboxBackground() { if (m_indexBuffer.Reset()) s_indexBuffer = nullptr; if (m_shader.Reset()) s_shader = nullptr; if (m_vertexBuffer.Reset()) s_vertexBuffer = nullptr; } void NzSkyboxBackground::Draw(const NzScene* scene) const { static NzRenderStates states(BuildRenderStates()); NzAbstractViewer* viewer = scene->GetViewer(); NzMatrix4f skyboxMatrix(viewer->GetViewMatrix()); skyboxMatrix.SetTranslation(NzVector3f::Zero()); NzRenderer::SetIndexBuffer(m_indexBuffer); NzRenderer::SetMatrix(nzMatrixType_View, skyboxMatrix); NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Scale(NzVector3f(viewer->GetZNear()))); NzRenderer::SetRenderStates(states); NzRenderer::SetShader(m_shader); NzRenderer::SetTexture(0, m_texture); NzRenderer::SetTextureSampler(0, m_sampler); NzRenderer::SetVertexBuffer(m_vertexBuffer); NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, 36); NzRenderer::SetMatrix(nzMatrixType_View, viewer->GetViewMatrix()); } nzBackgroundType NzSkyboxBackground::GetBackgroundType() const { return nzBackgroundType_Skybox; } NzTexture* NzSkyboxBackground::GetTexture() const { return m_texture; } void NzSkyboxBackground::SetTexture(NzTexture* cubemapTexture) { #if NAZARA_GRAPHICS_SAFE if (cubemapTexture) { if (!cubemapTexture->IsValid()) { NazaraError("Texture must be valid"); return; } if (!cubemapTexture->IsCubemap()) { NazaraError("Texture must be a cubemap"); return; } } #endif m_texture = cubemapTexture; }