GDI+

This library provides the implementation of the WIN32 GDI+ API, as a Wrapper of the Low Level API via NanoVG. In order to use GDI+ on WebAssembly gauges, it is required to include the static WASM library, and in the project settings, please include the following information:

  • Additional include directories: Additional Include Directories += $(MSFS_SDK)WASM\include\gdiplus
  • Additional library directories: Additional Library Directories += $(MSFS_SDK)WASM\lib
  • Additional dependencies:
    • Additional Dependencies (RELEASE) += gdiplus.a
    • Additional Dependencies (DEBUG) += gdiplus_debug.a
  • In the source files using GDI+, include the GdiPlus.h header: #include <GdiPlus.h>

 

 

Differences With WIN32 GDI+

This is a re-implementation of the GDI+ API using the underlying Low-Level Graphic API provided by Microsoft Flight Simulator. Given constraints in the graphic back-end, some method signatures have been changed, and some functionality is currently unavailable. In addition, some low priority functionality has not yet been implemented (such as pen caps).

NOTE: These differences might be reduced in future releases of the SDK

 

The main differences that must be considered when using GDI+ for WASM are:

  • The creation of a GdiPlus::Graphics object requires a FScontext (instead of an HDC).
  • Some graphical elements need to be associated to a GdiPlus::Graphics. They should be initialized before being used, ideally on PANEL_SERVICE_POST_INSTALL.
  • Frames need to be explicitly started using GdiPlus::Graphics::StartFrame(), passing the resolution information provided by (sGaugeDrawData*)pData.
  • Frames need to be explicitly flushed using GdiPlus::Graphics::Flush().
  • Some graphical elements require to be associated with a graphical context (e.g: GdiPlus::Bitmap).
  • GdiPlus::Graphics (and other context-dependent objects) need to be destroyed before the graphical context is released, either before or during PANEL_SERVICE_PRE_KILL.

 

Below is an example snippet of code so you can get a better picture of what is going on:


GdiPlus::Graphics* gfx;
GdiPlus::Bitmap* bitmap;
extern "C"
    {
    MSFS_CALLBACK bool my_gauge_callback(FsContext fsctx, int service_id, void* pData)
        {
        switch (service_id)
            {
            case PANEL_SERVICE_POST_INSTALL:
                {
                      ...
            (1)     gfx = new GdiPlus::Graphics(fsctx);
            (2)     bitmap = new GdiPlus::Bitmap(gfx,...);
                      ...
                }
            case PANEL_SERVICE_PRE_DRAW:
                {
            (3)     sGaugeDrawData* p_draw_data = (sGaugeDrawData*)pData;
            (3)     float fSize = (float)min(p_draw_data->winWidth, p_draw_data->winHeight);
            (3)     float pxRatio = (float)p_draw_data->fbWidth / (float)p_draw_data->winWidth;
            (3)     gfx->StartFrame(p_draw_data->winWidth, p_draw_data->winHeight, pxRatio);
                      ...
            (4)     gfx->Flush();
                    ...
                }
            case PANEL_SERVICE_PRE_KILL:
                {   
                      ...
            (5)     delete (bitmap);
            (5)     delete (gfx);
                      ...
                }
            }
        }
    }
   
  

Status

All methods present in the GDI+ API are declared, providing support for compilation of projects for previous instances of Flight Simulator. As not all GDI+ functionality is yet supported, non-implemented methods will return GpStatus::NotImplemented. For more details about the implementation, please refer to Building The Library.

 

The functionality available in the previous versions of the GDI+ wrapper is supported in the new implementation. Those functions that are not present in the official GDI+ API are considered experimental, and they might be changed or removed in the future.

 

Missing Image Functionality

  • GdiPlus::Bitmap requires a graphical context on construction.
    GdiPlus::Graphics* gfx = new Graphics(fsctx);
          ...
    bitmap = new Bitmap(gfx,L"{path-to-file-in-vfs.png}"
  • GdiPlus::Bitmap can either be loaded from a file or manipulated per pixel, but not both.
  • GdiPlus::Image does not support draw-to-image.
  • GdiPlus::MetaFile is not supported.

 

Missing Drawing Functionality

  • GdiPlus::Pen only supports simple caps.
  • GdiPlus::Brush supports SolidBrush and HatchBrush; neither TextureBrush nor GradientBrush are supported at this moment.

 

Missing Text Functionality

  • Fonts can only be created by file name:
    font = new Font(L"{alias}", L"{./local-path/font-name}.ttf", {size-in-px}, {unused});
  • GdiPlus::Graphics::DrawString() is restricted to UTF8 strings (even when the method signature accepts WCHAR strings).
  • GdiPlus::Font provides minimal functionality, neither GdiPlus::FontFamily nor GdiPlus::FontCollection are supported at this moment.

 

 

Building The Library

The source files for the GDI+ library are also provided in $(MSFS_SDK)WASM\projects\gdiplus. The project can be included to the Visual Studio solution used to build WebAssembly gauges. Using this approach allows the navigation of symbols and their debug. Modifying and rebuilding this project will update the GDI+ contents present in $(MSFS_SDK)WASM\include and $(MSFS_SDK)WASM\lib. Note that the modifications to the GDI+ library will be overridden by future SDK installs.

 

Build Configuration using Preprocessor Definitions

Some debug options can be enabled by using preprocessor definitions:

  • DEBUG_CLIP_MASK: Displays the contour of clipping masks.
  • DEBUG_TEXT: Displays bounding boxes and pivot of text rectangles.
  • DEBUG_IMAGE_CONTOUR: Displays bounding boxes and clipping regions for images and patterns.
  • GDIFLAT_SAFE: Checks for valid parameters on each call to the FLAT API. This is safer, but slower and it can hide parameter issues. This definition is present by default on RELEASE builds, and not on DEBUG.

 

 

Extra Links

The following links are provided to give you extra context as well as additional tools when working with the WASM Module.