#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);
}
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;
}
}
/*
* 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);
}
}
}
}
/*
* 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;
}
/*
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;
}
/*
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;
}
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)
{
}
#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);
}
}
/*
* 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);
}
/*
* 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;
}