Major release that introduces new features, general improvements and the usual set of fixes. This is release is almost backwards compatible with NAP 0.7.X and shouldn't require major changes when upgrading.
Download
New Features
Wayland, SDL3 & High DPI Rendering
Bump and integrate SDL 3; primarily because of the improved, now uniform, cross platform handling of high DPI displays. As a consequence, NAP applications now scale correct on every supported platform. This resolves the High DPI scaling Linux/X11 issue. It also gave me the opportunity to introduce a video back-end driver selector, which is shared between the editor and applications. Native wayland applications are now supported.
You can now ask NAP to run applications explicitly in X11 or Wayland on Linux. By default the system default is used, which selects the most appropriate video driver for your platform. On Ubuntu 24.04 this is XWayland on Raspberry Pi OS this is most likely Wayland, unless you revert to X11. The new VideoDriver option is a property of the nap::RenderServiceConfiguration, configurable in Napkin.
Note that native wayland apps cannot be positioned programmatically. The system will issue an error when the nap::RenderWindow::setPosition call fails. There are also other constraints you should be aware of before going full wayland, outlined in the SDL3 Wayland wiki.
Applets
Complete NAP applications that run inside another host process, alongside each other, thread safe.
Multiple applets can run at the same time, without interference unless requested. They're all bound to their own thread and all resources are local to that thread, including: core, the resource manager, spawned objects, services, the render engine etc. Currently, Napkin uses applets primarily for previewing assets like textures and meshes, but they can also be launched in any host environment as fully functional, standalone NAP applications. And you’re not limited to just one—you can run as many as you need.
Applets in Napkin enable developers or end-users to preview and inspect content before it is fully integrated into the main application, giving them a better understanding of what they are authoring (such as textures, meshes, materials, and more) and helps ensure the data is compatible with the application. The texture and mesh preview applets demonstrate this functionality, running inside Napkin. #81
System
Background & Threading
For this to work we had to re-work all the parts of the core system that are currently not thread safe, ie: not intended to be part of another process, which included services tied to imgui, sdl, the nap::RenderEngine and the nap::ModuleManager. We also improved the caching and handling of modules - resulting in much faster load times on Linux and Windows.
While working on module resolve for applets (including shared modules), I added a dependency list for each module in the project. This helps identify and flag redundant modules that were loaded earlier, making it easier to clean up the project. The introduction of this nap::ModuleCache, alongside the dependency tracking, leads to faster startup times. Napkin now launches in less than 3 seconds in release mode, with 3 NAP instances loading concurrently.
Integration
It is relatively straight forward to add a new applet to Napkin or another host environment: Every applet is spawned, initialized and run by an AppletRunner. API events are used to communicate with the applet without stalling the host application. Applets behave for the most part like a regular NAP application: they are sourced from an app.json and load all required modules and data (sequentially) using the standard core de-serialization and init procedures. You can even author your applet inside Napkin, like a regular application!
The applets inside Napkin run at 60fps but process events immediately when detected, without waiting. When an applet is disabled or minimized (hidden), it becomes inactive—stopping all processing and entering sleep mode to save resources. This behavior can be customized to suit specific needs, including the option to only render a frame when input is received.
Window & Events
Each applet that is spawned (via the RenderPanel widget hosting it) is bound to a Vulkan-compatible QWindow, rather than a Vulkan-compatible window created by SDL. Upon initialization, the nap::RenderWindow is set up using a window handle from Qt, instead of being created directly using SDL, which is achieved by registering a render window creation function prior to applet initialization.
The RenderPanel QWidget intercepts input events and converts those into NAP events using an AppletEventConverter. This is very similar to how the default SDLEventConverter works. All other remaining SDL functionality is confined to the applet thread, except for video subsystem initialization, which happens on the main thread before applet creation, as outlined in the official SDL documentation. I’ve disabled most SDL events and periodically pull to clear potential entries in the queue. Applets can be resized and undocked, like regular QDock widgets.
Texture Preview Applet
Allows you to inspect a 2D texture and cubemap in 2D and 3D, including all of it's properties such as: resolution, channels, bit depth etc. Every type of 2D texture and cubemap is supported, including the nap::ImageFromFile and nap::CubeMapFromFile.
- 2D textures can be previewed flat (orthographic, aspect-corrected) or on 3D meshes.
- Cube maps are applied to a skybox and reflected on a 3D (custom) mesh.
- The applet also provides detailed information about the texture, including available attributes, bounds, etc.
The last loaded object is tracked, and any property changes are detected and re-uploaded. The object is always framed correct, regardless of size, using its actual bounds to compute camera offsets and planes.
Video from old build:
texture_mesh_preview_LQ.mp4
Mesh Preview Applet
Allows you to inspect a mesh in 3D, including all of it's properties such as: light information, triangle count, available vertex attributes, connectivity, topology, bounds etc. Every type of mesh is supported, including triangular and non-triangular meshes.
The last loaded object is tracked, and any property changes are detected and re-uploaded. The object is always framed correct, regardless of size, using its actual bounds to compute camera offsets and planes.
Module Descriptor
Every NAP object now knows which module it originates from. This is achieved by registering a static function local to the translation unit that has a handle to the module descriptor, which is registered and resolved automatically when you define your type. You can access the module for any given type by using nap::rtti::getModuleDescription(T). #81
Zoom & Pan Controller
The new nap::ZoomPanController allows for freely moving around and zooming into a scene or 2D texture using an orthographic camera. Use the frameTexture function to adjust the scale and position of your texture, ensuring it fits perfectly in the viewport. #81
Improvements
- Group resources by module in Napkin instead of a flat list #81
- Making it easier to search for and find specific resources.
- New icons for common types, including
nap::Texture,nap::IMesh,nap::Material,nap::Window,nap::Shaderetc. - New
nap::UVTestTexture,nap::TestCubeMapandnap::SunsetCubeMapfor demo, debug and test purposes. #81 - New
nap::HumanoidMesh,nap::ToyMesh,nap::ShaderBallMeshandnap::LucyMeshfor demo, debug and test purposes. - Displays are no longer cached #104
RenderService::getDisplaysnow returns a list of currently connected displays- Added new display properties, including
Display::EOrientation - Moved
nap::Displayinto it's own header (display.h), included byrenderservice.h
- The content scaling factor is now window relative, and no longer tied to the display #104
- Use
nap::RenderWindow::getDisplayScaleto get the actual (final) content display scale - Use
nap::RenderWindow::getPixelDensityto get the window pixel density - Use
nap::Display::getContentScaleto get the content scale of a display
- Use
- High DPI mode is made implicit and always enabled #104
- As a result,
RenderService::getHighDPIEnabledis deprecated and always returns true
- As a result,
- Default window icons (Windows, X11..), using
SDL::createSurface#104 - Implement depth resolve attachments (MSAA) for depth render texture resources #90
- Improved setup of
nap::BoxFrameMesh#90 - Add
nap::ColorDepthRenderTargetto renderadvanced, restoring the simplicity ofnap::RenderTarget - Remove Vulkan version check from renderadvanced #90
- Remove nap::BufferBindingUVec4 #90
- Many new SDL helper functions #104
- Initialize shader compilation using provided (default) config. #107
- Allow initialization of render service using an external window handle #105
- Removed unnecessary stringFormat(..) calls in errorState.check(...) #96
- Improved thread safety while loading / saving sequences #95
- Add
nap::RenderWindow::AlwaysOnTopproperty to move a window to the front and keep it there. #93 - Internal Textures & Links #83
- A simple contract that enables external code to update the layout of a texture after completing (for example) a render pass.
- Error messages with level >= warning are always made visible in the logger.
- The log panel will scroll and highlight it when detected, raising the widget if the dock is not visible.
- Added
utility::computeCameraDistanceto calculate the required camera distance to fit a given plane or radius based on a specific FOV.
Fixes
- Create sync primitives based on number of allocated swap-chain images #101
- Render window Vulkan validation layer fix & sync optimization #99
- Construct
MidiInputPortandMidiOutputPortwith core handle - fix #98 - Fixed issue where wrong output pins would get disconnected in AudioOutput of sequencer #95
- Fix shader constant hash collisions in pipeline keys #89
- Fix object type in Napkin not being updated after swapping (moving) indices #92
- Fixed (re)size grip of main window. #81
- Update additive blend mode to multiply alpha #82
- Uploading a DynamicWrite buffer (internally double-buffered) does not update the descriptor in the material instance #90
- Sampler doesn't support VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT #90
Purged
Completely removed deprecated (since 0.5) macOS and pybind support from the build system and nap source code, including APPLE directives in CMake, build scripts and deprecated x86 libraries. #108
Breaking Changes
-
The list of displays, returned by the render service by
nap::RenderService::getDisplays(), is now a fresh copy instead of cached reference;
this ensures the display information is always up to date and reflects current display connection status. -
nap::RenderTargetno longer binds to a depth texture, only color. Use anap::ColorDepthRenderTargetto combine both or anap::DepthRenderTargetfor only depth. This change minimizes overhead and also restores original / previous functionality. -
Ubuntu 22.04 LTSis no longer supported.
I'd like to thank @TimGroeneboom, @stijnvanbeek, @lshoek and @cklosters for their contributions