This sample shows off the new instancing API, used for efficiently drawing objects without needing to write OpenGL.

Note: We’ve created a compatibility wrapper for X-Plane 10 plugins that want to migrate to the new instancing API. This is useful if your plugin supports both X-Plane 10 and 11, and you want to use the same code for both—just set up the compatibility wrapper for the X-Plane 10 version only, and you’ll get the performance benefits of the new API in your X-Plane 11 version.

#include <XPLMInstance.h>
#include <XPLMDisplay.h>
#include <XPLMGraphics.h>
#include <XPLMMenus.h>
#include <XPLMUtilities.h>
#include <XPLMPlugin.h>
#include <XPLMDataAccess.h>
#include <cstdio>
#include <cstring>

#if !XPLM300
	#error This plugin requires version 300 of the SDK
#endif

const char * g_objPath = "lib/airport/vehicles/pushback/tug.obj";
XPLMObjectRef g_object = NULL;
XPLMInstanceRef g_instance[3] = {NULL};

static void load_cb(const char * real_path, void * ref)
{
	XPLMObjectRef * dest = (XPLMObjectRef *) ref;
	if(*dest == NULL)
	{
		*dest = XPLMLoadObject(real_path);
	}
}

static void menu_cb(
					void *               inMenuRef,
					void *				inItemRef)
{
	if(!g_object)
	{
		XPLMLookupObjects(g_objPath, 0, 0, load_cb, &g_object);
	}
	if(g_object)
	{
		const char * drefs[] = { "sim/graphics/animation/ground_traffic/tire_steer_deg", NULL };
		if(!g_instance[0])
		{
			g_instance[0] = XPLMCreateInstance(g_object, drefs);
		}
		else if(!g_instance[1])
		{
			g_instance[1] = XPLMCreateInstance(g_object, drefs);
		}
		else if(!g_instance[2])
		{
			g_instance[2] = XPLMCreateInstance(g_object, drefs);
		}
	}
	
	static XPLMDataRef x = XPLMFindDataRef("sim/flightmodel/position/local_x");
	static XPLMDataRef y = XPLMFindDataRef("sim/flightmodel/position/local_y");
	static XPLMDataRef z = XPLMFindDataRef("sim/flightmodel/position/local_z");
	static XPLMDataRef heading = XPLMFindDataRef("sim/flightmodel/position/psi");
	static XPLMDataRef pitch = XPLMFindDataRef("sim/flightmodel/position/theta");
	static XPLMDataRef roll = XPLMFindDataRef("sim/flightmodel/position/phi");
	
	static float tire = 0.0;
	tire += 10.0;
	if(tire > 45.0) tire -= 90.0;
	
	XPLMDrawInfo_t		dr;
	dr.structSize = sizeof(dr);
	dr.x = XPLMGetDataf(x);
	dr.y = XPLMGetDataf(y);
	dr.z = XPLMGetDataf(z);
	dr.pitch = XPLMGetDataf(pitch);
	dr.heading = XPLMGetDataf(heading);
	dr.roll = XPLMGetDataf(roll);
	
	if(g_instance[0] || g_instance[1] || g_instance[2])
	{
		XPLMInstanceSetPosition(g_instance[2] ? g_instance[2] : (g_instance[1] ? g_instance[1] : g_instance[0]), &dr, &tire);
	}
}


PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc)
{
	std::strcpy(outName, "InstancingSample");
	std::strcpy(outSig, "lr.samples.instancing");
	std::strcpy(outDesc, "Sample plugin demonstrating the instancing API");
	
	int my_slot = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "instancing_sample", NULL, 0);
	XPLMMenuID m = XPLMCreateMenu("instancing_sample", XPLMFindPluginsMenu(), my_slot, menu_cb, NULL);
	XPLMAppendMenuItem(m, "add instance", NULL, 0);
	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	for(int i = 0; i < 3; ++i)
	{
		if(g_instance[i])
			XPLMDestroyInstance(g_instance[i]);
	}
	if(g_object)
		XPLMUnloadObject(g_object);
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API void XPluginReceiveMessage(XPLMPluginID, long, void*)
{
}

21 comments on “X-Plane 11 Instanced Drawing Sample

  1. Thanks for the example.
    I have a question though. I use 3D objects in my plugin to represent physical “staff” in X-Plane 3D space. I manage and “drive” them through the plugin code and not through any dataref (since they are not manipulators or scenery objects, they are “mission” 3D objects).
    For example: to draw a moving 3D object, I calculate their delta location between each frame and then call the “draw” command with the “new” location in mind.
    Will this drawing technique fail tot work on XP11.10 without the wrapper ? Will “you” break this kind of code ?
    Currently I prefer not to invest to much energy on the “old” Mission-X plugin version since I’m writing it from scratch for XP11 and with future XPSDK300 features in mind (when they will be available).

    Another thing, when I click the Download links above, I receive “page not found”.
    Thanks for the code example though, It will save much needed time if I’ll be force to “fix” the old drawing calls.

    Cheers
    Saar

    1. This kind of code will keep working as long as you are using a GL-based X-Plane. But it will not work on a Vulkan-based X-PLane, so once we offer both, if the user picks Vulkan, you’ll be toast.

      This code path is better handled via the new instance-based object…you’d push new location data to us per frame and let us sort out when to call draw. This works even if you don’t use any datarefs – you always provide position and orientation.

  2. Hi again,

    I was just trying to implement the new instance code when I stumble the following code:

    const char * drefs[] = { “sim/graphics/animation/ground_traffic/tire_steer_deg”, NULL };
    if(!g_instance[0])
    {
    g_instance[0] = XPLMCreateInstance(g_object, drefs);
    }

    If I have an Obj8 file that I want to display, why do I need a dataref in the: “XPLMCreateInstance”. Can I just send a NULL value to this function ? If so, please add this in the function comments.

    Thanks
    Saar

    1. It looks to me like it is legal to use a NULL pointer for the dataref list if the dataref list would have been empty, e.g.
      const char * drefs = NULL;
      is okay in place of
      const char * drefs[] = { NULL }; // no datarefs

      If it doesn’t crash, it’s sane…it’s a reasonable bit of syntactic sugar.

      1. Hi,

        Providing NULL to the “dref[]” pointer prooved ok while…
        Providing NULL to the “&tire” argument in the C demo example to “XPLMInstanceSetPosition” did crashed X-Plane.

        My workaround:
        1. send NULL for dref[] and send dummy float value to “XPLMInstanceSetPosition”;

        Not sure if this is kosher.

        Thanks

          1. Hi – I’ve noticed the same behavior. If you provide NULL for the float value, XP crashes. However, providing a NULL for the data ref pointer seems to work just fine.

            Cheers.

  3. Hi and thanks for this sample code. I am trying to create a plugin for XPlane 11 with the same function of Draw-Terrain Sample Code, drawing a dynamic object that moves in relation to the aircraft, but I haven’t had success with this new Instancing API and I couldn’t understand it totally. Do you have any sample to do this with XP11?

    Thanks
    Amri

  4. Hi,
    Thank you for this example, it works with my custom object designed in Blender, but what about custom datarefs ?
    I’m trying to change from your’s
    sim/graphics/animation/ground_traffic/tire_steer_deg
    to
    sim/graphics/animation/ground_traffic/mycustom_ref_deg
    for example, at both place: in your code and in my custom object animation, but nothing works…
    I also tried to declare my custom dataref using XPLMRegisterDataAccessor(), but without success… where I’m wrong ?

    Could you give me/us small piece of code as example to declare and use custom datarefs, please ?

    Thanks

  5. Just a general question about the Instance API. Will object movement interpolation take place automatically by X-Plane (e.g I only provide starting position and velocity and X-Pplane does the rest) or do I have to calculate and update the actual positions and set them via DataRefs?

  6. Hi – thanks for providing an example and I got it to work. However, is there any way to influence the pivot point of an OBJ? Instead of a tug I’ve drawn an aircraft and when I change the heading, or pitch the object is not turning/pitching at the center of gravity, but rather at the nose of the plane.

    Thanks!

  7. Hi, is there any drawing example? This example doesn’t really draw instances. I’d like to see some example how to use draw callback for instances (or objects).
    Thanks!

  8. This code compiles, and produces a folder named X-Plane-11-Instanced-Drawing-Sample which contains the actual win.xpl, and this folder is copied to x-plane resources plugins. The menu entry instancing sample is present in the plugins menu, as is the option to add an instance.

    My aircraft is spawned at whatever airport, and I have pressed shift + 4 for external view.
    What exactly should I be seeing there, except for my own aircraft ?
    The reason I ask is: There is *nothing* at all to be seen at my aircraft position, except for my aircraft.

    If I understand the code, the tub.obj should be spawing at exactly my aircraft position for which the according datarefs have been queried and saved stored, then the XPLMDrawInfo_t (struct resembling type) is fed with the data from the stored datarefs, and passed to XPLMInstanceSetPosition along with the tug object reference that is pointing to a supposedly loaded tub.obj.

    Using X-Plane 11.51r1 and a response would be greatly appreciated.

  9. I’ve compiled the plugin, and the execution in the simulator 11.51r1 has been verified using the debugger. When I click the menu option to add an instance, the code is executed but I see nothing in the simulator, neither in OpenGL nor in Vulkan.
    I would be expecting to see the tug spawn at the position of my aircraft, and at least just sit there, but nothing is visible at all.

    1. I had the same result. After some debugging (and a little dumb luck) I figured out that the better pushback plugin messes with the default tug object. So if you have that plugin installed you can move it out of the plugins directory and try again. Alternatively, you can load a different object by changing the virtual path assigned to g_objPath. For example, to load the fuel truck instead, you can change the value to “lib/airport/vehicles/fuel/hyd_disp_truck.obj.”

      TIP: To find virtual paths to other default objects you can load, take a look at “Resources/default scenery/sim objects/library.txt

      Hope this helps!

  10. The sample runs fine in my X-Plane V11.53 and I see the tug appearing on the aircraft position after selecting the menu option to add an instance.

    However, configuring a second PC with the same Version on it as External Channel (the master runs the test Plugin) with the same viewport settings I can observe
    * The Tug object is only added on the Master, but nothing appears on the External Channel.
    * The View direction and position syncs fine.
    * The tug model is visible in the airport traffic on both PCs, so the model file is available.

    I wonder why is the Instance Loaded Object is not synchronised to the external channel. Is that a bug or is there anything else I need to so in the plugin or in the setup?

    Tried on Windows7, x64 an Ubuntu18.04,x64

Leave a Reply

Your email address will not be published. Required fields are marked *

Please do not report bugs in the blog comments.
Only bugs reported via the X-Plane Bug Reporter are tracked.