2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include <string_view>
27 namespace fs = filesystem;
31 ///////////////////////////////////////////////////////////////////////////////////////////////////
32 string PROGRAM_NAME; ///< We set the program name on this global early on for use in Usage.
33 string_view VERSION = "1.0.0";
35 ///////////////////////////////////////////////////////////////////////////////////////////////////
36 /// Supported extensions for the files in the input directory.
38 constexpr string_view SHADER_EXTENSIONS[] =
46 ///////////////////////////////////////////////////////////////////////////////////////////////////
47 /// Function & variable to retrieve the size of the extension with the largest string size.
48 constexpr auto GetShaderExtensionMaxSize()
51 for(const auto& extension : SHADER_EXTENSIONS)
53 if(extension.size() > maxSize)
55 maxSize = extension.size();
60 constexpr const int SHADER_MAX_EXTENSION_SIZE(GetShaderExtensionMaxSize());
62 ///////////////////////////////////////////////////////////////////////////////////////////////////
63 /// Prints out the Usage to standard output.
66 cout << "Usage: " << PROGRAM_NAME << " [OPTIONS] [IN_DIR] [OUT_DIR]" << endl;
67 cout << " IN_DIR: Input Directory which has all the shader files." << endl;
68 cout << " Supported extensions:";
70 for(const auto& extension : SHADER_EXTENSIONS)
72 extensions = extensions + " \"" + string(extension) + "\",";
74 extensions.pop_back(); // Remove the last comma.
75 cout << extensions << "." << endl;
76 cout << " OUT_DIR: Directory where the generated shader source code will be outputted to." << endl;
77 cout << " This directory will be created if it does not exist." << endl;
78 cout << " Any existing files of the same name in the directory will be overwritten." << endl;
79 cout << " Options: " << endl;
80 cout << " -s|--skip Skips the generation of the built-in header and source files" << endl;
81 cout << " -v|--version Prints out the version" << endl;
82 cout << " -h|--help Help" << endl;
83 cout << " NOTE: The options can be placed after the IN_DIR & OUT_DIR as well" << endl;
86 ///////////////////////////////////////////////////////////////////////////////////////////////////
87 /// Uses the filename to generate the shader variable name to use in source code.
88 /// @param[in] filename The filename of the shader (including the extension)
89 /// @return The shader variable name
90 string GetShaderVariableName(const string& filename)
92 string shaderVariableName("SHADER_" + filename);
94 shaderVariableName.begin(),
95 shaderVariableName.end(),
108 character = ::toupper(character);
113 return shaderVariableName;
116 ///////////////////////////////////////////////////////////////////////////////////////////////////
117 /// Uses the ourDir & filename to generate the path of the output header file for the shader.
118 /// @param[in] outDir The directory where the readable shaders will be outputted to
119 /// @param[in] filename The filename of the shader (including the extension)
120 /// @return The path to the output file
121 fs::path GetShaderOutputFilePath(fs::path& outDir, const string& filename)
123 string outFilename(filename);
124 replace(outFilename.end() - SHADER_MAX_EXTENSION_SIZE, outFilename.end(), '.', '-');
125 outFilename = outDir.string() + "/" + outFilename + ".h";
129 ///////////////////////////////////////////////////////////////////////////////////////////////////
130 /// Generates the header file from the input shader file.
131 /// @param[in] shaderFile The full path of the input shader file
132 /// @param[in] shaderVariableName The variable name to use for the string_view
133 /// @param[in] outFilePath The full path to the output file
134 void GenerateHeaderFile(
135 ifstream& shaderFile,
136 const string& shaderVariableName,
137 const fs::path& outFilePath)
139 cout << " Generating \"" << shaderVariableName << "\" in " << outFilePath.filename();
140 ofstream outFile(outFilePath);
141 if(outFile.is_open())
143 outFile << "#pragma once" << endl
145 outFile << "const std::string_view " << shaderVariableName << endl;
146 outFile << "{" << endl;
147 outFile << "R\"(" << endl;
149 while(getline(shaderFile, line))
151 outFile << line << endl;
153 outFile << ")\"" << endl;
154 outFile << "};" << endl;
155 cout << " [OK]" << endl;
159 cout << " [FAIL]" << endl;
163 ///////////////////////////////////////////////////////////////////////////////////////////////////
164 /// If required, this accumulates data about all the shaders & generates the built-in cpp & header
165 class BuiltInFilesGenerator
169 /// @param[in] outDir The path to the output directory
170 BuiltInFilesGenerator(const fs::path& outDir)
171 : mHeaderFilePath(outDir.string() + "/../" + string(HEADER_FILE_NAME)),
172 mSourceFilePath(outDir.string() + "/" + string(SOURCE_FILE_NAME))
176 /// Default destructor
177 ~BuiltInFilesGenerator() = default;
179 /// Adds the variable and the header file name to the appropriate vectors.
180 /// @param[in] variableName The string_view variable name used
181 /// @param[in] headerFileName The name of the header used
182 void Add(string&& variableName, const std::string& headerFilename)
184 mVariableNames.emplace_back(variableName);
185 mHeaderFileNames.emplace_back(headerFilename);
188 // Generates the built in files.
194 "#pragma once\n\n#include <string_view>\n\n",
195 "extern const std::string_view ",
201 "#include \"../" + string(HEADER_FILE_NAME) + "\"\n\n",
207 /// Generates the required file.
208 /// @param[in] strings A reference to the vector to parse
209 /// @param[in] filePath Outputs the data to this file
210 /// @param[in] header Puts this before parsing any of the vector
211 /// @param[in] before For each string, puts this string before it on every line
212 /// @param[in] after For each string, puts this string after it on every line
214 vector<string>& strings,
215 const string& filePath,
216 const string_view header,
217 const string_view before,
218 const string_view after)
220 sort(strings.begin(), strings.end());
221 cout << " Generating \"" << filePath << "\"";
222 ofstream outFile(filePath);
226 for(auto& current : strings)
228 outFile << before << current << after << endl;
230 cout << " [OK]" << endl;
234 cout << " [FAIL]" << endl;
238 constexpr static string_view HEADER_FILE_NAME = "builtin-shader-extern-gen.h";
239 constexpr static string_view SOURCE_FILE_NAME = "builtin-shader-gen.cpp";
241 const string mHeaderFilePath; ///< Path to the header file to generate
242 const string mSourceFilePath; ///< Path to the source file to generate
243 vector<string> mVariableNames; ///< Holds all the variable names added through Add
244 vector<string> mHeaderFileNames; ///< Holds all the header file names added through Add
247 ///////////////////////////////////////////////////////////////////////////////////////////////////
248 /// Generates the header files from the shaders in the input directory & built-in files if reqruied.
250 /// @param[in] inDir The directory where all the input shader source is
251 /// @param[in] outDir The directory where the readable shaders will be outputted to
252 /// @param[in] generateBuiltInFiles If true, we generate the built-in files as well
253 /// @return 0 if successful, 1 if failure
254 int GenerateShaderSources(fs::path inDir, fs::path outDir, const bool generateBuiltInFiles)
256 if(!fs::is_directory(inDir))
258 cerr << "ERROR: " << inDir << " is not a valid directory" << endl;
265 fs::create_directories(outDir);
269 cerr << "ERROR: Unable to create directory " << outDir << endl;
273 cout << "====================================================================" << endl;
274 cout << "Shader Input Directory: " << inDir << endl;
275 cout << "Shader Output Directory: " << outDir << endl;
276 cout << "====================================================================" << endl;
278 BuiltInFilesGenerator generator(outDir);
280 for(auto& file : fs::directory_iterator(inDir))
282 if(file.is_regular_file())
284 for(const auto& extension : SHADER_EXTENSIONS)
286 if(file.path().extension() == extension)
288 const fs::path& path(file.path());
289 const string filename(path.filename().string());
290 string shaderVariableName(GetShaderVariableName(filename));
291 ifstream shaderFile(path);
292 if(shaderFile.is_open())
294 fs::path outFilePath(GetShaderOutputFilePath(outDir, filename));
295 GenerateHeaderFile(shaderFile, shaderVariableName, outFilePath);
296 generator.Add(std::move(shaderVariableName), outFilePath.filename().string());
304 if(generateBuiltInFiles)
306 generator.Generate();
309 cout << "====================================================================" << endl;
313 } // unnamed namespace
315 ///////////////////////////////////////////////////////////////////////////////////////////////////
317 int main(int argc, char* argv[])
319 PROGRAM_NAME = argv[0];
321 bool generateBuiltInFiles = true;
326 for(auto i = 1; i < argc; ++i)
328 string option(argv[i]);
329 if(option == "--skip" || option == "-s")
331 generateBuiltInFiles = false;
333 else if(option == "--help" || option == "-h")
335 cout << "DALi Shader Generator v" << VERSION << endl
340 else if(option == "--version" || option == "-v")
342 cout << VERSION << endl;
345 else if(*option.begin() == '-')
347 cerr << "ERROR: " << option << " is not a supported option" << endl;
351 else if(inDir.empty())
355 else if(outDir.empty())
359 else if(inDir.size() && outDir.size())
361 cerr << "ERROR: Too many options" << endl;
367 if(inDir.empty() || outDir.empty())
369 cerr << "ERROR: Both IN_DIR & OUT_DIR not provided" << endl;
374 return GenerateShaderSources(inDir, outDir, generateBuiltInFiles);