// Custom Commands
// ***********************************
//
// MANIPULATOR CODE EXAMPLE
//
// This example program illustrates control of X-Plane DataRefs using custom manipulators.
// Pumping the flap lever manipulator will lower the flaps a fractional amount. Raising
// the flap selector manipulator will change the direction of flap movement.
//
// For this example to work it is necessary to use AC3D to create two handle animations in
// the aircraft cockpit using the custom datarefs BSUB/Aircraft/FlapPumpPosition and
// BSUB/Aircraft/FlapSelectorPosition for the rotations. Both handles must be identified
// as axis manipulators with 0 to 1 limits and grabber hand cursor.
//
// For clarity this code has not been optimized.
//
// Blue side up,
// Bob
//
// Bob@RogerThat.ca
//
// ***********************************
#define XPLM200 = 1;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "XPLMDataAccess.h"
#include "XPLMPlugin.h"
#include "XPLMProcessing.h"
#define MSG_ADD_DATAREF 0x01000000
XPLMDataRef FlapRatioDataRef = NULL; // Existing dataref
XPLMDataRef FlapPumpPositionDataRef = NULL; // Custom dataref
XPLMDataRef FlapSelectorPositionDataRef = NULL; // Custom dataref
float GetFlapPumpPositionDRCB(void* inRefcon);
void SetFlapPumpPositionDRCB(void* inRefcon, float outValue);
float GetFlapSelectorPositionDRCB(void* inRefcon);
void SetFlapSelectorPositionDRCB(void* inRefcon, float outValue);
float FlapPumpPositionFLCB(float elapsedMe, float elapsedSim, int counter, void * refcon);
float FlapPumpPosition = 0;
float FlapSelectorPosition = 1; // Flap selector lever is down position at startup
float FlapSelectorDirectionFlag = 1; // Flap lever will pump flaps downwards at startup
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
strcpy(outName, "Flap Manipulator Example");
strcpy(outSig, "BlueSideUpBob.Flap Manipulator Example");
strcpy(outDesc, "Manipulating flap selector and flap pump levers raise and lower flaps.");
// CREATE DATAREFS, FIND DATAREFS FOR FLAP LEVER
FlapPumpPositionDataRef = XPLMRegisterDataAccessor(
"BSUB/Aircraft/FlapPumpPosition",
xplmType_Float, // The types we support
1, // Writable
NULL, NULL, // Integer accessors
GetFlapPumpPositionDRCB, SetFlapPumpPositionDRCB, // Float accessors
NULL, NULL, // Doubles accessors
NULL, NULL, // Int array accessors
NULL, NULL, // Float array accessors
NULL, NULL, // Raw data accessors
NULL, NULL); // Refcons not used
FlapSelectorPositionDataRef = XPLMRegisterDataAccessor(
"BSUB/Aircraft/FlapSelectorPosition",
xplmType_Float,
1,
NULL, NULL,
GetFlapSelectorPositionDRCB, SetFlapSelectorPositionDRCB,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL);
FlapPumpPositionDataRef = XPLMFindDataRef ("BSUB/Aircraft/FlapPumpPosition");
FlapSelectorPositionDataRef = XPLMFindDataRef ("BSUB/Aircraft/FlapSelectorPosition");
FlapRatioDataRef = XPLMFindDataRef("sim/cockpit2/controls/flap_ratio");
XPLMSetDataf(FlapPumpPositionDataRef, 0);
XPLMSetDataf(FlapSelectorPositionDataRef, 0);
XPLMRegisterFlightLoopCallback(FlapPumpPositionFLCB, 0.0, NULL);
XPLMSetFlightLoopCallbackInterval(FlapPumpPositionFLCB, 0.01, 1, NULL);
return 1;
}
PLUGIN_API void XPluginStop(void)
{
XPLMUnregisterDataAccessor(FlapPumpPositionDataRef);
XPLMUnregisterDataAccessor(FlapSelectorPositionDataRef);
XPLMUnregisterFlightLoopCallback(FlapPumpPositionFLCB, NULL);
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API void XPluginReceiveMessage(
XPLMPluginID inFromWho,
long inMessage,
void * inParam)
{
}
float GetFlapPumpPositionDRCB(void* inRefcon)
{
return FlapPumpPosition;
}
void SetFlapPumpPositionDRCB(void* inRefcon, float inValue)
{
FlapPumpPosition = inValue;
}
float GetFlapSelectorPositionDRCB(void* inRefcon)
{
return FlapSelectorPosition;
}
void SetFlapSelectorPositionDRCB(void* inRefcon, float inValue)
{
FlapSelectorPosition = inValue;
}
float FlapPumpPositionFLCB(
float inElapsedSinceLastCall,
float inElapsedTimeSinceLastFlightLoop,
int inCounter,
void * inRefcon)
{
float CurrentPumpPosition;
static float FlapPumpLastPosition = 0;
float DeltaPumpPosition;
static float FlapDeflection = 0;
int FlapSelectorDirection;
CurrentPumpPosition = XPLMGetDataf(FlapPumpPositionDataRef); // Where is handle now?
DeltaPumpPosition = CurrentPumpPosition - FlapPumpLastPosition; // Has handle moved?
if (DeltaPumpPosition == 0) {return 0.1;} // No. Check again later.
FlapPumpLastPosition = CurrentPumpPosition; // SetUp for next cycle.
if (DeltaPumpPosition < 0) {DeltaPumpPosition = - DeltaPumpPosition;} // Allows pumping on push and pull strokes.
FlapSelectorPosition = XPLMGetDataf(FlapSelectorPositionDataRef); // Where is the flap selector handle now?
if(FlapSelectorPosition > 0.9) {FlapSelectorDirection = 1;} // If flap selector is down lower flaps.
if(FlapSelectorPosition < 0.1) {FlapSelectorDirection = 0;} // If flap selector is up raise flaps.
if(FlapSelectorDirection == 1) // Move flaps down 1/10 of flap lever amount
{
FlapDeflection = XPLMGetDataf(FlapRatioDataRef) + DeltaPumpPosition * 0.1;
if (FlapDeflection > 1){FlapDeflection = 1;} // Limit flap ratio between 0 and 1.
XPLMSetDataf(FlapRatioDataRef, FlapDeflection); // Set flaps a proportional amount.
}
if(FlapSelectorDirection == 0) // Move flaps up
{
FlapDeflection = XPLMGetDataf(FlapRatioDataRef) - DeltaPumpPosition * 0.1;
if (FlapDeflection < 0){FlapDeflection = 0;}
XPLMSetDataf(FlapRatioDataRef, FlapDeflection);
}
return 0.1;
}
// Custom Commands
//
// Custom Commands Control Custom DataRef
//
// This example program creates a custom integer dataref, BSUB/CounterDataRef, and two custom
// commands, BSUB/CounterUpCommand and BSUB/CounterDownCommand. The custom commands
// are used to increment and decriment the custom dataref. The custom dataref can be used to drive an
// generic instrument display, animation, etc.
//
// After successfully creating your plugin you will need to use PlaneMaker to create two generic
// triggers, keyed to your custom commands on your aircraft panel. You will also need to place a generic
// counter such as an LED display on your aircraft panel.
//
// Content added by BlueSideUpBob.
#ifndef XPLM200
#error This example requires the v2.0 SDK or newer
#endif
#include "XPLMPlugin.h"
#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"
#include "XPLMUtilities.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include "XPLMScenery.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
XPLMDataRef gCounterDataRef = NULL; // Our custom dataref
int gCounterValue; // Our custom dataref's value
int GetCounterDataRefCB(void* inRefcon);
void SetCounterDataRefCB(void* inRefcon, int outValue);
XPLMCommandRef CounterUpCommand = NULL; // Our two custom commands
XPLMCommandRef CounterDownCommand = NULL;
int CounterUpCommandHandler(XPLMCommandRef inCommand, // Our two custom command handlers
XPLMCommandPhase inPhase,
void * inRefcon);
int CounterDownCommandHandler(XPLMCommandRef inCommand,
XPLMCommandPhase inPhase,
void * inRefcon);
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
// Plugin Info
strcpy(outName, "CustomCommandsAndDataRefs");
strcpy(outSig, "BlueSideUpBob.Example.CustomCommandsAndDataRef");
strcpy(outDesc, "This example illustrates creating and using custom commands to control a custom DataRef.");
// Create our custom integer dataref
gCounterDataRef = XPLMRegisterDataAccessor("BSUB/CounterDataRef",
xplmType_Int, // The types we support
1, // Writable
GetCounterDataRefCB, SetCounterDataRefCB, // Integer accessors
NULL, NULL, // Float accessors
NULL, NULL, // Doubles accessors
NULL, NULL, // Int array accessors
NULL, NULL, // Float array accessors
NULL, NULL, // Raw data accessors
NULL, NULL); // Refcons not used
// Find and intialize our Counter dataref
gCounterDataRef = XPLMFindDataRef ("BSUB/CounterDataRef");
XPLMSetDatai(gCounterDataRef, 0);
// Create our commands; these will increment and decrement our custom dataref.
CounterUpCommand = XPLMCreateCommand("BSUB/CounterUpCommand", "Counter Up");
CounterDownCommand = XPLMCreateCommand("BSUB/CounterDownCommand", "Counter Down");
// Register our custom commands
XPLMRegisterCommandHandler(CounterUpCommand, // in Command name
CounterUpCommandHandler, // in Handler
1, // Receive input before plugin windows.
(void *) 0); // inRefcon.
XPLMRegisterCommandHandler(CounterDownCommand,
CounterDownCommandHandler,
1,
(void *) 0);
return 1;
}
PLUGIN_API void XPluginStop(void)
{
XPLMUnregisterDataAccessor(gCounterDataRef);
XPLMUnregisterCommandHandler(CounterUpCommand, CounterUpCommandHandler, 0, 0);
XPLMUnregisterCommandHandler(CounterDownCommand, CounterDownCommandHandler, 0, 0);
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFromWho,
long inMessage,
void * inParam)
{
}
int GetCounterDataRefCB(void* inRefcon)
{
return gCounterValue;
}
void SetCounterDataRefCB(void* inRefcon, int inValue)
{
gCounterValue = inValue;
}
int CounterUpCommandHandler(XPLMCommandRef inCommand,
XPLMCommandPhase inPhase,
void * inRefcon)
{
// If inPhase == 0 the command is executed once on button down.
if (inPhase == 0)
{
gCounterValue++;
if(gCounterValue > 10) {gCounterValue = 10;}
}
// Return 1 to pass the command to plugin windows and X-Plane.
// Returning 0 disables further processing by X-Plane.
return 0;
}
int CounterDownCommandHandler(XPLMCommandRef inCommand,
XPLMCommandPhase inPhase,
void * inRefcon)
{
// If inPhase == 1 the command is executed continuously.
if (inPhase == 1)
{
gCounterValue--;
if(gCounterValue < -10) {gCounterValue = -10;}
}
return 0;
}
// Custom Commands
//
// This example program illustrates creating a custom command. In this case clicking a generic trigger on
// your aircraft panel writes to the DataRef controlling the pilots head position either continuously or one
// knotch at a time. We could use the existing position command: sim/view/move_right, however for illustrative
// purposes, this example uses a custom command: BSUB/ViewPoint/MoveRight
//
// For this example to work it is necessary to create a generic trigger on the panel of your aircraft keyed
// to the command: BSUB/ViewPoint/MoveRight.
//
// Content added by BlueSideUpBob.
//
#include "XPLMPlugin.h"
#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"
#include "XPLMUtilities.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include "XPLMScenery.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
XPLMDataRef gHeadPositionXDataRef = NULL;
XPLMCommandRef MyCommand = NULL;
int MyCommandHandler(XPLMCommandRef inCommand,
XPLMCommandPhase inPhase,
void * inRefcon);
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
// Plugin Info
strcpy(outName, "CommandControl");
strcpy(outSig, "BlueSideUpBob.Example.CommandControl");
strcpy(outDesc, "This example illustrates creating and sending a custom command to X-Plane using a generic trigger.");
// Create the test command, this will move the pilots point of view 10 cm to the right.
MyCommand = XPLMCreateCommand("BSUB/ViewPoint/MoveRight", "Move Right");
// Register our custom command
XPLMRegisterCommandHandler(MyCommand, // in Command name
MyCommandHandler, // in Handler
1, // Receive input before plugin windows.
(void *) 0); // inRefcon.
gHeadPositionXDataRef = XPLMFindDataRef("sim/aircraft/view/acf_peX");
return 1;
}
PLUGIN_API void XPluginStop(void)
{
XPLMUnregisterCommandHandler(MyCommand, MyCommandHandler, 0, 0);
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginReceiveMessage(
XPLMPluginID inFromWho,
long inMessage,
void * inParam)
{
}
int MyCommandHandler(XPLMCommandRef inCommand,
XPLMCommandPhase inPhase,
void * inRefcon)
{
// Use the structure below to have the command executed
// continuously while the button is being held down.
if (inPhase == xplm_CommandContinue)
{
XPLMSetDataf(gHeadPositionXDataRef, XPLMGetDataf(gHeadPositionXDataRef) + .1);
}
// Use this structure to have the command executed on button up only.
if (inPhase == xplm_CommandEnd)
{
XPLMSetDataf(gHeadPositionXDataRef, XPLMGetDataf(gHeadPositionXDataRef) + .1);
}
// Return 1 to pass the command to plugin windows and X-Plane.
// Returning 0 disables further processing by X-Plane.
// In this case we might return 0 or 1 because X-Plane does not duplicate our command.
return 0;
}
// Instructions Widget
/*
PullDown Menu Creates Widget Window to Disply Plugin Instructions or Notes.
This example shows how to use a pulldown menu to create a widget window to display a list of instructions or notes.
The widget window is distroyed by clicking a close box. There are several other widget window features that
can be explored; please see the SDK documentation.
This content added by Blue Side Up Bob.
*/
// #define XPLM200 = 1; This example does not require SDK2.0.
#include "XPLMUtilities.h"
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int gMenuItem;
char InstructionsText[50][200] = {
" 1. Text line one.",
" 2. Text.",
" 3. Text.",
" 4. Text.",
" 5. Text.",
" 6. Text.",
"end"
};
XPWidgetID InstructionsWidget = NULL;
XPWidgetID InstructionsWindow = NULL;
XPWidgetID InstructionsTextWidget[50] = {NULL};
void InstructionsMenuHandler(void *, void *);
void CreateInstructionsWidget(int x1, int y1, int w, int h);
int InstructionsHandler(XPWidgetMessage inMessage, XPWidgetID inWidget, long inParam1, long inParam2);
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
XPLMMenuID PluginMenu;
int PluginSubMenuItem;
strcpy(outName, "Instructions");
strcpy(outSig, "BlueSideUpBob.Example.Instructions");
strcpy(outDesc, "A plugin to display an Instruction Text window from the pull down menu.");
// Create our menu
PluginSubMenuItem = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "Instructions Plugin", NULL, 1);
PluginMenu = XPLMCreateMenu("Instructions Plugin", XPLMFindPluginsMenu(), PluginSubMenuItem, InstructionsMenuHandler, NULL);
XPLMAppendMenuItem(PluginMenu, "Instructions", (void *) +1, 1);
// Flag to tell us if the widget is being displayed.
gMenuItem = 0;
return 1;
}
PLUGIN_API void XPluginStop(void)
{
if (gMenuItem == 1)
{
XPDestroyWidget(InstructionsWidget, 1);
gMenuItem = 0;
}
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, long inMsg, void * inParam)
{
}
void InstructionsMenuHandler(void * inMenuRef, void * inItemRef)
{
switch ( (int) inItemRef)
{
case 1: if (gMenuItem == 0)
{
CreateInstructionsWidget(50, 712, 974, 662); //left, top, right, bottom.
gMenuItem = 1;
}
else
{
if(!XPIsWidgetVisible(InstructionsWidget))
XPShowWidget(InstructionsWidget);
}
break;
}
}
// This will create our widget dialog.
void CreateInstructionsWidget(int x, int y, int w, int h)
{
int Index;
int x2 = x + w;
int y2 = y - h;
// Create the Main Widget window.
InstructionsWidget = XPCreateWidget(x, y, x2, y2,
1, // Visible
"INSTRUCTIONS Blue Side Up Bob", // desc
1, // root
NULL, // no container
xpWidgetClass_MainWindow);
// Add Close Box to the Main Widget. Other options are available. See the SDK Documentation.
XPSetWidgetProperty(InstructionsWidget, xpProperty_MainWindowHasCloseBoxes, 1);
// Print each line of instructions.
for (Index=0; Index < 50; Index++)
{
if(strcmp(InstructionsText[Index],"end") == 0) {break;}
// Create a text widget
InstructionsTextWidget[Index] = XPCreateWidget(x+10, y-(30+(Index*20)) , x2-10, y-(42+(Index*20)),
1, // Visible
InstructionsText[Index],// desc
0, // root
InstructionsWidget,
xpWidgetClass_Caption);
}
// Register our widget handler
XPAddWidgetCallback(InstructionsWidget, InstructionsHandler);
}
// This is our widget handler. In this example we are only interested when the close box is pressed.
int InstructionsHandler(XPWidgetMessage inMessage, XPWidgetID inWidget, long inParam1, long inParam2)
{
if (inMessage == xpMessage_CloseButtonPushed)
{
if (gMenuItem == 1)
{
XPHideWidget(InstructionsWidget);
}
return 1;
}
return 0;
}
#include <stdio.h>
#include <string.h>
#include "XPLMPlanes.h"
#include "XPLMUtilities.h"
static int enable_count = 0;
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
strcpy(outName, "planes_test");
strcpy(outSig, "xplanesdk.examples.plane_test");
strcpy(outDesc, "A quick test of airplane acquisition.");
return 1;
}
PLUGIN_API void XPluginStop(void)
{
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API int XPluginEnable(void)
{
++enable_count;
if (enable_count == 1) return 0;
int r = XPLMAcquirePlanes(NULL, NULL, NULL);
if(r == 0) XPLMDebugString("Plane test: did not acquire plane.s\n");
else XPLMDebugString("Plane test: did acquire plane.s\n");
if(r)
{
char buf[1024];
XPLMPluginID who;
int total_before, active_before,total_after,active_after;
XPLMCountAircraft(&total_before,&active_before,&who);
XPLMSetActiveAircraftCount(total_before > 2 ? 2 : total_before);
XPLMCountAircraft(&total_after,&active_after,&who);
sprintf(buf,"Before: %d of %d, after: %d of %d\n",
active_before,total_before,active_after,total_after);
XPLMDebugString(buf);
}
return 1;
}
PLUGIN_API void XPluginReceiveMessage(
XPLMPluginID inFromWho,
int inMessage,
void * inParam)
{
}
This sample plugin plays a sound whenever an airplane is loaded. It demonstrates how to use OpenAL with a context from a plugin.
This plugin can safely run while X-Plane is using OpenAL.
This plugin requires the file “sound.wav” to be in the same folder as the plugin itself.
On Linux you will need to add -lopenal to LIBS.
On Windows you will need to add the OpenAL include and lib paths and add openal32.lib to the linker settings.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "XPLMUtilities.h"
#include "XPLMProcessing.h"
#include "XPLMPlugin.h"
// OS X: we use this to convert our file path.
#if APL
#include <Carbon/Carbon.h>
#endif
// Your include paths for OpenAL may vary by platform.
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
/**************************************************************************************************************
* WAVE FILE LOADING
**************************************************************************************************************/
// You can just use alutCreateBufferFromFile to load a wave file, but there seems to be a lot of problems with
// alut not beign available, being deprecated, etc. So...here's a stupid routine to load a wave file. I have
// tested this only on x86 machines, so if you find a bug on PPC please let me know.
// Macros to swap endian-values.
#define SWAP_32(value) \
(((((unsigned short)value)<<8) & 0xFF00) | \
((((unsigned short)value)>>8) & 0x00FF))
#define SWAP_16(value) \
(((((unsigned int)value)<<24) & 0xFF000000) | \
((((unsigned int)value)<< 8) & 0x00FF0000) | \
((((unsigned int)value)>> 8) & 0x0000FF00) | \
((((unsigned int)value)>>24) & 0x000000FF))
// Wave files are RIFF files, which are "chunky" - each section has an ID and a length. This lets us skip
// things we can't understand to find the parts we want. This header is common to all RIFF chunks.
struct chunk_header {
int id;
int size;
};
// WAVE file format info. We pass this through to OpenAL so we can support mono/stereo, 8/16/bit, etc.
struct format_info {
short format; // PCM = 1, not sure what other values are legal.
short num_channels;
int sample_rate;
int byte_rate;
short block_align;
short bits_per_sample;
};
// This utility returns the start of data for a chunk given a range of bytes it might be within. Pass 1 for
// swapped if the machine is not the same endian as the file.
static char * find_chunk(char * file_begin, char * file_end, int desired_id, int swapped)
{
while(file_begin < file_end)
{
chunk_header * h = (chunk_header *) file_begin;
if(h->id == desired_id && !swapped)
return file_begin+sizeof(chunk_header);
if(h->id == SWAP_32(desired_id) && swapped)
return file_begin+sizeof(chunk_header);
int chunk_size = swapped ? SWAP_32(h->size) : h->size;
char * next = file_begin + chunk_size + sizeof(chunk_header);
if(next > file_end || next <= file_begin)
return NULL;
file_begin = next;
}
return NULL;
}
// Given a chunk, find its end by going back to the header.
static char * chunk_end(char * chunk_start, int swapped)
{
chunk_header * h = (chunk_header *) (chunk_start - sizeof(chunk_header));
return chunk_start + (swapped ? SWAP_32(h->size) : h->size);
}
#define FAIL(X) { XPLMDebugString(X); free(mem); return 0; }
#define RIFF_ID 0x46464952 // 'RIFF'
#define FMT_ID 0x20746D66 // 'FMT '
#define DATA_ID 0x61746164 // 'DATA'
ALuint load_wave(const char * file_name)
{
// First: we open the file and copy it into a single large memory buffer for processing.
FILE * fi = fopen(file_name,"rb");
if(fi == NULL)
{
XPLMDebugString("WAVE file load failed - could not open.\n");
return 0;
}
fseek(fi,0,SEEK_END);
int file_size = ftell(fi);
fseek(fi,0,SEEK_SET);
char * mem = (char*) malloc(file_size);
if(mem == NULL)
{
XPLMDebugString("WAVE file load failed - could not allocate memory.\n");
fclose(fi);
return 0;
}
if (fread(mem, 1, file_size, fi) != file_size)
{
XPLMDebugString("WAVE file load failed - could not read file.\n");
free(mem);
fclose(fi);
return 0;
}
fclose(fi);
char * mem_end = mem + file_size;
// Second: find the RIFF chunk. Note that by searching for RIFF both normal
// and reversed, we can automatically determine the endian swap situation for
// this file regardless of what machine we are on.
int swapped = 0;
char * riff = find_chunk(mem, mem_end, RIFF_ID, 0);
if(riff == NULL)
{
riff = find_chunk(mem, mem_end, RIFF_ID, 1);
if(riff)
swapped = 1;
else
FAIL("Could not find RIFF chunk in wave file.\n")
}
// The wave chunk isn't really a chunk at all. :-( It's just a "WAVE" tag
// followed by more chunks. This strikes me as totally inconsistent, but
// anyway, confirm the WAVE ID and move on.
if (riff[0] != 'W' ||
riff[1] != 'A' ||
riff[2] != 'V' ||
riff[3] != 'E')
FAIL("Could not find WAVE signature in wave file.\n")
char * format = find_chunk(riff+4, chunk_end(riff,swapped), FMT_ID, swapped);
if(format == NULL)
FAIL("Could not find FMT chunk in wave file.\n")
// Find the format chunk, and swap the values if needed. This gives us our real format.
format_info * fmt = (format_info *) format;
if(swapped)
{
fmt->format = SWAP_16(fmt->format);
fmt->num_channels = SWAP_16(fmt->num_channels);
fmt->sample_rate = SWAP_32(fmt->sample_rate);
fmt->byte_rate = SWAP_32(fmt->byte_rate);
fmt->block_align = SWAP_16(fmt->block_align);
fmt->bits_per_sample = SWAP_16(fmt->bits_per_sample);
}
// Reject things we don't understand...expand this code to support weirder audio formats.
if(fmt->format != 1) FAIL("Wave file is not PCM format data.\n")
if(fmt->num_channels != 1 && fmt->num_channels != 2) FAIL("Must have mono or stereo sound.\n")
if(fmt->bits_per_sample != 8 && fmt->bits_per_sample != 16) FAIL("Must have 8 or 16 bit sounds.\n")
char * data = find_chunk(riff+4, chunk_end(riff,swapped), DATA_ID, swapped) ;
if(data == NULL)
FAIL("I could not find the DATA chunk.\n")
int sample_size = fmt->num_channels * fmt->bits_per_sample / 8;
int data_bytes = chunk_end(data,swapped) - data;
int data_samples = data_bytes / sample_size;
// If the file is swapped and we have 16-bit audio, we need to endian-swap the audio too or we'll
// get something that sounds just astoundingly bad!
if(fmt->bits_per_sample == 16 && swapped)
{
short * ptr = (short *) data;
int words = data_samples * fmt->num_channels;
while(words--)
{
*ptr = SWAP_16(*ptr);
++ptr;
}
}
// Finally, the OpenAL crud. Build a new OpenAL buffer and send the data to OpenAL, passing in
// OpenAL format enums based on the format chunk.
ALuint buf_id = 0;
alGenBuffers(1, &buf_id);
if(buf_id == 0) FAIL("Could not generate buffer id.\n");
alBufferData(buf_id, fmt->bits_per_sample == 16 ?
(fmt->num_channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16) :
(fmt->num_channels == 2 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8),
data, data_bytes, fmt->sample_rate);
free(mem);
return buf_id;
}
/**************************************************************************************************************
* SAMPLE OEPNAL PLUGIN:
**************************************************************************************************************/
static ALuint snd_src =0; // Sample source and buffer - this is one "sound" we play.
static ALuint snd_buffer =0;
static float pitch = 1.0f; // Start with 1.0 pitch - no pitch shift.
static ALCdevice * my_dev = NULL; // We make our own device and context to play sound through.
static ALCcontext * my_ctx = NULL;
// This is a stupid logging error function...useful for debugging, but not good error checking.
#define CHECK_ERR() __CHECK_ERR(__FILE__,__LINE__)
static void __CHECK_ERR(const char * f, int l)
{
ALuint e = alGetError();
if (e != AL_NO_ERROR)
printf("ERROR: %d (%s:%d\n", e, f, l);
}
// Mac specific: this converts file paths from HFS (which we get from the SDK) to Unix (which the OS wants).
// See this for more info:
//
// http://www.xsquawkbox.net/xpsdk/mediawiki/FilePathsAndMacho
#if APL
static int ConvertPath(const char * inPath, char * outPath, int outPathMaxLen) {
CFStringRef inStr = CFStringCreateWithCString(kCFAllocatorDefault, inPath ,kCFStringEncodingMacRoman);
if (inStr == NULL)
return -1;
CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inStr, kCFURLHFSPathStyle,0);
CFStringRef outStr = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
if (!CFStringGetCString(outStr, outPath, outPathMaxLen, kCFURLPOSIXPathStyle))
return -1;
CFRelease(outStr);
CFRelease(url);
CFRelease(inStr);
return 0;
}
#endif
// Initialization code.
static float init_sound(float elapsed, float elapsed_sim, int counter, void * ref)
{
CHECK_ERR();
char buf[2048];
// We have to save the old context and restore it later, so that we don't interfere with X-Plane
// and other plugins.
ALCcontext * old_ctx = alcGetCurrentContext();
if(old_ctx == NULL)
{
printf("0x%08x: I found no OpenAL, I will be the first to init.\n",XPLMGetMyID());
my_dev = alcOpenDevice(NULL);
if(my_dev == NULL)
{
XPLMDebugString("Could not open the default OpenAL device.\n");
return 0;
}
my_ctx = alcCreateContext(my_dev, NULL);
if(my_ctx == NULL)
{
if(old_ctx)
alcMakeContextCurrent(old_ctx);
alcCloseDevice(my_dev);
my_dev = NULL;
XPLMDebugString("Could not create a context.\n");
return 0;
}
// Make our context current, so that OpenAL commands affect our, um, stuff.
alcMakeContextCurrent(my_ctx);
printf("0x%08x: I created the context.\n",XPLMGetMyID(), my_ctx);
ALCint major_version, minor_version;
const char * al_hw=alcGetString(my_dev,ALC_DEVICE_SPECIFIER );
const char * al_ex=alcGetString(my_dev,ALC_EXTENSIONS
);
alcGetIntegerv(NULL,ALC_MAJOR_VERSION,sizeof(major_version),&major_version);
alcGetIntegerv(NULL,ALC_MINOR_VERSION,sizeof(minor_version),&minor_version);
printf("OpenAL version : %d.%d\n",major_version,minor_version);
printf("OpenAL hardware : %s\n", (al_hw?al_hw:"(none)"));
printf("OpenAL extensions: %s\n", (al_ex?al_ex:"(none)"));
CHECK_ERR();
}
else
{
printf("0x%08x: I found someone else's context 0x%08x.\n",XPLMGetMyID(), old_ctx);
}
ALfloat zero[3] = { 0 } ;
char dirchar = *XPLMGetDirectorySeparator();
XPLMGetPluginInfo(XPLMGetMyID(), NULL, buf, NULL, NULL);
char * p = buf;
char * slash = p;
while(*p)
{
if(*p==dirchar) slash = p;
++p;
}
++slash;
*slash=0;
strcat(buf,"sound.wav");
#if APL
ConvertPath(buf,buf,sizeof(buf));
#endif
// Generate 1 source and load a buffer of audio.
alGenSources(1,&snd_src);
CHECK_ERR();
snd_buffer = load_wave(buf);
printf("0x%08x: Loaded %d from %s\n", XPLMGetMyID(), snd_buffer,buf);
CHECK_ERR();
// Basic initializtion code to play a sound: specify the buffer the source is playing, as well as some
// sound parameters. This doesn't play the sound - it's just one-time initialization.
alSourcei(snd_src,AL_BUFFER,snd_buffer);
alSourcef(snd_src,AL_PITCH,1.0f);
alSourcef(snd_src,AL_GAIN,1.0f);
alSourcei(snd_src,AL_LOOPING,0);
alSourcefv(snd_src,AL_POSITION, zero);
alSourcefv(snd_src,AL_VELOCITY, zero);
CHECK_ERR();
return 0.0f;
}
PLUGIN_API int XPluginStart(char * name, char * sig, char * desc)
{
strcpy(name,"OpenAL Sound Demo");
strcpy(sig,"xpsdk.demo.openal2");
strcpy(desc,"Demonstrates sound playback with OpenAL.");
if( sizeof(unsigned int) != 4 ||
sizeof(unsigned short) != 2)
{
XPLMDebugString("This example plugin was compiled with a compiler with weird type sizes.\n");
return 0;
}
// Do deferred sound initialization. See http://www.xsquawkbox.net/xpsdk/mediawiki/DeferredInitialization
// for more info.
XPLMRegisterFlightLoopCallback(init_sound,-1.0,NULL);
printf("0x%08x: I am: %s\n", XPLMGetMyID(), sig);
return 1;
}
PLUGIN_API void XPluginStop(void)
{
// Cleanup: nuke our context if we have it. This is hacky and bad - we should really destroy
// our buffers and sources. I have _no_ idea if OpenAL will leak memory.
if(alcGetCurrentContext() != NULL)
{
printf("0x%08x: deleting snd %d\n", XPLMGetMyID(),snd_buffer);
if(snd_src) alDeleteSources(1,&snd_src);
if(snd_buffer) alDeleteBuffers(1,&snd_buffer);
}
if(my_ctx)
{
printf("0x%08x: deleting my context 0x%08x\n", XPLMGetMyID(),my_ctx);
alcMakeContextCurrent(NULL);
alcDestroyContext(my_ctx);
}
if(my_dev) alcCloseDevice(my_dev);
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API void XPluginReceiveMessage(XPLMPluginID from, int msg, void * p)
{
switch(msg) {
case XPLM_MSG_PLANE_LOADED:
if(snd_src)
{
printf("0x%08x: Playing %s (%d)\n",XPLMGetMyID(), "sound", snd_src);
// An example of actually playing the sound. First we change to our
// context, then we play the sound at pitch, then we change the context back.
// We check for null contexts both for us (our init failed) and the old context
// (X-plane's sound failed).
alSourcef(snd_src,AL_PITCH,pitch);
alSourcePlay(snd_src);
pitch *= 1.1f;
CHECK_ERR();
}
break;
}
}
/*
* TimedProcessing.c
*
* This example plugin demonstrates how to use the timed processing callbacks
* to continuously record sim data to disk.
*
* This technique can be used to record data to disk or to the network. Unlike
* UDP data output, we can increase our frequency to capture data every single
* sim frame. (This example records once per second.)
*
* Use the timed processing APIs to do any periodic or asynchronous action in
* your plugin.
*
*/
#if APL
#if defined(__MACH__)
#include <Carbon/Carbon.h>
#endif
#endif
#include <stdio.h>
#include <string.h>
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMUtilities.h"
/* File to write data to. */
static FILE * gOutputFile;
/* Data refs we will record. */
static XPLMDataRef gPlaneLat;
static XPLMDataRef gPlaneLon;
static XPLMDataRef gPlaneEl;
#if APL && __MACH__
static int ConvertPath(const char * inPath, char * outPath, int outPathMaxLen);
#endif
static float MyFlightLoopCallback(
float inElapsedSinceLastCall,
float inElapsedTimeSinceLastFlightLoop,
int inCounter,
void * inRefcon);
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
char outputPath[255];
#if APL && __MACH__
char outputPath2[255];
int Result = 0;
#endif
strcpy(outName, "TimedProcessing");
strcpy(outSig, "xplanesdk.examples.timedprocessing");
strcpy(outDesc, "A plugin that records sim data.");
/* Open a file to write to. We locate the X-System directory
* and then concatenate our file name. This makes us save in
* the X-System directory. Open the file. */
XPLMGetSystemPath(outputPath);
strcat(outputPath, "TimedProcessing.txt");
#if APL && __MACH__
Result = ConvertPath(outputPath, outputPath2, sizeof(outputPath));
if (Result == 0)
strcpy(outputPath, outputPath2);
else
XPLMDebugString("TimedProccessing - Unable to convert path\n");
#endif
gOutputFile = fopen(outputPath, "w");
/* Find the data refs we want to record. */
gPlaneLat = XPLMFindDataRef("sim/flightmodel/position/latitude");
gPlaneLon = XPLMFindDataRef("sim/flightmodel/position/longitude");
gPlaneEl = XPLMFindDataRef("sim/flightmodel/position/elevation");
/* Register our callback for once a second. Positive intervals
* are in seconds, negative are the negative of sim frames. Zero
* registers but does not schedule a callback for time. */
XPLMRegisterFlightLoopCallback(
MyFlightLoopCallback, /* Callback */
1.0, /* Interval */
NULL); /* refcon not used. */
return 1;
}
PLUGIN_API void XPluginStop(void)
{
/* Unregister the callback */
XPLMUnregisterFlightLoopCallback(MyFlightLoopCallback, NULL);
/* Close the file */
fclose(gOutputFile);
}
PLUGIN_API void XPluginDisable(void)
{
/* Flush the file when we are disabled. This is convenient; you
* can disable the plugin and then look at the output on disk. */
fflush(gOutputFile);
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginReceiveMessage(
XPLMPluginID inFromWho,
int inMessage,
void * inParam)
{
}
float MyFlightLoopCallback(
float inElapsedSinceLastCall,
float inElapsedTimeSinceLastFlightLoop,
int inCounter,
void * inRefcon)
{
/* The actual callback. First we read the sim's time and the data. */
float elapsed = XPLMGetElapsedTime();
float lat = XPLMGetDataf(gPlaneLat);
float lon = XPLMGetDataf(gPlaneLon);
float el = XPLMGetDataf(gPlaneEl);
/* Write the data to a file. */
fprintf(gOutputFile, "Time=%f, lat=%f,lon=%f,el=%f.\n",elapsed, lat, lon, el);
/* Return 1.0 to indicate that we want to be called again in 1 second. */
return 1.0;
}
#if APL && __MACH__
#include <Carbon/Carbon.h>
int ConvertPath(const char * inPath, char * outPath, int outPathMaxLen)
{
CFStringRef inStr = CFStringCreateWithCString(kCFAllocatorDefault, inPath ,kCFStringEncodingMacRoman);
if (inStr == NULL)
return -1;
CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inStr, kCFURLHFSPathStyle,0);
CFStringRef outStr = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
if (!CFStringGetCString(outStr, outPath, outPathMaxLen, kCFURLPOSIXPathStyle))
return -1;
CFRelease(outStr);
CFRelease(url);
CFRelease(inStr);
return 0;
}
#endif
/*
* SimData.c
*
* This example demonstrates how to interact with X-Plane by reading and writing
* data. This example creates menus items that change the nav-1 radio frequency.
*
*/
#include <stdio.h>
#include <string.h>
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"
/* We keep our data ref globally since only one is used for the whole plugin. */
static XPLMDataRef gDataRef = NULL;
static void MyMenuHandlerCallback(
void * inMenuRef,
void * inItemRef);
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
XPLMMenuID myMenu;
int mySubMenuItem;
/* Provide our plugin's profile to the plugin system. */
strcpy(outName, "SimData");
strcpy(outSig, "xplanesdk.examples.simdata");
strcpy(outDesc, "A plugin that changes sim data.");
/* First we put a new menu item into the plugin menu.
* This menu item will contain a submenu for us. */
mySubMenuItem = XPLMAppendMenuItem(
XPLMFindPluginsMenu(), /* Put in plugins menu */
"Sim Data", /* Item Title */
0, /* Item Ref */
1); /* Force English */
/* Now create a submenu attached to our menu item. */
myMenu = XPLMCreateMenu(
"Sim Data",
XPLMFindPluginsMenu(),
mySubMenuItem, /* Menu Item to attach to. */
MyMenuHandlerCallback, /* The handler */
0); /* Handler Ref */
/* Append a few menu items to our submenu. We will use the refcon to
* store the amount we want to change the radio by. */
XPLMAppendMenuItem(
myMenu,
"Decrement Nav1",
(void *) -1000,
1);
XPLMAppendMenuItem(
myMenu,
"Increment Nav1",
(void *) +1000,
1);
/* Look up our data ref. You find the string name of the data ref
* in the master list of data refs, including in HTML form in the
* plugin SDK. In this case, we want the nav1 frequency. */
gDataRef = XPLMFindDataRef("sim/cockpit/radios/nav1_freq_hz");
/* Only return that we initialized correctly if we found the data ref. */
return (gDataRef != NULL) ? 1 : 0;
}
PLUGIN_API void XPluginStop(void)
{
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginReceiveMessage(
XPLMPluginID inFromWho,
int inMessage,
void * inParam)
{
}
void MyMenuHandlerCallback(
void * inMenuRef,
void * inItemRef)
{
/* This is our handler for the menu item. Our inItemRef is the refcon
* we registered in our XPLMAppendMenuItem calls. It is either +1000 or
* -1000 depending on which menu item is picked. */
if (gDataRef != NULL)
{
/* We read the data ref, add the increment and set it again.
* This changes the nav frequency. */
XPLMSetDatai(gDataRef, XPLMGetDatai(gDataRef) + (int) inItemRef);
}
}
/*
* ShareData.c
*
* This is an example plugin that demonstrates how to share data, both owned
* by a plugin and shared.
*
* Data can be published in two ways: a plugin can publish data it owns.
* In this case, it provides callbacks to read (and optionally write) the
* data. As other plugins access the data ref, the SDK calls back the
* accessors.
*
* Data can also be shared. In this case, the SDK allocates the memory
* for the data. Each plugin that shares it registers a callback that is
* called by the SDK when any plugin writes the data.
*
* We use the xplanesdk namespace to allocate unique data refs. When creating
* your own datarefs, make sure to prefix the data ref with a domain unique to
* your organization. 'sim' is the domain for the main simulator.
*
*/
#include <stdio.h>
#include <string.h>
#include "XPLMDataAccess.h"
#include "XPLMUtilities.h"
/* This is the storage for the data we own. */
static double gOwnedData = 0.0;
static XPLMDataRef gOwnedDataRef = NULL;
static XPLMDataRef gSharedDataRef = NULL;
/* These callbacks are called by the SDK to read and write the sim.
* We provide two sets of callbacks allowing our data to appear as
* float and double. This is done for didactic purposes; multityped
* data is provided as a backward compatibility solution and probably
* should not be used in initial designs as a convenience to client
* code. */
static float MyGetDatafCallback(void * inRefcon);
static void MySetDatafCallback(void * inRefcon, float inValue);
static double MyGetDatadCallback(void * inRefcon);
static void MySetDatadCallback(void * inRefcon, double inValue);
/* This callback is called whenever our shared data is changed. */
static void MyDataChangedCallback(void * inRefcon);
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
int RetVal;
char Buffer[256];
strcpy(outName, "SharedData");
strcpy(outSig, "xplanesdk.examples.shareddata");
strcpy(outDesc, "A plugin that shares a data ref.");
/* Register our owned data. Note that we pass two sets of
* function callbacks for two data types and leave the rest blank. */
gOwnedDataRef = XPLMRegisterDataAccessor(
"xplanesdk/examples/sharedata/number",
xplmType_Float + xplmType_Double, /* The types we support */
1, /* Writable */
NULL, NULL, /* No accessors for ints */
MyGetDatafCallback, MySetDatafCallback, /* Accessors for floats */
MyGetDatadCallback, MySetDatadCallback, /* Accessors for doubles */
NULL, NULL, /* No accessors for int arrays */
NULL, NULL, /* No accessors for float arrays */
NULL, NULL, /* No accessors for raw data */
NULL, NULL); /* Refcons not used */
/* Subscribe to shared data. If no one else has made it, this will
* cause the SDK to allocate the data. */
RetVal = XPLMShareData("xplanesdk/examples/sharedata/sharedint", xplmType_Int,
MyDataChangedCallback, NULL);
gSharedDataRef = XPLMFindDataRef("xplanesdk/examples/sharedata/sharedint");
sprintf(Buffer, "ShareData 2 - gSharedDataRef := %x\n", gSharedDataRef);
XPLMDebugString(Buffer);
return 1;
}
PLUGIN_API void XPluginStop(void)
{
int RetVal;
if (gOwnedDataRef)
XPLMUnregisterDataAccessor(gOwnedDataRef);
RetVal = XPLMUnshareData("xplanesdk/examples/sharedata/sharedint", xplmType_Int,
MyDataChangedCallback, NULL);
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginReceiveMessage(
XPLMPluginID inFromWho,
int inMessage,
void * inParam)
{
}
/*
* These are the data accessors for our owned data.
*
*/
float MyGetDatafCallback(void * inRefcon)
{
return gOwnedData;
}
void MySetDatafCallback(void * inRefcon, float inValue)
{
gOwnedData = inValue;
}
double MyGetDatadCallback(void * inRefcon)
{
return gOwnedData;
}
void MySetDatadCallback(void * inRefcon, double inValue)
{
gOwnedData = inValue;
}
/*
* This is the callback for our shared data. Right now we do not react
* to our shared data being chagned.
*
*/
void MyDataChangedCallback(void * inRefcon)
{
}
#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMMenus.h"
#include "XPLMUtilities.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include "XPLMCamera.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#if IBM
#include <windows.h>
#endif
#define MAX_ITEMS 11
static XPLMDataRef gPositionDataRef[MAX_ITEMS];
static char DataRefString[MAX_ITEMS][255] = { "sim/flightmodel/position/local_x", "sim/flightmodel/position/local_y", "sim/flightmodel/position/local_z",
"sim/flightmodel/position/lat_ref", "sim/flightmodel/position/lon_ref", "sim/flightmodel/position/theta",
"sim/flightmodel/position/phi", "sim/flightmodel/position/psi",
"sim/flightmodel/position/latitude", "sim/flightmodel/position/longitude", "sim/flightmodel/position/elevation"};
static char DataRefDesc[MAX_ITEMS][255] = {"Local x", "Local y", "Local z", "Lat Ref", "Lon Ref", "Theta", "Phi", "Psi"};
static char Description[3][255] = {"Latitude", "Longitude", "Elevation"};
static int Element = 0, IntVals[128];
static float FloatVals[128];
static int ByteVals[128];
static int MenuItem1;
static XPWidgetID PositionWidget = NULL, PositionWindow = NULL;
static XPWidgetID PositionApplyButton = NULL;
static XPWidgetID PositionText[MAX_ITEMS] = {NULL};
static XPWidgetID PositionEdit[MAX_ITEMS] = {NULL};
static XPWidgetID UpArrow[MAX_ITEMS] = {NULL};
static XPWidgetID DownArrow[MAX_ITEMS] = {NULL};
static XPWidgetID LatLonAltApplyButton = NULL, LatLonRefApplyButton = NULL, ReloadSceneryButton = NULL;
static XPWidgetID Position2Text[3] = {NULL};
static XPWidgetID Position2Edit[3] = {NULL};
static void PositionMenuHandler(void *, void *);
static void CreatePosition(int x1, int y1, int w, int h);
static int PositionHandler(
XPWidgetMessage inMessage,
XPWidgetID inWidget,
intptr_t inParam1,
intptr_t inParam2);
static void DisplayFindDataRef(void);
static void ApplyValues(void);
static void ApplyLatLonRefValues(void);
static void ApplyLatLonAltValues(void);
inline float HACKFLOAT(float val)
{
return val;
}
/*
#if IBM
inline float HACKFLOAT(float val)
{
return val;
}
#else
inline long long HACKFLOAT(float val)
{
double d = val;
long long temp;
temp = *((long long *) &d);
return temp;
}
#endif
*/
PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc)
{
XPLMMenuID id;
int item;
strcpy(outName, "Position");
strcpy(outSig, "xpsdk.examples.position");
strcpy(outDesc, "A plug-in that allows positioning of lat/lon etc.");
item = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "Position", NULL, 1);
id = XPLMCreateMenu("Position", XPLMFindPluginsMenu(), item, PositionMenuHandler, NULL);
XPLMAppendMenuItem(id, "Position", (void *)"Position", 1);
MenuItem1 = 0;
for (int Item=0; Item<MAX_ITEMS; Item++)
gPositionDataRef[Item] = XPLMFindDataRef(DataRefString[Item]);
return 1;
}
PLUGIN_API void XPluginStop(void)
{
if (MenuItem1 == 1)
{
XPDestroyWidget(PositionWidget, 1);
MenuItem1 = 0;
}
}
PLUGIN_API void XPluginDisable(void)
{
}
PLUGIN_API int XPluginEnable(void)
{
return 1;
}
PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, int inMsg, void * inParam)
{
}
void PositionMenuHandler(void * mRef, void * iRef)
{
if (!strcmp((char *) iRef, "Position"))
{
if (MenuItem1 == 0)
{
CreatePosition(300, 600, 300, 550);
MenuItem1 = 1;
}
else
if(!XPIsWidgetVisible(PositionWidget))
XPShowWidget(PositionWidget);
}
}
void CreatePosition(int x, int y, int w, int h)
{
int x2 = x + w;
int y2 = y - h;
float FloatValue[MAX_ITEMS];
double DoubleValue[3];
char buffer[512];
int Item;
for (Item=0; Item<MAX_ITEMS; Item++)
FloatValue[Item] = XPLMGetDataf(gPositionDataRef[Item]);
/// X, Y, Z, Lat, Lon, Alt
XPLMLocalToWorld(FloatValue[0], FloatValue[1], FloatValue[2], &DoubleValue[0], &DoubleValue[1], &DoubleValue[2]);
DoubleValue[2] *= 3.28;
PositionWidget = XPCreateWidget(x, y, x2, y2,
1, // Visible
"Position", // desc
1, // root
NULL, // no container
xpWidgetClass_MainWindow);
XPSetWidgetProperty(PositionWidget, xpProperty_MainWindowHasCloseBoxes, 1);
PositionWindow = XPCreateWidget(x+50, y-50, x2-50, y2+50,
1, // Visible
"", // desc
0, // root
PositionWidget,
xpWidgetClass_SubWindow);
XPSetWidgetProperty(PositionWindow, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);
for (Item=0; Item<MAX_ITEMS-3; Item++)
{
PositionText[Item] = XPCreateWidget(x+60, y-(70 + (Item*30)), x+115, y-(92 + (Item*30)),
1, // Visible
DataRefDesc[Item],// desc
0, // root
PositionWidget,
xpWidgetClass_Caption);
sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
PositionEdit[Item] = XPCreateWidget(x+120, y-(70 + (Item*30)), x+210, y-(92 + (Item*30)),
1, buffer, 0, PositionWidget,
xpWidgetClass_TextField);
XPSetWidgetProperty(PositionEdit[Item], xpProperty_TextFieldType, xpTextEntryField);
UpArrow[Item] = XPCreateWidget(x+212, y-(66 + (Item*30)), x+224, y-(81 + (Item*30)),
1, "", 0, PositionWidget,
xpWidgetClass_Button);
XPSetWidgetProperty(UpArrow[Item], xpProperty_ButtonType, xpLittleUpArrow);
DownArrow[Item] = XPCreateWidget(x+212, y-(81 + (Item*30)), x+224, y-(96 + (Item*30)),
1, "", 0, PositionWidget,
xpWidgetClass_Button);
XPSetWidgetProperty(DownArrow[Item], xpProperty_ButtonType, xpLittleDownArrow);
}
PositionApplyButton = XPCreateWidget(x+50, y-310, x+140, y-332,
1, "Apply Data", 0, PositionWidget,
xpWidgetClass_Button);
XPSetWidgetProperty(PositionApplyButton, xpProperty_ButtonType, xpPushButton);
LatLonRefApplyButton = XPCreateWidget(x+145, y-310, x+240, y-332,
1, "Apply LatLonRef", 0, PositionWidget,
xpWidgetClass_Button);
XPSetWidgetProperty(LatLonRefApplyButton, xpProperty_ButtonType, xpPushButton);
for (Item=0; Item<3; Item++)
{
Position2Text[Item] = XPCreateWidget(x+60, y-(350 + (Item*30)), x+115, y-(372 + (Item*30)),
1, // Visible
Description[Item],// desc
0, // root
PositionWidget,
xpWidgetClass_Caption);
sprintf(buffer, "%lf", HACKFLOAT(DoubleValue[Item]));
Position2Edit[Item] = XPCreateWidget(x+120, y-(350 + (Item*30)), x+210, y-(372 + (Item*30)),
1, buffer, 0, PositionWidget,
xpWidgetClass_TextField);
XPSetWidgetProperty(PositionEdit[Item], xpProperty_TextFieldType, xpTextEntryField);
}
LatLonAltApplyButton = XPCreateWidget(x+70, y-440, x+220, y-462,
1, "Apply LatLonAlt", 0, PositionWidget,
xpWidgetClass_Button);
XPSetWidgetProperty(LatLonAltApplyButton, xpProperty_ButtonType, xpPushButton);
ReloadSceneryButton = XPCreateWidget(x+70, y-465, x+220, y-487,
1, "Reload Scenery", 0, PositionWidget,
xpWidgetClass_Button);
XPSetWidgetProperty(ReloadSceneryButton, xpProperty_ButtonType, xpPushButton);
XPAddWidgetCallback(PositionWidget, PositionHandler);
}
int PositionHandler(
XPWidgetMessage inMessage,
XPWidgetID inWidget,
intptr_t inParam1,
intptr_t inParam2)
{
float FloatValue[MAX_ITEMS];
char buffer[512];
int Item;
for (Item=0; Item<MAX_ITEMS; Item++)
FloatValue[Item] = XPLMGetDataf(gPositionDataRef[Item]);
if (inMessage == xpMessage_CloseButtonPushed)
{
if (MenuItem1 == 1)
{
XPHideWidget(PositionWidget);
}
return 1;
}
if (inMessage == xpMsg_PushButtonPressed)
{
if (inParam1 == (intptr_t)PositionApplyButton)
{
ApplyValues();
return 1;
}
if (inParam1 == (intptr_t)LatLonRefApplyButton)
{
ApplyLatLonRefValues();
return 1;
}
if (inParam1 == (intptr_t)LatLonAltApplyButton)
{
ApplyLatLonAltValues();
return 1;
}
if (inParam1 == (intptr_t)ReloadSceneryButton)
{
XPLMReloadScenery();
return 1;
}
for (Item=0; Item<MAX_ITEMS-3; Item++)
{
if (inParam1 == (intptr_t)UpArrow[Item])
{
FloatValue[Item] += 1.0;
sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
XPSetWidgetDescriptor(PositionEdit[Item], buffer);
XPLMSetDataf(gPositionDataRef[Item], FloatValue[Item]);
return 1;
}
}
for (Item=0; Item<MAX_ITEMS-3; Item++)
{
if (inParam1 == (intptr_t)DownArrow[Item])
{
FloatValue[Item] -= 1.0;
sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
XPSetWidgetDescriptor(PositionEdit[Item], buffer);
XPLMSetDataf(gPositionDataRef[Item], FloatValue[Item]);
return 1;
}
}
}
return 0;
}
void ApplyValues(void)
{
char buffer[512];
for (int Item=0; Item<MAX_ITEMS-3; Item++)
{
XPGetWidgetDescriptor(PositionEdit[Item], buffer, 512);
XPLMSetDataf(gPositionDataRef[Item], atof(buffer));
}
}
void ApplyLatLonRefValues(void)
{
float FloatValue;
char buffer[512];
XPGetWidgetDescriptor(PositionEdit[3], buffer, 512);
FloatValue = atof(buffer);
XPLMSetDataf(gPositionDataRef[3], FloatValue);
XPGetWidgetDescriptor(PositionEdit[4], buffer, 512);
FloatValue = atof(buffer);
XPLMSetDataf(gPositionDataRef[4], FloatValue);
}
void ApplyLatLonAltValues(void)
{
float FloatValue[3];
double DoubleValue[3];
char buffer[512];
int Item;
// This gets the lat/lon/alt from the widget text fields
for (Item=0; Item<3; Item++)
{
XPGetWidgetDescriptor(Position2Edit[Item], buffer, 512);
FloatValue[Item] = atof(buffer);
}
/// Lat, Lon, Alt, X, Y, Z
XPLMWorldToLocal(FloatValue[0], FloatValue[1], FloatValue[2] / 3.28, &DoubleValue[0], &DoubleValue[1], &DoubleValue[2]);
for (Item=0; Item<3; Item++)
{
// This writes out the lat/lon/alt from the widget text fields back to the datarefs
XPLMSetDataf(gPositionDataRef[Item+8], FloatValue[Item]);
// This writes out the x,y,z datarefs after conversion from lat/lon/alt back to the datarefs
XPLMSetDataf(gPositionDataRef[Item], DoubleValue[Item]);
}
ApplyLatLonRefValues();
}