Merge branch 'master' into vulkan
This commit is contained in:
@@ -15,6 +15,22 @@ namespace Nz
|
||||
* \brief Core class that represents an array of bytes
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Gives a string representation in base 16
|
||||
* \return String in base 16
|
||||
*/
|
||||
|
||||
String ByteArray::ToHex() const
|
||||
{
|
||||
std::size_t length = m_array.size() * 2;
|
||||
|
||||
String hexOutput(length, '\0');
|
||||
for (std::size_t i = 0; i < m_array.size(); ++i)
|
||||
std::sprintf(&hexOutput[i * 2], "%02x", m_array[i]);
|
||||
|
||||
return hexOutput;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Output operator
|
||||
* \return The stream
|
||||
|
||||
@@ -906,5 +906,5 @@ namespace Nz
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,13 +159,13 @@ namespace Nz
|
||||
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
|
||||
std::size_t instanceCount = instances.size();
|
||||
std::size_t 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);
|
||||
std::size_t renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
|
||||
@@ -267,13 +267,13 @@ namespace Nz
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
std::size_t 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
|
||||
std::size_t spriteChain = 0; // Which chain of sprites are we treating
|
||||
std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
@@ -281,13 +281,13 @@ namespace Nz
|
||||
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);
|
||||
std::size_t spriteCount = 0;
|
||||
std::size_t 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::size_t 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;
|
||||
@@ -373,17 +373,17 @@ namespace Nz
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
std::size_t billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
do
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
|
||||
@@ -435,12 +435,12 @@ namespace Nz
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
std::size_t maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
std::size_t billboardCount = billboardVector.size();
|
||||
do
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4);
|
||||
@@ -584,13 +584,13 @@ namespace Nz
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch
|
||||
std::size_t instanceCount = instances.size();
|
||||
std::size_t 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);
|
||||
std::size_t renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
|
||||
@@ -383,7 +383,7 @@ namespace Nz
|
||||
auto& transparentModelData = currentLayer.transparentModelData;
|
||||
|
||||
// The material is transparent, we must draw this mesh using another way (after the rendering of opages objects while sorting them)
|
||||
unsigned int index = transparentModelData.size();
|
||||
std::size_t index = transparentModelData.size();
|
||||
transparentModelData.resize(index+1);
|
||||
|
||||
TransparentModelData& data = transparentModelData.back();
|
||||
@@ -603,7 +603,7 @@ namespace Nz
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
std::sort(layer.transparentModels.begin(), layer.transparentModels.end(), [&layer, &nearPlane, &viewerNormal] (unsigned int index1, unsigned int index2)
|
||||
std::sort(layer.transparentModels.begin(), layer.transparentModels.end(), [&layer, &nearPlane, &viewerNormal] (std::size_t index1, std::size_t index2)
|
||||
{
|
||||
const Spheref& sphere1 = layer.transparentModelData[index1].squaredBoundingSphere;
|
||||
const Spheref& sphere2 = layer.transparentModelData[index2].squaredBoundingSphere;
|
||||
@@ -672,7 +672,7 @@ namespace Nz
|
||||
BatchedBillboardEntry& entry = it->second;
|
||||
|
||||
auto& billboardVector = entry.billboards;
|
||||
unsigned int prevSize = billboardVector.size();
|
||||
std::size_t prevSize = billboardVector.size();
|
||||
billboardVector.resize(prevSize + count);
|
||||
|
||||
return &billboardVector[prevSize];
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace Nz
|
||||
Vector2f uv;
|
||||
};
|
||||
|
||||
unsigned int s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
|
||||
unsigned int s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
|
||||
std::size_t s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
|
||||
std::size_t s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -347,13 +347,13 @@ namespace Nz
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
std::size_t 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
|
||||
std::size_t spriteChain = 0; // Which chain of sprites are we treating
|
||||
std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
@@ -361,13 +361,13 @@ namespace Nz
|
||||
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);
|
||||
std::size_t spriteCount = 0;
|
||||
std::size_t maxSpriteCount = std::min<std::size_t>(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::size_t 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;
|
||||
@@ -450,17 +450,17 @@ namespace Nz
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
std::size_t billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
do
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
|
||||
@@ -512,12 +512,12 @@ namespace Nz
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
std::size_t maxBillboardPerDraw = std::min<std::size_t>(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
std::size_t billboardCount = billboardVector.size();
|
||||
do
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4);
|
||||
@@ -666,16 +666,16 @@ namespace Nz
|
||||
|
||||
// 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;
|
||||
std::size_t lightCount = m_renderQueue.directionalLights.size();
|
||||
std::size_t 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)
|
||||
std::size_t passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
|
||||
for (std::size_t pass = 0; pass < passCount; ++pass)
|
||||
{
|
||||
if (shaderUniforms->hasLightUniforms)
|
||||
{
|
||||
unsigned int renderedLightCount = std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
|
||||
std::size_t renderedLightCount = std::min<std::size_t>(lightCount, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS);
|
||||
lightCount -= renderedLightCount;
|
||||
|
||||
if (pass == 1)
|
||||
@@ -690,18 +690,18 @@ namespace Nz
|
||||
}
|
||||
|
||||
// Sends the uniforms
|
||||
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
for (std::size_t i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset * i, freeTextureUnit + i);
|
||||
}
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch
|
||||
std::size_t instanceCount = instances.size();
|
||||
std::size_t 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);
|
||||
std::size_t renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
@@ -726,16 +726,16 @@ namespace Nz
|
||||
// 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();
|
||||
std::size_t lightCount = m_lights.size();
|
||||
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
unsigned int lightIndex = 0;
|
||||
std::size_t 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)
|
||||
std::size_t passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
|
||||
for (std::size_t pass = 0; pass < passCount; ++pass)
|
||||
{
|
||||
lightCount -= std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
|
||||
lightCount -= std::min<std::size_t>(lightCount, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS);
|
||||
|
||||
if (pass == 1)
|
||||
{
|
||||
@@ -749,7 +749,7 @@ namespace Nz
|
||||
}
|
||||
|
||||
// Sends the light uniforms to the shader
|
||||
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
for (std::size_t i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i);
|
||||
|
||||
// And we draw
|
||||
@@ -835,7 +835,7 @@ namespace Nz
|
||||
{
|
||||
lightCount = std::min(m_renderQueue.directionalLights.size(), static_cast<decltype(m_renderQueue.directionalLights.size())>(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS));
|
||||
|
||||
for (unsigned int i = 0; i < lightCount; ++i)
|
||||
for (std::size_t i = 0; i < lightCount; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, i, shaderUniforms->lightOffset * i, freeTextureUnit++);
|
||||
}
|
||||
|
||||
@@ -874,7 +874,7 @@ namespace Nz
|
||||
float radius = modelData.squaredBoundingSphere.radius;
|
||||
ChooseLights(Spheref(position, radius), false);
|
||||
|
||||
for (unsigned int i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
for (std::size_t i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, i, shaderUniforms->lightOffset*i, freeTextureUnit++);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ namespace Nz
|
||||
void InstancedRenderable::UpdateData(InstanceData* instanceData) const
|
||||
{
|
||||
NazaraAssert(instanceData, "Invalid instance data");
|
||||
NazaraUnused(instanceData);
|
||||
}
|
||||
|
||||
InstancedRenderableLibrary::LibraryMap InstancedRenderable::s_library;
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if type is not supported
|
||||
*/
|
||||
|
||||
void ParticleDeclaration::EnableComponent(ParticleComponent component, ComponentType type, unsigned int offset)
|
||||
void ParticleDeclaration::EnableComponent(ParticleComponent component, ComponentType type, std::size_t offset)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (component > ParticleComponent_Max)
|
||||
@@ -145,7 +145,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if enumeration is equal to ParticleComponent_Unused
|
||||
*/
|
||||
|
||||
void ParticleDeclaration::GetComponent(ParticleComponent component, bool* enabled, ComponentType* type, unsigned int* offset) const
|
||||
void ParticleDeclaration::GetComponent(ParticleComponent component, bool* enabled, ComponentType* type, std::size_t* offset) const
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (component > ParticleComponent_Max)
|
||||
@@ -180,7 +180,7 @@ namespace Nz
|
||||
* \return Stride of the declaration
|
||||
*/
|
||||
|
||||
unsigned int ParticleDeclaration::GetStride() const
|
||||
std::size_t ParticleDeclaration::GetStride() const
|
||||
{
|
||||
return m_stride;
|
||||
}
|
||||
|
||||
@@ -74,11 +74,11 @@ namespace Nz
|
||||
if (emissionCount >= 1.f)
|
||||
{
|
||||
// We compute the maximum number of particles which can be emitted
|
||||
unsigned int emissionCountInt = static_cast<unsigned int>(emissionCount);
|
||||
unsigned int maxParticleCount = emissionCountInt * m_emissionCount;
|
||||
std::size_t emissionCountInt = static_cast<std::size_t>(emissionCount);
|
||||
std::size_t maxParticleCount = emissionCountInt * m_emissionCount;
|
||||
|
||||
// We get the number of particles that we are able to create (depending on the free space)
|
||||
unsigned int particleCount = std::min(maxParticleCount, system.GetMaxParticleCount() - system.GetParticleCount());
|
||||
std::size_t particleCount = std::min(maxParticleCount, system.GetMaxParticleCount() - system.GetParticleCount());
|
||||
if (particleCount == 0)
|
||||
return;
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Nz
|
||||
* \return Current emission count
|
||||
*/
|
||||
|
||||
unsigned int ParticleEmitter::GetEmissionCount() const
|
||||
std::size_t ParticleEmitter::GetEmissionCount() const
|
||||
{
|
||||
return m_emissionCount;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ namespace Nz
|
||||
* \param count Emission count
|
||||
*/
|
||||
|
||||
void ParticleEmitter::SetEmissionCount(unsigned int count)
|
||||
void ParticleEmitter::SetEmissionCount(std::size_t count)
|
||||
{
|
||||
m_emissionCount = count;
|
||||
}
|
||||
|
||||
@@ -142,11 +142,10 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if renderQueue is invalid
|
||||
*/
|
||||
|
||||
void ParticleGroup::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");
|
||||
NazaraUnused(transformMatrix);
|
||||
|
||||
if (m_particleCount > 0)
|
||||
{
|
||||
@@ -215,7 +214,7 @@ namespace Nz
|
||||
if (m_particleCount + count > m_maxParticleCount)
|
||||
return nullptr;
|
||||
|
||||
unsigned int particlesIndex = m_particleCount;
|
||||
std::size_t particlesIndex = m_particleCount;
|
||||
m_particleCount += count;
|
||||
|
||||
return &m_buffer[particlesIndex * m_particleSize];
|
||||
@@ -264,7 +263,7 @@ namespace Nz
|
||||
* \return Current maximum number
|
||||
*/
|
||||
|
||||
unsigned int ParticleGroup::GetMaxParticleCount() const
|
||||
std::size_t ParticleGroup::GetMaxParticleCount() const
|
||||
{
|
||||
return m_maxParticleCount;
|
||||
}
|
||||
@@ -274,7 +273,7 @@ namespace Nz
|
||||
* \return Current number
|
||||
*/
|
||||
|
||||
unsigned int ParticleGroup::GetParticleCount() const
|
||||
std::size_t ParticleGroup::GetParticleCount() const
|
||||
{
|
||||
return m_particleCount;
|
||||
}
|
||||
@@ -284,7 +283,7 @@ namespace Nz
|
||||
* \return Current size
|
||||
*/
|
||||
|
||||
unsigned int ParticleGroup::GetParticleSize() const
|
||||
std::size_t ParticleGroup::GetParticleSize() const
|
||||
{
|
||||
return m_particleSize;
|
||||
}
|
||||
@@ -295,7 +294,7 @@ namespace Nz
|
||||
* \param index Index of the particle
|
||||
*/
|
||||
|
||||
void ParticleGroup::KillParticle(unsigned int index)
|
||||
void ParticleGroup::KillParticle(std::size_t index)
|
||||
{
|
||||
///FIXME: Verify the index
|
||||
|
||||
@@ -402,10 +401,8 @@ namespace Nz
|
||||
* \param transformMatrix Matrix transformation for our bounding volume
|
||||
*/
|
||||
|
||||
void ParticleGroup::UpdateBoundingVolume(const Matrix4f& transformMatrix)
|
||||
void ParticleGroup::UpdateBoundingVolume(const Matrix4f& /*transformMatrix*/)
|
||||
{
|
||||
NazaraUnused(transformMatrix);
|
||||
|
||||
// Nothing to do here (our bounding volume is global)
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace Nz
|
||||
* \return Number of techniques
|
||||
*/
|
||||
|
||||
unsigned int RenderTechniques::GetCount()
|
||||
std::size_t RenderTechniques::GetCount()
|
||||
{
|
||||
return s_renderTechniques.size();
|
||||
}
|
||||
|
||||
@@ -44,6 +44,64 @@ namespace Nz
|
||||
m_boundingVolume.Set(-origin, m_size.x*Vector3f::Right() + m_size.y*Vector3f::Down() - origin);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the material of the sprite from a name
|
||||
*
|
||||
* Tries to get a material from the MaterialLibrary and then the MaterialManager (which will treat the name as a path)
|
||||
* Fails if the texture name is not a part of the MaterialLibrary nor the MaterialManager (which fails if it couldn't load the texture from its filepath)
|
||||
*
|
||||
* \param materialName Named texture for the material
|
||||
* \param resizeSprite Should the sprite be resized to the material diffuse map size?
|
||||
*
|
||||
* \return True if the material was found or loaded from its name/path, false if it couldn't
|
||||
*/
|
||||
bool Sprite::SetMaterial(String materialName, bool resizeSprite)
|
||||
{
|
||||
MaterialRef material = MaterialLibrary::Query(materialName);
|
||||
if (!material)
|
||||
{
|
||||
material = MaterialManager::Get(materialName);
|
||||
if (!material)
|
||||
{
|
||||
NazaraError("Failed to get material \"" + materialName + "\"");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SetMaterial(std::move(material), resizeSprite);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the texture of the sprite from a name
|
||||
*
|
||||
* Tries to get a texture from the TextureLibrary and then the TextureManager (which will treat the name as a path)
|
||||
* Fails if the texture name is not a part of the TextureLibrary nor the TextureManager (which fails if it couldn't load the texture from its filepath)
|
||||
*
|
||||
* \param textureName Named texture for the sprite
|
||||
* \param resizeSprite Should the sprite be resized to the texture size?
|
||||
*
|
||||
* \return True if the texture was found or loaded from its name/path, false if it couldn't
|
||||
*
|
||||
* \remark The sprite material gets copied to prevent accidentally changing other drawable materials
|
||||
*/
|
||||
bool Sprite::SetTexture(String textureName, bool resizeSprite)
|
||||
{
|
||||
TextureRef texture = TextureLibrary::Query(textureName);
|
||||
if (!texture)
|
||||
{
|
||||
texture = TextureManager::Get(textureName);
|
||||
if (!texture)
|
||||
{
|
||||
NazaraError("Failed to get texture \"" + textureName + "\"");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SetTexture(std::move(texture), resizeSprite);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the data of the sprite
|
||||
*
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace Nz
|
||||
if (!m_buffer)
|
||||
m_buffer = std::make_unique<ByteArray>();
|
||||
|
||||
m_buffer->Resize(static_cast<std::size_t>(cursorPos));
|
||||
m_buffer->Resize(minCapacity);
|
||||
|
||||
m_memoryStream.SetBuffer(m_buffer.get(), openMode);
|
||||
m_memoryStream.SetCursorPos(cursorPos);
|
||||
|
||||
@@ -385,7 +385,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraError because it is a special stream
|
||||
*/
|
||||
|
||||
bool TcpClient::SetCursorPos(UInt64 offset)
|
||||
bool TcpClient::SetCursorPos(UInt64 /*offset*/)
|
||||
{
|
||||
NazaraError("SetCursorPos() cannot be used on sequential streams");
|
||||
return false;
|
||||
|
||||
@@ -437,6 +437,10 @@ namespace Nz
|
||||
|
||||
return result;
|
||||
#else
|
||||
NazaraUnused(fdarray);
|
||||
NazaraUnused(nfds);
|
||||
NazaraUnused(timeout);
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NotSupported;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
namespace Nz
|
||||
{
|
||||
Collider2D::~Collider2D() = default;
|
||||
|
||||
|
||||
/******************************** BoxCollider2D *********************************/
|
||||
|
||||
BoxCollider2D::BoxCollider2D(const Vector2f& size, float radius) :
|
||||
@@ -84,4 +84,25 @@ namespace Nz
|
||||
{
|
||||
return std::vector<cpShape*>();
|
||||
}
|
||||
|
||||
/******************************** SegmentCollider2D *********************************/
|
||||
|
||||
float SegmentCollider2D::ComputeInertialMatrix(float mass) const
|
||||
{
|
||||
return static_cast<float>(cpMomentForSegment(mass, cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness));
|
||||
}
|
||||
|
||||
ColliderType2D SegmentCollider2D::GetType() const
|
||||
{
|
||||
return ColliderType2D_Segment;
|
||||
}
|
||||
|
||||
std::vector<cpShape*> SegmentCollider2D::CreateShapes(RigidBody2D* body) const
|
||||
{
|
||||
std::vector<cpShape*> shapes;
|
||||
shapes.push_back(cpSegmentShapeNew(body->GetHandle(), cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness));
|
||||
|
||||
return shapes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// This file is part of the "Nazara Engine - Physics 2D module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Physics3D/Config.hpp>
|
||||
#if NAZARA_PHYSICS_MANAGE_MEMORY
|
||||
#include <Nazara/Physics2D/Config.hpp>
|
||||
#if NAZARA_PHYSICS2D_MANAGE_MEMORY
|
||||
|
||||
#include <Nazara/Core/MemoryManager.hpp>
|
||||
#include <new> // Nécessaire ?
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Nz
|
||||
Vector2f PhysWorld2D::GetGravity() const
|
||||
{
|
||||
cpVect gravity = cpSpaceGetGravity(m_handle);
|
||||
return Vector2f(gravity.x, gravity.y);
|
||||
return Vector2f(Vector2<cpFloat>(gravity.x, gravity.y));
|
||||
}
|
||||
|
||||
cpSpace* PhysWorld2D::GetHandle() const
|
||||
|
||||
@@ -22,13 +22,11 @@ namespace Nz
|
||||
m_geom(),
|
||||
m_world(world),
|
||||
m_gravityFactor(1.f),
|
||||
m_mass(0.f)
|
||||
m_mass(1.f)
|
||||
{
|
||||
NazaraAssert(m_world, "Invalid world");
|
||||
|
||||
m_handle = cpBodyNew(0.f, 0.f);
|
||||
cpBodySetUserData(m_handle, this);
|
||||
cpSpaceAddBody(m_world->GetHandle(), m_handle);
|
||||
Create();
|
||||
|
||||
SetGeom(geom);
|
||||
SetMass(mass);
|
||||
@@ -43,9 +41,7 @@ namespace Nz
|
||||
NazaraAssert(m_world, "Invalid world");
|
||||
NazaraAssert(m_geom, "Invalid geometry");
|
||||
|
||||
m_handle = cpBodyNew(0.f, 0.f);
|
||||
cpBodySetUserData(m_handle, this);
|
||||
cpSpaceAddBody(m_world->GetHandle(), m_handle);
|
||||
Create();
|
||||
|
||||
SetGeom(object.GetGeom());
|
||||
SetMass(object.GetMass());
|
||||
@@ -77,7 +73,7 @@ namespace Nz
|
||||
switch (coordSys)
|
||||
{
|
||||
case CoordSys_Global:
|
||||
cpBodyApplyForceAtWorldPoint(m_handle, cpv(force.x, force.y), cpv(force.x, force.y));
|
||||
cpBodyApplyForceAtWorldPoint(m_handle, cpv(force.x, force.y), cpv(point.x, point.y));
|
||||
break;
|
||||
|
||||
case CoordSys_Local:
|
||||
@@ -169,19 +165,60 @@ namespace Nz
|
||||
cpBodySetAngularVelocity(m_handle, angularVelocity);
|
||||
}
|
||||
|
||||
void RigidBody2D::SetGeom(Collider2DRef geom)
|
||||
{
|
||||
// We have no public way of getting rid of an existing geom without removing the whole body
|
||||
// So let's save some attributes of the body, destroy it and rebuild it
|
||||
if (m_geom)
|
||||
{
|
||||
cpVect pos = cpBodyGetPosition(m_handle);
|
||||
cpFloat mass = cpBodyGetMass(m_handle);
|
||||
cpFloat moment = cpBodyGetMoment(m_handle);
|
||||
cpFloat rot = cpBodyGetAngle(m_handle);
|
||||
cpVect vel = cpBodyGetVelocity(m_handle);
|
||||
|
||||
Destroy();
|
||||
Create(mass, moment);
|
||||
|
||||
cpBodySetAngle(m_handle, rot);
|
||||
cpBodySetPosition(m_handle, pos);
|
||||
cpBodySetVelocity(m_handle, vel);
|
||||
}
|
||||
|
||||
if (geom)
|
||||
m_geom = geom;
|
||||
else
|
||||
m_geom = NullCollider2D::New();
|
||||
|
||||
m_shapes = m_geom->CreateShapes(this);
|
||||
|
||||
cpSpace* space = m_world->GetHandle();
|
||||
for (cpShape* shape : m_shapes)
|
||||
cpSpaceAddShape(space, shape);
|
||||
|
||||
cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass));
|
||||
}
|
||||
|
||||
void RigidBody2D::SetMass(float mass)
|
||||
{
|
||||
if (m_mass > 0.f)
|
||||
{
|
||||
if (mass > 0.f)
|
||||
{
|
||||
cpBodySetMass(m_handle, mass);
|
||||
cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass));
|
||||
}
|
||||
else
|
||||
cpBodySetType(m_handle, CP_BODY_TYPE_STATIC);
|
||||
}
|
||||
else if (mass > 0.f)
|
||||
{
|
||||
if (cpBodyGetType(m_handle) == CP_BODY_TYPE_STATIC)
|
||||
{
|
||||
cpBodySetType(m_handle, CP_BODY_TYPE_DYNAMIC);
|
||||
cpBodySetMass(m_handle, mass);
|
||||
cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass));
|
||||
}
|
||||
}
|
||||
|
||||
m_mass = mass;
|
||||
@@ -196,6 +233,8 @@ namespace Nz
|
||||
void RigidBody2D::SetPosition(const Vector2f& position)
|
||||
{
|
||||
cpBodySetPosition(m_handle, cpv(position.x, position.y));
|
||||
if (cpBodyGetType(m_handle) == CP_BODY_TYPE_STATIC)
|
||||
cpSpaceReindexShapesForBody(m_world->GetHandle(), m_handle);
|
||||
}
|
||||
|
||||
void RigidBody2D::SetRotation(float rotation)
|
||||
@@ -230,22 +269,26 @@ namespace Nz
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RigidBody2D::Create(float mass, float moment)
|
||||
{
|
||||
m_handle = cpBodyNew(mass, moment);
|
||||
cpBodySetUserData(m_handle, this);
|
||||
cpSpaceAddBody(m_world->GetHandle(), m_handle);
|
||||
}
|
||||
|
||||
void RigidBody2D::Destroy()
|
||||
{
|
||||
cpSpace* space = m_world->GetHandle();
|
||||
for (cpShape* shape : m_shapes)
|
||||
{
|
||||
cpSpaceRemoveShape(space, shape);
|
||||
cpShapeFree(shape);
|
||||
}
|
||||
|
||||
if (m_handle)
|
||||
{
|
||||
cpSpaceRemoveBody(space, m_handle);
|
||||
cpBodyFree(m_handle);
|
||||
}
|
||||
|
||||
void RigidBody2D::SetGeom(Collider2DRef geom)
|
||||
{
|
||||
if (geom)
|
||||
m_geom = geom;
|
||||
else
|
||||
m_geom = NullCollider2D::New();
|
||||
|
||||
m_shapes = m_geom->CreateShapes(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Physics3D/Config.hpp>
|
||||
#if NAZARA_PHYSICS_MANAGE_MEMORY
|
||||
#if NAZARA_PHYSICS3D_MANAGE_MEMORY
|
||||
|
||||
#include <Nazara/Core/MemoryManager.hpp>
|
||||
#include <new> // Nécessaire ?
|
||||
|
||||
855
src/Nazara/Renderer/RenderTexture.cpp
Normal file
855
src/Nazara/Renderer/RenderTexture.cpp
Normal file
@@ -0,0 +1,855 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderTexture.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderBuffer.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct Attachment
|
||||
{
|
||||
NazaraSlot(RenderBuffer, OnRenderBufferDestroy, renderBufferDestroySlot);
|
||||
NazaraSlot(Texture, OnTextureDestroy, textureDestroySlot);
|
||||
|
||||
RenderBufferRef buffer;
|
||||
TextureRef texture;
|
||||
|
||||
AttachmentPoint attachmentPoint;
|
||||
bool isBuffer;
|
||||
bool isUsed = false;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
};
|
||||
|
||||
unsigned int attachmentIndex[AttachmentPoint_Max+1] =
|
||||
{
|
||||
3, // AttachmentPoint_Color
|
||||
0, // AttachmentPoint_Depth
|
||||
1, // AttachmentPoint_DepthStencil
|
||||
2 // AttachmentPoint_Stencil
|
||||
};
|
||||
|
||||
AttachmentPoint FormatTypeToAttachment(PixelFormatType format)
|
||||
{
|
||||
const PixelFormatInfo& info = PixelFormat::GetInfo(format);
|
||||
switch (info.content)
|
||||
{
|
||||
case PixelFormatContent_ColorRGBA:
|
||||
return AttachmentPoint_Color;
|
||||
|
||||
case PixelFormatContent_DepthStencil:
|
||||
return (!info.greenMask.TestAny()) ? AttachmentPoint_Depth : AttachmentPoint_DepthStencil;
|
||||
|
||||
case PixelFormatContent_Stencil:
|
||||
return AttachmentPoint_Stencil;
|
||||
|
||||
case PixelFormatContent_Undefined:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraInternalError("Unexpected pixel format content: 0x" + String::Number(info.content, 16));
|
||||
return AttachmentPoint_Max;
|
||||
}
|
||||
|
||||
GLuint lockedPrevious = 0;
|
||||
UInt8 lockedLevel = 0;
|
||||
}
|
||||
|
||||
struct RenderTextureImpl
|
||||
{
|
||||
NazaraSlot(Context, OnContextDestroy, contextDestroySlot);
|
||||
|
||||
GLuint fbo;
|
||||
std::vector<Attachment> attachments;
|
||||
std::vector<UInt8> colorTargets;
|
||||
mutable std::vector<GLenum> drawBuffers;
|
||||
const Context* context;
|
||||
bool complete = false;
|
||||
bool userDefinedTargets = false;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
};
|
||||
|
||||
bool RenderTexture::AttachBuffer(AttachmentPoint attachmentPoint, UInt8 index, RenderBuffer* buffer)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= Renderer::GetMaxColorAttachments())
|
||||
{
|
||||
NazaraError("Color index is over max color attachments (" + String::Number(index) + " >= " + String::Number(Renderer::GetMaxColorAttachments()) + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer || !buffer->IsValid())
|
||||
{
|
||||
NazaraError("Invalid render buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[AttachmentPoint_DepthStencil];
|
||||
if (m_impl->attachments.size() > depthStencilIndex && m_impl->attachments[depthStencilIndex].isUsed)
|
||||
{
|
||||
if (attachmentPoint == AttachmentPoint_Depth)
|
||||
{
|
||||
NazaraError("Depth target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
else if (attachmentPoint == AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Stencil target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AttachmentPoint targetAttachmentPoint = FormatTypeToAttachment(buffer->GetFormat());
|
||||
if (targetAttachmentPoint != attachmentPoint && targetAttachmentPoint != AttachmentPoint_DepthStencil &&
|
||||
attachmentPoint != AttachmentPoint_Depth && attachmentPoint != AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, buffer->GetOpenGLID());
|
||||
|
||||
Unlock();
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
m_impl->attachments.resize(attachIndex+1);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachIndex];
|
||||
attachment.attachmentPoint = attachmentPoint;
|
||||
attachment.buffer = buffer;
|
||||
attachment.renderBufferDestroySlot.Connect(buffer->OnRenderBufferDestroy, std::bind(&RenderTexture::OnRenderBufferDestroy, this, std::placeholders::_1, attachIndex));
|
||||
attachment.isBuffer = true;
|
||||
attachment.isUsed = true;
|
||||
attachment.height = buffer->GetHeight();
|
||||
attachment.width = buffer->GetWidth();
|
||||
|
||||
InvalidateSize();
|
||||
InvalidateTargets();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::AttachBuffer(AttachmentPoint attachmentPoint, UInt8 index, PixelFormatType format, unsigned int width, unsigned int height)
|
||||
{
|
||||
RenderBufferRef renderBuffer = RenderBuffer::New();
|
||||
if (!renderBuffer->Create(format, width, height))
|
||||
{
|
||||
NazaraError("Failed to create RenderBuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AttachBuffer(attachmentPoint, index, renderBuffer))
|
||||
{
|
||||
NazaraError("Failed to attach buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::AttachTexture(AttachmentPoint attachmentPoint, UInt8 index, Texture* texture, unsigned int z)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= Renderer::GetMaxColorAttachments())
|
||||
{
|
||||
NazaraError("Color index is over max color attachments (" + String::Number(index) + " >= " + String::Number(Renderer::GetMaxColorAttachments()) + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (attachmentPoint == AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Targeting stencil-only textures is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[AttachmentPoint_DepthStencil];
|
||||
if (attachmentPoint == AttachmentPoint_Depth && m_impl->attachments.size() > depthStencilIndex &&
|
||||
m_impl->attachments[depthStencilIndex].isUsed)
|
||||
{
|
||||
NazaraError("Depth target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!texture || !texture->IsValid())
|
||||
{
|
||||
NazaraError("Invalid texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depth = (texture->GetType() == ImageType_Cubemap) ? 6 : texture->GetDepth();
|
||||
if (z >= depth)
|
||||
{
|
||||
NazaraError("Z value exceeds depth (" + String::Number(z) + " >= (" + String::Number(depth) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachmentPoint targetAttachmentPoint = FormatTypeToAttachment(texture->GetFormat());
|
||||
if (targetAttachmentPoint != attachmentPoint && targetAttachmentPoint != AttachmentPoint_DepthStencil &&
|
||||
attachmentPoint != AttachmentPoint_Depth && attachmentPoint != AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
switch (texture->GetType())
|
||||
{
|
||||
case ImageType_1D:
|
||||
glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_1D, texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
|
||||
case ImageType_1D_Array:
|
||||
case ImageType_2D_Array:
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, texture->GetOpenGLID(), 0, z);
|
||||
break;
|
||||
|
||||
case ImageType_2D:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_2D, texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
|
||||
case ImageType_3D:
|
||||
glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_3D, texture->GetOpenGLID(), 0, z);
|
||||
break;
|
||||
|
||||
case ImageType_Cubemap:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, OpenGL::CubemapFace[z], texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
m_impl->attachments.resize(attachIndex+1);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachIndex];
|
||||
attachment.attachmentPoint = attachmentPoint;
|
||||
attachment.isBuffer = false;
|
||||
attachment.isUsed = true;
|
||||
attachment.height = texture->GetHeight();
|
||||
attachment.texture = texture;
|
||||
attachment.textureDestroySlot.Connect(texture->OnTextureDestroy, std::bind(&RenderTexture::OnTextureDestroy, this, std::placeholders::_1, attachIndex));
|
||||
attachment.width = texture->GetWidth();
|
||||
|
||||
InvalidateSize();
|
||||
InvalidateTargets();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::Create(bool lock)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<RenderTextureImpl> impl(new RenderTextureImpl);
|
||||
|
||||
impl->fbo = 0;
|
||||
glGenFramebuffers(1, &impl->fbo);
|
||||
|
||||
if (!impl->fbo)
|
||||
{
|
||||
NazaraError("Failed to create framebuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
m_impl->context = Context::GetCurrent();
|
||||
m_impl->contextDestroySlot.Connect(m_impl->context->OnContextDestroy, this, &RenderTexture::OnContextDestroy);
|
||||
|
||||
m_checked = false;
|
||||
m_drawBuffersUpdated = true;
|
||||
m_sizeUpdated = false;
|
||||
m_targetsUpdated = true;
|
||||
|
||||
if (lock)
|
||||
{
|
||||
// En cas d'exception, la ressource sera quand même libérée
|
||||
CallOnExit onExit([this] ()
|
||||
{
|
||||
Destroy();
|
||||
});
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
}
|
||||
|
||||
OnRenderTargetParametersChange(this);
|
||||
OnRenderTargetSizeChange(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
if (IsActive())
|
||||
Renderer::SetTarget(nullptr);
|
||||
|
||||
// Le FBO devant être supprimé dans son contexte d'origine, nous déléguons sa suppression à la classe OpenGL
|
||||
// Celle-ci va libérer le FBO dès que possible (la prochaine fois que son contexte d'origine sera actif)
|
||||
OpenGL::DeleteFrameBuffer(m_impl->context, m_impl->fbo);
|
||||
|
||||
delete m_impl; // Enlève également une références sur les Texture/RenderBuffer
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTexture::Detach(AttachmentPoint attachmentPoint, UInt8 index)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color && index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
return;
|
||||
|
||||
Attachment& attachement = m_impl->attachments[attachIndex];
|
||||
if (!attachement.isUsed)
|
||||
return;
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return;
|
||||
}
|
||||
|
||||
attachement.isUsed = false;
|
||||
|
||||
if (attachement.isBuffer)
|
||||
{
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, 0);
|
||||
|
||||
attachement.buffer = nullptr;
|
||||
attachement.renderBufferDestroySlot.Disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (glFramebufferTexture)
|
||||
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, 0, 0);
|
||||
else
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, 0, 0, 0);
|
||||
|
||||
attachement.texture = nullptr;
|
||||
attachement.textureDestroySlot.Disconnect();
|
||||
}
|
||||
|
||||
InvalidateSize();
|
||||
|
||||
if (attachement.attachmentPoint == AttachmentPoint_Color)
|
||||
InvalidateTargets();
|
||||
|
||||
Unlock();
|
||||
|
||||
m_checked = false;
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetHeight() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return m_impl->height;
|
||||
}
|
||||
|
||||
RenderTargetParameters RenderTexture::GetParameters() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
///TODO
|
||||
return RenderTargetParameters();
|
||||
}
|
||||
|
||||
Vector2ui RenderTexture::GetSize() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return Vector2ui(m_impl->width, m_impl->height);
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetWidth() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return m_impl->width;
|
||||
}
|
||||
|
||||
bool RenderTexture::IsComplete() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_checked)
|
||||
{
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
|
||||
Unlock();
|
||||
|
||||
m_impl->complete = false;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
m_impl->complete = true;
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
NazaraError("Incomplete attachment");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
NazaraInternalError("Incomplete draw buffer");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
NazaraInternalError("Incomplete read buffer");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
NazaraError("Incomplete missing attachment");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
NazaraError("Incomplete multisample");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||
NazaraError("Incomplete layer targets");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
NazaraError("Render texture has unsupported attachments");
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Unknown error");
|
||||
}
|
||||
|
||||
m_checked = true;
|
||||
}
|
||||
|
||||
return m_impl->complete;
|
||||
}
|
||||
|
||||
bool RenderTexture::IsRenderable() const
|
||||
{
|
||||
return IsComplete() && !m_impl->attachments.empty();
|
||||
}
|
||||
|
||||
bool RenderTexture::Lock() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lockedLevel++ == 0)
|
||||
{
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous);
|
||||
|
||||
lockedPrevious = previous;
|
||||
|
||||
if (lockedPrevious != m_impl->fbo)
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::SetColorTargets(const UInt8* targets, unsigned int targetCount) const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
for (unsigned int i = 0; i < targetCount; ++i)
|
||||
{
|
||||
unsigned int index = attachmentIndex[AttachmentPoint_Color] + targets[i];
|
||||
if (index >= m_impl->attachments.size() || !m_impl->attachments[index].isUsed)
|
||||
{
|
||||
NazaraError("Target " + String::Number(targets[i]) + " not attached");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->colorTargets.resize(targetCount);
|
||||
std::memcpy(&m_impl->colorTargets[0], targets, targetCount*sizeof(UInt8));
|
||||
|
||||
m_impl->userDefinedTargets = true;
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::SetColorTargets(const std::initializer_list<UInt8>& targets) const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
for (UInt8 target : targets)
|
||||
{
|
||||
unsigned int index = attachmentIndex[AttachmentPoint_Color] + target;
|
||||
if (index >= m_impl->attachments.size() || !m_impl->attachments[index].isUsed)
|
||||
{
|
||||
NazaraError("Target " + String::Number(target) + " not attached");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->colorTargets.resize(targets.size());
|
||||
|
||||
UInt8* ptr = &m_impl->colorTargets[0];
|
||||
for (UInt8 index : targets)
|
||||
*ptr++ = index;
|
||||
|
||||
m_impl->userDefinedTargets = true;
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::Unlock() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lockedLevel == 0)
|
||||
{
|
||||
NazaraWarning("Unlock called on non-locked texture");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--lockedLevel == 0 && lockedPrevious != m_impl->fbo) // Ici, il est important qu'un FBO soit débindé si l'ancien était 0
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lockedPrevious);
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetOpenGLID() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->fbo;
|
||||
}
|
||||
|
||||
bool RenderTexture::HasContext() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderTexture::Blit(RenderTexture* src, Rectui srcRect, RenderTexture* dst, Rectui dstRect, UInt32 buffers, bool bilinearFilter)
|
||||
{
|
||||
NazaraAssert(src && src->IsValid(), "Invalid source render texture");
|
||||
NazaraAssert(dst && dst->IsValid(), "Invalid destination render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (srcRect.x+srcRect.width > src->GetWidth() || srcRect.y+srcRect.height > src->GetHeight())
|
||||
{
|
||||
NazaraError("Source rectangle dimensions are out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dstRect.x+dstRect.width > dst->GetWidth() || dstRect.y+dstRect.height > dst->GetHeight())
|
||||
{
|
||||
NazaraError("Destination rectangle dimensions are out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bilinearFilter && (buffers & RendererBuffer_Depth || buffers & RendererBuffer_Stencil))
|
||||
{
|
||||
NazaraError("Filter cannot be bilinear when blitting depth/stencil buffers");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
GLbitfield mask = 0;
|
||||
if (buffers & RendererBuffer_Color)
|
||||
mask |= GL_COLOR_BUFFER_BIT;
|
||||
|
||||
if (buffers & RendererBuffer_Depth)
|
||||
mask |= GL_DEPTH_BUFFER_BIT;
|
||||
|
||||
if (buffers & RendererBuffer_Stencil)
|
||||
mask |= GL_STENCIL_BUFFER_BIT;
|
||||
|
||||
GLint previousDrawBuffer, previousReadBuffer;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previousDrawBuffer);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &previousReadBuffer);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->GetOpenGLID());
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->GetOpenGLID());
|
||||
|
||||
glBlitFramebuffer(srcRect.x, srcRect.y, srcRect.x + srcRect.width, srcRect.y + srcRect.height,
|
||||
dstRect.x, dstRect.y, dstRect.x + dstRect.width, dstRect.y + dstRect.height,
|
||||
mask, (bilinearFilter) ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, previousDrawBuffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, previousReadBuffer);
|
||||
}
|
||||
|
||||
bool RenderTexture::Activate() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
|
||||
|
||||
m_drawBuffersUpdated = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::Desactivate() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glFlush();
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void RenderTexture::EnsureTargetUpdated() const
|
||||
{
|
||||
if (!m_drawBuffersUpdated)
|
||||
UpdateDrawBuffers();
|
||||
|
||||
for (UInt8 index : m_impl->colorTargets)
|
||||
{
|
||||
Attachment& attachment = m_impl->attachments[attachmentIndex[AttachmentPoint_Color] + index];
|
||||
if (!attachment.isBuffer)
|
||||
attachment.texture->InvalidateMipmaps();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTexture::OnContextDestroy(const Context* context)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraUnused(context);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (m_impl->context != context)
|
||||
{
|
||||
NazaraInternalError("Not listening to " + String::Pointer(context));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void RenderTexture::OnRenderBufferDestroy(const RenderBuffer* renderBuffer, unsigned int attachmentIndex)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraAssert(attachmentIndex < m_impl->attachments.size(), "Invalid attachment index");
|
||||
NazaraAssert(m_impl->attachments[attachmentIndex].isBuffer, "Invalid attachment state");
|
||||
NazaraUnused(renderBuffer);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachmentIndex];
|
||||
attachment.buffer = nullptr;
|
||||
attachment.isUsed = false;
|
||||
attachment.renderBufferDestroySlot.Disconnect();
|
||||
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::OnTextureDestroy(const Texture* texture, unsigned int attachmentIndex)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraAssert(attachmentIndex < m_impl->attachments.size(), "Invalid attachment index");
|
||||
NazaraAssert(!m_impl->attachments[attachmentIndex].isBuffer, "Invalid attachment state");
|
||||
NazaraUnused(texture);
|
||||
NazaraUnused(attachmentIndex);
|
||||
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateDrawBuffers() const
|
||||
{
|
||||
if (!m_targetsUpdated)
|
||||
UpdateTargets();
|
||||
|
||||
glDrawBuffers(m_impl->drawBuffers.size(), &m_impl->drawBuffers[0]);
|
||||
|
||||
m_drawBuffersUpdated = true;
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateSize() const
|
||||
{
|
||||
m_impl->width = 0;
|
||||
m_impl->height = 0;
|
||||
for (Attachment& attachment : m_impl->attachments)
|
||||
{
|
||||
if (attachment.isUsed)
|
||||
{
|
||||
m_impl->height = std::max(m_impl->height, attachment.height);
|
||||
m_impl->width = std::max(m_impl->width, attachment.width);
|
||||
}
|
||||
}
|
||||
|
||||
m_sizeUpdated = true;
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateTargets() const
|
||||
{
|
||||
if (!m_impl->userDefinedTargets)
|
||||
{
|
||||
m_impl->colorTargets.clear();
|
||||
|
||||
unsigned int colorIndex = 0;
|
||||
for (unsigned int index = attachmentIndex[AttachmentPoint_Color]; index < m_impl->attachments.size(); ++index)
|
||||
m_impl->colorTargets.push_back(colorIndex++);
|
||||
}
|
||||
|
||||
if (m_impl->colorTargets.empty())
|
||||
{
|
||||
m_impl->drawBuffers.resize(1);
|
||||
m_impl->drawBuffers[0] = GL_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_impl->drawBuffers.resize(m_impl->colorTargets.size());
|
||||
GLenum* ptr = &m_impl->drawBuffers[0];
|
||||
for (UInt8 index : m_impl->colorTargets)
|
||||
*ptr++ = GL_COLOR_ATTACHMENT0 + index;
|
||||
}
|
||||
|
||||
m_targetsUpdated = true;
|
||||
}
|
||||
}
|
||||
@@ -742,7 +742,7 @@ namespace Nz
|
||||
Vector3f halfLengths = lengths/2.f;
|
||||
|
||||
// Face +X
|
||||
transform.MakeTransform(Vector3f::UnitX() * halfLengths.x, EulerAnglesf(-90.f, 0.f, -90.f));
|
||||
transform.MakeTransform(Vector3f::UnitX() * halfLengths.x, EulerAnglesf(-90.f, -90.f, 180.f));
|
||||
GeneratePlane(Vector2ui(subdivision.z, subdivision.y), Vector2f(lengths.z, lengths.y), Matrix4f::ConcatenateAffine(matrix, transform), textureCoords, vertexPointers, indices, nullptr, indexOffset);
|
||||
indexOffset += xVertexCount;
|
||||
indices += xIndexCount;
|
||||
@@ -776,7 +776,7 @@ namespace Nz
|
||||
vertexPointers.uvPtr += yVertexCount;
|
||||
|
||||
// Face +Z
|
||||
transform.MakeTransform(Vector3f::UnitZ() * halfLengths.z, EulerAnglesf(-90.f, 90.f, 90.f));
|
||||
transform.MakeTransform(Vector3f::UnitZ() * halfLengths.z, EulerAnglesf(90.f, 0.f, 0.f));
|
||||
GeneratePlane(Vector2ui(subdivision.x, subdivision.y), Vector2f(lengths.x, lengths.y), Matrix4f::ConcatenateAffine(matrix, transform), textureCoords, vertexPointers, indices, nullptr, indexOffset);
|
||||
indexOffset += zVertexCount;
|
||||
indices += zIndexCount;
|
||||
@@ -793,7 +793,7 @@ namespace Nz
|
||||
vertexPointers.uvPtr += zVertexCount;
|
||||
|
||||
// Face -X
|
||||
transform.MakeTransform(-Vector3f::UnitX() * halfLengths.x, EulerAnglesf(-90.f, 0.f, 90.f));
|
||||
transform.MakeTransform(-Vector3f::UnitX() * halfLengths.x, EulerAnglesf(-90.f, 90.f, 180.f));
|
||||
GeneratePlane(Vector2ui(subdivision.z, subdivision.y), Vector2f(lengths.z, lengths.y), Matrix4f::ConcatenateAffine(matrix, transform), textureCoords, vertexPointers, indices, nullptr, indexOffset);
|
||||
indexOffset += xVertexCount;
|
||||
indices += xIndexCount;
|
||||
@@ -810,7 +810,7 @@ namespace Nz
|
||||
vertexPointers.uvPtr += xVertexCount;
|
||||
|
||||
// Face -Y
|
||||
transform.MakeTransform(-Vector3f::UnitY() * halfLengths.y, EulerAnglesf(0.f, 0.f, 180.f));
|
||||
transform.MakeTransform(-Vector3f::UnitY() * halfLengths.y, EulerAnglesf(0.f, 180.f, 180.f));
|
||||
GeneratePlane(Vector2ui(subdivision.x, subdivision.z), Vector2f(lengths.x, lengths.z), Matrix4f::ConcatenateAffine(matrix, transform), textureCoords, vertexPointers, indices, nullptr, indexOffset);
|
||||
indexOffset += yVertexCount;
|
||||
indices += yIndexCount;
|
||||
@@ -827,7 +827,7 @@ namespace Nz
|
||||
vertexPointers.uvPtr += yVertexCount;
|
||||
|
||||
// Face -Z
|
||||
transform.MakeTransform(-Vector3f::UnitZ() * halfLengths.z, EulerAnglesf(-90.f, -90.f, 90.f));
|
||||
transform.MakeTransform(-Vector3f::UnitZ() * halfLengths.z, EulerAnglesf(90.f, 180.f, 0.f));
|
||||
GeneratePlane(Vector2ui(subdivision.x, subdivision.y), Vector2f(lengths.x, lengths.y), Matrix4f::ConcatenateAffine(matrix, transform), textureCoords, vertexPointers, indices, nullptr, indexOffset);
|
||||
indexOffset += zVertexCount;
|
||||
indices += zIndexCount;
|
||||
|
||||
@@ -174,15 +174,15 @@ namespace Nz
|
||||
if (header.format.flags & DDPF_RGB)
|
||||
{
|
||||
// Reverse bits for our masks
|
||||
info.redMask = ReverseBits(header.format.redMask);
|
||||
info.greenMask = ReverseBits(header.format.greenMask);
|
||||
info.blueMask = ReverseBits(header.format.blueMask);
|
||||
info.redMask = header.format.redMask;
|
||||
info.greenMask = header.format.greenMask;
|
||||
info.blueMask = header.format.blueMask;
|
||||
}
|
||||
else if (header.format.flags & DDPF_LUMINANCE)
|
||||
info.redMask = ReverseBits(header.format.redMask);
|
||||
info.redMask = header.format.redMask;
|
||||
|
||||
if (header.format.flags & (DDPF_ALPHA | DDPF_ALPHAPIXELS))
|
||||
info.alphaMask = ReverseBits(header.format.alphaMask);
|
||||
info.alphaMask = header.format.alphaMask;
|
||||
|
||||
*format = PixelFormat::IdentifyFormat(info);
|
||||
if (!PixelFormat::IsValid(*format))
|
||||
|
||||
@@ -331,19 +331,19 @@ namespace Nz
|
||||
Emit(mat.specular.b / 255.f);
|
||||
EmitLine();
|
||||
|
||||
if (mat.alpha != 1.f)
|
||||
if (!NumberEquals(mat.alpha, 1.f))
|
||||
{
|
||||
Emit("d ");
|
||||
EmitLine(mat.alpha);
|
||||
}
|
||||
|
||||
if (mat.refractionIndex != 1.f)
|
||||
if (!NumberEquals(mat.refractionIndex, 1.f))
|
||||
{
|
||||
Emit("ni ");
|
||||
EmitLine(mat.refractionIndex);
|
||||
}
|
||||
|
||||
if (mat.shininess != 1.f)
|
||||
if (!NumberEquals(mat.shininess, 1.f))
|
||||
{
|
||||
Emit("ns ");
|
||||
EmitLine(mat.shininess);
|
||||
|
||||
@@ -128,17 +128,17 @@ namespace Nz
|
||||
UInt32 faceReserve = 0;
|
||||
UInt32 vertexReserve = 0;
|
||||
unsigned int matCount = 0;
|
||||
auto GetMaterial = [&] (const String& meshName, const String& matName) -> Mesh*
|
||||
auto GetMaterial = [&] (const String& mesh, const String& mat) -> Mesh*
|
||||
{
|
||||
auto& map = meshesByName[meshName];
|
||||
auto it = map.find(matName);
|
||||
auto& map = meshesByName[mesh];
|
||||
auto it = map.find(mat);
|
||||
if (it == map.end())
|
||||
it = map.insert(std::make_pair(matName, MatPair(Mesh(), matCount++))).first;
|
||||
it = map.insert(std::make_pair(mat, MatPair(Mesh(), matCount++))).first;
|
||||
|
||||
Mesh& mesh = it->second.first;
|
||||
Mesh& meshData = it->second.first;
|
||||
|
||||
mesh.faces.reserve(faceReserve);
|
||||
mesh.vertices.reserve(vertexReserve);
|
||||
meshData.faces.reserve(faceReserve);
|
||||
meshData.vertices.reserve(vertexReserve);
|
||||
faceReserve = 0;
|
||||
vertexReserve = 0;
|
||||
|
||||
@@ -550,19 +550,19 @@ namespace Nz
|
||||
EmitLine(pair.second.size());
|
||||
EmitLine();
|
||||
|
||||
for (std::size_t meshIndex : pair.second)
|
||||
for (std::size_t index : pair.second)
|
||||
{
|
||||
const Mesh& mesh = m_meshes[meshIndex];
|
||||
const Mesh& mesh = m_meshes[index];
|
||||
|
||||
Emit("g ");
|
||||
EmitLine(mesh.name);
|
||||
EmitLine();
|
||||
|
||||
|
||||
Emit("# face count: ");
|
||||
EmitLine(mesh.faces.size());
|
||||
Emit("# vertex count: ");
|
||||
EmitLine(mesh.vertices.size());
|
||||
|
||||
|
||||
for (const Face& face : mesh.faces)
|
||||
{
|
||||
Emit('f');
|
||||
|
||||
@@ -825,6 +825,44 @@ namespace Nz
|
||||
return GetLevelSize(m_sharedImage->width, level);
|
||||
}
|
||||
|
||||
bool Image::HasAlpha() const
|
||||
{
|
||||
NazaraAssert(m_sharedImage != &emptyImage, "Image must be valid");
|
||||
|
||||
if (!PixelFormat::HasAlpha(m_sharedImage->format))
|
||||
return false;
|
||||
|
||||
if (!PixelFormat::IsCompressed(m_sharedImage->format))
|
||||
{
|
||||
const PixelFormatInfo& info = PixelFormat::GetInfo(m_sharedImage->format);
|
||||
const UInt8* pixel = GetConstPixels();
|
||||
|
||||
Bitset<> workingBitset;
|
||||
std::size_t pixelCount = m_sharedImage->width * m_sharedImage->height * ((m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth);
|
||||
if (pixelCount == 0)
|
||||
return false;
|
||||
|
||||
auto seq = workingBitset.Read(GetConstPixels(), info.bitsPerPixel);
|
||||
do
|
||||
{
|
||||
workingBitset &= info.alphaMask;
|
||||
if (workingBitset.Count() != info.alphaMask.Count()) //< Means that at least one bit of the alpha mask of this pixel is disabled
|
||||
return true;
|
||||
|
||||
workingBitset.Clear();
|
||||
workingBitset.Read(seq, info.bitsPerPixel);
|
||||
}
|
||||
while (--pixelCount > 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: Currently, we assume the pixel format is already the right one
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Image::IsValid() const
|
||||
{
|
||||
return m_sharedImage != &emptyImage;
|
||||
@@ -1441,7 +1479,7 @@ namespace Nz
|
||||
SharedImage::PixelContainer levels(m_sharedImage->levels.size());
|
||||
for (unsigned int i = 0; i < levels.size(); ++i)
|
||||
{
|
||||
unsigned int size = GetMemoryUsage(i);
|
||||
std::size_t size = GetMemoryUsage(i);
|
||||
levels[i].reset(new UInt8[size]);
|
||||
std::memcpy(levels[i].get(), m_sharedImage->levels[i].get(), size);
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace Nz
|
||||
Font* SimpleTextDrawer::GetFont(std::size_t index) const
|
||||
{
|
||||
NazaraAssert(index == 0, "Font index out of range");
|
||||
NazaraUnused(index);
|
||||
|
||||
return m_font;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
SoftwareBuffer::SoftwareBuffer(Buffer* /*parent*/, BufferType type)
|
||||
SoftwareBuffer::SoftwareBuffer(Buffer* /*parent*/, BufferType /*type*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Nz
|
||||
|
||||
bool VertexBuffer::Fill(const void* data, unsigned int startVertex, unsigned int length, bool forceDiscard)
|
||||
{
|
||||
unsigned int stride = m_vertexDeclaration->GetStride();
|
||||
std::size_t stride = m_vertexDeclaration->GetStride();
|
||||
return FillRaw(data, startVertex*stride, length*stride, forceDiscard);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ namespace Nz
|
||||
width(0)
|
||||
{
|
||||
}
|
||||
|
||||
VideoMode::VideoMode(unsigned int w, unsigned int h) :
|
||||
VideoMode(w, h, GetDesktopMode().bitsPerPixel)
|
||||
{
|
||||
}
|
||||
|
||||
VideoMode::VideoMode(unsigned int w, unsigned int h, UInt8 bpp) :
|
||||
bitsPerPixel(bpp),
|
||||
|
||||
@@ -83,6 +83,7 @@ namespace Nz
|
||||
|
||||
bool WindowImpl::Create(const VideoMode& mode, const String& title, UInt32 style)
|
||||
{
|
||||
bool async = (style & WindowStyle_Threaded) != 0;
|
||||
bool fullscreen = (style & WindowStyle_Fullscreen) != 0;
|
||||
DWORD win32Style, win32StyleEx;
|
||||
unsigned int x, y;
|
||||
@@ -147,19 +148,25 @@ namespace Nz
|
||||
|
||||
m_callback = 0;
|
||||
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
Mutex mutex;
|
||||
ConditionVariable condition;
|
||||
m_threadActive = true;
|
||||
m_eventListener = true;
|
||||
m_ownsWindow = true;
|
||||
m_sizemove = false;
|
||||
m_style = style;
|
||||
|
||||
// On attend que la fenêtre soit créée
|
||||
mutex.Lock();
|
||||
m_thread = Thread(WindowThread, &m_handle, win32StyleEx, title.GetWideString().data(), win32Style, x, y, width, height, this, &mutex, &condition);
|
||||
condition.Wait(&mutex);
|
||||
mutex.Unlock();
|
||||
#else
|
||||
m_handle = CreateWindowExW(win32StyleEx, className, title.GetWideString().data(), win32Style, x, y, width, height, nullptr, nullptr, GetModuleHandle(nullptr), this);
|
||||
#endif
|
||||
if (async)
|
||||
{
|
||||
Mutex mutex;
|
||||
ConditionVariable condition;
|
||||
m_threadActive = true;
|
||||
|
||||
// On attend que la fenêtre soit créée
|
||||
mutex.Lock();
|
||||
m_thread = Thread(WindowThread, &m_handle, win32StyleEx, title, win32Style, fullscreen, Rectui(x, y, width, height), this, &mutex, &condition);
|
||||
condition.Wait(&mutex);
|
||||
mutex.Unlock();
|
||||
}
|
||||
else
|
||||
m_handle = CreateWindowExW(win32StyleEx, className, title.GetWideString().data(), win32Style, x, y, width, height, nullptr, nullptr, GetModuleHandle(nullptr), this);
|
||||
|
||||
if (!m_handle)
|
||||
{
|
||||
@@ -167,26 +174,8 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
SetForegroundWindow(m_handle);
|
||||
ShowWindow(m_handle, SW_SHOW);
|
||||
}
|
||||
|
||||
m_eventListener = true;
|
||||
m_ownsWindow = true;
|
||||
#if !NAZARA_UTILITY_THREADED_WINDOW
|
||||
m_sizemove = false;
|
||||
#endif
|
||||
m_style = style;
|
||||
|
||||
// Récupération de la position/taille de la fenêtre (Après sa création)
|
||||
RECT clientRect, windowRect;
|
||||
GetClientRect(m_handle, &clientRect);
|
||||
GetWindowRect(m_handle, &windowRect);
|
||||
|
||||
m_position.Set(windowRect.left, windowRect.top);
|
||||
m_size.Set(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
|
||||
if (!async)
|
||||
PrepareWindow(fullscreen);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -203,9 +192,7 @@ namespace Nz
|
||||
|
||||
m_eventListener = false;
|
||||
m_ownsWindow = false;
|
||||
#if !NAZARA_UTILITY_THREADED_WINDOW
|
||||
m_sizemove = false;
|
||||
#endif
|
||||
m_style = RetrieveStyle(m_handle);
|
||||
|
||||
RECT clientRect, windowRect;
|
||||
@@ -222,18 +209,21 @@ namespace Nz
|
||||
{
|
||||
if (m_ownsWindow)
|
||||
{
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
if (m_thread.IsJoinable())
|
||||
if (m_style & WindowStyle_Threaded)
|
||||
{
|
||||
m_threadActive = false;
|
||||
PostMessageW(m_handle, WM_NULL, 0, 0); // Pour réveiller le thread
|
||||
if (m_thread.IsJoinable())
|
||||
{
|
||||
m_threadActive = false;
|
||||
PostMessageW(m_handle, WM_NULL, 0, 0); // Wake up our thread
|
||||
|
||||
m_thread.Join();
|
||||
m_thread.Join();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_handle)
|
||||
DestroyWindow(m_handle);
|
||||
}
|
||||
#else
|
||||
if (m_handle)
|
||||
DestroyWindow(m_handle);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
SetEventListener(false);
|
||||
@@ -280,7 +270,7 @@ namespace Nz
|
||||
if (titleSize == 0)
|
||||
return String();
|
||||
|
||||
titleSize++; // Caractère nul
|
||||
titleSize++; // \0
|
||||
|
||||
std::unique_ptr<wchar_t[]> wTitle(new wchar_t[titleSize]);
|
||||
GetWindowTextW(m_handle, wTitle.get(), titleSize);
|
||||
@@ -525,7 +515,6 @@ namespace Nz
|
||||
return true; // Afin que Windows ne ferme pas la fenêtre automatiquement
|
||||
}
|
||||
|
||||
#if !NAZARA_UTILITY_THREADED_WINDOW
|
||||
case WM_ENTERSIZEMOVE:
|
||||
{
|
||||
m_sizemove = true;
|
||||
@@ -536,6 +525,10 @@ namespace Nz
|
||||
{
|
||||
m_sizemove = false;
|
||||
|
||||
// In case of threaded window, size and move events are not blocked
|
||||
if (m_style & WindowStyle_Threaded)
|
||||
break;
|
||||
|
||||
// On vérifie ce qui a changé
|
||||
RECT clientRect, windowRect;
|
||||
GetClientRect(m_handle, &clientRect);
|
||||
@@ -565,7 +558,6 @@ namespace Nz
|
||||
m_parent->PushEvent(event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
@@ -789,15 +781,23 @@ namespace Nz
|
||||
|
||||
case WM_MOVE:
|
||||
{
|
||||
if (m_sizemove && (m_style & WindowStyle_Threaded) == 0)
|
||||
break;
|
||||
|
||||
RECT windowRect;
|
||||
GetWindowRect(m_handle, &windowRect);
|
||||
|
||||
WindowEvent event;
|
||||
event.type = WindowEventType_Moved;
|
||||
event.position.x = windowRect.left;
|
||||
event.position.y = windowRect.top;
|
||||
m_parent->PushEvent(event);
|
||||
Vector2i position(windowRect.left, windowRect.top);
|
||||
if (m_position != position)
|
||||
{
|
||||
m_position = position;
|
||||
|
||||
WindowEvent event;
|
||||
event.type = WindowEventType_Moved;
|
||||
event.position.x = position.x;
|
||||
event.position.y = position.y;
|
||||
m_parent->PushEvent(event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -852,27 +852,26 @@ namespace Nz
|
||||
|
||||
case WM_SIZE:
|
||||
{
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
if (wParam != SIZE_MINIMIZED)
|
||||
#else
|
||||
if (!m_sizemove && wParam != SIZE_MINIMIZED)
|
||||
#endif
|
||||
{
|
||||
RECT rect;
|
||||
GetClientRect(m_handle, &rect);
|
||||
if (m_sizemove && (m_style & WindowStyle_Threaded) == 0)
|
||||
break;
|
||||
|
||||
Vector2ui size(rect.right-rect.left, rect.bottom-rect.top); // On récupère uniquement la taille de la zone client
|
||||
if (m_size == size)
|
||||
break;
|
||||
if (wParam == SIZE_MINIMIZED)
|
||||
break;
|
||||
|
||||
m_size = size;
|
||||
RECT rect;
|
||||
GetClientRect(m_handle, &rect);
|
||||
|
||||
WindowEvent event;
|
||||
event.type = WindowEventType_Resized;
|
||||
event.size.width = size.x;
|
||||
event.size.height = size.y;
|
||||
m_parent->PushEvent(event);
|
||||
}
|
||||
Vector2ui size(rect.right-rect.left, rect.bottom-rect.top); // On récupère uniquement la taille de la zone client
|
||||
if (m_size == size)
|
||||
break;
|
||||
|
||||
m_size = size;
|
||||
|
||||
WindowEvent event;
|
||||
event.type = WindowEventType_Resized;
|
||||
event.size.width = size.x;
|
||||
event.size.height = size.y;
|
||||
m_parent->PushEvent(event);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -963,6 +962,23 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
void WindowImpl::PrepareWindow(bool fullscreen)
|
||||
{
|
||||
if (fullscreen)
|
||||
{
|
||||
SetForegroundWindow(m_handle);
|
||||
ShowWindow(m_handle, SW_SHOW);
|
||||
}
|
||||
|
||||
// Cache window position/size after creation
|
||||
RECT clientRect, windowRect;
|
||||
GetClientRect(m_handle, &clientRect);
|
||||
GetWindowRect(m_handle, &windowRect);
|
||||
|
||||
m_position.Set(windowRect.left, windowRect.top);
|
||||
m_size.Set(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
|
||||
}
|
||||
|
||||
bool WindowImpl::Initialize()
|
||||
{
|
||||
// Nous devons faire un type Unicode pour que la fenêtre le soit également
|
||||
@@ -1177,15 +1193,17 @@ namespace Nz
|
||||
return style;
|
||||
}
|
||||
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
void WindowImpl::WindowThread(HWND* handle, DWORD styleEx, const wchar_t* title, DWORD style, unsigned int x, unsigned int y, unsigned int width, unsigned int height, WindowImpl* window, Mutex* mutex, ConditionVariable* condition)
|
||||
void WindowImpl::WindowThread(HWND* handle, DWORD styleEx, const String& title, DWORD style, bool fullscreen, const Rectui& dimensions, WindowImpl* window, Mutex* mutex, ConditionVariable* condition)
|
||||
{
|
||||
HWND& winHandle = *handle;
|
||||
winHandle = CreateWindowExW(styleEx, className, title, style, x, y, width, height, nullptr, nullptr, GetModuleHandle(nullptr), window);
|
||||
winHandle = CreateWindowExW(styleEx, className, title.GetWideString().data(), style, dimensions.x, dimensions.y, dimensions.width, dimensions.height, nullptr, nullptr, GetModuleHandle(nullptr), window);
|
||||
|
||||
if (winHandle)
|
||||
window->PrepareWindow(fullscreen);
|
||||
|
||||
mutex->Lock();
|
||||
condition->Signal();
|
||||
mutex->Unlock(); // mutex et condition sont considérés invalides à partir d'ici
|
||||
mutex->Unlock(); // mutex and condition may be destroyed after this line
|
||||
|
||||
if (!winHandle)
|
||||
return;
|
||||
@@ -1195,5 +1213,4 @@ namespace Nz
|
||||
|
||||
DestroyWindow(winHandle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Core/Thread.hpp>
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Utility/Config.hpp>
|
||||
#include <Nazara/Utility/Keyboard.hpp>
|
||||
@@ -22,10 +23,8 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
class ConditionVariable;
|
||||
class Mutex;
|
||||
#endif
|
||||
class Window;
|
||||
|
||||
#undef IsMinimized // Conflit avec la méthode du même nom
|
||||
@@ -84,13 +83,12 @@ namespace Nz
|
||||
|
||||
private:
|
||||
bool HandleMessage(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void PrepareWindow(bool fullscreen);
|
||||
|
||||
static Keyboard::Key ConvertVirtualKey(WPARAM key, LPARAM flags);
|
||||
static LRESULT CALLBACK MessageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
static UInt32 RetrieveStyle(HWND window);
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
static void WindowThread(HWND* handle, DWORD styleEx, const wchar_t* title, DWORD style, unsigned int x, unsigned int y, unsigned int width, unsigned int height, WindowImpl* window, Mutex* mutex, ConditionVariable* condition);
|
||||
#endif
|
||||
static void WindowThread(HWND* handle, DWORD styleEx, const String& title, DWORD style, bool fullscreen, const Rectui& dimensions, WindowImpl* window, Mutex* mutex, ConditionVariable* condition);
|
||||
|
||||
HCURSOR m_cursor;
|
||||
HWND m_handle;
|
||||
@@ -101,21 +99,15 @@ namespace Nz
|
||||
Vector2i m_mousePos;
|
||||
Vector2i m_position;
|
||||
Vector2ui m_size;
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
Thread m_thread;
|
||||
#endif
|
||||
Window* m_parent;
|
||||
bool m_eventListener;
|
||||
bool m_keyRepeat;
|
||||
bool m_mouseInside;
|
||||
bool m_ownsWindow;
|
||||
#if !NAZARA_UTILITY_THREADED_WINDOW
|
||||
bool m_sizemove;
|
||||
#endif
|
||||
bool m_smoothScrolling;
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
bool m_threadActive;
|
||||
#endif
|
||||
short m_scrolling;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ namespace Nz
|
||||
else if (style & WindowStyle_Closable || style & WindowStyle_Resizable)
|
||||
style |= WindowStyle_Titlebar;
|
||||
|
||||
m_asyncWindow = (style & WindowStyle_Threaded) != 0;
|
||||
|
||||
std::unique_ptr<WindowImpl> impl = std::make_unique<WindowImpl>(this);
|
||||
if (!impl->Create(mode, title, style))
|
||||
{
|
||||
@@ -107,6 +109,7 @@ namespace Nz
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_asyncWindow = false;
|
||||
m_impl = new WindowImpl(this);
|
||||
if (!m_impl->Create(handle))
|
||||
{
|
||||
@@ -313,11 +316,8 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
LockGuard lock(m_eventMutex);
|
||||
#else
|
||||
m_impl->ProcessEvents(false);
|
||||
#endif
|
||||
if (!m_asyncWindow)
|
||||
m_impl->ProcessEvents(false);
|
||||
|
||||
if (!m_events.empty())
|
||||
{
|
||||
@@ -335,10 +335,19 @@ namespace Nz
|
||||
void Window::ProcessEvents(bool block)
|
||||
{
|
||||
NazaraAssert(m_impl, "Window not created");
|
||||
NazaraUnused(block);
|
||||
|
||||
#if !NAZARA_UTILITY_THREADED_WINDOW
|
||||
m_impl->ProcessEvents(block);
|
||||
#endif
|
||||
if (!m_asyncWindow)
|
||||
m_impl->ProcessEvents(block);
|
||||
else
|
||||
{
|
||||
LockGuard eventLock(m_eventMutex);
|
||||
|
||||
for (const WindowEvent& event : m_pendingEvents)
|
||||
HandleEvent(event);
|
||||
|
||||
m_pendingEvents.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::SetCursor(WindowCursor cursor)
|
||||
@@ -383,25 +392,13 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
m_impl->SetEventListener(listener);
|
||||
if (!listener)
|
||||
{
|
||||
// On vide la pile des évènements
|
||||
LockGuard lock(m_eventMutex);
|
||||
// Empty the event queue
|
||||
while (!m_events.empty())
|
||||
m_events.pop();
|
||||
}
|
||||
#else
|
||||
if (m_ownsWindow)
|
||||
{
|
||||
// Inutile de transmettre l'ordre dans ce cas-là
|
||||
if (!listener)
|
||||
NazaraError("A non-threaded window needs to listen to events");
|
||||
}
|
||||
else
|
||||
m_impl->SetEventListener(listener);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::SetFocus()
|
||||
@@ -589,22 +586,11 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
LockGuard lock(m_eventMutex);
|
||||
|
||||
if (m_events.empty())
|
||||
if (!m_asyncWindow)
|
||||
{
|
||||
m_waitForEvent = true;
|
||||
m_eventConditionMutex.Lock();
|
||||
m_eventMutex.Unlock();
|
||||
m_eventCondition.Wait(&m_eventConditionMutex);
|
||||
m_eventMutex.Lock();
|
||||
m_eventConditionMutex.Unlock();
|
||||
m_waitForEvent = false;
|
||||
}
|
||||
while (m_events.empty())
|
||||
m_impl->ProcessEvents(true);
|
||||
|
||||
if (!m_events.empty())
|
||||
{
|
||||
if (event)
|
||||
*event = m_events.front();
|
||||
|
||||
@@ -612,19 +598,33 @@ namespace Nz
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LockGuard lock(m_eventMutex);
|
||||
|
||||
return false;
|
||||
#else
|
||||
while (m_events.empty())
|
||||
m_impl->ProcessEvents(true);
|
||||
if (m_events.empty())
|
||||
{
|
||||
m_waitForEvent = true;
|
||||
m_eventConditionMutex.Lock();
|
||||
m_eventMutex.Unlock();
|
||||
m_eventCondition.Wait(&m_eventConditionMutex);
|
||||
m_eventMutex.Lock();
|
||||
m_eventConditionMutex.Unlock();
|
||||
m_waitForEvent = false;
|
||||
}
|
||||
|
||||
if (event)
|
||||
*event = m_events.front();
|
||||
if (!m_events.empty())
|
||||
{
|
||||
if (event)
|
||||
*event = m_events.front();
|
||||
|
||||
m_events.pop();
|
||||
m_events.pop();
|
||||
|
||||
return true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::OnWindowCreated()
|
||||
|
||||
@@ -23,32 +23,32 @@ namespace Nz
|
||||
switch (key)
|
||||
{
|
||||
// Lettres
|
||||
case Keyboard::A: keysym = XK_A; break;
|
||||
case Keyboard::B: keysym = XK_B; break;
|
||||
case Keyboard::C: keysym = XK_C; break;
|
||||
case Keyboard::D: keysym = XK_D; break;
|
||||
case Keyboard::E: keysym = XK_E; break;
|
||||
case Keyboard::F: keysym = XK_F; break;
|
||||
case Keyboard::G: keysym = XK_G; break;
|
||||
case Keyboard::H: keysym = XK_H; break;
|
||||
case Keyboard::I: keysym = XK_I; break;
|
||||
case Keyboard::J: keysym = XK_J; break;
|
||||
case Keyboard::K: keysym = XK_K; break;
|
||||
case Keyboard::L: keysym = XK_L; break;
|
||||
case Keyboard::M: keysym = XK_M; break;
|
||||
case Keyboard::N: keysym = XK_N; break;
|
||||
case Keyboard::O: keysym = XK_O; break;
|
||||
case Keyboard::P: keysym = XK_P; break;
|
||||
case Keyboard::Q: keysym = XK_Q; break;
|
||||
case Keyboard::R: keysym = XK_R; break;
|
||||
case Keyboard::S: keysym = XK_S; break;
|
||||
case Keyboard::T: keysym = XK_T; break;
|
||||
case Keyboard::U: keysym = XK_U; break;
|
||||
case Keyboard::V: keysym = XK_V; break;
|
||||
case Keyboard::W: keysym = XK_W; break;
|
||||
case Keyboard::X: keysym = XK_X; break;
|
||||
case Keyboard::Y: keysym = XK_Y; break;
|
||||
case Keyboard::Z: keysym = XK_Z; break;
|
||||
case Keyboard::A: keysym = XK_a; break;
|
||||
case Keyboard::B: keysym = XK_b; break;
|
||||
case Keyboard::C: keysym = XK_c; break;
|
||||
case Keyboard::D: keysym = XK_d; break;
|
||||
case Keyboard::E: keysym = XK_e; break;
|
||||
case Keyboard::F: keysym = XK_f; break;
|
||||
case Keyboard::G: keysym = XK_g; break;
|
||||
case Keyboard::H: keysym = XK_h; break;
|
||||
case Keyboard::I: keysym = XK_i; break;
|
||||
case Keyboard::J: keysym = XK_j; break;
|
||||
case Keyboard::K: keysym = XK_k; break;
|
||||
case Keyboard::L: keysym = XK_l; break;
|
||||
case Keyboard::M: keysym = XK_m; break;
|
||||
case Keyboard::N: keysym = XK_n; break;
|
||||
case Keyboard::O: keysym = XK_o; break;
|
||||
case Keyboard::P: keysym = XK_p; break;
|
||||
case Keyboard::Q: keysym = XK_q; break;
|
||||
case Keyboard::R: keysym = XK_r; break;
|
||||
case Keyboard::S: keysym = XK_s; break;
|
||||
case Keyboard::T: keysym = XK_t; break;
|
||||
case Keyboard::U: keysym = XK_u; break;
|
||||
case Keyboard::V: keysym = XK_v; break;
|
||||
case Keyboard::W: keysym = XK_w; break;
|
||||
case Keyboard::X: keysym = XK_x; break;
|
||||
case Keyboard::Y: keysym = XK_y; break;
|
||||
case Keyboard::Z: keysym = XK_z; break;
|
||||
|
||||
// Touches de fonction
|
||||
case Keyboard::F1: keysym = XK_F1; break;
|
||||
@@ -248,6 +248,8 @@ namespace Nz
|
||||
|
||||
xcb_keysym_t keySym = GetKeySym(key);
|
||||
|
||||
xcb_keycode_t realKeyCode = XCB_NO_SYMBOL;
|
||||
|
||||
xcb_key_symbols_t* keySymbols = X11::XCBKeySymbolsAlloc(connection);
|
||||
if (!keySymbols)
|
||||
{
|
||||
@@ -261,6 +263,20 @@ namespace Nz
|
||||
NazaraError("Failed to get key code");
|
||||
return false;
|
||||
}
|
||||
|
||||
// One keysym is associated with multiple key codes, we have to find the matching one ...
|
||||
int i = 0;
|
||||
while (keyCode.get()[i] != XCB_NO_SYMBOL)
|
||||
{
|
||||
xcb_keycode_t toTry = keyCode.get()[i];
|
||||
if (keySym == xcb_key_symbols_get_keysym(keySymbols, toTry, 0))
|
||||
{
|
||||
realKeyCode = toTry;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
X11::XCBKeySymbolsFree(keySymbols);
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> error(nullptr);
|
||||
@@ -281,7 +297,7 @@ namespace Nz
|
||||
}
|
||||
|
||||
// Check our keycode
|
||||
return (keymap->keys[*keyCode.get() / 8] & (1 << (*keyCode.get() % 8))) != 0;
|
||||
return (keymap->keys[realKeyCode / 8] & (1 << (realKeyCode % 8))) != 0;
|
||||
}
|
||||
|
||||
bool EventImpl::IsMouseButtonPressed(Mouse::Button button)
|
||||
|
||||
@@ -203,17 +203,18 @@ namespace Nz
|
||||
// Set the window's name
|
||||
SetTitle(title);
|
||||
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
Mutex mutex;
|
||||
ConditionVariable condition;
|
||||
m_threadActive = true;
|
||||
if (m_style & WindowStyle_Threaded)
|
||||
{
|
||||
Mutex mutex;
|
||||
ConditionVariable condition;
|
||||
m_threadActive = true;
|
||||
|
||||
// We wait that thread is well launched
|
||||
mutex.Lock();
|
||||
m_thread = Thread(WindowThread, this, &mutex, &condition);
|
||||
condition.Wait(&mutex);
|
||||
mutex.Unlock();
|
||||
#endif
|
||||
// Wait until the thread is ready
|
||||
mutex.Lock();
|
||||
m_thread = Thread(WindowThread, this, &mutex, &condition);
|
||||
condition.Wait(&mutex);
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
// Set fullscreen video mode and switch to fullscreen if necessary
|
||||
if (fullscreen)
|
||||
@@ -275,13 +276,15 @@ namespace Nz
|
||||
{
|
||||
if (m_ownsWindow)
|
||||
{
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
if (m_thread.IsJoinable())
|
||||
if (m_style & WindowStyle_Threaded)
|
||||
{
|
||||
m_threadActive = false;
|
||||
m_thread.Join();
|
||||
if (m_thread.IsJoinable())
|
||||
{
|
||||
m_threadActive = false;
|
||||
m_thread.Join();
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
// Destroy the window
|
||||
if (m_window && m_ownsWindow)
|
||||
{
|
||||
@@ -293,13 +296,11 @@ namespace Nz
|
||||
xcb_destroy_window(
|
||||
connection,
|
||||
m_window
|
||||
))
|
||||
)
|
||||
)))
|
||||
NazaraError("Failed to destroy window");
|
||||
|
||||
xcb_flush(connection);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
SetEventListener(false);
|
||||
@@ -1247,7 +1248,7 @@ namespace Nz
|
||||
|
||||
char32_t codePoint = GetRepresentation(keysym);
|
||||
|
||||
// WTF if (std::isprint(codePoint, std::locale(""))) + handle combining ?
|
||||
// if (std::isprint(codePoint)) Is not working ? + handle combining ?
|
||||
{
|
||||
WindowEvent event;
|
||||
event.type = Nz::WindowEventType_TextEntered;
|
||||
@@ -1405,7 +1406,7 @@ namespace Nz
|
||||
// Catch reparent events to properly apply fullscreen on
|
||||
// some "strange" window managers (like Awesome) which
|
||||
// seem to make use of temporary parents during mapping
|
||||
if (m_style & Nz::WindowStyle_Fullscreen)
|
||||
if (m_style & WindowStyle_Fullscreen)
|
||||
SwitchToFullscreen();
|
||||
|
||||
break;
|
||||
@@ -1685,12 +1686,11 @@ namespace Nz
|
||||
));
|
||||
}
|
||||
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
void WindowImpl::WindowThread(WindowImpl* window, Mutex* mutex, ConditionVariable* condition)
|
||||
{
|
||||
mutex->Lock();
|
||||
condition->Signal();
|
||||
mutex->Unlock(); // mutex et condition sont considérés invalides à partir d'ici
|
||||
mutex->Unlock(); // mutex and condition may be destroyed after this line
|
||||
|
||||
if (!window->m_window)
|
||||
return;
|
||||
@@ -1700,5 +1700,4 @@ namespace Nz
|
||||
|
||||
window->Destroy();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20,10 +20,8 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
class ConditionVariable;
|
||||
class Mutex;
|
||||
#endif
|
||||
class Cursor;
|
||||
class Icon;
|
||||
class VideoMode;
|
||||
@@ -103,25 +101,19 @@ namespace Nz
|
||||
bool UpdateNormalHints();
|
||||
void UpdateEventQueue(xcb_generic_event_t* event);
|
||||
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
static void WindowThread(WindowImpl* window, Mutex* mutex, ConditionVariable* condition);
|
||||
#endif
|
||||
|
||||
xcb_window_t m_window;
|
||||
xcb_screen_t* m_screen;
|
||||
xcb_randr_get_screen_info_reply_t m_oldVideoMode;
|
||||
xcb_size_hints_t m_size_hints;
|
||||
UInt32 m_style;
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
Thread m_thread;
|
||||
#endif
|
||||
UInt32 m_style;
|
||||
Window* m_parent;
|
||||
bool m_eventListener;
|
||||
bool m_ownsWindow;
|
||||
bool m_smoothScrolling;
|
||||
#if NAZARA_UTILITY_THREADED_WINDOW
|
||||
bool m_threadActive;
|
||||
#endif
|
||||
short m_scrolling;
|
||||
Vector2i m_mousePos;
|
||||
bool m_keyRepeat;
|
||||
|
||||
Reference in New Issue
Block a user