Skip to content

Commit

Permalink
#5532: Transformation edit controls
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Mar 19, 2021
1 parent 954b069 commit 15af1b0
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 21 deletions.
11 changes: 11 additions & 0 deletions include/ishaderlayer.h
Expand Up @@ -407,4 +407,15 @@ class IEditableShaderLayer :

// Update the "map" expression of this stage
virtual void setMapExpressionFromString(const std::string& expression) = 0;

// Adds a empty transformation to this layer, returning its new index
virtual std::size_t addTransformation(TransformType type, const std::string& expression1, const std::string& expression2) = 0;

// Removes the indexed transformation
virtual void removeTransformation(std::size_t index) = 0;

// Set the type and expressions of the indexed transformation. The transformation index must not be
// out of bounds, use appendTransformation() to add new ones
virtual void updateTransformation(std::size_t index, TransformType type,
const std::string& expression1, const std::string& expression2) = 0;
};
70 changes: 55 additions & 15 deletions radiant/ui/materials/MaterialEditor.cpp
Expand Up @@ -468,8 +468,12 @@ void MaterialEditor::setupMaterialStageProperties()
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);
transformView->AppendTextColumn("Index", _stageTransformationColumns.index.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);
transformView->AppendTextColumn("Expression", _stageTransformationColumns.expression.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);
transformView->AppendTextColumn("Expr1", _stageTransformationColumns.expression1.getColumnIndex(),
wxDATAVIEW_CELL_EDITABLE, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);
transformView->AppendTextColumn("Expr2", _stageTransformationColumns.expression2.getColumnIndex(),
wxDATAVIEW_CELL_EDITABLE, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);

transformView->Bind(wxEVT_DATAVIEW_ITEM_EDITING_DONE, &MaterialEditor::_onStageTransformEdited, this);

transformationPanel->GetSizer()->Add(transformView, 1, wxEXPAND);

Expand All @@ -492,10 +496,10 @@ void MaterialEditor::setupMaterialStageProperties()
_stageProgramParameters = wxutil::TreeModel::Ptr(new wxutil::TreeModel(_stageProgramColumns, true));

auto paramsView = wxutil::TreeView::CreateWithModel(parameterPanel, _stageProgramParameters.get(), wxDV_NO_HEADER);
paramsView->AppendTextColumn("Type", _stageProgramColumns.type.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);
paramsView->AppendTextColumn("Index", _stageProgramColumns.index.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);
paramsView->AppendTextColumn("Type", _stageProgramColumns.type.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);
paramsView->AppendTextColumn("Expression", _stageProgramColumns.expression.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);

Expand Down Expand Up @@ -1019,17 +1023,10 @@ void MaterialEditor::updateStageTransformControls()
row[_stageTransformationColumns.type] = shaders::getStringForTransformType(transformation.type);
row[_stageTransformationColumns.index] = string::to_string(i);

if (transformation.expression1)
{
auto expression = transformation.expression1->getExpressionString();
row[_stageTransformationColumns.expression] = expression;
}
else
{
row[_stageTransformationColumns.expression] = std::string();
}

row[_stageTransformationColumns.expression] = expression;
row[_stageTransformationColumns.expression1] = transformation.expression1 ?
transformation.expression1->getExpressionString() : std::string();
row[_stageTransformationColumns.expression2] = transformation.expression2 ?
transformation.expression2->getExpressionString() : std::string();

row.SendItemAdded();
}
Expand Down Expand Up @@ -1188,6 +1185,49 @@ void MaterialEditor::_onAddStageTransform(wxCommandEvent& ev)
}
}

void MaterialEditor::_onStageTransformEdited(wxDataViewEvent& ev)
{
if (ev.IsEditCancelled()) return;

auto stage = getEditableStageForSelection();

if (!stage) return;

wxutil::TreeModel::Row row(ev.GetItem(), *_stageTransformations);

// The iter points to the edited cell now, get the actor number
int transformIndex = row[_stageTransformationColumns.index].getInteger();
std::string transformTypeString = row[_stageTransformationColumns.type];

if (transformIndex < 0 || transformIndex > stage->getTransformations().size())
{
return;
}

std::string expression1, expression2;
auto type = shaders::getTransformTypeForString(transformTypeString);

#if wxCHECK_VERSION(3, 1, 0)
// wx 3.1+ delivers the new value through the event
if (ev.GetColumn() == _stageTransformationColumns.expression1.getColumnIndex())
{
expression1 = ev.GetValue().GetString().ToStdString();
expression2 = row[_stageTransformationColumns.expression2];
}
else if (ev.GetColumn() == _stageTransformationColumns.expression2.getColumnIndex())
{
expression1 = row[_stageTransformationColumns.expression1];
expression2 = ev.GetValue().GetString().ToStdString();
}
#else
// wx 3.0.x has the values set in the model
expression1 = row[_stageTransformationColumns.expression1];
expression2 = row[_stageTransformationColumns.expression2];
#endif

stage->updateTransformation(transformIndex, type, expression1, expression2);
}

void MaterialEditor::onMaterialChanged()
{
_preview->onMaterialChanged();
Expand Down
25 changes: 21 additions & 4 deletions radiant/ui/materials/MaterialEditor.h
Expand Up @@ -38,10 +38,10 @@ class MaterialEditor :
std::set<std::shared_ptr<Binding<IShaderLayer::Ptr>>> _stageBindings;
std::map<Material::DeformType, wxPanel*> _deformPanels;

struct IndexedExpressionColumns :
struct StageProgramColumns :
public wxutil::TreeModel::ColumnRecord
{
IndexedExpressionColumns() :
StageProgramColumns() :
type(add(wxutil::TreeModel::Column::String)),
index(add(wxutil::TreeModel::Column::String)),
expression(add(wxutil::TreeModel::Column::String))
Expand All @@ -52,10 +52,26 @@ class MaterialEditor :
wxutil::TreeModel::Column expression;
};

IndexedExpressionColumns _stageProgramColumns;
struct StageTransformColumns :
public wxutil::TreeModel::ColumnRecord
{
StageTransformColumns() :
type(add(wxutil::TreeModel::Column::String)),
index(add(wxutil::TreeModel::Column::String)),
expression1(add(wxutil::TreeModel::Column::String)),
expression2(add(wxutil::TreeModel::Column::String))
{}

wxutil::TreeModel::Column type;
wxutil::TreeModel::Column index;
wxutil::TreeModel::Column expression1;
wxutil::TreeModel::Column expression2;
};

StageProgramColumns _stageProgramColumns;
wxutil::TreeModel::Ptr _stageProgramParameters;

IndexedExpressionColumns _stageTransformationColumns;
StageTransformColumns _stageTransformationColumns;
wxutil::TreeModel::Ptr _stageTransformations;

bool _stageUpdateInProgress;
Expand Down Expand Up @@ -105,6 +121,7 @@ class MaterialEditor :
void _onStageListSelectionChanged(wxDataViewEvent& ev);
void _onMaterialTypeChoice(wxCommandEvent& ev);
void _onAddStageTransform(wxCommandEvent& ev);
void _onStageTransformEdited(wxDataViewEvent& ev);

void onMaterialChanged();

Expand Down
81 changes: 79 additions & 2 deletions radiantcore/shaders/Doom3ShaderLayer.cpp
Expand Up @@ -74,6 +74,17 @@ BlendFunc blendFuncFromStrings(const StringPair& blendFunc)
}
}

inline IShaderExpression::Ptr getDefaultExpressionForTransformType(IShaderLayer::TransformType type)
{
if (type == IShaderLayer::TransformType::CenterScale ||
type == IShaderLayer::TransformType::Scale)
{
return ShaderExpression::createConstant(1);
}

return ShaderExpression::createConstant(0);
}

// IShaderLayer implementation

const IShaderExpression::Ptr Doom3ShaderLayer::NULL_EXPRESSION;
Expand Down Expand Up @@ -265,11 +276,23 @@ void Doom3ShaderLayer::setColour(const Vector4& col)

void Doom3ShaderLayer::appendTransformation(const Transformation& transform)
{
Transformation copy(transform);

if (!copy.expression1)
{
copy.expression1 = getDefaultExpressionForTransformType(transform.type);
}

if (!copy.expression2 && transform.type != TransformType::Rotate)
{
copy.expression2 = getDefaultExpressionForTransformType(transform.type);
}

// Store this original transformation, we need it later
_transformations.emplace_back(transform);
_transformations.emplace_back(copy);

// Construct a transformation matrix and multiply it on top of the existing one
_textureMatrix.applyTransformation(transform);
_textureMatrix.applyTransformation(copy);
}

const std::vector<IShaderLayer::Transformation>& Doom3ShaderLayer::getTransformations()
Expand Down Expand Up @@ -480,4 +503,58 @@ void Doom3ShaderLayer::addVertexParm(const VertexParm& parm)
assert(_vertexParms.size() % 4 == 0);
}

void Doom3ShaderLayer::recalculateTransformationMatrix()
{
_textureMatrix.setIdentity();

for (const auto& transform : _transformations)
{
_textureMatrix.applyTransformation(transform);
}
}

std::size_t Doom3ShaderLayer::addTransformation(TransformType type, const std::string& expression1, const std::string& expression2)
{
_transformations.emplace_back(Transformation
{
type,
ShaderExpression::createFromString(expression1),
type != TransformType::Rotate ? ShaderExpression::createFromString(expression2) : IShaderExpression::Ptr()
});

recalculateTransformationMatrix();

return _transformations.size() - 1;
}

void Doom3ShaderLayer::removeTransformation(std::size_t index)
{
assert(index >= 0 && index < _transformations.size());

_transformations.erase(_transformations.begin() + index);

recalculateTransformationMatrix();
}

void Doom3ShaderLayer::updateTransformation(std::size_t index, TransformType type, const std::string& expression1, const std::string& expression2)
{
assert(index >= 0 && index < _transformations.size());

_transformations[index].type = type;
auto expr1 = ShaderExpression::createFromString(expression1);
_transformations[index].expression1 = expr1 ? expr1 : getDefaultExpressionForTransformType(type);;

if (type != TransformType::Rotate)
{
auto expr2 = ShaderExpression::createFromString(expression2);
_transformations[index].expression2 = expr2 ? expr2 : getDefaultExpressionForTransformType(type);
}
else
{
_transformations[index].expression2.reset();
}

recalculateTransformationMatrix();
}

}
7 changes: 7 additions & 0 deletions radiantcore/shaders/Doom3ShaderLayer.h
Expand Up @@ -429,8 +429,15 @@ class Doom3ShaderLayer :
shaders::IMapExpression::Ptr getMapExpression() const override;
void setMapExpressionFromString(const std::string& expression) override;

std::size_t addTransformation(TransformType type, const std::string& expression1, const std::string& expression2) override;
void removeTransformation(std::size_t index) override;
void updateTransformation(std::size_t index, TransformType type, const std::string& expression1, const std::string& expression2) override;

int getParseFlags() const override;
void setParseFlag(ParseFlags flag);

private:
void recalculateTransformationMatrix();
};

}
Expand Down
21 changes: 21 additions & 0 deletions radiantcore/shaders/TextureMatrix.cpp
Expand Up @@ -6,6 +6,18 @@
namespace shaders
{

namespace
{
inline void unlinkAndDeleteExpression(IShaderExpression::Ptr& expression)
{
if (expression)
{
expression->unlinkFromRegisters();
expression.reset();
}
}
}

struct TextureMatrix::TemporaryMatrix
{
IShaderExpression::Ptr xx;
Expand All @@ -30,6 +42,13 @@ void TextureMatrix::setIdentity()
xy().registerIndex = REG_ZERO;
yy().registerIndex = REG_ONE;
ty().registerIndex = REG_ZERO;

unlinkAndDeleteExpression(xx().expression);
unlinkAndDeleteExpression(yx().expression);
unlinkAndDeleteExpression(tx().expression);
unlinkAndDeleteExpression(xy().expression);
unlinkAndDeleteExpression(yy().expression);
unlinkAndDeleteExpression(ty().expression);
}

Matrix4 TextureMatrix::getMatrix4()
Expand Down Expand Up @@ -154,6 +173,8 @@ void TextureMatrix::multiplyMatrix(const TemporaryMatrix& matrix)

IShaderExpression::Ptr TextureMatrix::add(const IShaderExpression::Ptr& a, const IShaderExpression::Ptr& b)
{
assert(a);
assert(b);
return ShaderExpression::createAddition(a, b);
}

Expand Down

0 comments on commit 15af1b0

Please sign in to comment.