Code Sample Type: XPLM200 SDK

Register Custom DataRef in Dataref Editor

// Custom Commands

 // Register Custom DataRefs in DataRefEditor.  
 //
 // This plugin adds a few lines of code and a flight loop callback to the Custom Commands Control 
 // Custom DataRef example.  The flight loop callback sends the message to DataRefEditor to 
 // register your custom dataref in DataRefEditor.  Returning 0 from the flight loop sends the message
 // only once.  A similar flight loop is required for each of you custom datarefs.  
 // 
 // Content added by BlueSideUpBob.
 
 #define XPLM200 = 1;  // This example requires SDK2.0
 
 #include "XPLMPlugin.h"
 #include "XPLMDisplay.h"
 #include "XPLMGraphics.h"
 #include "XPLMProcessing.h"
 #include "XPLMDataAccess.h"
 #include "XPLMMenus.h"
 #include "XPLMUtilities.h"
 #include "XPWidgets.h"
 #include "XPStandardWidgets.h"
 #include "XPLMScenery.h"
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #define MSG_ADD_DATAREF 0x01000000           //  Add dataref to DRE message
 
 XPLMDataRef gCounterDataRef = NULL;          //  Our custom dataref
 
 int     gCounterValue;                       //  Our custom dataref's value  
 float   RegCounterDataRefInDRE(float elapsedMe, float elapsedSim, int counter, void * refcon);  //  Declare callback to register dataref
 int     GetCounterDataRefCB(void* inRefcon);
 void    SetCounterDataRefCB(void* inRefcon, int outValue);
 
 XPLMCommandRef CounterUpCommand = NULL;	//  Our two custom commands
 XPLMCommandRef CounterDownCommand = NULL;
 
 int    CounterUpCommandHandler(XPLMCommandRef       inCommand,          //  Our two custom command handlers
                                XPLMCommandPhase     inPhase,
                                void *               inRefcon);
 
 int    CounterDownCommandHandler(XPLMCommandRef     inCommand,
                                 XPLMCommandPhase    inPhase,
                                 void *              inRefcon);
 
 PLUGIN_API int XPluginStart(
         char *        outName,
         char *        outSig,
         char *        outDesc)
 {
 
 // Plugin Info
     strcpy(outName, "CustomCommandsAndDataRefs");
     strcpy(outSig, "BlueSideUpBob.Example.CustomCommandsAndDataRef");
     strcpy(outDesc, "This example illustrates creating and using custom commands to control a custom DataRef.");
 
 //  Create our custom integer dataref
 gCounterDataRef = XPLMRegisterDataAccessor("BSUB/CounterDataRef",
                                             xplmType_Int,                                  // The types we support
                                             1,                                             // Writable
                                             GetCounterDataRefCB, SetCounterDataRefCB,      // Integer accessors
                                             NULL, NULL,                                    // Float accessors
                                             NULL, NULL,                                    // Doubles accessors
                                             NULL, NULL,                                    // Int array accessors
                                             NULL, NULL,                                    // Float array accessors
                                             NULL, NULL,                                    // Raw data accessors
                                             NULL, NULL);                                   // Refcons not used
 
 
 // Find and intialize our Counter dataref
 gCounterDataRef = XPLMFindDataRef ("BSUB/CounterDataRef");
 XPLMSetDatai(gCounterDataRef, 0);
 
 XPLMRegisterFlightLoopCallback(RegCounterDataRefInDRE, 1, NULL);   // This FLCB will register our custom dataref in DRE
 
 // Create our commands; these will increment and decrement our custom dataref.
 CounterUpCommand = XPLMCreateCommand("BSUB/CounterUpCommand", "Counter Up");
 CounterDownCommand = XPLMCreateCommand("BSUB/CounterDownCommand", "Counter Down");
 
 // Register our custom commands
 XPLMRegisterCommandHandler(CounterUpCommand,           // in Command name
                            CounterUpCommandHandler,    // in Handler
                            1,                          // Receive input before plugin windows.
                            (void *) 0);                // inRefcon.
 
 XPLMRegisterCommandHandler(CounterDownCommand,
                            CounterDownCommandHandler,
                            1,
                            (void *) 0);
 
 return 1;
 }
 
  
 PLUGIN_API void     XPluginStop(void)
 { 
 XPLMUnregisterDataAccessor(gCounterDataRef);
 XPLMUnregisterCommandHandler(CounterUpCommand, CounterUpCommandHandler, 0, 0);
 XPLMUnregisterCommandHandler(CounterDownCommand, CounterDownCommandHandler, 0, 0);
 XPLMUnregisterFlightLoopCallback(RegCounterDataRefInDRE, NULL);	 //  Don't forget to unload this callback.  
 }
  
 PLUGIN_API void XPluginDisable(void)
 {
 }
 
 PLUGIN_API int XPluginEnable(void)
 {
     return 1;
 }
 
 PLUGIN_API void XPluginReceiveMessage(XPLMPluginID    inFromWho,
                                      long             inMessage,
                                      void *           inParam)
 {
 }
 
 int     GetCounterDataRefCB(void* inRefcon)
 {
     return gCounterValue;
 }
 
 void	SetCounterDataRefCB(void* inRefcon, int inValue)
 {
      gCounterValue = inValue;
 }
 
 int    CounterUpCommandHandler(XPLMCommandRef       inCommand,
                                XPLMCommandPhase     inPhase,
                                void *               inRefcon)
 {
 //  If inPhase == 0 the command is executed once on button down.
 if (inPhase == 0)
     {
      gCounterValue++;
      if(gCounterValue > 10) {gCounterValue = 10;}
     }
 // Return 1 to pass the command to plugin windows and X-Plane.
 // Returning 0 disables further processing by X-Plane.
  
 return 0;
 }
 
 int    CounterDownCommandHandler(XPLMCommandRef       inCommand,
                         XPLMCommandPhase     inPhase,
                         void *               inRefcon)
 {
     if (inPhase == 1)
     {
           gCounterValue--;
           if(gCounterValue < -10) {gCounterValue = -10;}
     }
 
 return 0;
 }
  
 //  This single shot FLCB registers our custom dataref in DRE
 float RegCounterDataRefInDRE(float elapsedMe, float elapsedSim, int counter, void * refcon)
 {
     XPLMPluginID PluginID = XPLMFindPluginBySignature("xplanesdk.examples.DataRefEditor");
     if (PluginID != XPLM_NO_PLUGIN_ID)
     {
          XPLMSendMessageToPlugin(PluginID, MSG_ADD_DATAREF, (void*)"BSUB/CounterDataRef");   
     }
 
     return 0;  // Flight loop is called only once!  
 }
1 Comment

Draw Terrain Object

// *************************************************
// DRAW TERRAIN OBJECT
//
// This example illustrates drawing a terrain object that moves in relation to the aircraft.  In this case 
// the object is located directly forward of the cockpit.  
// 
// For this example to work it is necessary to create an object in the aircraft folder.  Example:
// "Aircraft/General Aviation/FP404/objects/TestObject.obj".  See line 143.
//
// To turn the object on and off it is nececssary to place generic triggers on the panel of your aircraft keyed 
// to the command: BSUB/ShowObject/TestObject and BSUB/HideObject/TestObject.  
//
// Blue Side Up, 
// Bob.  
//
// Bob@RogerThat.ca
// 
// *************************************************
 
#include "XPLMPlugin.h"
#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"
#include "XPLMUtilities.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include "XPLMScenery.h"
#include 
#include 
#include 
#include 

char gBob_debstr[128];

XPLMDataRef  gHeadingDataRef = NULL;
XPLMDataRef  gPitchDataRef = NULL;
XPLMDataRef  gRollDataRef = NULL;
XPLMDataRef  CofG_refx = NULL;
XPLMDataRef  CofG_refy = NULL;
XPLMDataRef  CofG_refz = NULL;

XPLMCommandRef ShowObjectCommand = NULL;
XPLMCommandRef HideObjectCommand = NULL;

int	ShowObjectCommandHandler(XPLMCommandRef   inCommand,    
                          XPLMCommandPhase      inPhase,    
                          void *                inRefcon);

int	HideObjectCommandHandler(XPLMCommandRef   inCommand,    
                          XPLMCommandPhase      inPhase,    
                          void *                inRefcon);


// Used by the Draw Objects test
XPLMObjectRef     gTestObject=NULL;


const float Pi = 3.14159265358979;
const float RadToDeg = 180.0 / Pi;
const float DegToRad = 1.0 / RadToDeg;


// Prototype for Draw Object tests
int     DrawTestObject(XPLMDrawingPhase     inPhase,    
                      int                  inIsBefore,    
                      void *               inRefcon);

PLUGIN_API int XPluginStart(
                            char *     outName,
                            char *     outSig,
                            char *     outDesc)
{
    // Plugin Info 
    strcpy(outName, "DrawTerrainObject");
    strcpy(outSig, "BlueSideUpBob.Example.DrawTerrainObject");
    strcpy(outDesc, "Draw, hide, and show a terrain object that moves along with aircraft.");

    // Create the test commands; these will Show/Hide the test object.
    ShowObjectCommand = XPLMCreateCommand("BSUB/ShowObject/TestObject", "Show TestObject");
    HideObjectCommand = XPLMCreateCommand("BSUB/HideObject/TestObject", "Hide TestObject");

    // Register our custom commands
    XPLMRegisterCommandHandler(ShowObjectCommand,          // in Command name
                           ShowObjectCommandHandler,       // in Handler
                           1,                              // Receive input before plugin windows.
                           (void *) 0);                    // inRefcon. 

    XPLMRegisterCommandHandler(HideObjectCommand,          // in Command name
                           HideObjectCommandHandler,       // in Handler
                           1,                              // Receive input before plugin windows.
                           (void *) 0);                    // inRefcon. 

    // Get the aicraft position
    CofG_refx = XPLMFindDataRef("sim/flightmodel/position/local_x");
    CofG_refy = XPLMFindDataRef("sim/flightmodel/position/local_y");
    CofG_refz = XPLMFindDataRef("sim/flightmodel/position/local_z");

    gHeadingDataRef = XPLMFindDataRef ("sim/flightmodel/position/psi");
    gRollDataRef = XPLMFindDataRef ("sim/flightmodel/position/phi");
    gPitchDataRef = XPLMFindDataRef ("sim/flightmodel/position/theta");

    // This used to draw the test object.
    XPLMRegisterDrawCallback( DrawTestObject, xplm_Phase_Objects, 0, 0 );
    return 1;
}


PLUGIN_API void	XPluginStop(void)
{
    XPLMUnregisterCommandHandler(ShowObjectCommand, ShowObjectCommandHandler, 0, 0);	
    XPLMUnregisterCommandHandler(HideObjectCommand, HideObjectCommandHandler, 0, 0);		
}


PLUGIN_API void XPluginDisable(void)
{
}


PLUGIN_API int XPluginEnable(void)
{
    return 1;
}


PLUGIN_API void XPluginReceiveMessage(
                                      XPLMPluginID   inFromWho,
                                      long           inMessage,
                                      void *         inParam)
{
}



int	ShowObjectCommandHandler( XPLMCommandRef     inCommand,    
                                XPLMCommandPhase   inPhase,    
                                void *             inRefcon)
{
    if (inPhase == 0)
       {	
             gTestObject = XPLMLoadObject("Aircraft/General Aviation/FP404Master/objects/TestObject.obj");
             if (gTestObject == NULL) 	
                {
                     sprintf(gBob_debstr,"Test Object not found, inPhase %d \n", inPhase);
                     XPLMDebugString(gBob_debstr);
                }
       }

    // Return 1 to pass the command to plugin windows and X-Plane.  
    // Returning 0 disables further processing by X-Plane.	 
    // In this case we might return 0 or 1 because X-Plane does not duplicate our command. 
    return 0;
}

int	HideObjectCommandHandler(  XPLMCommandRef     inCommand,    
                                 XPLMCommandPhase    inPhase,    
                                 void *              inRefcon)

{
       if (inPhase == 0)
       {
            // Unload the imported object
            XPLMUnloadObject(gTestObject);
       }

   return 0;
}


// Function for Draw Object tests
int	DrawTestObject( XPLMDrawingPhase inPhase,    
                      int              inIsBefore,    
                      void *           inRefcon)
{	 
    static float LongitudinalOffset = -20.0;
   static float VerticalOffset = 2.0;
   float AircraftHeading;

    // Draw the imported object.  Only do this if we have everything we need.
    if (gTestObject &amp;&amp; CofG_refx &amp;&amp; CofG_refy &amp;&amp; CofG_refz)
    //Locate the test object by its heading.
    { 
           AircraftHeading = XPLMGetDataf(gHeadingDataRef);
 					
            if (AircraftHeading &lt;= 90)
            {
                XPLMDrawInfo_t	locations[1] = { 0 };
                locations[0].structSize = sizeof(XPLMDrawInfo_t);
                locations[0].x = XPLMGetDatad(CofG_refx) - LongitudinalOffset * sin (AircraftHeading * DegToRad);
                locations[0].y = XPLMGetDatad(CofG_refy) + VerticalOffset;
                locations[0].z = XPLMGetDatad(CofG_refz) + LongitudinalOffset * cos (AircraftHeading * DegToRad);
                locations[0].pitch = XPLMGetDataf(gPitchDataRef);
                locations[0].heading = AircraftHeading;
                locations[0].roll = XPLMGetDataf(gRollDataRef);
                // Draw the object 
                XPLMDrawObjects(gTestObject, 1, locations, 0, 0);
 
               return 1;
           }
 
          if (AircraftHeading &lt;= 180)
           {
                XPLMDrawInfo_t	locations[1] = { 0 };
                locations[0].structSize = sizeof(XPLMDrawInfo_t);
                locations[0].x = XPLMGetDatad(CofG_refx) - LongitudinalOffset * sin ((180 - AircraftHeading) * DegToRad);
                locations[0].y = XPLMGetDatad(CofG_refy) + VerticalOffset;
                locations[0].z = XPLMGetDatad(CofG_refz) - LongitudinalOffset * cos ((180 - AircraftHeading) * DegToRad);
                locations[0].pitch = XPLMGetDataf(gPitchDataRef);
                locations[0].heading = AircraftHeading;
                locations[0].roll = XPLMGetDataf(gRollDataRef);
                // Draw the object 
               XPLMDrawObjects(gTestObject, 1, locations, 0, 0);
 
               return 1;
            }

           if (AircraftHeading &lt;= 270) 
           {
                XPLMDrawInfo_t	locations[1] = { 0 };
                locations[0].structSize = sizeof(XPLMDrawInfo_t);
                locations[0].x = XPLMGetDatad(CofG_refx) + LongitudinalOffset * cos ((270 - AircraftHeading) * DegToRad);
                locations[0].y = XPLMGetDatad(CofG_refy) + VerticalOffset;
                locations[0].z = XPLMGetDatad(CofG_refz) - LongitudinalOffset * sin ((270 - AircraftHeading) * DegToRad);
                locations[0].pitch = XPLMGetDataf(gPitchDataRef);
                locations[0].heading = AircraftHeading;
                locations[0].roll = XPLMGetDataf(gRollDataRef);
                // Draw the object 
               XPLMDrawObjects(gTestObject, 1, locations, 0, 0);
 
               return 1;
           }

          if (AircraftHeading &lt;= 360) 
          {
                XPLMDrawInfo_t	locations[1] = { 0 };
                locations[0].structSize = sizeof(XPLMDrawInfo_t);
                locations[0].x = XPLMGetDatad(CofG_refx) + LongitudinalOffset * sin ((360 - AircraftHeading) * DegToRad);
                locations[0].y = XPLMGetDatad(CofG_refy) + VerticalOffset;
                locations[0].z = XPLMGetDatad(CofG_refz) + LongitudinalOffset * cos ((360 - AircraftHeading) * DegToRad);
                locations[0].pitch = XPLMGetDataf(gPitchDataRef);
                locations[0].heading = AircraftHeading;
                locations[0].roll = XPLMGetDataf(gRollDataRef);
                // Draw the object 
               XPLMDrawObjects(gTestObject, 1, locations, 0, 0);
 
               return 1;
            }
    }

    return 1;
}
4 Comments

Custom Manipulator Controlling X-Plane

// Custom Commands

 //  ***********************************
 //
 //  MANIPULATOR CODE EXAMPLE
 //
 //  This example program illustrates control of X-Plane DataRefs using custom manipulators.
 //  Pumping the flap lever manipulator will lower the flaps a fractional amount.  Raising 
 //  the flap selector manipulator will change the direction of flap movement.  
 //	
 //  For this example to work it is necessary to use AC3D to create two handle animations in  
 //  the aircraft cockpit using the custom datarefs BSUB/Aircraft/FlapPumpPosition and  
 //  BSUB/Aircraft/FlapSelectorPosition for the rotations.  Both handles must be identified  
 //  as axis manipulators with 0 to 1 limits and grabber hand cursor.  
 //
 //  For clarity this code has not been optimized.  
 //
 //  Blue side up,
 //  Bob
 //	
 //  Bob@RogerThat.ca
 //
 //  ***********************************
 
 
 #define XPLM200 = 1;
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include "XPLMDataAccess.h"
 #include "XPLMPlugin.h"
 #include "XPLMProcessing.h"
 
 #define MSG_ADD_DATAREF 0x01000000
 
 XPLMDataRef FlapRatioDataRef = NULL;                 // Existing dataref
 
 XPLMDataRef FlapPumpPositionDataRef = NULL;          // Custom dataref 
 XPLMDataRef FlapSelectorPositionDataRef = NULL;      // Custom dataref
 
 
 float	GetFlapPumpPositionDRCB(void* inRefcon);
 void	SetFlapPumpPositionDRCB(void* inRefcon, float outValue);
 
 float	GetFlapSelectorPositionDRCB(void* inRefcon);
 void	SetFlapSelectorPositionDRCB(void* inRefcon, float outValue);
 
 float	FlapPumpPositionFLCB(float elapsedMe, float elapsedSim, int counter, void * refcon);
 
 float FlapPumpPosition = 0;
 float FlapSelectorPosition = 1;          // Flap selector lever is down position at startup
 float FlapSelectorDirectionFlag = 1;     // Flap lever will pump flaps downwards at startup
 
 PLUGIN_API int XPluginStart(
                                            char *          outName,
                                            char *          outSig,
                                            char *          outDesc)
 {
          strcpy(outName, "Flap Manipulator Example");
          strcpy(outSig, "BlueSideUpBob.Flap Manipulator Example");
          strcpy(outDesc, "Manipulating flap selector and flap pump levers raise and lower flaps.");
 
 // CREATE DATAREFS, FIND DATAREFS FOR FLAP LEVER
 
 FlapPumpPositionDataRef = XPLMRegisterDataAccessor(
 
     "BSUB/Aircraft/FlapPumpPosition",
     xplmType_Float,          // The types we support 
     1,                       // Writable 
     NULL, NULL,              // Integer accessors  
     GetFlapPumpPositionDRCB, SetFlapPumpPositionDRCB,     // Float accessors 
     NULL, NULL,              // Doubles accessors 
     NULL, NULL,              // Int array accessors 
     NULL, NULL,              // Float array accessors 
     NULL, NULL,              // Raw data accessors 
     NULL, NULL);             // Refcons not used 
 
 FlapSelectorPositionDataRef = XPLMRegisterDataAccessor(
 
     "BSUB/Aircraft/FlapSelectorPosition",
     xplmType_Float,
     1,
     NULL, NULL,
     GetFlapSelectorPositionDRCB, SetFlapSelectorPositionDRCB,
     NULL, NULL,
     NULL, NULL,
     NULL, NULL,
     NULL, NULL,
     NULL, NULL);
 
 FlapPumpPositionDataRef = XPLMFindDataRef ("BSUB/Aircraft/FlapPumpPosition");
 FlapSelectorPositionDataRef = XPLMFindDataRef ("BSUB/Aircraft/FlapSelectorPosition");
 FlapRatioDataRef = XPLMFindDataRef("sim/cockpit2/controls/flap_ratio");
 
 XPLMSetDataf(FlapPumpPositionDataRef, 0);
 XPLMSetDataf(FlapSelectorPositionDataRef, 0);
 
 XPLMRegisterFlightLoopCallback(FlapPumpPositionFLCB, 0.0, NULL);
 XPLMSetFlightLoopCallbackInterval(FlapPumpPositionFLCB, 0.01, 1, NULL);	
 
 return 1;	
 }
 
 
 PLUGIN_API void	XPluginStop(void)
 {	
     XPLMUnregisterDataAccessor(FlapPumpPositionDataRef);
     XPLMUnregisterDataAccessor(FlapSelectorPositionDataRef);
     XPLMUnregisterFlightLoopCallback(FlapPumpPositionFLCB, NULL);				
 }
 
 
 PLUGIN_API int XPluginEnable(void)
 {
     return 1;
 }
 
 
 PLUGIN_API void XPluginDisable(void)
 {
 
 }
 
 
 
 PLUGIN_API void XPluginReceiveMessage(
                 XPLMPluginID	inFromWho,
                 long			inMessage,
                 void *			inParam)
 {
 }
 
 
 
 float	GetFlapPumpPositionDRCB(void* inRefcon)
 {
     return FlapPumpPosition;
 }
 
 
 void	SetFlapPumpPositionDRCB(void* inRefcon, float inValue)
 {
     FlapPumpPosition = inValue;
 }
 
 
 float	GetFlapSelectorPositionDRCB(void* inRefcon)
 {
     return FlapSelectorPosition;
 }
 
 
 void	SetFlapSelectorPositionDRCB(void* inRefcon, float inValue)
 {
     FlapSelectorPosition = inValue;
 }
 
 
 float  FlapPumpPositionFLCB(
                              float                inElapsedSinceLastCall,    
                              float                inElapsedTimeSinceLastFlightLoop,    
                              int                  inCounter,    
                              void *               inRefcon)
 {	
     float CurrentPumpPosition;
     static float FlapPumpLastPosition = 0; 
     float DeltaPumpPosition; 
     static float FlapDeflection = 0;
     int FlapSelectorDirection;
 
     CurrentPumpPosition = XPLMGetDataf(FlapPumpPositionDataRef);           // Where is handle now? 
     DeltaPumpPosition = CurrentPumpPosition - FlapPumpLastPosition;        // Has handle moved? 
     if (DeltaPumpPosition == 0) {return 0.1;}                              // No.  Check again later.  
 
     FlapPumpLastPosition = CurrentPumpPosition;                            //  SetUp for next cycle.  
 
     if (DeltaPumpPosition < 0) {DeltaPumpPosition = - DeltaPumpPosition;}  // Allows pumping on push and pull strokes.
 
     FlapSelectorPosition = XPLMGetDataf(FlapSelectorPositionDataRef);      // Where is the flap selector handle now? 
     if(FlapSelectorPosition > 0.9) {FlapSelectorDirection = 1;}            // If flap selector is down lower flaps.  
     if(FlapSelectorPosition < 0.1) {FlapSelectorDirection = 0;}            // If flap selector is up raise flaps.
 
     if(FlapSelectorDirection == 1)                                         // Move flaps down 1/10 of flap lever amount
     {
          FlapDeflection = XPLMGetDataf(FlapRatioDataRef) + DeltaPumpPosition * 0.1;
          if (FlapDeflection > 1){FlapDeflection = 1;}                      // Limit flap ratio between 0 and 1.  
          XPLMSetDataf(FlapRatioDataRef, FlapDeflection);                   // Set flaps a proportional amount. 
     } 
 
     if(FlapSelectorDirection == 0)                                         //  Move flaps up
     {
          FlapDeflection = XPLMGetDataf(FlapRatioDataRef) - DeltaPumpPosition * 0.1;	
          if (FlapDeflection < 0){FlapDeflection = 0;}
          XPLMSetDataf(FlapRatioDataRef, FlapDeflection);
     }
 
 return 0.1;
 }
1 Comment

Custom Command with Custom DataRef

// Custom Commands
 //
 // Custom Commands Control Custom DataRef
 //
 // This example program creates a custom integer dataref, BSUB/CounterDataRef, and two custom 
 // commands, BSUB/CounterUpCommand and BSUB/CounterDownCommand.  The custom commands 
 // are used to increment and decriment the custom dataref.  The custom dataref can be used to drive an 
 // generic instrument display, animation, etc.  
 //
 // After successfully creating your plugin you will need to use PlaneMaker to create two generic 
 // triggers, keyed to your custom commands on your aircraft panel.  You will also need to place a generic 
 // counter such as an LED display on your aircraft panel.  
 //
 // Content added by BlueSideUpBob.
 
#ifndef XPLM200
  #error This example requires the v2.0 SDK or newer
#endif
 
 #include "XPLMPlugin.h"
 #include "XPLMDisplay.h"
 #include "XPLMGraphics.h"
 #include "XPLMProcessing.h"
 #include "XPLMDataAccess.h"
 #include "XPLMMenus.h"
 #include "XPLMUtilities.h"
 #include "XPWidgets.h"
 #include "XPStandardWidgets.h"
 #include "XPLMScenery.h"
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 
 XPLMDataRef gCounterDataRef = NULL;          //  Our custom dataref
 
 int     gCounterValue;                       //  Our custom dataref's value  
 int     GetCounterDataRefCB(void* inRefcon);
 void    SetCounterDataRefCB(void* inRefcon, int outValue);
 
 XPLMCommandRef CounterUpCommand = NULL;	//  Our two custom commands
 XPLMCommandRef CounterDownCommand = NULL;
 
 int    CounterUpCommandHandler(XPLMCommandRef       inCommand,          //  Our two custom command handlers
                                XPLMCommandPhase     inPhase,
                                void *               inRefcon);
 
 int    CounterDownCommandHandler(XPLMCommandRef     inCommand,
                                 XPLMCommandPhase    inPhase,
                                 void *              inRefcon);
 
 PLUGIN_API int XPluginStart(
         char *        outName,
         char *        outSig,
         char *        outDesc)
 {
 
 // Plugin Info
     strcpy(outName, "CustomCommandsAndDataRefs");
     strcpy(outSig, "BlueSideUpBob.Example.CustomCommandsAndDataRef");
     strcpy(outDesc, "This example illustrates creating and using custom commands to control a custom DataRef.");
 
 //  Create our custom integer dataref
 gCounterDataRef = XPLMRegisterDataAccessor("BSUB/CounterDataRef",
                                             xplmType_Int,                                  // The types we support
                                             1,                                                   // Writable
                                             GetCounterDataRefCB, SetCounterDataRefCB,      // Integer accessors
                                             NULL, NULL,                                    // Float accessors
                                             NULL, NULL,                                    // Doubles accessors
                                             NULL, NULL,                                    // Int array accessors
                                             NULL, NULL,                                    // Float array accessors
                                             NULL, NULL,                                    // Raw data accessors
                                             NULL, NULL);                                   // Refcons not used
 
 
 // Find and intialize our Counter dataref
 gCounterDataRef = XPLMFindDataRef ("BSUB/CounterDataRef");
 XPLMSetDatai(gCounterDataRef, 0);
 
 
 // Create our commands; these will increment and decrement our custom dataref.
 CounterUpCommand = XPLMCreateCommand("BSUB/CounterUpCommand", "Counter Up");
 CounterDownCommand = XPLMCreateCommand("BSUB/CounterDownCommand", "Counter Down");
 
 // Register our custom commands
 XPLMRegisterCommandHandler(CounterUpCommand,           // in Command name
                            CounterUpCommandHandler,    // in Handler
                            1,                          // Receive input before plugin windows.
                            (void *) 0);                // inRefcon.
 
 XPLMRegisterCommandHandler(CounterDownCommand,
                            CounterDownCommandHandler,
                            1,
                            (void *) 0);
 
 return 1;
 }
 
  
 PLUGIN_API void     XPluginStop(void)
 { 
 XPLMUnregisterDataAccessor(gCounterDataRef);
 XPLMUnregisterCommandHandler(CounterUpCommand, CounterUpCommandHandler, 0, 0);
 XPLMUnregisterCommandHandler(CounterDownCommand, CounterDownCommandHandler, 0, 0);
 }
  
 PLUGIN_API void XPluginDisable(void)
 {
 }
 
 PLUGIN_API int XPluginEnable(void)
 {
     return 1;
 }
 
 PLUGIN_API void XPluginReceiveMessage(XPLMPluginID    inFromWho,
                                      long             inMessage,
                                      void *           inParam)
 {
 }
 
 int     GetCounterDataRefCB(void* inRefcon)
 {
     return gCounterValue;
 }
 
 void	SetCounterDataRefCB(void* inRefcon, int inValue)
 {
      gCounterValue = inValue;
 }
 
 int    CounterUpCommandHandler(XPLMCommandRef       inCommand,
                                XPLMCommandPhase     inPhase,
                                void *               inRefcon)
 {
 //  If inPhase == 0 the command is executed once on button down.
 if (inPhase == 0)
     {
      gCounterValue++;
      if(gCounterValue > 10) {gCounterValue = 10;}
     }
 // Return 1 to pass the command to plugin windows and X-Plane.
 // Returning 0 disables further processing by X-Plane.
  
 return 0;
 }
 
 int    CounterDownCommandHandler(XPLMCommandRef       inCommand,
                         XPLMCommandPhase     inPhase,
                         void *               inRefcon)
 {
 //  If inPhase == 1 the command is executed continuously.
      if (inPhase == 1)
    {
           gCounterValue--;
           if(gCounterValue < -10) {gCounterValue = -10;}
     }
 
 return 0;
 }
3 Comments

Custom Command

// Custom Commands
//
// This example program illustrates creating a custom command.  In this case clicking a generic trigger on
// your aircraft panel writes to the DataRef controlling the pilots head position either continuously or one
// knotch at a time. We could use the existing position command: sim/view/move_right, however for illustrative
// purposes, this example uses a custom command:  BSUB/ViewPoint/MoveRight
//
// For this example to work it is necessary to create a generic trigger on the panel of your aircraft keyed
// to the command: BSUB/ViewPoint/MoveRight.
//
// Content added by BlueSideUpBob.
//

#include "XPLMPlugin.h"
#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"
#include "XPLMUtilities.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include "XPLMScenery.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

XPLMDataRef gHeadPositionXDataRef = NULL;

XPLMCommandRef MyCommand = NULL;

int    MyCommandHandler(XPLMCommandRef        inCommand,
					 XPLMCommandPhase      inPhase,
					 void *                inRefcon);

PLUGIN_API int XPluginStart(
					 char *        outName,
					 char *        outSig,
					 char *        outDesc)
{
	// Plugin Info
	strcpy(outName, "CommandControl");
	strcpy(outSig, "BlueSideUpBob.Example.CommandControl");
	strcpy(outDesc, "This example illustrates creating and sending a custom command to X-Plane using a generic trigger.");

	// Create the test command, this will move the pilots point of view 10 cm to the right.
	MyCommand = XPLMCreateCommand("BSUB/ViewPoint/MoveRight", "Move Right");

	// Register our custom command
	XPLMRegisterCommandHandler(MyCommand,              // in Command name
							 MyCommandHandler,       // in Handler
							 1,                      // Receive input before plugin windows.
							 (void *) 0);            // inRefcon.

	gHeadPositionXDataRef = XPLMFindDataRef("sim/aircraft/view/acf_peX");

	return 1;
}

PLUGIN_API void    XPluginStop(void)
{
	XPLMUnregisterCommandHandler(MyCommand, MyCommandHandler, 0, 0);
}


PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginReceiveMessage(
			 XPLMPluginID    inFromWho,
			 long            inMessage,
			 void *          inParam)
{

}

int    MyCommandHandler(XPLMCommandRef       inCommand,
				 XPLMCommandPhase     inPhase,
				 void *               inRefcon)
{

	//  Use the structure below to have the command executed
	//  continuously while the button is being held down.
	if (inPhase == xplm_CommandContinue)
	{
		XPLMSetDataf(gHeadPositionXDataRef, XPLMGetDataf(gHeadPositionXDataRef) + .1);
	}

	//  Use this structure to have the command executed on button up only.
	if (inPhase == xplm_CommandEnd)
	{
		XPLMSetDataf(gHeadPositionXDataRef, XPLMGetDataf(gHeadPositionXDataRef) + .1);
	}

	// Return 1 to pass the command to plugin windows and X-Plane.
	// Returning 0 disables further processing by X-Plane.
	// In this case we might return 0 or 1 because X-Plane does not duplicate our command.
	return 0;
}
Leave a comment

Create Instructions Widget

// Instructions Widget

/*
	PullDown Menu Creates Widget Window to Disply Plugin Instructions or Notes.
		
	This example shows how to use a pulldown menu to create a widget window to display a list of instructions or notes.  
	The widget window is distroyed by clicking a close box.   There are several other widget window features that
	can be explored;  please see the SDK documentation.  
	
	This content added by Blue Side Up Bob.  
*/

// #define XPLM200 = 1;  This example does not require SDK2.0.

#include "XPLMUtilities.h"
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int gMenuItem;

char InstructionsText[50][200] = {  
"   1. Text line one.",   
"   2. Text.",
"   3. Text.",  
"   4. Text.",  
"   5. Text.", 
"   6. Text.",  
"end"

};


XPWidgetID	InstructionsWidget = NULL; 
XPWidgetID	InstructionsWindow = NULL;
XPWidgetID	InstructionsTextWidget[50] = {NULL};

void InstructionsMenuHandler(void *, void *);
void CreateInstructionsWidget(int x1, int y1, int w, int h);
int InstructionsHandler(XPWidgetMessage  inMessage, XPWidgetID  inWidget, long  inParam1, long  inParam2);


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	XPLMMenuID	PluginMenu;
	int			PluginSubMenuItem;

	strcpy(outName, "Instructions");
	strcpy(outSig, "BlueSideUpBob.Example.Instructions");
	strcpy(outDesc, "A plugin to display an Instruction Text window from the pull down menu.");

// Create our menu
	PluginSubMenuItem = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "Instructions Plugin", NULL, 1);
	PluginMenu = XPLMCreateMenu("Instructions Plugin", XPLMFindPluginsMenu(), PluginSubMenuItem, InstructionsMenuHandler, NULL);
	XPLMAppendMenuItem(PluginMenu, "Instructions", (void *) +1, 1);

// Flag to tell us if the widget is being displayed.
	gMenuItem = 0;
	
	return 1;
}

PLUGIN_API void	XPluginStop(void)
{

	if (gMenuItem == 1)
	{
		XPDestroyWidget(InstructionsWidget, 1);
		gMenuItem = 0;
	}
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, long inMsg, void * inParam)
{
}


void InstructionsMenuHandler(void * inMenuRef, void * inItemRef)
{
	switch ( (int) inItemRef)
	{
	
		case 1:	if (gMenuItem == 0)
				{
					CreateInstructionsWidget(50, 712, 974, 662);	//left, top, right, bottom.
					gMenuItem = 1;
				}
				else
				{
					if(!XPIsWidgetVisible(InstructionsWidget))
					XPShowWidget(InstructionsWidget);
				}
				break;
	}
}						

// This will create our widget dialog.
void CreateInstructionsWidget(int x, int y, int w, int h)
{
int Index;

	int x2 = x + w;
	int y2 = y - h;
	
// Create the Main Widget window.
	InstructionsWidget = XPCreateWidget(x, y, x2, y2,
					1,										// Visible
					"INSTRUCTIONS     Blue Side Up Bob",	// desc
					1,										// root
					NULL,									// no container
					xpWidgetClass_MainWindow);


// Add Close Box to the Main Widget.  Other options are available.  See the SDK Documentation.  
	XPSetWidgetProperty(InstructionsWidget, xpProperty_MainWindowHasCloseBoxes, 1);


// Print each line of instructions.
	for (Index=0; Index < 50; Index++)
	{
	if(strcmp(InstructionsText[Index],"end") == 0) {break;}

		// Create a text widget
		InstructionsTextWidget[Index] = XPCreateWidget(x+10, y-(30+(Index*20)) , x2-10, y-(42+(Index*20)),
		1,	// Visible
		InstructionsText[Index],// desc
		0,		// root
		InstructionsWidget,
		xpWidgetClass_Caption);
	}
		
													
							
// Register our widget handler
	XPAddWidgetCallback(InstructionsWidget, InstructionsHandler);
}


// This is our widget handler.  In this example we are only interested when the close box is pressed.
int	InstructionsHandler(XPWidgetMessage  inMessage, XPWidgetID  inWidget, long  inParam1, long  inParam2)
{
	if (inMessage == xpMessage_CloseButtonPushed)
	{
		if (gMenuItem == 1)
		{
			XPHideWidget(InstructionsWidget);
		}
		return 1;
	}

	return 0;
}
Leave a comment

AcquirePlaneTest

#include <stdio.h>
#include <string.h>
#include "XPLMPlanes.h"
#include "XPLMUtilities.h"

static int	enable_count = 0;


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	strcpy(outName, "planes_test");
	strcpy(outSig, "xplanesdk.examples.plane_test");
	strcpy(outDesc, "A quick test of airplane acquisition.");

	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	++enable_count;
	if (enable_count == 1)	return 0;

	int r = XPLMAcquirePlanes(NULL, NULL, NULL);
	
	if(r == 0)	XPLMDebugString("Plane test: did not acquire plane.s\n");
	else		XPLMDebugString("Plane test: did acquire plane.s\n");
	if(r)
	{
		char buf[1024];
		XPLMPluginID who;
		int total_before, active_before,total_after,active_after;
		XPLMCountAircraft(&total_before,&active_before,&who);
		XPLMSetActiveAircraftCount(total_before > 2 ? 2 : total_before);
		XPLMCountAircraft(&total_after,&active_after,&who);
		sprintf(buf,"Before: %d of %d, after: %d of %d\n",
			active_before,total_before,active_after,total_after);
		XPLMDebugString(buf);
	}
	
	return 1;
}

PLUGIN_API void XPluginReceiveMessage(
					XPLMPluginID	inFromWho,
					int				inMessage,
					void *			inParam)
{
}
1 Comment

OpenAL Shared Example

This sample plugin plays a sound whenever an airplane is loaded. It demonstrates how to use OpenAL with a context from a plugin.

This plugin can safely run while X-Plane is using OpenAL.

This plugin requires the file “sound.wav” to be in the same folder as the plugin itself.

On Linux you will need to add -lopenal to LIBS.

On Windows you will need to add the OpenAL include and lib paths and add openal32.lib to the linker settings.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "XPLMUtilities.h"
#include "XPLMProcessing.h"
#include "XPLMPlugin.h"

// OS X: we use this to convert our file path.
#if APL
#include <Carbon/Carbon.h>
#endif

// Your include paths for OpenAL may vary by platform.
#include <OpenAL/al.h>
#include <OpenAL/alc.h>

/**************************************************************************************************************
 * WAVE FILE LOADING
**************************************************************************************************************/

// You can just use alutCreateBufferFromFile to load a wave file, but there seems to be a lot of problems with 
// alut not beign available, being deprecated, etc.  So...here's a stupid routine to load a wave file.  I have
// tested this only on x86 machines, so if you find a bug on PPC please let me know.

// Macros to swap endian-values.

#define SWAP_32(value)                 \
        (((((unsigned short)value)<<8) & 0xFF00)   | \
         ((((unsigned short)value)>>8) & 0x00FF))

#define SWAP_16(value)                     \
        (((((unsigned int)value)<<24) & 0xFF000000)  | \
         ((((unsigned int)value)<< 8) & 0x00FF0000)  | \
         ((((unsigned int)value)>> 8) & 0x0000FF00)  | \
         ((((unsigned int)value)>>24) & 0x000000FF))

// Wave files are RIFF files, which are "chunky" - each section has an ID and a length.  This lets us skip
// things we can't understand to find the parts we want.  This header is common to all RIFF chunks.
struct chunk_header { 
	int			id;
	int			size;
};

// WAVE file format info.  We pass this through to OpenAL so we can support mono/stereo, 8/16/bit, etc.
struct format_info {
	short		format;				// PCM = 1, not sure what other values are legal.
	short		num_channels;
	int			sample_rate;
	int			byte_rate;
	short		block_align;
	short		bits_per_sample;
};

// This utility returns the start of data for a chunk given a range of bytes it might be within.  Pass 1 for
// swapped if the machine is not the same endian as the file.
static char *	find_chunk(char * file_begin, char * file_end, int desired_id, int swapped)
{
	while(file_begin < file_end)
	{
		chunk_header * h = (chunk_header *) file_begin;
		if(h->id == desired_id && !swapped)
			return file_begin+sizeof(chunk_header);
		if(h->id == SWAP_32(desired_id) && swapped)
			return file_begin+sizeof(chunk_header);
		int chunk_size = swapped ? SWAP_32(h->size) : h->size;
		char * next = file_begin + chunk_size + sizeof(chunk_header);
		if(next > file_end || next <= file_begin)
			return NULL;
		file_begin = next;		
	}
	return NULL;
}

// Given a chunk, find its end by going back to the header.
static char * chunk_end(char * chunk_start, int swapped)
{
	chunk_header * h = (chunk_header *) (chunk_start - sizeof(chunk_header));
	return chunk_start + (swapped ? SWAP_32(h->size) : h->size);
}

#define FAIL(X) { XPLMDebugString(X); free(mem); return 0; }

#define RIFF_ID 0x46464952			// 'RIFF'
#define FMT_ID  0x20746D66			// 'FMT '
#define DATA_ID 0x61746164			// 'DATA'

ALuint load_wave(const char * file_name)
{
	// First: we open the file and copy it into a single large memory buffer for processing.

	FILE * fi = fopen(file_name,"rb");
	if(fi == NULL)
	{
		XPLMDebugString("WAVE file load failed - could not open.\n");	
		return 0;
	}
	fseek(fi,0,SEEK_END);
	int file_size = ftell(fi);
	fseek(fi,0,SEEK_SET);
	char * mem = (char*) malloc(file_size);
	if(mem == NULL)
	{
		XPLMDebugString("WAVE file load failed - could not allocate memory.\n");
		fclose(fi);
		return 0;
	}
	if (fread(mem, 1, file_size, fi) != file_size)
	{
		XPLMDebugString("WAVE file load failed - could not read file.\n");	
		free(mem);
		fclose(fi);
		return 0;
	}
	fclose(fi);
	char * mem_end = mem + file_size;
	
	// Second: find the RIFF chunk.  Note that by searching for RIFF both normal
	// and reversed, we can automatically determine the endian swap situation for
	// this file regardless of what machine we are on.
	
	int swapped = 0;
	char * riff = find_chunk(mem, mem_end, RIFF_ID, 0);
	if(riff == NULL)
	{
		riff = find_chunk(mem, mem_end, RIFF_ID, 1);
		if(riff)
			swapped = 1;
		else
			FAIL("Could not find RIFF chunk in wave file.\n")
	}
	
	// The wave chunk isn't really a chunk at all. :-(  It's just a "WAVE" tag 
	// followed by more chunks.  This strikes me as totally inconsistent, but
	// anyway, confirm the WAVE ID and move on.
	
	if (riff[0] != 'W' ||
		riff[1] != 'A' ||
		riff[2] != 'V' ||
		riff[3] != 'E')
		FAIL("Could not find WAVE signature in wave file.\n")

	char * format = find_chunk(riff+4, chunk_end(riff,swapped), FMT_ID, swapped);
	if(format == NULL)
		FAIL("Could not find FMT  chunk in wave file.\n")
	
	// Find the format chunk, and swap the values if needed.  This gives us our real format.
	
	format_info * fmt = (format_info *) format;
	if(swapped)
	{
		fmt->format = SWAP_16(fmt->format);
		fmt->num_channels = SWAP_16(fmt->num_channels);
		fmt->sample_rate = SWAP_32(fmt->sample_rate);
		fmt->byte_rate = SWAP_32(fmt->byte_rate);
		fmt->block_align = SWAP_16(fmt->block_align);
		fmt->bits_per_sample = SWAP_16(fmt->bits_per_sample);
	}
	
	// Reject things we don't understand...expand this code to support weirder audio formats.
	
	if(fmt->format != 1) FAIL("Wave file is not PCM format data.\n")
	if(fmt->num_channels != 1 && fmt->num_channels != 2) FAIL("Must have mono or stereo sound.\n")
	if(fmt->bits_per_sample != 8 && fmt->bits_per_sample != 16) FAIL("Must have 8 or 16 bit sounds.\n")
	char * data = find_chunk(riff+4, chunk_end(riff,swapped), DATA_ID, swapped) ;
	if(data == NULL)
		FAIL("I could not find the DATA chunk.\n")
	
	int sample_size = fmt->num_channels * fmt->bits_per_sample / 8;
	int data_bytes = chunk_end(data,swapped) - data;
	int data_samples = data_bytes / sample_size;
	
	// If the file is swapped and we have 16-bit audio, we need to endian-swap the audio too or we'll 
	// get something that sounds just astoundingly bad!
	
	if(fmt->bits_per_sample == 16 && swapped)
	{
		short * ptr = (short *) data;
		int words = data_samples * fmt->num_channels;
		while(words--)
		{
			*ptr = SWAP_16(*ptr);
			++ptr;
		}
	}
	
	// Finally, the OpenAL crud.  Build a new OpenAL buffer and send the data to OpenAL, passing in
	// OpenAL format enums based on the format chunk.
	
	ALuint buf_id = 0;
	alGenBuffers(1, &buf_id);
	if(buf_id == 0) FAIL("Could not generate buffer id.\n");
	
	alBufferData(buf_id, fmt->bits_per_sample == 16 ? 
							(fmt->num_channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16) :
							(fmt->num_channels == 2 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8),
					data, data_bytes, fmt->sample_rate);
	free(mem);
	return buf_id;
}




/**************************************************************************************************************
 * SAMPLE OEPNAL PLUGIN:
 **************************************************************************************************************/
 
static ALuint			snd_src		=0;				// Sample source and buffer - this is one "sound" we play.
static ALuint			snd_buffer	=0;
static float			pitch		= 1.0f;			// Start with 1.0 pitch - no pitch shift.

static ALCdevice *		my_dev		= NULL;			// We make our own device and context to play sound through.
static ALCcontext *		my_ctx		= NULL;


// This is a stupid logging error function...useful for debugging, but not good error checking.
#define CHECK_ERR() __CHECK_ERR(__FILE__,__LINE__)
static void __CHECK_ERR(const char * f, int l)
{
	ALuint e = alGetError();
	if (e != AL_NO_ERROR)
		printf("ERROR: %d (%s:%d\n", e, f, l);
}

// Mac specific: this converts file paths from HFS (which we get from the SDK) to Unix (which the OS wants).
// See this for more info:
//
// http://www.xsquawkbox.net/xpsdk/mediawiki/FilePathsAndMacho

#if APL
static int ConvertPath(const char * inPath, char * outPath, int outPathMaxLen) {

	CFStringRef inStr = CFStringCreateWithCString(kCFAllocatorDefault, inPath ,kCFStringEncodingMacRoman);
	if (inStr == NULL)
		return -1;
	CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inStr, kCFURLHFSPathStyle,0);
	CFStringRef outStr = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
	if (!CFStringGetCString(outStr, outPath, outPathMaxLen, kCFURLPOSIXPathStyle))
		return -1;
	CFRelease(outStr);
	CFRelease(url);
	CFRelease(inStr);
	return 0;
}
#endif

// Initialization code.

static float init_sound(float elapsed, float elapsed_sim, int counter, void * ref)
{
	CHECK_ERR();

	char buf[2048];
	
	// We have to save the old context and restore it later, so that we don't interfere with X-Plane
	// and other plugins.

	ALCcontext * old_ctx = alcGetCurrentContext();
	
	if(old_ctx == NULL)
	{
		printf("0x%08x: I found no OpenAL, I will be the first to init.\n",XPLMGetMyID());
		my_dev = alcOpenDevice(NULL);
		if(my_dev == NULL)
		{
			XPLMDebugString("Could not open the default OpenAL device.\n");
			return 0;		
		}	
		my_ctx = alcCreateContext(my_dev, NULL);
		if(my_ctx == NULL)
		{
			if(old_ctx)
				alcMakeContextCurrent(old_ctx);
			alcCloseDevice(my_dev);
			my_dev = NULL;
			XPLMDebugString("Could not create a context.\n");
			return 0;				
		}
		
		// Make our context current, so that OpenAL commands affect our, um, stuff.
		
		alcMakeContextCurrent(my_ctx);
		printf("0x%08x: I created the context.\n",XPLMGetMyID(), my_ctx);

		ALCint		major_version, minor_version;
		const char * al_hw=alcGetString(my_dev,ALC_DEVICE_SPECIFIER	);
		const char * al_ex=alcGetString(my_dev,ALC_EXTENSIONS		
);
		alcGetIntegerv(NULL,ALC_MAJOR_VERSION,sizeof(major_version),&major_version);
		alcGetIntegerv(NULL,ALC_MINOR_VERSION,sizeof(minor_version),&minor_version);
		
		printf("OpenAL version   : %d.%d\n",major_version,minor_version);
		printf("OpenAL hardware  : %s\n", (al_hw?al_hw:"(none)"));
		printf("OpenAL extensions: %s\n", (al_ex?al_ex:"(none)"));
		CHECK_ERR();

	} 
	else
	{
		printf("0x%08x: I found someone else's context 0x%08x.\n",XPLMGetMyID(), old_ctx);
	}
	
	ALfloat	zero[3] = { 0 } ;

	char dirchar = *XPLMGetDirectorySeparator();
	XPLMGetPluginInfo(XPLMGetMyID(), NULL, buf, NULL, NULL);
	char * p = buf;
	char * slash = p;
	while(*p)
	{
		if(*p==dirchar) slash = p;
		++p;
	}
	++slash;
	*slash=0;
	strcat(buf,"sound.wav");
	#if APL
		ConvertPath(buf,buf,sizeof(buf));
	#endif
	
	// Generate 1 source and load a buffer of audio.
	alGenSources(1,&snd_src);
	CHECK_ERR();
	snd_buffer = load_wave(buf);
	printf("0x%08x: Loaded %d from %s\n", XPLMGetMyID(), snd_buffer,buf);
	CHECK_ERR();
	
	// Basic initializtion code to play a sound: specify the buffer the source is playing, as well as some 
	// sound parameters. This doesn't play the sound - it's just one-time initialization.
	alSourcei(snd_src,AL_BUFFER,snd_buffer);
	alSourcef(snd_src,AL_PITCH,1.0f);
	alSourcef(snd_src,AL_GAIN,1.0f);	
	alSourcei(snd_src,AL_LOOPING,0);
	alSourcefv(snd_src,AL_POSITION, zero);
	alSourcefv(snd_src,AL_VELOCITY, zero);
	CHECK_ERR();

	return 0.0f;
}

PLUGIN_API int XPluginStart(char * name, char * sig, char * desc)
{
	strcpy(name,"OpenAL Sound Demo");
	strcpy(sig,"xpsdk.demo.openal2");
	strcpy(desc,"Demonstrates sound playback with OpenAL.");
	
	if( sizeof(unsigned int) != 4 ||
		sizeof(unsigned short) != 2)
	{
		XPLMDebugString("This example plugin was compiled with a compiler with weird type sizes.\n");
		return 0;
	}
	
	// Do deferred sound initialization. See http://www.xsquawkbox.net/xpsdk/mediawiki/DeferredInitialization
	// for more info.
	XPLMRegisterFlightLoopCallback(init_sound,-1.0,NULL);	
	printf("0x%08x: I am: %s\n", XPLMGetMyID(), sig);
	return 1;
}

PLUGIN_API void XPluginStop(void)
{
	// Cleanup: nuke our context if we have it.  This is hacky and bad - we should really destroy
	// our buffers and sources.  I have _no_ idea if OpenAL will leak memory.
	if(alcGetCurrentContext() != NULL)
	{
		printf("0x%08x: deleting snd %d\n", XPLMGetMyID(),snd_buffer);
		if(snd_src)		alDeleteSources(1,&snd_src);
		if(snd_buffer) alDeleteBuffers(1,&snd_buffer);
	}
	if(my_ctx) 
	{
		printf("0x%08x: deleting my context 0x%08x\n", XPLMGetMyID(),my_ctx);
		alcMakeContextCurrent(NULL);
		alcDestroyContext(my_ctx);
	}
	if(my_dev) alcCloseDevice(my_dev);
	
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API void XPluginReceiveMessage(XPLMPluginID from, int msg, void * p)
{
	switch(msg) {
	case XPLM_MSG_PLANE_LOADED:
		if(snd_src)
		{
			printf("0x%08x: Playing %s (%d)\n",XPLMGetMyID(), "sound", snd_src);
			// An example of actually playing the sound.  First we change to our 
			// context, then we play the sound at pitch, then we change the context back.
			// We check for null contexts both for us (our init failed) and the old context
			// (X-plane's sound failed).
			alSourcef(snd_src,AL_PITCH,pitch);
			alSourcePlay(snd_src);
			pitch *= 1.1f;
			CHECK_ERR();			
		}
		break;
	}		
}
1 Comment

TimedProcessing

/*
 * TimedProcessing.c
 * 
 * This example plugin demonstrates how to use the timed processing callbacks
 * to continuously record sim data to disk.
 * 
 * This technique can be used to record data to disk or to the network.  Unlike
 * UDP data output, we can increase our frequency to capture data every single
 * sim frame.  (This example records once per second.)
 * 
 * Use the timed processing APIs to do any periodic or asynchronous action in
 * your plugin.
 * 
 */

#if APL
#if defined(__MACH__)
#include <Carbon/Carbon.h>
#endif
#endif

#include <stdio.h>
#include <string.h>
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMUtilities.h"

/* File to write data to. */
static FILE *	gOutputFile;

/* Data refs we will record. */
static XPLMDataRef		gPlaneLat;
static XPLMDataRef		gPlaneLon;
static XPLMDataRef		gPlaneEl;

#if APL && __MACH__
static int ConvertPath(const char * inPath, char * outPath, int outPathMaxLen);
#endif


static float	MyFlightLoopCallback(
                                   float                inElapsedSinceLastCall,    
                                   float                inElapsedTimeSinceLastFlightLoop,    
                                   int                  inCounter,    
                                   void *               inRefcon);    


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	char	outputPath[255];
	#if APL && __MACH__
	char outputPath2[255];
	int Result = 0;
	#endif
		
	strcpy(outName, "TimedProcessing");
	strcpy(outSig, "xplanesdk.examples.timedprocessing");
	strcpy(outDesc, "A plugin that records sim data.");

	/* Open a file to write to.  We locate the X-System directory 
	 * and then concatenate our file name.  This makes us save in
	 * the X-System directory.  Open the file. */
	XPLMGetSystemPath(outputPath);
	strcat(outputPath, "TimedProcessing.txt");

	#if APL && __MACH__
	Result = ConvertPath(outputPath, outputPath2, sizeof(outputPath));
	if (Result == 0)
		strcpy(outputPath, outputPath2);
	else
		XPLMDebugString("TimedProccessing - Unable to convert path\n");
	#endif
	
	gOutputFile = fopen(outputPath, "w");

	/* Find the data refs we want to record. */
	gPlaneLat = XPLMFindDataRef("sim/flightmodel/position/latitude");
	gPlaneLon = XPLMFindDataRef("sim/flightmodel/position/longitude");
	gPlaneEl = XPLMFindDataRef("sim/flightmodel/position/elevation");

	/* Register our callback for once a second.  Positive intervals
	 * are in seconds, negative are the negative of sim frames.  Zero
	 * registers but does not schedule a callback for time. */
	XPLMRegisterFlightLoopCallback(		
			MyFlightLoopCallback,	/* Callback */
			1.0,					/* Interval */
			NULL);					/* refcon not used. */
			
	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	/* Unregister the callback */
	XPLMUnregisterFlightLoopCallback(MyFlightLoopCallback, NULL);
	
	/* Close the file */
	fclose(gOutputFile);
}

PLUGIN_API void XPluginDisable(void)
{
	/* Flush the file when we are disabled.  This is convenient; you 
	 * can disable the plugin and then look at the output on disk. */
	fflush(gOutputFile);
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginReceiveMessage(
					XPLMPluginID	inFromWho,
					int				inMessage,
					void *			inParam)
{
}

float	MyFlightLoopCallback(
                                   float                inElapsedSinceLastCall,    
                                   float                inElapsedTimeSinceLastFlightLoop,    
                                   int                  inCounter,    
                                   void *               inRefcon)
{
	/* The actual callback.  First we read the sim's time and the data. */
	float	elapsed = XPLMGetElapsedTime();
	float	lat = XPLMGetDataf(gPlaneLat);
	float	lon = XPLMGetDataf(gPlaneLon);
	float	el = XPLMGetDataf(gPlaneEl);
	
	/* Write the data to a file. */
	fprintf(gOutputFile, "Time=%f, lat=%f,lon=%f,el=%f.\n",elapsed, lat, lon, el);
	
	/* Return 1.0 to indicate that we want to be called again in 1 second. */
	return 1.0;
}                                   

#if APL && __MACH__
#include <Carbon/Carbon.h>
int ConvertPath(const char * inPath, char * outPath, int outPathMaxLen)
{
	CFStringRef inStr = CFStringCreateWithCString(kCFAllocatorDefault, inPath ,kCFStringEncodingMacRoman);
	if (inStr == NULL)
		return -1;
	CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inStr, kCFURLHFSPathStyle,0);
	CFStringRef outStr = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
	if (!CFStringGetCString(outStr, outPath, outPathMaxLen, kCFURLPOSIXPathStyle))
		return -1;
	CFRelease(outStr);
	CFRelease(url);
	CFRelease(inStr); 	
	return 0;
}
#endif
3 Comments

SimData

/*
 * SimData.c
 * 
 * This example demonstrates how to interact with X-Plane by reading and writing
 * data.  This example creates menus items that change the nav-1 radio frequency.
 * 
 */

#include <stdio.h>
#include <string.h>
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"

/* We keep our data ref globally since only one is used for the whole plugin. */
static XPLMDataRef		gDataRef = NULL;

static void	MyMenuHandlerCallback(
                                   void *               inMenuRef,    
                                   void *               inItemRef);    

PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
		XPLMMenuID	myMenu;
		int			mySubMenuItem;

	/* Provide our plugin's profile to the plugin system. */
	strcpy(outName, "SimData");
	strcpy(outSig, "xplanesdk.examples.simdata");
	strcpy(outDesc, "A plugin that changes sim data.");

	/* First we put a new menu item into the plugin menu.
	 * This menu item will contain a submenu for us. */
	mySubMenuItem = XPLMAppendMenuItem(
						XPLMFindPluginsMenu(),	/* Put in plugins menu */
						"Sim Data",				/* Item Title */
						0,						/* Item Ref */
						1);						/* Force English */
	
	/* Now create a submenu attached to our menu item. */
	myMenu = XPLMCreateMenu(
						"Sim Data", 
						XPLMFindPluginsMenu(), 
						mySubMenuItem, 			/* Menu Item to attach to. */
						MyMenuHandlerCallback,	/* The handler */
						0);						/* Handler Ref */
						
	/* Append a few menu items to our submenu.  We will use the refcon to
	 * store the amount we want to change the radio by. */
	XPLMAppendMenuItem(
						myMenu,
						"Decrement Nav1",
						(void *) -1000,
						1);
	XPLMAppendMenuItem(
						myMenu,
						"Increment Nav1",
						(void *) +1000,
						1);
	
	/* Look up our data ref.  You find the string name of the data ref
	 * in the master list of data refs, including in HTML form in the 
	 * plugin SDK.  In this case, we want the nav1 frequency. */
	gDataRef = XPLMFindDataRef("sim/cockpit/radios/nav1_freq_hz");
	
	/* Only return that we initialized correctly if we found the data ref. */
	return (gDataRef != NULL) ? 1 : 0;
}

PLUGIN_API void	XPluginStop(void)
{
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginReceiveMessage(
					XPLMPluginID	inFromWho,
					int				inMessage,
					void *			inParam)
{
}

void	MyMenuHandlerCallback(
                                   void *               inMenuRef,    
                                   void *               inItemRef)
{
	/* This is our handler for the menu item.  Our inItemRef is the refcon
	 * we registered in our XPLMAppendMenuItem calls.  It is either +1000 or
	 * -1000 depending on which menu item is picked. */
	if (gDataRef != NULL)
	{
		/* We read the data ref, add the increment and set it again.
		 * This changes the nav frequency. */
		XPLMSetDatai(gDataRef, XPLMGetDatai(gDataRef) + (int) inItemRef);
	}
}
5 Comments