Introduction to Pixies

This article assumes the reader is familiar with Lua and knows the basics of creating add-ons using Houston and Apollo. 

What’s a Pixie?

Pixies are textured rectangles that can be drawn anywhere within a window. Like windows, they have anchor points and offsets, can contain text, and have a background sprite. Unlike windows, they have no styles, tooltips, or event handlers, and they cannot have children.

There is no Lua userdata associated with a Pixie, so we don’t get any of the convenient methods that windows have, such as GetHeight() or Show(). Instead, we are given an ID that can be used to get some information about, update, or delete a Pixie later on. But we’ll get to the code in a bit! The main point is that because of the reduced Lua overhead, Pixies are fast. There would be a significant performance penalty to, say,  creating 1,000+ windows in order to draw a complex shape, whereas Pixies can handle that just fine.

One of the most useful things about Pixies is that they can be drawn as lines. We still define our Pixie as a rectangle using anchor points and offsets, and by setting a flag, a line will be drawn from the top-left corner to the bottom-right corner of that rectangle with some specified line width. This combined with background sprites and text can produce some interesting results with little effort:

PixieOptions

In the above image, taken from Houston, there are four windows each containing a single Pixie. All four Pixies have the same anchor points and offsets. The first has a solid background fill. The second uses a transparent background fill and a background sprite. The third was set to be a line with 10 width. The fourth is a line with some text.

What can I do with Pixies?

Lots of things! With the ability to draw arbitrary lines, rectangles, and other shapes, what we have here is a primitive graphics sub-system. Here are just a few examples:

Make Graphs

Everybody likes graphs, right? Right?? Well, maybe it’s just me. I wrote an (unreasonably powerful) plotting library called PixiePlot and – you guessed it – it uses Pixies to generate graphs! I might write a separate article just for PixiePlot, but here’s a little taste:

PixiePlot_Bars

PixiePlot_PolarPink

XPS1

Not bad for just lines, rectangles, and text!

Create Games

Snake

Some may remember Loftis, a Tetris clone add-on created by Apollo Lead Jon “Bitwise” Wiesman. And as you probably guessed, Loftis uses Pixies for the bricks. But it doesn’t have to stop there! I wrote a Snake clone to play around with Pixies, pictured above. Now, I know you’re about to ask, “Wait a minute, could we create an entire Lua game engine within WildStar using Pixies?” The answer is Yes.

Draw on In-World Objects

Reticules1

Apollo provides some nifty methods for converting positions between world (x,y,z) and screen (x,y) coordinate systems. To give an example, I snuck up on some unsuspecting Beta testers and drew targeting reticules on top of them. It’s possible to accomplish something like this in other ways, such as by attaching windows directly to in-game units. If you use Pixies, however, you often don’t have to deal with XML Forms at all! Here I used a (fairly new) Apollo method, GameLib.GetUnitScreenPosition():

1
2
3
4
5
6
7
8
9
function MyAddon:ShowReticuleForUnit(unit)
  local tScreenPos = GameLib.GetUnitScreenPosition(unit)
  if tScreenPos.bOnScreen then
    self:DrawReticule({
      x = tScreenPos.nX,
      y = tScreenPos.nY
    })
  end
end

DrawReticule() will be a small function that adds a Pixie to a window, and there is an example of how that’s done below. The “window” to which I’m adding these Pixies is actually a 100% transparent, mouse-click-ignoring window covering the entire screen. So when I get a unit’s screen coordinates, they will be the same as that window’s coordinates, and it works beautifully! If you’re wondering where we get the unit reference, there are a lot of possibilities, but in this case I am listening to the UnitCreated event. We’ll leave that for another tutorial, however…

These examples are really just scratching the surface. I hope I’ve at least sparked your imagination; we need more Pixies on Nexus!

How to Create Pixies

Pixies can either be added to windows by hand in Houston or created programmatically with Lua. Let’s go through both methods:

In Houston

In the Form Editor, click on a window, then click the Pixies tab in the Window Properties dialog.

PixieCreate

I encourage everyone to simply create some Pixies this way so you can get a feel for how they’re positioned and styled. If you want, you can reduce window clutter in your Forms by using Pixies for text labels, though that can get tedious quickly.

In Lua

Creating Pixies from Lua is the most interesting way to do it, because it allows us to create many of them dynamically. There are 4 API calls for working with Pixies, and you’ll find them all on a window object, such as the one returned by Apollo.LoadForm():

  • AddPixie(tOptions)
    • Adds a Pixie to the window with the given options. Returns a number ID that can later be passed to DestroyPixie(), UpdatePixie(), or GetPixieInfo().
  • DestroyPixie(nPixieId)
    • Removes the Pixie with ID nPixieId from the window.
  • UpdatePixie(nPixieId, tOptions)
    • Updates the Pixie with ID nPixieId with the given options.
  • GetPixieInfo(nPixieId)
    • Returns a table that is similar but not identical to the tOptions table used to create the Pixie with ID nPixieId.

tOptions is a table that has fields for most or all of the same options that are available in the Window Properties dialog. I actually don’t know all of the options yet, and some I had to guess! Here’s what I know so far:

  • strText
    • Text to draw inside the Pixie.
  • strFont
    • Name of the font to use for strText, i.e. “CRB_Interface11”
  • strSprite
    • Name of the background sprite, i.e. “WhiteCircle”
  • bLine
    • If true, the Pixie is drawn as a line with width fWidth from the top-left to bottom-right corner of the rectangle defined by loc.
  • fWidth
    • Pixel width of the line, if bLine is true
  • cr
    • A background color table in the form {a=alpha, r=red, g=green, b=blue} where alpha, red, green, and blue are numbers between 0 and 1. Can also be an ApolloColor.
  • crText
    • A color table in the same form as cr, specifying text color. 
  • loc
    • fPoints
      • An anchor point array in the form {left,top,right,bottom}
    • nOffsets
      • An offsets array in the form {left,top,right,bottom}
  • fRotation
    • Degrees to rotate the Pixie (clockwise from its center)
  • flagsText
    • DT_RIGHT
      • If true, the text will be right-aligned
    • DT_CENTER
      • If true, the text will be center-aligned horizontally
    • DT_VCENTER
      • If true, the text will be center-aligned vertically
    • DT_BOTTOM
      • If true, the text will be bottom-aligned

Finally, a quick example call to AddPixie():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local wnd = Apollo.LoadForm("MyAddon.xml", "PixieForm", nil, self)
local nPixieId = wnd:AddPixie({
  strText = "Hello Pixie!",
  strFont = "CRB_Interface10",
  bLine = false,
  strSprite = "WhiteCircle",
  cr = {a=1,r=0.37,g=0.00,b=1.00},
  loc = {
    fPoints = {0,0,0,0},
    nOffsets = {50,50,100,100}
  },
  flagsText = {
    DT_CENTER = true,
    DT_VCENTER = true
  }
})

That’s it for now! Until next time…

Bookmark the permalink.

4 Comments

  1. Some great info to get started. Thnx.

    Just a question whilst playing with pixies:

    How does one change the order/z-index of a pixie? It seems the newly created ones are placed above the older pixies. Is there a way from scripting to bring one back to front so to say in the same way as the window call ToFront?

    • There is nothing like ToFront() that I know of. To bring a Pixie to the top, you’ll have to destroy it and re-add it. I’ve never had to do that personally, but in PixiePlot for example I am careful about the order in which the Pixies are added (axes first, then data points, then grid lines, etc…).

  2. Neat stuff! I have a question or two, if I may.

    I’m new to addon development when it comes to WildStar, so I’m sorry if I missed anywhere that this was covered — I’ve only just gotten in the stress test for this weekend so I’m still taking everything in as fast as I can.

    There would be a significant performance penalty to, say, creating 1,000+ windows in order to draw a complex shape, whereas Pixies can handle that just fine.

    I found this interesting. What does this mean about the pixies pipeline? Is the information/properties of the pixies we generate just translated into primitives and passed onto the rendering context? Is there any optimization, such as culling, or should we do that ourselves?

    I guess in simplest terms my question is: What’s the rendering and processing pipeline for pixies like on a lower level?

    • I don’t know the specifics. What I do know is that there is no userdata associated with Pixie, where there is a large userdata object associated with a Window. That alone creates a lot of performance overhead.

      Pixies are just glorified Sprites, and specifically Sprites displayed inside a Window. That means they are part of the UI. They’re not drawn in-world, but rather on the 2D UI layer overlayed on top of the world viewport. So, things like culling have to be done by hand. In the tutorial, I showed that this information is often available (there a field in the object returned by GameLib.GetUnitScreenPosition()). But all we know is that the unit is off-screen, so we don’t draw the Pixie at all. There isn’t enough information to actually clip the Pixie sprite by what portion is on-screen and what is off-screen.

Leave a Reply

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