Skip to content

Commit

Permalink
#5532: Two-way material binding, used for polygonOffset
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Mar 20, 2021
1 parent 808c324 commit 9e0b59f
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 6 deletions.
3 changes: 3 additions & 0 deletions include/ishaders.h
Expand Up @@ -215,6 +215,9 @@ class Material
/// Return a polygon offset if one is defined. The default is 0.
virtual float getPolygonOffset() const = 0;

// Set the polygon offset of this material. Clear the FLAG_POLYGONOFFSET to disable the offset altogether.
virtual void setPolygonOffset(float offset) = 0;

/// Get the desired texture repeat behaviour.
virtual ClampType getClampType() const = 0;

Expand Down
52 changes: 52 additions & 0 deletions radiant/ui/materials/Binding.h
Expand Up @@ -63,6 +63,58 @@ class TwoWayBinding :
}
};

template<typename ValueType>
class TwoWayMaterialBinding :
public TwoWayBinding<MaterialPtr, MaterialPtr>
{
protected:
std::function<ValueType(const MaterialPtr&)> _getValue;
std::function<void(const MaterialPtr&, ValueType)> _updateValue;
std::function<void()> _postChangeNotify;

public:
TwoWayMaterialBinding(const std::function<ValueType(const MaterialPtr&)>& loadFunc,
const std::function<void(const MaterialPtr&, ValueType)>& saveFunc,
const std::function<void()>& postChangeNotify = std::function<void()>()) :
TwoWayBinding([this] { return getSource(); }),
_getValue(loadFunc),
_updateValue(saveFunc),
_postChangeNotify(postChangeNotify)
{}

protected:
// Just load the given value into the control
virtual void setValueOnControl(const ValueType& value) = 0;

virtual void updateFromSource() override
{
util::ScopedBoolLock lock(_blockUpdates);

if (!getSource())
{
setValueOnControl(ValueType());
return;
}

setValueOnControl(_getValue(getSource()));
}

virtual void updateValueOnTarget(const ValueType& newValue)
{
auto target = getTarget();

if (target)
{
_updateValue(target, newValue);
}

if (_postChangeNotify)
{
_postChangeNotify();
}
}
};

template<typename ValueType>
class TwoWayStageBinding :
public TwoWayBinding<IShaderLayer::Ptr, IEditableShaderLayer::Ptr>
Expand Down
13 changes: 11 additions & 2 deletions radiant/ui/materials/MaterialEditor.cpp
Expand Up @@ -219,6 +219,15 @@ void MaterialEditor::setupMaterialProperties()

_materialBindings.emplace(std::make_shared<CheckBoxBinding<MaterialPtr>>(getControl<wxCheckBox>("MaterialHasSortValue"),
[](const MaterialPtr& material) { return (material->getParseFlags() & Material::PF_HasSortDefined) != 0; }));

_materialBindings.emplace(std::make_shared<SpinCtrlMaterialBinding<wxSpinCtrlDouble>>(getControl<wxSpinCtrlDouble>("MaterialPolygonOffsetValue"),
[](const MaterialPtr& material) { return material->getPolygonOffset(); },
[this](const MaterialPtr& material, const double& value)
{
material->setPolygonOffset(value);
getControl<wxCheckBox>("MaterialFlagHasPolygonOffset")->SetValue(true);
},
[this]() { onMaterialChanged(); }));
}

void MaterialEditor::setupSurfaceFlag(const std::string& controlName, Material::SurfaceFlags flag)
Expand Down Expand Up @@ -445,7 +454,7 @@ void MaterialEditor::createSpinCtrlBinding(const std::string& ctrlName,
const std::function<int(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<void(const IEditableShaderLayer::Ptr&, int)>& saveFunc)
{
_stageBindings.emplace(std::make_shared<SpinCtrlBinding<wxSpinCtrl>>(
_stageBindings.emplace(std::make_shared<SpinCtrlStageBinding<wxSpinCtrl>>(
getControl<wxSpinCtrl>(ctrlName),
loadFunc,
std::bind(&MaterialEditor::getEditableStageForSelection, this),
Expand All @@ -457,7 +466,7 @@ void MaterialEditor::createSpinCtrlDoubleBinding(const std::string& ctrlName,
const std::function<double(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<void(const IEditableShaderLayer::Ptr&, double)>& saveFunc)
{
_stageBindings.emplace(std::make_shared<SpinCtrlBinding<wxSpinCtrlDouble>>(
_stageBindings.emplace(std::make_shared<SpinCtrlStageBinding<wxSpinCtrlDouble>>(
getControl<wxSpinCtrlDouble>(ctrlName),
loadFunc,
std::bind(&MaterialEditor::getEditableStageForSelection, this),
Expand Down
49 changes: 45 additions & 4 deletions radiant/ui/materials/SpinCtrlBinding.h
Expand Up @@ -7,15 +7,56 @@ namespace ui
{

template<typename SpinCtrlType>
class SpinCtrlBinding :
class SpinCtrlMaterialBinding :
public TwoWayMaterialBinding<decltype(std::declval<SpinCtrlType>().GetValue())>
{
private:
SpinCtrlType* _spinCtrl;
using ValueType = decltype(std::declval<SpinCtrlType>().GetValue());

public:
SpinCtrlMaterialBinding(SpinCtrlType* spinCtrl,
const std::function<ValueType(const MaterialPtr&)>& loadFunc,
const std::function<void(const MaterialPtr&, ValueType)>& saveFunc,
const std::function<void()>& postChangeNotify = std::function<void()>()) :
TwoWayMaterialBinding<ValueType>(loadFunc, saveFunc, postChangeNotify),
_spinCtrl(spinCtrl)
{
if (saveFunc)
{
if (std::is_integral<ValueType>::value)
{
_spinCtrl->Bind(wxEVT_SPINCTRL, &SpinCtrlMaterialBinding::onValueChanged, this);
}
else
{
_spinCtrl->Bind(wxEVT_SPINCTRLDOUBLE, &SpinCtrlMaterialBinding::onValueChanged, this);
}
}
}

protected:
void setValueOnControl(const ValueType& value) override
{
_spinCtrl->SetValue(value);
}

void onValueChanged(wxCommandEvent& ev)
{
TwoWayMaterialBinding<ValueType>::updateValueOnTarget(_spinCtrl->GetValue());
}
};

template<typename SpinCtrlType>
class SpinCtrlStageBinding :
public TwoWayStageBinding<decltype(std::declval<SpinCtrlType>().GetValue())>
{
private:
SpinCtrlType* _spinCtrl;
using ValueType = decltype(std::declval<SpinCtrlType>().GetValue());

public:
SpinCtrlBinding(SpinCtrlType* spinCtrl,
SpinCtrlStageBinding(SpinCtrlType* spinCtrl,
const std::function<ValueType(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<IEditableShaderLayer::Ptr()>& acquireSaveTarget,
const std::function<void(const IEditableShaderLayer::Ptr&, ValueType)>& saveFunc,
Expand All @@ -27,11 +68,11 @@ class SpinCtrlBinding :
{
if (std::is_integral<ValueType>::value)
{
_spinCtrl->Bind(wxEVT_SPINCTRL, &SpinCtrlBinding::onValueChanged, this);
_spinCtrl->Bind(wxEVT_SPINCTRL, &SpinCtrlStageBinding::onValueChanged, this);
}
else
{
_spinCtrl->Bind(wxEVT_SPINCTRLDOUBLE, &SpinCtrlBinding::onValueChanged, this);
_spinCtrl->Bind(wxEVT_SPINCTRLDOUBLE, &SpinCtrlStageBinding::onValueChanged, this);
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions radiantcore/shaders/CShader.cpp
Expand Up @@ -52,6 +52,12 @@ float CShader::getPolygonOffset() const
return _template->getPolygonOffset();
}

void CShader::setPolygonOffset(float offset)
{
ensureTemplateCopy();
_template->setPolygonOffset(offset);
}

TexturePtr CShader::getEditorImage()
{
if (!_editorTexture)
Expand Down
1 change: 1 addition & 0 deletions radiantcore/shaders/CShader.h
Expand Up @@ -56,6 +56,7 @@ class CShader final :
/* Material implementation */
int getSortRequest() const override;
float getPolygonOffset() const override;
void setPolygonOffset(float offset) override;
TexturePtr getEditorImage() override;
bool isEditorImageNoTex() override;
TexturePtr lightFalloffImage() override;
Expand Down
7 changes: 7 additions & 0 deletions radiantcore/shaders/ShaderTemplate.h
Expand Up @@ -293,6 +293,13 @@ class ShaderTemplate final
return _polygonOffset;
}

void setPolygonOffset(float offset)
{
if (!_parsed) parseDefinition();
setMaterialFlag(Material::FLAG_POLYGONOFFSET);
_polygonOffset = offset;
}

// Sets the raw block definition contents, will be parsed on demand
void setBlockContents(const std::string& blockContents)
{
Expand Down

0 comments on commit 9e0b59f

Please sign in to comment.