Skip to content

Commit

Permalink
#5532: Start refactoring expression handling in the shader layer. Ins…
Browse files Browse the repository at this point in the history
…tead of keeping track of multiple indices, introduce an ExpressionSlot structure which will hold the necessary information. Alphatest has already been migrated.
  • Loading branch information
codereader committed Mar 14, 2021
1 parent 9179605 commit 9b4e70d
Show file tree
Hide file tree
Showing 16 changed files with 247 additions and 164 deletions.
3 changes: 2 additions & 1 deletion include/ishaderexpression.h
Expand Up @@ -38,6 +38,8 @@ enum ReservedRegisters
class IShaderExpression
{
public:
using Ptr = std::shared_ptr<IShaderExpression>;

/**
* Retrieve the floating point value of this expression. DEPRECATED
*/
Expand Down Expand Up @@ -81,7 +83,6 @@ class IShaderExpression
// Returns the string this expression has been parsed from
virtual std::string getExpressionString() = 0;
};
typedef std::shared_ptr<IShaderExpression> IShaderExpressionPtr;

// Interface of a material expression used to specify a map image
// It can either represent a texture path to a file on disk or
Expand Down
30 changes: 20 additions & 10 deletions include/ishaderlayer.h
Expand Up @@ -99,6 +99,16 @@ class IShaderLayer
PF_HasColoredKeyword = 1 << 3, // colored has been specified
};

// Expression slot selector
struct Expression
{
enum Slot
{
AlphaTest = 0,
NumExpressionSlots
};
};

/**
* \brief
* Destructor
Expand Down Expand Up @@ -148,7 +158,7 @@ class IShaderLayer
virtual float getTexGenParam(std::size_t index) const = 0;

// The expressions used to calculate the tex gen params. Index in [0..2]
virtual shaders::IShaderExpressionPtr getTexGenExpression(std::size_t index) const = 0;
virtual shaders::IShaderExpression::Ptr getTexGenExpression(std::size_t index) const = 0;

/**
* \brief
Expand Down Expand Up @@ -180,7 +190,7 @@ class IShaderLayer
};

// Returns the expression to calculate the RGBA vertex colour values
virtual const shaders::IShaderExpressionPtr& getColourExpression(ColourComponentSelector component) const = 0;
virtual const shaders::IShaderExpression::Ptr& getColourExpression(ColourComponentSelector component) const = 0;

/**
* \brief
Expand Down Expand Up @@ -242,38 +252,38 @@ class IShaderLayer
virtual Vector2 getScale() const = 0;

// Returns the expression of the given scale component (0 == x, 1 == y)
virtual const shaders::IShaderExpressionPtr& getScaleExpression(std::size_t index) const = 0;
virtual const shaders::IShaderExpression::Ptr& getScaleExpression(std::size_t index) const = 0;

// Workaround: the shader layer is storing the centerscale expression in the same location as scale expressions,
// making them mutually exclusive - which is not the way the idTech4 materials work.
// These stage transforms need to be redesigned to support an arbitrary number of transforms respecting their order.
// Texture Matrix calculation needs to be performed by the stage itself, not in OpenGLShaderPass
// I need to go ahead with the material editor, so I'm not changing it immediately
virtual const shaders::IShaderExpressionPtr& getCenterScaleExpression(std::size_t index) const = 0;
virtual const shaders::IShaderExpression::Ptr& getCenterScaleExpression(std::size_t index) const = 0;

/**
* Returns the value of the translate expressions of this stage.
*/
virtual Vector2 getTranslation() const = 0;

// Returns the expression of the given translation component (0 == x, 1 == y)
virtual const shaders::IShaderExpressionPtr& getTranslationExpression(std::size_t index) const = 0;
virtual const shaders::IShaderExpression::Ptr& getTranslationExpression(std::size_t index) const = 0;

/**
* Returns the value of the rotate expression of this stage.
*/
virtual float getRotation() const = 0;

// Returns the expression used to calculate the rotation value
virtual const shaders::IShaderExpressionPtr& getRotationExpression() const = 0;
virtual const shaders::IShaderExpression::Ptr& getRotationExpression() const = 0;

/**
* Returns the value of the 'shear' expressions of this stage.
*/
virtual Vector2 getShear() const = 0;

// Returns the expression of the given shear component (0 == x, 1 == y)
virtual const shaders::IShaderExpressionPtr& getShearExpression(std::size_t index) const = 0;
virtual const shaders::IShaderExpression::Ptr& getShearExpression(std::size_t index) const = 0;

// Returns true if this layer has an alphatest expression defined
virtual bool hasAlphaTest() const = 0;
Expand All @@ -289,7 +299,7 @@ class IShaderLayer
virtual float getAlphaTest() const = 0;

// Returns the expression used to calculate the alpha test value
virtual const shaders::IShaderExpressionPtr& getAlphaTestExpression() const = 0;
virtual const shaders::IShaderExpression::Ptr& getAlphaTestExpression() const = 0;

/**
* Whether this stage is active. Unconditional stages always return true,
Expand All @@ -298,7 +308,7 @@ class IShaderLayer
virtual bool isVisible() const = 0;

// Returns the if-expression used to evaluate this stage's visibility, or null if none defined
virtual const shaders::IShaderExpressionPtr& getConditionExpression() const = 0;
virtual const shaders::IShaderExpression::Ptr& getConditionExpression() const = 0;

/**
* Returns the name of this stage's fragment program.
Expand Down Expand Up @@ -326,7 +336,7 @@ class IShaderLayer
{}

int index;
shaders::IShaderExpressionPtr expressions[4];
shaders::IShaderExpression::Ptr expressions[4];
};

// Returns the vertex parameter with the given index [0..3]
Expand Down
4 changes: 2 additions & 2 deletions include/ishaders.h
Expand Up @@ -243,7 +243,7 @@ class Material
virtual DeformType getDeformType() const = 0;

// Returns the shader expression used to define the deform parameters (valid indices in [0..2])
virtual shaders::IShaderExpressionPtr getDeformExpression(std::size_t index) = 0;
virtual shaders::IShaderExpression::Ptr getDeformExpression(std::size_t index) = 0;

// Used for Deform_Particle/Particle2 defines the name of the particle def
virtual std::string getDeformDeclName() = 0;
Expand Down Expand Up @@ -489,7 +489,7 @@ class MaterialManager
* Creates a new shader expression for the given string. This can be used to create standalone
* expression objects for unit testing purposes.
*/
virtual shaders::IShaderExpressionPtr createShaderExpressionFromString(const std::string& exprStr) = 0;
virtual shaders::IShaderExpression::Ptr createShaderExpressionFromString(const std::string& exprStr) = 0;

// Creates a named, internal material for debug/testing etc.
// Used by shaders without corresponding material declaration, like entity wireframe shaders
Expand Down
4 changes: 2 additions & 2 deletions radiant/ui/materials/ExpressionBinding.h
Expand Up @@ -12,13 +12,13 @@ class ExpressionBinding :
{
private:
wxTextCtrl* _textCtrl;
std::function<shaders::IShaderExpressionPtr(const IShaderLayer::Ptr&)> _getExpression;
std::function<shaders::IShaderExpression::Ptr(const IShaderLayer::Ptr&)> _getExpression;
std::function<void(const IEditableShaderLayer::Ptr&, const std::string&)> _updateExpression;
std::function<void()> _postChangeNotify;

public:
ExpressionBinding(wxTextCtrl* textCtrl,
const std::function<shaders::IShaderExpressionPtr(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<shaders::IShaderExpression::Ptr(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<IEditableShaderLayer::Ptr()>& acquireSaveTarget,
const std::function<void(const IEditableShaderLayer::Ptr&, const std::string&)>& saveFunc,
const std::function<void()>& postChangeNotify = std::function<void()>()) :
Expand Down
2 changes: 1 addition & 1 deletion radiant/ui/materials/MaterialEditor.cpp
Expand Up @@ -364,7 +364,7 @@ void MaterialEditor::setupStageFlag(const std::string& controlName, int flags)
}

void MaterialEditor::createExpressionBinding(const std::string& textCtrlName,
const std::function<shaders::IShaderExpressionPtr(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<shaders::IShaderExpression::Ptr(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<void(const IEditableShaderLayer::Ptr&, const std::string&)>& saveFunc)
{
_stageBindings.emplace(std::make_shared<ExpressionBinding>(
Expand Down
2 changes: 1 addition & 1 deletion radiant/ui/materials/MaterialEditor.h
Expand Up @@ -80,7 +80,7 @@ class MaterialEditor :
void setupStageFlag(const std::string& controlName, int flags);

void createExpressionBinding(const std::string& textCtrlName,
const std::function<shaders::IShaderExpressionPtr(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<shaders::IShaderExpression::Ptr(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<void(const IEditableShaderLayer::Ptr&, const std::string&)>& saveFunc = std::function<void(const IEditableShaderLayer::Ptr&, const std::string&)>());

void updateControlsFromMaterial();
Expand Down
2 changes: 1 addition & 1 deletion radiantcore/shaders/CShader.cpp
Expand Up @@ -196,7 +196,7 @@ Material::DeformType CShader::getDeformType() const
return _template->getDeformType();
}

IShaderExpressionPtr CShader::getDeformExpression(std::size_t index)
IShaderExpression::Ptr CShader::getDeformExpression(std::size_t index)
{
return _template->getDeformExpression(index);
}
Expand Down
2 changes: 1 addition & 1 deletion radiantcore/shaders/CShader.h
Expand Up @@ -74,7 +74,7 @@ class CShader final :
SurfaceType getSurfaceType() const override;
void setSurfaceType(SurfaceType type) override;
DeformType getDeformType() const override;
IShaderExpressionPtr getDeformExpression(std::size_t index) override;
IShaderExpression::Ptr getDeformExpression(std::size_t index) override;
std::string getDeformDeclName() override;
int getSpectrum() const override;
DecalInfo getDecalInfo() const override;
Expand Down
112 changes: 62 additions & 50 deletions radiantcore/shaders/Doom3ShaderLayer.cpp
Expand Up @@ -76,11 +76,61 @@ BlendFunc blendFuncFromStrings(const StringPair& blendFunc)

// IShaderLayer implementation

const IShaderExpressionPtr Doom3ShaderLayer::NULL_EXPRESSION;
const IShaderExpression::Ptr Doom3ShaderLayer::NULL_EXPRESSION;

void ExpressionSlots::assign(IShaderLayer::Expression::Slot slot, const IShaderExpression::Ptr& newExpression, std::size_t defaultRegisterIndex)
{
auto& expressionSlot = at(slot);

if (!newExpression)
{
expressionSlot.expression.reset();
expressionSlot.expressionIndex = ExpressionSlot::Unused;
expressionSlot.registerIndex = defaultRegisterIndex;
return;
}

// Non-empty expression, overwrite if we have an existing expression in the slot
if (expressionSlot.expression)
{
// We assume that if there was an expression in the slot, it shouldn't point to the default registers
assert(expressionSlot.registerIndex != defaultRegisterIndex);

// Re-use the register index
expressionSlot.expression = newExpression;
expressionSlot.expression->linkToSpecificRegister(_registers, expressionSlot.registerIndex);
}
else
{
expressionSlot.expression = newExpression;
expressionSlot.registerIndex = expressionSlot.expression->linkToRegister(_registers);
}
}

void ExpressionSlots::assignFromString(IShaderLayer::Expression::Slot slot, const std::string& expressionString, std::size_t defaultRegisterIndex)
{
// An empty string will clear the expression
if (expressionString.empty())
{
assign(slot, IShaderExpression::Ptr(), defaultRegisterIndex);
return;
}

// Attempt to parse the string
auto expression = ShaderExpression::createFromString(expressionString);

if (!expression)
{
return; // parsing failures will not overwrite the expression slot
}

assign(slot, expression, defaultRegisterIndex);
}

Doom3ShaderLayer::Doom3ShaderLayer(ShaderTemplate& material, IShaderLayer::Type type, const NamedBindablePtr& btex)
: _material(material),
_registers(NUM_RESERVED_REGISTERS),
_expressionSlots(_registers),
_condition(REG_ONE),
_conditionExpression(NOT_DEFINED),
_bindableTex(btex),
Expand All @@ -91,15 +141,15 @@ Doom3ShaderLayer::Doom3ShaderLayer(ShaderTemplate& material, IShaderLayer::Type
_cubeMapMode(CUBE_MAP_NONE),
_stageFlags(0),
_clampType(CLAMP_REPEAT),
_alphaTest(REG_ZERO),
_alphaTestExpression(NOT_DEFINED),
_texGenType(TEXGEN_NORMAL),
_privatePolygonOffset(0),
_parseFlags(0)
{
_registers[REG_ZERO] = 0;
_registers[REG_ONE] = 1;

_expressionSlots[Expression::AlphaTest].registerIndex = REG_ZERO;

// Init the colour to 1,1,1,1
_colIdx[0] = _colIdx[1] = _colIdx[2] = _colIdx[3] = REG_ONE;
_colExpression[0] = _colExpression[1] = _colExpression[2] = _colExpression[3] = NOT_DEFINED;
Expand Down Expand Up @@ -128,6 +178,7 @@ Doom3ShaderLayer::Doom3ShaderLayer(const Doom3ShaderLayer& other, ShaderTemplate
_material(material),
_registers(other._registers),
_expressions(other._expressions),
_expressionSlots(other._expressionSlots, _registers),
_condition(other._condition),
_conditionExpression(other._conditionExpression),
_bindableTex(other._bindableTex),
Expand All @@ -139,8 +190,6 @@ Doom3ShaderLayer::Doom3ShaderLayer(const Doom3ShaderLayer& other, ShaderTemplate
_cubeMapMode(other._cubeMapMode),
_stageFlags(other._stageFlags),
_clampType(other._clampType),
_alphaTest(other._alphaTest),
_alphaTestExpression(other._alphaTestExpression),
_texGenType(other._texGenType),
_rotation(other._rotation),
_rotationExpression(other._rotationExpression),
Expand Down Expand Up @@ -215,7 +264,7 @@ Colour4 Doom3ShaderLayer::getColour() const
return colour;
}

const IShaderExpressionPtr& Doom3ShaderLayer::getColourExpression(ColourComponentSelector component) const
const IShaderExpression::Ptr& Doom3ShaderLayer::getColourExpression(ColourComponentSelector component) const
{
std::size_t expressionIndex = NOT_DEFINED;

Expand Down Expand Up @@ -254,7 +303,7 @@ const IShaderExpressionPtr& Doom3ShaderLayer::getColourExpression(ColourComponen
return expressionIndex != NOT_DEFINED ? _expressions[expressionIndex] : NULL_EXPRESSION;
}

void Doom3ShaderLayer::setColourExpression(ColourComponentSelector comp, const IShaderExpressionPtr& expr)
void Doom3ShaderLayer::setColourExpression(ColourComponentSelector comp, const IShaderExpression::Ptr& expr)
{
// Store the expression and link it to our registers
auto expressionIndex = _expressions.size();
Expand Down Expand Up @@ -353,17 +402,17 @@ void Doom3ShaderLayer::setRenderMapSize(const Vector2& size)

bool Doom3ShaderLayer::hasAlphaTest() const
{
return _alphaTestExpression != NOT_DEFINED;
return _expressionSlots[Expression::AlphaTest].expression != nullptr;
}

float Doom3ShaderLayer::getAlphaTest() const
{
return _registers[_alphaTest];
return _registers[_expressionSlots[Expression::AlphaTest].registerIndex];
}

const shaders::IShaderExpressionPtr& Doom3ShaderLayer::getAlphaTestExpression() const
const IShaderExpression::Ptr& Doom3ShaderLayer::getAlphaTestExpression() const
{
return _alphaTestExpression != NOT_DEFINED ? _expressions[_alphaTestExpression] : NULL_EXPRESSION;
return _expressionSlots[Expression::AlphaTest].expression;
}

TexturePtr Doom3ShaderLayer::getFragmentMapTexture(int index) const
Expand Down Expand Up @@ -514,7 +563,7 @@ void Doom3ShaderLayer::addVertexParm(const VertexParm& parm)
assert(_vertexParms.size() % 4 == 0);
}

void Doom3ShaderLayer::assignExpression(const IShaderExpressionPtr& expression,
void Doom3ShaderLayer::assignExpression(const IShaderExpression::Ptr& expression,
std::size_t& expressionIndex, std::size_t& registerIndex, std::size_t defaultRegisterIndex)
{
if (!expression)
Expand Down Expand Up @@ -566,19 +615,7 @@ void Doom3ShaderLayer::assignExpressionFromString(const std::string& expressionS
// An empty string will clear the expression
if (expressionString.empty())
{
assignExpression(IShaderExpressionPtr(), expressionIndex, registerIndex, defaultRegisterIndex);
#if 0
if (expressionIndex != NOT_DEFINED)
{
assert(_expressions[expressionIndex]);

_expressions[expressionIndex]->unlinkFromRegisters();
_expressions[expressionIndex].reset();
}

registerIndex = defaultRegisterIndex;
expressionIndex = NOT_DEFINED;
#endif
assignExpression(IShaderExpression::Ptr(), expressionIndex, registerIndex, defaultRegisterIndex);
return;
}

Expand All @@ -591,31 +628,6 @@ void Doom3ShaderLayer::assignExpressionFromString(const std::string& expressionS
}

assignExpression(expression, expressionIndex, registerIndex, defaultRegisterIndex);
#if 0
if (expressionIndex != NOT_DEFINED)
{
// Try to re-use the previous register position
auto previousExpression = _expressions[expressionIndex];
_expressions[expressionIndex] = expression;

if (previousExpression->isLinked())
{
registerIndex = previousExpression->unlinkFromRegisters();
expression->linkToSpecificRegister(_registers, registerIndex);
}
else
{
registerIndex = expression->linkToRegister(_registers);
}
}
else
{
expressionIndex = _expressions.size();
_expressions.emplace_back(expression);

registerIndex = expression->linkToRegister(_registers);
}
#endif
}

}

0 comments on commit 9b4e70d

Please sign in to comment.