Browse Source

Upgraded resource pool to allow not ending with a separator. Automatically making paths local.

David Piuva 3 years ago
parent
commit
99b9711381

+ 21 - 4
Source/DFPSR/api/fileAPI.cpp

@@ -91,7 +91,8 @@ static FILE* accessFile(const ReadableString &filename, bool write) {
 }
 }
 
 
 Buffer file_loadBuffer(const ReadableString& filename, bool mustExist) {
 Buffer file_loadBuffer(const ReadableString& filename, bool mustExist) {
-	FILE *file = accessFile(filename, false);
+	String modifiedFilename = file_optimizePath(filename);
+	FILE *file = accessFile(modifiedFilename, false);
 	if (file != nullptr) {
 	if (file != nullptr) {
 		// Get the file's size by going to the end, measuring, and going back
 		// Get the file's size by going to the end, measuring, and going back
 		fseek(file, 0L, SEEK_END);
 		fseek(file, 0L, SEEK_END);
@@ -104,7 +105,7 @@ Buffer file_loadBuffer(const ReadableString& filename, bool mustExist) {
 		return buffer;
 		return buffer;
 	} else {
 	} else {
 		if (mustExist) {
 		if (mustExist) {
-			throwError(U"The file ", filename, U" could not be opened for reading.\n");
+			throwError(U"Failed to load ", filename, " which was optimized into ", modifiedFilename, ".\n");
 		}
 		}
 		// If the file cound not be found and opened, an empty buffer is returned
 		// If the file cound not be found and opened, an empty buffer is returned
 		return Buffer();
 		return Buffer();
@@ -112,15 +113,16 @@ Buffer file_loadBuffer(const ReadableString& filename, bool mustExist) {
 }
 }
 
 
 void file_saveBuffer(const ReadableString& filename, Buffer buffer) {
 void file_saveBuffer(const ReadableString& filename, Buffer buffer) {
+	String modifiedFilename = file_optimizePath(filename);
 	if (!buffer_exists(buffer)) {
 	if (!buffer_exists(buffer)) {
 		throwError(U"buffer_save: Cannot save a buffer that don't exist to a file.\n");
 		throwError(U"buffer_save: Cannot save a buffer that don't exist to a file.\n");
 	} else {
 	} else {
-		FILE *file = accessFile(filename, true);
+		FILE *file = accessFile(modifiedFilename, true);
 		if (file != nullptr) {
 		if (file != nullptr) {
 			fwrite((void*)buffer_dangerous_getUnsafeData(buffer), buffer_getSize(buffer), 1, file);
 			fwrite((void*)buffer_dangerous_getUnsafeData(buffer), buffer_getSize(buffer), 1, file);
 			fclose(file);
 			fclose(file);
 		} else {
 		} else {
-			throwError("Failed to save ", filename, ".\n");
+			throwError("Failed to save ", filename, " which was optimized into ", modifiedFilename, ".\n");
 		}
 		}
 	}
 	}
 }
 }
@@ -144,6 +146,21 @@ static int64_t getLastSeparator(const ReadableString &path, int defaultIndex) {
 	return defaultIndex;
 	return defaultIndex;
 }
 }
 
 
+String file_optimizePath(const ReadableString &path) {
+	String result;
+	int inputLength = string_length(path);
+	string_reserve(result, inputLength);
+	for (int i = 0; i < inputLength; i++) {
+		DsrChar c = path[i];
+		if (isSeparator(c)) {
+			string_append(result, pathSeparator);
+		} else {
+			string_appendChar(result, c);
+		}
+	}
+	return result;
+}
+
 ReadableString file_getPathlessName(const ReadableString &path) {
 ReadableString file_getPathlessName(const ReadableString &path) {
 	return string_after(path, getLastSeparator(path, -1));
 	return string_after(path, getLastSeparator(path, -1));
 }
 }

+ 6 - 2
Source/DFPSR/api/fileAPI.h

@@ -55,12 +55,12 @@ TODO:
 //   Buffers need a filename to be saved or loaded while strings use buffers to store their characters.
 //   Buffers need a filename to be saved or loaded while strings use buffers to store their characters.
 namespace dsr {
 namespace dsr {
 	// Post-condition:
 	// Post-condition:
-	//   Returns the content of the file referred to be filename.
+	//   Returns the content of the file referred to by file_optimizePath(filename).
 	//   If mustExist is true, then failure to load will throw an exception.
 	//   If mustExist is true, then failure to load will throw an exception.
 	//   If mustExist is false, then failure to load will return an empty handle (returning false for buffer_exists).
 	//   If mustExist is false, then failure to load will return an empty handle (returning false for buffer_exists).
 	Buffer file_loadBuffer(const ReadableString& filename, bool mustExist = true);
 	Buffer file_loadBuffer(const ReadableString& filename, bool mustExist = true);
 
 
-	// Side-effect: Saves buffer to filename as a binary file.
+	// Side-effect: Saves buffer to file_optimizePath(filename) as a binary file.
 	// Pre-condition: buffer exists
 	// Pre-condition: buffer exists
 	void file_saveBuffer(const ReadableString& filename, Buffer buffer);
 	void file_saveBuffer(const ReadableString& filename, Buffer buffer);
 
 
@@ -68,6 +68,10 @@ namespace dsr {
 	//   Can be used to construct a file path that works for both forward and backward slash separators.
 	//   Can be used to construct a file path that works for both forward and backward slash separators.
 	const char32_t* file_separator();
 	const char32_t* file_separator();
 
 
+	// Turns / and \ into the local system's convention, so that loading and saving files can use either one of them automatically.
+	// TODO: Remove redundant . and .. to reduce the risk of running out of buffer space.
+	String file_optimizePath(const ReadableString &path);
+
 	// TODO: Create regression tests for the file system.
 	// TODO: Create regression tests for the file system.
 
 
 	// Returns the local name of the file or folder after the last path separator, or the whole path if no separator was found.
 	// Returns the local name of the file or folder after the last path separator, or the whole path if no separator was found.

+ 2 - 1
Source/DFPSR/render/ResourcePool.cpp

@@ -23,6 +23,7 @@
 
 
 #include "ResourcePool.h"
 #include "ResourcePool.h"
 #include "../image/stbImage/stbImageWrapper.h"
 #include "../image/stbImage/stbImageWrapper.h"
+#include "../api/fileAPI.h"
 
 
 using namespace dsr;
 using namespace dsr;
 
 
@@ -51,7 +52,7 @@ const ImageRgbaU8 BasicResourcePool::fetchImageRgba(const String& name) {
 			throwError("The image \"", name, "\" contained a path separator, which is not allowed because of ambiguity. The same file can have multiple paths to the same folder and multiple files can have the same name in different folders.\n");
 			throwError("The image \"", name, "\" contained a path separator, which is not allowed because of ambiguity. The same file can have multiple paths to the same folder and multiple files can have the same name in different folders.\n");
 		} else {
 		} else {
 			// Look for a png image
 			// Look for a png image
-			const String extensionless = this->path + name;
+			const String extensionless = file_combinePaths(this->path, name);
 			result = image_load_RgbaU8(extensionless + ".png", false);
 			result = image_load_RgbaU8(extensionless + ".png", false);
 			// Look for gif
 			// Look for gif
 			if (!image_exists(result)) {
 			if (!image_exists(result)) {

+ 13 - 8
Source/SDK/cube/main.cpp

@@ -4,8 +4,10 @@
 
 
 using namespace dsr;
 using namespace dsr;
 
 
-const String mediaPath = string_combine(U"media", file_separator());
-static BasicResourcePool pool(mediaPath);
+// Get the application folder when possible, falling back on current directory on systems not offering the feature.
+const String applicationFolder = file_getApplicationFolder();
+const String mediaFolder = file_combinePaths(applicationFolder, U"media");
+static BasicResourcePool pool(mediaFolder);
 
 
 // Global variables
 // Global variables
 float distance = 4.0f;
 float distance = 4.0f;
@@ -46,11 +48,12 @@ Model createCubeModel(const FVector3D &min, const FVector3D &max) {
 	return result;
 	return result;
 }
 }
 
 
-int main(int argn, char **argv) {
+DSR_MAIN_CALLER(dsrMain)
+int dsrMain(List<String> args) {
 	// Create a window
 	// Create a window
 	window = window_create(U"David Piuva's Software Renderer - Cube example", 1600, 900);
 	window = window_create(U"David Piuva's Software Renderer - Cube example", 1600, 900);
 	// Load an interface to the window
 	// Load an interface to the window
-	window_loadInterfaceFromFile(window, mediaPath + U"interface.lof");
+	window_loadInterfaceFromFile(window, file_combinePaths(mediaFolder, U"interface.lof"));
 
 
 	// Tell the application to terminate when the window is closed
 	// Tell the application to terminate when the window is closed
 	window_setCloseEvent(window, []() {
 	window_setCloseEvent(window, []() {
@@ -102,9 +105,9 @@ int main(int argn, char **argv) {
 
 
 	// Import models
 	// Import models
 	// TODO: Load write protected models from a resource pool
 	// TODO: Load write protected models from a resource pool
-	Model crateModel = importFromContent_DMF1(string_load(mediaPath + U"Model_Crate.dmf"), pool);
-	Model barrelModel = importFromContent_DMF1(string_load(mediaPath + U"Model_Barrel.dmf"), pool);
-	Model testModel = importFromContent_DMF1(string_load(mediaPath + U"Model_Test.dmf"), pool);
+	Model crateModel = importFromContent_DMF1(string_load(file_combinePaths(mediaFolder, U"Model_Crate.dmf")), pool);
+	Model barrelModel = importFromContent_DMF1(string_load(file_combinePaths(mediaFolder, U"Model_Barrel.dmf")), pool);
+	Model testModel = importFromContent_DMF1(string_load(file_combinePaths(mediaFolder, U"Model_Test.dmf")), pool);
 
 
 	// Create a renderer for multi-threading
 	// Create a renderer for multi-threading
 	Renderer worker = renderer_create();
 	Renderer worker = renderer_create();
@@ -179,5 +182,7 @@ int main(int argn, char **argv) {
 
 
 		window_showCanvas(window);
 		window_showCanvas(window);
 	}
 	}
-}
 
 
+	// When the DSR_MAIN_CALLER wrapper is used over the real main function, returning zero is no longer implicit.
+	return 0;
+}

+ 8 - 4
Source/SDK/fileFinder/main.cpp

@@ -16,7 +16,7 @@ TODO:
 using namespace dsr;
 using namespace dsr;
 
 
 void exploreFolder(const ReadableString& folderPath, const ReadableString& indentation) {
 void exploreFolder(const ReadableString& folderPath, const ReadableString& indentation) {
-	file_getFolderContent(folderPath, [indentation](ReadableString entryPath, EntryType entryType) {
+	/*file_getFolderContent(folderPath, [indentation](ReadableString entryPath, EntryType entryType) {
 		ReadableString shortName = file_getPathlessName(entryPath);
 		ReadableString shortName = file_getPathlessName(entryPath);
 		if (entryType == EntryType::Folder) {
 		if (entryType == EntryType::Folder) {
 			printText(indentation, " Folder(", shortName, ")\n");
 			printText(indentation, " Folder(", shortName, ")\n");
@@ -24,15 +24,16 @@ void exploreFolder(const ReadableString& folderPath, const ReadableString& inden
 		} else if (entryType == EntryType::File) {
 		} else if (entryType == EntryType::File) {
 			printText(indentation, " File(", shortName, ") of ", file_getSize(entryPath), " bytes\n");
 			printText(indentation, " File(", shortName, ") of ", file_getSize(entryPath), " bytes\n");
 		}
 		}
-	});
+	});*/
 }
 }
 
 
-int main(int argn, NativeChar **argv) {
-	List<String> args = file_convertInputArguments(argn, argv);
+DSR_MAIN_CALLER(dsrMain)
+int dsrMain(List<String> args) {
 	printText("Input arguments:\n");
 	printText("Input arguments:\n");
 	for (int a = 0; a < args.length(); a++) {
 	for (int a = 0; a < args.length(); a++) {
 		printText("  args[", a, "] = ", args[a], "\n");
 		printText("  args[", a, "] = ", args[a], "\n");
 	}
 	}
+	/*
 	String absolutePath = file_getCanonicalPath(args[0]);
 	String absolutePath = file_getCanonicalPath(args[0]);
 	printText("Absolute path = ", absolutePath, "\n");
 	printText("Absolute path = ", absolutePath, "\n");
 	if (args.length() > 1) {
 	if (args.length() > 1) {
@@ -47,4 +48,7 @@ int main(int argn, NativeChar **argv) {
 		printText("Exploring ", currentPath, " because no folders were given.\n");
 		printText("Exploring ", currentPath, " because no folders were given.\n");
 		exploreFolder(currentPath, U"");
 		exploreFolder(currentPath, U"");
 	}
 	}
+	*/
+	// When the DSR_MAIN_CALLER wrapper is used over the real main function, returning zero is no longer implicit.
+	return 0;
 }
 }

+ 10 - 4
Source/SDK/guiExample/main.cpp

@@ -3,8 +3,6 @@
 
 
 using namespace dsr;
 using namespace dsr;
 
 
-// Global
-const String mediaPath = string_combine(U"media", file_separator());
 bool running = true;
 bool running = true;
 
 
 // GUI handles
 // GUI handles
@@ -13,13 +11,18 @@ Component buttonClear;
 Component buttonAdd;
 Component buttonAdd;
 Component myListBox;
 Component myListBox;
 
 
-int main(int argn, char **argv) {
+DSR_MAIN_CALLER(dsrMain)
+int dsrMain(List<String> args) {
+	// Set current path to the application folder, so that it's safe to use relative paths for loading GUI resources.
+	// Loading and saving files will automatically convert / and \ to the local format using file_optimizePath, so that you can use them directly in relative paths.
+	//file_setCurrentPath(file_getApplicationFolder());
+
 	// Create a window
 	// Create a window
 	window = window_create(U"GUI example", 1000, 700);
 	window = window_create(U"GUI example", 1000, 700);
 	// Register your custom components here
 	// Register your custom components here
 	//REGISTER_PERSISTENT_CLASS(className);
 	//REGISTER_PERSISTENT_CLASS(className);
 	// Load an interface to the window
 	// Load an interface to the window
-	window_loadInterfaceFromFile(window, mediaPath + U"interface.lof");
+	window_loadInterfaceFromFile(window, U"media/interface.lof");
 
 
 	// Bind methods to events
 	// Bind methods to events
 	window_setCloseEvent(window, []() {
 	window_setCloseEvent(window, []() {
@@ -75,4 +78,7 @@ int main(int argn, char **argv) {
 		// Show the final image
 		// Show the final image
 		window_showCanvas(window);
 		window_showCanvas(window);
 	}
 	}
+
+	// When the DSR_MAIN_CALLER wrapper is used over the real main function, returning zero is no longer implicit.
+	return 0;
 }
 }

+ 10 - 6
Source/SDK/terrain/main.cpp

@@ -75,7 +75,8 @@
 
 
 using namespace dsr;
 using namespace dsr;
 
 
-const String mediaPath = string_combine(U"media", file_separator());
+const String applicationFolder = file_getApplicationFolder();
+const String mediaFolder = file_combinePaths(applicationFolder, U"media");
 
 
 // A real point (x, y, z) may touch a certain tile at integer indices (tileU, tileV) when:
 // A real point (x, y, z) may touch a certain tile at integer indices (tileU, tileV) when:
 //   tileU <= x <= tileU + 1.0
 //   tileU <= x <= tileU + 1.0
@@ -313,7 +314,8 @@ bool showBuffers = false;
 // The window handle
 // The window handle
 Window window;
 Window window;
 
 
-int main(int argn, char **argv) {
+DSR_MAIN_CALLER(dsrMain)
+int dsrMain(List<String> args) {
 	// Create a window
 	// Create a window
 	window = window_create(U"David Piuva's Software Renderer - Terrain example", 1600, 900);
 	window = window_create(U"David Piuva's Software Renderer - Terrain example", 1600, 900);
 
 
@@ -338,11 +340,11 @@ int main(int argn, char **argv) {
 	});
 	});
 
 
 	// Load height map
 	// Load height map
-	ImageU8 heightMap = image_get_red(image_load_RgbaU8(mediaPath + U"HeightMap.png"));
+	ImageU8 heightMap = image_get_red(image_load_RgbaU8(file_combinePaths(mediaFolder, U"HeightMap.png")));
 	// Load generic cloud pattern
 	// Load generic cloud pattern
-	ImageU8 genericCloudPattern = image_get_red(image_load_RgbaU8(mediaPath + U"Cloud.png"));
+	ImageU8 genericCloudPattern = image_get_red(image_load_RgbaU8(file_combinePaths(mediaFolder, U"Cloud.png")));
 	// Load height ramp
 	// Load height ramp
-	ImageRgbaU8 heightRamp = image_load_RgbaU8(mediaPath + U"RampIsland.png");
+	ImageRgbaU8 heightRamp = image_load_RgbaU8(file_combinePaths(mediaFolder, U"RampIsland.png"));
 
 
 	// Get dimensions
 	// Get dimensions
 	const int heighMapWidth = image_getWidth(heightMap);
 	const int heighMapWidth = image_getWidth(heightMap);
@@ -430,5 +432,7 @@ int main(int argn, char **argv) {
 	}
 	}
 
 
 	printText("\nTerminating the application.\n");
 	printText("\nTerminating the application.\n");
-}
 
 
+	// When the DSR_MAIN_CALLER wrapper is used over the real main function, returning zero is no longer implicit.
+	return 0;
+}