# Creating WASM Gauges {{< glossterm >}}wasm{{< /glossterm >}} (C/C++) gauges can be developed for Microsoft Flight Simulator 2024 with the **Microsoft Flight Simulator Platform Toolset.** Those gauges will draw in a bitmap which will replace a texture inside the aircraft.     ### MSFS 2024 vs MSFS 2020 The way WASM gauges are implemented has changed between MSFS 2020 and MSFS 2024, and even though the legacy methods still work, we **strongly** advise you to use the new MSFS 2024 way of working. Thanks to these changes, WASM gauges in Microsoft Flight Simulator 2024 benefit from better optimisations and a much clearer way to define them. These changes have been made to remove the burden of legacy code from Microsoft Flight Simulator X that no longer makes sense in the new engine architecture.   In Microsoft Flight Simulator 2020, all gauge functions - update and draw - were executed during the draw time. However, because the update function doesn't draw anything (and must not), it could be moved in Microsoft Flight Simulator 2024 to the actual update time. Thanks to that change, the new gauge system uses the entire frame while the old one used only a small part of it which has led to improved performance.   In Microsoft Flight Simulator 2020 and previously, gauge functions could be called before and after a specific timing: pre-update, post-update, pre-draw, post-draw, etc... This made some sense in FSX, but less-so in MSFS 2020 where some pre/post function were called sequentially, and now in MSFS 2024 it makes no sense at all. That is why new callbacks have been created to make the gauge system clearer. - New system : [Creating A New Gauge For Your Project](creating-wasm-gauges/#gauge_creation) - Old system (deprecated) : [Creating A New Gauge For Your Project - MSFS 2020](creating-wasm-gauges/#creating)     ### Creating A New Gauge For Your Project As explained in the [Creating A WASM Project](creating-a-wasm-project/) page, you first need to create a MSFS 2024 WASM Module. By doing that, you will get a new project with only the `module_init` and `module_deinit` functions.   To create a new gauge, right click on your project in the solution explorer and add a new file. In the selection page, choose "MSFS" and pick "Gauge".   After selecting the **MSFS WASM Module** template, you will be presented with the following basic project, which we'll be editing: ``` wasm MSFS_CALLBACK bool [MODULE_NAME]_gauge_init(FsContext ctx, sGaugeInstallData* pInstallData) { // This is called during initialization of the gauge // Width given in p_install_data->iSizeX // Height given in p_install_data->iSizeY NVGparams params; params.userPtr = ctx; params.edgeAntiAlias = true; NVGcontext* nvgCtx = nvgCreateInternal(¶ms); g_[MODULE_NAME]Vars.m_nvgCtx = nvgCtx; // do initialization // ... // return false if there is any error return true; // if successfully intialized } ``` - The `[MODULE_NAME]_gauge_init` is the initialisation function - the first function to be called in the gauge cycle - that allows you to initialise everything related to the gauge. - The `pInstallData` parameter points to a `sGaugeInstallData` structure: - The `iSizeX` member gives the width of the gauge bitmap. - The `iSizeY` member gives the height of the gauge bitmap. - The `strParameters` member gives the optional parameter string.   ``` wasm MSFS_CALLBACK bool [MODULE_NAME]_gauge_update(FsContext ctx, float dTime) { // This is called each frame // dTime is the time between the previous frame and this one // return false if there is any error return true; } ``` - The `[MODULE_NAME]_gauge_update` is the update function dedicated to this gauge. It will be called once per frame. **This function must not use any draw functions** because it will be called at a moment in which draw system in not ready. - The `dTime` parameter represents the time during the previous update and this one.   ``` wasm MSFS_CALLBACK bool [MODULE_NAME]_gauge_draw(FsContext ctx, sGaugeDrawData* pDrawData) { // This is called each frame, this is the only callback in which it is possible to draw // update visual layout float pxRatio = (float)p_draw_data->fbWidth / (float)pDrawData->winWidth; NVGcontext* nvgCtx = g_[MODULE_NAME]Vars.m_nvgCtx; nvgBeginFrame(nvgCtx, pDrawData->winWidth, pDrawData->winHeight, pxRatio); { // render // ... } nvgEndFrame(nvgCtx); // return false if there is any error return true; } ``` - The `[MODULE_NAME]_gauge_draw` is the draw function dedicated to this gauge. It will be called once per frame. All draw function calls must be made in the context of this function. - The `pDrawData` parameter points to a `sGaugeDrawData` structure: - The `mx` member gives the X-coordinate of the mouse in texture space. - The `my` member gives the Y-coordinate of the mouse in texture space. - The `t` member gives the absolute simulation time. - The `dt` member gives the time elapsed since last frame. - The `winWidth` member gives the width of the gauge bitmap. - The `winHeight` member gives the height of the gauge bitmap. - The `fbWidth` member gives the width of the gauge bitmap. - The `fbHeight` member gives the height of the gauge bitmap.   ``` wasm MSFS_CALLBACK bool [MODULE_NAME]_gauge_kill(FsContext ctx) { // This is called before the gauge is destroyed NVGcontext* nvgCtx = g_[MODULE_NAME]Vars.m_nvgCtx; nvgDeleteInternal(nvgCtx); // return false if there is any error return true; } ``` - The `[MODULE_NAME]_gauge_kill` is the de-initialisation function, last function to be called in the gauge cycle, that allow you to de-initialise everything related to the gauge.   ``` wasm MSFS_CALLBACK void [MODULE_NAME]_gauge_mouse_handler(FsContext ctx, float fX, float fY, int iFlags) { // This is called when the user click on the gauge, enum for iFlags are in "MSFS/Types/MSFS_EventsEnum.h" } ``` - The `[MODULE_NAME]_gauge_mouse_handler` is a mouse callback function. See [Handling Mouse Events](creating-wasm-gauges/#mouse_events), below.     ### Handling Mouse Events It may be that you also need your gauge to deal with the input from users, and in that case you will need to add in **mouse events**. Mouse events are forwarded to your gauge through a mouse callback that is defined as follows: ``` wasm extern "C" { MSFS_CALLBACK void _mouse_callback(float fX, float fY, unsigned int iFlags) { ... } } ```   The parameters in this callback are: - The `fX` parameter gives the X-coordinate of the mouse in texture space. - The `fY` parameter gives the Y-coordinate of the mouse in texture space. - The `iFlags` parameter is a combination of the various `MOUSE_*` flags defined in `gauges.h`. Supported flags are: - `MOUSE_MOVE`: the mouse cursor has moved. - `MOUSE_LEFTDRAG`: left button down. - `MOUSE_RIGHTDRAG`: right button down. - `MOUSE_MIDDLEDRAG`: middle button down. - `MOUSE_LEFTRELEASE`: left button up. - `MOUSE_RIGHTRELEASE`: right button up. - `MOUSE_MIDDLERELEASE`: middle button up. - `MOUSE_LEFTSINGLE`: left button click (sent after a down/up sequence). - `MOUSE_RIGHTSINGLE`: right button click (sent after a down/up sequence). - `MOUSE_MIDDLESINGLE`: middle button click (sent after a down/up sequence). - `MOUSE_LEFTDOUBLE`: left button click (sent after two consecutive clicks). - `MOUSE_MIDDLEDOUBLE`: middle button click (sent after two consecutive clicks). - `MOUSE_WHEEL_UP`: wheel moved up. - `MOUSE_WHEEL_DOWN`: wheel moved down.     ### Editing The WASM Module Project Now you've initialised the new WASM project and setup Visual Studio, you'll need to edit the source code to include the minimum header files - supplied by the SDK - to create the module. You can find all the available files that can be included from the following SDK location: ``` codeblock \WASM\include\MSFS ``` {{< image-center src="images/6_Programming/WASM/wasm_tutorial//msfs_h_location.png" alt="Location Of The MSFS.h File" >}}   These different API's are as follows:       ### Adding The Gauge To Your Aircraft Once you have created the gauge, you need to be able to add it to your aircraft and to test it. This means that you should already have created an aircraft package (as explained here: [Creating The Project](../../samples-tutorials/tutorials/aircraft-checklist/creating-the-project/)), and after building the {{< glossterm >}}wasm{{< /glossterm >}} module from Visual Studio, you will want to save it beside the [`panel.cfg`](../../content-configuration/cfg-files/panel.cfg/) file in the **PackageSources** directory, as shown in the following image taken from the [Gauge Aircraft Sample](../../samples-tutorials/samples/simobjects-aircraft/modularaircraft/gaugeaircraft/): {{< image-center src="images/6_Programming/WASM/wasm_tutorial//wasm_5_panellocation.png" alt="The Location For Saving The WASM Module" >}}   Since Microsoft Flight Simulator 2024, it is also possible to put your WASM file in a `wasm` folder (instead of the *panel* one). Thanks to that, the same WASM file can be use to handle WASM gauges and WASM systems at the same time. If a WASM system is implemented but the WASM file is located in the `panel` folder, **it will not be accessible**.   Once you have built the module and saved it to the appropriate location, you need to tell the aircraft to reference it. This is done in the [`panel.cfg`](../../content-configuration/cfg-files/panel.cfg/), under the `[VCockpitN]` header, something like this: ``` xml [VCockpit01] size_mm=1024,768 pixel_size=1024,768 texture=TEXTURE background_color=0,0,255 htmlgauge00=WasmInstrument/WasmInstrument.html?wasm_module=.wasm&wasm_gauge=, 0, 0, 1024, 768, ```   The important thing to note here is that *all* WASM modules will need a `[VCockpitN]` definition, and the path (defined by the `htmlgauge00` parameter) will always take the same prefixed format: ``` codeblock WasmInstrument/WasmInstrument.html?wasm_module= ```   When you have the file in the correct location, you can go ahead and build the package (as explained here: [Building A Package](../../devmode/editors/project-editor/the-project-editor/#building-a-package)). Once built, you will need to restart the flight to see the module in the simulation. Note that this is the case for every edition you make to the WASM code - afterwards it will need exported, built, and the flight restarted.     ### Creating A New Gauge For Your Project - MSFS 2020 The old system (which is now deprecated) works with a unique callback which will receive an enum telling the user when this callback is called and a pointer that must be cast accordingly.   ``` wasm extern "C" { MSFS_CALLBACK bool [MODULE_NAME]_gauge_callback(FsContext ctx, int service_id, void* pData) { switch (service_id) { // further code here ... } return false; } } ```  Check [Events Received By The Gauge Callback](creating-wasm-gauges/) for more information.     #### Events Received By The Gauge Callback Once the gauge has been loaded by Microsoft Flight Simulator 2020, the following events are sent to the callback function so they can be intercepted and acted on (if required):   - **`PANEL_SERVICE_PRE_INSTALL`**: sent before the gauge is installed. The `pData` parameter points to a `sGaugeInstallData` structure: - The `iSizeX` member gives the width of the gauge bitmap. - The `iSizeY` member gives the height of the gauge bitmap. - The `strParameters` member gives the optional parameter string. - **`PANEL_SERVICE_POST_INSTALL`**: sent after the gauge has been installed. The `pData` parameter points to a `sGaugePostInstallData` structure: - The `ctx` member is a pointer to the `FsContex`t used by the gauge (it is the same as the `ctx` parameter provided to the callback function). - **`PANEL_SERVICE_PRE_INITIALIZE`**: sent before the gauge is initialized. The `pData` parameter is null. - **`PANEL_SERVICE_POST_INITIALIZE`**: sent after the gauge has been initialized. The `pData` parameter is null. - **`PANEL_SERVICE_PRE_UPDATE`**: sent before the gauge is updated. The `pData` parameter is null. - **`PANEL_SERVICE_POST_UPDATE`**: sent after the gauge has been updated. The `pData` parameter is null. - **`PANEL_SERVICE_PRE_DRAW`**: sent before the gauge is drawn. The `pData` parameter points to a `sGaugeDrawData` structure: - The `mx` member gives the X-coordinate of the mouse in texture space. - The `my` member gives the Y-coordinate of the mouse in texture space. - The `t` member gives the absolute simulation time. - The `dt` member gives the time elapsed since last frame. - The `winWidth` member gives the width of the gauge bitmap. - The `winHeight` member gives the height of the gauge bitmap. - The `fbWidth` member gives the width of the gauge bitmap. - The `fbHeight` member gives the height of the gauge bitmap. - **`PANEL_SERVICE_POST_DRAW`**: sent after the gauge has been drawn. The `pData` parameter points to a `sGaugeDrawData` structure (see above). - **`PANEL_SERVICE_PRE_KILL`**: sent before the gauge is deleted. The `pData` parameter is null. - **`PANEL_SERVICE_POST_KILL`**: sent after the gauge has been deleted. The `pData` parameter is null.