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