From b770360ee15a6022b039a1e56a4dc3bdf3a452a6 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 27 Mar 2022 21:10:33 +0200 Subject: [PATCH] Parse techniques --- .../Sequence/TechniqueNoScopeSequences.cpp | 44 ++++ .../Sequence/TechniqueNoScopeSequences.h | 15 ++ .../Sequence/TechniquePassScopeSequences.cpp | 200 +++++++++++++++++ .../Sequence/TechniquePassScopeSequences.h | 15 ++ .../TechniqueShaderScopeSequences.cpp | 207 ++++++++++++++++++ .../Sequence/TechniqueShaderScopeSequences.h | 15 ++ .../Techset/Parsing/TechniqueFileParser.cpp | 16 +- .../Parsing/TechniqueFileParserState.cpp | 6 +- .../Parsing/TechniqueFileParserState.h | 5 + .../Techset/TechniqueDefinitionAcceptor.h | 2 + .../AssetDumpers/AssetDumperTechniqueSet.cpp | 2 +- 11 files changed, 520 insertions(+), 7 deletions(-) create mode 100644 src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp create mode 100644 src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h create mode 100644 src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp create mode 100644 src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.h create mode 100644 src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp create mode 100644 src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp b/src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp new file mode 100644 index 00000000..9abdf1c2 --- /dev/null +++ b/src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp @@ -0,0 +1,44 @@ +#include "TechniqueNoScopeSequences.h" + +#include + +#include "Parsing/Simple/Matcher/SimpleMatcherFactory.h" + +using namespace techset; + +namespace techset +{ + class SequencePass final : public TechniqueParser::sequence_t + { + public: + SequencePass() + { + const SimpleMatcherFactory create(this); + + AddMatchers({ + create.Char('{') + }); + } + + protected: + void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override + { + assert(state->m_in_pass == false); + state->m_in_pass = true; + + if (state->m_before_first_pass) + state->m_before_first_pass = false; + else + state->m_acceptor->AcceptNextPass(); + } + }; +} + +const std::vector& TechniqueNoScopeSequences::GetSequences() +{ + static std::vector tests({ + new SequencePass() + }); + + return tests; +} diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h b/src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h new file mode 100644 index 00000000..d8f33f7e --- /dev/null +++ b/src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h @@ -0,0 +1,15 @@ +#pragma once +#include + +#include "Techset/Parsing/TechniqueFileParser.h" + +namespace techset +{ + class TechniqueNoScopeSequences + { + TechniqueNoScopeSequences() = default; + + public: + static const std::vector& GetSequences(); + }; +} diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp b/src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp new file mode 100644 index 00000000..bd95f818 --- /dev/null +++ b/src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp @@ -0,0 +1,200 @@ +#include "TechniquePassScopeSequences.h" + +#include +#include + +#include "Parsing/Simple/Matcher/SimpleMatcherFactory.h" + +using namespace techset; + +namespace techset +{ + class SequenceEndPass final : public TechniqueParser::sequence_t + { + public: + SequenceEndPass() + { + const SimpleMatcherFactory create(this); + + AddMatchers({ + create.Char('}') + }); + } + + protected: + void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override + { + assert(state->m_in_pass == true); + state->m_in_pass = false; + } + }; + + class SequenceStateMap final : public TechniqueParser::sequence_t + { + static constexpr auto CAPTURE_STATE_MAP_NAME = 1; + + public: + SequenceStateMap() + { + const SimpleMatcherFactory create(this); + + AddMatchers({ + create.Keyword("stateMap"), + create.String().Capture(CAPTURE_STATE_MAP_NAME), + create.Char(';') + }); + } + + protected: + void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override + { + state->m_acceptor->AcceptStateMap(result.NextCapture(CAPTURE_STATE_MAP_NAME).StringValue()); + } + }; + + class SequenceShader final : public TechniqueParser::sequence_t + { + static constexpr auto TAG_VERTEX_SHADER = 1; + static constexpr auto TAG_PIXEL_SHADER = 2; + + static constexpr auto CAPTURE_START = 1; + static constexpr auto CAPTURE_VERSION_MAJOR = 2; + static constexpr auto CAPTURE_VERSION_MINOR = 3; + static constexpr auto CAPTURE_SHADER_NAME = 4; + + public: + SequenceShader() + { + const SimpleMatcherFactory create(this); + + AddMatchers({ + create.Or({ + create.Keyword("vertexShader").Tag(TAG_VERTEX_SHADER), + create.Keyword("pixelShader").Tag(TAG_PIXEL_SHADER), + }).Capture(CAPTURE_START), + create.Integer().Capture(CAPTURE_VERSION_MAJOR), + create.Char('.'), + create.Integer().Capture(CAPTURE_VERSION_MINOR), + create.String().Capture(CAPTURE_SHADER_NAME), + create.Char('{') + }); + } + + protected: + void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override + { + const auto& firstToken = result.NextCapture(CAPTURE_START); + + const auto& versionMajorToken = result.NextCapture(CAPTURE_VERSION_MAJOR); + if (versionMajorToken.IntegerValue() < 0) + throw ParsingException(versionMajorToken.GetPos(), "Major version must be positive"); + const auto versionMajor = static_cast(versionMajorToken.IntegerValue()); + + const auto& versionMinorToken = result.NextCapture(CAPTURE_VERSION_MINOR); + if (versionMinorToken.IntegerValue() < 0) + throw ParsingException(versionMinorToken.GetPos(), "Minor version must be positive"); + const auto versionMinor = static_cast(versionMajorToken.IntegerValue()); + + const auto& shaderNameToken = result.NextCapture(CAPTURE_SHADER_NAME); + + bool acceptorResult; + std::string errorMessage; + const auto shaderTag = result.NextTag(); + assert(shaderTag == TAG_VERTEX_SHADER || shaderTag == TAG_PIXEL_SHADER); + if (shaderTag == TAG_VERTEX_SHADER) + { + acceptorResult = state->m_acceptor->AcceptVertexShader(versionMajor, versionMinor, shaderNameToken.StringValue(), errorMessage); + state->m_current_shader = ShaderSelector::VERTEX_SHADER; + } + else + { + acceptorResult = state->m_acceptor->AcceptPixelShader(versionMajor, versionMinor, shaderNameToken.StringValue(), errorMessage); + state->m_current_shader = ShaderSelector::PIXEL_SHADER; + } + + state->m_in_shader = true; + + if (!acceptorResult) + throw ParsingException(firstToken.GetPos(), std::move(errorMessage)); + } + }; + + class SequenceVertexStreamRouting final : public TechniqueParser::sequence_t + { + static constexpr auto CAPTURE_FIRST_TOKEN = 1; + static constexpr auto CAPTURE_STREAM_DESTINATION_NAME = 2; + static constexpr auto CAPTURE_STREAM_DESTINATION_INDEX = 3; + static constexpr auto CAPTURE_STREAM_SOURCE_NAME = 4; + static constexpr auto CAPTURE_STREAM_SOURCE_INDEX = 5; + + public: + SequenceVertexStreamRouting() + { + const SimpleMatcherFactory create(this); + + AddMatchers({ + create.Keyword("vertex").Capture(CAPTURE_FIRST_TOKEN), + create.Char('.'), + create.Identifier().Capture(CAPTURE_STREAM_DESTINATION_NAME), + create.Optional(create.And({ + create.Char('['), + create.Integer().Capture(CAPTURE_STREAM_DESTINATION_INDEX), + create.Char(']') + })), + + create.Char('='), + + create.Keyword("code"), + create.Char('.'), + create.Identifier().Capture(CAPTURE_STREAM_SOURCE_NAME), + create.Optional(create.And({ + create.Char('['), + create.Integer().Capture(CAPTURE_STREAM_SOURCE_INDEX), + create.Char(']') + })), + + create.Char(';') + }); + } + + static std::string CreateRoutingString(SequenceResult& result, const int nameCapture, const int indexCapture) + { + if (result.HasNextCapture(indexCapture)) + { + const auto& indexToken = result.NextCapture(indexCapture); + if (indexToken.IntegerValue() < 0) + throw ParsingException(indexToken.GetPos(), "Index cannot be negative"); + + std::ostringstream ss; + ss << result.NextCapture(nameCapture).IdentifierValue() << '[' << indexToken.IntegerValue() << ']'; + return ss.str(); + } + + return result.NextCapture(nameCapture).IdentifierValue(); + } + + protected: + void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override + { + const auto& firstToken = result.NextCapture(CAPTURE_FIRST_TOKEN); + const std::string destinationString = CreateRoutingString(result, CAPTURE_STREAM_DESTINATION_NAME, CAPTURE_STREAM_DESTINATION_INDEX); + const std::string sourceString = CreateRoutingString(result, CAPTURE_STREAM_SOURCE_NAME, CAPTURE_STREAM_SOURCE_INDEX); + + std::string errorMessage; + if (!state->m_acceptor->AcceptVertexStreamRouting(destinationString, sourceString, errorMessage)) + throw ParsingException(firstToken.GetPos(), std::move(errorMessage)); + } + }; +} + +const std::vector& TechniquePassScopeSequences::GetSequences() +{ + static std::vector tests({ + new SequenceEndPass(), + new SequenceStateMap(), + new SequenceShader(), + new SequenceVertexStreamRouting() + }); + + return tests; +} diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.h b/src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.h new file mode 100644 index 00000000..c159c497 --- /dev/null +++ b/src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.h @@ -0,0 +1,15 @@ +#pragma once +#include + +#include "Techset/Parsing/TechniqueFileParser.h" + +namespace techset +{ + class TechniquePassScopeSequences + { + TechniquePassScopeSequences() = default; + + public: + static const std::vector& GetSequences(); + }; +} diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp b/src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp new file mode 100644 index 00000000..97047553 --- /dev/null +++ b/src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp @@ -0,0 +1,207 @@ +#include "TechniqueShaderScopeSequences.h" + +#include + +#include "Parsing/Simple/Matcher/SimpleMatcherFactory.h" + +using namespace techset; + +namespace techset +{ + class SequenceEndShader final : public TechniqueParser::sequence_t + { + public: + SequenceEndShader() + { + const SimpleMatcherFactory create(this); + + AddMatchers({ + create.Char('}') + }); + } + + protected: + void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override + { + assert(state->m_in_shader == true); + state->m_in_shader = false; + } + }; + + class SequenceShaderArgument final : public TechniqueParser::sequence_t + { + static constexpr auto TAG_CODE = 1; + static constexpr auto TAG_LITERAL = 2; + static constexpr auto TAG_MATERIAL = 3; + + static constexpr auto CAPTURE_FIRST_TOKEN = 1; + static constexpr auto CAPTURE_SHADER_ARGUMENT = 2; + static constexpr auto CAPTURE_SHADER_INDEX = 3; + static constexpr auto CAPTURE_CODE_ACCESSOR = 4; + static constexpr auto CAPTURE_CODE_INDEX = 5; + static constexpr auto CAPTURE_LITERAL_VALUE = 6; + static constexpr auto CAPTURE_MATERIAL_HASH = 7; + static constexpr auto CAPTURE_MATERIAL_NAME = 8; + + static std::unique_ptr CodeMatchers(const SimpleMatcherFactory& create) + { + return create.And({ + create.Keyword("code"), + create.Char('.'), + create.Identifier().Capture(CAPTURE_CODE_ACCESSOR), + create.OptionalLoop(create.And({ + create.Char('.'), + create.Identifier().Capture(CAPTURE_CODE_ACCESSOR) + })), + create.Optional(create.And({ + create.Char('['), + create.Integer().Capture(CAPTURE_CODE_INDEX), + create.Char(']') + })) + }).Tag(TAG_CODE); + } + + static std::unique_ptr LiteralMatchers(const SimpleMatcherFactory& create) + { + return create.And({ + create.Keyword("float4"), + create.Char('('), + create.FloatingPoint().Capture(CAPTURE_LITERAL_VALUE), + create.Char(','), + create.FloatingPoint().Capture(CAPTURE_LITERAL_VALUE), + create.Char(','), + create.FloatingPoint().Capture(CAPTURE_LITERAL_VALUE), + create.Char(','), + create.FloatingPoint().Capture(CAPTURE_LITERAL_VALUE), + create.Char(')'), + }).Tag(TAG_LITERAL); + } + + static std::unique_ptr MaterialMatchers(const SimpleMatcherFactory& create) + { + return create.And({ + create.Keyword("material"), + create.Char('.'), + + create.Or({ + create.And({ + create.Char('#'), + create.Integer().Capture(CAPTURE_MATERIAL_HASH) + }), + create.Identifier().Capture(CAPTURE_MATERIAL_NAME) + }) + }).Tag(TAG_MATERIAL); + } + + public: + SequenceShaderArgument() + { + const SimpleMatcherFactory create(this); + + AddMatchers({ + create.Identifier().Capture(CAPTURE_SHADER_ARGUMENT), + create.Optional(create.And({ + create.Char('['), + create.Integer().Capture(CAPTURE_SHADER_INDEX), + create.Char(']') + })), + create.Char('='), + create.Or({ + CodeMatchers(create), + LiteralMatchers(create), + MaterialMatchers(create) + }), + create.Char(';') + }); + } + + static void ProcessCodeArgument(const TechniqueParserState* state, SequenceResult& result, ShaderArgument arg) + { + std::vector accessors; + while (result.HasNextCapture(CAPTURE_CODE_ACCESSOR)) + accessors.emplace_back(result.NextCapture(CAPTURE_CODE_ACCESSOR).IdentifierValue()); + + ShaderArgumentCodeSource source; + if (result.HasNextCapture(CAPTURE_CODE_INDEX)) + { + const auto& codeIndexToken = result.NextCapture(CAPTURE_CODE_INDEX); + if (codeIndexToken.IntegerValue() < 0) + throw ParsingException(codeIndexToken.GetPos(), "Index cannot be negative"); + source = ShaderArgumentCodeSource(std::move(accessors), static_cast(codeIndexToken.IntegerValue())); + } + else + source = ShaderArgumentCodeSource(std::move(accessors)); + + std::string errorMessage; + if (!state->m_acceptor->AcceptShaderCodeArgument(state->m_current_shader, std::move(arg), std::move(source), errorMessage)) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + } + + static void ProcessLiteralArgument(const TechniqueParserState* state, SequenceResult& result, ShaderArgument arg) + { + float value[4]; + for (float& i : value) + i = static_cast(result.NextCapture(CAPTURE_LITERAL_VALUE).FloatingPointValue()); + + const ShaderArgumentLiteralSource source(value); + std::string errorMessage; + if (!state->m_acceptor->AcceptShaderLiteralArgument(state->m_current_shader, std::move(arg), source, errorMessage)) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + } + + static void ProcessMaterialArgument(const TechniqueParserState* state, SequenceResult& result, ShaderArgument arg) + { + std::string errorMessage; + if (result.HasNextCapture(CAPTURE_MATERIAL_HASH)) + { + ShaderArgumentMaterialSource source(static_cast(result.NextCapture(CAPTURE_MATERIAL_HASH).IntegerValue())); + if (!state->m_acceptor->AcceptShaderMaterialArgument(state->m_current_shader, std::move(arg), std::move(source), errorMessage)) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + } + else + { + ShaderArgumentMaterialSource source(result.NextCapture(CAPTURE_MATERIAL_NAME).IdentifierValue()); + if (!state->m_acceptor->AcceptShaderMaterialArgument(state->m_current_shader, std::move(arg), std::move(source), errorMessage)) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + } + } + + protected: + void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override + { + assert(state->m_in_shader == true); + state->m_in_shader = false; + + const auto& shaderArgumentNameToken = result.NextCapture(CAPTURE_SHADER_ARGUMENT); + + size_t index = 0u; + if (result.HasNextCapture(CAPTURE_SHADER_INDEX)) + { + const auto& shaderArgumentIndexToken = result.NextCapture(CAPTURE_SHADER_INDEX); + if (shaderArgumentIndexToken.IntegerValue() < 0) + throw ParsingException(shaderArgumentIndexToken.GetPos(), "Index cannot be negative"); + index = static_cast(shaderArgumentIndexToken.IntegerValue()); + } + + ShaderArgument arg(shaderArgumentNameToken.IdentifierValue(), index); + + const auto typeTag = result.NextTag(); + assert(typeTag == TAG_CODE || typeTag == TAG_LITERAL || typeTag == TAG_MATERIAL); + if (typeTag == TAG_CODE) + ProcessCodeArgument(state, result, std::move(arg)); + else if (typeTag == TAG_LITERAL) + ProcessLiteralArgument(state, result, std::move(arg)); + else + ProcessMaterialArgument(state, result, std::move(arg)); + } + }; +} + +const std::vector& TechniqueShaderScopeSequences::GetSequences() +{ + static std::vector tests({ + new SequenceEndShader() + }); + + return tests; +} diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h b/src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h new file mode 100644 index 00000000..e49fe54c --- /dev/null +++ b/src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h @@ -0,0 +1,15 @@ +#pragma once +#include + +#include "Techset/Parsing/TechniqueFileParser.h" + +namespace techset +{ + class TechniqueShaderScopeSequences + { + TechniqueShaderScopeSequences() = default; + + public: + static const std::vector& GetSequences(); + }; +} diff --git a/src/ObjLoading/Techset/Parsing/TechniqueFileParser.cpp b/src/ObjLoading/Techset/Parsing/TechniqueFileParser.cpp index 16d41cc1..1032d6ed 100644 --- a/src/ObjLoading/Techset/Parsing/TechniqueFileParser.cpp +++ b/src/ObjLoading/Techset/Parsing/TechniqueFileParser.cpp @@ -1,5 +1,9 @@ #include "TechniqueFileParser.h" +#include "Sequence/TechniqueNoScopeSequences.h" +#include "Sequence/TechniquePassScopeSequences.h" +#include "Sequence/TechniqueShaderScopeSequences.h" + using namespace techset; TechniqueParser::TechniqueParser(SimpleLexer* lexer, ITechniqueDefinitionAcceptor* acceptor) @@ -7,11 +11,13 @@ TechniqueParser::TechniqueParser(SimpleLexer* lexer, ITechniqueDefinitionAccepto { } -const std::vector::sequence_t*>& TechniqueParser::GetTestsForState() +const std::vector& TechniqueParser::GetTestsForState() { - // TODO: Tests - static std::vector tests({ - }); + if (m_state->m_in_shader) + return TechniqueShaderScopeSequences::GetSequences(); - return tests; + if (m_state->m_in_pass) + return TechniquePassScopeSequences::GetSequences(); + + return TechniqueNoScopeSequences::GetSequences(); } diff --git a/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.cpp b/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.cpp index c146c108..46397e57 100644 --- a/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.cpp +++ b/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.cpp @@ -5,7 +5,11 @@ using namespace techset; TechniqueParserState::TechniqueParserState(ITechniqueDefinitionAcceptor* acceptor) - : m_acceptor(acceptor) + : m_acceptor(acceptor), + m_before_first_pass(true), + m_in_pass(false), + m_in_shader(false), + m_current_shader(ShaderSelector::VERTEX_SHADER) { assert(acceptor); } diff --git a/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.h b/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.h index 3d688ea9..9a03745e 100644 --- a/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.h +++ b/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.h @@ -9,6 +9,11 @@ namespace techset public: ITechniqueDefinitionAcceptor* const m_acceptor; + bool m_before_first_pass; + bool m_in_pass; + bool m_in_shader; + ShaderSelector m_current_shader; + explicit TechniqueParserState(ITechniqueDefinitionAcceptor* acceptor); }; } diff --git a/src/ObjLoading/Techset/TechniqueDefinitionAcceptor.h b/src/ObjLoading/Techset/TechniqueDefinitionAcceptor.h index 27b93c3f..1f1d93cd 100644 --- a/src/ObjLoading/Techset/TechniqueDefinitionAcceptor.h +++ b/src/ObjLoading/Techset/TechniqueDefinitionAcceptor.h @@ -71,6 +71,8 @@ namespace techset ITechniqueDefinitionAcceptor& operator=(const ITechniqueDefinitionAcceptor& other) = default; ITechniqueDefinitionAcceptor& operator=(ITechniqueDefinitionAcceptor&& other) noexcept = default; + virtual void AcceptNextPass() = 0; + virtual void AcceptStateMap(const std::string& stateMapName) = 0; virtual bool AcceptVertexShader(size_t shaderVersionMajor, size_t shaderVersionMinor, const std::string& vertexShaderName, std::string& errorMessage) = 0; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperTechniqueSet.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperTechniqueSet.cpp index 5797402c..1ba07bc8 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperTechniqueSet.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperTechniqueSet.cpp @@ -209,7 +209,7 @@ namespace IW4 else if (arg.type == MTL_ARG_MATERIAL_PIXEL_CONST || arg.type == MTL_ARG_MATERIAL_VERTEX_CONST || arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER) { Indent(); - m_stream << codeDestAccessor << " = material.#" << std::hex << arg.u.nameHash << ";\n"; + m_stream << codeDestAccessor << " = material.#0x" << std::hex << arg.u.nameHash << ";\n"; } else {