Slides: CEDEC 2017

Here are my slides from my talk at CEDEC 2017 titled “More performance, more gameplay”. This time I removed all the build transitions from the PDF, so some builds will be hard to follow, but it makes for a shorter read. Enjoy.

Fredriksson_CEDEC_2017_Final

Advertisements

Why Qt and not IMGUI?

Here’s some bonus chatter after my web talk postmortem at GDC 2017. I’ll try to answer a bunch of FAQs here so I can refer people to them rather than answering everyone individually 🙂

Why didn’t you chose IMGUI for the client reboot?

I think IMGUI is great for in-game UI and read-only presentation of stuff, but it is not attractive for a small team working on desktop tools. We did consider switching to an immediate approach, but were a few strong reasons we didn’t.

First of all, there are no off the shelf IMGUI libraries that can compete with traditional GUI frameworks like Qt when it comes to features and completeness. People at Insomniac expect a robust familiar looking UI with good performance. But they also expect a lot of power tools to come with that. Things like:

  • Filtering and sorting every list and tree view
  • Copy and paste
  • Multi-selection logic with order preservation
  • Undo/redo
  • Drag and drop with preview and animation
  • Full unicode support (i.e. localization)

Yes, you can totally do all that in IMGUI. But it’s a lot of code to write and maintain, and before you have written it you have nothing. And we had just escaped the hell of writing every control ourselves in the web space, so that was not something we wanted to start this project off by doing.

Second, we only have 5 programmers on the tool side. Starting an IMGUI reboot of the level editor would involve fun decisions like:

  • How are we going to render fonts?
  • How are we going to load icons?
  • How do we handle resizing layouts?
  • How do we handle high DPI?

Bikeshedding opportunities for all! Using a framework that has reasonable answers to all those questions already means you can start doing what’s important from day one, which is make the damn tool, instead of inventing yet another font renderer.

But I’ve heard that traditional frameworks suck?

Well, they have a lot of baggage, sure. And you definitely don’t want to be using anything like MFC or classic Win32 where the widgets take ownership of the data. Qt’s model-view architecture however is pretty sane.

You implement a model interface, telling the library how to access (and edit) your data and then it handles input and rendering for the views. The views are completely stock and run unmodified, with standard look and feel, sane multi-selection and keyboard behavior, editing support etc etc. The cost is that you have to express your data access using a framework-defined interface. That’s a pretty small price to pay for the massive leapfrogging you get by relying on those stock views.

The above is true for all “multiple things” widgets, like combo boxes, list and tree views. What remains are the “scalar” widgets, like a single string, checkbox etc. Yes, they retain state so they can repaint themselves without involving your code. And yes, you need to keep them in sync with your data by connecting signals to slots. But it also means that the data is not committed automatically as soon as the checkbox changes. You can actually complain and have the user correct their settings before committing. Tradeoffs.

Are you using Qt Quick?

No, we’re sticking with traditional Qt widgets only. The reasons are:

  1. We want perfect Win32 interop for our native 3D view
  2. We’re sick and tired of Javascript, and Qt Quick uses CSS/JS-like concepts

But don’t custom widgets in Qt suck?

No, they’re in fact just like IMGUI if you do things correctly! The differences are:

  1. You’re painting using a traditional pixel-oriented API rather than a 3D API
  2. Mostly the framework decides when you need to repaint, not you
  3. But if your data changes, you’ll need to schedule a repaint yourself (which is easily accomplished in a decoupled fashion using signals and slots)

But other than that, you’re painting a view of your app’s data directly to a drawing surface. So in fact, it’s more like IMGUI than you might think.

Walking Set Bits

Sometimes you want to walk the set bits of an integer and do something for each bit. For example, consider printing a human readable version of a flag field (which could have up to say 32 unique flags set).

The naive way to accomplish this is of course to visit every bit and see if something is set. But we’re cooler than that.

A better approach is to repeatedly pick off the lowest set bit until there’s nothing left. Here’s what that looks like:

while (bits) {
  uint32_t lsb = bits & ~(bits - 1);
  // do something with lsb here..
  bits &= ~lsb; // mask off lsb and keep going
}

This gives you the value of each bit as you’re walking it (i.e. bit 7 will have the value 0x80 if we’re counting from 0). If you need the bit’s position as well, it’s convenient to use the Intel BSF (bit scan forward) instruction via compiler intrinsics:

  int bitpos;
  while (0 != (bitpos = __builtin_ffs(bits))) {
    uint32_t lsb = 1 << (bitpos - 1);
    // use bitpos, lsb as required..
    // bitpos is 1-based on GCC
    bits &= ~lsb;
  }

It sort of sucks that we still have to compute the LSB value so we can remove it and move on to the next bit. If your CPU has a fast CTZ instructions (count trailing zeroes) we can substitute that for the barrel shift:

while (bits) {
  uint32_t lsb = bits & ~(bits - 1);
  int bitpos = __builtin_ctz(lsb);
  // use bitpos, lsb as required..
  bits &= ~lsb; // mask off lsb and keep going
}

The intrinsics shown here work on GCC and Clang. There are similar ones for MSVC but I’m too lazy to write Windows examples!