aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-12-11 18:05:26 +0100
committerDavid Robillard <d@drobilla.net>2020-12-11 18:05:26 +0100
commitf829cfa6306c5c6dae0d0a885664fe0fe5a1b0b7 (patch)
tree14e963b9feac2b3135eb1f800e716abbd08e0581
parent07c8253c2621daab8a08713aae557ae1fdea5df0 (diff)
downloadpugl-f829cfa6306c5c6dae0d0a885664fe0fe5a1b0b7.tar.gz
pugl-f829cfa6306c5c6dae0d0a885664fe0fe5a1b0b7.tar.bz2
pugl-f829cfa6306c5c6dae0d0a885664fe0fe5a1b0b7.zip
Make demo programs work from any directory, and install them
-rw-r--r--.clang-format2
-rw-r--r--examples/file_utils.c68
-rw-r--r--examples/file_utils.h41
-rw-r--r--examples/pugl_shader_demo.c20
-rw-r--r--examples/pugl_vulkan_cxx_demo.cpp53
-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--wscript33
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
diff --git a/wscript b/wscript
index 7cb1da5..e4a4798 100644
--- a/wscript
+++ b/wscript
@@ -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'])