// 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!
}
// *************************************************
// 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 && CofG_refx && CofG_refy && CofG_refz)
//Locate the test object by its heading.
{
AircraftHeading = XPLMGetDataf(gHeadingDataRef);
if (AircraftHeading <= 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 <= 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 <= 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 <= 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;
}
// 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;
}
// 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;
}
// 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;
}
// 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;
}
#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)
{
}
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;
}
}
/*
* 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
/*
* 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);
}
}