Rendering Engine 0.2.9
Modular Graphics Rendering Engine | v0.2.9
utility.cpp
Go to the documentation of this file.
1#include "utility.hpp"
2#include <nlohmann/json.hpp>
3
4namespace rendering_engine
5{
6using namespace boost::filesystem;
7
8path const Utility::sDefaultShadersBinaryRelativePath = {"/Content/Shaders/"};
9path const Utility::sContentRelativePathFolder = path{} / "Content";
10path const Utility::sTextureRelativePathFolder = sContentRelativePathFolder / "Textures";
11path const Utility::sModelsRelativePathFolder = sContentRelativePathFolder / "Models";
12path const Utility::sFontsRelativePathFolder = sContentRelativePathFolder / "Fonts";
13path const Utility::sShadersRelativePathFolder = sContentRelativePathFolder / "Shaders";
14path const Utility:: sAppConfigFilePath = path{} / "Config" / "app_config.json";
15path const Utility::sLogFolderPath = path{} / "Logs";
16
20
22static bool sPackEntriesLoaded = false;
23path const Utility::sContentPackageFilePath = path{} / "Content" / "Pack.bin";
24path const Utility::sContentPackEntriesFilePath = path{} / "Content" / "Pack.json";
25
26void Utility::InitializePaths(int argc, char* argv[])
27{
28 sApplicationPath = boost::filesystem::path(argv[0]);
29
30 sBuildPath = FindPath( "Build" );
32}
33
35{
36 AppConfig cfg;
37
38 std::ifstream f(GetConfigFilePath().string());
39 if (!f.is_open())
40 {
41 return cfg;
42 }
43
44 try
45 {
46 nlohmann::json appConfigData = nlohmann::json::parse(f);
47
48 if (appConfigData.contains("appName"))
49 cfg.appName = appConfigData["appName"].get<std::string>();
50
51 if (appConfigData.contains("isFullScreen"))
52 cfg.isFullScreen = appConfigData["isFullScreen"].get<bool>();
53
54 if (appConfigData.contains("screenWidth"))
55 cfg.screenWidth = appConfigData["screenWidth"].get<float>();
56
57 if (appConfigData.contains("screenHeight"))
58 cfg.screenHeight = appConfigData["screenHeight"].get<float>();
59
60 if (appConfigData.contains("text"))
61 {
62 const auto& textNode = appConfigData["text"];
63
64 if (textNode.contains("scripts") && textNode["scripts"].is_array())
65 {
66 for (const auto& script : textNode["scripts"])
67 {
68 if (script.is_string())
69 {
70 auto found = std::find(cfg.textScripts.begin(), cfg.textScripts.end(), script);
71 if(found == cfg.textScripts.end())
72 {
73 cfg.textScripts.push_back(script.get<std::string>());
74 }
75 }
76 }
77 }
78
79 if (textNode.contains("fontSizePreload") && textNode["fontSizePreload"].is_array())
80 {
81 for (const auto& fontSize : textNode["fontSizePreload"])
82 {
83 auto found = std::find(cfg.fontSizePreload.begin(), cfg.fontSizePreload.end(), fontSize);
84 if (found == cfg.fontSizePreload.end())
85 {
86 cfg.fontSizePreload.push_back(fontSize.get<int>());
87 }
88 }
89 }
90 }
91
92 if (appConfigData.contains("logLevel"))
93 cfg.logLevel = appConfigData["logLevel"].get<std::string>();
94
95 if (appConfigData.contains("useSmoothedFPS"))
96 cfg.useSmoothedFPS = appConfigData["useSmoothedFPS"].get<bool>();
97
98 if (appConfigData.contains("targetFPS"))
99 cfg.targetFPS = appConfigData["targetFPS"].get<float>();
100
101 if (appConfigData.contains("showStatsOverlay"))
102 cfg.showStatsOverlay = appConfigData["showStatsOverlay"].get<bool>();
103
104 }
105 catch (const std::exception& e)
106 {
107 return cfg;
108 }
109
110 return cfg;
111}
112
113std::vector<char> Utility::ReadShaderBinaryFile( std::string const & filename )
114{
115 std::ifstream file(filename, std::ios::ate | std::ios::binary);
116
117 if (!file.is_open())
118 {
119 throw std::runtime_error("failed to open shader binary file!");
120 }
121
122 size_t fileSize = (size_t) file.tellg();
123 std::vector<char> buffer(fileSize);
124
125 file.seekg(0);
126 file.read(buffer.data(), fileSize);
127
128 file.close();
129
130 return buffer;
131}
132
133std::vector<std::string> Utility::GetListOfFilesInDirectory( std::string directory )
134{
135 std::vector<std::string> shaderFileNames;
136
137 try
138 {
139 //check if parameter string is directory
140 if( boost::filesystem::exists( boost::filesystem::path( directory ) ) && boost::filesystem::is_directory( boost::filesystem::path( directory ) ) )
141 {
142 boost::filesystem::path pathToDirectory = boost::filesystem::path( directory );
143
144 if( boost::filesystem::is_directory( pathToDirectory ) )
145 {
146 for( boost::filesystem::directory_entry& x : boost::filesystem::directory_iterator( pathToDirectory ) )
147 {
148 size_t dot = x.path().string().find_last_of( "." );
149
150 if( std::string{ "spv" } == x.path().string().substr( dot + 1 ) )
151 {
152 std::cout << "Shader binary file: " << x.path().string() << "\n";
153 shaderFileNames.push_back( x.path().string() );
154 }
155 }
156 }
157 }
158 }
159 catch( const boost::filesystem::filesystem_error& ex )
160 {
161 std::cout << ex.what() << '\n';
162 }
163
164 return shaderFileNames;
165}
166
167boost::filesystem::path Utility::GetApplicationPath()
168{
169 return sApplicationPath;
170}
171
172boost::filesystem::path Utility::GetBuildPath()
173{
174 return sBuildPath;
175}
176
177boost::filesystem::path Utility::GetShadersBinaryPath()
178{
179 return sShadersBinaryPath;
180}
181
182
183boost::filesystem::path Utility::FindPath(std::string fileOrFolderName, std::string searchingFrom)
184{
185 boost::filesystem::path result;
186 for( boost::filesystem::directory_entry& x : boost::filesystem::directory_iterator(searchingFrom) )
187 {
188 if( x.path().filename().string() == fileOrFolderName )
189 {
190 result = x.path().generic_path();
191 }
192 }
193 return result;
194}
195
196std::vector<std::string> Utility::GetListOfFileNamesInDirectory(const char* directory, std::string extToSearch)
197{
198 std::vector<std::string> imageFileNames;
199
200 try
201 {
202 //check if parameter string is directory
203 if( boost::filesystem::exists(boost::filesystem::path(directory)) && boost::filesystem::is_directory(boost::filesystem::path(directory)) )
204 {
205 boost::filesystem::path pathToDirectory = boost::filesystem::path(directory);
206
207 if( boost::filesystem::is_directory(pathToDirectory) )
208 {
209 for( boost::filesystem::directory_entry& x : boost::filesystem::directory_iterator(pathToDirectory) )
210 {
211 size_t dot = x.path().string().find_last_of(".");
212
213 if( extToSearch == x.path().string().substr(dot + 1) )
214 {
215 imageFileNames.push_back(x.path().string());
216 }
217 }
218 }
219 }
220 }
221 catch( const boost::filesystem::filesystem_error& ex )
222 {
223 std::cout << ex.what() << '\n';
224 }
225
226 return imageFileNames;
227}
228
229boost::filesystem::path Utility::ResolveProjectRoot()
230{
231 auto exeDir = boost::filesystem::canonical(boost::filesystem::path(boost::filesystem::current_path())); // default
232 if (exeDir.filename() == "Debug" || exeDir.filename() == "Release")
233 exeDir = exeDir.parent_path(); // step out of Debug/Release
234 if (exeDir.filename() == "Binaries")
235 exeDir = exeDir.parent_path(); // step out of Binaries
236 return exeDir;
237}
238
239boost::filesystem::path Utility::GetContentFolderPath()
240{
242}
243
244boost::filesystem::path Utility::GetTextureFolderPath()
245{
247}
248
249boost::filesystem::path Utility::GetModelsFolderPath()
250{
252}
253
254boost::filesystem::path Utility::GetFontsFolderPath()
255{
257}
258
259boost::filesystem::path Utility::GetShadersFolderPath()
260{
262}
263
264boost::filesystem::path Utility::GetConfigFilePath()
265{
267}
268
269boost::filesystem::path Utility::GetLogsFolderPath()
270{
272}
273
275{
276 const auto root = ResolveProjectRoot();
277 return boost::filesystem::exists(root / sContentPackageFilePath) &&
278 boost::filesystem::exists(root / sContentPackEntriesFilePath);
279}
280
282{
284 return sPackEntries;
285
286 sPackEntries.clear();
287
288 // Path to Pack.json
289 const boost::filesystem::path jsonPath = ResolveProjectRoot() / sContentPackEntriesFilePath;
290
291 if (!boost::filesystem::exists(jsonPath))
292 {
293 sPackEntriesLoaded = true;
294 return sPackEntries; // empty
295 }
296
297 // Load JSON
298 std::ifstream f(jsonPath.string());
299 if (!f.is_open())
300 {
301 std::cerr << "[ERROR] Failed to open Pack.json\n";
302 sPackEntriesLoaded = true;
303 return sPackEntries;
304 }
305
306 nlohmann::json j;
307 f >> j;
308
309 // Parse entries
310 for (auto it = j.begin(); it != j.end(); ++it)
311 {
312 PackEntry entry;
313 entry.offset = it.value().value("offset", 0);
314 entry.size = it.value().value("size", 0);
315 sPackEntries[it.key()] = entry;
316 }
317
318 sPackEntriesLoaded = true;
319 return sPackEntries;
320}
321
322std::vector<uint8_t> Utility::ReadPackedFile(const std::string& entryPath)
323{
324 std::vector<std::uint8_t> data;
325
326 if (!IsPackageProvided())
327 return data;
328
329 const path binPath = ResolveProjectRoot() / sContentPackageFilePath;
330 const path jsonPath = ResolveProjectRoot() / sContentPackEntriesFilePath;
331
332 if (!boost::filesystem::exists(binPath) ||
333 !boost::filesystem::exists(jsonPath))
334 {
335 std::cerr << "[Utility::ReadPackedFile] Missing Pack.bin or Pack.json\n";
336 return data;
337 }
338
340 // Check if this entry exists in Pack.json
341 auto it = sPackEntries.find(entryPath);
342 if (it == sPackEntries.end())
343 {
344 std::cerr << "[Utility::ReadPackedFile] No such packed entry: "
345 << entryPath << std::endl;
346 return data; // empty
347 }
348
349 const PackEntry& entry = it->second;
350
351 std::ifstream bin(binPath.string(), std::ios::binary);
352 if (!bin)
353 {
354 std::cerr << "[Utility::ReadPackedFile] Failed to open Pack.bin: "
355 << binPath.string() << std::endl;
356 return data;
357 }
358
359 // Read the memory region [offset, offset + size)
360
361 data.resize(entry.size);
362
363 bin.seekg(entry.offset, std::ios::beg);
364 if (!bin.good())
365 {
366 std::cerr << "[Utility::ReadPackedFile] Seek error for entry: "
367 << entryPath << std::endl;
368 return {};
369 }
370
371 bin.read(reinterpret_cast<char*>(data.data()), entry.size);
372 if (!bin.good())
373 {
374 std::cerr << "[Utility::ReadPackedFile] Read error for entry: "
375 << entryPath << std::endl;
376 return {};
377 }
378
379 return data;
380}
381
382
383}
static boost::filesystem::path GetConfigFilePath()
Returns absolute path to Config/app_config.json.
Definition: utility.cpp:264
static boost::filesystem::path GetShadersFolderPath()
Returns absolute path to Content/Shaders.
Definition: utility.cpp:259
static std::vector< std::string > GetListOfFileNamesInDirectory(const char *directory, std::string extToSearch)
Returns a list of file names in a directory matching the specified extension.
Definition: utility.cpp:196
static std::vector< char > ReadShaderBinaryFile(std::string const &filename)
Reads a binary shader file from disk.
Definition: utility.cpp:113
static boost::filesystem::path GetApplicationPath()
Returns the absolute path of the running application.
Definition: utility.cpp:167
static boost::filesystem::path GetShadersBinaryPath()
Returns the directory path containing compiled shader binaries.
Definition: utility.cpp:177
static boost::filesystem::path sApplicationPath
Definition: utility.hpp:177
static boost::filesystem::path sBuildPath
Definition: utility.hpp:179
static boost::filesystem::path ResolveProjectRoot()
Resolves project root folder (handles Release/Debug/Binaries layouts).
Definition: utility.cpp:229
static boost::filesystem::path GetBuildPath()
Returns the build output directory path.
Definition: utility.cpp:172
static boost::filesystem::path const sContentRelativePathFolder
Definition: utility.hpp:181
static boost::filesystem::path const sDefaultShadersBinaryRelativePath
Definition: utility.hpp:178
static boost::filesystem::path const sAppConfigFilePath
Definition: utility.hpp:188
static const PackEntries & GetPackEntries()
Returns the manifest of packed files.
Definition: utility.cpp:281
static boost::filesystem::path GetFontsFolderPath()
Returns absolute path to Content/Fonts.
Definition: utility.cpp:254
static std::vector< std::string > GetListOfFilesInDirectory(std::string directory)
Returns a list of full file paths in the given directory.
Definition: utility.cpp:133
static boost::filesystem::path GetLogsFolderPath()
Returns absolute path to Logs folder.
Definition: utility.cpp:269
static boost::filesystem::path const sContentPackageFilePath
Definition: utility.hpp:182
static boost::filesystem::path const sLogFolderPath
Definition: utility.hpp:189
static AppConfig ReadConfigFile()
Reads application settings from the JSON config file.
Definition: utility.cpp:34
static boost::filesystem::path const sTextureRelativePathFolder
Definition: utility.hpp:184
static boost::filesystem::path GetTextureFolderPath()
Returns absolute path to Content/Textures.
Definition: utility.cpp:244
static boost::filesystem::path const sContentPackEntriesFilePath
Definition: utility.hpp:183
static boost::filesystem::path const sShadersRelativePathFolder
Definition: utility.hpp:187
static boost::filesystem::path const sFontsRelativePathFolder
Definition: utility.hpp:186
static boost::filesystem::path const sModelsRelativePathFolder
Definition: utility.hpp:185
static boost::filesystem::path sShadersBinaryPath
Definition: utility.hpp:180
static std::vector< uint8_t > ReadPackedFile(const std::string &entryPath)
Reads raw bytes of a file stored inside Pack.bin.
Definition: utility.cpp:322
static boost::filesystem::path GetModelsFolderPath()
Returns absolute path to Content/Models.
Definition: utility.cpp:249
static bool IsPackageProvided()
Checks whether packed assets (Pack.bin / Pack.json) exist.
Definition: utility.cpp:274
static void InitializePaths(int argc, char *argv[])
Initializes engine paths based on the executable location.
Definition: utility.cpp:26
static boost::filesystem::path GetContentFolderPath()
Returns absolute path to Content.
Definition: utility.cpp:239
static PackEntries sPackEntries
Definition: utility.cpp:21
std::unordered_map< std::string, PackEntry > PackEntries
Definition: utility.hpp:60
static bool sPackEntriesLoaded
Definition: utility.cpp:22
Basic application settings loaded from a configuration file.
Definition: utility.hpp:27
float targetFPS
Target frame rate (0 = uncapped).
Definition: utility.hpp:45
float screenWidth
Desired window width in pixels (ignored in full-screen mode).
Definition: utility.hpp:33
bool isFullScreen
Whether the application should start in full-screen mode.
Definition: utility.hpp:31
std::string appName
Name of the application.
Definition: utility.hpp:29
bool useSmoothedFPS
Enable FPS smoothing and frame pacing behavior.
Definition: utility.hpp:43
bool showStatsOverlay
Enable on-screen statistics overlay.
Definition: utility.hpp:47
float screenHeight
Desired window height in pixels (ignored in full-screen mode).
Definition: utility.hpp:35
std::vector< std::string > textScripts
Unicode scripts to preload for text rendering.
Definition: utility.hpp:37
std::string logLevel
Logging verbosity level ("Error", "Warning", "Info", "Debug").
Definition: utility.hpp:41
std::vector< int > fontSizePreload
Font sizes to preload at startup.
Definition: utility.hpp:39
Metadata describing one file stored inside a packed asset archive.
Definition: utility.hpp:55