ShaderNodes: Use PreviewValues instead of QImage

This commit is contained in:
Jérôme Leclercq
2020-07-03 22:53:00 +02:00
parent 4f671873c1
commit 33d94c05f3
24 changed files with 314 additions and 204 deletions

View File

@@ -176,7 +176,7 @@ bool CastVec<ToComponentCount>::ComputePreview(QPixmap& pixmap)
if (!m_input)
return false;
pixmap = QPixmap::fromImage(m_output->preview);
pixmap = QPixmap::fromImage(m_output->preview.GenerateImage());
return true;
}
@@ -185,47 +185,38 @@ void CastVec<ToComponentCount>::UpdateOutput()
{
if (!m_input)
{
m_output->preview = QImage(1, 1, QImage::Format_RGBA8888);
m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0));
m_output->preview = PreviewValues(1, 1);
m_output->preview(0, 0) = Nz::Vector4f::Zero();
return;
}
const QImage& input = m_input->preview;
const PreviewValues& input = m_input->preview;
int inputWidth = input.width();
int inputHeight = input.height();
std::size_t inputWidth = input.GetWidth();
std::size_t inputHeight = input.GetHeight();
QImage& output = m_output->preview;
output = QImage(inputWidth, inputHeight, QImage::Format_RGBA8888);
PreviewValues& output = m_output->preview;
output = PreviewValues(inputWidth, inputHeight);
std::size_t fromComponentCount = m_input->componentCount;
std::size_t commonComponents = std::min(fromComponentCount, ToComponentCount);
std::size_t overflowComponentCount = (ToComponentCount > fromComponentCount) ? ToComponentCount - fromComponentCount : 0;
std::size_t voidComponents = 4 - overflowComponentCount - commonComponents;
std::array<std::uint8_t, 4> constants;
if (ToComponentCount > fromComponentCount)
for (std::size_t y = 0; y < inputHeight; ++y)
{
for (std::size_t i = 0; i < overflowComponentCount; ++i)
constants[i] = static_cast<std::uint8_t>(std::clamp(int(m_overflowComponents[i] * 255), 0, 255));
}
std::uint8_t* outputPtr = output.bits();
const std::uint8_t* inputPtr = input.constBits();
for (int y = 0; y < inputHeight; ++y)
{
for (int x = 0; x < inputWidth; ++x)
for (std::size_t x = 0; x < inputWidth; ++x)
{
for (std::size_t i = 0; i < commonComponents; ++i)
*outputPtr++ = inputPtr[i];
Nz::Vector4f color = input(x, y);
float* colorPtr = &color.x;
for (std::size_t i = 0; i < overflowComponentCount; ++i)
*outputPtr++ = constants[i];
*colorPtr++ = m_overflowComponents[i];
for (std::size_t i = 0; i < voidComponents; ++i)
*outputPtr++ = (i == voidComponents - 1) ? 255 : 0;
*colorPtr++ = (i == voidComponents - 1) ? 1.f : 0.f;
inputPtr += 4;
output(x, y) = color;
}
}

View File

@@ -46,7 +46,7 @@ std::shared_ptr<QtNodes::NodeData> FloatValue::outData(QtNodes::PortIndex port)
assert(port == 0);
auto out = std::make_shared<FloatData>();
out->preview.fill(ToColor());
out->preview(0, 0) = Nz::Vector4f(m_value, m_value, m_value, 1.f);
return out;
}

View File

@@ -48,7 +48,7 @@ bool InputValue::ComputePreview(QPixmap& pixmap)
const auto& inputEntry = graph.GetInput(*m_currentInputIndex);
const auto& preview = graph.GetPreviewModel();
pixmap = QPixmap::fromImage(preview.GetImage(inputEntry.role, inputEntry.roleIndex));
pixmap = QPixmap::fromImage(preview.GetPreview(inputEntry.role, inputEntry.roleIndex).GenerateImage());
return true;
}
@@ -171,7 +171,7 @@ std::shared_ptr<QtNodes::NodeData> InputValue::outData(QtNodes::PortIndex port)
const auto& preview = graph.GetPreviewModel();
auto vecData = std::make_shared<VecData>(GetComponentCount(inputEntry.type));
vecData->preview = preview.GetImage(inputEntry.role, inputEntry.roleIndex);
vecData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex);
return vecData;
}

View File

@@ -170,7 +170,7 @@ bool OutputValue::ComputePreview(QPixmap& pixmap)
if (!m_input)
return false;
pixmap = QPixmap::fromImage(m_input->preview);
pixmap = QPixmap::fromImage(m_input->preview.GenerateImage());
return true;
}

View File

@@ -23,57 +23,37 @@ unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const
void SampleTexture::UpdateOutput()
{
QImage& output = m_output->preview;
PreviewValues& output = m_output->preview;
if (!m_texture || !m_uv)
{
output = QImage(1, 1, QImage::Format_RGBA8888);
output.fill(QColor::fromRgb(0, 0, 0, 0));
output = PreviewValues(1, 1);
output.Fill(Nz::Vector4f::Zero());
return;
}
const QImage& texturePreview = m_texture->preview;
const PreviewValues& texturePreview = m_texture->preview;
int textureWidth = texturePreview.width();
int textureHeight = texturePreview.height();
std::size_t textureWidth = texturePreview.GetWidth();
std::size_t textureHeight = texturePreview.GetHeight();
const QImage& uv = m_uv->preview;
const PreviewValues& uv = m_uv->preview;
int uvWidth = uv.width();
int uvHeight = uv.height();
std::size_t uvWidth = uv.GetWidth();
std::size_t uvHeight = uv.GetHeight();
output = QImage(uvWidth, uvHeight, QImage::Format_RGBA8888);
output = PreviewValues(uvWidth, uvHeight);
std::uint8_t* outputPtr = output.bits();
const std::uint8_t* uvPtr = uv.constBits();
const std::uint8_t* texturePtr = texturePreview.constBits();
for (int y = 0; y < uvHeight; ++y)
for (std::size_t y = 0; y < uvHeight; ++y)
{
for (int x = 0; x < uvWidth; ++x)
for (std::size_t x = 0; x < uvWidth; ++x)
{
float u = float(uvPtr[0]) / 255;
float v = float(uvPtr[1]) / 255;
Nz::Vector4f uvValue = uv(x, y);
if (textureWidth > 0 && textureHeight > 0)
{
int texX = std::clamp(int(u * textureWidth), 0, textureWidth - 1);
int texY = std::clamp(int(v * textureHeight), 0, textureHeight - 1);
int texPixel = (texY * textureWidth + texX) * 4;
*outputPtr++ = texturePtr[texPixel + 0];
*outputPtr++ = texturePtr[texPixel + 1];
*outputPtr++ = texturePtr[texPixel + 2];
*outputPtr++ = texturePtr[texPixel + 3];
}
output(x, y) = texturePreview.Sample(uvValue.x, uvValue.y);
else
{
*outputPtr++ = 0;
*outputPtr++ = 0;
*outputPtr++ = 0;
*outputPtr++ = 0xFF;
}
uvPtr += 4;
output(x, y) = Nz::Vector4f(0.f, 0.f, 0.f, 1.f);
}
}
@@ -87,7 +67,7 @@ bool SampleTexture::ComputePreview(QPixmap& pixmap)
if (!m_texture || !m_uv)
return false;
pixmap = QPixmap::fromImage(m_output->preview);
pixmap = QPixmap::fromImage(m_output->preview.GenerateImage());
return true;
}

View File

@@ -158,7 +158,18 @@ std::shared_ptr<QtNodes::NodeData> TextureValue::outData(QtNodes::PortIndex port
assert(textureData);
textureData->preview = textureEntry.preview;
const QImage& previewImage = textureEntry.preview;
textureData->preview = PreviewValues(previewImage.width(), previewImage.height());
for (std::size_t y = 0; y < textureData->preview.GetHeight(); ++y)
{
for (std::size_t x = 0; x < textureData->preview.GetWidth(); ++x)
{
QColor pixelColor = previewImage.pixelColor(int(x), int(y));
textureData->preview(x, y) = Nz::Vector4f(pixelColor.redF(), pixelColor.greenF(), pixelColor.blueF(), pixelColor.alphaF());
}
}
return textureData;
}

View File

@@ -12,15 +12,10 @@ QString VecAdd::name() const
return name;
}
void VecAdd::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount)
void VecAdd::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount)
{
for (std::size_t i = 0; i < pixelCount; ++i)
{
unsigned int lValue = left[i];
unsigned int rValue = right[i];
output[i] = static_cast<std::uint8_t>(std::min(lValue + rValue, 255U));
}
output[i] = left[i] + right[i];
}
QString VecMul::caption() const
@@ -35,15 +30,10 @@ QString VecMul::name() const
return name;
}
void VecMul::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount)
void VecMul::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount)
{
for (std::size_t i = 0; i < pixelCount; ++i)
{
unsigned int lValue = left[i];
unsigned int rValue = right[i];
output[i] = static_cast<std::uint8_t>(lValue * rValue / 255);
}
output[i] = left[i] * right[i];
}
QString VecSub::caption() const
@@ -59,17 +49,10 @@ QString VecSub::name() const
return name;
}
void VecSub::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount)
void VecSub::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount)
{
for (std::size_t i = 0; i < pixelCount; ++i)
{
unsigned int lValue = left[i];
unsigned int rValue = right[i];
unsigned int sub = (lValue >= rValue) ? lValue - rValue : 0u;
output[i] = static_cast<std::uint8_t>(sub);
}
output[i] = left[i] - right[i];
}
QString VecDiv::caption() const
@@ -85,21 +68,8 @@ QString VecDiv::name() const
return name;
}
void VecDiv::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount)
void VecDiv::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount)
{
for (std::size_t i = 0; i < pixelCount; ++i)
{
unsigned int lValue = left[i];
unsigned int rValue = right[i];
unsigned res;
if (rValue != 0)
res = lValue / rValue;
else if (lValue != 0)
res = 0xFF; //< positive / 0 = +inf, which we clamp to 0xFF
else
res = 0; //< 0 / 0 = NaN, which we set to zero
output[i] = static_cast<std::uint8_t>(res);
}
output[i] = left[i] / right[i];
}

View File

@@ -27,7 +27,7 @@ class VecBinOp : public ShaderNode
QString validationMessage() const override;
private:
virtual void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) = 0;
virtual void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) = 0;
bool ComputePreview(QPixmap& pixmap) override;
void UpdateOutput();
@@ -45,7 +45,7 @@ class VecAdd : public VecBinOp<Nz::ShaderNodes::BinaryType::Add>
QString caption() const override;
QString name() const override;
void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override;
void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override;
};
class VecMul : public VecBinOp<Nz::ShaderNodes::BinaryType::Multiply>
@@ -56,7 +56,7 @@ class VecMul : public VecBinOp<Nz::ShaderNodes::BinaryType::Multiply>
QString caption() const override;
QString name() const override;
void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override;
void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override;
};
class VecSub : public VecBinOp<Nz::ShaderNodes::BinaryType::Substract>
@@ -67,7 +67,7 @@ class VecSub : public VecBinOp<Nz::ShaderNodes::BinaryType::Substract>
QString caption() const override;
QString name() const override;
void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override;
void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override;
};
class VecDiv : public VecBinOp<Nz::ShaderNodes::BinaryType::Divide>
@@ -78,7 +78,7 @@ class VecDiv : public VecBinOp<Nz::ShaderNodes::BinaryType::Divide>
QString caption() const override;
QString name() const override;
void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override;
void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override;
};
#include <ShaderNode/DataModels/VecBinOp.inl>

View File

@@ -95,7 +95,7 @@ bool VecBinOp<BinOp>::ComputePreview(QPixmap& pixmap)
if (!m_lhs || !m_rhs)
return false;
pixmap = QPixmap::fromImage(m_output->preview);
pixmap = QPixmap::fromImage(m_output->preview.GenerateImage());
return true;
}
@@ -105,29 +105,29 @@ void VecBinOp<BinOp>::UpdateOutput()
if (validationState() != QtNodes::NodeValidationState::Valid)
{
m_output = std::make_shared<VecData>(4);
m_output->preview = QImage(1, 1, QImage::Format_RGBA8888);
m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0));
m_output->preview = PreviewValues(1, 1);
m_output->preview.Fill(Nz::Vector4f::Zero());
return;
}
m_output = std::make_shared<VecData>(m_lhs->componentCount);
const QImage& leftPreview = m_lhs->preview;
const QImage& rightPreview = m_rhs->preview;
int maxWidth = std::max(leftPreview.width(), rightPreview.width());
int maxHeight = std::max(leftPreview.height(), rightPreview.height());
const PreviewValues& leftPreview = m_lhs->preview;
const PreviewValues& rightPreview = m_rhs->preview;
std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth());
std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight());
// Exploit COW
QImage leftResized = leftPreview;
if (leftResized.width() != maxWidth || leftResized.height() != maxHeight)
leftResized = leftResized.scaled(maxWidth, maxHeight);
// FIXME: Prevent useless copy
PreviewValues leftResized = leftPreview;
if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight)
leftResized = leftResized.Resized(maxWidth, maxHeight);
QImage rightResized = rightPreview;
if (rightResized.width() != maxWidth || rightResized.height() != maxHeight)
rightResized = rightResized.scaled(maxWidth, maxHeight);
PreviewValues rightResized = rightPreview;
if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight)
rightResized = rightResized.Resized(maxWidth, maxHeight);
m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888);
ApplyOp(leftResized.constBits(), rightResized.constBits(), m_output->preview.bits(), maxWidth * maxHeight * 4);
m_output->preview = PreviewValues(maxWidth, maxHeight);
ApplyOp(leftResized.GetData(), rightResized.GetData(), m_output->preview.GetData(), maxWidth * maxHeight);
Q_EMIT dataUpdated(0);

View File

@@ -112,7 +112,7 @@ bool VecDot::ComputePreview(QPixmap& pixmap)
if (validationState() != QtNodes::NodeValidationState::Valid)
return false;
pixmap = QPixmap::fromImage(m_output->preview);
pixmap = QPixmap::fromImage(m_output->preview.GenerateImage());
return true;
}
@@ -120,45 +120,41 @@ void VecDot::UpdateOutput()
{
if (validationState() != QtNodes::NodeValidationState::Valid)
{
m_output->preview = QImage(1, 1, QImage::Format_RGBA8888);
m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0));
m_output->preview = PreviewValues(1, 1);
m_output->preview.Fill(Nz::Vector4f::Zero());
return;
}
const QImage& leftPreview = m_lhs->preview;
const QImage& rightPreview = m_rhs->preview;
int maxWidth = std::max(leftPreview.width(), rightPreview.width());
int maxHeight = std::max(leftPreview.height(), rightPreview.height());
const PreviewValues& leftPreview = m_lhs->preview;
const PreviewValues& rightPreview = m_rhs->preview;
std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth());
std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight());
// Exploit COW
QImage leftResized = leftPreview;
if (leftResized.width() != maxWidth || leftResized.height() != maxHeight)
leftResized = leftResized.scaled(maxWidth, maxHeight);
// FIXME: Prevent useless copy
PreviewValues leftResized = leftPreview;
if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight)
leftResized = leftResized.Resized(maxWidth, maxHeight);
QImage rightResized = rightPreview;
if (rightResized.width() != maxWidth || rightResized.height() != maxHeight)
rightResized = rightResized.scaled(maxWidth, maxHeight);
PreviewValues rightResized = rightPreview;
if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight)
rightResized = rightResized.Resized(maxWidth, maxHeight);
m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888);
m_output->preview = PreviewValues(maxWidth, maxHeight);
const uchar* left = leftResized.constBits();
const uchar* right = rightPreview.constBits();
uchar* output = m_output->preview.bits();
const Nz::Vector4f* left = leftResized.GetData();
const Nz::Vector4f* right = rightPreview.GetData();
Nz::Vector4f* output = m_output->preview.GetData();
std::size_t pixelCount = maxWidth * maxHeight;
for (std::size_t i = 0; i < pixelCount; ++i)
{
unsigned int acc = 0;
float acc = 0.f;
for (std::size_t j = 0; j < m_lhs->componentCount; ++j)
acc += left[j] * right[j] / 255;
acc += left[i][j] * right[i][j];
unsigned int result = static_cast<std::uint8_t>(std::min(acc, 255U));
for (std::size_t j = 0; j < 3; ++j)
*output++ = result;
*output++ = 255; //< leave alpha at maximum
left += 4;
right += 4;
output[i][j] = acc;
output[i][3] = 1.f; //< leave alpha at maximum
}
Q_EMIT dataUpdated(0);

View File

@@ -132,7 +132,7 @@ bool VecFloatMul::ComputePreview(QPixmap& pixmap)
if (validationState() != QtNodes::NodeValidationState::Valid)
return false;
pixmap = QPixmap::fromImage(m_output->preview);
pixmap = QPixmap::fromImage(m_output->preview.GenerateImage());
return true;
}
@@ -141,41 +141,36 @@ void VecFloatMul::UpdateOutput()
if (validationState() != QtNodes::NodeValidationState::Valid)
{
m_output = std::make_shared<VecData>(4);
m_output->preview = QImage(1, 1, QImage::Format_RGBA8888);
m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0));
m_output->preview = PreviewValues(1, 1);
m_output->preview.Fill(Nz::Vector4f::Zero());
return;
}
m_output = std::make_shared<VecData>(m_rhs->componentCount);
const QImage& leftPreview = m_lhs->preview;
const QImage& rightPreview = m_rhs->preview;
int maxWidth = std::max(leftPreview.width(), rightPreview.width());
int maxHeight = std::max(leftPreview.height(), rightPreview.height());
const PreviewValues& leftPreview = m_lhs->preview;
const PreviewValues& rightPreview = m_rhs->preview;
std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth());
std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight());
// Exploit COW
QImage leftResized = leftPreview;
if (leftResized.width() != maxWidth || leftResized.height() != maxHeight)
leftResized = leftResized.scaled(maxWidth, maxHeight);
// FIXME: Prevent useless copy
PreviewValues leftResized = leftPreview;
if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight)
leftResized = leftResized.Resized(maxWidth, maxHeight);
QImage rightResized = rightPreview;
if (rightResized.width() != maxWidth || rightResized.height() != maxHeight)
rightResized = rightResized.scaled(maxWidth, maxHeight);
PreviewValues rightResized = rightPreview;
if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight)
rightResized = rightResized.Resized(maxWidth, maxHeight);
m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888);
m_output->preview = PreviewValues(maxWidth, maxHeight);
const uchar* left = leftResized.constBits();
const uchar* right = rightPreview.constBits();
uchar* output = m_output->preview.bits();
const Nz::Vector4f* left = leftResized.GetData();
const Nz::Vector4f* right = rightPreview.GetData();
Nz::Vector4f* output = m_output->preview.GetData();
std::size_t pixelCount = maxWidth * maxHeight * 4;
std::size_t pixelCount = maxWidth * maxHeight;
for (std::size_t i = 0; i < pixelCount; ++i)
{
unsigned int lValue = left[i];
unsigned int rValue = right[i];
output[i] = static_cast<std::uint8_t>(lValue * rValue / 255);
}
output[i] = left[i] * right[i];
Q_EMIT dataUpdated(0);

View File

@@ -63,8 +63,14 @@ std::shared_ptr<QtNodes::NodeData> VecValue<ComponentCount>::outData(QtNodes::Po
assert(port == 0);
auto out = std::make_shared<VecData>(ComponentCount);
out->preview = QImage(1, 1, QImage::Format_RGBA8888);
out->preview.fill(ToColor());
std::array<float, 4> values = { 0.f, 0.f, 0.f, 1.f };
for (std::size_t i = 0; i < ComponentCount; ++i)
values[i] = m_value[i];
out->preview = PreviewValues(1, 1);
out->preview(0, 0) = Nz::Vector4f(values[0], values[1], values[2], values[3]);
return out;
}