XPLMGraphics

To use:

import xp

A few notes on coordinate systems:

X-Plane uses three kinds of coordinates. Global coordinates are specified as latitude, longitude and elevation. This coordinate system never changes but is not very precise.

OpenGL (or ‘local’) coordinates are Cartesian and shift with the plane. They offer more precision and are used for 3-d OpenGL drawing. The X axis is aligned east-west with positive X meaning east. The Y axis is aligned straight up and down at the point 0,0,0 (but since the earth is round it is not truly straight up and down at other points). The Z axis is aligned north-south at 0, 0, 0 with positive Z pointing south (but since the earth is round it isn’t exactly north-south as you move east or west of 0, 0, 0). One unit is one meter and the point 0,0,0 is on the surface of the earth at sea level for some latitude and longitude picked by the sim such that the user’s aircraft is reasonably nearby.

Cockpit coordinates are 2d, with the X axis horizontal and the Y axis vertical. The point 0,0 is the bottom left and 1024,768 is the upper right of the screen. This is true no matter what resolution the user’s monitor is in; when running in higher resolution, graphics will be scaled.

Use X-Plane’s routines to convert between global and local coordinates. Do not attempt to do this conversion yourself; the precise ‘roundness’ of X-Plane’s physics model may not match your own, and (to make things weirder) the user can potentially customize the physics of the current planet.

These functions are divided into three sections:

OpenGL Functions

setGraphicsState(fog=0, numberTexUnits=0, lighting=0, alphaTesting=0, alphaBlending=0, depthTesting=0, depthWriting=0)
Parameters
  • fog (int) – (GL_FOG)

  • numberTexUnits (int) – (GL_TEXTURE_2D)

  • lighting (int) – (GL_LIGHTING)

  • alphaTesting (int) – (GL_ALPHA_TEST)

  • alphaBlending (int) – (GL_BLEND)

  • depthTesting (int) – (GL_DEPTH_TEST)

  • depthWriting (int) – glDepthMask(GL_TRUE)

Changes OpenGL’s graphics state. Use these instead of glEnable() and glDisable()

The purpose of this function is to change OpenGL state while keeping X-Plane aware of the state changes; this keeps X-Plane from getting surprised by OGL state changes, and prevents X-Plane and plug-ins from having to set all state before all draws; setGraphicsState() internally skips calls to change state that is already properly enabled.

X-Plane does not have a ‘default’ OGL state to plug-ins; plug-ins should totally set OGL state before drawing. Use setGraphicsState() instead of any of the OpenGL glEnable / glDisable calls below.

Warning

Any routine that performs drawing (e.g. XPLMDrawString() or widget code) may change X-Plane’s state. Always set state before drawing after unknown code has executed.

fog: enables or disables fog, equivalent to: glEnable(GL_FOG);

numberTexUnits: enables or disables a number of multitexturing units. If the number is 0, 2d texturing is disabled entirely, as in glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a number of multitexturing units are enabled sequentially, starting with unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB);  glEnable(GL_TEXTURE_2D);

lighting: enables or disables OpenGL lighting, e.g. glEnable(GL_LIGHTING); glEnable(GL_LIGHT0);

alphaTesting: enables or disables the alpha test per pixel: glEnable(GL_ALPHA_TEST);

alphaBlending: enables or disables alpha blending per pixel: glEnable(GL_BLEND);

depthTesting: enables per pixel depth testing, as in glEnable(GL_DEPTH_TEST);

depthWriting: enables writing back of depth information to the depth bufffer, as in glDepthMask(GL_TRUE);

X-Plane’s lighting and fog environment is significantly more complex than the fixed function pipeline can express; do not assume that lighting and fog state is a good approximation for 3-d drawing. Prefer to use XPLMInstance API to draw objects. Calls to setGraphicsState should have no fog or lighting.

Official SDK XPLMSetGraphicsState

bindTexture2d(textureID, textureUnit)
Parameters
  • textureID (int) – ID of texture to be bound (

  • textureUnit (int) – Unit id (0-3)

Changes currently bound texture.

This routine caches the current 2d texture across all texturing units in the sim and plug-ins, preventing extraneous binding. For example, consider several plug-ins running in series; if they all use the ‘general interface’ bitmap to do UI, calling this function will skip the rebinding of the general interface texture on all but the first plug-in, which can provide better frame rates on some graphics cards.

textureID is the ID of the texture object to bind; textureUnit is a zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 units. (This number may increase in future versions of x-plane.)

Use this routine instead of:

glBindTexture(GL_TEXTURE_2D, textureID);
glActiveTexture(GL_TEXTURE0 + textureUnit);  // I think...

Official SDK XPLMBindTexture2d

generateTextureNumbers(count)
Parameters

count (int) – Count of texture numbers to be generated

Returns

List[int] texture number(s). Note a list generated even for count == 1

Generate number of textures for a plugin.

This routine generates unused texture numbers (ints) that a plug-in can use to safely bind textures.

Use this routine instead of glGenTextures; glGenTextures will allocate texture numbers in ranges that X-Plane reserves for its own use but does not always use; for example, it might provide an ID within the range of textures reserved for terrain…loading a new .env file as the plane flies might then cause X-Plane to use this texture ID. X-Plane will then overwrite the plug-ins texture.

This routine returns a list of integer texture IDs that are out of X-Plane’s usage range.

>>> tex_num = xp.generateTextureNumbers(1)[0]
>>> xp.bindTexture2d(tex_num, 0)
>>> GL.glDeleteTextures(1, tex_num)

See demo code in plugin PI_TextureDraw.py

Official SDK XPLMGenerateTextureNumbers

getTexture(textureID)
Parameters

textureID (XPLMTextureID) – One of specific XPLMTextureID

Returns

OpenGL texture ID

Return the OpenGL texture ID of an X-Plane texture based on a generic identifying code (XPLMTextureID). For example, you can get the texture for X-Plane’s weather radar using the Tex_Radar_Pilot.

There aren’t a lot of textures which can be obtained using this function, but here’s an example using Tex_Radar_Pilot.

To see this, you need to be executing within an aircraft that supports weather radar, such as the Cirrus Vision SF50 jet. With engine running, bring up the radar on the MFD (this way you know the radar is running with the proper settings (I don’t know how to do this setup programmatically.) Now, to create a custom avionics device (see createAvionicsEx()) do the following:

>>> from XPPython3 import xpgl
>>> from OpenGL import GL
>>> def MyScreenDraw(refCon):
...    xpgl.clear()
...    xp.bindTexture2d(xp.getTexture(xp.Tex_Radar_Pilot), 0)
...    xp.setGraphicsState(numberTexUnits=1)
...    GL.glBegin(GL.GL_QUADS)
...    GL.glTexCoord(1, 0); GL.glVertex(refCon['width'], 0)
...    GL.glTexCoord(0, 0); GL.glVertex(0, 0)
...    GL.glTexCoord(0, 1); GL.glVertex(0, refCon['height'])
...    GL.glTexCoord(1, 1); GL.glVertex(refCon['width'], refCon['height'])
...    GL.glEnd()
...    xp.setGraphicsState(numberTexUnits=0)
...    GL.glFlush()
...
>>> def MyBezelDraw(_r, _g, _b, refCon):
...    xp.setGraphicsState(depthWriting=1, alphaBlending=1)
...    xpgl.drawPolygon([(0, 0),
...                      (0, refCon['height']),
...                      (refCon['width'], refCon['height']),
...                      (refCon['width'], 0)],
...                     color=xpgl.Colors['black'])
...
>>> info = {'width': 200, 'height': 200}
>>> avionicsID = xp.createAvionicsEx(
...     screenDraw=MyScreenDraw, bezelDraw=MyBezelDraw,
...     screenWidth=info['width'], screenHeight=info['height'],
...     bezelWidth=info['width'], bezelHeight=info['height'],
...     screenOffsetX=0, screenOffsetY=0,
...     refCon=info)
...
>>> xp.setAvionicsPopupVisible(avionicsID)

As common with custom avionics devices, we draw a black background using the bezel, and then draw the screen on top. The following image shows the MFD on the left, and our simple weather radar device on the right, both updating with the radar scan.

../../_images/weatherRadarTexture.png

Official SDK XPLMGetTexture

Coordinate Conversion Functions

worldToLocal(lat, lon, alt=0)
Parameters
  • lat (float) –

  • lon (float) – Latitude and longitude in decimal degrees

  • alt (float) – Altitude in meters MSL

Returns

Tuple of three floats in meters, in local OpenGL coordinate system.

Convert Lat/Lon/Alt to local scene coordinates (x, y, z)

Note that not all the world is available at the same time. You will get a value for a location half-way around the world, but it won’t make sense. As the location gets close (i.e., “in-region”), the OpenGL coordinates will be correct and useful.

>>> lat = xp.getDatad(xp.findDataRef('sim/flightmodel/position/latitude'))
>>> lon = xp.getDatad(xp.findDataRef('sim/flightmodel/position/longitude'))
>>> alt = xp.getDatad(xp.findDataRef('sim/flightmodel/position/elevation'))
>>> (lat, lon, alt)
(47.463586666721014, -122.30775530395267, 122.93034338392317)
>>> xp.worldToLocal(lat, lon, alt)
(-23161.567539629053, 79.61748455422719, 4007.734676883242)
>>> xp.localToWorld(*xp.worldToLocal(lat, lon, alt))
(47.463586666721014, -122.30775530395267, 122.93034338392317)

Official SDK XPLMWorldToLocal

localToWorld(x, y, z)
Parameters
  • x (float) –

  • y (float) –

  • z (float) – Local OpenGL scene coordinates

Returns

Tuple of three floats matching latitude, longitude (degrees) and altitude (meters)

Convert local scene coordinates (x, y, z) to Lat/Lon/Alt

This routine translates a local coordinate triplet back into latitude, longitude, and altitude. Latitude and longitude are in decimal degrees, and altitude is in meters MSL (mean sea level). The XYZ coordinates are in meters in the local OpenGL coordinate system.

Returns tuple of three floats (lat, lon, alt).

Note

World coordinates are less precise than local coordinates; you should try to avoid round tripping from local to world and back.

>>> x = xp.getDataf(xp.findDataRef('sim/graphics/view/view_x'))
>>> y = xp.getDataf(xp.findDataRef('sim/graphics/view/view_y'))
>>> z = xp.getDataf(xp.findDataRef('sim/graphics/view/view_z'))
>>> (x, y, z)
(-23161.3359375, 79.97235870361328, 4007.6552734375)
>>> xp.localToWorld(x, y, z)
(47.46358739027689, -122.3977522090232, 123.28432321269065)
>>> xp.worldToLocal(*xp.localToWorld(x, y, z))
(-23161.335585060915, 79.9723599828585, 4007.655274833594)

Official SDK XPLMLocalToWorld

Basic Drawing Functions

Note drawTranslucentDarkBox(), drawString(), and drawNumber() must be called within a draw callback: they will not work otherwise.

drawTranslucentDarkBox(left, top, right, bottom)
Parameters
  • left (int) –

  • top (int) –

  • right (int) –

  • bottom (int) – coordinates of box to be drawn in screen coordinates

Draw translucent dark box at location (left, top, right, bottom)

This routine draws a translucent dark box, partially obscuring parts of the screen but making text easy to read. This is the same graphics primitive used by X-Plane to show text files and ATC info.

>>> def MyDraw(phase, after, refCon):
...     width, height = xp.getScreenSize()
...     xp.drawTranslucentDarkBox(100, height - 100, 300, height - 200)
...
>>> xp.registerDrawCallback(MyDraw)
../../_images/translucentDarkBox.png

Official SDK XPLMDrawTranslucentDarkBox

drawString(rgb=white_tuple, x=0, y=0, value='', wordWrapWidth=None, fontID=Font_Proportional)
Parameters
  • rgb (Tuple[float]) – (r, g, b) values ranging 0.0 to 1.0, defaults to white

  • x (int) –

  • y (int) – x and y location to start the string (lower left corner of the string)

  • value (str) – String to be displayed

  • wordWrapWidth (int) – None to not wrap, otherwise maximum width of string

  • fontId (int) – XPLMFontID value

Draw a string value at location (x, y) using given fontID (XPLMFontID). wordWrapWidth is either an integer width, or None: don’t word-wrap. rgb defaults to the tuple (1.0, 1.0, 1.0) which is white.

(x, y) represents the lower-left pixel of the string to be written. If wrapping occurs, (x, y) represent the lower-left of the first character written and the wrap extends downward from there.

>>> def MyDraw(phase, after, refCon):
...     xp.drawString((0, 1.0, 0), 10, 10, "Lower left")
...
>>> xp.registerDrawCallback(MyDraw)
../../_images/drawString.png

Official SDK XPLMDrawString

drawNumber(rgb=white_tuple, x=0, y=0, value=0.0, digits=-1, decimals=0, showSign=1, fontID=Font_Proportional)
Parameters
  • rgb (Tuple[float]) – (r, g, b) values ranging 0.0 to 1.0, defaults to white

  • x (int) –

  • y (int) – x and y location to start the display (lower left corner of the string)

  • value (float) – Value to be displayed

  • digits (int) –

  • decimals (int) – digit and decimals control formatting of floating point number

  • showSign (int) – include the sign.

  • fontId (int) – XPLMFontID value

This routine draws a number similar to the data output display in X-Plane. Pass in a color (r, g, b) as rgb tuple, which defaults to the tuple (1.0, 1.0, 1.0) or white. Pass position (x, y), a floating point value, and formatting info. Specify how many digits to show left of the decimal point (digits) and how many to show to the right (decimals) and showSign whether to show a sign, as well as the font (XPLMFontID).

If digits is -1, we’ll calculate correct width for digits left of the decimal point. Note X-Plane interprets the formatting loosely:

For value 150.925:

Decimals >>

Digits

0

1

2

3

4

-1

150

150.9

150.93

150.925

150.9250

0

1.5x2

150.9

150.93

150.925

150.9250

1

1.5x2

150.9

150.93

150.925

150.9250

2

1.5x2

150.9

150.93

150.925

150.9250

3

150

150.9

150.93

150.925

150.9250

4

150

150.9

150.93

150.925

150.9250

>>> def MyDraw(phase, after, refCon):
...     xp.drawNumber((1, .25, .75), 10, 10, 15.65, decimals=1)
...
>>> xp.registerDrawCallback(MyDraw)
../../_images/drawNumber.png
getFontDimensions(fontID)
Parameters

fontID (XPLMFontID) – one of XPLMFontID

Returns

3-element tuple: width, height, 1 if supports only digits

Retrieve a font info, for fontID. (XPLMFontID)

Returns tuple (width, height, digitsOnly) where digitsOnly is 1 if font only supports digits.

This routine returns the width and height of a character in a given font. It also tells you if the font only supports numeric digits. Note that for a proportional font the width will be an arbitrary, hopefully average width.

>>> xp.getFontDimensions(xp.Font_Basic)
(6, 10, 0)
>>> xp.getFontDimensions(xp.Font_Proportional)
(10, 10, 0)

Official SDK XPLMGetFontDimensions

measureString(fontID, string)
Parameters
  • fontID (XPLMFontID) – one of XPLMFontID

  • string (str) – string to be measured

Returns

floating point width of string

Return a width of a given string in a given font fontID (XPLMFontID).

The returned width is fractional pixels.

The full length of the string is measured: if you need to measure a substring, pass only that substring to this function. The return value is floating point; it is possible that future font drawing may allow for fractional pixels.

Note

A common use for this function is to determine the size of a widget in which to display the string. Note that widget sizes require integers, so you should cast or round the results of this function prior to use.

>>> xp.measureString(xp.Font_Basic, "Hello World")
66.0
>>> xp.measureString(xp.Font_Proportional, "Hello World")
65.0

Official SDK XPLMMeasureString

Constants

XPLMFontID

../../_images/font_example.png

X-Plane features some fixed-character fonts. Each font may have its own metrics.

Font_Basic = 0

Mono-spaced font for user interface. Available in all versions of the SDK.

Official SDK xplm_Font_Basic

Font_Proportional = 18

Proportional UI font.

Official SDK xplm_Font_Proportional

XPLMTextureID

Predefined texture bitmaps for use with getTexture().

Tex_GeneralInterface = 0

Window outlines, button outlines, fonts, etc.

Tex_Radar_Pilot = 3

Weather radar instrument texture as controlled by the pilot-side radar controls.

Tex_Radar_Copilot = 4

Weather radar instrument texture as controlled by the copilot-side radar controls

Official SDK XPLMTextureID