10Result<double>
number(std::string_view
text,
const VegetationPresetCommand& command) {
17 "preset numeric argument is invalid", command.sourcePath, {},
18 "asset.import.vegetation-preset.apply"));
22Result<std::array<double, 4>> vector(
const VegetationPresetCommand& command) {
23 if (command.arguments.size() != 5)
24 return Result<std::array<double, 4>>::failure(
26 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
27 std::array<double, 4> result{};
28 for (std::size_t i = 0; i < 4; ++i) {
29 auto value =
number(command.arguments[i + 1], command);
30 if (!
value)
return Result<std::array<double, 4>>::failure(
value.status());
31 result[i] =
value.value();
33 return Result<std::array<double, 4>>::success(result);
36std::string join(
const std::vector<std::string>&
values) {
39 if (!result.empty()) result.push_back(
' ');
45bool metadata(std::string_view domain) {
46 return domain ==
"InfoTitle" || domain ==
"InfoPreset" || domain ==
"InfoStatus" || domain ==
"InfoOnline" ||
47 domain ==
"InfoWarning" || domain ==
"InfoMessage" || domain ==
"Updated" || domain ==
"Detect" ||
51bool meshOperation(std::string_view
operation) {
52 static const std::set<std::string_view>
values{
"SetVariation",
"SetOcclusion",
"SetDetailMask",
"SetDetailCoord",
53 "SetHeight",
"SetMotion2",
"SetMotion3",
"SetPivots",
54 "SetNormals",
"SetBounds",
"SetReadWrite"};
58bool outputDomain(std::string_view domain) {
59 static const std::set<std::string_view>
values{
60 "OutputOptions",
"OutputTransforms",
"OutputMeshes",
"OutputMaterials",
"OutputTextures",
"OutputBase",
61 "OutputData",
"OutputCollection",
"OutputGUIDs",
"OutputPipelines",
"CollectBase",
"CollectData"};
62 return values.contains(domain);
65Result<void> applyMaterial(VegetationConversionCandidate& out,
const VegetationPresetCommand& command) {
66 const auto&
a = command.arguments;
67 if (command.operation ==
"SET_FLOAT") {
70 "SET_FLOAT requires property and value", command.sourcePath,
71 {},
"asset.import.vegetation-preset.apply"));
74 out.materialFloats[
a[0]] =
value.value();
75 }
else if (command.operation ==
"SET_VECTOR" || command.operation ==
"SET_COLOR") {
76 auto value = vector(command);
78 if (command.operation ==
"SET_COLOR")
79 out.materialColors[
a[0]] =
value.value();
81 out.materialVectors[
a[0]] =
value.value();
82 }
else if (command.operation ==
"COPY_FLOAT" || command.operation ==
"COPY_VECTOR" ||
83 command.operation ==
"COPY_COLOR" || command.operation ==
"COPY_TEX") {
84 const bool ignoredLegacyFloatArgument = command.operation ==
"COPY_FLOAT" &&
a.size() == 3;
85 if (
a.size() != 2 && !ignoredLegacyFloatArgument)
88 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
89 if (command.operation ==
"COPY_FLOAT") {
90 if (
auto v = out.materialFloats.find(
a[0]);
v != out.materialFloats.end())
91 out.materialFloats[
a[1]] =
v->second;
92 }
else if (command.operation ==
"COPY_VECTOR") {
93 if (
auto v = out.materialVectors.find(
a[0]);
v != out.materialVectors.end())
94 out.materialVectors[
a[1]] =
v->second;
95 else if (
auto v = out.materialColors.find(
a[0]);
v != out.materialColors.end())
96 out.materialVectors[
a[1]] =
v->second;
97 }
else if (command.operation ==
"COPY_COLOR") {
98 if (
auto v = out.materialColors.find(
a[0]);
v != out.materialColors.end())
99 out.materialColors[
a[1]] =
v->second;
100 else if (
auto v = out.materialVectors.find(
a[0]);
v != out.materialVectors.end())
101 out.materialColors[
a[1]] =
v->second;
102 }
else if (
auto v = out.materialTextures.find(
a[0]);
v != out.materialTextures.end()) {
103 if (out.firstValidTextureDestinations.contains(
a[1]))
104 out.materialTextures.try_emplace(
a[1],
v->second);
106 out.materialTextures[
a[1]] =
v->second;
108 }
else if (command.operation ==
"COPY_ST_AS_VECTOR") {
112 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
113 if (
auto v = out.materialTextureTransforms.find(
a[0]);
v != out.materialTextureTransforms.end())
114 out.materialVectors[
a[1]] =
v->second;
115 }
else if (command.operation.starts_with(
"COPY_FLOAT_AS_VECTOR_")) {
119 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
120 static constexpr std::string_view axes =
"XYZW";
121 const auto axis = axes.find(command.operation.back());
122 if (axis == std::string_view::npos)
124 "float-to-vector axis is invalid", command.sourcePath, {},
125 "asset.import.vegetation-preset.apply"));
126 if (
auto v = out.materialFloats.find(
a[0]);
v != out.materialFloats.end())
127 out.materialVectors[
a[1]][axis] =
v->second;
128 }
else if (command.operation.starts_with(
"COPY_VECTOR_") && command.operation.ends_with(
"_AS_FLOAT")) {
132 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
133 static constexpr std::string_view axes =
"XYZW";
134 const auto axis = axes.find(command.operation[12]);
135 if (axis == std::string_view::npos)
137 "vector-to-float axis is invalid", command.sourcePath, {},
138 "asset.import.vegetation-preset.apply"));
139 if (
auto v = out.materialVectors.find(
a[0]);
v != out.materialVectors.end())
140 out.materialFloats[
a[1]] =
v->second[axis];
141 }
else if (command.operation ==
"SET_SHADER") {
144 command.sourcePath, {},
145 "asset.import.vegetation-preset.apply"));
146 const auto found = out.shaderAliases.find(
a[0]);
147 out.materialShader =
found == out.shaderAliases.end() ?
a[0] :
found->second;
148 }
else if (command.operation ==
"SET_SHADER_BY_NAME") {
151 "SET_SHADER_BY_NAME requires a name", command.sourcePath, {},
152 "asset.import.vegetation-preset.apply"));
153 out.materialShader = join(
a);
154 }
else if (command.operation ==
"SET_SHADER_BY_LIGHTING") {
158 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
159 out.materialLighting =
a[0];
160 }
else if (command.operation ==
"ENABLE_KEYWORD" || command.operation ==
"LOCK_PROP") {
164 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
165 (command.operation ==
"ENABLE_KEYWORD" ? out.materialKeywords : out.lockedMaterialProperties).insert(
a[0]);
166 }
else if (command.operation ==
"ENABLE_INSTANCING" || command.operation ==
"DISABLE_INSTANCING") {
169 "instancing command takes no arguments", command.sourcePath,
170 {},
"asset.import.vegetation-preset.apply"));
171 out.materialInstancing = command.operation ==
"ENABLE_INSTANCING";
172 }
else if (command.operation ==
"COPY_TEX_FIRST_VALID") {
176 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
177 out.firstValidTextureDestinations.insert(
a[0]);
180 "unknown Material preset operation: " + command.operation,
181 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
188 const std::vector<VegetationPresetCommand>&
commands) {
189 for (
const auto& command :
commands) {
190 if (command.domain ==
"Material") {
191 auto result = applyMaterial(out, command);
193 }
else if (command.domain ==
"Mesh") {
194 if (!meshOperation(command.operation) || command.arguments.empty())
197 "asset.import.vegetation-preset.apply"));
198 out.
meshRules[command.operation] = command.arguments;
199 }
else if (command.domain ==
"Utility") {
200 static const std::set<std::string_view> utilities{
"START_TEXTURE_PACKING",
"USE_MATERIAL_POST_PROCESSING",
201 "USE_CURRENT_MATERIAL_AS_BASE",
202 "USE_CONVERTED_MATERIAL_AS_BASE"};
203 if (!utilities.contains(command.operation) || !command.arguments.empty())
206 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
208 if (command.operation ==
"START_TEXTURE_PACKING") out.
texturePacks.emplace_back();
209 }
else if (command.domain ==
"Texture") {
213 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
215 if (command.operation ==
"PropName" || command.operation ==
"ImportType" ||
216 command.operation ==
"TransformSpace") {
217 if (command.arguments.size() != 1)
220 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
221 if (command.operation ==
"PropName")
222 recipe.targetProperty = command.arguments[0];
223 else if (command.operation ==
"ImportType")
224 recipe.importType = command.arguments[0];
226 recipe.transformSpace = command.arguments[0];
228 const std::map<std::string, std::size_t>
channels{
229 {
"SetRed", 0}, {
"SetGreen", 1}, {
"SetBlue", 2}, {
"SetAlpha", 3}};
231 const bool none = command.arguments.size() == 1 && command.arguments[0] ==
"NONE";
233 (!none && (command.arguments.size() < 2 || command.arguments.size() > 3)))
236 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
237 recipe.channels[
found->second] =
240 command.arguments.size() == 3 ? command.arguments[2] :
""};
242 }
else if (command.domain ==
"Shader") {
243 if (!command.operation.starts_with(
"SHADER_") || command.arguments.empty())
246 "asset.import.vegetation-preset.apply"));
247 out.
shaderAliases[command.operation] = join(command.arguments);
248 }
else if (outputDomain(command.domain)) {
249 auto values = command.arguments;
252 }
else if (!metadata(command.domain)) {
255 command.sourcePath, {},
"asset.import.vegetation-preset.apply"));
ActionParameterOperation operation
std::map< std::string, std::vector< Key >, std::less<> > channels
std::map< std::string, Var > values
std::vector< VegetationPresetCommand > commands
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
EVENGINE_API_PLATFORM Result< VegetationConversionCandidate > applyVegetationPreset(VegetationConversionCandidate source, const std::vector< VegetationPresetCommand > &commands)
Type-check and atomically apply an evaluated TVE command sequence.
int axis(int64_t a, size_t rank)
Axis.
Owning unpublished material, mesh and texture candidate mutated transactionally by preset commands.
std::vector< std::string > utilityModes
std::map< std::string, std::vector< std::string > > meshRules
std::vector< VegetationTexturePackRecipe > texturePacks
std::map< std::string, std::vector< std::string > > outputDirectives
std::map< std::string, std::string > shaderAliases
One channel instruction in a TVE packed-texture recipe.