diff options
author | David Robillard <d@drobilla.net> | 2019-08-04 23:37:58 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2020-03-11 20:32:58 +0100 |
commit | 315b1a784d270c9f3ca0d430c3c1802a3ebfd918 (patch) | |
tree | d5757ecf31b3287a66e2ad53cca07c1c4f6c5f15 | |
parent | 5c02f37c8d1dd74f3b72f1fb0b2a77f4d1dc2da9 (diff) | |
download | pugl-315b1a784d270c9f3ca0d430c3c1802a3ebfd918.tar.gz pugl-315b1a784d270c9f3ca0d430c3c1802a3ebfd918.tar.bz2 pugl-315b1a784d270c9f3ca0d430c3c1802a3ebfd918.zip |
WIP: Update C++ bindingsc++
-rw-r--r-- | .clang-format | 2 | ||||
-rw-r--r-- | .clang-tidy | 15 | ||||
-rw-r--r-- | examples/pugl_cxx_demo.cpp | 119 | ||||
-rw-r--r-- | pugl/pugl.hpp | 437 | ||||
-rw-r--r-- | wscript | 31 |
5 files changed, 553 insertions, 51 deletions
diff --git a/.clang-format b/.clang-format index b788676..1c3e537 100644 --- a/.clang-format +++ b/.clang-format @@ -104,7 +104,7 @@ SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: false SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: true +SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements diff --git a/.clang-tidy b/.clang-tidy index 0f46134..d714003 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,14 +1,27 @@ Checks: > *, + -*avoid-c-arrays, -*magic-numbers, + -*non-private-member-variables-in-classes, -*uppercase-literal-suffix, -android-cloexec-fopen, -bugprone-suspicious-string-compare, -clang-analyzer-alpha.*, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-static-cast-downcast, + -cppcoreguidelines-pro-type-vararg, + -google-runtime-references, -hicpp-multiway-paths-covered, + -hicpp-no-array-decay, -hicpp-signed-bitwise, + -hicpp-vararg, -llvm-header-guard, - -readability-else-after-return + -modernize-use-trailing-return-type, + -readability-else-after-return, + -readability-implicit-bool-conversion, + -readability-named-parameter, WarningsAsErrors: '' HeaderFilterRegex: 'pugl/.*|test/.*' FormatStyle: file diff --git a/examples/pugl_cxx_demo.cpp b/examples/pugl_cxx_demo.cpp new file mode 100644 index 0000000..4043486 --- /dev/null +++ b/examples/pugl_cxx_demo.cpp @@ -0,0 +1,119 @@ +/* + Copyright 2012-2019 David Robillard <http://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. +*/ + +/** + @file pugl_test.c A simple Pugl test that creates a top-level window. +*/ + +#define GL_SILENCE_DEPRECATION 1 + +#include "cube_view.h" +#include "demo_utils.h" +#include "test/test_utils.h" + +#include "pugl/gl.h" +#include "pugl/pugl.hpp" +#include "pugl/pugl_gl.h" + +#include <cmath> +#include <cstdint> +#include <type_traits> +#include <utility> + +struct CubeData { + double xAngle{0.0}; + double yAngle{0.0}; + double lastDrawTime{0.0}; + unsigned framesDrawn{0}; + bool quit{false}; +}; + +using CubeView = pugl::View<CubeData>; + +static pugl::Status +onConfigure(CubeView&, const pugl::ConfigureEvent& event) +{ + reshapeCube(event.width, event.height); + + return pugl::Status::success; +} + +static pugl::Status +onExpose(CubeView& view, const pugl::ExposeEvent&) +{ + const pugl::World& world = view.getWorld(); + CubeData& data = view.getData(); + const double thisTime = world.getTime(); + const double dTime = thisTime - data.lastDrawTime; + const double dAngle = dTime * 100.0; + + data.xAngle = fmod(data.xAngle + dAngle, 360.0); + data.yAngle = fmod(data.yAngle + dAngle, 360.0); + displayCube(view.cobj(), 8.0, data.xAngle, data.yAngle, false); + + data.lastDrawTime = thisTime; + ++data.framesDrawn; + + return pugl::Status::success; +} + +static pugl::Status +onKeyPress(CubeView& view, const pugl::KeyPressEvent& event) +{ + if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { + view.getData().quit = true; + } + + return pugl::Status::success; +} + +int +main(int argc, char** argv) +{ + const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); + + pugl::World world; + CubeView view{world}; + PuglFpsPrinter fpsPrinter{}; + + world.setClassName("Pugl C++ Test"); + + view.setFrame({0, 0, 512, 512}); + view.setMinSize(64, 64); + view.setAspectRatio(1, 1, 16, 9); + view.setBackend(puglGlBackend()); + view.setHint(pugl::ViewHint::resizable, opts.resizable); + view.setHint(pugl::ViewHint::samples, opts.samples); + view.setHint(pugl::ViewHint::doubleBuffer, opts.doubleBuffer); + view.setHint(pugl::ViewHint::swapInterval, opts.doubleBuffer); + view.setHint(pugl::ViewHint::ignoreKeyRepeat, opts.ignoreKeyRepeat); + + view.setEventFunc(onConfigure); + view.setEventFunc(onExpose); + view.setEventFunc(onKeyPress); + + view.createWindow("Pugl C++ Test"); + view.showWindow(); + + while (!view.getData().quit) { + view.postRedisplay(); + world.dispatchEvents(); + + puglPrintFps(world.cobj(), &fpsPrinter, &view.getData().framesDrawn); + } + + return 0; +} diff --git a/pugl/pugl.hpp b/pugl/pugl.hpp index 73cfe2a..18451ee 100644 --- a/pugl/pugl.hpp +++ b/pugl/pugl.hpp @@ -22,6 +22,13 @@ #define PUGL_PUGL_HPP #include "pugl/pugl.h" +#include "pugl/pugl_gl.h" // FIXME + +#include <chrono> +#include <functional> +#include <ratio> +#include <stdexcept> +#include <utility> /** @defgroup puglxx C++ @@ -37,84 +44,430 @@ */ namespace pugl { -/** - A drawable region that receives events. +enum class Status { + success = PUGL_SUCCESS, + failure = PUGL_FAILURE, + unknownError = PUGL_UNKNOWN_ERROR, + badBackend = PUGL_BAD_BACKEND, + backendFailed = PUGL_BACKEND_FAILED, + registrationFailed = PUGL_REGISTRATION_FAILED, + createWindowFailed = PUGL_CREATE_WINDOW_FAILED, + setFormatFailed = PUGL_SET_FORMAT_FAILED, + createContextFailed = PUGL_CREATE_CONTEXT_FAILED, + unsupportedType = PUGL_UNSUPPORTED_TYPE, +}; - This is a thin wrapper for a PuglView that contains only a pointer. +enum class ViewHint { + useCompatProfile, ///< Use compatible (not core) OpenGL profile + useDebugContext, ///< True to use a debug OpenGL context + contextVersionMajor, ///< OpenGL context major version + contextVersionMinor, ///< OpenGL context minor version + redBits, ///< Number of bits for red channel + greenBits, ///< Number of bits for green channel + blueBits, ///< Number of bits for blue channel + alphaBits, ///< Number of bits for alpha channel + depthBits, ///< Number of bits for depth buffer + stencilBits, ///< Number of bits for stencil buffer + samples, ///< Number of samples per pixel (AA) + doubleBuffer, ///< True if double buffering should be used + swapInterval, ///< Number of frames between buffer swaps + resizable, ///< True if window should be resizable + ignoreKeyRepeat, ///< True if key repeat events are ignored +}; - @ingroup puglxx -*/ -class View { +using Rect = PuglRect; +using NativeWindow = PuglNativeWindow; +using GlFunc = PuglGlFunc; +using Event = PuglEvent; + +template<PuglEventType t, class Base> +struct TypedEvent : public Base { + static constexpr const PuglEventType type = t; +}; + +/* Strong types for every event type. */ + +using ButtonPressEvent = TypedEvent<PUGL_BUTTON_PRESS, PuglEventButton>; +using ButtonReleaseEvent = TypedEvent<PUGL_BUTTON_RELEASE, PuglEventButton>; +using CreateEvent = TypedEvent<PUGL_CREATE, PuglEventAny>; +using DestroyEvent = TypedEvent<PUGL_DESTROY, PuglEventAny>; +using MapEvent = TypedEvent<PUGL_MAP, PuglEventAny>; +using UnmapEvent = TypedEvent<PUGL_UNMAP, PuglEventAny>; +using ConfigureEvent = TypedEvent<PUGL_CONFIGURE, PuglEventConfigure>; +using ExposeEvent = TypedEvent<PUGL_EXPOSE, PuglEventExpose>; +using CloseEvent = TypedEvent<PUGL_CLOSE, PuglEventAny>; +using KeyPressEvent = TypedEvent<PUGL_KEY_PRESS, PuglEventKey>; +using KeyReleaseEvent = TypedEvent<PUGL_KEY_RELEASE, PuglEventKey>; +using TextEvent = TypedEvent<PUGL_TEXT, PuglEventText>; +using EnterEvent = TypedEvent<PUGL_ENTER_NOTIFY, PuglEventCrossing>; +using LeaveEvent = TypedEvent<PUGL_LEAVE_NOTIFY, PuglEventCrossing>; +using MotionEvent = TypedEvent<PUGL_MOTION_NOTIFY, PuglEventMotion>; +using ScrollEvent = TypedEvent<PUGL_SCROLL, PuglEventScroll>; +using FocusInEvent = TypedEvent<PUGL_FOCUS_IN, PuglEventFocus>; +using FocusOutEvent = TypedEvent<PUGL_FOCUS_OUT, PuglEventFocus>; +using ClientEvent = TypedEvent<PUGL_CLIENT, PuglEventClient>; + +static inline const char* +strerror(pugl::Status status) +{ + return puglStrerror(static_cast<PuglStatus>(status)); +} + +static inline GlFunc +getProcAddress(const char* name) +{ + return puglGetProcAddress(name); +} + +class World; + +class Clock +{ +public: + using rep = double; + using period = std::ratio<1>; + using duration = std::chrono::duration<double>; + using time_point = std::chrono::time_point<Clock>; + + static constexpr bool is_steady = true; + + explicit Clock(World& world) + : _world{world} + {} + + time_point now() const; + +private: + const pugl::World& _world; +}; + +class World +{ +public: + World() + : _clock(*this) + , _world(puglNewWorld()) + { + if (!_world) { + throw std::runtime_error("Failed to create pugl::World"); + } + } + + ~World() { puglFreeWorld(_world); } + + World(const World&) = delete; + World& operator=(const World&) = delete; + World(World&&) = delete; + World&& operator=(World&&) = delete; + + Status setClassName(const char* const name) + { + return static_cast<Status>(puglSetClassName(_world, name)); + } + + double getTime() const { return puglGetTime(_world); } + + Status pollEvents(const double timeout) + { + return static_cast<Status>(puglPollEvents(_world, timeout)); + } + + Status dispatchEvents() + { + return static_cast<Status>(puglDispatchEvents(_world)); + } + + const PuglWorld* cobj() const { return _world; } + PuglWorld* cobj() { return _world; } + + const Clock& clock() { return _clock; } + +private: + Clock _clock; + PuglWorld* const _world; +}; + +inline Clock::time_point +Clock::now() const +{ + return time_point{duration{_world.getTime()}}; +} + +class ViewBase +{ public: - View(int* pargc, char** argv) - : _view(puglInit(pargc, argv)) + explicit ViewBase(World& world) + : _world(world) + , _view(puglNewView(world.cobj())) { + if (!_view) { + throw std::runtime_error("Failed to create pugl::View"); + } + puglSetHandle(_view, this); - puglSetEventFunc(_view, _onEvent); } - virtual ~View() { puglDestroy(_view); } + ~ViewBase() { puglFreeView(_view); } + + ViewBase(const ViewBase&) = delete; + ViewBase(ViewBase&&) = delete; + ViewBase& operator=(const ViewBase&) = delete; + ViewBase&& operator=(ViewBase&&) = delete; + + Status setHint(ViewHint hint, int value) + { + return static_cast<Status>( + puglSetViewHint(_view, static_cast<PuglViewHint>(hint), value)); + } + + bool getVisible() const { return puglGetVisible(_view); } + + Status postRedisplay() + { + return static_cast<Status>(puglPostRedisplay(_view)); + } + + const pugl::World& getWorld() const { return _world; } + pugl::World& getWorld() { return _world; } + + Rect getFrame() const { return puglGetFrame(_view); } - virtual void initWindowParent(PuglNativeWindow parent) { - puglInitWindowParent(_view, parent); + Status setFrame(Rect frame) + { + return static_cast<Status>(puglSetFrame(_view, frame)); } - virtual void initWindowSize(int width, int height) { - puglInitWindowSize(_view, width, height); + Status setMinSize(int width, int height) + { + return static_cast<Status>(puglSetMinSize(_view, width, height)); } - virtual void initWindowMinSize(int width, int height) { - puglInitWindowMinSize(_view, width, height); + Status setAspectRatio(int minX, int minY, int maxX, int maxY) + { + return static_cast<Status>( + puglSetAspectRatio(_view, minX, minY, maxX, maxY)); } - virtual void initWindowAspectRatio(int min_x, int min_y, int max_x, int max_y) { - puglInitWindowAspectRatio(_view, min_x, min_y, max_x, max_y); + Status setWindowTitle(const char* title) + { + return static_cast<Status>(puglSetWindowTitle(_view, title)); } - virtual void initResizable(bool resizable) { - puglInitResizable(_view, resizable); + Status setParentWindow(NativeWindow parent) + { + return static_cast<Status>(puglSetParentWindow(_view, parent)); } - virtual void initTransientFor(uintptr_t parent) { - puglInitTransientFor(_view, parent); + Status setTransientFor(NativeWindow parent) + { + return static_cast<Status>(puglSetTransientFor(_view, parent)); } - virtual void initBackend(const PuglBackend* backend) { - puglInitBackend(_view, backend); + Status createWindow(const char* title) + { + return static_cast<Status>(puglCreateWindow(_view, title)); } - virtual void createWindow(const char* title) { - puglCreateWindow(_view, title); + Status showWindow() { return static_cast<Status>(puglShowWindow(_view)); } + + Status hideWindow() { return static_cast<Status>(puglHideWindow(_view)); } + + NativeWindow getNativeWindow() { return puglGetNativeWindow(_view); } + + Status setBackend(const PuglBackend* backend) + { + return static_cast<Status>(puglSetBackend(_view, backend)); } - virtual void showWindow() { puglShowWindow(_view); } - virtual void hideWindow() { puglHideWindow(_view); } - virtual PuglNativeWindow getNativeWindow() { return puglGetNativeWindow(_view); } + void* getContext() { return puglGetContext(_view); } - virtual void onEvent(const PuglEvent* event) = 0; + bool hasFocus() const { return puglHasFocus(_view); } - virtual void* getContext() { return puglGetContext(_view); } - virtual void ignoreKeyRepeat(bool ignore) { puglIgnoreKeyRepeat(_view, ignore); } - virtual void grabFocus() { puglGrabFocus(_view); } - virtual void requestAttention() { puglRequestAttention(_view); } - virtual PuglStatus waitForEvent() { return puglWaitForEvent(_view); } - virtual PuglStatus processEvents() { return puglProcessEvents(_view); } - virtual void postRedisplay() { puglPostRedisplay(_view); } + Status grabFocus() { return static_cast<Status>(puglGrabFocus(_view)); } + + Status requestAttention() + { + return static_cast<Status>(puglRequestAttention(_view)); + } PuglView* cobj() { return _view; } +protected: + World& _world; + PuglView* _view; +}; + +/** + A drawable region that receives events. + + This is a thin wrapper for a PuglView that contains only a pointer. + + @ingroup puglxx +*/ +template<typename Data> +class View : public ViewBase +{ +public: + template<class E> + using TypedEventFunc = std::function<pugl::Status(View&, const E&)>; + + using NothingEvent = TypedEvent<PUGL_NOTHING, PuglEvent>; + + /** + A tuple of event handlers, one for each event type. + + Note that the indices here must correspond to PuglEventType. + */ + using EventFuncs = std::tuple<TypedEventFunc<NothingEvent>, + TypedEventFunc<ButtonPressEvent>, + TypedEventFunc<ButtonReleaseEvent>, + TypedEventFunc<CreateEvent>, + TypedEventFunc<DestroyEvent>, + TypedEventFunc<MapEvent>, + TypedEventFunc<UnmapEvent>, + TypedEventFunc<ConfigureEvent>, + TypedEventFunc<ExposeEvent>, + TypedEventFunc<CloseEvent>, + TypedEventFunc<KeyPressEvent>, + TypedEventFunc<KeyReleaseEvent>, + TypedEventFunc<TextEvent>, + TypedEventFunc<EnterEvent>, + TypedEventFunc<LeaveEvent>, + TypedEventFunc<MotionEvent>, + TypedEventFunc<ScrollEvent>, + TypedEventFunc<FocusInEvent>, + TypedEventFunc<FocusOutEvent>, + TypedEventFunc<ClientEvent>>; + + using EventFunc = std::function<pugl::Status(View&, const PuglEvent&)>; + + explicit View(World& world) + : ViewBase{world} + , _data{} + { + puglSetEventFunc(_view, _onEvent); + } + + View(World& world, Data data) + : ViewBase{world} + , _data{data} + { + puglSetEventFunc(_view, _onEvent); + } + + template<class HandledEvent> + Status setEventFunc( + std::function<pugl::Status(View&, const HandledEvent&)> handler) + { + std::get<HandledEvent::type>(_eventFuncs) = handler; + + return Status::success; + } + + template<class HandledEvent> + Status setEventFunc(pugl::Status (*handler)(View&, const HandledEvent&)) + { + std::get<HandledEvent::type>(_eventFuncs) = handler; + + return Status::success; + } + + const Data& getData() const { return _data; } + Data& getData() { return _data; } + private: - static void _onEvent(PuglView* view, const PuglEvent* event) { - ((View*)puglGetHandle(view))->onEvent(event); + static PuglStatus _onEvent(PuglView* view, const PuglEvent* event) noexcept + { + View* self = static_cast<View*>(puglGetHandle(view)); + + return static_cast<PuglStatus>(self->dispatchEvent(*event)); } - PuglView* _view; + Status dispatchEvent(const PuglEvent& event) + { + switch (event.type) { + case PUGL_NOTHING: + return Status::success; + case PUGL_BUTTON_PRESS: + return dispatchTypedEvent( + static_cast<const ButtonPressEvent&>(event.button)); + case PUGL_BUTTON_RELEASE: + return dispatchTypedEvent( + static_cast<const ButtonReleaseEvent&>(event.button)); + case PUGL_CREATE: + return dispatchTypedEvent( + static_cast<const CreateEvent&>(event.any)); + case PUGL_DESTROY: + return dispatchTypedEvent( + static_cast<const DestroyEvent&>(event.any)); + case PUGL_MAP: + return dispatchTypedEvent(static_cast<const MapEvent&>(event.any)); + case PUGL_UNMAP: + return dispatchTypedEvent( + static_cast<const UnmapEvent&>(event.any)); + case PUGL_CONFIGURE: + return dispatchTypedEvent( + static_cast<const ConfigureEvent&>(event.configure)); + case PUGL_EXPOSE: + return dispatchTypedEvent( + static_cast<const ExposeEvent&>(event.expose)); + case PUGL_CLOSE: + return dispatchTypedEvent( + static_cast<const CloseEvent&>(event.any)); + case PUGL_KEY_PRESS: + return dispatchTypedEvent( + static_cast<const KeyPressEvent&>(event.key)); + case PUGL_KEY_RELEASE: + return dispatchTypedEvent( + static_cast<const KeyReleaseEvent&>(event.key)); + case PUGL_TEXT: + return dispatchTypedEvent( + static_cast<const TextEvent&>(event.text)); + case PUGL_ENTER_NOTIFY: + return dispatchTypedEvent( + static_cast<const EnterEvent&>(event.crossing)); + case PUGL_LEAVE_NOTIFY: + return dispatchTypedEvent( + static_cast<const LeaveEvent&>(event.crossing)); + case PUGL_MOTION_NOTIFY: + return dispatchTypedEvent( + static_cast<const MotionEvent&>(event.motion)); + case PUGL_SCROLL: + return dispatchTypedEvent( + static_cast<const ScrollEvent&>(event.scroll)); + case PUGL_FOCUS_IN: + return dispatchTypedEvent( + static_cast<const FocusInEvent&>(event.focus)); + case PUGL_FOCUS_OUT: + return dispatchTypedEvent( + static_cast<const FocusOutEvent&>(event.focus)); + case PUGL_CLIENT: + return dispatchTypedEvent( + static_cast<const ClientEvent&>(event.client)); + } + + return Status::failure; + } + + template<class E> + Status dispatchTypedEvent(const E& event) + { + auto& handler = std::get<E::type>(_eventFuncs); + if (handler) { + return handler(*this, event); + } + + return Status::success; + } + + Data _data; + EventFuncs _eventFuncs; }; -} // namespace pugl +} // namespace pugl /** @} */ -#endif /* PUGL_PUGL_HPP */ +#endif /* PUGL_PUGL_HPP */ @@ -22,6 +22,7 @@ out = 'build' # Build directory def options(ctx): ctx.load('compiler_c') + ctx.load('compiler_cxx') opts = ctx.configuration_options() opts.add_option('--target', default=None, dest='target', @@ -43,24 +44,34 @@ def options(ctx): def configure(conf): conf.load('compiler_c', cache=True) + try: + conf.load('compiler_cxx', cache=True) + except Exception: + pass + conf.load('autowaf', cache=True) autowaf.set_c_lang(conf, 'c99') + if 'COMPILER_CXX' in conf.env: + autowaf.set_cxx_lang(conf, 'c++11') conf.env.ALL_HEADERS = Options.options.all_headers conf.env.TARGET_PLATFORM = Options.options.target or sys.platform platform = conf.env.TARGET_PLATFORM + def append_cflags(flags): + conf.env.append_value('CFLAGS', flags) + conf.env.append_value('CXXFLAGS', flags) + if platform == 'darwin': - conf.env.append_unique('CFLAGS', ['-Wno-deprecated-declarations']) + append_cflags(['-Wno-deprecated-declarations']) if conf.env.MSVC_COMPILER: - conf.env.append_unique('CFLAGS', ['/wd4191']) + append_cflags(['/wd4191']) else: - conf.env.append_value('LINKFLAGS', ['-fvisibility=hidden']) - conf.env.append_value('CFLAGS', ['-fvisibility=hidden']) + conf.env.append_unique('LINKFLAGS', ['-fvisibility=hidden']) + append_cflags(['-fvisibility=hidden']) if Options.options.strict: - conf.env.append_value('CFLAGS', ['-Wunused-parameter', - '-Wno-pedantic']) + append_cflags(['-Wunused-parameter', '-Wno-pedantic']) if Options.options.ultra_strict and 'clang' in conf.env.CC: for var in ['CFLAGS', 'CXXFLAGS']: @@ -289,6 +300,8 @@ def build(bld): source=['pugl/detail/x11_cairo.c']) def build_example(prog, source, platform, backend, **kwargs): + lang = 'cxx' if source[0].endswith('.cpp') else 'c' + use = ['pugl_%s_static' % platform, 'pugl_%s_%s_static' % (platform, backend)] @@ -308,7 +321,7 @@ def build(bld): deps.get(platform, {}).get(k, []) + deps.get(backend_lib, {}).get(k, []))}) - bld(features = 'c cprogram', + bld(features = '%s %sprogram' % (lang, lang), source = source, target = target, use = use, @@ -349,6 +362,10 @@ def build(bld): 'pugl_%s_stub_static' % platform], uselib = deps[platform]['uselib'] + ['CAIRO']) + if bld.env.CXX and bld.env.HAVE_GL: + build_example('pugl_cxx_demo', ['examples/pugl_cxx_demo.cpp'], + platform, 'gl', uselib=['GL', 'M']) + if bld.env.DOCS: autowaf.build_dox(bld, 'PUGL', PUGL_VERSION, top, out) |