Go Back   Orbiter-Forum > Blogs > martins
Register Blogs Orbinauts List Social Groups FAQ Projects Mark Forums Read

Rating: 2 votes, 5.00 average.

Developer masterclass: Creating 2-D panels (Part 3)

Posted 09-10-2010 at 05:41 PM by martins

This continues the tutorial from Part 2.

Lesson 6: Adding a switch (button, dial, etc.)
Apart from MFDs, the panel can contain many more active elements. A common class of elements has two or more discrete states (a switch that can be flipped up or down, a dial that can be turned to a set of discrete positions, a control light that can be on or off, etc.) Representative for all those objects, let’s add a 2-way switch now.

Active objects that have a number of discrete visual states are generally defined by one of a set of bitmaps representing the state. We can implement this in two ways: (a) blitting the bitmap displaying the required state into the background panel texture, or (b) putting a billboard texture group over the background mesh, and dynamically modifying the texture coordinates to point to a section of the texture containing an image of the required state.

There are advantages and disadvantages to both methods: (a) doesn’t increase the mesh complexity. Once the blitting operation is performed, the rendering process is as efficient as before. This method is best if the object state only changes very infrequently. (b) doesn’t require a blit, just a modification to the vertex texture coordinates. This method is best if the object state changes continuously (so that the overhead of the blitting operation becomes significant).

A switch usually changes its state only occasionally (on user input), so method (a) should be suitable and will be implemented here. I will discuss an example for method (b) in the next part.

As with the MFD button columns, the switch is defined as a class derived from PanelElement:
class MySwitch: public PanelElement {
  MySwitch (VESSEL3 *v);
  bool Redraw2D (SURFHANDLE surf);
  bool ProcessMouse2D (int event, int mx, int my);

  int switch_state;
As before, we have the Redraw2D and ProcessMouse2D functions to deal with updating the visual state and responding to user interaction. They can be implemented as follows:
MySwitch::MySwitch (VESSEL3 *v): PanelElement (v)
  switch_state = 0;
  // this is the base state as shown in the panel background

bool MySwitch::Redraw2D (SURFHANDLE surf)
  int new_switch_state = GetMySwitchState();
  if (new_switch_state != switch_state) {
    switch_state = new_switch_state;
    tx_x = tx_x0 + switch_state*tx_dx;
    oapiBlt (surf, surf, btn_x, btn_y, tx_x, tx_y0, tx_w, tx_h);
  return false;

bool MySwitch::ProcessMouse2D (int event, int mx, int my)
  int curr_switch_state = GetMySwitchState();
  int new_switch_state;
  if (my < tx_h/2) new_switch_state = 0;
  else             new_switch_state = 1;
  if (new_switch_state != curr_switch_state) {
    SetMySwitchState (new_switch_state);
    return true;
  } else
    return false;
GetMySwitchState and SetMySwitchState are assumed to be implemented in MyVessel. In Redraw2D, btn_x and btn_y represent the target location of the button in the background texture. tx_x0 and tx_y0 are the locations of the button image in its “base state”, tx_w and tx_h are the width and height of the button in pixels. The images for the additional states are assumed to be in a horizontal row to the right of the base state, so that tx_x0 + switch_state*tx_dx picks out the required one.

In ProcessMouse2D, we flip the switch depending on whether the user clicks the top or bottom half of the switch. Returning true triggers a redraw event.

We add the switch as a new panel element in the constructor (after increasing the length of the pel array to 3):
MyVessel::MyVessel (...)
  for (int i = 0; i < 2; i++)
    pel[i] = new MFDButtonCol (this, i);
  pel[2] = new MySwitch (this);
and register the switch as an active element inside DefineMainPanel:
void MyVessel::DefineMainPanel (PANELHANDLE hPanel)
  RegisterPanelArea (hPanel, AID_MYSWITCH, _R(btn_x, btn_y, tx_w, tx_h),
    PANEL_REDRAW_MOUSE, PANEL_MOUSE_LBDOWN, panel2dtex, pel[2]);
That’s it. The redraw and mouse event callback functions we have defined for the MFD button columns in the last section already take care of calling the appropriate MySwitch methods when needed.

Note: If you are implementing an entire row of switches, it is probably more efficient to define the row as a single panel element, rather than creating a new object for each individual switch.

The next part will implement a slider using mesh vertex transformations.
Views 15633 Comments 10
« Prev     Main     Next »
Total Comments 10


  1. Old Comment
    Is anyone following this tutorial? Let me know if it actually works. I am writing this alongside updating the Shuttle-A panel code, but there is always a possibility of mistakes.

    Out of interest: Have any existing vessel addons already adopted the new panel interface, or is the stock DG still the only pioneer out there?
    Posted 09-10-2010 at 05:49 PM by martins martins is offline
  2. Old Comment
    Xyon's Avatar
    Well, I'm giving it a go with one of my "unreleased, possibly never to be released" vessel addons, but I'm neither texturer nor modeller, so it's taking some time. :/

    Thus far I am up to adding MFD areas, so far, so good.
    Posted 09-11-2010 at 12:15 AM by Xyon Xyon is offline
    Updated 09-11-2010 at 10:04 AM by Xyon
  3. Old Comment
    n72.75's Avatar
    I've been really busy with school, but as soon as I have the time: I have some addon ideas that I've been wanting to try out. So I'll definitely use these tutorials then.
    Posted 09-12-2010 at 03:41 PM by n72.75 n72.75 is offline
  4. Old Comment
    tblaxland's Avatar
    Reading, but not implementing currently. Very useful information anyway
    Posted 09-13-2010 at 10:44 AM by tblaxland tblaxland is offline
  5. Old Comment
    Invaluable information!! My first add-ons will be extra mfd displays and these masterclasses are quite useful.
    Posted 09-14-2010 at 09:40 AM by Keatah Keatah is offline
  6. Old Comment
    Moach's Avatar
    i have plans to adapt the whole panel implementation for my G42 to accordance with the new methods... but i'm still waiting for further info, as it doesn't have a 2D panel, so i must have it all working on the VC

    but great reading so far! thanks
    Posted 09-14-2010 at 11:22 AM by Moach Moach is offline
  7. Old Comment
    Bibi Uncle's Avatar
    Once again, thank you for this tutorial ! (and for this wonderful API !). However, there is something that I do not understand.

    In the second code sample, I saw that you do not return true (so it returns false) when you are blitting. I found that weird because, in the documentation, it is said that we must return true when the event is process. I think (I'm not 100% sure about it) that in the 2006 version, when we didn't return true, the image was not blitted. However, I tested this code (in Orbiter 2010) and the switch is refreshing, but the function returns false.

    Is it normal ? Or did I miss something ? If not, why does the callback has a boolean return if it doesn't change anything at all between a false or a true return ?
    Posted 03-07-2011 at 03:18 AM by Bibi Uncle Bibi Uncle is offline
  8. Old Comment
    Posted 03-09-2011 at 12:05 AM by Keith Keith is offline
  9. Old Comment
    n122vu's Avatar
    I am attempting to implement this in my EA Cortez addon. Any chance you will continue this series with the tutorial to implement the slider using vertex transformations?

    Also, any issues if I compile these lessons into a single PDF and make available? I have the PDF of the lessons thus far, created for myself so I can read it while coding.

    Thanks for putting time into creating these.
    Posted 06-02-2011 at 01:22 PM by n122vu n122vu is offline
  10. Old Comment
    PolliMatrix's Avatar
    I'm developing the 2-D panel of my first add-on using the new mesh-based method. This tutorial is very helpful, especially since looking at the DeltaGlider examples by myself was a bit confusing at first.
    I made some modifications, but aside from what Bibi Uncle found in part 2 I didn't notice any mistakes.
    I'll try to make some custom displays and sliders myself, but are you still planning to do some more parts of this tutorial?
    Posted 07-02-2011 at 11:35 AM by PolliMatrix PolliMatrix is offline

All times are GMT. The time now is 02:40 PM.

Quick Links Need Help?

About Us | Rules & Guidelines | TOS Policy | Privacy Policy

Orbiter-Forum is hosted at Orbithangar.com
Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.
Copyright ©2007 - 2017, Orbiter-Forum.com. All rights reserved.