Merge remote-tracking branch 'refs/remotes/origin/master' into vulkan
Former-commit-id: 2d7b8f2258dcb13272482a886aa88e780bffd307 [formerly ffaa87cb5564013addc8749dff6589f732ffe599] [formerly 6792cc9d7a87711eab92875da19bc4200e4463d6 [formerly 0a51ed831d274b1e325cc2efc57016094a7aee83]] Former-commit-id: b16416186770928262bc982969e9dbf10308d121 [formerly 92dc66185439cf46dcd3fb4672061d75d003d508] Former-commit-id: 34072644c9bf88918998070201d9b131ea5b3731
This commit is contained in:
@@ -385,7 +385,7 @@ namespace Nz
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the cursor
|
||||
* \brief Sets the position of the cursor
|
||||
* \return true if cursor is successfully positioned
|
||||
*
|
||||
* \param pos Position of the cursor
|
||||
@@ -404,7 +404,7 @@ namespace Nz
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the cursor
|
||||
* \brief Sets the position of the cursor
|
||||
* \return true if cursor is successfully positioned
|
||||
*
|
||||
* \param offset Offset according to the cursor begin position
|
||||
@@ -725,7 +725,7 @@ namespace Nz
|
||||
return true;
|
||||
else if (path.Match("\\\\*")) // Ex: \\Laptop
|
||||
return true;
|
||||
else if (path.StartsWith('\\')) // Special : '\' refering to the root
|
||||
else if (path.StartsWith('\\')) // Special : '\' referring to the root
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
@@ -23,6 +23,11 @@ namespace Nz
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
inline bool IsSpace(char32_t character)
|
||||
{
|
||||
return character == '\t' || Unicode::GetCategory(character) & Unicode::Category_Separator;
|
||||
}
|
||||
|
||||
// This algorithm is inspired by the documentation of Qt
|
||||
inline std::size_t GetNewSize(std::size_t newSize)
|
||||
{
|
||||
@@ -1379,7 +1384,7 @@ namespace Nz
|
||||
if (it.base() != m_sharedString->string.get())
|
||||
{
|
||||
--it;
|
||||
if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*it++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1391,7 +1396,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tIt == '\0' || Unicode::GetCategory(*tIt) & Unicode::Category_Separator)
|
||||
if (*tIt == '\0' || Detail::IsSpace(*tIt))
|
||||
return it.base() - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1421,7 +1426,7 @@ namespace Nz
|
||||
if (it.base() != m_sharedString->string.get())
|
||||
{
|
||||
--it;
|
||||
if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*it++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1433,7 +1438,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tIt == '\0' || Unicode::GetCategory(*tIt) & Unicode::Category_Separator)
|
||||
if (*tIt == '\0' || Detail::IsSpace(*tIt))
|
||||
return it.base() - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1465,7 +1470,7 @@ namespace Nz
|
||||
if (ptr != m_sharedString->string.get())
|
||||
{
|
||||
--ptr;
|
||||
if (!(Unicode::GetCategory(*ptr++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*ptr++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1475,7 +1480,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator)
|
||||
if (*tPtr == '\0' || Detail::IsSpace(*tPtr))
|
||||
return ptr-m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1503,7 +1508,7 @@ namespace Nz
|
||||
if (ptr != m_sharedString->string.get())
|
||||
{
|
||||
--ptr;
|
||||
if (!(Unicode::GetCategory(*ptr++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*ptr++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1513,7 +1518,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator)
|
||||
if (*tPtr == '\0' || Detail::IsSpace(*tPtr))
|
||||
return ptr-m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1579,7 +1584,7 @@ namespace Nz
|
||||
if (it.base() != m_sharedString->string.get())
|
||||
{
|
||||
--it;
|
||||
if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*it++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1591,7 +1596,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tIt == '\0' || Unicode::GetCategory(*tIt) & Unicode::Category_Separator)
|
||||
if (*tIt == '\0' || Detail::IsSpace(*tIt))
|
||||
return it.base() - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1621,7 +1626,7 @@ namespace Nz
|
||||
if (it.base() != m_sharedString->string.get())
|
||||
{
|
||||
--it;
|
||||
if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*it++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1633,7 +1638,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tIt == '\0' || Unicode::GetCategory(*tIt) & Unicode::Category_Separator)
|
||||
if (*tIt == '\0' || Detail::IsSpace(*tIt))
|
||||
return it.base() - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1664,7 +1669,7 @@ namespace Nz
|
||||
if (Detail::ToLower(*ptr) == c)
|
||||
{
|
||||
char nextC = *(ptr + 1);
|
||||
if (nextC != '\0' && (Unicode::GetCategory(nextC) & Unicode::Category_Separator_Space) == 0)
|
||||
if (nextC != '\0' && (Detail::IsSpace(nextC)) == 0)
|
||||
continue;
|
||||
|
||||
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
||||
@@ -1675,7 +1680,7 @@ namespace Nz
|
||||
|
||||
if (p == &string.m_sharedString->string[0])
|
||||
{
|
||||
if (ptr == m_sharedString->string.get() || Unicode::GetCategory(*(ptr-1)) & Unicode::Category_Separator_Space)
|
||||
if (ptr == m_sharedString->string.get() || Detail::IsSpace(*(ptr-1)))
|
||||
return ptr-m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1695,7 +1700,7 @@ namespace Nz
|
||||
if (*ptr == string.m_sharedString->string[string.m_sharedString->size-1])
|
||||
{
|
||||
char nextC = *(ptr + 1);
|
||||
if (nextC != '\0' && (Unicode::GetCategory(nextC) & Unicode::Category_Separator_Space) == 0)
|
||||
if (nextC != '\0' && !Detail::IsSpace(nextC))
|
||||
continue;
|
||||
|
||||
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
||||
@@ -1706,7 +1711,7 @@ namespace Nz
|
||||
|
||||
if (p == &string.m_sharedString->string[0])
|
||||
{
|
||||
if (ptr == m_sharedString->string.get() || Unicode::GetCategory(*(ptr - 1)) & Unicode::Category_Separator_Space)
|
||||
if (ptr == m_sharedString->string.get() || Detail::IsSpace(*(ptr - 1)))
|
||||
return ptr-m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1766,7 +1771,7 @@ namespace Nz
|
||||
if (it.base() != m_sharedString->string.get())
|
||||
{
|
||||
--it;
|
||||
if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*it++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1778,7 +1783,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tIt == '\0' || Unicode::GetCategory(*it++) & Unicode::Category_Separator)
|
||||
if (*tIt == '\0' || Detail::IsSpace(*it++))
|
||||
return it.base() - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1806,7 +1811,7 @@ namespace Nz
|
||||
if (it.base() != m_sharedString->string.get())
|
||||
{
|
||||
--it;
|
||||
if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*it++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1818,7 +1823,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tIt == '\0' || Unicode::GetCategory(*it++) & Unicode::Category_Separator)
|
||||
if (*tIt == '\0' || Detail::IsSpace(*it++))
|
||||
return it.base() - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1844,7 +1849,7 @@ namespace Nz
|
||||
{
|
||||
if (Detail::ToLower(*ptr) == c)
|
||||
{
|
||||
if (ptr != m_sharedString->string.get() && (Unicode::GetCategory(*(ptr - 1)) & Unicode::Category_Separator) == 0)
|
||||
if (ptr != m_sharedString->string.get() && !Detail::IsSpace(*(ptr - 1)))
|
||||
continue;
|
||||
|
||||
const char* p = &string[1];
|
||||
@@ -1853,7 +1858,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator)
|
||||
if (*tPtr == '\0' || Detail::IsSpace(*tPtr))
|
||||
return ptr - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1875,7 +1880,7 @@ namespace Nz
|
||||
{
|
||||
if (*ptr == string[0])
|
||||
{
|
||||
if (ptr != m_sharedString->string.get() && (Unicode::GetCategory(*(ptr-1)) & Unicode::Category_Separator) == 0)
|
||||
if (ptr != m_sharedString->string.get() && !Detail::IsSpace(*(ptr-1)))
|
||||
continue;
|
||||
|
||||
const char* p = &string[1];
|
||||
@@ -1884,7 +1889,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator)
|
||||
if (*tPtr == '\0' || Detail::IsSpace(*tPtr))
|
||||
return ptr - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1947,7 +1952,7 @@ namespace Nz
|
||||
if (it.base() != m_sharedString->string.get())
|
||||
{
|
||||
--it;
|
||||
if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*it++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1959,7 +1964,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tIt == '\0' || Unicode::GetCategory(*it++) & Unicode::Category_Separator)
|
||||
if (*tIt == '\0' || Detail::IsSpace(*it++))
|
||||
return it.base() - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -1987,7 +1992,7 @@ namespace Nz
|
||||
if (it.base() != m_sharedString->string.get())
|
||||
{
|
||||
--it;
|
||||
if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
|
||||
if (!Detail::IsSpace(*it++))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1999,7 +2004,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tIt == '\0' || Unicode::GetCategory(*it++) & Unicode::Category_Separator)
|
||||
if (*tIt == '\0' || Detail::IsSpace(*it++))
|
||||
return it.base() - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -2026,7 +2031,7 @@ namespace Nz
|
||||
{
|
||||
if (Detail::ToLower(*ptr) == c)
|
||||
{
|
||||
if (ptr != m_sharedString->string.get() && (Unicode::GetCategory(*(ptr-1)) & Unicode::Category_Separator_Space) == 0)
|
||||
if (ptr != m_sharedString->string.get() && !Detail::IsSpace(*(ptr-1)))
|
||||
continue;
|
||||
|
||||
const char* p = &string.m_sharedString->string[1];
|
||||
@@ -2035,7 +2040,7 @@ namespace Nz
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator_Space)
|
||||
if (*tPtr == '\0' || Detail::IsSpace(*tPtr))
|
||||
return ptr - m_sharedString->string.get();
|
||||
else
|
||||
break;
|
||||
@@ -2056,7 +2061,7 @@ namespace Nz
|
||||
while ((ptr = std::strstr(ptr, string.GetConstBuffer())) != nullptr)
|
||||
{
|
||||
// If the word is really alone
|
||||
if ((ptr == m_sharedString->string.get() || Unicode::GetCategory(*(ptr-1)) & Unicode::Category_Separator_Space) && (*(ptr+m_sharedString->size) == '\0' || Unicode::GetCategory(*(ptr+m_sharedString->size)) & Unicode::Category_Separator_Space))
|
||||
if ((ptr == m_sharedString->string.get() || Detail::IsSpace(*(ptr-1))) && (*(ptr+m_sharedString->size) == '\0' || Detail::IsSpace(*(ptr+m_sharedString->size))))
|
||||
return ptr - m_sharedString->string.get();
|
||||
|
||||
ptr++;
|
||||
@@ -2219,7 +2224,7 @@ namespace Nz
|
||||
utf8::unchecked::iterator<const char*> it(ptr);
|
||||
do
|
||||
{
|
||||
if (Unicode::GetCategory(*it) & Unicode::Category_Separator)
|
||||
if (Detail::IsSpace(*it))
|
||||
{
|
||||
endPos = static_cast<std::intmax_t>(it.base() - m_sharedString->string.get() - 1);
|
||||
break;
|
||||
@@ -2231,7 +2236,7 @@ namespace Nz
|
||||
{
|
||||
do
|
||||
{
|
||||
if (Unicode::GetCategory(*ptr) & Unicode::Category_Separator)
|
||||
if (Detail::IsSpace(*ptr))
|
||||
{
|
||||
endPos = static_cast<std::intmax_t>(ptr - m_sharedString->string.get() - 1);
|
||||
break;
|
||||
@@ -2265,7 +2270,7 @@ namespace Nz
|
||||
utf8::unchecked::iterator<const char*> it(ptr);
|
||||
do
|
||||
{
|
||||
if (Unicode::GetCategory(*it) & Unicode::Category_Separator)
|
||||
if (Detail::IsSpace(*it))
|
||||
inWord = false;
|
||||
else
|
||||
{
|
||||
@@ -2283,7 +2288,7 @@ namespace Nz
|
||||
{
|
||||
do
|
||||
{
|
||||
if (Unicode::GetCategory(*ptr) & Unicode::Category_Separator)
|
||||
if (Detail::IsSpace(*ptr))
|
||||
inWord = false;
|
||||
else
|
||||
{
|
||||
@@ -3414,7 +3419,7 @@ namespace Nz
|
||||
utf8::unchecked::iterator<const char*> it(ptr);
|
||||
do
|
||||
{
|
||||
if (Unicode::GetCategory(*it) & Unicode::Category_Separator)
|
||||
if (Detail::IsSpace(*it))
|
||||
{
|
||||
if (inword)
|
||||
{
|
||||
@@ -3435,7 +3440,7 @@ namespace Nz
|
||||
const char* limit = &m_sharedString->string[m_sharedString->size];
|
||||
do
|
||||
{
|
||||
if (Unicode::GetCategory(*ptr) & Unicode::Category_Separator)
|
||||
if (Detail::IsSpace(*ptr))
|
||||
{
|
||||
if (inword)
|
||||
{
|
||||
@@ -4240,7 +4245,7 @@ namespace Nz
|
||||
utf8::unchecked::iterator<const char*> it(m_sharedString->string.get());
|
||||
do
|
||||
{
|
||||
if (*it != '\t' && (Unicode::GetCategory(*it) & Unicode::Category_Separator) == 0)
|
||||
if (!Detail::IsSpace(*it))
|
||||
break;
|
||||
}
|
||||
while (*++it);
|
||||
@@ -4255,7 +4260,7 @@ namespace Nz
|
||||
utf8::unchecked::iterator<const char*> it(&m_sharedString->string[m_sharedString->size]);
|
||||
while ((it--).base() != m_sharedString->string.get())
|
||||
{
|
||||
if (*it != '\t' && (Unicode::GetCategory(*it) & Unicode::Category_Separator) == 0)
|
||||
if (!Detail::IsSpace(*it))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4271,8 +4276,8 @@ namespace Nz
|
||||
{
|
||||
for (; startPos < m_sharedString->size; ++startPos)
|
||||
{
|
||||
char c = m_sharedString->string[startPos];
|
||||
if (c != '\t' && (Unicode::GetCategory(c) & Unicode::Category_Separator) == 0)
|
||||
char c = m_sharedString->string[startPos];
|
||||
if (!Detail::IsSpace(c))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4282,8 +4287,8 @@ namespace Nz
|
||||
{
|
||||
for (; endPos > 0; --endPos)
|
||||
{
|
||||
char c = m_sharedString->string[endPos];
|
||||
if (c != '\t' && (Unicode::GetCategory(c) & Unicode::Category_Separator) == 0)
|
||||
char c = m_sharedString->string[endPos];
|
||||
if (!Detail::IsSpace(c))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "..\..\..\include\Nazara\Core\StringStream.hpp"
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Nz
|
||||
if (!m_material)
|
||||
return;
|
||||
|
||||
renderQueue->AddBillboard(instanceData.renderOrder, m_material, instanceData.transformMatrix->GetTranslation(), m_size, m_sinCos, m_color);
|
||||
Nz::Vector3f position = instanceData.transformMatrix->GetTranslation();
|
||||
renderQueue->AddBillboards(instanceData.renderOrder, m_material, 1, &position, &m_size, &m_sinCos, &m_color);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -19,11 +19,11 @@ namespace Nz
|
||||
RenderStates BuildRenderStates()
|
||||
{
|
||||
RenderStates states;
|
||||
states.cullingSide = FaceSide_Back;
|
||||
states.depthFunc = RendererComparison_Equal;
|
||||
states.faceCulling = FaceSide_Back;
|
||||
states.parameters[RendererParameter_DepthBuffer] = true;
|
||||
states.parameters[RendererParameter_DepthWrite] = false;
|
||||
states.parameters[RendererParameter_FaceCulling] = true;
|
||||
states.depthBuffer = true;
|
||||
states.depthWrite = false;
|
||||
states.faceCulling = true;
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Nz
|
||||
|
||||
m_bloomBrightShader = ShaderLibrary::Get("DeferredBloomBright");
|
||||
m_bloomFinalShader = ShaderLibrary::Get("DeferredBloomFinal");
|
||||
m_bloomStates.parameters[RendererParameter_DepthBuffer] = false;
|
||||
m_bloomStates.depthBuffer = false;
|
||||
m_gaussianBlurShader = ShaderLibrary::Get("DeferredGaussianBlur");
|
||||
m_gaussianBlurShaderFilterLocation = m_gaussianBlurShader->GetUniformLocation("Filter");
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace Nz
|
||||
m_pointSampler.SetFilterMode(SamplerFilter_Nearest);
|
||||
m_pointSampler.SetWrapMode(SamplerWrap_Clamp);
|
||||
|
||||
m_states.parameters[RendererParameter_DepthBuffer] = false;
|
||||
m_states.depthBuffer = false;
|
||||
}
|
||||
|
||||
DeferredDOFPass::~DeferredDOFPass() = default;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Nz
|
||||
m_pointSampler.SetFilterMode(SamplerFilter_Nearest);
|
||||
m_pointSampler.SetWrapMode(SamplerWrap_Clamp);
|
||||
|
||||
m_states.parameters[RendererParameter_DepthBuffer] = false;
|
||||
m_states.depthBuffer = false;
|
||||
}
|
||||
|
||||
DeferredFXAAPass::~DeferredFXAAPass() = default;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Nz
|
||||
m_pointSampler.SetFilterMode(SamplerFilter_Nearest);
|
||||
m_pointSampler.SetWrapMode(SamplerWrap_Clamp);
|
||||
|
||||
m_states.parameters[RendererParameter_DepthBuffer] = false;
|
||||
m_states.depthBuffer = false;
|
||||
|
||||
m_uberShader = UberShaderLibrary::Get("Basic");
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Nz
|
||||
m_shader = BuildFogShader();
|
||||
m_shaderEyePositionLocation = m_shader->GetUniformLocation("EyePosition");
|
||||
|
||||
m_states.parameters[RendererParameter_DepthBuffer] = false;
|
||||
m_states.depthBuffer = false;
|
||||
}
|
||||
|
||||
DeferredFogPass::~DeferredFogPass() = default;
|
||||
|
||||
@@ -31,12 +31,12 @@ namespace Nz
|
||||
DeferredGeometryPass::DeferredGeometryPass()
|
||||
{
|
||||
m_clearShader = ShaderLibrary::Get("DeferredGBufferClear");
|
||||
m_clearStates.parameters[RendererParameter_DepthBuffer] = true;
|
||||
m_clearStates.parameters[RendererParameter_FaceCulling] = true;
|
||||
m_clearStates.parameters[RendererParameter_StencilTest] = true;
|
||||
m_clearStates.depthBuffer = true;
|
||||
m_clearStates.faceCulling = true;
|
||||
m_clearStates.stencilTest = true;
|
||||
m_clearStates.depthFunc = RendererComparison_Always;
|
||||
m_clearStates.frontFace.stencilCompare = RendererComparison_Always;
|
||||
m_clearStates.frontFace.stencilPass = StencilOperation_Zero;
|
||||
m_clearStates.stencilCompare.front = RendererComparison_Always;
|
||||
m_clearStates.stencilPass.front = StencilOperation_Zero;
|
||||
}
|
||||
|
||||
DeferredGeometryPass::~DeferredGeometryPass() = default;
|
||||
@@ -73,122 +73,132 @@ namespace Nz
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& pair : m_renderQueue->layers)
|
||||
for (auto& layerPair : m_renderQueue->layers)
|
||||
{
|
||||
DeferredRenderQueue::Layer& layer = pair.second;
|
||||
|
||||
for (auto& matIt : layer.opaqueModels)
|
||||
for (auto& pipelinePair : layerPair.second.opaqueModels)
|
||||
{
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
DeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
bool instancing = (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT);
|
||||
|
||||
if (!meshInstances.empty())
|
||||
UInt32 flags = ShaderFlags_Deferred;
|
||||
if (instancing)
|
||||
flags |= ShaderFlags_Instancing;
|
||||
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(flags);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
// We begin by getting the program for materials
|
||||
UInt32 flags = ShaderFlags_Deferred;
|
||||
if (useInstancing)
|
||||
flags |= ShaderFlags_Instancing;
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
const Shader* shader = material->Apply(flags);
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
// The uniforms are conserved in our program, there's no point to send them back if they don't change
|
||||
if (shader != lastShader)
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
DeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
// Ambient color for the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
if (!instances.empty())
|
||||
if (!meshInstances.empty())
|
||||
{
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (indexBuffer)
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
if (useInstancing)
|
||||
{
|
||||
// We get the buffer for instance of Renderer and we configure it to work with matrices
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // The number of matrices that can be hold in the buffer
|
||||
|
||||
while (instanceCount > 0)
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
if (!instances.empty())
|
||||
{
|
||||
// We compute the number of instances that we will be able to show this time (Depending on the instance buffer size)
|
||||
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
// And we show
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
if (indexBuffer)
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
if (instancing)
|
||||
{
|
||||
// We get the buffer for instance of Renderer and we configure it to work with matrices
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // The number of matrices that can be hold in the buffer
|
||||
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
// We compute the number of instances that we will be able to show this time (Depending on the instance buffer size)
|
||||
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// And we show
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Without instancing, we must do one draw call for each instance
|
||||
// This may be faster than instancing under a threshold
|
||||
// Due to the time to modify the instancing buffer
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
|
||||
instances.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Without instancing, we must do one draw call for each instance
|
||||
// This may be faster than instancing under a threshold
|
||||
// Due to the time to modify the instancing buffer
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
|
||||
instances.clear();
|
||||
}
|
||||
|
||||
// And we set it back data to zero
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Abd we set it back data to zero
|
||||
matEntry.enabled = false;
|
||||
matEntry.instancingEnabled = false;
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,9 +120,9 @@ namespace Nz
|
||||
RenderStates lightStates;
|
||||
lightStates.dstBlend = BlendFunc_One;
|
||||
lightStates.srcBlend = BlendFunc_One;
|
||||
lightStates.parameters[RendererParameter_Blend] = true;
|
||||
lightStates.parameters[RendererParameter_DepthBuffer] = false;
|
||||
lightStates.parameters[RendererParameter_DepthWrite] = false;
|
||||
lightStates.blending = true;
|
||||
lightStates.depthBuffer = false;
|
||||
lightStates.depthWrite = false;
|
||||
|
||||
// Directional lights
|
||||
if (!m_renderQueue->directionalLights.empty())
|
||||
@@ -146,18 +146,18 @@ namespace Nz
|
||||
if (!m_renderQueue->pointLights.empty() || !m_renderQueue->spotLights.empty())
|
||||
{
|
||||
// http://www.altdevblogaday.com/2011/08/08/stencil-buffer-optimisation-for-deferred-lights/
|
||||
lightStates.parameters[RendererParameter_StencilTest] = true;
|
||||
lightStates.faceCulling = FaceSide_Front;
|
||||
lightStates.backFace.stencilMask = 0xFF;
|
||||
lightStates.backFace.stencilReference = 0;
|
||||
lightStates.backFace.stencilFail = StencilOperation_Keep;
|
||||
lightStates.backFace.stencilPass = StencilOperation_Keep;
|
||||
lightStates.backFace.stencilZFail = StencilOperation_Invert;
|
||||
lightStates.frontFace.stencilMask = 0xFF;
|
||||
lightStates.frontFace.stencilReference = 0;
|
||||
lightStates.frontFace.stencilFail = StencilOperation_Keep;
|
||||
lightStates.frontFace.stencilPass = StencilOperation_Keep;
|
||||
lightStates.frontFace.stencilZFail = StencilOperation_Invert;
|
||||
lightStates.cullingSide = FaceSide_Front;
|
||||
lightStates.stencilTest = true;
|
||||
lightStates.stencilDepthFail.back = StencilOperation_Invert;
|
||||
lightStates.stencilDepthFail.front = StencilOperation_Invert;
|
||||
lightStates.stencilFail.back = StencilOperation_Keep;
|
||||
lightStates.stencilFail.front = StencilOperation_Keep;
|
||||
lightStates.stencilPass.back = StencilOperation_Keep;
|
||||
lightStates.stencilPass.front = StencilOperation_Keep;
|
||||
lightStates.stencilReference.back = 0;
|
||||
lightStates.stencilReference.front = 0;
|
||||
lightStates.stencilWriteMask.back = 0xFF;
|
||||
lightStates.stencilWriteMask.front = 0xFF;
|
||||
|
||||
Renderer::SetRenderStates(lightStates);
|
||||
|
||||
|
||||
@@ -29,22 +29,6 @@ namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds billboard to the queue
|
||||
*
|
||||
* \param renderOrder Order of rendering
|
||||
* \param material Material of the billboard
|
||||
* \param position Position of the billboard
|
||||
* \param size Sizes of the billboard
|
||||
* \param sinCos Rotation of the billboard
|
||||
* \param color Color of the billboard
|
||||
*/
|
||||
|
||||
void DeferredRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color)
|
||||
{
|
||||
m_forwardQueue->AddBillboard(renderOrder, material, position, size, sinCos, color);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds multiple billboards to the queue
|
||||
*
|
||||
@@ -207,27 +191,39 @@ namespace Nz
|
||||
|
||||
void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
|
||||
{
|
||||
if (material->IsEnabled(RendererParameter_Blend))
|
||||
if (material->IsBlendingEnabled())
|
||||
// One transparent material ? I don't like it, go see if I'm in the forward queue
|
||||
m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix);
|
||||
else
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& opaqueModels = currentLayer.opaqueModels;
|
||||
MeshPipelineBatches& opaqueModels = currentLayer.opaqueModels;
|
||||
|
||||
auto it = opaqueModels.find(material);
|
||||
if (it == opaqueModels.end())
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = opaqueModels.find(materialPipeline);
|
||||
if (pipelineIt == opaqueModels.end())
|
||||
{
|
||||
BatchedMaterialEntry materialEntry;
|
||||
pipelineIt = opaqueModels.insert(MeshPipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedMaterialEntry& materialEntry = pipelineIt->second;
|
||||
MeshMaterialBatches& materialMap = materialEntry.materialMap;
|
||||
|
||||
auto materialIt = materialMap.find(material);
|
||||
if (materialIt == materialMap.end())
|
||||
{
|
||||
BatchedModelEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &DeferredRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
|
||||
materialIt = materialMap.insert(MeshMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedModelEntry& entry = it->second;
|
||||
BatchedModelEntry& entry = materialIt->second;
|
||||
entry.enabled = true;
|
||||
|
||||
auto& meshMap = entry.meshMap;
|
||||
MeshInstanceContainer& meshMap = entry.meshMap;
|
||||
|
||||
auto it2 = meshMap.find(meshData);
|
||||
if (it2 == meshMap.end())
|
||||
@@ -241,13 +237,8 @@ namespace Nz
|
||||
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
|
||||
}
|
||||
|
||||
// We add matrices to the list of instances of this object
|
||||
std::vector<Matrix4f>& instances = it2->second.instances;
|
||||
instances.push_back(transformMatrix);
|
||||
|
||||
// Do we have enough instances to perform instancing ?
|
||||
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
|
||||
entry.instancingEnabled = true; // Thus we can activate it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +300,7 @@ namespace Nz
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of an index buffer
|
||||
*
|
||||
@@ -322,16 +313,19 @@ namespace Nz
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& modelPair : layer.opaqueModels)
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
MeshInstanceContainer& meshes = modelPair.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.indexBuffer == indexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.indexBuffer == indexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,7 +343,8 @@ namespace Nz
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
layer.opaqueModels.erase(material);
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,73 +359,21 @@ namespace Nz
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& modelPair : layer.opaqueModels)
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
MeshInstanceContainer& meshes = modelPair.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.vertexBuffer == vertexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.vertexBuffer == vertexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two batched model with material
|
||||
* \return true If first material is "smaller" than the second one
|
||||
*
|
||||
* \param mat1 First material to compare
|
||||
* \param mat2 Second material to compare
|
||||
*/
|
||||
|
||||
bool DeferredRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
const UberShader* uberShader2 = mat2->GetShader();
|
||||
if (uberShader1 != uberShader2)
|
||||
return uberShader1 < uberShader2;
|
||||
|
||||
const Shader* shader1 = mat1->GetShaderInstance(ShaderFlags_Deferred)->GetShader();
|
||||
const Shader* shader2 = mat2->GetShaderInstance(ShaderFlags_Deferred)->GetShader();
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
return diffuseMap1 < diffuseMap2;
|
||||
|
||||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two mesh data
|
||||
* \return true If first mesh is "smaller" than the second one
|
||||
*
|
||||
* \param data1 First mesh to compare
|
||||
* \param data2 Second mesh to compare
|
||||
*/
|
||||
|
||||
bool DeferredRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const
|
||||
{
|
||||
const Buffer* buffer1;
|
||||
const Buffer* buffer2;
|
||||
|
||||
buffer1 = (data1.indexBuffer) ? data1.indexBuffer->GetBuffer() : nullptr;
|
||||
buffer2 = (data2.indexBuffer) ? data2.indexBuffer->GetBuffer() : nullptr;
|
||||
if (buffer1 != buffer2)
|
||||
return buffer1 < buffer2;
|
||||
|
||||
buffer1 = data1.vertexBuffer->GetBuffer();
|
||||
buffer2 = data2.vertexBuffer->GetBuffer();
|
||||
if (buffer1 != buffer2)
|
||||
return buffer1 < buffer2;
|
||||
|
||||
return data1.primitiveMode < data2.primitiveMode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,40 +23,11 @@ namespace Nz
|
||||
{
|
||||
// Material
|
||||
m_baseMaterial = Material::New();
|
||||
m_baseMaterial->Enable(RendererParameter_ColorWrite, false);
|
||||
m_baseMaterial->Enable(RendererParameter_FaceCulling, false);
|
||||
m_baseMaterial->EnableColorWrite(false);
|
||||
m_baseMaterial->EnableFaceCulling(false);
|
||||
//m_baseMaterial->SetFaceCulling(FaceSide_Front);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds billboard to the queue
|
||||
*
|
||||
* \param renderOrder Order of rendering
|
||||
* \param material Material of the billboard
|
||||
* \param position Position of the billboard
|
||||
* \param size Sizes of the billboard
|
||||
* \param sinCos Rotation of the billboard
|
||||
* \param color Color of the billboard
|
||||
*
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
|
||||
if (!IsMaterialSuitable(material))
|
||||
return;
|
||||
|
||||
if (material->HasDepthMaterial())
|
||||
material = material->GetDepthMaterial();
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboard(0, material, position, size, sinCos, color);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds multiple billboards to the queue
|
||||
*
|
||||
|
||||
@@ -52,6 +52,10 @@ namespace Nz
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
std::array<UInt8, 4> whitePixel = {255, 255, 255, 255};
|
||||
m_whiteTexture.Create(ImageType_2D, PixelFormatType_RGBA8, 1, 1);
|
||||
m_whiteTexture.Update(whitePixel.data());
|
||||
|
||||
m_vertexBuffer.Create(s_vertexBufferSize, DataStorage_Hardware, BufferUsage_Dynamic);
|
||||
|
||||
m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer);
|
||||
@@ -208,6 +212,8 @@ namespace Nz
|
||||
|
||||
void DepthRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
@@ -215,95 +221,102 @@ namespace Nz
|
||||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||
|
||||
for (auto& matIt : layer.basicSprites)
|
||||
for (auto& pipelinePair : layer.basicSprites)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt32 flags = 0;
|
||||
if (overlay)
|
||||
flags |= ShaderFlags_TextureOverlay;
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
UInt8 overlayUnit;
|
||||
const Shader* shader = material->Apply(flags, 0, &overlayUnit);
|
||||
|
||||
if (overlay)
|
||||
{
|
||||
overlayUnit++;
|
||||
Renderer::SetTexture(overlayUnit, overlay);
|
||||
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
|
||||
}
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Overlay
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
unsigned int spriteChain = 0; // Which chain of sprites are we treating
|
||||
unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
// We open the buffer in writing mode
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||
VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
unsigned int spriteCount = 0;
|
||||
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount()/4);
|
||||
|
||||
do
|
||||
{
|
||||
ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
|
||||
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
|
||||
|
||||
std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(VertexStruct_XYZ_Color_UV));
|
||||
vertices += count*4;
|
||||
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChain.spriteCount)
|
||||
{
|
||||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
}
|
||||
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount*6);
|
||||
}
|
||||
while (spriteChain < spriteChainCount);
|
||||
|
||||
spriteChainVector.clear();
|
||||
}
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
// On remet à zéro
|
||||
matEntry.enabled = false;
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
UInt8 overlayUnit;
|
||||
material->Apply(pipelineInstance, 0, &overlayUnit);
|
||||
overlayUnit++;
|
||||
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
|
||||
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
|
||||
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
{
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
Renderer::SetTexture(overlayUnit, (overlay) ? overlay : &m_whiteTexture);
|
||||
|
||||
unsigned int spriteChain = 0; // Which chain of sprites are we treating
|
||||
unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
// We open the buffer in writing mode
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
unsigned int spriteCount = 0;
|
||||
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||
|
||||
do
|
||||
{
|
||||
ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
|
||||
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
|
||||
|
||||
std::memcpy(vertices, currentChain.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
|
||||
vertices += count * 4;
|
||||
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChain.spriteCount)
|
||||
{
|
||||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
} while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
} while (spriteChain < spriteChainCount);
|
||||
|
||||
spriteChainVector.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// We set it back to zero
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
pipelineEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,9 +327,11 @@ namespace Nz
|
||||
* \param sceneData Data of the scene
|
||||
* \param layer Layer of the rendering
|
||||
*/
|
||||
|
||||
|
||||
void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
@@ -327,17 +342,16 @@ namespace Nz
|
||||
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
for (auto& matIt : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
@@ -345,27 +359,43 @@ namespace Nz
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
do
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
|
||||
data += renderedBillboardCount;
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(renderedBillboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
do
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
|
||||
data += renderedBillboardCount;
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(renderedBillboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,17 +404,16 @@ namespace Nz
|
||||
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
|
||||
Renderer::SetVertexBuffer(&m_billboardPointBuffer);
|
||||
|
||||
for (auto& matIt : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
@@ -392,63 +421,73 @@ namespace Nz
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount()/4);
|
||||
|
||||
do
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4);
|
||||
BillboardPoint* vertices = reinterpret_cast<BillboardPoint*>(vertexMapper.GetPointer());
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
|
||||
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
do
|
||||
{
|
||||
const ForwardRenderQueue::BillboardData& billboard = *data++;
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 1.f);
|
||||
vertices++;
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4);
|
||||
BillboardPoint* vertices = static_cast<BillboardPoint*>(vertexMapper.GetPointer());
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 1.f);
|
||||
vertices++;
|
||||
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
|
||||
{
|
||||
const ForwardRenderQueue::BillboardData& billboard = *data++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 0.f);
|
||||
vertices++;
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 1.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 0.f);
|
||||
vertices++;
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 1.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 0.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 0.f);
|
||||
vertices++;
|
||||
}
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6);
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount*6);
|
||||
billboardVector.clear();
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,116 +499,131 @@ namespace Nz
|
||||
* \param sceneData Data of the scene
|
||||
* \param layer Layer of the rendering
|
||||
*/
|
||||
|
||||
|
||||
void DepthRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& matIt : layer.opaqueModels)
|
||||
for (auto& pipelinePair : layer.opaqueModels)
|
||||
{
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
bool instancing = (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply((instancing) ? ShaderFlags_Instancing : 0);
|
||||
|
||||
if (!meshInstances.empty())
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
bool instancing = m_instancingEnabled && matEntry.instancingEnabled;
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt8 freeTextureUnit;
|
||||
const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit);
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
lastShader = shader;
|
||||
}
|
||||
UInt8 freeTextureUnit;
|
||||
material->Apply(pipelineInstance, 0, &freeTextureUnit);
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
const Spheref& squaredBoundingSphere = meshEntry.squaredBoundingSphere;
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
|
||||
if (!instances.empty())
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
const Spheref& squaredBoundingSphere = meshEntry.squaredBoundingSphere;
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
|
||||
if (indexBuffer)
|
||||
if (!instances.empty())
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (instancing)
|
||||
{
|
||||
// We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
if (indexBuffer)
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // The maximum number of instances in one batch
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
while (instanceCount > 0)
|
||||
if (instancing)
|
||||
{
|
||||
// We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
|
||||
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch
|
||||
|
||||
// And we draw
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
// We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
|
||||
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// And we draw
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Without instancing, we must do a draw call for each instance
|
||||
else
|
||||
{
|
||||
// Without instancing, we must do a draw call for each instance
|
||||
// This may be faster than instancing under a certain number
|
||||
// Due to the time to modify the instancing buffer
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
instances.clear();
|
||||
}
|
||||
instances.clear();
|
||||
}
|
||||
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// And we set the data back to zero
|
||||
matEntry.enabled = false;
|
||||
matEntry.instancingEnabled = false;
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Nz
|
||||
else
|
||||
NazaraWarning("Failed to load material from file " + String::Number(i));
|
||||
}
|
||||
else if (matData.HasParameter(MaterialData::CustomDefined))
|
||||
else
|
||||
{
|
||||
MaterialRef material = Material::New();
|
||||
material->BuildFromParameters(matData, parameters.material);
|
||||
|
||||
@@ -17,40 +17,6 @@ namespace Nz
|
||||
* \brief Graphics class that represents the rendering queue for forward rendering
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Adds billboard to the queue
|
||||
*
|
||||
* \param renderOrder Order of rendering
|
||||
* \param material Material of the billboard
|
||||
* \param position Position of the billboard
|
||||
* \param size Sizes of the billboard
|
||||
* \param sinCos Rotation of the billboard
|
||||
* \param color Color of the billboard
|
||||
*
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
auto& billboards = GetLayer(renderOrder).billboards;
|
||||
|
||||
auto it = billboards.find(material);
|
||||
if (it == billboards.end())
|
||||
{
|
||||
BatchedBillboardEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedBillboardEntry& entry = it->second;
|
||||
|
||||
auto& billboardVector = entry.billboards;
|
||||
billboardVector.push_back(BillboardData{color, position, size, sinCos});
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds multiple billboards to the queue
|
||||
*
|
||||
@@ -406,12 +372,11 @@ namespace Nz
|
||||
*
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (material->IsEnabled(RendererParameter_Blend))
|
||||
if (material->IsBlendingEnabled())
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& transparentModels = currentLayer.transparentModels;
|
||||
@@ -432,21 +397,33 @@ namespace Nz
|
||||
else
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& opaqueModels = currentLayer.opaqueModels;
|
||||
MeshPipelineBatches& opaqueModels = currentLayer.opaqueModels;
|
||||
|
||||
auto it = opaqueModels.find(material);
|
||||
if (it == opaqueModels.end())
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = opaqueModels.find(materialPipeline);
|
||||
if (pipelineIt == opaqueModels.end())
|
||||
{
|
||||
BatchedMaterialEntry materialEntry;
|
||||
pipelineIt = opaqueModels.insert(MeshPipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedMaterialEntry& materialEntry = pipelineIt->second;
|
||||
MeshMaterialBatches& materialMap = materialEntry.materialMap;
|
||||
|
||||
auto materialIt = materialMap.find(material);
|
||||
if (materialIt == materialMap.end())
|
||||
{
|
||||
BatchedModelEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
|
||||
materialIt = materialMap.insert(MeshMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedModelEntry& entry = it->second;
|
||||
BatchedModelEntry& entry = materialIt->second;
|
||||
entry.enabled = true;
|
||||
|
||||
auto& meshMap = entry.meshMap;
|
||||
MeshInstanceContainer& meshMap = entry.meshMap;
|
||||
|
||||
auto it2 = meshMap.find(meshData);
|
||||
if (it2 == meshMap.end())
|
||||
@@ -465,9 +442,7 @@ namespace Nz
|
||||
std::vector<Matrix4f>& instances = it2->second.instances;
|
||||
instances.push_back(transformMatrix);
|
||||
|
||||
// Do we have enough instances to perform instancing ?
|
||||
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
|
||||
entry.instancingEnabled = true; // Thus we can activate it
|
||||
materialEntry.maxInstanceCount = std::max(materialEntry.maxInstanceCount, instances.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,21 +457,34 @@ namespace Nz
|
||||
*
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& basicSprites = currentLayer.basicSprites;
|
||||
SpritePipelineBatches& basicSprites = currentLayer.basicSprites;
|
||||
|
||||
auto matIt = basicSprites.find(material);
|
||||
if (matIt == basicSprites.end())
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = basicSprites.find(materialPipeline);
|
||||
if (pipelineIt == basicSprites.end())
|
||||
{
|
||||
BatchedSpritePipelineEntry materialEntry;
|
||||
pipelineIt = basicSprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second;
|
||||
pipelineEntry.enabled = true;
|
||||
|
||||
SpriteMaterialBatches& materialMap = pipelineEntry.materialMap;
|
||||
|
||||
auto matIt = materialMap.find(material);
|
||||
if (matIt == materialMap.end())
|
||||
{
|
||||
BatchedBasicSpriteEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
matIt = basicSprites.insert(std::make_pair(material, std::move(entry))).first;
|
||||
matIt = materialMap.insert(SpriteMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedBasicSpriteEntry& entry = matIt->second;
|
||||
@@ -575,19 +563,22 @@ namespace Nz
|
||||
return nearPlane.Distance(position1) > nearPlane.Distance(position2);
|
||||
});
|
||||
|
||||
for (auto& pair : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* mat = pair.first;
|
||||
|
||||
if (mat->IsDepthSortingEnabled())
|
||||
for (auto& matPair : pipelinePair.second.materialMap)
|
||||
{
|
||||
BatchedBillboardEntry& entry = pair.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
const Material* mat = matPair.first;
|
||||
|
||||
std::sort(billboardVector.begin(), billboardVector.end(), [&viewerPos] (const BillboardData& data1, const BillboardData& data2)
|
||||
if (mat->IsDepthSortingEnabled())
|
||||
{
|
||||
return viewerPos.SquaredDistance(data1.center) > viewerPos.SquaredDistance(data2.center);
|
||||
});
|
||||
BatchedBillboardEntry& entry = matPair.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
std::sort(billboardVector.begin(), billboardVector.end(), [&viewerPos] (const BillboardData& data1, const BillboardData& data2)
|
||||
{
|
||||
return viewerPos.SquaredDistance(data1.center) > viewerPos.SquaredDistance(data2.center);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -605,13 +596,26 @@ namespace Nz
|
||||
{
|
||||
auto& billboards = GetLayer(renderOrder).billboards;
|
||||
|
||||
auto it = billboards.find(material);
|
||||
if (it == billboards.end())
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = billboards.find(materialPipeline);
|
||||
if (pipelineIt == billboards.end())
|
||||
{
|
||||
BatchedBillboardPipelineEntry pipelineEntry;
|
||||
pipelineIt = billboards.insert(BillboardPipelineBatches::value_type(materialPipeline, std::move(pipelineEntry))).first;
|
||||
}
|
||||
BatchedBillboardPipelineEntry& pipelineEntry = pipelineIt->second;
|
||||
pipelineEntry.enabled = true;
|
||||
|
||||
BatchedBillboardContainer& materialMap = pipelineEntry.materialMap;
|
||||
|
||||
auto it = materialMap.find(material);
|
||||
if (it == materialMap.end())
|
||||
{
|
||||
BatchedBillboardEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
|
||||
it = materialMap.insert(BatchedBillboardContainer::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedBillboardEntry& entry = it->second;
|
||||
@@ -654,16 +658,19 @@ namespace Nz
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& modelPair : layer.opaqueModels)
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
MeshInstanceContainer& meshes = modelPair.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.indexBuffer == indexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.indexBuffer == indexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -681,9 +688,14 @@ namespace Nz
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
layer.basicSprites.erase(material);
|
||||
layer.billboards.erase(material);
|
||||
layer.opaqueModels.erase(material);
|
||||
for (auto& pipelineEntry : layer.basicSprites)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
|
||||
for (auto& pipelineEntry : layer.billboards)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,10 +710,10 @@ namespace Nz
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
for (auto matIt = layer.basicSprites.begin(); matIt != layer.basicSprites.end(); ++matIt)
|
||||
for (auto& pipelineEntry : layer.basicSprites)
|
||||
{
|
||||
auto& overlayMap = matIt->second.overlayMap;
|
||||
overlayMap.erase(texture);
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
materialEntry.second.overlayMap.erase(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -717,41 +729,26 @@ namespace Nz
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
for (auto& modelPair : layer.opaqueModels)
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
MeshInstanceContainer& meshes = modelPair.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.vertexBuffer == vertexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.vertexBuffer == vertexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two batched billboard with material
|
||||
* \return true If first material is "smaller" than the second one
|
||||
*
|
||||
* \param mat1 First material to compare
|
||||
* \param mat2 Second material to compare
|
||||
*/
|
||||
|
||||
bool ForwardRenderQueue::BatchedBillboardComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
bool ForwardRenderQueue::MaterialComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
const UberShader* uberShader2 = mat2->GetShader();
|
||||
if (uberShader1 != uberShader2)
|
||||
return uberShader1 < uberShader2;
|
||||
|
||||
const Shader* shader1 = mat1->GetShaderInstance(ShaderFlags_Billboard | ShaderFlags_VertexColor)->GetShader();
|
||||
const Shader* shader2 = mat2->GetShaderInstance(ShaderFlags_Billboard | ShaderFlags_VertexColor)->GetShader();
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
@@ -760,60 +757,14 @@ namespace Nz
|
||||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two batched model with material
|
||||
* \return true If first material is "smaller" than the second one
|
||||
*
|
||||
* \param mat1 First material to compare
|
||||
* \param mat2 Second material to compare
|
||||
*/
|
||||
|
||||
bool ForwardRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
bool ForwardRenderQueue::MaterialPipelineComparator::operator()(const MaterialPipeline* pipeline1, const MaterialPipeline* pipeline2) const
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
const UberShader* uberShader2 = mat2->GetShader();
|
||||
if (uberShader1 != uberShader2)
|
||||
return uberShader1 < uberShader2;
|
||||
|
||||
const Shader* shader1 = mat1->GetShaderInstance()->GetShader();
|
||||
const Shader* shader2 = mat2->GetShaderInstance()->GetShader();
|
||||
const Shader* shader1 = pipeline1->GetInstance().renderPipeline.GetInfo().shader;
|
||||
const Shader* shader2 = pipeline2->GetInstance().renderPipeline.GetInfo().shader;
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
return diffuseMap1 < diffuseMap2;
|
||||
|
||||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two batched sprites with material
|
||||
* \return true If first material is "smaller" than the second one
|
||||
*
|
||||
* \param mat1 First material to compare
|
||||
* \param mat2 Second material to compare
|
||||
*/
|
||||
|
||||
bool ForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const Material* mat1, const Material* mat2)
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
const UberShader* uberShader2 = mat2->GetShader();
|
||||
if (uberShader1 != uberShader2)
|
||||
return uberShader1 < uberShader2;
|
||||
|
||||
const Shader* shader1 = mat1->GetShaderInstance()->GetShader();
|
||||
const Shader* shader2 = mat2->GetShaderInstance()->GetShader();
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
return diffuseMap1 < diffuseMap2;
|
||||
|
||||
return mat1 < mat2;
|
||||
return pipeline1 < pipeline2;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -53,6 +53,10 @@ namespace Nz
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
std::array<UInt8, 4> whitePixel = {255, 255, 255, 255};
|
||||
m_whiteTexture.Create(ImageType_2D, PixelFormatType_RGBA8, 1, 1);
|
||||
m_whiteTexture.Update(whitePixel.data());
|
||||
|
||||
m_vertexBuffer.Create(s_vertexBufferSize, DataStorage_Hardware, BufferUsage_Dynamic);
|
||||
|
||||
m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer);
|
||||
@@ -297,97 +301,102 @@ namespace Nz
|
||||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||
|
||||
for (auto& matIt : layer.basicSprites)
|
||||
for (auto& pipelinePair : layer.basicSprites)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt32 flags = ShaderFlags_VertexColor;
|
||||
if (overlay)
|
||||
flags |= ShaderFlags_TextureOverlay;
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
UInt8 overlayUnit;
|
||||
const Shader* shader = material->Apply(flags, 0, &overlayUnit);
|
||||
|
||||
if (overlay)
|
||||
{
|
||||
overlayUnit++;
|
||||
Renderer::SetTexture(overlayUnit, overlay);
|
||||
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
|
||||
}
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Overlay
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
unsigned int spriteChain = 0; // Which chain of sprites are we treating
|
||||
unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
// We open the buffer in writing mode
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
unsigned int spriteCount = 0;
|
||||
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||
|
||||
do
|
||||
{
|
||||
ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
|
||||
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
|
||||
|
||||
std::memcpy(vertices, currentChain.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
|
||||
vertices += count * 4;
|
||||
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChain.spriteCount)
|
||||
{
|
||||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
}
|
||||
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
}
|
||||
while (spriteChain < spriteChainCount);
|
||||
|
||||
spriteChainVector.clear();
|
||||
}
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
// We set it back to zero
|
||||
matEntry.enabled = false;
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
UInt8 overlayUnit;
|
||||
material->Apply(pipelineInstance, 0, &overlayUnit);
|
||||
overlayUnit++;
|
||||
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
|
||||
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
|
||||
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
{
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
Renderer::SetTexture(overlayUnit, (overlay) ? overlay : &m_whiteTexture);
|
||||
|
||||
unsigned int spriteChain = 0; // Which chain of sprites are we treating
|
||||
unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
// We open the buffer in writing mode
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
unsigned int spriteCount = 0;
|
||||
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||
|
||||
do
|
||||
{
|
||||
ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
|
||||
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
|
||||
|
||||
std::memcpy(vertices, currentChain.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
|
||||
vertices += count * 4;
|
||||
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChain.spriteCount)
|
||||
{
|
||||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
} while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
} while (spriteChain < spriteChainCount);
|
||||
|
||||
spriteChainVector.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// We set it back to zero
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
pipelineEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -415,17 +424,16 @@ namespace Nz
|
||||
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
for (auto& matIt : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
@@ -441,21 +449,35 @@ namespace Nz
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
do
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
|
||||
data += renderedBillboardCount;
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(renderedBillboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
do
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
|
||||
data += renderedBillboardCount;
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(renderedBillboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -464,17 +486,16 @@ namespace Nz
|
||||
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
|
||||
Renderer::SetVertexBuffer(&m_billboardPointBuffer);
|
||||
|
||||
for (auto& matIt : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
@@ -490,57 +511,65 @@ namespace Nz
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
|
||||
do
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4);
|
||||
BillboardPoint* vertices = static_cast<BillboardPoint*>(vertexMapper.GetPointer());
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
|
||||
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
do
|
||||
{
|
||||
const ForwardRenderQueue::BillboardData& billboard = *data++;
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 1.f);
|
||||
vertices++;
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4);
|
||||
BillboardPoint* vertices = static_cast<BillboardPoint*>(vertexMapper.GetPointer());
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 1.f);
|
||||
vertices++;
|
||||
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
|
||||
{
|
||||
const ForwardRenderQueue::BillboardData& billboard = *data++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 0.f);
|
||||
vertices++;
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 1.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 0.f);
|
||||
vertices++;
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 1.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 0.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 0.f);
|
||||
vertices++;
|
||||
}
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6);
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6);
|
||||
billboardVector.clear();
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -562,158 +591,98 @@ namespace Nz
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& matIt : layer.opaqueModels)
|
||||
for (auto& pipelinePair : layer.opaqueModels)
|
||||
{
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
bool instancing = (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply((instancing) ? ShaderFlags_Instancing : 0);
|
||||
|
||||
if (!meshInstances.empty())
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// We only use instancing when no light (other than directional) is active
|
||||
// This is because instancing is not compatible with the search of nearest lights
|
||||
// Deferred shading does not have this problem
|
||||
bool noPointSpotLight = m_renderQueue.pointLights.empty() && m_renderQueue.spotLights.empty();
|
||||
bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || noPointSpotLight) && matEntry.instancingEnabled;
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt8 freeTextureUnit;
|
||||
const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit);
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
UInt8 freeTextureUnit;
|
||||
material->Apply(pipelineInstance, 0, &freeTextureUnit);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
const Spheref& squaredBoundingSphere = meshEntry.squaredBoundingSphere;
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
|
||||
if (!instances.empty())
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
const Spheref& squaredBoundingSphere = meshEntry.squaredBoundingSphere;
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
|
||||
if (indexBuffer)
|
||||
if (!instances.empty())
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (instancing)
|
||||
{
|
||||
// We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
// With instancing, impossible to select the lights for each object
|
||||
// So, it's only activated for directional lights
|
||||
unsigned int lightCount = m_renderQueue.directionalLights.size();
|
||||
unsigned int lightIndex = 0;
|
||||
RendererComparison oldDepthFunc = Renderer::GetDepthFunc();
|
||||
|
||||
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
|
||||
for (unsigned int pass = 0; pass < passCount; ++pass)
|
||||
if (indexBuffer)
|
||||
{
|
||||
if (shaderUniforms->hasLightUniforms)
|
||||
{
|
||||
unsigned int renderedLightCount = std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
|
||||
lightCount -= renderedLightCount;
|
||||
|
||||
if (pass == 1)
|
||||
{
|
||||
// To add the result of light computations
|
||||
// We won't interfeer with materials parameters because we only render opaques objects
|
||||
// (A.K.A., without blending)
|
||||
// About the depth function, it must be applied only the first time
|
||||
Renderer::Enable(RendererParameter_Blend, true);
|
||||
Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One);
|
||||
Renderer::SetDepthFunc(RendererComparison_Equal);
|
||||
}
|
||||
|
||||
// Sends the uniforms
|
||||
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset * i, freeTextureUnit + i);
|
||||
|
||||
// And we give them to draw
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch
|
||||
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
// We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
|
||||
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// And we draw
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
// We don't forget to disable the blending to avoid to interfeer with the rest of the rendering
|
||||
Renderer::Enable(RendererParameter_Blend, false);
|
||||
Renderer::SetDepthFunc(oldDepthFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (shaderUniforms->hasLightUniforms)
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
if (instancing)
|
||||
{
|
||||
for (const Matrix4f& matrix : instances)
|
||||
// We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
// With instancing, impossible to select the lights for each object
|
||||
// So, it's only activated for directional lights
|
||||
unsigned int lightCount = m_renderQueue.directionalLights.size();
|
||||
unsigned int lightIndex = 0;
|
||||
RendererComparison oldDepthFunc = Renderer::GetDepthFunc();
|
||||
|
||||
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
|
||||
for (unsigned int pass = 0; pass < passCount; ++pass)
|
||||
{
|
||||
// Choose the lights depending on an object position and apparent radius
|
||||
ChooseLights(Spheref(matrix.GetTranslation() + squaredBoundingSphere.GetPosition(), squaredBoundingSphere.radius));
|
||||
|
||||
unsigned int lightCount = m_lights.size();
|
||||
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
unsigned int lightIndex = 0;
|
||||
RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); // In the case where we have to change it
|
||||
|
||||
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
|
||||
for (unsigned int pass = 0; pass < passCount; ++pass)
|
||||
if (shaderUniforms->hasLightUniforms)
|
||||
{
|
||||
lightCount -= std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
|
||||
unsigned int renderedLightCount = std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
|
||||
lightCount -= renderedLightCount;
|
||||
|
||||
if (pass == 1)
|
||||
{
|
||||
@@ -726,38 +695,98 @@ namespace Nz
|
||||
Renderer::SetDepthFunc(RendererComparison_Equal);
|
||||
}
|
||||
|
||||
// Sends the light uniforms to the shader
|
||||
// Sends the uniforms
|
||||
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i);
|
||||
|
||||
// And we draw
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset * i, freeTextureUnit + i);
|
||||
}
|
||||
|
||||
Renderer::Enable(RendererParameter_Blend, false);
|
||||
Renderer::SetDepthFunc(oldDepthFunc);
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch
|
||||
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
// We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
|
||||
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// And we draw
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't forget to disable the blending to avoid to interferering with the rest of the rendering
|
||||
Renderer::Enable(RendererParameter_Blend, false);
|
||||
Renderer::SetDepthFunc(oldDepthFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Without instancing, we must do a draw call for each instance
|
||||
// This may be faster than instancing under a certain number
|
||||
// Due to the time to modify the instancing buffer
|
||||
for (const Matrix4f& matrix : instances)
|
||||
if (shaderUniforms->hasLightUniforms)
|
||||
{
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
// Choose the lights depending on an object position and apparent radius
|
||||
ChooseLights(Spheref(matrix.GetTranslation() + squaredBoundingSphere.GetPosition(), squaredBoundingSphere.radius));
|
||||
|
||||
unsigned int lightCount = m_lights.size();
|
||||
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
unsigned int lightIndex = 0;
|
||||
RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); // In the case where we have to change it
|
||||
|
||||
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
|
||||
for (unsigned int pass = 0; pass < passCount; ++pass)
|
||||
{
|
||||
lightCount -= std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
|
||||
|
||||
if (pass == 1)
|
||||
{
|
||||
// To add the result of light computations
|
||||
// We won't interfeer with materials parameters because we only render opaques objects
|
||||
// (A.K.A., without blending)
|
||||
// About the depth function, it must be applied only the first time
|
||||
Renderer::Enable(RendererParameter_Blend, true);
|
||||
Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One);
|
||||
Renderer::SetDepthFunc(RendererComparison_Equal);
|
||||
}
|
||||
|
||||
// Sends the light uniforms to the shader
|
||||
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i);
|
||||
|
||||
// And we draw
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
|
||||
Renderer::Enable(RendererParameter_Blend, false);
|
||||
Renderer::SetDepthFunc(oldDepthFunc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Without instancing, we must do a draw call for each instance
|
||||
// This may be faster than instancing under a certain number
|
||||
// Due to the time to modify the instancing buffer
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
instances.clear();
|
||||
}
|
||||
instances.clear();
|
||||
}
|
||||
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// And we set the data back to zero
|
||||
matEntry.enabled = false;
|
||||
matEntry.instancingEnabled = false;
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -775,6 +804,8 @@ namespace Nz
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
unsigned int lightCount = 0;
|
||||
@@ -786,11 +817,19 @@ namespace Nz
|
||||
// Material
|
||||
const Material* material = modelData.material;
|
||||
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const MaterialPipeline* pipeline = material->GetPipeline();
|
||||
if (pipeline != lastPipeline)
|
||||
{
|
||||
pipelineInstance = &pipeline->Apply();
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
// We begin to apply the material
|
||||
UInt8 freeTextureUnit;
|
||||
const Shader* shader = material->Apply(0, 0, &freeTextureUnit);
|
||||
material->Apply(*pipelineInstance, 0, &freeTextureUnit);
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <Nazara/Graphics/SkinningManager.hpp>
|
||||
#include <Nazara/Graphics/SkyboxBackground.hpp>
|
||||
#include <Nazara/Graphics/Sprite.hpp>
|
||||
#include <Nazara/Graphics/TileMap.hpp>
|
||||
#include <Nazara/Graphics/Formats/MeshLoader.hpp>
|
||||
#include <Nazara/Graphics/Formats/TextureLoader.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
@@ -62,12 +63,20 @@ namespace Nz
|
||||
// Initialisation of the module
|
||||
CallOnExit onExit(Graphics::Uninitialize);
|
||||
|
||||
// Materials
|
||||
if (!MaterialPipeline::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize material pipelines");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Material::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize materials");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Renderables
|
||||
if (!ParticleController::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize particle controllers");
|
||||
@@ -110,11 +119,17 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TileMap::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize tilemaps");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generic loaders
|
||||
Loaders::RegisterMesh();
|
||||
Loaders::RegisterTexture();
|
||||
|
||||
// RenderTechniques
|
||||
// Render techniques
|
||||
if (!DepthRenderTechnique::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Depth Rendering");
|
||||
@@ -206,17 +221,24 @@ namespace Nz
|
||||
Loaders::UnregisterMesh();
|
||||
Loaders::UnregisterTexture();
|
||||
|
||||
DeferredRenderTechnique::Uninitialize();
|
||||
DepthRenderTechnique::Uninitialize();
|
||||
ForwardRenderTechnique::Uninitialize();
|
||||
SkinningManager::Uninitialize();
|
||||
// Renderables
|
||||
ParticleRenderer::Uninitialize();
|
||||
ParticleGenerator::Uninitialize();
|
||||
ParticleDeclaration::Uninitialize();
|
||||
ParticleController::Uninitialize();
|
||||
Material::Uninitialize();
|
||||
SkyboxBackground::Uninitialize();
|
||||
Sprite::Uninitialize();
|
||||
TileMap::Uninitialize();
|
||||
|
||||
// Render techniques
|
||||
DeferredRenderTechnique::Uninitialize();
|
||||
DepthRenderTechnique::Uninitialize();
|
||||
ForwardRenderTechnique::Uninitialize();
|
||||
SkinningManager::Uninitialize();
|
||||
|
||||
// Materials
|
||||
Material::Uninitialize();
|
||||
MaterialPipeline::Uninitialize();
|
||||
|
||||
NazaraNotice("Uninitialized: Graphics module");
|
||||
|
||||
|
||||
@@ -2,40 +2,15 @@
|
||||
// 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 // Mandatory to include the OpenGL headers
|
||||
#endif
|
||||
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/UberShaderPreprocessor.hpp>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const UInt8 r_basicFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_basicVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.vert.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h>
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::Material
|
||||
@@ -46,7 +21,6 @@ namespace Nz
|
||||
* \brief Checks whether the parameters for the material are correct
|
||||
* \return true If parameters are valid
|
||||
*/
|
||||
|
||||
bool MaterialParams::IsValid() const
|
||||
{
|
||||
if (!UberShaderLibrary::Has(shaderName))
|
||||
@@ -57,41 +31,35 @@ namespace Nz
|
||||
|
||||
/*!
|
||||
* \brief Applies shader to the material
|
||||
* \return Constant pointer to the shader
|
||||
*
|
||||
* \param shaderFlags Flags for the shader
|
||||
* \param instance Pipeline instance to update
|
||||
* \param textureUnit Unit for the texture GL_TEXTURE"i"
|
||||
* \param lastUsedUnit Optional argument to get the last texture unit
|
||||
*/
|
||||
|
||||
const Shader* Material::Apply(UInt32 shaderFlags, UInt8 textureUnit, UInt8* lastUsedUnit) const
|
||||
void Material::Apply(const MaterialPipeline::Instance& instance, UInt8 textureUnit, UInt8* lastUsedUnit) const
|
||||
{
|
||||
const ShaderInstance& instance = m_shaders[shaderFlags];
|
||||
if (!instance.uberInstance)
|
||||
GenerateShader(shaderFlags);
|
||||
|
||||
instance.uberInstance->Activate();
|
||||
const Shader* shader = instance.renderPipeline.GetInfo().shader;
|
||||
|
||||
if (instance.uniforms[MaterialUniform_AlphaThreshold] != -1)
|
||||
instance.shader->SendFloat(instance.uniforms[MaterialUniform_AlphaThreshold], m_alphaThreshold);
|
||||
shader->SendFloat(instance.uniforms[MaterialUniform_AlphaThreshold], m_alphaThreshold);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Ambient] != -1)
|
||||
instance.shader->SendColor(instance.uniforms[MaterialUniform_Ambient], m_ambientColor);
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Ambient], m_ambientColor);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Diffuse] != -1)
|
||||
instance.shader->SendColor(instance.uniforms[MaterialUniform_Diffuse], m_diffuseColor);
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Diffuse], m_diffuseColor);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Shininess] != -1)
|
||||
instance.shader->SendFloat(instance.uniforms[MaterialUniform_Shininess], m_shininess);
|
||||
shader->SendFloat(instance.uniforms[MaterialUniform_Shininess], m_shininess);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Specular] != -1)
|
||||
instance.shader->SendColor(instance.uniforms[MaterialUniform_Specular], m_specularColor);
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Specular], m_specularColor);
|
||||
|
||||
if (m_alphaMap && instance.uniforms[MaterialUniform_AlphaMap] != -1)
|
||||
{
|
||||
Renderer::SetTexture(textureUnit, m_alphaMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_AlphaMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_AlphaMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
@@ -99,7 +67,7 @@ namespace Nz
|
||||
{
|
||||
Renderer::SetTexture(textureUnit, m_diffuseMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_DiffuseMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_DiffuseMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
@@ -107,7 +75,7 @@ namespace Nz
|
||||
{
|
||||
Renderer::SetTexture(textureUnit, m_emissiveMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_EmissiveMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_EmissiveMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
@@ -115,7 +83,7 @@ namespace Nz
|
||||
{
|
||||
Renderer::SetTexture(textureUnit, m_heightMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_HeightMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_HeightMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
@@ -123,7 +91,7 @@ namespace Nz
|
||||
{
|
||||
Renderer::SetTexture(textureUnit, m_normalMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_NormalMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_NormalMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
@@ -131,25 +99,20 @@ namespace Nz
|
||||
{
|
||||
Renderer::SetTexture(textureUnit, m_specularMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_specularSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_SpecularMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_SpecularMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
Renderer::SetRenderStates(m_states);
|
||||
|
||||
if (lastUsedUnit)
|
||||
*lastUsedUnit = textureUnit;
|
||||
|
||||
return instance.shader;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Builds the material from parameters
|
||||
* \brief Builds the material from a parameter list
|
||||
*
|
||||
* \param matData Data information for the material
|
||||
* \param matParams Parameters for the material
|
||||
* \param matParams Additional parameters for the material
|
||||
*/
|
||||
|
||||
void Material::BuildFromParameters(const ParameterList& matData, const MaterialParams& matParams)
|
||||
{
|
||||
Color color;
|
||||
@@ -160,7 +123,6 @@ namespace Nz
|
||||
|
||||
ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled, true);
|
||||
|
||||
|
||||
if (matData.GetFloatParameter(MaterialData::AlphaThreshold, &fValue))
|
||||
SetAlphaThreshold(fValue);
|
||||
|
||||
@@ -188,14 +150,11 @@ namespace Nz
|
||||
if (matData.GetIntegerParameter(MaterialData::FaceFilling, &iValue))
|
||||
SetFaceFilling(static_cast<FaceFilling>(iValue));
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::Lighting, &isEnabled))
|
||||
EnableLighting(isEnabled);
|
||||
|
||||
if (matData.GetFloatParameter(MaterialData::LineWidth, &fValue))
|
||||
m_states.lineWidth = fValue;
|
||||
SetLineWidth(fValue);
|
||||
|
||||
if (matData.GetFloatParameter(MaterialData::PointSize, &fValue))
|
||||
m_states.pointSize = fValue;
|
||||
SetPointSize(fValue);
|
||||
|
||||
if (matData.GetColorParameter(MaterialData::SpecularColor, &color))
|
||||
SetSpecularColor(color);
|
||||
@@ -206,30 +165,27 @@ namespace Nz
|
||||
if (matData.GetIntegerParameter(MaterialData::SrcBlend, &iValue))
|
||||
SetSrcBlend(static_cast<BlendFunc>(iValue));
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::Transform, &isEnabled))
|
||||
EnableTransform(isEnabled);
|
||||
|
||||
// RendererParameter
|
||||
if (matData.GetBooleanParameter(MaterialData::Blending, &isEnabled))
|
||||
Enable(RendererParameter_Blend, isEnabled);
|
||||
EnableBlending(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::ColorWrite, &isEnabled))
|
||||
Enable(RendererParameter_ColorWrite, isEnabled);
|
||||
EnableColorWrite(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::DepthBuffer, &isEnabled))
|
||||
Enable(RendererParameter_DepthBuffer, isEnabled);
|
||||
EnableDepthBuffer(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::DepthWrite, &isEnabled))
|
||||
Enable(RendererParameter_DepthWrite, isEnabled);
|
||||
EnableDepthWrite(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::FaceCulling, &isEnabled))
|
||||
Enable(RendererParameter_FaceCulling, isEnabled);
|
||||
EnableFaceCulling(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::ScissorTest, &isEnabled))
|
||||
Enable(RendererParameter_ScissorTest, isEnabled);
|
||||
EnableScissorTest(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::StencilTest, &isEnabled))
|
||||
Enable(RendererParameter_StencilTest, isEnabled);
|
||||
EnableStencilTest(isEnabled);
|
||||
|
||||
// Samplers
|
||||
if (matData.GetIntegerParameter(MaterialData::DiffuseAnisotropyLevel, &iValue))
|
||||
@@ -252,41 +208,43 @@ namespace Nz
|
||||
|
||||
// Stencil
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilCompare, &iValue))
|
||||
m_states.frontFace.stencilCompare = static_cast<RendererComparison>(iValue);
|
||||
m_pipelineInfo.stencilCompare.front = static_cast<RendererComparison>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilFail, &iValue))
|
||||
m_states.frontFace.stencilFail = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilFail.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilPass, &iValue))
|
||||
m_states.frontFace.stencilPass = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilPass.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilZFail, &iValue))
|
||||
m_states.frontFace.stencilZFail = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilDepthFail.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilMask, &iValue))
|
||||
m_states.frontFace.stencilMask = static_cast<UInt32>(iValue);
|
||||
m_pipelineInfo.stencilWriteMask.front = static_cast<UInt32>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilReference, &iValue))
|
||||
m_states.frontFace.stencilReference = static_cast<unsigned int>(iValue);
|
||||
m_pipelineInfo.stencilReference.front = static_cast<unsigned int>(iValue);
|
||||
|
||||
// Stencil (back)
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilCompare, &iValue))
|
||||
m_states.backFace.stencilCompare = static_cast<RendererComparison>(iValue);
|
||||
m_pipelineInfo.stencilCompare.back = static_cast<RendererComparison>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilFail, &iValue))
|
||||
m_states.backFace.stencilFail = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilFail.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilPass, &iValue))
|
||||
m_states.backFace.stencilPass = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilPass.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilZFail, &iValue))
|
||||
m_states.backFace.stencilZFail = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilDepthFail.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilMask, &iValue))
|
||||
m_states.backFace.stencilMask = static_cast<UInt32>(iValue);
|
||||
m_pipelineInfo.stencilWriteMask.back = static_cast<UInt32>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilReference, &iValue))
|
||||
m_states.backFace.stencilReference = static_cast<unsigned int>(iValue);
|
||||
m_pipelineInfo.stencilReference.back = static_cast<unsigned int>(iValue);
|
||||
|
||||
InvalidatePipeline();
|
||||
|
||||
// Textures
|
||||
if (matParams.loadAlphaMap && matData.GetStringParameter(MaterialData::AlphaTexturePath, &path))
|
||||
@@ -310,6 +268,11 @@ namespace Nz
|
||||
SetShader(matParams.shaderName);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Builds a ParameterList with material data
|
||||
*
|
||||
* \param matData Destination parameter list which will receive material data
|
||||
*/
|
||||
void Material::SaveToParameters(ParameterList* matData)
|
||||
{
|
||||
NazaraAssert(matData, "Invalid ParameterList");
|
||||
@@ -323,22 +286,20 @@ namespace Nz
|
||||
matData->SetParameter(MaterialData::DiffuseColor, GetDiffuseColor());
|
||||
matData->SetParameter(MaterialData::DstBlend, int(GetDstBlend()));
|
||||
matData->SetParameter(MaterialData::FaceFilling, int(GetFaceFilling()));
|
||||
matData->SetParameter(MaterialData::Lighting, IsLightingEnabled());
|
||||
matData->SetParameter(MaterialData::LineWidth, GetRenderStates().lineWidth);
|
||||
matData->SetParameter(MaterialData::PointSize, GetRenderStates().pointSize);
|
||||
matData->SetParameter(MaterialData::LineWidth, GetLineWidth());
|
||||
matData->SetParameter(MaterialData::PointSize, GetPointSize());
|
||||
matData->SetParameter(MaterialData::Shininess, GetShininess());
|
||||
matData->SetParameter(MaterialData::SpecularColor, GetSpecularColor());
|
||||
matData->SetParameter(MaterialData::SrcBlend, int(GetSrcBlend()));
|
||||
matData->SetParameter(MaterialData::Transform, IsTransformEnabled());
|
||||
|
||||
// RendererParameter
|
||||
matData->SetParameter(MaterialData::Blending, GetRenderStates().parameters[RendererParameter_Blend]);
|
||||
matData->SetParameter(MaterialData::ColorWrite, GetRenderStates().parameters[RendererParameter_ColorWrite]);
|
||||
matData->SetParameter(MaterialData::DepthBuffer, GetRenderStates().parameters[RendererParameter_DepthBuffer]);
|
||||
matData->SetParameter(MaterialData::DepthWrite, GetRenderStates().parameters[RendererParameter_DepthWrite]);
|
||||
matData->SetParameter(MaterialData::FaceCulling, GetRenderStates().parameters[RendererParameter_FaceCulling]);
|
||||
matData->SetParameter(MaterialData::ScissorTest, GetRenderStates().parameters[RendererParameter_ScissorTest]);
|
||||
matData->SetParameter(MaterialData::StencilTest, GetRenderStates().parameters[RendererParameter_StencilTest]);
|
||||
matData->SetParameter(MaterialData::Blending, IsBlendingEnabled());
|
||||
matData->SetParameter(MaterialData::ColorWrite, IsColorWriteEnabled());
|
||||
matData->SetParameter(MaterialData::DepthBuffer, IsDepthBufferEnabled());
|
||||
matData->SetParameter(MaterialData::DepthWrite, IsDepthWriteEnabled());
|
||||
matData->SetParameter(MaterialData::FaceCulling, IsFaceCullingEnabled());
|
||||
matData->SetParameter(MaterialData::ScissorTest, IsScissorTestEnabled());
|
||||
matData->SetParameter(MaterialData::StencilTest, IsStencilTestEnabled());
|
||||
|
||||
// Samplers
|
||||
matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, int(GetDiffuseSampler().GetAnisotropicLevel()));
|
||||
@@ -350,20 +311,20 @@ namespace Nz
|
||||
matData->SetParameter(MaterialData::SpecularWrap, int(GetSpecularSampler().GetWrapMode()));
|
||||
|
||||
// Stencil
|
||||
matData->SetParameter(MaterialData::StencilCompare, int(GetRenderStates().frontFace.stencilCompare));
|
||||
matData->SetParameter(MaterialData::StencilFail, int(GetRenderStates().frontFace.stencilFail));
|
||||
matData->SetParameter(MaterialData::StencilPass, int(GetRenderStates().frontFace.stencilPass));
|
||||
matData->SetParameter(MaterialData::StencilZFail, int(GetRenderStates().frontFace.stencilZFail));
|
||||
matData->SetParameter(MaterialData::StencilMask, int(GetRenderStates().frontFace.stencilMask));
|
||||
matData->SetParameter(MaterialData::StencilReference, int(GetRenderStates().frontFace.stencilReference));
|
||||
matData->SetParameter(MaterialData::StencilCompare, int(GetPipelineInfo().stencilCompare.front));
|
||||
matData->SetParameter(MaterialData::StencilFail, int(GetPipelineInfo().stencilFail.front));
|
||||
matData->SetParameter(MaterialData::StencilPass, int(GetPipelineInfo().stencilPass.front));
|
||||
matData->SetParameter(MaterialData::StencilZFail, int(GetPipelineInfo().stencilDepthFail.front));
|
||||
matData->SetParameter(MaterialData::StencilMask, int(GetPipelineInfo().stencilWriteMask.front));
|
||||
matData->SetParameter(MaterialData::StencilReference, int(GetPipelineInfo().stencilReference.front));
|
||||
|
||||
// Stencil (back)
|
||||
matData->SetParameter(MaterialData::BackFaceStencilCompare, int(GetRenderStates().backFace.stencilCompare));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilFail, int(GetRenderStates().backFace.stencilFail));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilPass, int(GetRenderStates().backFace.stencilPass));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilZFail, int(GetRenderStates().backFace.stencilZFail));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilMask, int(GetRenderStates().backFace.stencilMask));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilReference, int(GetRenderStates().backFace.stencilReference));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilCompare, int(GetPipelineInfo().stencilCompare.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilFail, int(GetPipelineInfo().stencilFail.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilPass, int(GetPipelineInfo().stencilPass.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilZFail, int(GetPipelineInfo().stencilDepthFail.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilMask, int(GetPipelineInfo().stencilWriteMask.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilReference, int(GetPipelineInfo().stencilReference.back));
|
||||
|
||||
// Textures
|
||||
if (HasAlphaMap())
|
||||
@@ -411,6 +372,8 @@ namespace Nz
|
||||
|
||||
/*!
|
||||
* \brief Resets the material, cleans everything
|
||||
*
|
||||
* \remark Invalidates the pipeline
|
||||
*/
|
||||
void Material::Reset()
|
||||
{
|
||||
@@ -423,29 +386,22 @@ namespace Nz
|
||||
m_heightMap.Reset();
|
||||
m_normalMap.Reset();
|
||||
m_specularMap.Reset();
|
||||
m_uberShader.Reset();
|
||||
|
||||
for (ShaderInstance& instance : m_shaders)
|
||||
instance.uberInstance = nullptr;
|
||||
|
||||
m_alphaThreshold = 0.2f;
|
||||
m_alphaTestEnabled = false;
|
||||
m_ambientColor = Color(128, 128, 128);
|
||||
m_depthSortingEnabled = false;
|
||||
m_diffuseColor = Color::White;
|
||||
m_diffuseSampler = TextureSampler();
|
||||
m_lightingEnabled = true;
|
||||
m_shadowCastingEnabled = true;
|
||||
m_shadowReceiveEnabled = true;
|
||||
m_shininess = 50.f;
|
||||
m_specularColor = Color::White;
|
||||
m_specularSampler = TextureSampler();
|
||||
m_states = RenderStates();
|
||||
m_states.parameters[RendererParameter_DepthBuffer] = true;
|
||||
m_states.parameters[RendererParameter_FaceCulling] = true;
|
||||
m_transformEnabled = true;
|
||||
m_pipelineInfo = MaterialPipelineInfo();
|
||||
m_pipelineInfo.depthBuffer = true;
|
||||
m_pipelineInfo.faceCulling = true;
|
||||
|
||||
SetShader("Basic");
|
||||
|
||||
InvalidatePipeline();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -453,24 +409,18 @@ namespace Nz
|
||||
*
|
||||
* \param material Material to copy into this
|
||||
*/
|
||||
|
||||
void Material::Copy(const Material& material)
|
||||
{
|
||||
// Copy of base states
|
||||
m_alphaTestEnabled = material.m_alphaTestEnabled;
|
||||
m_alphaThreshold = material.m_alphaThreshold;
|
||||
m_ambientColor = material.m_ambientColor;
|
||||
m_depthSortingEnabled = material.m_depthSortingEnabled;
|
||||
m_diffuseColor = material.m_diffuseColor;
|
||||
m_diffuseSampler = material.m_diffuseSampler;
|
||||
m_lightingEnabled = material.m_lightingEnabled;
|
||||
m_pipelineInfo = material.m_pipelineInfo;
|
||||
m_shininess = material.m_shininess;
|
||||
m_shadowCastingEnabled = material.m_shadowCastingEnabled;
|
||||
m_shadowReceiveEnabled = material.m_shadowReceiveEnabled;
|
||||
m_specularColor = material.m_specularColor;
|
||||
m_specularSampler = material.m_specularSampler;
|
||||
m_states = material.m_states;
|
||||
m_transformEnabled = material.m_transformEnabled;
|
||||
|
||||
// Copy of reference to the textures
|
||||
m_alphaMap = material.m_alphaMap;
|
||||
@@ -480,61 +430,8 @@ namespace Nz
|
||||
m_heightMap = material.m_heightMap;
|
||||
m_normalMap = material.m_normalMap;
|
||||
m_specularMap = material.m_specularMap;
|
||||
m_uberShader = material.m_uberShader;
|
||||
|
||||
// We copy the instances of the shader too
|
||||
std::memcpy(&m_shaders[0], &material.m_shaders[0], (ShaderFlags_Max + 1) * sizeof(ShaderInstance));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Generates the shader based on flag
|
||||
*
|
||||
* \param flags Flag for the shaer
|
||||
*/
|
||||
|
||||
void Material::GenerateShader(UInt32 flags) const
|
||||
{
|
||||
ParameterList list;
|
||||
list.SetParameter("ALPHA_MAPPING", m_alphaMap.IsValid());
|
||||
list.SetParameter("ALPHA_TEST", m_alphaTestEnabled);
|
||||
list.SetParameter("COMPUTE_TBNMATRIX", m_normalMap.IsValid() || m_heightMap.IsValid());
|
||||
list.SetParameter("DIFFUSE_MAPPING", m_diffuseMap.IsValid());
|
||||
list.SetParameter("EMISSIVE_MAPPING", m_emissiveMap.IsValid());
|
||||
list.SetParameter("LIGHTING", m_lightingEnabled);
|
||||
list.SetParameter("NORMAL_MAPPING", m_normalMap.IsValid());
|
||||
list.SetParameter("PARALLAX_MAPPING", m_heightMap.IsValid());
|
||||
list.SetParameter("SHADOW_MAPPING", m_shadowReceiveEnabled);
|
||||
list.SetParameter("SPECULAR_MAPPING", m_specularMap.IsValid());
|
||||
list.SetParameter("TEXTURE_MAPPING", m_alphaMap.IsValid() || m_diffuseMap.IsValid() || m_emissiveMap.IsValid() ||
|
||||
m_normalMap.IsValid() || m_heightMap.IsValid() || m_specularMap.IsValid() ||
|
||||
flags & ShaderFlags_TextureOverlay);
|
||||
list.SetParameter("TRANSFORM", m_transformEnabled);
|
||||
|
||||
list.SetParameter("FLAG_BILLBOARD", static_cast<bool>((flags & ShaderFlags_Billboard) != 0));
|
||||
list.SetParameter("FLAG_DEFERRED", static_cast<bool>((flags & ShaderFlags_Deferred) != 0));
|
||||
list.SetParameter("FLAG_INSTANCING", static_cast<bool>((flags & ShaderFlags_Instancing) != 0));
|
||||
list.SetParameter("FLAG_TEXTUREOVERLAY", static_cast<bool>((flags & ShaderFlags_TextureOverlay) != 0));
|
||||
list.SetParameter("FLAG_VERTEXCOLOR", static_cast<bool>((flags & ShaderFlags_VertexColor) != 0));
|
||||
|
||||
ShaderInstance& instance = m_shaders[flags];
|
||||
instance.uberInstance = m_uberShader->Get(list);
|
||||
instance.shader = instance.uberInstance->GetShader();
|
||||
|
||||
#define CacheUniform(name) instance.uniforms[MaterialUniform_##name] = instance.shader->GetUniformLocation("Material" #name)
|
||||
|
||||
CacheUniform(AlphaMap);
|
||||
CacheUniform(AlphaThreshold);
|
||||
CacheUniform(Ambient);
|
||||
CacheUniform(Diffuse);
|
||||
CacheUniform(DiffuseMap);
|
||||
CacheUniform(EmissiveMap);
|
||||
CacheUniform(HeightMap);
|
||||
CacheUniform(NormalMap);
|
||||
CacheUniform(Shininess);
|
||||
CacheUniform(Specular);
|
||||
CacheUniform(SpecularMap);
|
||||
|
||||
#undef CacheUniform
|
||||
InvalidatePipeline();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -543,7 +440,6 @@ namespace Nz
|
||||
*
|
||||
* \remark Produces a NazaraError if the material library failed to be initialized
|
||||
*/
|
||||
|
||||
bool Material::Initialize()
|
||||
{
|
||||
if (!MaterialLibrary::Initialize())
|
||||
@@ -558,67 +454,21 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
// Basic shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_basicFragmentShader), sizeof(r_basicFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_basicVertexShader), sizeof(r_basicVertexShader));
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_INSTANCING FLAG_VERTEXCOLOR TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("Basic", uberShader);
|
||||
}
|
||||
|
||||
// PhongLighting shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_phongLightingFragmentShader), sizeof(r_phongLightingFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_phongLightingVertexShader), sizeof(r_phongLightingVertexShader));
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING EMISSIVE_MAPPING LIGHTING NORMAL_MAPPING PARALLAX_MAPPING SHADOW_MAPPING SPECULAR_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_DEFERRED FLAG_INSTANCING FLAG_VERTEXCOLOR COMPUTE_TBNMATRIX LIGHTING PARALLAX_MAPPING SHADOW_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("PhongLighting", uberShader);
|
||||
}
|
||||
|
||||
// Once the base shaders are registered, we can now set some default materials
|
||||
s_defaultMaterial = New();
|
||||
s_defaultMaterial->Enable(RendererParameter_FaceCulling, false);
|
||||
s_defaultMaterial->EnableFaceCulling(false);
|
||||
s_defaultMaterial->SetFaceFilling(FaceFilling_Line);
|
||||
MaterialLibrary::Register("Default", s_defaultMaterial);
|
||||
|
||||
MaterialRef mat;
|
||||
|
||||
mat = New();
|
||||
mat->Enable(RendererParameter_DepthWrite, false);
|
||||
mat->Enable(RendererParameter_FaceCulling, false);
|
||||
mat->EnableLighting(false);
|
||||
MaterialLibrary::Register("Basic2D", std::move(mat));
|
||||
|
||||
mat = New();
|
||||
mat->Enable(RendererParameter_Blend, true);
|
||||
mat->Enable(RendererParameter_DepthWrite, false);
|
||||
mat->Enable(RendererParameter_FaceCulling, false);
|
||||
mat->EnableLighting(false);
|
||||
mat->SetDstBlend(BlendFunc_InvSrcAlpha);
|
||||
mat->SetSrcBlend(BlendFunc_SrcAlpha);
|
||||
MaterialLibrary::Register("Translucent2D", std::move(mat));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the material librairies
|
||||
*/
|
||||
|
||||
void Material::Uninitialize()
|
||||
{
|
||||
s_defaultMaterial.Reset();
|
||||
UberShaderLibrary::Unregister("PhongLighting");
|
||||
UberShaderLibrary::Unregister("Basic");
|
||||
|
||||
MaterialManager::Uninitialize();
|
||||
MaterialLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
168
src/Nazara/Graphics/MaterialPipeline.cpp
Normal file
168
src/Nazara/Graphics/MaterialPipeline.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
// Copyright (C) 2016 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/MaterialPipeline.hpp>
|
||||
|
||||
#ifndef NAZARA_RENDERER_OPENGL
|
||||
#define NAZARA_RENDERER_OPENGL // Mandatory to include the OpenGL headers
|
||||
#endif
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/UberShaderPreprocessor.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const UInt8 r_basicFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_basicVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.vert.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h>
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::MaterialPipeline
|
||||
*
|
||||
* \brief Graphics class used to contains all rendering states that are not allowed to change individually on rendering devices
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to a MaterialPipeline built with MaterialPipelineInfo
|
||||
*
|
||||
* This function is using a cache, calling it multiples times with the same MaterialPipelineInfo will returns references to a single MaterialPipeline
|
||||
*
|
||||
* \param pipelineInfo Pipeline informations used to build/retrieve a MaterialPipeline object
|
||||
*/
|
||||
MaterialPipelineRef MaterialPipeline::GetPipeline(const MaterialPipelineInfo& pipelineInfo)
|
||||
{
|
||||
auto it = s_pipelineCache.lower_bound(pipelineInfo);
|
||||
if (it == s_pipelineCache.end() || it->first != pipelineInfo)
|
||||
it = s_pipelineCache.insert(it, PipelineCache::value_type(pipelineInfo, New(pipelineInfo)));
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void MaterialPipeline::GenerateRenderPipeline(UInt32 flags) const
|
||||
{
|
||||
ParameterList list;
|
||||
list.SetParameter("ALPHA_MAPPING", m_pipelineInfo.hasAlphaMap);
|
||||
list.SetParameter("ALPHA_TEST", m_pipelineInfo.alphaTest);
|
||||
list.SetParameter("COMPUTE_TBNMATRIX", m_pipelineInfo.hasNormalMap || m_pipelineInfo.hasHeightMap);
|
||||
list.SetParameter("DIFFUSE_MAPPING", m_pipelineInfo.hasDiffuseMap);
|
||||
list.SetParameter("EMISSIVE_MAPPING", m_pipelineInfo.hasEmissiveMap);
|
||||
list.SetParameter("NORMAL_MAPPING", m_pipelineInfo.hasNormalMap);
|
||||
list.SetParameter("PARALLAX_MAPPING", m_pipelineInfo.hasHeightMap);
|
||||
list.SetParameter("SHADOW_MAPPING", m_pipelineInfo.shadowReceive);
|
||||
list.SetParameter("SPECULAR_MAPPING", m_pipelineInfo.hasSpecularMap);
|
||||
list.SetParameter("TEXTURE_MAPPING", m_pipelineInfo.hasAlphaMap || m_pipelineInfo.hasDiffuseMap || m_pipelineInfo.hasEmissiveMap ||
|
||||
m_pipelineInfo.hasNormalMap || m_pipelineInfo.hasHeightMap || m_pipelineInfo.hasSpecularMap ||
|
||||
flags & ShaderFlags_TextureOverlay);
|
||||
list.SetParameter("TRANSFORM", true);
|
||||
|
||||
list.SetParameter("FLAG_BILLBOARD", static_cast<bool>((flags & ShaderFlags_Billboard) != 0));
|
||||
list.SetParameter("FLAG_DEFERRED", static_cast<bool>((flags & ShaderFlags_Deferred) != 0));
|
||||
list.SetParameter("FLAG_INSTANCING", static_cast<bool>((flags & ShaderFlags_Instancing) != 0));
|
||||
list.SetParameter("FLAG_TEXTUREOVERLAY", static_cast<bool>((flags & ShaderFlags_TextureOverlay) != 0));
|
||||
list.SetParameter("FLAG_VERTEXCOLOR", static_cast<bool>((flags & ShaderFlags_VertexColor) != 0));
|
||||
|
||||
Instance& instance = m_instances[flags];
|
||||
instance.uberInstance = m_pipelineInfo.uberShader->Get(list);
|
||||
|
||||
RenderPipelineInfo renderPipelineInfo;
|
||||
static_cast<RenderStates&>(renderPipelineInfo).operator=(m_pipelineInfo); // Not my proudest line
|
||||
|
||||
renderPipelineInfo.shader = instance.uberInstance->GetShader();
|
||||
|
||||
instance.renderPipeline.Create(renderPipelineInfo);
|
||||
|
||||
#define CacheUniform(name) instance.uniforms[MaterialUniform_##name] = renderPipelineInfo.shader->GetUniformLocation("Material" #name)
|
||||
|
||||
CacheUniform(AlphaMap);
|
||||
CacheUniform(AlphaThreshold);
|
||||
CacheUniform(Ambient);
|
||||
CacheUniform(Diffuse);
|
||||
CacheUniform(DiffuseMap);
|
||||
CacheUniform(EmissiveMap);
|
||||
CacheUniform(HeightMap);
|
||||
CacheUniform(NormalMap);
|
||||
CacheUniform(Shininess);
|
||||
CacheUniform(Specular);
|
||||
CacheUniform(SpecularMap);
|
||||
|
||||
#undef CacheUniform
|
||||
}
|
||||
|
||||
bool MaterialPipeline::Initialize()
|
||||
{
|
||||
// Basic shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_basicFragmentShader), sizeof(r_basicFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_basicVertexShader), sizeof(r_basicVertexShader));
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_INSTANCING FLAG_VERTEXCOLOR TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("Basic", uberShader);
|
||||
}
|
||||
|
||||
// PhongLighting shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_phongLightingFragmentShader), sizeof(r_phongLightingFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_phongLightingVertexShader), sizeof(r_phongLightingVertexShader));
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING EMISSIVE_MAPPING NORMAL_MAPPING PARALLAX_MAPPING SHADOW_MAPPING SPECULAR_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_DEFERRED FLAG_INSTANCING FLAG_VERTEXCOLOR COMPUTE_TBNMATRIX PARALLAX_MAPPING SHADOW_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("PhongLighting", uberShader);
|
||||
}
|
||||
|
||||
// Once the base shaders are registered, we can now set some default materials
|
||||
MaterialPipelineInfo pipelineInfo;
|
||||
|
||||
// Basic 2D - No depth write/face culling
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
|
||||
MaterialPipelineLibrary::Register("Basic2D", GetPipeline(pipelineInfo));
|
||||
|
||||
// Translucent 2D - Alpha blending with no depth write/face culling
|
||||
pipelineInfo.blending = false;
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||
|
||||
MaterialPipelineLibrary::Register("Translucent2D", GetPipeline(pipelineInfo));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MaterialPipeline::Uninitialize()
|
||||
{
|
||||
s_pipelineCache.clear();
|
||||
UberShaderLibrary::Unregister("PhongLighting");
|
||||
UberShaderLibrary::Unregister("Basic");
|
||||
MaterialPipelineLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
MaterialPipelineLibrary::LibraryMap MaterialPipeline::s_library;
|
||||
MaterialPipeline::PipelineCache MaterialPipeline::s_pipelineCache;
|
||||
}
|
||||
@@ -38,9 +38,9 @@ namespace Nz
|
||||
|
||||
ParticleDeclaration::ParticleDeclaration(const ParticleDeclaration& declaration) :
|
||||
RefCounted(),
|
||||
m_components(declaration.m_components),
|
||||
m_stride(declaration.m_stride)
|
||||
{
|
||||
std::memcpy(m_components, declaration.m_components, sizeof(Component) * (ParticleComponent_Max + 1));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -205,7 +205,7 @@ namespace Nz
|
||||
|
||||
ParticleDeclaration& ParticleDeclaration::operator=(const ParticleDeclaration& declaration)
|
||||
{
|
||||
std::memcpy(m_components, declaration.m_components, sizeof(Component) * (ParticleComponent_Max + 1));
|
||||
m_components = declaration.m_components;
|
||||
m_stride = declaration.m_stride;
|
||||
|
||||
return *this;
|
||||
@@ -222,13 +222,7 @@ namespace Nz
|
||||
|
||||
ParticleDeclaration* ParticleDeclaration::Get(ParticleLayout layout)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (layout > ParticleLayout_Max)
|
||||
{
|
||||
NazaraError("Particle layout out of enum");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(layout <= ParticleLayout_Max, "Particle layout out of enum");
|
||||
|
||||
return &s_declarations[layout];
|
||||
}
|
||||
@@ -314,9 +308,9 @@ namespace Nz
|
||||
declaration = &s_declarations[ParticleLayout_Sprite];
|
||||
declaration->EnableComponent(ParticleComponent_Color, ComponentType_Color, NazaraOffsetOf(ParticleStruct_Sprite, color));
|
||||
declaration->EnableComponent(ParticleComponent_Life, ComponentType_Int1, NazaraOffsetOf(ParticleStruct_Sprite, life));
|
||||
declaration->EnableComponent(ParticleComponent_Position, ComponentType_Float2, NazaraOffsetOf(ParticleStruct_Sprite, position));
|
||||
declaration->EnableComponent(ParticleComponent_Position, ComponentType_Float3, NazaraOffsetOf(ParticleStruct_Sprite, position));
|
||||
declaration->EnableComponent(ParticleComponent_Rotation, ComponentType_Float1, NazaraOffsetOf(ParticleStruct_Sprite, rotation));
|
||||
declaration->EnableComponent(ParticleComponent_Velocity, ComponentType_Float2, NazaraOffsetOf(ParticleStruct_Sprite, velocity));
|
||||
declaration->EnableComponent(ParticleComponent_Velocity, ComponentType_Float3, NazaraOffsetOf(ParticleStruct_Sprite, velocity));
|
||||
|
||||
NazaraAssert(declaration->GetStride() == sizeof(ParticleStruct_Sprite), "Invalid stride for declaration ParticleLayout_Sprite");
|
||||
}
|
||||
@@ -338,6 +332,6 @@ namespace Nz
|
||||
ParticleDeclarationLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
ParticleDeclaration ParticleDeclaration::s_declarations[ParticleLayout_Max + 1];
|
||||
std::array<ParticleDeclaration, ParticleLayout_Max + 1> ParticleDeclaration::s_declarations;
|
||||
ParticleDeclarationLibrary::LibraryMap ParticleDeclaration::s_library;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <Nazara/Graphics/ParticleMapper.hpp>
|
||||
#include <Nazara/Graphics/ParticleSystem.hpp>
|
||||
#include <Nazara/Graphics/ParticleGroup.hpp>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
@@ -32,7 +32,27 @@ namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
ParticleEmitter::~ParticleEmitter() = default;
|
||||
ParticleEmitter::ParticleEmitter(const ParticleEmitter& emitter) :
|
||||
m_lagCompensationEnabled(emitter.m_lagCompensationEnabled),
|
||||
m_emissionAccumulator(0.f),
|
||||
m_emissionRate(emitter.m_emissionRate),
|
||||
m_emissionCount(emitter.m_emissionCount)
|
||||
{
|
||||
}
|
||||
|
||||
ParticleEmitter::ParticleEmitter(ParticleEmitter&& emitter) :
|
||||
m_lagCompensationEnabled(emitter.m_lagCompensationEnabled),
|
||||
m_emissionAccumulator(0.f),
|
||||
m_emissionRate(emitter.m_emissionRate),
|
||||
m_emissionCount(emitter.m_emissionCount)
|
||||
{
|
||||
OnParticleEmitterMove(&emitter, this);
|
||||
}
|
||||
|
||||
ParticleEmitter::~ParticleEmitter()
|
||||
{
|
||||
OnParticleEmitterRelease(this);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Emits particles according to the delta time between the previous frame
|
||||
@@ -41,7 +61,7 @@ namespace Nz
|
||||
* \param elapsedTime Delta time between the previous frame
|
||||
*/
|
||||
|
||||
void ParticleEmitter::Emit(ParticleSystem& system, float elapsedTime) const
|
||||
void ParticleEmitter::Emit(ParticleGroup& system, float elapsedTime) const
|
||||
{
|
||||
if (m_emissionRate > 0.f)
|
||||
{
|
||||
@@ -141,4 +161,14 @@ namespace Nz
|
||||
{
|
||||
m_emissionRate = rate;
|
||||
}
|
||||
|
||||
ParticleEmitter& ParticleEmitter::operator=(ParticleEmitter && emitter)
|
||||
{
|
||||
m_emissionCount = emitter.m_emissionCount;
|
||||
m_emissionRate = emitter.m_emissionRate;
|
||||
m_lagCompensationEnabled = emitter.m_lagCompensationEnabled;
|
||||
|
||||
OnParticleEmitterMove(&emitter, this);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 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/ParticleSystem.hpp>
|
||||
#include <Nazara/Graphics/ParticleGroup.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
@@ -26,8 +26,8 @@ namespace Nz
|
||||
* \param layout Enumeration for the layout of data information for the particles
|
||||
*/
|
||||
|
||||
ParticleSystem::ParticleSystem(unsigned int maxParticleCount, ParticleLayout layout) :
|
||||
ParticleSystem(maxParticleCount, ParticleDeclaration::Get(layout))
|
||||
ParticleGroup::ParticleGroup(unsigned int maxParticleCount, ParticleLayout layout) :
|
||||
ParticleGroup(maxParticleCount, ParticleDeclaration::Get(layout))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Nz
|
||||
* \param declaration Data information for the particles
|
||||
*/
|
||||
|
||||
ParticleSystem::ParticleSystem(unsigned int maxParticleCount, ParticleDeclarationConstRef declaration) :
|
||||
ParticleGroup::ParticleGroup(unsigned int maxParticleCount, ParticleDeclarationConstRef declaration) :
|
||||
m_declaration(std::move(declaration)),
|
||||
m_processing(false),
|
||||
m_maxParticleCount(maxParticleCount),
|
||||
@@ -58,7 +58,7 @@ namespace Nz
|
||||
* \param system ParticleSystem to copy into this
|
||||
*/
|
||||
|
||||
ParticleSystem::ParticleSystem(const ParticleSystem& system) :
|
||||
ParticleGroup::ParticleGroup(const ParticleGroup& system) :
|
||||
Renderable(system),
|
||||
m_controllers(system.m_controllers),
|
||||
m_generators(system.m_generators),
|
||||
@@ -77,7 +77,10 @@ namespace Nz
|
||||
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize);
|
||||
}
|
||||
|
||||
ParticleSystem::~ParticleSystem() = default;
|
||||
ParticleGroup::~ParticleGroup()
|
||||
{
|
||||
OnParticleGroupRelease(this);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a controller to the particles
|
||||
@@ -87,7 +90,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if controller is invalid
|
||||
*/
|
||||
|
||||
void ParticleSystem::AddController(ParticleControllerRef controller)
|
||||
void ParticleGroup::AddController(ParticleControllerRef controller)
|
||||
{
|
||||
NazaraAssert(controller, "Invalid particle controller");
|
||||
|
||||
@@ -102,11 +105,16 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if emitter is invalid
|
||||
*/
|
||||
|
||||
void ParticleSystem::AddEmitter(ParticleEmitter* emitter)
|
||||
void ParticleGroup::AddEmitter(ParticleEmitter* emitter)
|
||||
{
|
||||
NazaraAssert(emitter, "Invalid particle emitter");
|
||||
|
||||
m_emitters.emplace_back(emitter);
|
||||
EmitterEntry entry;
|
||||
entry.emitter = emitter;
|
||||
entry.moveSlot.Connect(emitter->OnParticleEmitterMove, this, &ParticleGroup::OnEmitterMove);
|
||||
entry.releaseSlot.Connect(emitter->OnParticleEmitterRelease, this, &ParticleGroup::OnEmitterRelease);
|
||||
|
||||
m_emitters.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -117,7 +125,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if generator is invalid
|
||||
*/
|
||||
|
||||
void ParticleSystem::AddGenerator(ParticleGeneratorRef generator)
|
||||
void ParticleGroup::AddGenerator(ParticleGeneratorRef generator)
|
||||
{
|
||||
NazaraAssert(generator, "Invalid particle generator");
|
||||
|
||||
@@ -134,7 +142,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if renderQueue is invalid
|
||||
*/
|
||||
|
||||
void ParticleSystem::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const
|
||||
void ParticleGroup::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const
|
||||
{
|
||||
NazaraAssert(m_renderer, "Invalid particle renderer");
|
||||
NazaraAssert(renderQueue, "Invalid renderqueue");
|
||||
@@ -154,8 +162,7 @@ namespace Nz
|
||||
* \param particleCount Number of particles
|
||||
* \param elapsedTime Delta time between the previous frame
|
||||
*/
|
||||
|
||||
void ParticleSystem::ApplyControllers(ParticleMapper& mapper, unsigned int particleCount, float elapsedTime)
|
||||
void ParticleGroup::ApplyControllers(ParticleMapper& mapper, unsigned int particleCount, float elapsedTime)
|
||||
{
|
||||
m_processing = true;
|
||||
|
||||
@@ -174,8 +181,8 @@ namespace Nz
|
||||
if (m_dyingParticles.size() < m_particleCount)
|
||||
{
|
||||
// We kill them in reverse order, std::set sorting them via std::greater
|
||||
// The reason is simple, as the death of a particle means the move of the last particle in the buffer,
|
||||
// without this solution, certain particles could avoid the death
|
||||
// The reason is simple, as the death of a particle means moving the last particle in the buffer,
|
||||
// without this solution, certain particles could avoid death
|
||||
for (unsigned int index : m_dyingParticles)
|
||||
KillParticle(index);
|
||||
}
|
||||
@@ -190,7 +197,7 @@ namespace Nz
|
||||
* \return Pointer to the particle memory buffer
|
||||
*/
|
||||
|
||||
void* ParticleSystem::CreateParticle()
|
||||
void* ParticleGroup::CreateParticle()
|
||||
{
|
||||
return CreateParticles(1);
|
||||
}
|
||||
@@ -200,7 +207,7 @@ namespace Nz
|
||||
* \return Pointer to the first particle memory buffer
|
||||
*/
|
||||
|
||||
void* ParticleSystem::CreateParticles(unsigned int count)
|
||||
void* ParticleGroup::CreateParticles(unsigned int count)
|
||||
{
|
||||
if (count == 0)
|
||||
return nullptr;
|
||||
@@ -219,7 +226,7 @@ namespace Nz
|
||||
* \return Pointer to the particle memory buffer
|
||||
*/
|
||||
|
||||
void* ParticleSystem::GenerateParticle()
|
||||
void* ParticleGroup::GenerateParticle()
|
||||
{
|
||||
return GenerateParticles(1);
|
||||
}
|
||||
@@ -229,7 +236,7 @@ namespace Nz
|
||||
* \return Pointer to the first particle memory buffer
|
||||
*/
|
||||
|
||||
void* ParticleSystem::GenerateParticles(unsigned int count)
|
||||
void* ParticleGroup::GenerateParticles(unsigned int count)
|
||||
{
|
||||
void* ptr = CreateParticles(count);
|
||||
if (!ptr)
|
||||
@@ -247,27 +254,17 @@ namespace Nz
|
||||
* \return Particle declaration
|
||||
*/
|
||||
|
||||
const ParticleDeclarationConstRef& ParticleSystem::GetDeclaration() const
|
||||
const ParticleDeclarationConstRef& ParticleGroup::GetDeclaration() const
|
||||
{
|
||||
return m_declaration;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the fixed step size
|
||||
* \return Current fixed step size
|
||||
*/
|
||||
|
||||
float ParticleSystem::GetFixedStepSize() const
|
||||
{
|
||||
return m_stepSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the maximum number of particles
|
||||
* \return Current maximum number
|
||||
*/
|
||||
|
||||
unsigned int ParticleSystem::GetMaxParticleCount() const
|
||||
unsigned int ParticleGroup::GetMaxParticleCount() const
|
||||
{
|
||||
return m_maxParticleCount;
|
||||
}
|
||||
@@ -277,7 +274,7 @@ namespace Nz
|
||||
* \return Current number
|
||||
*/
|
||||
|
||||
unsigned int ParticleSystem::GetParticleCount() const
|
||||
unsigned int ParticleGroup::GetParticleCount() const
|
||||
{
|
||||
return m_particleCount;
|
||||
}
|
||||
@@ -287,28 +284,18 @@ namespace Nz
|
||||
* \return Current size
|
||||
*/
|
||||
|
||||
unsigned int ParticleSystem::GetParticleSize() const
|
||||
unsigned int ParticleGroup::GetParticleSize() const
|
||||
{
|
||||
return m_particleSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the fixed step is enabled
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
bool ParticleSystem::IsFixedStepEnabled() const
|
||||
{
|
||||
return m_fixedStepEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Kills one particle
|
||||
*
|
||||
* \param index Index of the particle
|
||||
*/
|
||||
|
||||
void ParticleSystem::KillParticle(unsigned int index)
|
||||
void ParticleGroup::KillParticle(unsigned int index)
|
||||
{
|
||||
///FIXME: Verify the index
|
||||
|
||||
@@ -328,7 +315,7 @@ namespace Nz
|
||||
* \brief Kills every particles
|
||||
*/
|
||||
|
||||
void ParticleSystem::KillParticles()
|
||||
void ParticleGroup::KillParticles()
|
||||
{
|
||||
m_particleCount = 0;
|
||||
}
|
||||
@@ -339,7 +326,7 @@ namespace Nz
|
||||
* \param controller Controller for the particles to remove
|
||||
*/
|
||||
|
||||
void ParticleSystem::RemoveController(ParticleController* controller)
|
||||
void ParticleGroup::RemoveController(ParticleController* controller)
|
||||
{
|
||||
auto it = std::find(m_controllers.begin(), m_controllers.end(), controller);
|
||||
if (it != m_controllers.end())
|
||||
@@ -352,11 +339,16 @@ namespace Nz
|
||||
* \param emitter Emitter for the particles to remove
|
||||
*/
|
||||
|
||||
void ParticleSystem::RemoveEmitter(ParticleEmitter* emitter)
|
||||
void ParticleGroup::RemoveEmitter(ParticleEmitter* emitter)
|
||||
{
|
||||
auto it = std::find(m_emitters.begin(), m_emitters.end(), emitter);
|
||||
if (it != m_emitters.end())
|
||||
m_emitters.erase(it);
|
||||
for (auto it = m_emitters.begin(); it != m_emitters.end(); ++it)
|
||||
{
|
||||
if (it->emitter == emitter)
|
||||
{
|
||||
m_emitters.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -365,31 +357,20 @@ namespace Nz
|
||||
* \param generator Generator for the particles to remove
|
||||
*/
|
||||
|
||||
void ParticleSystem::RemoveGenerator(ParticleGenerator* generator)
|
||||
void ParticleGroup::RemoveGenerator(ParticleGenerator* generator)
|
||||
{
|
||||
auto it = std::find(m_generators.begin(), m_generators.end(), generator);
|
||||
if (it != m_generators.end())
|
||||
m_generators.erase(it);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the fixed step size
|
||||
*
|
||||
* \param stepSize Fixed step size
|
||||
*/
|
||||
|
||||
void ParticleSystem::SetFixedStepSize(float stepSize)
|
||||
{
|
||||
m_stepSize = stepSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the renderer of the particles
|
||||
*
|
||||
* \param renderer Renderer for the particles
|
||||
*/
|
||||
|
||||
void ParticleSystem::SetRenderer(ParticleRenderer* renderer)
|
||||
void ParticleGroup::SetRenderer(ParticleRenderer* renderer)
|
||||
{
|
||||
m_renderer = renderer;
|
||||
}
|
||||
@@ -400,11 +381,11 @@ namespace Nz
|
||||
* \param elapsedTime Delta time between the previous frame
|
||||
*/
|
||||
|
||||
void ParticleSystem::Update(float elapsedTime)
|
||||
void ParticleGroup::Update(float elapsedTime)
|
||||
{
|
||||
// Emission
|
||||
for (ParticleEmitter* emitter : m_emitters)
|
||||
emitter->Emit(*this, elapsedTime);
|
||||
for (const EmitterEntry& entry : m_emitters)
|
||||
entry.emitter->Emit(*this, elapsedTime);
|
||||
|
||||
// Update
|
||||
if (m_particleCount > 0)
|
||||
@@ -421,7 +402,7 @@ namespace Nz
|
||||
* \param transformMatrix Matrix transformation for our bounding volume
|
||||
*/
|
||||
|
||||
void ParticleSystem::UpdateBoundingVolume(const Matrix4f& transformMatrix)
|
||||
void ParticleGroup::UpdateBoundingVolume(const Matrix4f& transformMatrix)
|
||||
{
|
||||
NazaraUnused(transformMatrix);
|
||||
|
||||
@@ -435,7 +416,7 @@ namespace Nz
|
||||
* \param system The other ParticleSystem
|
||||
*/
|
||||
|
||||
ParticleSystem& ParticleSystem::operator=(const ParticleSystem& system)
|
||||
ParticleGroup& ParticleGroup::operator=(const ParticleGroup& system)
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
@@ -448,12 +429,10 @@ namespace Nz
|
||||
m_particleCount = system.m_particleCount;
|
||||
m_particleSize = system.m_particleSize;
|
||||
m_renderer = system.m_renderer;
|
||||
m_stepSize = system.m_stepSize;
|
||||
|
||||
// The copy can not (or should not) happen during the update, there is no use to copy
|
||||
m_dyingParticles.clear();
|
||||
m_processing = false;
|
||||
m_stepAccumulator = 0.f;
|
||||
|
||||
m_buffer.clear(); // To avoid a copy due to resize() which will be pointless
|
||||
ResizeBuffer();
|
||||
@@ -468,19 +447,39 @@ namespace Nz
|
||||
* \brief Makes the bounding volume of this text
|
||||
*/
|
||||
|
||||
void ParticleSystem::MakeBoundingVolume() const
|
||||
void ParticleGroup::MakeBoundingVolume() const
|
||||
{
|
||||
///TODO: Compute the AABB (taking into account the size of particles)
|
||||
m_boundingVolume.MakeInfinite();
|
||||
}
|
||||
|
||||
void ParticleGroup::OnEmitterMove(ParticleEmitter* oldEmitter, ParticleEmitter* newEmitter)
|
||||
{
|
||||
for (EmitterEntry& entry : m_emitters)
|
||||
{
|
||||
if (entry.emitter == oldEmitter)
|
||||
entry.emitter = newEmitter;
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleGroup::OnEmitterRelease(const ParticleEmitter* emitter)
|
||||
{
|
||||
for (auto it = m_emitters.begin(); it != m_emitters.end();)
|
||||
{
|
||||
if (it->emitter == emitter)
|
||||
it = m_emitters.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resizes the internal buffer
|
||||
*
|
||||
* \remark Produces a NazaraError if resize did not work
|
||||
*/
|
||||
|
||||
void ParticleSystem::ResizeBuffer()
|
||||
void ParticleGroup::ResizeBuffer()
|
||||
{
|
||||
// Just to have a better description of our problem in case of error
|
||||
try
|
||||
@@ -132,7 +132,7 @@ void main()
|
||||
vec2 texCoord = vTexCoord;
|
||||
#endif
|
||||
|
||||
#if LIGHTING && PARALLAX_MAPPING
|
||||
#if PARALLAX_MAPPING
|
||||
float height = texture(MaterialHeightMap, texCoord).r;
|
||||
float v = height*ParallaxScale + ParallaxBias;
|
||||
|
||||
@@ -159,17 +159,16 @@ void main()
|
||||
discard;
|
||||
#endif // ALPHA_TEST
|
||||
|
||||
#if LIGHTING
|
||||
#if NORMAL_MAPPING
|
||||
#if NORMAL_MAPPING
|
||||
vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture(MaterialNormalMap, texCoord)) - 1.0));
|
||||
#else
|
||||
#else
|
||||
vec3 normal = normalize(vNormal);
|
||||
#endif // NORMAL_MAPPING
|
||||
#endif // NORMAL_MAPPING
|
||||
|
||||
vec3 specularColor = MaterialSpecular.rgb;
|
||||
#if SPECULAR_MAPPING
|
||||
#if SPECULAR_MAPPING
|
||||
specularColor *= texture(MaterialSpecularMap, texCoord).rgb;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
Texture0: Diffuse Color + Specular
|
||||
@@ -179,9 +178,6 @@ void main()
|
||||
RenderTarget0 = vec4(diffuseColor.rgb, dot(specularColor, vec3(0.3, 0.59, 0.11)));
|
||||
RenderTarget1 = vec4(EncodeNormal(normal));
|
||||
RenderTarget2 = vec4(FloatToColor(gl_FragCoord.z), (MaterialShininess == 0.0) ? 0.0 : max(log2(MaterialShininess), 0.1)/10.5); // http://www.guerrilla-games.com/publications/dr_kz2_rsx_dev07.pdf
|
||||
#else // LIGHTING
|
||||
RenderTarget0 = vec4(diffuseColor.rgb, 0.0);
|
||||
#endif
|
||||
#else // FLAG_DEFERRED
|
||||
#if ALPHA_MAPPING
|
||||
diffuseColor.a *= texture(MaterialAlphaMap, texCoord).r;
|
||||
@@ -192,16 +188,15 @@ void main()
|
||||
discard;
|
||||
#endif
|
||||
|
||||
#if LIGHTING
|
||||
vec3 lightAmbient = vec3(0.0);
|
||||
vec3 lightDiffuse = vec3(0.0);
|
||||
vec3 lightSpecular = vec3(0.0);
|
||||
|
||||
#if NORMAL_MAPPING
|
||||
#if NORMAL_MAPPING
|
||||
vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture(MaterialNormalMap, texCoord)) - 1.0));
|
||||
#else
|
||||
#else
|
||||
vec3 normal = normalize(vNormal);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (MaterialShininess > 0.0)
|
||||
{
|
||||
@@ -459,24 +454,21 @@ void main()
|
||||
}
|
||||
|
||||
lightSpecular *= MaterialSpecular.rgb;
|
||||
#if SPECULAR_MAPPING
|
||||
#if SPECULAR_MAPPING
|
||||
lightSpecular *= texture(MaterialSpecularMap, texCoord).rgb; // Utiliser l'alpha de MaterialSpecular n'aurait aucun sens
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vec3 lightColor = (lightAmbient + lightDiffuse + lightSpecular);
|
||||
vec4 fragmentColor = vec4(lightColor, 1.0) * diffuseColor;
|
||||
|
||||
#if EMISSIVE_MAPPING
|
||||
#if EMISSIVE_MAPPING
|
||||
float lightIntensity = dot(lightColor, vec3(0.3, 0.59, 0.11));
|
||||
|
||||
vec3 emissionColor = MaterialDiffuse.rgb * texture(MaterialEmissiveMap, texCoord).rgb;
|
||||
RenderTarget0 = vec4(mix(fragmentColor.rgb, emissionColor, clamp(1.0 - 3.0*lightIntensity, 0.0, 1.0)), fragmentColor.a);
|
||||
#else
|
||||
RenderTarget0 = fragmentColor;
|
||||
#endif // EMISSIVE_MAPPING
|
||||
#else
|
||||
RenderTarget0 = diffuseColor;
|
||||
#endif // LIGHTING
|
||||
RenderTarget0 = fragmentColor;
|
||||
#endif // EMISSIVE_MAPPING
|
||||
#endif // FLAG_DEFERRED
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,6 +12,7 @@ in vec3 VertexPosition;
|
||||
in vec3 VertexNormal;
|
||||
in vec3 VertexTangent;
|
||||
in vec2 VertexTexCoord;
|
||||
in vec4 VertexUserdata0;
|
||||
|
||||
/********************Sortant********************/
|
||||
out vec4 vColor;
|
||||
@@ -27,6 +28,7 @@ uniform vec3 EyePosition;
|
||||
uniform mat4 InvViewMatrix;
|
||||
uniform mat4 LightViewProjMatrix[3];
|
||||
uniform float VertexDepth;
|
||||
uniform mat4 ViewMatrix;
|
||||
uniform mat4 ViewProjMatrix;
|
||||
uniform mat4 WorldMatrix;
|
||||
uniform mat4 WorldViewProjMatrix;
|
||||
@@ -107,21 +109,19 @@ void main()
|
||||
|
||||
vColor = color;
|
||||
|
||||
#if LIGHTING
|
||||
#if FLAG_INSTANCING
|
||||
#if FLAG_INSTANCING
|
||||
mat3 rotationMatrix = mat3(InstanceData0);
|
||||
#else
|
||||
#else
|
||||
mat3 rotationMatrix = mat3(WorldMatrix);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if COMPUTE_TBNMATRIX
|
||||
#if COMPUTE_TBNMATRIX
|
||||
vec3 binormal = cross(VertexNormal, VertexTangent);
|
||||
vLightToWorld[0] = normalize(rotationMatrix * VertexTangent);
|
||||
vLightToWorld[1] = normalize(rotationMatrix * binormal);
|
||||
vLightToWorld[2] = normalize(rotationMatrix * VertexNormal);
|
||||
#else
|
||||
#else
|
||||
vNormal = normalize(rotationMatrix * VertexNormal);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SHADOW_MAPPING
|
||||
@@ -133,12 +133,12 @@ void main()
|
||||
vTexCoord = VertexTexCoord;
|
||||
#endif
|
||||
|
||||
#if LIGHTING && PARALLAX_MAPPING
|
||||
#if PARALLAX_MAPPING
|
||||
vViewDir = EyePosition - VertexPosition;
|
||||
vViewDir *= vLightToWorld;
|
||||
#endif
|
||||
|
||||
#if LIGHTING && !FLAG_DEFERRED
|
||||
#if !FLAG_DEFERRED
|
||||
#if FLAG_INSTANCING
|
||||
vWorldPos = vec3(InstanceData0 * vec4(VertexPosition, 1.0));
|
||||
#else
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -181,10 +181,10 @@ namespace Nz
|
||||
|
||||
// Renderstates
|
||||
s_renderStates.depthFunc = RendererComparison_Equal;
|
||||
s_renderStates.faceCulling = FaceSide_Front;
|
||||
s_renderStates.parameters[RendererParameter_DepthBuffer] = true;
|
||||
s_renderStates.parameters[RendererParameter_DepthWrite] = false;
|
||||
s_renderStates.parameters[RendererParameter_FaceCulling] = true;
|
||||
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);
|
||||
|
||||
@@ -20,10 +20,10 @@ namespace Nz
|
||||
{
|
||||
RenderStates states;
|
||||
states.depthFunc = RendererComparison_Equal;
|
||||
states.faceCulling = FaceSide_Back;
|
||||
states.parameters[RendererParameter_DepthBuffer] = true;
|
||||
states.parameters[RendererParameter_DepthWrite] = false;
|
||||
states.parameters[RendererParameter_FaceCulling] = true;
|
||||
states.cullingSide = FaceSide_Back;
|
||||
states.depthBuffer = true;
|
||||
states.depthWrite = false;
|
||||
states.faceCulling = true;
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
110
src/Nazara/Graphics/TileMap.cpp
Normal file
110
src/Nazara/Graphics/TileMap.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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 <Nazara/Graphics/TileMap.hpp>
|
||||
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::TileMap
|
||||
* \brief Graphics class that represent several tiles of the same size assembled into a grid
|
||||
* This class is far more efficient than using a sprite for every tile
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Adds the TileMap to the rendering queue
|
||||
*
|
||||
* \param renderQueue Queue to be added
|
||||
* \param instanceData Data for the instance
|
||||
*/
|
||||
void TileMap::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
|
||||
{
|
||||
const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<const VertexStruct_XYZ_Color_UV*>(instanceData.data.data());
|
||||
|
||||
std::size_t spriteCount = 0;
|
||||
for (const Layer& layer : m_layers)
|
||||
{
|
||||
if (layer.material)
|
||||
renderQueue->AddSprites(instanceData.renderOrder, layer.material, &vertices[spriteCount], layer.tiles.size());
|
||||
|
||||
spriteCount += layer.tiles.size();
|
||||
}
|
||||
}
|
||||
|
||||
void TileMap::MakeBoundingVolume() const
|
||||
{
|
||||
Nz::Vector2f size = GetSize();
|
||||
m_boundingVolume.Set(Vector3f(0.f), size.x*Vector3f::Right() + size.y*Vector3f::Down());
|
||||
}
|
||||
|
||||
void TileMap::UpdateData(InstanceData* instanceData) const
|
||||
{
|
||||
std::size_t spriteCount = 0;
|
||||
for (const Layer& layer : m_layers)
|
||||
spriteCount += layer.tiles.size();
|
||||
|
||||
instanceData->data.resize(4 * spriteCount * sizeof(VertexStruct_XYZ_Color_UV));
|
||||
VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<VertexStruct_XYZ_Color_UV*>(instanceData->data.data());
|
||||
|
||||
spriteCount = 0;
|
||||
for (const Layer& layer : m_layers)
|
||||
{
|
||||
SparsePtr<Color> colorPtr(&vertices[spriteCount].color, sizeof(VertexStruct_XYZ_Color_UV));
|
||||
SparsePtr<Vector3f> posPtr(&vertices[spriteCount].position, sizeof(VertexStruct_XYZ_Color_UV));
|
||||
SparsePtr<Vector2f> texCoordPtr(&vertices[spriteCount].uv, sizeof(VertexStruct_XYZ_Color_UV));
|
||||
|
||||
for (std::size_t tileIndex : layer.tiles)
|
||||
{
|
||||
const Tile& tile = m_tiles[tileIndex];
|
||||
NazaraAssert(tile.enabled, "Tile specified for rendering is not enabled");
|
||||
|
||||
std::size_t x = tileIndex % m_mapSize.x;
|
||||
std::size_t y = tileIndex / m_mapSize.x;
|
||||
Vector3f tileLeftCorner(x * m_tileSize.x, y * -m_tileSize.y, 0.f);
|
||||
|
||||
*colorPtr++ = tile.color;
|
||||
*posPtr++ = instanceData->transformMatrix->Transform(tileLeftCorner);
|
||||
*texCoordPtr++ = tile.textureCoords.GetCorner(RectCorner_LeftTop);
|
||||
|
||||
*colorPtr++ = tile.color;
|
||||
*posPtr++ = instanceData->transformMatrix->Transform(tileLeftCorner + m_tileSize.x * Vector3f::Right());
|
||||
*texCoordPtr++ = tile.textureCoords.GetCorner(RectCorner_RightTop);
|
||||
|
||||
*colorPtr++ = tile.color;
|
||||
*posPtr++ = instanceData->transformMatrix->Transform(tileLeftCorner + m_tileSize.y * Vector3f::Down());
|
||||
*texCoordPtr++ = tile.textureCoords.GetCorner(RectCorner_LeftBottom);
|
||||
|
||||
*colorPtr++ = tile.color;
|
||||
*posPtr++ = instanceData->transformMatrix->Transform(tileLeftCorner + m_tileSize.x * Vector3f::Right() + m_tileSize.y * Vector3f::Down());
|
||||
*texCoordPtr++ = tile.textureCoords.GetCorner(RectCorner_RightBottom);
|
||||
}
|
||||
spriteCount += layer.tiles.size();
|
||||
}
|
||||
}
|
||||
|
||||
bool TileMap::Initialize()
|
||||
{
|
||||
if (!TileMapLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TileMap::Uninitialize()
|
||||
{
|
||||
TileMapLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
TileMapLibrary::LibraryMap TileMap::s_library;
|
||||
}
|
||||
@@ -652,7 +652,7 @@ namespace Nz
|
||||
|
||||
void DebugDrawer::EnableDepthBuffer(bool depthBuffer)
|
||||
{
|
||||
s_renderStates.parameters[RendererParameter_DepthBuffer] = depthBuffer;
|
||||
s_renderStates.depthBuffer = depthBuffer;
|
||||
}
|
||||
|
||||
float DebugDrawer::GetLineWidth()
|
||||
@@ -698,7 +698,7 @@ namespace Nz
|
||||
}
|
||||
|
||||
s_primaryColor = Color::Red;
|
||||
s_renderStates.parameters[RendererParameter_DepthBuffer] = true;
|
||||
s_renderStates.depthBuffer = true;
|
||||
s_secondaryColor = Color::Green;
|
||||
|
||||
s_initialized = true;
|
||||
@@ -709,7 +709,7 @@ namespace Nz
|
||||
|
||||
bool DebugDrawer::IsDepthBufferEnabled()
|
||||
{
|
||||
return s_renderStates.parameters[RendererParameter_DepthBuffer];
|
||||
return s_renderStates.depthBuffer;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetLineWidth(float width)
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Nz
|
||||
RenderStates& currentRenderStates = s_contextStates->renderStates;
|
||||
|
||||
// Les fonctions de blend n'a aucun intérêt sans blending
|
||||
if (states.parameters[RendererParameter_Blend])
|
||||
if (states.blending)
|
||||
{
|
||||
if (currentRenderStates.dstBlend != states.dstBlend ||
|
||||
currentRenderStates.srcBlend != states.srcBlend)
|
||||
@@ -169,7 +169,7 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
if (states.parameters[RendererParameter_DepthBuffer])
|
||||
if (states.depthBuffer)
|
||||
{
|
||||
// La comparaison de profondeur n'a aucun intérêt sans depth buffer
|
||||
if (currentRenderStates.depthFunc != states.depthFunc)
|
||||
@@ -179,20 +179,20 @@ namespace Nz
|
||||
}
|
||||
|
||||
// Le DepthWrite n'a aucune importance si le DepthBuffer est désactivé
|
||||
if (currentRenderStates.parameters[RendererParameter_DepthWrite] != states.parameters[RendererParameter_DepthWrite])
|
||||
if (currentRenderStates.depthWrite != states.depthWrite)
|
||||
{
|
||||
glDepthMask((states.parameters[RendererParameter_DepthWrite]) ? GL_TRUE : GL_FALSE);
|
||||
currentRenderStates.parameters[RendererParameter_DepthWrite] = states.parameters[RendererParameter_DepthWrite];
|
||||
glDepthMask((states.depthWrite) ? GL_TRUE : GL_FALSE);
|
||||
currentRenderStates.depthWrite = states.depthWrite;
|
||||
}
|
||||
}
|
||||
|
||||
// Inutile de changer le mode de face culling s'il n'est pas actif
|
||||
if (states.parameters[RendererParameter_FaceCulling])
|
||||
if (states.faceCulling)
|
||||
{
|
||||
if (currentRenderStates.faceCulling != states.faceCulling)
|
||||
if (currentRenderStates.cullingSide != states.cullingSide)
|
||||
{
|
||||
glCullFace(FaceSide[states.faceCulling]);
|
||||
currentRenderStates.faceCulling = states.faceCulling;
|
||||
glCullFace(FaceSide[states.cullingSide]);
|
||||
currentRenderStates.cullingSide = states.cullingSide;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,33 +203,46 @@ namespace Nz
|
||||
}
|
||||
|
||||
// Ici encore, ça ne sert à rien de se soucier des fonctions de stencil sans qu'il soit activé
|
||||
if (states.parameters[RendererParameter_StencilTest])
|
||||
if (states.stencilTest)
|
||||
{
|
||||
for (unsigned int i = 0; i < 2; ++i)
|
||||
if (currentRenderStates.stencilCompare.back != states.stencilCompare.back ||
|
||||
currentRenderStates.stencilReference.back != states.stencilReference.back ||
|
||||
currentRenderStates.stencilWriteMask.back != states.stencilWriteMask.back)
|
||||
{
|
||||
GLenum face = (i == 0) ? GL_BACK : GL_FRONT;
|
||||
const RenderStates::Face& srcStates = (i == 0) ? states.backFace : states.frontFace;
|
||||
RenderStates::Face& dstStates = (i == 0) ? currentRenderStates.backFace : currentRenderStates.frontFace;
|
||||
glStencilFuncSeparate(GL_BACK, RendererComparison[states.stencilCompare.back], states.stencilReference.back, states.stencilWriteMask.back);
|
||||
currentRenderStates.stencilCompare.back = states.stencilCompare.back;
|
||||
currentRenderStates.stencilReference.back = states.stencilReference.back;
|
||||
currentRenderStates.stencilWriteMask.back = states.stencilWriteMask.back;
|
||||
}
|
||||
|
||||
if (dstStates.stencilCompare != srcStates.stencilCompare ||
|
||||
dstStates.stencilMask != srcStates.stencilMask ||
|
||||
dstStates.stencilReference != srcStates.stencilReference)
|
||||
{
|
||||
glStencilFuncSeparate(face, RendererComparison[srcStates.stencilCompare], srcStates.stencilReference, srcStates.stencilMask);
|
||||
dstStates.stencilCompare = srcStates.stencilCompare;
|
||||
dstStates.stencilMask = srcStates.stencilMask;
|
||||
dstStates.stencilReference = srcStates.stencilReference;
|
||||
}
|
||||
if (currentRenderStates.stencilDepthFail.back != states.stencilDepthFail.back ||
|
||||
currentRenderStates.stencilFail.back != states.stencilFail.back ||
|
||||
currentRenderStates.stencilPass.back != states.stencilPass.back)
|
||||
{
|
||||
glStencilOpSeparate(GL_BACK, StencilOperation[states.stencilFail.back], StencilOperation[states.stencilDepthFail.back], StencilOperation[states.stencilPass.back]);
|
||||
currentRenderStates.stencilDepthFail.back = states.stencilDepthFail.back;
|
||||
currentRenderStates.stencilFail.back = states.stencilFail.back;
|
||||
currentRenderStates.stencilPass.back = states.stencilPass.back;
|
||||
}
|
||||
|
||||
if (dstStates.stencilFail != srcStates.stencilFail ||
|
||||
dstStates.stencilPass != srcStates.stencilPass ||
|
||||
dstStates.stencilZFail != srcStates.stencilZFail)
|
||||
{
|
||||
glStencilOpSeparate(face, StencilOperation[srcStates.stencilFail], StencilOperation[srcStates.stencilZFail], StencilOperation[srcStates.stencilPass]);
|
||||
dstStates.stencilFail = srcStates.stencilFail;
|
||||
dstStates.stencilPass = srcStates.stencilPass;
|
||||
dstStates.stencilZFail = srcStates.stencilZFail;
|
||||
}
|
||||
if (currentRenderStates.stencilCompare.front != states.stencilCompare.front ||
|
||||
currentRenderStates.stencilReference.front != states.stencilReference.front ||
|
||||
currentRenderStates.stencilWriteMask.front != states.stencilWriteMask.front)
|
||||
{
|
||||
glStencilFuncSeparate(GL_FRONT, RendererComparison[states.stencilCompare.front], states.stencilReference.front, states.stencilWriteMask.front);
|
||||
currentRenderStates.stencilCompare.front = states.stencilCompare.front;
|
||||
currentRenderStates.stencilReference.front = states.stencilReference.front;
|
||||
currentRenderStates.stencilWriteMask.front = states.stencilWriteMask.front;
|
||||
}
|
||||
|
||||
if (currentRenderStates.stencilDepthFail.front != states.stencilDepthFail.front ||
|
||||
currentRenderStates.stencilFail.front != states.stencilFail.front ||
|
||||
currentRenderStates.stencilPass.front != states.stencilPass.front)
|
||||
{
|
||||
glStencilOpSeparate(GL_FRONT, StencilOperation[states.stencilFail.front], StencilOperation[states.stencilDepthFail.front], StencilOperation[states.stencilPass.front]);
|
||||
currentRenderStates.stencilDepthFail.front = states.stencilDepthFail.front;
|
||||
currentRenderStates.stencilFail.front = states.stencilFail.front;
|
||||
currentRenderStates.stencilPass.front = states.stencilPass.front;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,62 +259,62 @@ namespace Nz
|
||||
}
|
||||
|
||||
// Paramètres de rendu
|
||||
if (currentRenderStates.parameters[RendererParameter_Blend] != states.parameters[RendererParameter_Blend])
|
||||
if (currentRenderStates.blending != states.blending)
|
||||
{
|
||||
if (states.parameters[RendererParameter_Blend])
|
||||
if (states.blending)
|
||||
glEnable(GL_BLEND);
|
||||
else
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
currentRenderStates.parameters[RendererParameter_Blend] = states.parameters[RendererParameter_Blend];
|
||||
currentRenderStates.blending = states.blending;
|
||||
}
|
||||
|
||||
if (currentRenderStates.parameters[RendererParameter_ColorWrite] != states.parameters[RendererParameter_ColorWrite])
|
||||
if (currentRenderStates.colorWrite != states.colorWrite)
|
||||
{
|
||||
GLboolean param = (states.parameters[RendererParameter_ColorWrite]) ? GL_TRUE : GL_FALSE;
|
||||
GLboolean param = (states.colorWrite) ? GL_TRUE : GL_FALSE;
|
||||
glColorMask(param, param, param, param);
|
||||
|
||||
currentRenderStates.parameters[RendererParameter_ColorWrite] = states.parameters[RendererParameter_ColorWrite];
|
||||
currentRenderStates.colorWrite = states.colorWrite;
|
||||
}
|
||||
|
||||
if (currentRenderStates.parameters[RendererParameter_DepthBuffer] != states.parameters[RendererParameter_DepthBuffer])
|
||||
if (currentRenderStates.depthBuffer != states.depthBuffer)
|
||||
{
|
||||
if (states.parameters[RendererParameter_DepthBuffer])
|
||||
if (states.depthBuffer)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
currentRenderStates.parameters[RendererParameter_DepthBuffer] = states.parameters[RendererParameter_DepthBuffer];
|
||||
currentRenderStates.depthBuffer = states.depthBuffer;
|
||||
}
|
||||
|
||||
if (currentRenderStates.parameters[RendererParameter_FaceCulling] != states.parameters[RendererParameter_FaceCulling])
|
||||
if (currentRenderStates.faceCulling != states.faceCulling)
|
||||
{
|
||||
if (states.parameters[RendererParameter_FaceCulling])
|
||||
if (states.faceCulling)
|
||||
glEnable(GL_CULL_FACE);
|
||||
else
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
currentRenderStates.parameters[RendererParameter_FaceCulling] = states.parameters[RendererParameter_FaceCulling];
|
||||
currentRenderStates.faceCulling = states.faceCulling;
|
||||
}
|
||||
|
||||
if (currentRenderStates.parameters[RendererParameter_ScissorTest] != states.parameters[RendererParameter_ScissorTest])
|
||||
if (currentRenderStates.scissorTest != states.scissorTest)
|
||||
{
|
||||
if (states.parameters[RendererParameter_ScissorTest])
|
||||
if (states.scissorTest)
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
else
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
currentRenderStates.parameters[RendererParameter_ScissorTest] = states.parameters[RendererParameter_ScissorTest];
|
||||
currentRenderStates.scissorTest = states.scissorTest;
|
||||
}
|
||||
|
||||
if (currentRenderStates.parameters[RendererParameter_StencilTest] != states.parameters[RendererParameter_StencilTest])
|
||||
if (currentRenderStates.stencilTest != states.stencilTest)
|
||||
{
|
||||
if (states.parameters[RendererParameter_StencilTest])
|
||||
if (states.stencilTest)
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
else
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
currentRenderStates.parameters[RendererParameter_StencilTest] = states.parameters[RendererParameter_StencilTest];
|
||||
currentRenderStates.stencilTest = states.stencilTest;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -396,7 +396,38 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
s_states.parameters[parameter] = enable;
|
||||
switch (parameter)
|
||||
{
|
||||
case RendererParameter_Blend:
|
||||
s_states.blending = enable;
|
||||
return;
|
||||
|
||||
case RendererParameter_ColorWrite:
|
||||
s_states.colorWrite = enable;
|
||||
return;
|
||||
|
||||
case RendererParameter_DepthBuffer:
|
||||
s_states.depthBuffer = enable;
|
||||
return;
|
||||
|
||||
case RendererParameter_DepthWrite:
|
||||
s_states.depthWrite = enable;
|
||||
return;
|
||||
|
||||
case RendererParameter_FaceCulling:
|
||||
s_states.faceCulling = enable;
|
||||
return;
|
||||
|
||||
case RendererParameter_ScissorTest:
|
||||
s_states.scissorTest = enable;
|
||||
return;
|
||||
|
||||
case RendererParameter_StencilTest:
|
||||
s_states.stencilTest = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
NazaraInternalError("Unhandled renderer parameter: 0x" + String::Number(parameter, 16));
|
||||
}
|
||||
|
||||
void Renderer::EndCondition()
|
||||
@@ -762,7 +793,32 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
return s_states.parameters[parameter];
|
||||
switch (parameter)
|
||||
{
|
||||
case RendererParameter_Blend:
|
||||
return s_states.blending;
|
||||
|
||||
case RendererParameter_ColorWrite:
|
||||
return s_states.colorWrite;
|
||||
|
||||
case RendererParameter_DepthBuffer:
|
||||
return s_states.depthBuffer;
|
||||
|
||||
case RendererParameter_DepthWrite:
|
||||
return s_states.depthWrite;
|
||||
|
||||
case RendererParameter_FaceCulling:
|
||||
return s_states.faceCulling;
|
||||
|
||||
case RendererParameter_ScissorTest:
|
||||
return s_states.scissorTest;
|
||||
|
||||
case RendererParameter_StencilTest:
|
||||
return s_states.stencilTest;
|
||||
}
|
||||
|
||||
NazaraInternalError("Unhandled renderer parameter: 0x" + String::Number(parameter, 16));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Renderer::IsInitialized()
|
||||
@@ -865,7 +921,7 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
s_states.faceCulling = faceSide;
|
||||
s_states.cullingSide = faceSide;
|
||||
}
|
||||
|
||||
void Renderer::SetFaceFilling(FaceFilling fillingMode)
|
||||
@@ -1042,16 +1098,16 @@ namespace Nz
|
||||
switch (faceSide)
|
||||
{
|
||||
case FaceSide_Back:
|
||||
s_states.backFace.stencilCompare = compareFunc;
|
||||
s_states.stencilCompare.back = compareFunc;
|
||||
break;
|
||||
|
||||
case FaceSide_Front:
|
||||
s_states.frontFace.stencilCompare = compareFunc;
|
||||
s_states.stencilCompare.front = compareFunc;
|
||||
break;
|
||||
|
||||
case FaceSide_FrontAndBack:
|
||||
s_states.backFace.stencilCompare = compareFunc;
|
||||
s_states.frontFace.stencilCompare = compareFunc;
|
||||
s_states.stencilCompare.back = compareFunc;
|
||||
s_states.stencilCompare.front = compareFunc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1075,16 +1131,16 @@ namespace Nz
|
||||
switch (faceSide)
|
||||
{
|
||||
case FaceSide_Back:
|
||||
s_states.backFace.stencilFail = failOperation;
|
||||
s_states.stencilFail.back = failOperation;
|
||||
break;
|
||||
|
||||
case FaceSide_Front:
|
||||
s_states.frontFace.stencilFail = failOperation;
|
||||
s_states.stencilFail.front = failOperation;
|
||||
break;
|
||||
|
||||
case FaceSide_FrontAndBack:
|
||||
s_states.backFace.stencilFail = failOperation;
|
||||
s_states.frontFace.stencilFail = failOperation;
|
||||
s_states.stencilFail.back = failOperation;
|
||||
s_states.stencilFail.front = failOperation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1102,16 +1158,16 @@ namespace Nz
|
||||
switch (faceSide)
|
||||
{
|
||||
case FaceSide_Back:
|
||||
s_states.backFace.stencilMask = mask;
|
||||
s_states.stencilWriteMask.back = mask;
|
||||
break;
|
||||
|
||||
case FaceSide_Front:
|
||||
s_states.frontFace.stencilMask = mask;
|
||||
s_states.stencilWriteMask.front = mask;
|
||||
break;
|
||||
|
||||
case FaceSide_FrontAndBack:
|
||||
s_states.backFace.stencilMask = mask;
|
||||
s_states.frontFace.stencilMask = mask;
|
||||
s_states.stencilWriteMask.back = mask;
|
||||
s_states.stencilWriteMask.front = mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1135,16 +1191,16 @@ namespace Nz
|
||||
switch (faceSide)
|
||||
{
|
||||
case FaceSide_Back:
|
||||
s_states.backFace.stencilPass = passOperation;
|
||||
s_states.stencilPass.back = passOperation;
|
||||
break;
|
||||
|
||||
case FaceSide_Front:
|
||||
s_states.frontFace.stencilPass = passOperation;
|
||||
s_states.stencilPass.front = passOperation;
|
||||
break;
|
||||
|
||||
case FaceSide_FrontAndBack:
|
||||
s_states.backFace.stencilPass = passOperation;
|
||||
s_states.frontFace.stencilPass = passOperation;
|
||||
s_states.stencilPass.back = passOperation;
|
||||
s_states.stencilPass.front = passOperation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1162,16 +1218,16 @@ namespace Nz
|
||||
switch (faceSide)
|
||||
{
|
||||
case FaceSide_Back:
|
||||
s_states.backFace.stencilReference = refValue;
|
||||
s_states.stencilReference.back = refValue;
|
||||
break;
|
||||
|
||||
case FaceSide_Front:
|
||||
s_states.frontFace.stencilReference = refValue;
|
||||
s_states.stencilReference.front = refValue;
|
||||
break;
|
||||
|
||||
case FaceSide_FrontAndBack:
|
||||
s_states.backFace.stencilReference = refValue;
|
||||
s_states.frontFace.stencilReference = refValue;
|
||||
s_states.stencilReference.back = refValue;
|
||||
s_states.stencilReference.front = refValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1195,16 +1251,16 @@ namespace Nz
|
||||
switch (faceSide)
|
||||
{
|
||||
case FaceSide_Back:
|
||||
s_states.backFace.stencilZFail = zfailOperation;
|
||||
s_states.stencilDepthFail.back = zfailOperation;
|
||||
break;
|
||||
|
||||
case FaceSide_Front:
|
||||
s_states.frontFace.stencilZFail = zfailOperation;
|
||||
s_states.stencilDepthFail.front = zfailOperation;
|
||||
break;
|
||||
|
||||
case FaceSide_FrontAndBack:
|
||||
s_states.backFace.stencilZFail = zfailOperation;
|
||||
s_states.frontFace.stencilZFail = zfailOperation;
|
||||
s_states.stencilDepthFail.back = zfailOperation;
|
||||
s_states.stencilDepthFail.front = zfailOperation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,6 @@ namespace Nz
|
||||
stream.Read(skin, 68*sizeof(char));
|
||||
|
||||
ParameterList matData;
|
||||
matData.SetParameter(MaterialData::CustomDefined);
|
||||
matData.SetParameter(MaterialData::DiffuseTexturePath, baseDir + skin);
|
||||
|
||||
mesh->SetMaterialData(i, std::move(matData));
|
||||
|
||||
@@ -73,8 +73,6 @@ namespace Nz
|
||||
{
|
||||
ParameterList data;
|
||||
|
||||
data.SetParameter(MaterialData::CustomDefined);
|
||||
|
||||
UInt8 alphaValue = static_cast<UInt8>(mtlMat->alpha*255.f);
|
||||
|
||||
Color ambientColor(mtlMat->ambient);
|
||||
|
||||
@@ -97,7 +97,8 @@ namespace Nz
|
||||
if (m_currentLine.GetSize() < 7) // Since we only treat triangles, this is the minimum length of a face line (f 1 2 3)
|
||||
{
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
UnrecognizedLine();
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -106,7 +107,8 @@ namespace Nz
|
||||
if (vertexCount < 3)
|
||||
{
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
UnrecognizedLine();
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -138,7 +140,8 @@ namespace Nz
|
||||
if (std::sscanf(&m_currentLine[pos], "%d%n", &p, &offset) != 1)
|
||||
{
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
UnrecognizedLine();
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
error = true;
|
||||
break;
|
||||
@@ -217,7 +220,8 @@ namespace Nz
|
||||
case 'm': //< MTLLib
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
if (m_currentLine.GetWord(0).ToLower() != "mtllib")
|
||||
UnrecognizedLine();
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
m_mtlLib = m_currentLine.SubString(m_currentLine.GetWordPosition(1));
|
||||
@@ -229,7 +233,8 @@ namespace Nz
|
||||
if (m_currentLine.GetSize() <= 2 || m_currentLine[1] != ' ')
|
||||
{
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
UnrecognizedLine();
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -238,7 +243,8 @@ namespace Nz
|
||||
if (objectName.IsEmpty())
|
||||
{
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
UnrecognizedLine();
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -254,17 +260,20 @@ namespace Nz
|
||||
{
|
||||
String param = m_currentLine.SubString(2);
|
||||
if (param != "all" && param != "on" && param != "off" && !param.IsNumber())
|
||||
UnrecognizedLine();
|
||||
{
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
UnrecognizedLine();
|
||||
else if (!UnrecognizedLine())
|
||||
return false;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'u': //< Usemtl
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
if (m_currentLine.GetWord(0) != "usemtl")
|
||||
UnrecognizedLine();
|
||||
if (m_currentLine.GetWord(0) != "usemtl" && !UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
matName = m_currentLine.SubString(m_currentLine.GetWordPosition(1));
|
||||
@@ -272,7 +281,8 @@ namespace Nz
|
||||
if (matName.IsEmpty())
|
||||
{
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
UnrecognizedLine();
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -288,8 +298,8 @@ namespace Nz
|
||||
if (paramCount >= 1)
|
||||
m_positions.push_back(vertex);
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
else
|
||||
UnrecognizedLine();
|
||||
else if (!UnrecognizedLine())
|
||||
false;
|
||||
#endif
|
||||
}
|
||||
else if (word == "vn")
|
||||
@@ -299,8 +309,8 @@ namespace Nz
|
||||
if (paramCount == 3)
|
||||
m_normals.push_back(normal);
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
else
|
||||
UnrecognizedLine();
|
||||
else if (!UnrecognizedLine())
|
||||
false;
|
||||
#endif
|
||||
}
|
||||
else if (word == "vt")
|
||||
@@ -310,13 +320,13 @@ namespace Nz
|
||||
if (paramCount >= 2)
|
||||
m_texCoords.push_back(uvw);
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
else
|
||||
UnrecognizedLine();
|
||||
else if (!UnrecognizedLine())
|
||||
false;
|
||||
#endif
|
||||
}
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
else
|
||||
UnrecognizedLine();
|
||||
else if (!UnrecognizedLine())
|
||||
false;
|
||||
#endif
|
||||
|
||||
break;
|
||||
@@ -324,7 +334,8 @@ namespace Nz
|
||||
|
||||
default:
|
||||
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
|
||||
UnrecognizedLine();
|
||||
if (!UnrecognizedLine())
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -120,9 +120,10 @@ namespace Nz
|
||||
|
||||
MTLParser::Material* material = mtlFormat.AddMaterial(name);
|
||||
|
||||
bool bValue;
|
||||
String strVal;
|
||||
if (matData.HasParameter(MaterialData::CustomDefined))
|
||||
if (matData.GetStringParameter(MaterialData::FilePath, &strVal))
|
||||
material->diffuseMap = strVal;
|
||||
else
|
||||
{
|
||||
Color colorVal;
|
||||
float fValue;
|
||||
@@ -148,8 +149,6 @@ namespace Nz
|
||||
if (matData.GetStringParameter(MaterialData::SpecularTexturePath, &strVal))
|
||||
material->specularMap = strVal;
|
||||
}
|
||||
else if (matData.GetStringParameter(MaterialData::FilePath, &strVal))
|
||||
material->diffuseMap = strVal;
|
||||
}
|
||||
|
||||
// Meshes
|
||||
|
||||
@@ -1352,6 +1352,15 @@ namespace Nz
|
||||
|
||||
void Image::Copy(UInt8* destination, const UInt8* source, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, unsigned int dstWidth, unsigned int dstHeight, unsigned int srcWidth, unsigned int srcHeight)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (width == 0)
|
||||
NazaraError("Width must be greater than zero");
|
||||
if (height == 0)
|
||||
NazaraError("Height must be greater than zero");
|
||||
if (depth == 0)
|
||||
NazaraError("Depth must be greater than zero");
|
||||
#endif
|
||||
|
||||
if (dstWidth == 0)
|
||||
dstWidth = width;
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Nz
|
||||
|
||||
VertexDeclaration::VertexDeclaration(const VertexDeclaration& declaration) :
|
||||
RefCounted(),
|
||||
m_components(declaration.m_components),
|
||||
m_stride(declaration.m_stride)
|
||||
{
|
||||
std::memcpy(m_components, declaration.m_components, sizeof(Component)*(VertexComponent_Max+1));
|
||||
}
|
||||
|
||||
VertexDeclaration::~VertexDeclaration()
|
||||
@@ -133,7 +133,7 @@ namespace Nz
|
||||
|
||||
VertexDeclaration& VertexDeclaration::operator=(const VertexDeclaration& declaration)
|
||||
{
|
||||
std::memcpy(m_components, declaration.m_components, sizeof(Component)*(VertexComponent_Max+1));
|
||||
m_components = declaration.m_components;
|
||||
m_stride = declaration.m_stride;
|
||||
|
||||
return *this;
|
||||
@@ -141,13 +141,7 @@ namespace Nz
|
||||
|
||||
VertexDeclaration* VertexDeclaration::Get(VertexLayout layout)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (layout > VertexLayout_Max)
|
||||
{
|
||||
NazaraError("Vertex layout out of enum");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(layout <= VertexLayout_Max, "Vertex layout out of enum");
|
||||
|
||||
return &s_declarations[layout];
|
||||
}
|
||||
@@ -301,6 +295,6 @@ namespace Nz
|
||||
VertexDeclarationLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
VertexDeclaration VertexDeclaration::s_declarations[VertexLayout_Max+1];
|
||||
std::array<VertexDeclaration, VertexLayout_Max + 1> VertexDeclaration::s_declarations;
|
||||
VertexDeclarationLibrary::LibraryMap VertexDeclaration::s_library;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user