xpgl Images

To use:

from XPPython3 import xpgl

Images refer to files loaded from disk such as PNG, GIF or JPEG. In most cases, you’ll loadImage() during plugin startup, and then drawTexture() during your draw callback.

This requires the use of the python Pillow and numpy modules, and will generate an error if not already installed.

loadImage(filename, x=0, y=0, width=0, height=0) int
Parameters
  • filename (str) – Path to file, relative to X-Plane (e.g., “Resources/plugins/PythonPlugins/myfile.png”)

  • x (float) –

  • y (float) – Optional offset into the image from lower-left corner.

  • width (float) –

  • height (float) – Optional width and height of part of the image to be extracted

Returns

internal integer representing texture

In the simplest form, loadImage(filename), an image file is loaded into a texture, and an internal ID is returned. This ID is not an OpenGL texture ID, but represent a part of (perhaps all of) a texture.

Optionally, you can provide data to extract a portion of the file’s image. Specify the offset into the image (x, y), and the (width, height) of the portion to extract.

If the file is already loaded as a texture, that texture will be reused, saving GPU space. A separate internal ID will be returned representing the different portion of the texture to be displayed.

(Unlike SASL, we do not currently support a “search path” for resources.)

For performance reasons, images should not be loaded during a draw callback. For example, use the XPluginEnable() callback.

To load:

filename = "Resources/bitmaps/cockpit/radios/transponder/transponder_HM-1.png"
Data['fullID'] = xpgl.loadImage(filename)
Data['dials'] = []
for i in range(5):
    Data['dials'].append(xpgl.loadImage(filename, x=5 + i * 27, width=21, height=22))

In the above example code, we’ve loaded the single file which contains five images for a transponder dial. First we load the full image and save its ID as Data['fullID']. Then we load each individual dial with a separate ID. The underlying OpenGL Texture (containing all of transponder_HM-1.png) is loaded only once.

To display the full image, and separately display each individual dial, just reference the proper ID (note that if you provide a value for color, that color us used to replace white in the image.):

xpgl.drawRectangle(0, 0, 640, 480, color=Colors['light gray'])
xpgl.drawTexture(Data['fullID'], 100, 100, width=135, height=27)
for i in range(5):
    xpgl.drawTexture(Data['dials'][i], 100 + i * (22 + 10), 200 + (i * 5), width=22, height=27, color=Colors['green'])
../../_images/xpgl_loadImage.png
drawTexture(texture_id, x, y, width, height, color=None) None
Parameters
  • texture_id (int) – return from loadImage() for image to be displayed

  • x (float) –

  • y (float) – (x, y) location of the lower left corner of the texture

  • width (float) –

  • height (float) – Width and height of image to be displayed

  • color (RGBColor) – Optional color to use to “add” to the image

Returns

None

Draw the texture, with its lower-left corner placed at the (x, y) location. Width and height are required, Width and height can be different from the original image’s width and height resulting in scaling or distorting the image.

Color (normally) should not be provided. If present, that color will be blended with the original image.

Assume the same load() as used with loadImage() example above, here are some different ways of displaying the first dial:

xpgl.drawRectangle(0, 0, 640, 480, color=Colors['light gray'])

w = 22
h = 27
xpgl.drawTexture(Data['dials'][0], 100, 200, w,     h)
xpgl.drawTexture(Data['dials'][0], 150, 200, w,     h, color=Colors['green'])
xpgl.drawTexture(Data['dials'][0], 200, 200, w * 2, h * 2)
xpgl.drawTexture(Data['dials'][0], 250, 200, w * 2, h)
xpgl.drawTexture(Data['dials'][0], 300, 200, w / 2, h / 2)
../../_images/xpgl_drawTexture.png
drawRotatedTexture(texture_id, angle, x, y, width, height, color=None) None:
Parameters
  • texture_id (int) – return from loadImage() for image to be displayed

  • angle (float) – Degrees angle of rotation (counter-clockwise)

  • x (float) –

  • y (float) – (x, y) location of the lower left corner of the texture

  • width (float) –

  • height (float) – Width and height of image to be displayed

  • color (RGBColor) – Optional color to use to “add” to the image

Returns

None

Similar to drawTexture(), but first rotates the image around its lower-left corner. Negative angle results in clockwise rotation.

# in load()
texture = xpgl.loadImage("Resources/bitmaps/cockpit/clocks/chrono_HM.png")

# in draw()
xpgl.drawRotatedTexture(texture, 0, 300, 300, width=110, height=110)
xpgl.drawRotatedTexture(texture, 45, 300, 300, width=110, height=110)
xpgl.drawRotatedTexture(texture, 90, 300, 300, width=110, height=110)
xpgl.drawRotatedTexture(texture, -45, 300, 300, width=110, height=110)
../../_images/xpgl_drawRotatedTexture.png
drawRotatedTextureCenter(texture_id, angle, x, y, width, height, color=None) None:
Parameters
  • texture_id (int) – return from loadImage() for image to be displayed

  • angle (float) – Degrees angle of rotation (counter-clockwise)

  • x (float) –

  • y (float) – (x, y) location of the lower left corner of the texture

  • width (float) –

  • height (float) – Width and height of image to be displayed

  • color (RGBColor) – Optional color to use to “add” in the image

Returns

None

Same as drawRotatedTexture(), but calculates, and rotates around the center of the image. Negative angle results in clockwise rotation.

# in load()
texture = xpgl.loadImage("Resources/bitmaps/cockpit/supplement/gmeter_linear-1.png")

# in draw()
w = 25
h = 511
xpgl.drawRotatedTextureCenter(texture,   0, 300, (screen.height - h) / 2, w, h)
xpgl.drawRotatedTextureCenter(texture,  45, 300, (screen.height - h) / 2, w, h)
xpgl.drawRotatedTextureCenter(texture,  90, 300, (screen.height - h) / 2, w, h)
xpgl.drawRotatedTextureCenter(texture, -45, 300, (screen.height - h) / 2, w, h)
../../_images/xpgl_drawRotatedTextureCenter.png