diff options
-rw-r--r-- | .clang-format | 2 | ||||
-rw-r--r-- | examples/file_utils.c | 68 | ||||
-rw-r--r-- | examples/file_utils.h | 41 | ||||
-rw-r--r-- | examples/pugl_shader_demo.c | 20 | ||||
-rw-r--r-- | examples/pugl_vulkan_cxx_demo.cpp | 53 | ||||
-rw-r--r-- | examples/shaders/header_330.glsl (renamed from shaders/header_330.glsl) | 0 | ||||
-rw-r--r-- | examples/shaders/header_420.glsl (renamed from shaders/header_420.glsl) | 0 | ||||
-rw-r--r-- | examples/shaders/rect.frag (renamed from shaders/rect.frag) | 0 | ||||
-rw-r--r-- | examples/shaders/rect.vert (renamed from shaders/rect.vert) | 0 | ||||
-rw-r--r-- | wscript | 33 |
10 files changed, 189 insertions, 28 deletions
diff --git a/.clang-format b/.clang-format index 043fd1f..a505e26 100644 --- a/.clang-format +++ b/.clang-format @@ -33,7 +33,7 @@ BraceWrapping: AfterObjCDeclaration: true AfterStruct: false AfterUnion: false - AfterExternBlock: true + AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false diff --git a/examples/file_utils.c b/examples/file_utils.c new file mode 100644 index 0000000..2b00bdc --- /dev/null +++ b/examples/file_utils.c @@ -0,0 +1,68 @@ +/* + Copyright 2019-2020 David Robillard <d@drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#if !defined(__APPLE__) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif + +#include "file_utils.h" + +#ifdef _WIN32 +# include <io.h> +# include <windows.h> +# define F_OK 0 +#else +# include <libgen.h> +# include <unistd.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +char* +resourcePath(const char* const programPath, const char* const name) +{ + char* const binary = strdup(programPath); + +#ifdef _WIN32 + char programDir[_MAX_DIR]; + _splitpath(binary, programDir, NULL, NULL, NULL); + _splitpath(binary, NULL, programDir + strlen(programDir), NULL, NULL); + programDir[strlen(programDir) - 1] = '\0'; +#else + char* const programDir = dirname(binary); +#endif + + const size_t programDirLen = strlen(programDir); + const size_t nameLen = strlen(name); + const size_t totalLen = programDirLen + nameLen + 4; + + char* const programRelative = (char*)calloc(totalLen, 1); + snprintf(programRelative, totalLen, "%s/%s", programDir, name); + if (!access(programRelative, F_OK)) { + free(binary); + return programRelative; + } + + free(programRelative); + free(binary); + + const size_t sysPathLen = strlen(PUGL_DATA_DIR) + nameLen + 4; + char* const sysPath = (char*)calloc(sysPathLen, 1); + snprintf(sysPath, sysPathLen, "%s/%s", PUGL_DATA_DIR, name); + return sysPath; +} diff --git a/examples/file_utils.h b/examples/file_utils.h new file mode 100644 index 0000000..1530157 --- /dev/null +++ b/examples/file_utils.h @@ -0,0 +1,41 @@ +/* + Copyright 2019-2020 David Robillard <d@drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef EXAMPLES_FILE_UTILS_H +#define EXAMPLES_FILE_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return the path to a resource file. + + This takes a name like "shaders/something.glsl" and returns the actual + path that can be used to load that resource, which may be relative to the + current executable (for running in bundles or the build directory), or a + shared system directory for installs. + + The returned path must be freed with free(). +*/ +char* +resourcePath(const char* programPath, const char* name); + +#ifdef __cplusplus +} +#endif + +#endif // EXAMPLES_FILE_UTILS_H diff --git a/examples/pugl_shader_demo.c b/examples/pugl_shader_demo.c index 800b8f0..8ebbe60 100644 --- a/examples/pugl_shader_demo.c +++ b/examples/pugl_shader_demo.c @@ -35,6 +35,7 @@ */ #include "demo_utils.h" +#include "file_utils.h" #include "rects.h" #include "shader_utils.h" #include "test/test_utils.h" @@ -62,6 +63,7 @@ typedef struct typedef struct { + const char* programPath; PuglWorld* world; PuglView* view; PuglTestOptions opts; @@ -203,14 +205,18 @@ makeRects(const size_t numRects) } static char* -loadShader(const char* const path) +loadShader(const char* const programPath, const char* const name) { + char* const path = resourcePath(programPath, name); + fprintf(stderr, "Loading shader %s\n", path); + FILE* const file = fopen(path, "r"); if (!file) { logError("Failed to open '%s'\n", path); return NULL; } + free(path); fseek(file, 0, SEEK_END); const size_t fileSize = (size_t)ftell(file); @@ -303,9 +309,14 @@ setupGl(PuglTestApp* app) : "shaders/header_420.glsl"); // Load shader sources - char* const headerSource = loadShader(headerFile); - char* const vertexSource = loadShader("shaders/rect.vert"); - char* const fragmentSource = loadShader("shaders/rect.frag"); + char* const headerSource = loadShader(app->programPath, headerFile); + + char* const vertexSource = loadShader(app->programPath, + "shaders/rect.vert"); + + char* const fragmentSource = loadShader(app->programPath, + "shaders/rect.frag"); + if (!vertexSource || !fragmentSource) { logError("Failed to load shader sources\n"); return PUGL_FAILURE; @@ -405,6 +416,7 @@ main(int argc, char** argv) { PuglTestApp app = {0}; + app.programPath = argv[0]; app.glMajorVersion = 3; app.glMinorVersion = 3; diff --git a/examples/pugl_vulkan_cxx_demo.cpp b/examples/pugl_vulkan_cxx_demo.cpp index 0a86d16..21fd4df 100644 --- a/examples/pugl_vulkan_cxx_demo.cpp +++ b/examples/pugl_vulkan_cxx_demo.cpp @@ -28,6 +28,7 @@ */ #include "demo_utils.h" +#include "file_utils.h" #include "rects.h" #include "test/test_utils.h" @@ -150,7 +151,9 @@ struct RectData { /// Shader modules for drawing rectangles struct RectShaders { - VkResult init(const sk::VulkanApi& vk, const GraphicsDevice& gpu); + VkResult init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + const std::string& programPath); sk::ShaderModule vert{}; sk::ShaderModule frag{}; @@ -687,9 +690,15 @@ RenderPass::init(const sk::VulkanApi& vk, } std::vector<uint32_t> -readFile(const std::string& filename) +readFile(const char* const programPath, const std::string& filename) { - std::unique_ptr<FILE, decltype(&fclose)> file{fopen(filename.c_str(), "rb"), + std::unique_ptr<char, decltype(&free)> path{resourcePath(programPath, + filename.c_str()), + &free}; + + std::cerr << "Loading shader: " << path.get() << std::endl; + + std::unique_ptr<FILE, decltype(&fclose)> file{fopen(path.get(), "rb"), &fclose}; if (!file) { @@ -726,10 +735,15 @@ createShaderModule(const sk::VulkanApi& vk, } VkResult -RectShaders::init(const sk::VulkanApi& vk, const GraphicsDevice& gpu) +RectShaders::init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + const std::string& programPath) { - auto vertShaderCode = readFile("build/shaders/rect.vert.spv"); - auto fragShaderCode = readFile("build/shaders/rect.frag.spv"); + auto vertShaderCode = readFile(programPath.c_str(), + "shaders/rect.vert.spv"); + + auto fragShaderCode = readFile(programPath.c_str(), + "shaders/rect.frag.spv"); if (vertShaderCode.empty() || fragShaderCode.empty()) { return VK_ERROR_INITIALIZATION_FAILED; @@ -1407,8 +1421,11 @@ private: class PuglVulkanDemo { public: - PuglVulkanDemo(const PuglTestOptions& o, size_t numRects); + PuglVulkanDemo(const char* executablePath, + const PuglTestOptions& o, + size_t numRects); + const char* programPath; PuglTestOptions opts; pugl::World world; pugl::VulkanLoader loader; @@ -1436,8 +1453,11 @@ makeRects(const size_t numRects, const uint32_t windowWidth) return rects; } -PuglVulkanDemo::PuglVulkanDemo(const PuglTestOptions& o, const size_t numRects) - : opts{o} +PuglVulkanDemo::PuglVulkanDemo(const char* const executablePath, + const PuglTestOptions& o, + const size_t numRects) + : programPath{executablePath} + , opts{o} , world{pugl::WorldType::program, pugl::WorldFlag::threads} , loader{world} , view{world, *this} @@ -1732,9 +1752,11 @@ VulkanContext::init(pugl::VulkanLoader& loader, const PuglTestOptions& opts) } int -run(const PuglTestOptions opts, const size_t numRects) +run(const char* const programPath, + const PuglTestOptions opts, + const size_t numRects) { - PuglVulkanDemo app{opts, numRects}; + PuglVulkanDemo app{programPath, opts, numRects}; VkResult r = VK_SUCCESS; const auto width = static_cast<int>(app.extent.width); @@ -1778,7 +1800,7 @@ run(const PuglTestOptions opts, const size_t numRects) } // Load shader modules - if ((r = app.rectShaders.init(vk, app.gpu))) { + if ((r = app.rectShaders.init(vk, app.gpu, app.programPath))) { return logError("Failed to load shaders (%s)\n", sk::string(r)); } @@ -1826,9 +1848,10 @@ int main(int argc, char** argv) { // Parse command line options - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); + const char* const programPath = argv[0]; + const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); if (opts.help) { - puglPrintTestUsage(argv[0], ""); + puglPrintTestUsage(programPath, ""); return 0; } @@ -1844,5 +1867,5 @@ main(int argc, char** argv) } // Run application - return run(opts, static_cast<size_t>(numRects)); + return run(programPath, opts, static_cast<size_t>(numRects)); } diff --git a/shaders/header_330.glsl b/examples/shaders/header_330.glsl index bfe7a00..bfe7a00 100644 --- a/shaders/header_330.glsl +++ b/examples/shaders/header_330.glsl diff --git a/shaders/header_420.glsl b/examples/shaders/header_420.glsl index 55fbe8a..55fbe8a 100644 --- a/shaders/header_420.glsl +++ b/examples/shaders/header_420.glsl diff --git a/shaders/rect.frag b/examples/shaders/rect.frag index ecec50d..ecec50d 100644 --- a/shaders/rect.frag +++ b/examples/shaders/rect.frag diff --git a/shaders/rect.vert b/examples/shaders/rect.vert index 09f1917..09f1917 100644 --- a/shaders/rect.vert +++ b/examples/shaders/rect.vert @@ -58,6 +58,8 @@ def configure(conf): conf.env.TARGET_PLATFORM = Options.options.target or sys.platform platform = conf.env.TARGET_PLATFORM + data_dir = '%s/%s' % (conf.env.DATADIR, 'pugl-%s' % PUGL_MAJOR_VERSION) + if Options.options.strict: # Check for programs used by lint target conf.find_program("flake8", var="FLAKE8", mandatory=False) @@ -87,6 +89,7 @@ def configure(conf): '/wd4710', # function not inlined '/wd4711', # function selected for automatic inline expansion '/wd4820', # padding added after construct + '/wd4996', # POSIX name for this item is deprecated '/wd5045', # will insert Spectre mitigation for memory load ], }) @@ -294,6 +297,8 @@ def configure(conf): else: conf.env.PUGL_PLATFORM = 'x11' + conf.define('PUGL_DATA_DIR', data_dir) + autowaf.set_lib_env(conf, 'pugl', PUGL_VERSION, lib='pugl_' + conf.env.PUGL_PLATFORM) @@ -393,6 +398,8 @@ def build(bld): # Library dependencies of pugl libraries (for building examples) deps = {} + data_dir = os.path.join(bld.env.DATADIR, 'pugl-%s' % PUGL_MAJOR_VERSION) + def build_pugl_lib(name, **kwargs): deps[name] = {} for k in ('lib', 'framework', 'uselib'): @@ -540,7 +547,7 @@ def build(bld): use = ['pugl_%s_static' % platform, 'pugl_%s_%s_static' % (platform, backend)] - target = prog + target = 'examples/' + prog if bld.env.TARGET_PLATFORM == 'darwin': target = '{0}.app/Contents/MacOS/{0}'.format(prog) @@ -562,16 +569,22 @@ def build(bld): target = target, includes = includes, use = use, - install_path = '', + install_path = bld.env.BINDIR, **kwargs) if bld.env.BUILD_TESTS: - for s in ('rect.vert', 'rect.frag'): + for s in [ + 'header_330.glsl', + 'header_420.glsl', + 'rect.frag', + 'rect.vert', + ]: # Copy shaders to build directory for example programs bld(features = 'subst', is_copy = True, - source = 'shaders/%s' % s, - target = 'shaders/%s' % s) + source = 'examples/shaders/%s' % s, + target = 'examples/shaders/%s' % s, + install_path = os.path.join(data_dir, 'shaders')) if bld.env.HAVE_GL: glad_cflags = [] if bld.env.MSVC_COMPILER else ['-Wno-pedantic'] @@ -586,6 +599,7 @@ def build(bld): platform, 'stub') build_example('pugl_shader_demo', ['examples/pugl_shader_demo.c', + 'examples/file_utils.c', 'examples/glad/glad.c'], platform, 'gl', cflags=glad_cflags, @@ -605,13 +619,15 @@ def build(bld): complete = bld.path.get_bld().make_node( 'shaders/%s' % s.replace('.', '.vulkan.')) bld(rule = concatenate, - source = ['shaders/header_420.glsl', 'shaders/%s' % s], + source = ['examples/shaders/header_420.glsl', + 'examples/shaders/%s' % s], target = complete) cmd = bld.env.GLSLANGVALIDATOR[0] + " -V -o ${TGT} ${SRC}" bld(rule = cmd, source = complete, - target = 'shaders/%s.spv' % s) + target = 'examples/shaders/%s.spv' % s, + install_path = os.path.join(data_dir, 'shaders')) build_example('pugl_vulkan_demo', ['examples/pugl_vulkan_demo.c'], @@ -620,7 +636,8 @@ def build(bld): if bld.env.CXX: build_example('pugl_vulkan_cxx_demo', - ['examples/pugl_vulkan_cxx_demo.cpp'], + ['examples/pugl_vulkan_cxx_demo.cpp', + 'examples/file_utils.c'], platform, 'vulkan', defines=['PUGL_DISABLE_DEPRECATED'], uselib=['DL', 'M', 'PTHREAD', 'VULKAN']) |