The content is basically identical to before, but there are three important changes:
The version number now uses four numbers: 188.8.131.52. The fourth number is a package-build number which I can increase, even though I pack the same version of GLFW. This finally allows me to get rid of the “pre-release” flags I previously used for the VS 2017 repackage.
I no longer use CoApp. CoApp is dead and not really missed. At work I started writing .nuspec and .targets files manually, and this is neither very hard, nor very much work.
Last but not least, I added some properties, available within the Visual Studio GUI as part of the properties pages. There you can now enforce configuration and toolset version of the library you want to use. This is especially useful if you have special configurations which cannot automatically mapped by NuGet. You can now map those manually, at least.
I am playing Horizon Zero Dawn (by Guerrilla Games). Brillant game! I am having a great time with it.
When I learned (this Friday) in the Game, that the small Device Aloy is using is called “Focus” and was produced by a Company called “Faro (Automated Solutions)”, I laughed so hard I had to pause the game.
This is even more funny, since I am working at FARO, and I am working on the software for our Focus laser scanner.
Here we are. At the end of 2017. Compared to 2016 it was a great year, and much has happened. In fact, I was so busy, I found almost no time to write here, that this blog seemed genuinely dead. It is not! It is … just … slow.
Most important change for me: I left the academia for good. This spring I joined FARO Scanner Production, a high-tech company creating laser scanner hardware and software. Obviously, I came for the software, more precisely for the visualization and rendering functionality. So far, I am truly happy with my new job. Everyone I work with is great, the tasks are great, and I have fun! Towards the end of the year I got promoted to Team Lead of the visualization group. Things are getting busy but also more and more interesting. I am really looking forward for the new challenges and opportunities coming in 2018.
And now there is Voro++ on Nuget. Voro++ is a library and utility, written by Chris Rycroft (with Applied Mathematics in Harvard SEAS) for compute Voronoi cells für 3D data. I use his lib actually to compute natural neighbors in my particle data sets. For me, Voro++ is better suited than other libs, like e.g. qhull, for several reasons: it is easy to use, streamlined for 3D, and natively support periodic boundary conditions. The single drawback I found, there are no official binary releases for Windows. And that is why I started this nuget package.
The library’s source code is rather clean and compiles without problem in Visual Studio. So all I did, was compiling the static library for the four latest Visual C++ versions, and I put the nuget package together. My Visual Studio solution and project files are also publicly available on bitbucket: https://bitbucket.org/sgrottel_nuget/voro
The package contains the static library, the header files, some files from the documentation, and the command line tool built with MSVC 2015. If you only want the command line tool and don’t care for the lib, simply download the nuget package, unzip it (yes, nuget packages are basically zip files), and you’ll find the exe in the tools subdirectory. For the full documentation of the library, go the Chris’ website or the original source code package.
What I didn’t include in the nuget package are any samples. But compiling them for yourself is as simple as it could be:
1. start a new C++ console application in visual studio.
Be sure to deactivate precompiled headers and to make the project empty.
2. drag-drop-add any cc-example.
Just use any file from Chris’ source code package into the project.
3. Add the voroplusplus nuget package.
4. And you’re done! Compile it and run it by a push of a button.
We have projects working with WinForms GUIS. Different Developers work with different Computers, and these have different DPI settings. Every time the Project is opened on a system with different DPIs the WinForms get scaled, which is painfully bad.
Set in your Forms Designer: Font = MS Sans; 11px
In the Forms Ctor, after InitializeComponent, set: Font = SystemFonts.DefaultFont
Enable DPI-Awareness, either through a manifest or by API function SetProcessDPIAwareness
A modern Windows approach to High-DPI Displays
More and more Computers get equipped with High-DPI Displays, a trend I like very much. Pixels cannot be small enough. With modern Windows, however, GUI of older Applications get infamously blurry. This is due to Microsoft’s approach for backward-compatibility: applications will be rendered at their native DPI and scaled up to the system’s DPI. This way, the application does not need to know anything about DPI, but user controls will keep a decent size on any setting. While most people hate the blurriness of old GUIs on modern Windows, this approach does make a lot of sense:
Backward-Compatibility is instantly given, as nothing changes for the old Applications.
The users input experience is retained, as the GUI will keep its apparent size. (Just thing, if you’re old enough, of the original GUI of Winamp, where the buttons in the default skin were sometimes just a few Pixels in size.)
(last but not least) for new Applications, Developers hopefully get upset with the blurry look, that they actually invest some time, to do it right!
So, don’t claim it’s all Microsoft’s fault that the GUI of your applications look blurry. Truth is, you were just too lazy to do it right.
If you browse the internet in search for how to handle high-DPI settings with WinForms, you are bound to stumble upon a smart-ass telling you to switch to WPF. That person does have a point: WPF is designed to be a GUI for all resolutions. But, that person is also an idiot. Don’t bother discussing.
If you decided to use WinForms, then use WinForms. It is not deprecated, it is not legacy, it is not broken. There are good reasons to use WinForms. One, for example, would be the nice compatibility with Mono (Linux and MacOS). Another one would be compatibility with native GUI controls. Whatever your reason is, don’t let other people easily throw you off track.
If you’re not fixed on WinForms, but want to write a new Application for Windows, then have a look at WPF.
Why does Visual Studio Scale?
Normally Windows works at 96 DPI. That is, you need 96 pixels to fill up one inch of screen space. On a higher setting, let’s say 144 DPI, you need 144 pixels. So, either your GUI elements will look smaller, or your GUI elements must be larger to look the same. Modern graphical content is thus not described in pixels, but often in points (pt). Points are defined as 1/72 inch, that is in screen space, and not in pixels.
WinForms is not a modern GUI. All Elements are designed with pixels. However, higher DPI settings were present in Windows for a long time (accessibility feature). WinForms answers to this by having a mechanism to scale the whole GUI ‘manually’. If a scaling factor different from one is determined, all GUI elements, positions, sizes, etc., are multiplied by that factor, including the overall size of the window. By default, this scaling factor is determined comparing the Font settings of the form. Fonts are usually specified with a size in pt. Windows computes the font size in pixels based on the active DPI value. If WinForms now detects a mismatch between the pixel-based font sizes between design-time specifications and run-time evaluation, the form and all content is scaled. And this is exactly what happens in the Visual Studio Windows Forms designer.
Visual Studio does basically nothing at all. However, the font size evaluation is based on the system’s DPI setting. So on high-DPI systems, the font’s pixel size will be different from the stored design-time pixel size, and thus the whole form will be scaled accordingly. That is a good idea at run-time. I mean, that is the whole point of this mechanism. However, we are still at design time. The problem raises, because the Forms designer in Visual Studio actually runs the WinForms engine. As now all GUI elements change their sizes, the designer is informed (likely by the normal events) and adjusts all generated code to the new sizes and locations. This is, of course, ugly, painful and stupid, if you are going to continue the development on another machine with another, maybe, lower DPI setting.
Disable Scaling at Design-Time, Enable Scaling at Run-Time
What I am writing here is not a premium solution. It is the workaround I found for myself to work best.
The basic idea is to (manually) disable scaling at design time, and to (manually) enable scaling at run time.
I write scaling, but what we actually change is the Font!
Keep the Form’s AutoScaleMode = Font. That setting is correct and is not the problem at all. The problem is the automatically used font. It is the system’s default font, which specifies its size in pt. Again, a good idea at run time. What we change is the Font setting of the Form, to specify the size in pixels.
In the Designer, set the Font to: Microsoft Sans Serif; 11px
Windows default Font is Microsoft San Serif 8 pt. according to MSDN. Actually, it seems more like 8.25 pt. So this is 8.25/72 inch, which finally results in 8.25 * 96/72 = 11 pixel on a normal DPI system. That is why you set the font to this painfully small looking value. It is the right one! Now edit your GUI on all systems you have. Your Forms will not be scaled by Visual Studio any more. So, design time is fixed.
Now for the run time. That one is easy, too. All we need to do is to ‘reset’ the Form’s font to have its size specified in pt. again. The easiest way to do that is to reassign the system’s default font. Just set it in the constructor, right after InitializeComponent:
Font = SystemFonts.DefaultFont;
This, of course, only works if you are on a system where the system’s default font is as expected, and only if you do not change fonts for the controls inside your form. If you did change some control’s font, you specify the font with pixel size for design time and you update these at run time initialization to use pt.-based sizes again.
Scalable GUI Design
And that is that. If your application is already DPI aware, your forms will now scale nicely. That is, if you designed them correctly.
You should not mix docking-based and anchor-based design in the same form. That is bound to produce weird scaling issues.
You must use either, otherwise the controls will just randomly shift somewhere.
Be aware that the control might no longer fit into your Form, due to the maximum window size. Use flowing layout containers and auto scrollbars.
Enable DPI Awareness
All that, of course, only makes any sense if you enable DPI awareness for your application. There are basically two options:
Maybe, you know, that modern Windows can be even more complicated by per-monitor DPI settings. The idea is, that attached external screens have different sizes and resolutions, and should thus be handled with different DPIs. The good news is: this approach here works instantly with per-monitor DPI. When the form is dragged onto another monitor, the system automatically adjusts the font setting, as the font size is at run time specified in points. This automatically triggers a rescaling of the form. Wheee!
Each year at the renowned international conference for visualization, the IEEE VIS, the so called SciVis Contest takes place. This year, we, the staff of the Computer Graphics and Visualisation Group of the TU Dresden, together with colleagues from the Visualization Research Centre of the University of Stuttgart, have won the contest.
With the SciVis Contest the visualization community can confront themselves with challenging visual analysis tasks on real data scenarios. This year’s contest asked questions about large ensemble data sets of chemical processes of salt dissolution, namely the appearance and influence of viscous fingers. The entry by TU Dresden was deemed being the most wholesome and versatile solution, and thus gained the winning edge over its competitors.
When I read this comic on xkcd i started thinking. I enjoy reading xkcd. Few comics are bad, most are nice, and some are brilliant. And those are the ones I will now start reblogging here, as distributed archive. 😉
The reason, of course, is MegaMol, more precisely an upcoming addition to MegaMol enabling scripting of all internal management functions. After some thought, we opted for Lua as scripting language in our project. Building Lua is no big deal. But I also wanted the build process of MegaMol as a whole to be a simple as possible. On Windows this calls for nuget.
Of course, the nuget package already existed, but it was old. Instead of just starting another one, I contacted the original authors of the coapp team. They were happy to grant me access to the package, so that I could update to the new binaries. I will try my best to keep it up to date and to support many Visual Studio versions and settings.
Plugin B exports one module using the call exported by modul A.
Exporting Call Header
Usually, modules and calls are only exported via their meta data description classes as part of the implementation in “plugin_instance”. This meta data is sufficient for the MegaMol™ core to instantiate the module at runtime. However, these classes are normally not exported by the plugins.
If you want to use a class, a Call, in other plugins at compile time, you have to export the type. You need to place the corresponding header file in the public export folder. For a typical case, have a look at the demo project: “./a/include/interplugin_test_a/IplgDemoCall.h” I also recommend to add the header files to the filter “Public Header Files” in the Visual Studio Solution Explorer.
Additionally, you need to export the class using the corresponding API macro: e.g. “INTERPLUGIN_TEST_A_API”, which is defined in the plugin’s primary header file, e.g. “interplugin_test_a/interplugin_test_a.h”
Of course, you still need to export the meta data description for the call itself in the “plugin_instance” definition (cf. “interplugin_test_a.cpp” line 51).
Using Call in another Plugin
Now, to use the Call in another Plugin, that one basically needs to link against the exporting Plugin. Following the demo project, the exporting plugin is called A and the using plugin in named B.
First A is a library and a normal development dependency for B. For Visual Studio, I recommend using the “configure.win.pl” and “ExtLibs.props.input” similar to any other 3rd-party library. In the demo project, the access to the subdirectory of A is hard coded in the “ExtLibs.props.input”. Then, you can use this user macro in the project settings:
C/C++ > General > Additional Include Directories
Linker > General > Additional Library Directories
Linker > Input > Additional Dependencies
As you see, the linker only uses the built input library of the plugin, not the compiled plugin A itself.
Now you can find the public header file of the call exported by the plugin, cf. “./b/src/IplgValueInvertB.cpp” line 3. Plugin B uses this class like any class exported from the core. Nothing special is required.
For Linux you could introduce similar settings in the “CMakeLists.txt” file. I did not.
Since I install everything of MegaMol™ into a local user directory (using the install prefix settings in the build scripts) all parts of MegaMol™ are available at the same location. This includes the core, which the “CMakeLists.txt” file already searches for and Plugin A, which is thus accidentally found too. So the public include files, which were copied when Plugin A was “installed” are already available. Linux does not require shared objects to link against their dependencies. The runtime loader is expected to resolve all issues. Thus, for building on Linux no additional settings are required.
If you want to be able to work with plugins not locally installed, you should write a corresponding find script for the base plugin A and use “find_package” in the “CMakeLists.txt” of plugin B. For now, I don’t care.
Configuring MegaMol™ with both Plugins
Just add both plugins, as usual, to the MegaMol™ configuration file. Either explicitly (recommended) or using file globing. You should keep the dependencies in mind. So you should load plugin A before you load plugin B. But technically, it does not matter.
Both plugins, all plugins, are basically Dlls. So if you load plugin B first, the Dll is loaded with all its dependencies. These include the Dll plugin A. So plugin A is in memory the, but the meta data is not known to the core yet. If then the command for loading plugin A is executed, the OS runtime is asked to load the Dll plugin A. Since that Dll is already in memory, the load succeeds and the plugins meta data is received and added to the core factory constructs.
Beware of Cyclic Dependencies
Cyclic Dependencies should be avoided, as always. In theory, they could work, like Plugin A uses a class from Plugin B and the other way round at the same time. However, if you are going towards such a scenario, I strongly recommend to create a third Plugin holding the shared classes, e.g. Calls.
Runtime Behavior if Dependent Plugin is not found
The OS runtime errors when a Dll (Plugin) cannot be loaded are rather useless. (I am working on something better here, but it is not as easy as one would think.) Usually, it only tells you that the Dll could not be loaded. So keep in mind, if you developing your plugins that other plugins you depend on, not only need to be available at compile time, but also need to be installed in the same bin directory for runtime access.
Version Number Tests
All plugins check their version numbers of Core and Vislib with the loading core. This is to avoid inconstancies at runtime. Imagine you build the Core, then work on your Plugin. In this work you stumble upon a bug in the Vislib and fix that. Then your core and your plugin use different Vislibs and only this very version check tells you that this is a bad idea.
Now, use that scenario and replace Vislib with plugin A. Welcome to hell. There currently is not version check implemented for cross-plugin dependencies. (Most likely, there will be no such check before the infamous coming “Call Interface Redesign”.) You need to be careful!
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.