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

16 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!

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.