NazaraEngine/src/ShaderNode/DataModels/SampleTexture.cpp

218 lines
4.5 KiB
C++

#include <ShaderNode/ShaderGraph.hpp>
#include <ShaderNode/DataModels/SampleTexture.hpp>
#include <NZSL/ShaderBuilder.hpp>
SampleTexture::SampleTexture(ShaderGraph& graph) :
ShaderNode(graph)
{
m_output = std::make_shared<VecData>(4);
UpdateOutput();
}
unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const
{
switch (portType)
{
case QtNodes::PortType::In: return 2;
case QtNodes::PortType::Out: return 1;
}
return 0;
}
void SampleTexture::UpdateOutput()
{
PreviewValues& output = m_output->preview;
if (!m_texture || !m_uv)
{
output = PreviewValues(1, 1);
output.Fill(nzsl::Vector4f32(0.f, 0.f, 0.f, 0.f));
return;
}
const PreviewValues& texturePreview = m_texture->preview;
std::size_t textureWidth = texturePreview.GetWidth();
std::size_t textureHeight = texturePreview.GetHeight();
const PreviewValues& uv = m_uv->preview;
std::size_t uvWidth = uv.GetWidth();
std::size_t uvHeight = uv.GetHeight();
output = PreviewValues(uvWidth, uvHeight);
for (std::size_t y = 0; y < uvHeight; ++y)
{
for (std::size_t x = 0; x < uvWidth; ++x)
{
nzsl::Vector4f32 uvValue = uv(x, y);
if (textureWidth > 0 && textureHeight > 0)
output(x, y) = texturePreview.Sample(uvValue.x(), uvValue.y());
else
output(x, y) = nzsl::Vector4f32(0.f, 0.f, 0.f, 1.f);
}
}
Q_EMIT dataUpdated(0);
UpdatePreview();
}
bool SampleTexture::ComputePreview(QPixmap& pixmap)
{
if (!m_texture || !m_uv)
return false;
pixmap = QPixmap::fromImage(m_output->preview.GenerateImage());
return true;
}
nzsl::Ast::NodePtr SampleTexture::BuildNode(nzsl::Ast::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const
{
assert(m_texture);
assert(m_uv);
assert(count == 2);
assert(outputIndex == 0);
std::vector<nzsl::Ast::ExpressionPtr> params;
params.push_back(std::move(expressions[0]));
params.push_back(std::move(expressions[1]));
return nzsl::ShaderBuilder::Intrinsic(nzsl::Ast::IntrinsicType::SampleTexture, std::move(params));
}
auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType
{
switch (portType)
{
case QtNodes::PortType::In:
{
switch (portIndex)
{
case 0: return Texture2Data::Type();
case 1: return VecData::Type();
}
assert(false);
throw std::runtime_error("invalid port index");
}
case QtNodes::PortType::Out:
{
assert(portIndex == 0);
return VecData::Type();
}
default:
assert(false);
throw std::runtime_error("invalid PortType");
}
}
QString SampleTexture::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
{
switch (portType)
{
case QtNodes::PortType::In:
{
switch (portIndex)
{
case 0: return tr("Texture");
case 1: return tr("UV");
}
assert(false);
throw std::runtime_error("invalid port index");
}
case QtNodes::PortType::Out:
{
assert(portIndex == 0);
return tr("Sample");
}
default:
assert(false);
throw std::runtime_error("Invalid PortType");
}
}
bool SampleTexture::portCaptionVisible(QtNodes::PortType /*portType*/, QtNodes::PortIndex /*portIndex*/) const
{
return true;
}
std::shared_ptr<QtNodes::NodeData> SampleTexture::outData(QtNodes::PortIndex port)
{
assert(port == 0);
return m_output;
}
void SampleTexture::setInData(std::shared_ptr<QtNodes::NodeData> value, int index)
{
switch (index)
{
case 0:
{
if (value && value->type().id == Texture2Data::Type().id)
{
assert(dynamic_cast<Texture2Data*>(value.get()) != nullptr);
m_texture = std::static_pointer_cast<Texture2Data>(value);
}
else
m_texture.reset();
break;
}
case 1:
{
if (value && value->type().id == VecData::Type().id)
{
assert(dynamic_cast<VecData*>(value.get()) != nullptr);
m_uv = std::static_pointer_cast<VecData>(value);
}
else
m_uv.reset();
break;
}
default:
assert(false);
throw std::runtime_error("Invalid PortType");
}
UpdateOutput();
}
QtNodes::NodeValidationState SampleTexture::validationState() const
{
if (!m_texture || !m_uv)
return QtNodes::NodeValidationState::Error;
if (m_uv->componentCount != 2)
return QtNodes::NodeValidationState::Error;
return QtNodes::NodeValidationState::Valid;
}
QString SampleTexture::validationMessage() const
{
if (!m_texture)
return "Missing texture";
if (!m_uv)
return "Missing uv";
if (m_uv->componentCount != 2)
return "Incompatible UV (expected 2, got " + QString::number(m_uv->componentCount) + ")";
return QString();
}