Archives: Code Samples

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

ShareData

/*
 * ShareData.c
 * 
 * This is an example plugin that demonstrates how to share data, both owned
 * by a plugin and shared.
 * 
 * Data can be published in two ways: a plugin can publish data it owns.
 * In this case, it provides callbacks to read (and optionally write) the
 * data.  As other plugins access the data ref, the SDK calls back the
 * accessors.
 * 
 * Data can also be shared.  In this case, the SDK allocates the memory
 * for the data.  Each plugin that shares it registers a callback that is
 * called by the SDK when any plugin writes the data.
 * 
 * We use the xplanesdk namespace to allocate unique data refs.  When creating
 * your own datarefs, make sure to prefix the data ref with a domain unique to
 * your organization.  'sim' is the domain for the main simulator.
 * 
 */

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

/* This is the storage for the data we own. */
static double	gOwnedData = 0.0;


static XPLMDataRef	gOwnedDataRef = NULL;
static XPLMDataRef	gSharedDataRef = NULL;

/* These callbacks are called by the SDK to read and write the sim.
 * We provide two sets of callbacks allowing our data to appear as
 * float and double.  This is done for didactic purposes; multityped
 * data is provided as a backward compatibility solution and probably
 * should not be used in initial designs as a convenience to client 
 * code.  */
static float	MyGetDatafCallback(void * inRefcon);
static void	MySetDatafCallback(void * inRefcon, float inValue);
static double	MyGetDatadCallback(void * inRefcon);
static void	MySetDatadCallback(void * inRefcon, double inValue);

/* This callback is called whenever our shared data is changed. */
static void	MyDataChangedCallback(void * inRefcon);

PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	int RetVal;
	char Buffer[256];
	
	strcpy(outName, "SharedData");
	strcpy(outSig, "xplanesdk.examples.shareddata");
	strcpy(outDesc, "A plugin that shares a data ref.");

	/* Register our owned data.  Note that we pass two sets of
	 * function callbacks for two data types and leave the rest blank. */
	gOwnedDataRef = XPLMRegisterDataAccessor(
								"xplanesdk/examples/sharedata/number",
								xplmType_Float + xplmType_Double,			/* The types we support */
								1,											/* Writable */
								NULL, NULL,									/* No accessors for ints */
								MyGetDatafCallback, MySetDatafCallback,		/* Accessors for floats */
								MyGetDatadCallback, MySetDatadCallback,		/* Accessors for doubles */
								NULL, NULL,									/* No accessors for int arrays */
								NULL, NULL,									/* No accessors for float arrays */
								NULL, NULL,									/* No accessors for raw data */
								NULL, NULL);								/* Refcons not used */

	/* Subscribe to shared data.  If no one else has made it, this will 
	 * cause the SDK to allocate the data. */

	RetVal = XPLMShareData("xplanesdk/examples/sharedata/sharedint", xplmType_Int,
		MyDataChangedCallback, NULL);

	gSharedDataRef = XPLMFindDataRef("xplanesdk/examples/sharedata/sharedint");
	sprintf(Buffer, "ShareData 2 - gSharedDataRef := %x\n", gSharedDataRef);
	XPLMDebugString(Buffer);

	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	int RetVal;

	if (gOwnedDataRef)
		XPLMUnregisterDataAccessor(gOwnedDataRef);

	RetVal = XPLMUnshareData("xplanesdk/examples/sharedata/sharedint", xplmType_Int,
		MyDataChangedCallback, NULL);
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

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


/*
 * These are the data accessors for our owned data.  
 * 
 */

float	MyGetDatafCallback(void * inRefcon)
{
	return gOwnedData;
}

void	MySetDatafCallback(void * inRefcon, float inValue)
{
	gOwnedData = inValue;
}

double	MyGetDatadCallback(void * inRefcon)
{
	return gOwnedData;
}

void	MySetDatadCallback(void * inRefcon, double inValue)
{
	gOwnedData = inValue;
}

/*
 * This is the callback for our shared data.  Right now we do not react
 * to our shared data being chagned.
 * 
 */

void	MyDataChangedCallback(void * inRefcon)
{
}
Leave a comment

Position

#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 "XPLMCamera.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#if IBM
#include <windows.h>
#endif

#define MAX_ITEMS 11

static XPLMDataRef gPositionDataRef[MAX_ITEMS];

static char DataRefString[MAX_ITEMS][255] = {	"sim/flightmodel/position/local_x", "sim/flightmodel/position/local_y", "sim/flightmodel/position/local_z",
										"sim/flightmodel/position/lat_ref", "sim/flightmodel/position/lon_ref",	"sim/flightmodel/position/theta",
										"sim/flightmodel/position/phi", "sim/flightmodel/position/psi",
										"sim/flightmodel/position/latitude", "sim/flightmodel/position/longitude", "sim/flightmodel/position/elevation"};

static char DataRefDesc[MAX_ITEMS][255] = {"Local x", "Local y", "Local z", "Lat Ref", "Lon Ref", "Theta", "Phi", "Psi"};
static char Description[3][255] = {"Latitude", "Longitude", "Elevation"};

static int	Element = 0, IntVals[128];
static float FloatVals[128];
static int ByteVals[128];

static int MenuItem1;

static XPWidgetID			PositionWidget = NULL, PositionWindow = NULL;
static XPWidgetID			PositionApplyButton = NULL;
static XPWidgetID			PositionText[MAX_ITEMS] = {NULL};
static XPWidgetID			PositionEdit[MAX_ITEMS] = {NULL};
static XPWidgetID			UpArrow[MAX_ITEMS] = {NULL};
static XPWidgetID			DownArrow[MAX_ITEMS] = {NULL};
static XPWidgetID			LatLonAltApplyButton = NULL, LatLonRefApplyButton = NULL, ReloadSceneryButton = NULL;
static XPWidgetID			Position2Text[3] = {NULL};
static XPWidgetID			Position2Edit[3] = {NULL};

static void PositionMenuHandler(void *, void *);

static void CreatePosition(int x1, int y1, int w, int h);

static int PositionHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						intptr_t				inParam1,
						intptr_t				inParam2);

static void DisplayFindDataRef(void);
static void ApplyValues(void);
static void ApplyLatLonRefValues(void);
static void ApplyLatLonAltValues(void);

inline	float	HACKFLOAT(float val)
{
	return val;
}
/*
#if IBM
inline	float	HACKFLOAT(float val)
{
	return val;
}
#else
inline long long HACKFLOAT(float val)
{
	double	d = val;
	long long temp;
	temp = *((long long *) &d);
	return temp;
}
#endif
*/

PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	XPLMMenuID	id;
	int			item;

	strcpy(outName, "Position");
	strcpy(outSig, "xpsdk.examples.position");
	strcpy(outDesc, "A plug-in that allows positioning of lat/lon etc.");

	item = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "Position", NULL, 1);

	id = XPLMCreateMenu("Position", XPLMFindPluginsMenu(), item, PositionMenuHandler, NULL);
	XPLMAppendMenuItem(id, "Position", (void *)"Position", 1);

	MenuItem1 = 0;

	for (int Item=0; Item<MAX_ITEMS; Item++)
		gPositionDataRef[Item] = XPLMFindDataRef(DataRefString[Item]);

	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	if (MenuItem1 == 1)
	{
		XPDestroyWidget(PositionWidget, 1);
		MenuItem1 = 0;
	}
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

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

void PositionMenuHandler(void * mRef, void * iRef)
{
	if (!strcmp((char *) iRef, "Position"))
	{
		if (MenuItem1 == 0)
		{
			CreatePosition(300, 600, 300, 550);
			MenuItem1 = 1;
		}
		else
			if(!XPIsWidgetVisible(PositionWidget))
				XPShowWidget(PositionWidget);
	}
}


void CreatePosition(int x, int y, int w, int h)
{
	int x2 = x + w;
	int y2 = y - h;
	float FloatValue[MAX_ITEMS];
	double DoubleValue[3];

	char buffer[512];
	int Item;

	for (Item=0; Item<MAX_ITEMS; Item++)
		FloatValue[Item] = XPLMGetDataf(gPositionDataRef[Item]);

	/// X, Y, Z, Lat, Lon, Alt
	XPLMLocalToWorld(FloatValue[0], FloatValue[1], FloatValue[2], &DoubleValue[0], &DoubleValue[1], &DoubleValue[2]);
	DoubleValue[2] *= 3.28;

	PositionWidget = XPCreateWidget(x, y, x2, y2,
					1,	// Visible
					"Position",	// desc
					1,		// root
					NULL,	// no container
					xpWidgetClass_MainWindow);

	XPSetWidgetProperty(PositionWidget, xpProperty_MainWindowHasCloseBoxes, 1);

	PositionWindow = XPCreateWidget(x+50, y-50, x2-50, y2+50,
					1,	// Visible
					"",	// desc
					0,		// root
					PositionWidget,
					xpWidgetClass_SubWindow);

	XPSetWidgetProperty(PositionWindow, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

	for (Item=0; Item<MAX_ITEMS-3; Item++)
	{
		PositionText[Item] = XPCreateWidget(x+60, y-(70 + (Item*30)), x+115, y-(92 + (Item*30)),
							1,	// Visible
							DataRefDesc[Item],// desc
							0,		// root
							PositionWidget,
							xpWidgetClass_Caption);

		sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
		PositionEdit[Item] = XPCreateWidget(x+120, y-(70 + (Item*30)), x+210, y-(92 + (Item*30)),
							1, buffer, 0, PositionWidget,
							xpWidgetClass_TextField);

		XPSetWidgetProperty(PositionEdit[Item], xpProperty_TextFieldType, xpTextEntryField);

		UpArrow[Item] = XPCreateWidget(x+212, y-(66 + (Item*30)), x+224, y-(81 + (Item*30)),
							1, "", 0, PositionWidget,
							xpWidgetClass_Button);

		XPSetWidgetProperty(UpArrow[Item], xpProperty_ButtonType, xpLittleUpArrow);

		DownArrow[Item] = XPCreateWidget(x+212, y-(81 + (Item*30)), x+224, y-(96 + (Item*30)),
							1, "", 0, PositionWidget,
							xpWidgetClass_Button);

		XPSetWidgetProperty(DownArrow[Item], xpProperty_ButtonType, xpLittleDownArrow);
	}

	PositionApplyButton = XPCreateWidget(x+50, y-310, x+140, y-332,
					1, "Apply Data", 0, PositionWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(PositionApplyButton, xpProperty_ButtonType, xpPushButton);


	LatLonRefApplyButton = XPCreateWidget(x+145, y-310, x+240, y-332,
					1, "Apply LatLonRef", 0, PositionWidget, 
					xpWidgetClass_Button);

	XPSetWidgetProperty(LatLonRefApplyButton, xpProperty_ButtonType, xpPushButton);


	for (Item=0; Item<3; Item++)
	{
		Position2Text[Item] = XPCreateWidget(x+60, y-(350 + (Item*30)), x+115, y-(372 + (Item*30)),
							1,	// Visible
							Description[Item],// desc
							0,		// root
							PositionWidget,
							xpWidgetClass_Caption);
	
		sprintf(buffer, "%lf", HACKFLOAT(DoubleValue[Item]));
		Position2Edit[Item] = XPCreateWidget(x+120, y-(350 + (Item*30)), x+210, y-(372 + (Item*30)),
							1, buffer, 0, PositionWidget,
							xpWidgetClass_TextField);

		XPSetWidgetProperty(PositionEdit[Item], xpProperty_TextFieldType, xpTextEntryField);
	}
	
	LatLonAltApplyButton = XPCreateWidget(x+70, y-440, x+220, y-462,
						1, "Apply LatLonAlt", 0, PositionWidget, 
						xpWidgetClass_Button);

	XPSetWidgetProperty(LatLonAltApplyButton, xpProperty_ButtonType, xpPushButton);

	ReloadSceneryButton = XPCreateWidget(x+70, y-465, x+220, y-487,
						1, "Reload Scenery", 0, PositionWidget, 
						xpWidgetClass_Button);

	XPSetWidgetProperty(ReloadSceneryButton, xpProperty_ButtonType, xpPushButton);

	XPAddWidgetCallback(PositionWidget, PositionHandler);
}

int	PositionHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						intptr_t				inParam1,
						intptr_t				inParam2)
{
	float FloatValue[MAX_ITEMS];
	char buffer[512];
	int Item;

	for (Item=0; Item<MAX_ITEMS; Item++)
		FloatValue[Item] = XPLMGetDataf(gPositionDataRef[Item]);

	if (inMessage == xpMessage_CloseButtonPushed)
		{
			if (MenuItem1 == 1)
			{
				XPHideWidget(PositionWidget);
			}
			return 1;
		}

	if (inMessage == xpMsg_PushButtonPressed)
	{
		if (inParam1 == (intptr_t)PositionApplyButton)
		{
			ApplyValues();
			return 1;
		}

		if (inParam1 == (intptr_t)LatLonRefApplyButton)
		{
			ApplyLatLonRefValues();
			return 1;
		}

		if (inParam1 == (intptr_t)LatLonAltApplyButton)
		{
			ApplyLatLonAltValues();
			return 1;
		}

		if (inParam1 == (intptr_t)ReloadSceneryButton)
		{
			XPLMReloadScenery();
			return 1;
		}

		for (Item=0; Item<MAX_ITEMS-3; Item++)
		{
			if (inParam1 == (intptr_t)UpArrow[Item])
			{
				FloatValue[Item] += 1.0;
				sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
				XPSetWidgetDescriptor(PositionEdit[Item], buffer);
				XPLMSetDataf(gPositionDataRef[Item], FloatValue[Item]);
				return 1;
			}
		}

		for (Item=0; Item<MAX_ITEMS-3; Item++)
		{
			if (inParam1 == (intptr_t)DownArrow[Item])
			{
				FloatValue[Item] -= 1.0;
				sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
				XPSetWidgetDescriptor(PositionEdit[Item], buffer);
				XPLMSetDataf(gPositionDataRef[Item], FloatValue[Item]);
				return 1;
			}
		}
	}
	return 0;
}						

void ApplyValues(void)
{
	char	buffer[512];

	for (int Item=0; Item<MAX_ITEMS-3; Item++)
	{
		XPGetWidgetDescriptor(PositionEdit[Item], buffer, 512);
		XPLMSetDataf(gPositionDataRef[Item], atof(buffer));
	}
}

void ApplyLatLonRefValues(void)
{
	float FloatValue;
	char	buffer[512];

	XPGetWidgetDescriptor(PositionEdit[3], buffer, 512);
	FloatValue = atof(buffer);
	XPLMSetDataf(gPositionDataRef[3], FloatValue);

	XPGetWidgetDescriptor(PositionEdit[4], buffer, 512);
	FloatValue = atof(buffer);
	XPLMSetDataf(gPositionDataRef[4], FloatValue);
}

void ApplyLatLonAltValues(void)
{
	float FloatValue[3];
	double DoubleValue[3];
	char	buffer[512];
	int Item;

	// This gets the lat/lon/alt from the widget text fields
	for (Item=0; Item<3; Item++)
	{
		XPGetWidgetDescriptor(Position2Edit[Item], buffer, 512);
		FloatValue[Item] = atof(buffer);
	}

	/// Lat, Lon, Alt, X, Y, Z
	XPLMWorldToLocal(FloatValue[0], FloatValue[1], FloatValue[2] / 3.28, &DoubleValue[0], &DoubleValue[1], &DoubleValue[2]);  

	for (Item=0; Item<3; Item++)
	{
		// This writes out the lat/lon/alt from the widget text fields back to the datarefs
		XPLMSetDataf(gPositionDataRef[Item+8], FloatValue[Item]);
		// This writes out the x,y,z datarefs after conversion from lat/lon/alt back to the datarefs
		XPLMSetDataf(gPositionDataRef[Item], DoubleValue[Item]);
	}

	ApplyLatLonRefValues();
}
4 Comments