Archives: Code Samples

Override

#include "XPLMPlugin.h"
#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include "XPLMProcessing.h"
#include "XPLMMenus.h"
#include "XPLMUtilities.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include "XPLMDataAccess.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#if IBM
#include <windows.h>
#endif
#include <vector>

#define NUMBER_OF_OVERRIDES 20

static int MenuItem1, MenuItem2, MenuItem3;

static XPWidgetID OverrideWidget = NULL, OverridePanel = NULL, OverridePreviousButton = NULL, OverrideNextButton = NULL;
static XPWidgetID OverrideEdit[8] = {NULL};
static XPWidgetID OverrideCheckBox[8] = {NULL};

static char DataRefGroup[] = "sim/operation/override/";
static char DataRefDesc[NUMBER_OF_OVERRIDES][40] = {"override_planepath", "override_joystick", "override_artstab",
											 "override_flightcontrol", "override_gearbrake", "override_navneedles",
												"override_adf", "override_dme", "override_gps", "override_flightdir", "override_annunciators",
												"override_autopilot","override_pfc_autopilot_lites",
												"override_joystick_heading", "override_joystick_pitch",
												"override_joystick_roll", "override_throttles",
												"override_groundplane", "disable_cockpit_object", "disable_twosided_fuselage"};

static int NumberOfOverrides, OverrideScreenNumber, MaxScreenNumber;
typedef	std::vector<XPLMDataRef> aXPLMDataRefID;

static aXPLMDataRefID DataRefID;
static XPLMDataRef gSpecialDataRef;

static void OverrideMenuHandler(void *, void *);
static void CreateOverride(int x1, int y1, int w, int h);
static int OverrideHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						intptr_t				inParam1,
						intptr_t				inParam2);
static void RefreshOverride(void);
static void GetDataRefIds(void);

static int GetDataRefState(XPLMDataRef DataRefID);
static void SetDataRefState(XPLMDataRef DataRefID, int State);

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

	strcpy(outName, "Override");
	strcpy(outSig, "xpsdk.examples.override");
	strcpy(outDesc, "A plug-in that Overrides Xplane.");

	item = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "Override Xplane", NULL, 1);

	id = XPLMCreateMenu("Override", XPLMFindPluginsMenu(), item, OverrideMenuHandler, NULL);

	XPLMAppendMenuItem(id, "Enable/Disable Override", (void *) "EnableDisableOverride", 1);

	MenuItem1 = 0;
	MenuItem2 = 0;
	MenuItem3 = 0;

	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	if (MenuItem1 == 1)
	{
		XPDestroyWidget(OverrideWidget, 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)
{
}

float OverrideLoopCB(float elapsedMe, float elapsedSim, int counter, void * refcon)
{
	return 1;
}

void OverrideMenuHandler(void * mRef, void * iRef)
{
	if (!strcmp((char *) iRef, "EnableDisableOverride"))
	{
		if (MenuItem1 == 0)
		{
			OverrideScreenNumber = 0;
			CreateOverride(300, 550, 350, 380);
			MenuItem1 = 1;
		}
		else
			if(!XPIsWidgetVisible(OverrideWidget))
				XPShowWidget(OverrideWidget);
	}
}


void CreateOverride(int x, int y, int w, int h)
{
	int x2 = x + w;
	int y2 = y - h;
	int Item;
	int WindowCentre = x+w/2;
	int yOffset;
	char Buffer[255];

	DataRefID.clear();
	memset(OverrideCheckBox, 0, sizeof(OverrideCheckBox));

	GetDataRefIds();

	OverrideWidget = XPCreateWidget(x, y, x2, y2,
					1, "Xplane Override", 1, NULL,
					xpWidgetClass_MainWindow);

	XPSetWidgetProperty(OverrideWidget, xpProperty_MainWindowHasCloseBoxes, 1);

	OverridePanel = XPCreateWidget(x+50, y-50, x2-50, y2+50,
					1, "", 0, OverrideWidget,
					xpWidgetClass_SubWindow);

	XPSetWidgetProperty(OverridePanel, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);


	OverridePreviousButton = XPCreateWidget(WindowCentre-80, y2+24, WindowCentre-10, y2+2,
					1, "Previous", 0, OverrideWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(OverridePreviousButton, xpProperty_ButtonType, xpPushButton);

	OverrideNextButton = XPCreateWidget(WindowCentre+10, y2+24, WindowCentre+80, y2+2,
					1, "Next", 0, OverrideWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(OverrideNextButton, xpProperty_ButtonType, xpPushButton);

	for (Item=0; Item<8; Item++)
	{
		yOffset = (45+28+(Item*30));
		strcpy(Buffer, "");
		OverrideEdit[Item] = XPCreateWidget(x+60, y-yOffset, x+60+200, y-yOffset-20,
					1, Buffer, 0, OverrideWidget,
					xpWidgetClass_TextField);
		XPSetWidgetProperty(OverrideEdit[Item], xpProperty_TextFieldType, xpTextEntryField);
	}

	for (Item=0; Item<8; Item++)
	{
		yOffset = (45+28+(Item*30));
		OverrideCheckBox[Item] = XPCreateWidget(x+260, y-yOffset, x+260+22, y-yOffset-20,
					1, "", 0, OverrideWidget,
					xpWidgetClass_Button);

		XPSetWidgetProperty(OverrideCheckBox[Item], xpProperty_ButtonType, xpRadioButton);
		XPSetWidgetProperty(OverrideCheckBox[Item], xpProperty_ButtonBehavior, xpButtonBehaviorCheckBox);
		XPSetWidgetProperty(OverrideCheckBox[Item], xpProperty_ButtonState, 1);
	}

	RefreshOverride();

	XPAddWidgetCallback(OverrideWidget, OverrideHandler);
}

int	OverrideHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						intptr_t				inParam1,
						intptr_t				inParam2)
{
	int Item, State;

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

	if (inMessage == xpMsg_PushButtonPressed)
	{
		if (inParam1 == (intptr_t)OverridePreviousButton)
		{
			OverrideScreenNumber--;
			if (OverrideScreenNumber<0)
				OverrideScreenNumber = 0;
			RefreshOverride();
			return 1;
		}

		if (inParam1 == (intptr_t)OverrideNextButton)
		{
			OverrideScreenNumber++;
			if (OverrideScreenNumber>MaxScreenNumber)
				OverrideScreenNumber = MaxScreenNumber;
			RefreshOverride();
			return 1;
		}
	}

	if (inMessage == xpMsg_ButtonStateChanged)
	{
		for (Item=0; Item<8; Item++)
		{
			if (DataRefID[Item+(OverrideScreenNumber*8)])
			{
				State = XPGetWidgetProperty(OverrideCheckBox[Item], xpProperty_ButtonState, 0);
				SetDataRefState(DataRefID[Item+(OverrideScreenNumber*8)], State);
			}
		}
	}
	return 0;
}						


void RefreshOverride(void)
{
	int Item;
	char Buffer[255];
	
	for (Item=0; Item<8; Item++)
	{
		strcpy(Buffer, "");
		if ((Item+(OverrideScreenNumber*8)) < NumberOfOverrides)
		{
			if (DataRefID[Item+(OverrideScreenNumber*8)])
			{
				XPSetWidgetDescriptor(OverrideEdit[Item], DataRefDesc[Item+(OverrideScreenNumber*8)]);
				if (GetDataRefState(DataRefID[Item+(OverrideScreenNumber*8)]))
					XPSetWidgetProperty(OverrideCheckBox[Item], xpProperty_ButtonState, 1);
				else
					XPSetWidgetProperty(OverrideCheckBox[Item], xpProperty_ButtonState, 0);
				XPSetWidgetProperty(OverrideCheckBox[Item], xpProperty_Enabled, 1);
			}
		}
		else
		{
			XPSetWidgetDescriptor(OverrideEdit[Item], Buffer);
			XPSetWidgetProperty(OverrideCheckBox[Item], xpProperty_ButtonState, 0);
		}
	}
	if (OverrideScreenNumber == 0)
		XPSetWidgetProperty(OverridePreviousButton, xpProperty_Enabled, 0);
	else
		XPSetWidgetProperty(OverridePreviousButton, xpProperty_Enabled, 1);
		XPSetWidgetDescriptor(OverridePreviousButton, "Previous");

	if (OverrideScreenNumber == MaxScreenNumber)
		XPSetWidgetProperty(OverrideNextButton, xpProperty_Enabled, 0);
	else
		XPSetWidgetProperty(OverrideNextButton, xpProperty_Enabled, 1);	
		XPSetWidgetDescriptor(OverrideNextButton, "Next");
}						

void GetDataRefIds(void)
{
	int Item, ItemIndex=0;
	XPLMDataRef TempDataRefID;
	char TempDesc[256];

	NumberOfOverrides = NUMBER_OF_OVERRIDES;

	for (Item=0; Item<NumberOfOverrides; Item++)
	{
		strcpy(TempDesc, DataRefGroup);
		strcat(TempDesc, DataRefDesc[Item]);
		TempDataRefID = XPLMFindDataRef(TempDesc);
		if (Item == 0)
			gSpecialDataRef = TempDataRefID;
		DataRefID.push_back(TempDataRefID);
	}

	MaxScreenNumber = (NumberOfOverrides-1) / 8;
}

int GetDataRefState(XPLMDataRef DataRefID)
{
	int	DataRefi, IntVals[8];
	
	memset(IntVals, 0, sizeof(IntVals));
	if (DataRefID == gSpecialDataRef)
	{
		XPLMGetDatavi(DataRefID, IntVals, 0, 8);
		DataRefi = IntVals[0];
	}
	else
		DataRefi = XPLMGetDatai(DataRefID);

	return DataRefi;
}

void SetDataRefState(XPLMDataRef DataRefID, int State)
{
	int	IntVals[8];
	
	memset(IntVals, 0, sizeof(IntVals));
	if (DataRefID == gSpecialDataRef)
	{
		IntVals[0] = State;
		XPLMSetDatavi(DataRefID, IntVals, 0, 8);
	}
	else
		XPLMSetDatai(DataRefID, State);
}
Leave a comment

OpenAL 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.
static void CHECK_ERR(void)
{
	ALuint e = alGetError();
	if (e != AL_NO_ERROR)
		printf("ERROR: %d\n", e);
}

// 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
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)
{
	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();
	
	// Try to create our own default device and context.  If we fail, we're dead, we won't play any sound.
	
	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);

	ALfloat	zero[3] = { 0 } ;

	// Build a path to "sound.wav" in our parent directory.	
	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);
	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();

	// Finally: put back the old context _if_ we had one.  If old_ctx was null, X-Plane isn't using OpenAL.

	if(old_ctx)
		alcMakeContextCurrent(old_ctx);
	return 0.0f;
}

PLUGIN_API int XPluginStart(char * name, char * sig, char * desc)
{
	strcpy(name,"OpenAL Sound Demo");
	strcpy(sig,"xpsdk.demo.openal");
	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);	
	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(my_ctx) alcDestroyContext(my_ctx);
	if(my_dev) alcCloseDevice(my_dev);
	my_ctx = NULL;
	my_dev = NULL;
}

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(my_ctx)
		{
			// 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).
			ALCcontext * old_ctx = alcGetCurrentContext();
			alcMakeContextCurrent(my_ctx);
			
			alSourcef(snd_src,AL_PITCH,pitch);
			alSourcePlay(snd_src);
			pitch *= 1.1f;
			CHECK_ERR();
			
			if(old_ctx)
				alcMakeContextCurrent(old_ctx);
		}
		break;
	}		
}
Leave a comment

ManagePlugins

/*
 * ManagePlugins.c
 * 
 * This plugin demonstrates how to manage other plugins.  Most of the time you
 * won't have to do this.  In this plugin we either enable or disable all other
 * plugins.
 * 
 */

#include <stdio.h>
#include <string.h>
#include "XPLMPlugin.h"
#include "XPLMMenus.h"
#include "XPLMUtilities.h"

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

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

	strcpy(outName, "ManagePlugins");
	strcpy(outSig, "xplanesdk.examples.manageplugins");
	strcpy(outDesc, "A plugin that manages other plugins.");

	/* Add menbu items to disable and enable plugins.  The refcon
	 * will distinguish which command we are doing. */

	mySubMenuItem = XPLMAppendMenuItem(
						XPLMFindPluginsMenu(),	/* Put in plugins menu */
						"Manage Plugins",				/* Item Title */
						0,						/* Item Ref */
						1);						/* Force English */
	
	myMenu = XPLMCreateMenu(
						"Manage Plugins", 
						XPLMFindPluginsMenu(), 
						mySubMenuItem, 			/* Menu Item to attach to. */
						MyMenuHandlerCallback,	/* The handler */
						0);						/* Handler Ref */

	XPLMAppendMenuItem(myMenu, "Disable Others", (void *) 0, 1);
	XPLMAppendMenuItem(myMenu, "Enable All", (void *) 1, 1);

	return 1;
}

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 the menu handler.  We will go through each plugin. */

		int	n;

	for (n = 0; n < XPLMCountPlugins(); ++n)
	{
		char			str[128];
		XPLMPluginID	plugin = XPLMGetNthPlugin(n);
		XPLMPluginID	me = XPLMGetMyID();

		/* Check to see if the plugin is us.  If so, don't
		 * disable ourselves! */
		sprintf(str,"plugin=%d,me=%d\n",plugin, me);
		XPLMDebugString(str);
		if (plugin != me)
		{
			/* Disable based on the item ref for the menu. */
			if (inItemRef == NULL)
			{
				XPLMDisablePlugin(plugin);
			} else {
				XPLMEnablePlugin(plugin);
			}
		}
	}
}
Leave a comment

KeySniffer

/*
 * KeySniffer.c
 * 
 * KeySniffer shows the use of key sniffers to intercept and process raw 
 * keystrokes.  This one creates a window where all data about the keystroke
 * is displayed.
 * 
 * Key strokes have two sets of character data.  The ASCII key code is a valid
 * ASCII value.  This value discriminates between the A key with and without shift
 * (e.g. 'A' and 'a') but does not discriminate between numbers on the main 
 * keyboard vs. numeric keypad.  Virtual key codes tell exactly what physical key
 * was pressed (e.g. top-row-0 vs. num-pad-0) but do not change by modifier keys.
 * Modifier keys are returned separately.
 * 
 * ASCII codes are good for handling text entry; virtual key codes are good for 
 * setting up key commands (since they allow for separate binding of the numeric
 * key pad).
 * 
 */

#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include "XPLMUtilities.h"
#include <stdio.h>
#include <string.h>

/* We will store the information we got from our last key press globally 
 * so the window can show the most recent key press. */
static XPLMWindowID	gWindow = NULL;
static XPLMKeyFlags	gFlags = 0;
static char			gVirtualKey = 0;
static char			gChar = 0;

static void MyDrawWindowCallback(
                                   XPLMWindowID         inWindowID,    
                                   void *               inRefcon);    

static void MyHandleKeyCallback(
                                   XPLMWindowID         inWindowID,    
                                   char                 inKey,    
                                   XPLMKeyFlags         inFlags,    
                                   char                 inVirtualKey,    
                                   void *               inRefcon,    
                                   int                  losingFocus);    

static int MyHandleMouseClickCallback(
                                   XPLMWindowID         inWindowID,    
                                   int                  x,    
                                   int                  y,    
                                   XPLMMouseStatus      inMouse,    
                                   void *               inRefcon);    

static int MyKeySniffer(
                                   char                 inChar,    
                                   XPLMKeyFlags         inFlags,    
                                   char                 inVirtualKey,    
                                   void *               inRefcon);    



PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	/* First set up our plugin info. */
	strcpy(outName, "KeySniffer");
	strcpy(outSig, "xplanesdk.examples.keysniffer");
	strcpy(outDesc, "A plugin that makes a window.");

	/* Now create a new window.  Pass in our three callbacks. */
	gWindow = XPLMCreateWindow(
					50, 750, 350, 700,			/* Area of the window. */
					1,							/* Start visible. */
					MyDrawWindowCallback,		/* Callbacks */
					MyHandleKeyCallback,
					MyHandleMouseClickCallback,
					NULL);						/* Refcon - not used. */
					
	/* Finally register our key sniffer. */
	XPLMRegisterKeySniffer(
					MyKeySniffer, 				/* Our callback. */
					1, 							/* Receive input before plugin windows. */
					0);							/* Refcon - not used. */
	
	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	XPLMDestroyWindow(gWindow);
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

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

/*
 * MyDrawWindowCallback
 * 
 * This routine draws the window, showing the last keyboard stroke to be 
 * recorded by our sniffer.
 * 
 */
void MyDrawWindowCallback(
                                   XPLMWindowID         inWindowID,
                                   void *               inRefcon)
{
		char	str[50];
		int		left, top, right, bottom;
		float	color[] = { 1.0, 1.0, 1.0 };

	/* First get our window's location. */
	XPLMGetWindowGeometry(inWindowID, &left, &top, &right, &bottom);

	/* Draw a translucent dark box as our window outline. */
	XPLMDrawTranslucentDarkBox(left, top, right, bottom);

	/* Take the last key stroke and form a descriptive string.
	 * Note that ASCII values may be printed directly.  Virtual key
	 * codes are not ASCII and cannot be, but the utility function
	 * XPLMGetVirtualKeyDescription provides a human-readable string
	 * for each key.  These strings may be multicharacter, e.g. 'ENTER'
	 * or 'NUMPAD-0'. */
	sprintf(str,"%d '%c' | %d '%s' (%c %c %c %c %c)",
		gChar,
		(gChar) ? gChar : '0',
		(int) (unsigned char) gVirtualKey,
		XPLMGetVirtualKeyDescription(gVirtualKey),
		(gFlags & xplm_ShiftFlag) ? 'S' : ' ',
		(gFlags & xplm_OptionAltFlag) ? 'A' : ' ',
		(gFlags & xplm_ControlFlag) ? 'C' : ' ',
		(gFlags & xplm_DownFlag) ? 'D' : ' ',
		(gFlags & xplm_UpFlag) ? 'U' : ' ');

	/* Draw the string into the window. */
	XPLMDrawString(color, left + 5, top - 20, str, NULL, xplmFont_Basic);
}

void MyHandleKeyCallback(
                                   XPLMWindowID         inWindowID,
                                   char                 inKey,
                                   XPLMKeyFlags         inFlags,
                                   char                 inVirtualKey,
                                   void *               inRefcon,
                                   int                  losingFocus)
{
}                                   

int MyHandleMouseClickCallback(
                                   XPLMWindowID         inWindowID,    
                                   int                  x,    
                                   int                  y,    
                                   XPLMMouseStatus      inMouse,    
                                   void *               inRefcon)
{
	return 0;
}                                      

/*
 * MyKeySniffer
 * 
 * This routnine receives keystrokes from the simulator as they are pressed.
 * A separate message is received for each key press and release as well as 
 * keys being held down.  
 * 
 */
int MyKeySniffer(
                                   char                 inChar,    
                                   XPLMKeyFlags         inFlags,    
                                   char                 inVirtualKey,    
                                   void *               inRefcon)
{
	/* First record the key data. */
	gVirtualKey = inVirtualKey;
	gFlags = inFlags;
	gChar = inChar;

	/* Return 1 to pass the keystroke to plugin windows and X-Plane.  
	 * Returning 0 would consume the keystroke. */
	return 1;
}
Leave a comment

EngineStarter

/*
	Engine Starter example
	Written by Sandy Barbour - 28/09/2005
	
	This examples shows how to start the engines.
	It also shows some neat widgetry
*/

#include "XPLMPlugin.h"
#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>
#if IBM
#include <windows.h>
#endif

// Limit to 8 engines, any more and you are on your own :-)
#define MAX_NUMBER_ENGINES 8

// Enums for each engine
typedef struct _MESSAGE_STRUCT
{
	int MessageEnum;
} MESSAGE_STRUCT;

MESSAGE_STRUCT JoystickCommands[MAX_NUMBER_ENGINES] =
{
	{xplm_joy_start_0},
	{xplm_joy_start_1},
	{xplm_joy_start_2},
	{xplm_joy_start_3},
	{xplm_joy_start_4},
	{xplm_joy_start_5},
	{xplm_joy_start_6},
	{xplm_joy_start_7}
};

// These will hold the XPLMDataRef values	
static XPLMDataRef gIgnitersDataRef = NULL;
static XPLMDataRef gStarterDurationDataRef = NULL;
static XPLMDataRef gNumberOfEnginesDataRef = NULL;

// Descriptions for the Input Text widget
static char DataRefDesc[MAX_NUMBER_ENGINES][20] = {"1", "2", "3", "4", "5", "6", "7", "8"};

static float EngineStarterLoopCB(float elapsedMe, float elapsedSim, int counter, void * refcon);;

static int MenuItem1;
// Widgets
static XPWidgetID	EngineStarterWidget = NULL, EngineStarterWindow = NULL;
static XPWidgetID	Description[MAX_NUMBER_ENGINES] = {NULL};
static XPWidgetID	IgnitersState[MAX_NUMBER_ENGINES] = {NULL};
static XPWidgetID	StartButton[MAX_NUMBER_ENGINES] = {NULL};
static XPWidgetID	XPlaneStarterDurationEdit[MAX_NUMBER_ENGINES] = {NULL};
static XPWidgetID	StarterDurationText = NULL;
static XPWidgetID	StarterDurationEdit = NULL;
static XPWidgetID	ReleaseDelayText = NULL;
static XPWidgetID	ReleaseDelayEdit = NULL;

// Globals for engine starting.
static int Igniters[MAX_NUMBER_ENGINES] = {0};
static int ElapsedTime[MAX_NUMBER_ENGINES] = {0};
static int EngineStarting[MAX_NUMBER_ENGINES] = {0};

// Intitial window size
static int x = 300, y = 500, w = 390, h = 290;

// Callback prototypes
static void EngineStarterMenuHandler(void *, void *);

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

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

static void ResizeWidgets(int NumberOfEngines);

// Standard Plugin callbacks
PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	XPLMMenuID	Id;
	int			Item;

	strcpy(outName, "EngineStarter");
	strcpy(outSig, "xpsdk.examples.EngineStarter");
	strcpy(outDesc, "A plug-in that handles data Input/Output.");

	// Create our menu
	Item = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "Engine Starter", NULL, 1);
	Id = XPLMCreateMenu("Engine Starter", XPLMFindPluginsMenu(), Item, EngineStarterMenuHandler, NULL);
	XPLMAppendMenuItem(Id, "Start Engines", (void *)"EngineStarter", 1);

	// Flag to tell us if the widget is being displayed.
	MenuItem1 = 0;


	// Get our dataref handles here
	gIgnitersDataRef = XPLMFindDataRef("sim/cockpit/engine/igniters_on");
	gStarterDurationDataRef = XPLMFindDataRef("sim/cockpit/engine/starter_duration");
	gNumberOfEnginesDataRef = XPLMFindDataRef("sim/aircraft/engine/acf_num_engines");


	// Register our FL callback with initial callback time period of 1 second.
	XPLMRegisterFlightLoopCallback(EngineStarterLoopCB, 1.0, NULL);

	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	/* Unregister the callback */
	XPLMUnregisterFlightLoopCallback(EngineStarterLoopCB, NULL);

	if (MenuItem1 == 1)
	{
		XPDestroyWidget(EngineStarterWidget, 1);
		MenuItem1 = 0;
	}
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, int inMsg, void * inParam)
{
    if (inFrom == XPLM_PLUGIN_XPLANE)
    {
		switch(inMsg)
		{
			case XPLM_MSG_PLANE_LOADED:
				// Need to resize widgets if number of engines change.
				// This messge is received on XPlane start so that is covered.
				int NumberOfEngines = XPLMGetDatai(gNumberOfEnginesDataRef);
				ResizeWidgets(NumberOfEngines);
				break;
		}
	}
}


float EngineStarterLoopCB(float elapsedMe, float elapsedSim, int counter, void * refcon)
{
	int Item;
	int count;
	char Buffer[255];
	float StarterDurationArray[MAX_NUMBER_ENGINES];

	if (MenuItem1 == 0) // Don't process if widget not visible
		return 1;

	// Only deal with the actual engines that we have
	int NumberOfEngines = XPLMGetDatai(gNumberOfEnginesDataRef);

	// Get our Igniters states for each engine
	count = XPLMGetDatavi(gIgnitersDataRef, Igniters, 0, MAX_NUMBER_ENGINES);

	// Get Xplane starter duration for each engine
	count = XPLMGetDatavf(gStarterDurationDataRef, StarterDurationArray, 0, MAX_NUMBER_ENGINES);

	// Uncheck all Igniters check boxes, need this if user load an aircraft
	// with less engines than the current aircraft
	for (Item=0; Item<MAX_NUMBER_ENGINES; Item++)
		XPSetWidgetProperty(IgnitersState[Item], xpProperty_ButtonState, 0);

	// Process each actual engine
	for (Item=0; Item<NumberOfEngines; Item++)
	{
		if (Igniters[Item] == 1)
			XPSetWidgetProperty(IgnitersState[Item], xpProperty_ButtonState, 1);
		else
			XPSetWidgetProperty(IgnitersState[Item], xpProperty_ButtonState, 0);

		sprintf(Buffer, "%f", StarterDurationArray[Item]);
		XPSetWidgetDescriptor(XPlaneStarterDurationEdit[Item], Buffer);
	}

	// I have used extra braces for clarity.
	// Store elapsed start time for each engine
	for (Item=0; Item<NumberOfEngines; Item++)
	{
		if (EngineStarting[Item] == 1)
			ElapsedTime[Item]++;
	}

	// I have used extra braces for clarity.
	// If the time for that engine has elapsed then send release
	XPGetWidgetDescriptor(ReleaseDelayEdit, Buffer, sizeof(Buffer));
	int ReleaseDelay = atoi(Buffer);

	for (Item=0; Item<NumberOfEngines; Item++)
	{
		if (EngineStarting[Item] == 1)
		{
			if (ElapsedTime[Item] > ReleaseDelay)
			{
				XPLMCommandButtonRelease(JoystickCommands[Item].MessageEnum);
				XPSetWidgetProperty(StartButton[Item], xpProperty_Enabled, 1);
			}
		}
	}

	// This means call us ever 1 second.
	return (float) 1.0;
}

void EngineStarterMenuHandler(void * mRef, void * iRef)
{

	// If menu selected create our widget dialog
	if (!strcmp((char *) iRef, "EngineStarter"))
	{
		if (MenuItem1 == 0)
		{
			// Take care of resize based on actual number of engines
			int NumberOfEngines = XPLMGetDatai(gNumberOfEnginesDataRef);
			CreateEngineStarterWidget(x, y, w, h);
			ResizeWidgets(NumberOfEngines);
			MenuItem1 = 1;
		}
		else
			if(!XPIsWidgetVisible(EngineStarterWidget))
				XPShowWidget(EngineStarterWidget);
	}
}						

// This will create our widget dialog.
// I have made all child widgets relative to the input paramter.
// This makes it easy to position the dialog
// Any position or size changes need to be done in the "ResizeWidgets" function as well.
// This could be made more manageable if required
void CreateEngineStarterWidget(int x, int y, int w, int h)
{
	int Item;

	int x2 = x + w;
	int y2 = y - h;
	
	// Create the Main Widget window
	EngineStarterWidget = XPCreateWidget(x, y, x2, y2,
					1,	// Visible
					"Engine Starter Example by Sandy Barbour",	// desc
					1,		// root
					NULL,	// no container
					xpWidgetClass_MainWindow);

	// Add Close Box decorations to the Main Widget
	XPSetWidgetProperty(EngineStarterWidget, xpProperty_MainWindowHasCloseBoxes, 1);

	// Create the Sub Widget window
	EngineStarterWindow = XPCreateWidget(x+10, y-30, x2-10, y2+10,
					1,	// Visible
					"",	// desc
					0,		// root
					EngineStarterWidget,
					xpWidgetClass_SubWindow);

	// Set the style to sub window
	XPSetWidgetProperty(EngineStarterWindow, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

	// For each engine
	for (Item=0; Item<MAX_NUMBER_ENGINES; Item++)
	{
		// Create a text widget
		Description[Item] = XPCreateWidget(x+20, y-(40 + (Item*30)), x+82, y-(62 + (Item*30)),
							1,	// Visible
							DataRefDesc[Item],// desc
							0,		// root
							EngineStarterWidget,
							xpWidgetClass_Caption);

		// Create a check box for the Igniters
		IgnitersState[Item] = XPCreateWidget(x+45, y-(40 + (Item*30)), x+67, y-(62 + (Item*30)),
							1, "", 0, EngineStarterWidget,
							xpWidgetClass_Button);

		// Set it to be check box
		XPSetWidgetProperty(IgnitersState[Item], xpProperty_ButtonType, xpRadioButton);
		XPSetWidgetProperty(IgnitersState[Item], xpProperty_ButtonBehavior, xpButtonBehaviorCheckBox);
		XPSetWidgetProperty(IgnitersState[Item], xpProperty_ButtonState, 1);

		// Create a button widget for the Start Engine
		StartButton[Item] = XPCreateWidget(x+80, y-(40 + (Item*30)), x+130, y-(62 + (Item*30)),
							1, " Start", 0, EngineStarterWidget,
							xpWidgetClass_Button);

		// Set it to be normal push button
		XPSetWidgetProperty(StartButton[Item], xpProperty_ButtonType, xpPushButton);

		// Create an edit widget for the xplane starter duration
		XPlaneStarterDurationEdit[Item] = XPCreateWidget(x+140, y-(40 + (Item*30)), x+200, y-(62 + (Item*30)),
							1, "", 0, EngineStarterWidget,
							xpWidgetClass_TextField);

	}

	// Create a text widget for the starter duration
	StarterDurationText = XPCreateWidget(x+210, y-40, x+310, y-62,
							1,	// Visible
							"Starter Duration",// desc
							0,		// root
							EngineStarterWidget,
							xpWidgetClass_Caption);

	// Create an edit widget for the starter duration
	StarterDurationEdit = XPCreateWidget(x+315, y-40, x+355, y-62,
						1, "10", 0, EngineStarterWidget,
						xpWidgetClass_TextField);

	// Create a text widget for the release delay
	ReleaseDelayText = XPCreateWidget(x+210, y-70, x+310, y-92,
							1,	// Visible
							"Release Delay",// desc
							0,		// root
							EngineStarterWidget,
							xpWidgetClass_Caption);

	// Set it to be text entry
	XPSetWidgetProperty(StarterDurationEdit, xpProperty_TextFieldType, xpTextEntryField);

	// Create an edit widget for the release delay
	ReleaseDelayEdit = XPCreateWidget(x+315, y-70, x+355, y-92,
						1, "10", 0, EngineStarterWidget,
						xpWidgetClass_TextField);

	// Set it to be text entry
	XPSetWidgetProperty(ReleaseDelayEdit, xpProperty_TextFieldType, xpTextEntryField);

	// Register our widget handler
	XPAddWidgetCallback(EngineStarterWidget, EngineStarterHandler);
}

// Included this as it shows how to maintain a dynamic widget
// Any position or size changes need to be done in the "CreateEngineStarterWidget" function as well.
// This could be made more manageable if required
void ResizeWidgets(int NumberOfEngines)
{
	int Item;

	// Adjust main Widget height
	switch (NumberOfEngines)
	{
		case 1:
		case 2:
			h = 110;
			break;
		case 4:
			h = 170;
			break;
		case 8:
			h = 290;
			break;
	}
	int x2 = x + w;
	int y2 = y - h;

	// Only set or enable widgets that are actually needed
	for (Item=0; Item<MAX_NUMBER_ENGINES; Item++)
	{
		XPSetWidgetProperty(IgnitersState[Item], xpProperty_ButtonState, 0);
		XPSetWidgetDescriptor(Description[Item], "");
		XPHideWidget(Description[Item]);
		XPHideWidget(StartButton[Item]);
		XPHideWidget(IgnitersState[Item]);
		XPHideWidget(XPlaneStarterDurationEdit[Item]);
	}

	// Resize the main widget and window
	XPSetWidgetGeometry(EngineStarterWidget, x, y, x2, y2);
	XPSetWidgetGeometry(EngineStarterWindow, x+10, y-30, x2-10, y2+10);

	
	// For each engine widget do a resize
	// Then make sure each widget is shown.
	for (Item=0; Item<NumberOfEngines; Item++)
	{
		XPSetWidgetGeometry(Description[Item], x+20, y-(40 + (Item*30)), x+82, y-(62 + (Item*30)));
		XPSetWidgetGeometry(IgnitersState[Item], x+45, y-(40 + (Item*30)), x+67, y-(62 + (Item*30)));
		XPSetWidgetGeometry(StartButton[Item], x+80, y-(40 + (Item*30)), x+130, y-(62 + (Item*30)));
		XPSetWidgetGeometry(XPlaneStarterDurationEdit[Item], x+140, y-(40 + (Item*30)), x+200, y-(62 + (Item*30)));
		XPSetWidgetDescriptor(Description[Item], DataRefDesc[Item]);
		XPShowWidget(Description[Item]);
		XPShowWidget(StartButton[Item]);
		XPShowWidget(IgnitersState[Item]);
		XPShowWidget(XPlaneStarterDurationEdit[Item]);
	}

	// No take care of the rest
	XPSetWidgetGeometry(StarterDurationText, x+210, y-40, x+310, y-62);
	XPSetWidgetGeometry(StarterDurationEdit, x+315, y-40, x+355, y-62);
	XPSetWidgetGeometry(ReleaseDelayText, x+210, y-70, x+310, y-92);
	XPSetWidgetGeometry(ReleaseDelayEdit, x+315, y-70, x+355, y-92);
}

// This is the handler for our widget
// It can be used to process button presses etc.
// In this example we are only interested when the close box is pressed
int	EngineStarterHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						intptr_t				inParam1,
						intptr_t				inParam2)
{
	char Buffer[255];
	int Item, State;
	float StarterDuration, StarterDurationArray[MAX_NUMBER_ENGINES];

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

	// Handle any button pushes
	if (inMessage == xpMsg_PushButtonPressed)
	{
		// This is redundant in V8.
		// It will work in V7 but my other method can be used
		// which reduces the code size.
		XPGetWidgetDescriptor(StarterDurationEdit, Buffer, sizeof(Buffer));
		StarterDuration = (float)atof(Buffer);

		// Set all starter durations in XPlane
		for (Item=0; Item<MAX_NUMBER_ENGINES; Item++)
			StarterDurationArray[Item] = StarterDuration;

		XPLMSetDatavf(gStarterDurationDataRef, StarterDurationArray, 0, MAX_NUMBER_ENGINES);

		for (Item=0; Item<MAX_NUMBER_ENGINES; Item++)
		{
			// Handle if the Start Button is pushed
			if (inParam1 == (intptr_t)StartButton[Item])
			{
				// Do the actual joystick button press
				XPLMCommandButtonPress(JoystickCommands[Item].MessageEnum);
				// Set flag for the engine selected
				EngineStarting[Item] = 1;
				// Reset the timer for that engine
				ElapsedTime[Item] = 0;
				// Disable the start button for that engine
				XPSetWidgetProperty(StartButton[Item], xpProperty_Enabled, 0);
			}
		}
		return 1;
	}

	// Handle any check box selections
	if (inMessage == xpMsg_ButtonStateChanged)
	{
		// Get the Igniters check box for each engine.
		for (Item=0; Item<MAX_NUMBER_ENGINES; Item++)
		{
			State = (int) XPGetWidgetProperty(IgnitersState[Item], xpProperty_ButtonState, 0);
			Igniters[Item] = State;
		}
		// This will switch the igniter on/off depeding on State.
		XPLMSetDatavi(gIgnitersDataRef, Igniters, 0, MAX_NUMBER_ENGINES);
		return 1;
	}

	return 0;
}
1 Comment

DrawAircraft

/*
	DrawAircraft example
	Written by Sandy Barbour - 11/02/2003

	Modified by Sandy Barbour - 07/12/2009
	Combined source files and fixed a few bugs.
	
	This examples Draws 7 AI aircraft around the user aicraft.
	It also uses an Aircraft class to simplify things.

	This is a very simple example intended to show how to use the AI datarefs.
	In a production plugin Aircraft Aquisition and Release would have to be handled.
	Also loading the approriate aircraft model would also have to be done.
	This example may be updated to do that at a later time.

	NOTE
	Set the aircraft number to 8 in the XPlane Aircraft & Situations settings screen.
*/

#include <string.h>
#include <math.h>
#include "XPLMPlanes.h"
#include "XPLMDataAccess.h"
#include "XPLMProcessing.h"

const	double	kMaxPlaneDistance = 5280.0 / 3.2 * 10.0;
const	double	kFullPlaneDist = 5280.0 / 3.2 * 3.0;

// Aircraft class, allows access to an AI aircraft

class Aircraft
{
private:
	XPLMDataRef	dr_plane_x;
	XPLMDataRef	dr_plane_y;
	XPLMDataRef	dr_plane_z;
	XPLMDataRef	dr_plane_the;
	XPLMDataRef	dr_plane_phi;
	XPLMDataRef	dr_plane_psi;
	XPLMDataRef	dr_plane_gear_deploy;
	XPLMDataRef	dr_plane_throttle;
public:
	float		plane_x;
	float		plane_y;
	float		plane_z;
	float		plane_the;
	float		plane_phi;
	float		plane_psi;
	float		plane_gear_deploy[5];
	float		plane_throttle[8];
	Aircraft(int AircraftNo);
	void GetAircraftData(void);
	void SetAircraftData(void);
};

Aircraft::Aircraft(int AircraftNo)
{
	char	x_str[80];
	char	y_str[80];
	char	z_str[80];
	char	the_str[80];
	char	phi_str[80];
	char	psi_str[80];
	char	gear_deploy_str[80];
	char	throttle_str[80];

	strcpy(x_str, "sim/multiplayer/position/planeX_x");
	strcpy(y_str,	"sim/multiplayer/position/planeX_y");
	strcpy(z_str,	"sim/multiplayer/position/planeX_z");
	strcpy(the_str,	"sim/multiplayer/position/planeX_the");
	strcpy(phi_str,	"sim/multiplayer/position/planeX_phi");
	strcpy(psi_str,	"sim/multiplayer/position/planeX_psi");
	strcpy(gear_deploy_str,	"sim/multiplayer/position/planeX_gear_deploy");
	strcpy(throttle_str, "sim/multiplayer/position/planeX_throttle");

	char cTemp = (AircraftNo + 0x30);
	x_str[30]			=	cTemp;
	y_str[30]			=	cTemp;
	z_str[30]			=	cTemp;
	the_str[30]			=	cTemp;
	phi_str[30]			=	cTemp;
	psi_str[30]			=	cTemp;
	gear_deploy_str[30] =	cTemp;
	throttle_str[30]	=	cTemp;

	dr_plane_x				= XPLMFindDataRef(x_str);
	dr_plane_y				= XPLMFindDataRef(y_str);
	dr_plane_z				= XPLMFindDataRef(z_str);
	dr_plane_the			= XPLMFindDataRef(the_str);
	dr_plane_phi			= XPLMFindDataRef(phi_str);
	dr_plane_psi			= XPLMFindDataRef(psi_str);
	dr_plane_gear_deploy	= XPLMFindDataRef(gear_deploy_str);
	dr_plane_throttle		= XPLMFindDataRef(throttle_str);
}

void Aircraft::GetAircraftData(void)
{
	plane_x = XPLMGetDataf(dr_plane_x);
	plane_y = XPLMGetDataf(dr_plane_y);
	plane_z = XPLMGetDataf(dr_plane_z);
	plane_the = XPLMGetDataf(dr_plane_the);
	plane_phi = XPLMGetDataf(dr_plane_phi);
	plane_psi = XPLMGetDataf(dr_plane_psi);
	XPLMGetDatavf(dr_plane_gear_deploy, plane_gear_deploy, 0, 5);
	XPLMGetDatavf(dr_plane_throttle, plane_throttle, 0, 8);
}

void Aircraft::SetAircraftData(void)
{
	XPLMSetDataf(dr_plane_x, plane_x);
	XPLMSetDataf(dr_plane_y, plane_y);
	XPLMSetDataf(dr_plane_z, plane_z);
	XPLMSetDataf(dr_plane_the, plane_the);
	XPLMSetDataf(dr_plane_phi, plane_phi);
	XPLMSetDataf(dr_plane_psi, plane_psi);
	XPLMSetDatavf(dr_plane_gear_deploy, plane_gear_deploy, 0, 5);
	XPLMSetDatavf(dr_plane_throttle, plane_throttle, 0, 8);
}

// Datarefs for the User Aircraft

static XPLMDataRef		gPlaneX = NULL;
static XPLMDataRef		gPlaneY = NULL;
static XPLMDataRef		gPlaneZ = NULL;
static XPLMDataRef		gPlaneTheta = NULL;
static XPLMDataRef		gPlanePhi = NULL;
static XPLMDataRef		gPlanePsi = NULL;
static XPLMDataRef		gOverRidePlanePosition = NULL;
static XPLMDataRef		gAGL = NULL;


// Create 7 instances of the Aircraft class.

Aircraft Aircraft1(1);
Aircraft Aircraft2(2);
Aircraft Aircraft3(3);
Aircraft Aircraft4(4);
Aircraft Aircraft5(5);
Aircraft Aircraft6(6);
Aircraft Aircraft7(7);

// Used to disable AI so we have control.

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

// Used to update each aircraft every frame.

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


PLUGIN_API int XPluginStart(	char *		outName,
								char *		outSig,
								char *		outDesc)
{
	strcpy(outName, "DrawAircraft");
	strcpy(outSig, "xplanesdk.examples.drawaircraft");
	strcpy(outDesc, "A plugin that draws aircraft.");

	/* Prefetch the sim variables we will use. */
	gPlaneX = XPLMFindDataRef("sim/flightmodel/position/local_x");
	gPlaneY = XPLMFindDataRef("sim/flightmodel/position/local_y");
	gPlaneZ = XPLMFindDataRef("sim/flightmodel/position/local_z");
	gPlaneTheta = XPLMFindDataRef("sim/flightmodel/position/theta");
	gPlanePhi = XPLMFindDataRef("sim/flightmodel/position/phi");
	gPlanePsi = XPLMFindDataRef("sim/flightmodel/position/psi");
	gOverRidePlanePosition = XPLMFindDataRef("sim/operation/override/override_planepath");
	gAGL = XPLMFindDataRef("sim/flightmodel/position/y_agl");

	XPLMRegisterFlightLoopCallback(		
			MyFlightLoopCallback0,	/* Callback */
			1.0,					/* Interval */
			NULL);					/* refcon not used. */

	XPLMRegisterFlightLoopCallback(		
			MyFlightLoopCallback,	/* Callback */
			1.0,					/* Interval */
			NULL);					/* refcon not used. */

	return 1;
}


PLUGIN_API void	XPluginStop(void)
{
	XPLMUnregisterFlightLoopCallback(MyFlightLoopCallback0, NULL);
	XPLMUnregisterFlightLoopCallback(MyFlightLoopCallback, NULL);
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

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

float	MyFlightLoopCallback0(
                                   float                inElapsedSinceLastCall,    
                                   float                inElapsedTimeSinceLastFlightLoop,    
                                   int                  inCounter,    
                                   void *               inRefcon)
{
	int AircraftIndex;

	// Disable AI for each aircraft.
	for (AircraftIndex=1; AircraftIndex<8; AircraftIndex++)
		XPLMDisableAIForPlane(AircraftIndex);    

	return 0;
}


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

	double	x,y,z,theta,phi,psi;

	double Lat = 34.09, Lon = -117.25, Alt = 1170;
	float Heading = 0, Pitch = 0, Roll = 0, Altitude;

	// Get User Aircraft data
	x = XPLMGetDataf(gPlaneX);
	y = XPLMGetDataf(gPlaneY);
	z = XPLMGetDataf(gPlaneZ);
	theta = XPLMGetDataf(gPlaneTheta);
	phi = XPLMGetDataf(gPlanePhi);
	psi = XPLMGetDataf(gPlanePsi);
	Altitude = XPLMGetDataf(gAGL);

	// Copy it to each aircraft using different offsets for each aircraft.

	Aircraft1.plane_x = x + 50.0;
	Aircraft1.plane_y = y;
	Aircraft1.plane_z = z + 50.0;
	Aircraft1.plane_the = theta;
	Aircraft1.plane_phi = phi;
	Aircraft1.plane_psi = psi;

	Aircraft2.plane_x = x - 50.0;
	Aircraft2.plane_y = y;
	Aircraft2.plane_z = z - 50.0;
	Aircraft2.plane_the = theta;
	Aircraft2.plane_phi = phi;
	Aircraft2.plane_psi = psi;

	Aircraft3.plane_x = x + 50.0;
	Aircraft3.plane_y = y;
	Aircraft3.plane_z = z - 50.0;
	Aircraft3.plane_the = theta;
	Aircraft3.plane_phi = phi;
	Aircraft3.plane_psi = psi;

	Aircraft4.plane_x = x - 50.0;
	Aircraft4.plane_y = y;
	Aircraft4.plane_z = z + 50.0;
	Aircraft4.plane_the = theta;
	Aircraft4.plane_phi = phi;
	Aircraft4.plane_psi = psi;

	Aircraft5.plane_x = x + 100.0;
	Aircraft5.plane_y = y;
	Aircraft5.plane_z = z + 100.0;
	Aircraft5.plane_the = theta;
	Aircraft5.plane_phi = phi;
	Aircraft5.plane_psi = psi;

	Aircraft6.plane_x = x - 100.0;
	Aircraft6.plane_y = y;
	Aircraft6.plane_z = z - 100.0;
	Aircraft6.plane_the = theta;
	Aircraft6.plane_phi = phi;
	Aircraft6.plane_psi = psi;

	Aircraft7.plane_x = x + 100.0;
	Aircraft7.plane_y = y;
	Aircraft7.plane_z = z - 100.0;
	Aircraft7.plane_the = theta;
	Aircraft7.plane_phi = phi;
	Aircraft7.plane_psi = psi;

	// Raise the gear when above 200 feet.
	if (Altitude > 200)
		GearState = 0;
	else
		GearState = 1;

	/// Changed from 5 to 6 - Sandy Barbour 18/01/2005
	/// This will be changed to handle versions when the
	/// increase to 10 is implemented in the glue.
	for (int Gear=0; Gear<6; Gear++)
	{
		Aircraft1.plane_gear_deploy[Gear] = GearState;
		Aircraft2.plane_gear_deploy[Gear] = GearState;
		Aircraft3.plane_gear_deploy[Gear] = GearState;
		Aircraft4.plane_gear_deploy[Gear] = GearState;
		Aircraft5.plane_gear_deploy[Gear] = GearState;
		Aircraft6.plane_gear_deploy[Gear] = GearState;
		Aircraft7.plane_gear_deploy[Gear] = GearState;
	}

	// Now set the data in each instance.
	Aircraft1.SetAircraftData();
	Aircraft2.SetAircraftData();
	Aircraft3.SetAircraftData();
	Aircraft4.SetAircraftData();
	Aircraft5.SetAircraftData();
	Aircraft6.SetAircraftData();
	Aircraft7.SetAircraftData();

	return -1;
}
1 Comment

Custom Prop Disc

A discussion of customized prop discs for authors can be found here.

#include <string.h>
#include <math.h>
#include "XPLMDataAccess.h"
#include "XPLMProcessing.h"

static XPLMDataRef		prop_rotation_speed_rad_sec = NULL;
static XPLMDataRef		prop_rotation_angle_deg = NULL;
static XPLMDataRef		side_angle = NULL;
static XPLMDataRef		prop_is_disc = NULL;
static XPLMDataRef		disc_s = NULL;
static XPLMDataRef		disc_t = NULL;
static XPLMDataRef		side_s = NULL;
static XPLMDataRef		side_t = NULL;
static XPLMDataRef		sim_speed = NULL;
static XPLMDataRef		frame_rate_period = NULL;

// Interp - rescales a floating point variable, clamping to the outer limits.  Handy
// for mapping a range of physics behavior to something in the graphics.
static float interp(float in1, float out1, float in2, float out2, float x)
{
	if(x < in1) return out1;
	if(x > in2) return out2;
	return out1 + (out2 - out1) * (x - in1) / (in2 - in1);
}

// Two util funcs to write the first two slots of array datarefs...we do this a lot, 
// so this saves some typing.
static void set_2f(XPLMDataRef r, float v1, float v2)
{
	float v[2] = { v1, v2 };
	XPLMSetDatavf(r,v,0,2);
}

static void set_2i(XPLMDataRef r, int i1, int i2)
{
	int i[2] = { i1, i2 };
	XPLMSetDatavi(r,i,0,2);
}

static float deferred_init(
                                   float                inElapsedSinceLastCall,    
                                   float                inElapsedTimeSinceLastFlightLoop,    
                                   int                  inCounter,    
                                   void *               inRefcon)
{
	// These get set once when we take over the airplane...these are custom prop disc settings that
	// we won't change per frame.
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/override"), 1, 1);

	// Our prop disc has 4 slots across and 2 down.
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_s_dim"), 4, 4);
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_t_dim"), 2, 2);
	
	// Alpha settings for the prop disc.
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_alpha_front"), 1.0, 1.0);
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_alpha_side"), 0.1, 0.1);
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_alpha_inside"), 0.8, 0.8);
	
	// Side is a 2-blade prop 15 cm wide.  We have 32x2 slots for side discs.
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_width") , 0.15, 0.15);
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_number_of_blades"), 2, 2);
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_s_dim"), 32, 32);
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_t_dim"), 2, 2);
	// Alpha setting for side disc is separate
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_alpha_front"), 0.0, 0.0);
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_alpha_side"), 1.0, 1.0);
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_alpha_inside"), 0.8, 0.8);
	// Do not use auto-billboarding.  We will spin the side disc ourselves.
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_is_billboard"), 0, 0);
	
	return 0;
}

static float prop_per_frame(
                                   float                inElapsedSinceLastCall,    
                                   float                inElapsedTimeSinceLastFlightLoop,    
                                   int                  inCounter,    
                                   void *               inRefcon)
{
	float prop_speed_now[2];
	float prop_angle_now[2];
	float side_angle_now[2];

	// First we need to know how fast the sim is really running - a function
	// of the sim speed and framerate period.  We also need to know how fast our
	// disc is going.  Btw s in seconds per frame.
	float s = XPLMGetDatai(sim_speed);
	s *= XPLMGetDataf(frame_rate_period);
	XPLMGetDatavf(prop_rotation_speed_rad_sec,prop_speed_now,0,2);
	
	// And - where is our disc right now.
	XPLMGetDatavf(side_angle,side_angle_now,0,2);
	XPLMGetDatavf(prop_rotation_angle_deg,prop_angle_now,0,2);

	// "Spin" the disc just a bit and write it bck.
	prop_angle_now[0] += prop_speed_now[0] * s * 60.0;
	prop_angle_now[1] += prop_speed_now[1] * s * 60.0;
	side_angle_now[0] += prop_speed_now[0] * s * 60.0;
	side_angle_now[1] += prop_speed_now[1] * s * 60.0;
	
	XPLMSetDatavf(side_angle,side_angle_now, 0, 2);
	XPLMSetDatavf(prop_rotation_angle_deg,prop_angle_now, 0, 2);

	// Individual blades or a disc?  We switch at greater than 18 rads/sec spinning.
	set_2i(prop_is_disc, prop_speed_now[0] > 18.0, prop_speed_now[1] > 18.0);

	// We pick our texture slots by interping the prop speed.  So as the prop speeds up, we
	// pick different slots.
	set_2f(disc_s,interp(15,0,100,2,prop_speed_now[0]),interp(15,0,100,2,prop_speed_now[1]));
	set_2i(disc_t,0,1);

	set_2f(side_s,interp(15,26,100,24,prop_speed_now[0]),interp(15,24,100,26,prop_speed_now[1]));
	set_2i(side_t,0,1);

	return -1.0;	
}


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	strcpy(outName, "Custom Prop Disc Example");
	strcpy(outSig, "xplanesdk.examples.custom_prop_disc");
	strcpy(outDesc, "A plugin that demonstrates custom prop disc patterns.");

	XPLMRegisterFlightLoopCallback(deferred_init, -1.0, NULL);
	XPLMRegisterFlightLoopCallback(prop_per_frame, -2.0, NULL);

	prop_rotation_speed_rad_sec = XPLMFindDataRef("sim/flightmodel2/engines/prop_rotation_speed_rad_sec");
	prop_rotation_angle_deg = XPLMFindDataRef("sim/flightmodel2/engines/prop_rotation_angle_deg");
	side_angle = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_angle");
	prop_is_disc = XPLMFindDataRef("sim/flightmodel2/engines/prop_is_disc");
	disc_s = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_s");
	disc_t = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_t");
	side_s = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_s");
	side_t = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_t");
	sim_speed = XPLMFindDataRef("sim/time/sim_speed");
	frame_rate_period = XPLMFindDataRef("sim/operation/misc/frame_rate_period");

	
	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	XPLMUnregisterFlightLoopCallback(deferred_init,NULL);
	XPLMUnregisterFlightLoopCallback(prop_per_frame,NULL);

	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/override"), 0, 0);


}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

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

Control

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

#define MAX_ITEMS 12
	
static XPLMDataRef gControlDataRef[MAX_ITEMS];

static char DataRefString[MAX_ITEMS][255] = {	"sim/joystick/yoke_pitch_ratio", "sim/joystick/yoke_roll_ratio", "sim/joystick/yoke_heading_ratio",
										"sim/joystick/artstab_pitch_ratio", "sim/joystick/artstab_roll_ratio", "sim/joystick/artstab_heading_ratio",
										"sim/joystick/FC_ptch", "sim/joystick/FC_roll", "sim/joystick/FC_hdng",
										"sim/flightmodel/weight/m_fuel1", "sim/flightmodel/weight/m_fuel2", "sim/flightmodel/weight/m_fuel3"};

static char DataRefDesc[MAX_ITEMS][255] = {"Yoke Pitch", "Yoke Roll", "Yoke Heading", "AS Pitch", "AS Roll", "AS Heading", "FC Pitch", "FC Roll", "FC Heading", "Fuel 1", "Fuel 2", "Fuel 3"};


static float IncrementValue[MAX_ITEMS] = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 10.0, 10.0, 10.0};

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

static int MenuItem1;

static XPWidgetID			ControlWidget = NULL, ControlWindow = NULL;
static XPWidgetID			ControlApplyButton = NULL; 
static XPWidgetID			ControlText[MAX_ITEMS] = {NULL};
static XPWidgetID			ControlEdit[MAX_ITEMS] = {NULL};
static XPWidgetID			UpArrow[MAX_ITEMS] = {NULL};
static XPWidgetID			DownArrow[MAX_ITEMS] = {NULL};

static void ControlMenuHandler(void *, void *);

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

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

static void DisplayFindDataRef(void);
static void ApplyValues(void);
static void RefreshValues(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, "Control");
	strcpy(outSig, "xpsdk.examples.Control");
	strcpy(outDesc, "A plug-in that allows Controling of lat/lon etc.");

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

	id = XPLMCreateMenu("Control", XPLMFindPluginsMenu(), item, ControlMenuHandler, NULL);
	XPLMAppendMenuItem(id, "Control", (void *)"Control", 1);
	
	MenuItem1 = 0;

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

	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	if (MenuItem1 == 1)
	{
		XPDestroyWidget(ControlWidget, 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)
{
	if (inFrom == XPLM_PLUGIN_XPLANE)
	{
		switch(inMsg)
		{
			case XPLM_MSG_PLANE_LOADED:
				RefreshValues();
				break;
		}
	}
}

void ControlMenuHandler(void * mRef, void * iRef)
{
	if (!strcmp((char *) iRef, "Control"))
	{
		if (MenuItem1 == 0)
		{
			CreateControl(300, 550, 350, 530);
			MenuItem1 = 1;
		}
		else
		{
			if(!XPIsWidgetVisible(ControlWidget))
			{
				RefreshValues();
				XPShowWidget(ControlWidget);
	}
}						
	}
}						


void CreateControl(int x, int y, int w, int h)
{
	int x2 = x + w;
	int y2 = y - h;
	char buffer[512];
	float FloatValue[MAX_ITEMS];
	int Item;

	for (Item=0; Item<MAX_ITEMS; Item++)
		FloatValue[Item] = XPLMGetDataf(gControlDataRef[Item]);
	
	ControlWidget = XPCreateWidget(x, y, x2, y2,
					1,	// Visible
					"Control",	// desc
					1,		// root
					NULL,	// no container
					xpWidgetClass_MainWindow);

	XPSetWidgetProperty(ControlWidget, xpProperty_MainWindowHasCloseBoxes, 1);

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

	XPSetWidgetProperty(ControlWindow, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

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

		sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
		ControlEdit[Item] = XPCreateWidget(x+160, y-(70 + (Item*30)), x+250, y-(92 + (Item*30)),
							1, buffer, 0, ControlWidget,
							xpWidgetClass_TextField);

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

		UpArrow[Item] = XPCreateWidget(x+252, y-(66 + (Item*30)), x+264, y-(81 + (Item*30)),
							1, "", 0, ControlWidget,
							xpWidgetClass_Button);

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

		DownArrow[Item] = XPCreateWidget(x+252, y-(81 + (Item*30)), x+264, y-(96 + (Item*30)),
							1, "", 0, ControlWidget,
							xpWidgetClass_Button);
	
		XPSetWidgetProperty(DownArrow[Item], xpProperty_ButtonType, xpLittleDownArrow);
	}

	ControlApplyButton = XPCreateWidget(x+120, y-440, x+210, y-462,
					1, "Apply Data", 0, ControlWidget, 
					xpWidgetClass_Button);

	XPSetWidgetProperty(ControlApplyButton, xpProperty_ButtonType, xpPushButton);

	XPAddWidgetCallback(ControlWidget, ControlHandler);
}

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

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

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

	if (inMessage == xpMsg_PushButtonPressed)
	{

		if (inParam1 == (intptr_t)ControlApplyButton)
		{
			ApplyValues();
			return 1;
		}

		for (Item=0; Item<MAX_ITEMS; Item++)
		{
			if (inParam1 == (intptr_t)UpArrow[Item])
			{
				FloatValue[Item] += IncrementValue[Item];
				sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
				XPSetWidgetDescriptor(ControlEdit[Item], buffer);
				XPLMSetDataf(gControlDataRef[Item], FloatValue[Item]);
				return 1;
			}
		}

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

	return 0;
}						

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

	for (int Item=0; Item<MAX_ITEMS; Item++)
	{
		XPGetWidgetDescriptor(ControlEdit[Item], buffer, 512);
		XPLMSetDataf(gControlDataRef[Item], atof(buffer));
	}
}

void RefreshValues(void)
{
	char	buffer[512];
	float FloatValue[MAX_ITEMS];
	int Item;

	for (Item=0; Item<MAX_ITEMS; Item++)
		FloatValue[Item] = XPLMGetDataf(gControlDataRef[Item]);
	
	for (Item=0; Item<MAX_ITEMS; Item++)
	{
		sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
		XPSetWidgetDescriptor(ControlEdit[Item], buffer);
	}
}
Leave a comment

CommandSim

/*
 * CommandSim.c
 * 
 * This function demonstrates how to send commands to the sim.  Commands allow you to simulate
 * any keystroke or joystick button press or release.
 * 
 */

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

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

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

	strcpy(outName, "CommandSim");
	strcpy(outSig, "xplanesdk.examples.commandsim");
	strcpy(outDesc, "A plugin that makes the command do things.");
	
	/* Create a menu for ourselves.  */
	mySubMenuItem = XPLMAppendMenuItem(
						XPLMFindPluginsMenu(),	/* Put in plugins menu */
						"Command Sim",				/* Item Title */
						0,						/* Item Ref */
						1);						/* Force English */
	
	myMenu = XPLMCreateMenu(
						"Command Sim", 
						XPLMFindPluginsMenu(), 
						mySubMenuItem, 			/* Menu Item to attach to. */
						MyMenuHandlerCallback,	/* The handler */
						0);						/* Handler Ref */

	/* For each command, we set the item refcon to be the key command ID we wnat
	 * to run.   Our callback will use this item refcon to do the right command.
	 * This allows us to write only one callback for the menu. */	 
	XPLMAppendMenuItem(myMenu, "Pause", (void *) xplm_key_pause, 1);
	XPLMAppendMenuItem(myMenu, "Reverse Thrust", (void *) xplm_key_revthrust, 1);
	XPLMAppendMenuItem(myMenu, "Jettison", (void *) xplm_key_jettison, 1);
	XPLMAppendMenuItem(myMenu, "Brakes (Regular)", (void *) xplm_key_brakesreg, 1);
	XPLMAppendMenuItem(myMenu, "Brakes (Full)", (void *) xplm_key_brakesmax, 1);
	XPLMAppendMenuItem(myMenu, "Landing Gear", (void *) xplm_key_gear, 1);
	return 1;
}

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 the menu callback.  We simply turn the item ref back
	 * into a command ID and tell the sim to do it. */
	XPLMCommandKeyStroke((XPLMCommandKeyID) inItemRef);
}
4 Comments

Camera

/*
 * Camera.c
 * 
 * This plugin registers a new view with the sim that orbits the aircraft.  We do this by:
 * 
 * 1. Registering a hotkey to engage the view.
 * 2. Setting the view to external when we are engaged.
 * 3. Registering a new camera control funcioin that ends when a new view is picked.
 * 
 */

#include <string.h>
#include "XPLMDisplay.h"
#include "XPLMUtilities.h"
#include "XPLMCamera.h"
#include "XPLMDataAccess.h"
#include "XPLMDisplay.h"
#include <stdio.h>
#include <math.h>

static XPLMHotKeyID	gHotKey = NULL;
static XPLMDataRef		gPlaneX = NULL;
static XPLMDataRef		gPlaneY = NULL;
static XPLMDataRef		gPlaneZ = NULL;


static void	MyHotKeyCallback(void *               inRefcon);    
static int 	MyOrbitPlaneFunc(
                                   XPLMCameraPosition_t * outCameraPosition,  
                                   int                  inIsLosingControl,    
                                   void *               inRefcon);    


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	strcpy(outName, "Camera");
	strcpy(outSig, "xplanesdk.examples.camera");
	strcpy(outDesc, "A plugin that adds a camera view.");

	/* Prefetch the sim variables we will use. */
	gPlaneX = XPLMFindDataRef("sim/flightmodel/position/local_x");
	gPlaneY = XPLMFindDataRef("sim/flightmodel/position/local_y");
	gPlaneZ = XPLMFindDataRef("sim/flightmodel/position/local_z");

	/* Register our hot key for the new view. */
	gHotKey = XPLMRegisterHotKey(XPLM_VK_F8, xplm_DownFlag, 
				"Circling External View",
				MyHotKeyCallback,
				NULL);
	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	XPLMUnregisterHotKey(gHotKey);
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

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

void	MyHotKeyCallback(void *               inRefcon)
{
	/* This is the hotkey callback.  First we simulate a joystick press and
	 * release to put us in 'free view 1'.  This guarantees that no panels
	 * are showing and we are an external view. */
	XPLMCommandButtonPress(xplm_joy_v_fr1);
	XPLMCommandButtonRelease(xplm_joy_v_fr1);
	
	/* Now we control the camera until the view changes. */
	XPLMControlCamera(xplm_ControlCameraUntilViewChanges, MyOrbitPlaneFunc, NULL);
}

/*
 * MyOrbitPlaneFunc
 * 
 * This is the actual camera control function, the real worker of the plugin.  It is 
 * called each time X-Plane needs to draw a frame.
 * 
 */
int 	MyOrbitPlaneFunc(
                                   XPLMCameraPosition_t * outCameraPosition,   
                                   int                  inIsLosingControl,    
                                   void *               inRefcon)
{
	if (outCameraPosition && !inIsLosingControl)
	{
			int	w, h, x, y;
			float dx, dz, dy, heading, pitch;
			char	buf[256];
		
		/* First get the screen size and mouse location.  We will use this to decide
		 * what part of the orbit we are in.  The mouse will move us up-down and around. */
		XPLMGetScreenSize(&w, &h);
		XPLMGetMouseLocation(&x, &y);
		heading = 360.0 * (float) x / (float) w;
		pitch = 20.0 * (((float) y / (float) h) * 2.0 - 1.0);
		
		/* Now calculate where the camera should be positioned to be 200
		 * meters from the plane and pointing at the plane at the pitch and
		 * heading we wanted above. */
		dx = -200.0 * sin(heading * 3.1415 / 180.0);
		dz = 200.0 * cos(heading * 3.1415 / 180.0);
		dy = -200 * tan(pitch * 3.1415 / 180.0);
		
		/* Fill out the camera position info. */
		outCameraPosition->x = XPLMGetDataf(gPlaneX) + dx;
		outCameraPosition->y = XPLMGetDataf(gPlaneY) + dy;
		outCameraPosition->z = XPLMGetDataf(gPlaneZ) + dz;
		outCameraPosition->pitch = pitch;
		outCameraPosition->heading = heading;
		outCameraPosition->roll = 0;		

	}
	
	/* Return 1 to indicate we want to keep controlling the camera. */
	return 1;
}
Leave a comment