Elaztek Developer Hub
Blamite Game Engine - Tool (Library)
A command-line utility that aids in the creation of Blamite Cache (.map) Files.
MaterialCommand.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <Strings/components/utils/io/io.h>
4 #include <Strings/components/utils/string/string.h>
5 #include <Strings/components/utils/converters/converters.h>
6 #include <Strings/components/logger/logger.h>
7 
8 #include <HEKGuerilla/components/tags/importers/bitmap/bitmap.h>
9 #include <HEKGuerilla/components/tags/tags.h>
10 #include <HEKGuerilla/components/tags/fields/block/block.h>
11 #include <HEKGuerilla/components/tags/fields/tagref/tagref.h>
12 #include <HEKGuerilla/components/tags/fields/enum/enum.h>
13 #include <HEKGuerilla/components/tags/fields/color/color.h>
14 #include <HEKGuerilla/components/tags/fields/float32/float32.h>
15 #include <HEKGuerilla/components/settings/config/config.h>
16 
17 #include "../ToolCommand.hpp"
18 #include "../console.h"
19 #include "BitmapsCommand.hpp"
20 #include "components/utils/utils.h"
21 
22 #ifdef TOOL_LIB_EXPORTS
23 #define TOOL_LIB_API __declspec(dllexport)
24 #else
25 #define TOOL_LIB_API __declspec(dllimport)
26 #endif
27 
35 {
36 private:
37  std::vector<std::string> diffuse_texture_keywords = {
38  "diffuse", "basecolor", "color", "albedo"
39  };
40 
41  std::vector<std::string> normal_texture_keywords = {
42  "normal"
43  };
44 
45  std::vector<std::string> roughness_texture_keywords = {
46  "roughness", "rough"
47  };
48 
49  std::vector<std::string> specular_texture_keywords = {
50  "specular", "spec"
51  };
52 
53  std::vector<std::string> emissive_texture_keywords = {
54  "emissive", "glow", "illum"
55  };
56 
57  std::vector<std::string> metallic_texture_keywords = {
58  "metallic", "metal"
59  };
60 
61 public:
63  {
64  command = "material";
65  syntax = "material <directory> [overwrite] [skip bitmap import]";
66  description = "creates a pbr material from a texture set. assigns textures based on guesses from names. materials will generally be imperfect and require fine tuning.";
67  }
68 
69  int execute(std::vector<std::string> args)
70  {
71  if (args.size() == 0)
72  {
73  BlamStrings::Logger::LogEvent("no input directory path was provided, cannot compile bitmaps", BlamLogLevel::Warning);
74  return -1;
75  }
76 
77  if (args.size() > 3)
78  {
79  BlamStrings::Logger::LogEvent("too many arguments specified - skipping import. check your input and try again. "
80  "for additional help, use 'tool.exe help material'.", BlamLogLevel::Warning);
81  return -1;
82  }
83 
84  std::string project_root = BlamTool::Utils::GetProjectRoot();
85 
86  std::string import_base_dir = BlamStrings::Utils::IO::NormalizePath(project_root + "data/");
87  std::string output_base_dir = BlamStrings::Utils::IO::NormalizePath(project_root + "tags/");
88 
89  bool overwrite = false;
90  bool skip_bitmaps = false;
91  std::string input_directory = "";
92  std::string output_directory = "";
93  std::string material_tag_name = "";
94 
95  // Prepare arguments
96  {
97  if (args.size() >= 2)
98  {
99  if (BlamStrings::Converters::StringToBool(args[1]))
100  {
101  overwrite = true;
102  }
103  }
104 
105  if (args.size() >= 3)
106  {
107  if (BlamStrings::Converters::StringToBool(args[2]))
108  {
109  skip_bitmaps = true;
110  }
111  }
112 
113  input_directory = BlamStrings::Utils::IO::NormalizePath(import_base_dir + args[0]);
114  output_directory = BlamStrings::Utils::IO::NormalizePath(output_base_dir + args[0]);
115  material_tag_name = BlamStrings::Utils::IO::GetFileName(output_directory);
116  }
117 
118  BitmapsCommand* bitmaps_command = (BitmapsCommand*)BlamTool::Console::GetCommand("bitmaps");
119 
120  if (!bitmaps_command)
121  {
122  BlamStrings::Logger::LogEvent("cannot resolve bitmaps command - this is a bug and should be reported", BlamLogLevel::Warning);
123  return -1;
124  }
125 
126  BlamStrings::Logger::LogEvent("step 1: bitmap import");
127 
128  if (!skip_bitmaps)
129  {
130  if (bitmaps_command->execute({ args.at(0), "true" }) != 0)
131  {
132  BlamStrings::Logger::LogEvent("bitmaps command execution returned non-zero, bitmaps may not be imported", BlamLogLevel::Warning);
133  }
134  }
135 
136  BlamStrings::Logger::LogEvent("step 2: material creation");
137 
138  if (BlamStrings::Utils::IO::FileExists(output_directory + "/" + material_tag_name + ".material") && !overwrite)
139  {
140  BlamStrings::Logger::LogEvent("not creating new material tag, file already exists - to force material creation anyway, set override to true (will destroy existing tag!)", BlamLogLevel::Warning);
141  return -1;
142  }
143 
144  Guerilla::Tags::LoadPlugins();
145 
146  std::vector<std::string> bitmap_paths = std::vector<std::string>();
147 
148  for (std::string file_path : BlamStrings::Utils::IO::GetFileList(output_directory))
149  {
150  if (!str_tolower(file_path).ends_with(".bitmap"))
151  {
152  continue;
153  }
154 
155  bitmap_paths.push_back(file_path);
156  }
157 
158  BlamPlugin* material_plugin = Guerilla::Tags::GetPlugin("material");
159 
160  if (!material_plugin)
161  {
162  BlamStrings::Logger::LogEvent("cannot create material: cannot locate material plugin", WSV_WARNING);
163  return -1;
164  }
165 
166  BlamTag* tag = material_plugin->CreateNewTag();
167 
168  tag->file_path = output_directory + "/" + material_tag_name + ".material";
169 
170  BlamTagField_Block* pbr_material_block = tag->GetField<BlamTagField_Block>("pbr_material");
171 
172  if (!pbr_material_block)
173  {
174  BlamStrings::Logger::LogEvent("cannot create material: material plugin is missing a pbr_material block", WSV_WARNING);
175  return -1;
176  }
177 
178  pbr_material_block->AddEntry();
179  BlamTagBlockEntry* entry = pbr_material_block->entries.at(0);
180  BlamTagField_Block* textures_block = entry->GetField<BlamTagField_Block>("textures");
181 
182  if (!textures_block)
183  {
184  BlamStrings::Logger::LogEvent("cannot create material: pbr_material block is missing a textures block", WSV_WARNING);
185  return -1;
186  }
187 
188  std::string diffuse = "";
189  std::string normal = "";
190  std::string specular = "";
191  std::string roughness = "";
192  std::string emissive = "";
193  std::string metallic = "";
194 
195  for (std::string texture_file : bitmap_paths)
196  {
197  std::string tag_path = str_replace(texture_file, output_base_dir, "");
198  std::string tag_name = BlamStrings::Utils::IO::GetFileName(tag_path);
199 
200  if (diffuse.length() == 0 && BlamStrings::Utils::String::ContainsAny(tag_name, diffuse_texture_keywords, true))
201  diffuse = tag_path;
202 
203  if (normal.length() == 0 && BlamStrings::Utils::String::ContainsAny(tag_name, normal_texture_keywords, true))
204  normal = tag_path;
205 
206  if (specular.length() == 0 && BlamStrings::Utils::String::ContainsAny(tag_name, specular_texture_keywords, true))
207  specular = tag_path;
208 
209  if (roughness.length() == 0 && BlamStrings::Utils::String::ContainsAny(tag_name, roughness_texture_keywords, true))
210  roughness = tag_path;
211 
212  if (emissive.length() == 0 && BlamStrings::Utils::String::ContainsAny(tag_name, emissive_texture_keywords, true))
213  emissive = tag_path;
214 
215  if (metallic.length() == 0 && BlamStrings::Utils::String::ContainsAny(tag_name, metallic_texture_keywords, true))
216  metallic = tag_path;
217  }
218 
219  if (diffuse.length() > 0) CreateNewTextureEntry(textures_block, "diffuse", diffuse);
220  if (normal.length() > 0) CreateNewTextureEntry(textures_block, "normal", normal);
221  if (specular.length() > 0) CreateNewTextureEntry(textures_block, "specular", specular);
222  if (roughness.length() > 0) CreateNewTextureEntry(textures_block, "roughness", roughness);
223  if (emissive.length() > 0) CreateNewTextureEntry(textures_block, "emissive", emissive);
224  if (metallic.length() > 0) CreateNewTextureEntry(textures_block, "metallic", metallic);
225 
226  // Set other fields to moderate defaults
227  {
228  BlamTagField_Float32* metalness = entry->GetField<BlamTagField_Float32>("metalness");
229  BlamTagField_Float32* roughness = entry->GetField<BlamTagField_Float32>("roughness");
230  BlamTagField_Color* emissive_color = entry->GetField<BlamTagField_Color>("emissive_color");
231 
232  if (metalness) metalness->value = 0.5f;
233  if (roughness) roughness->value = 0.5f;
234  if (emissive_color) emissive_color->value = BlamColor(0, 0, 0, 0);
235  }
236 
237  if (!Guerilla::Tags::SaveTag(tag))
238  {
239  BlamStrings::Logger::LogEvent("failed to save material tag - see log for details", WSV_WARNING);
240  }
241 
242  Guerilla::Tags::ReleasePlugins();
243 
244  BlamStrings::Logger::LogEvent("finished.");
245  return 0;
246  }
247 
248  bool CreateNewTextureEntry(BlamTagField_Block* block, std::string type, std::string tag)
249  {
250  if (!block->AddEntry())
251  {
252  BlamStrings::Logger::LogEvent("failed to add material entry for '" + type + "': add entry failed", WSV_WARNING);
253  return false;
254  }
255 
256  BlamTagBlockEntry* entry = block->entries.at(block->entries.size() - 1);
257 
258  entry->name = type;
259  BlamTagField_Enum* texture_type = entry->GetField<BlamTagField_Enum>("texture_type", BlamTagFieldType::Enum32);
260  BlamTagField_Tagref* texture = entry->GetField<BlamTagField_Tagref>("texture");
261 
262  if (!texture_type || !texture)
263  {
264  BlamStrings::Logger::LogEvent("failed to add material entry for '" + type
265  + "': missing texture_type (enum32) and/or texture (tagref) fields", WSV_WARNING);
266  return false;
267  }
268 
269  texture_type->current_option = type;
270  texture->referenced_tag_class = "bitm";
271  texture->referenced_tag_path = tag;
272  return true;
273  }
274 };
MaterialCommand::CreateNewTextureEntry
bool CreateNewTextureEntry(BlamTagField_Block *block, std::string type, std::string tag)
Definition: MaterialCommand.hpp:248
BitmapsCommand::execute
int execute(std::vector< std::string > args)
Executes the command.
Definition: BitmapsCommand.hpp:66
BlamTool::Console::GetCommand
TOOL_LIB_API ToolCommand * GetCommand(std::string name)
Retrieves a command based on its name.
Definition: console.cpp:129
MaterialCommand
Class for the Material command.
Definition: MaterialCommand.hpp:34
BitmapsCommand.hpp
MaterialCommand::MaterialCommand
MaterialCommand()
Definition: MaterialCommand.hpp:62
utils.h
ToolCommand::syntax
std::string syntax
The syntax of the command. This should include the command name, as well as any arguments.
Definition: ToolCommand.hpp:19
MaterialCommand::execute
int execute(std::vector< std::string > args)
Executes the command.
Definition: MaterialCommand.hpp:69
ToolCommand::command
std::string command
The name of the command.
Definition: ToolCommand.hpp:18
BitmapsCommand
Class for the Bitmaps command.
Definition: BitmapsCommand.hpp:30
ToolCommand
Base class representing a Tool command.
Definition: ToolCommand.hpp:15
ToolCommand::description
std::string description
A description of the command.
Definition: ToolCommand.hpp:20
BlamTool::Utils::GetProjectRoot
TOOL_LIB_API std::string GetProjectRoot()
Retrieves the current project root.
Definition: utils.cpp:6