OHM HUDDrawer SDK v.0.4 for Orbiter 2016

OrbitHangar

Addon Comments
Joined
Apr 9, 2008
Messages
3,832
Reaction score
13
Points
0

Author: enjo

'Nuff blocking other developers, who are waiting with their HUD drawing modules to bust, by Launch MFD's internal HUD drawing system! This library centralizes the internals of “VESSEL virtual table hijacking”, providing a common system where all the modules, willing to draw on HUD, are registered, and receive the HUD drawing context afterwards. A good example of a module that could use this system would be Axial Velocity HUD, which is currently not compatible with Launch MFD's former HUD drawing system (or the other way around).

Reference posts: Problem reportsolution used.

WARNING! This library is a HACK and it may stop working in future versions of Orbiter API if the library isn't maintained anymore. Note however that it's very easy to do so by updating the VesselHooking class.

Documentation available at:
OrbiterSDK\doc\HUDDrawerSDK

======================
Changes:
v. 0.4    11.09.2016
- MFD: Fixed a CTD upon clicking on buttons when list is empty

Copyright (C) 2008 Steve Arch "agentgonzo" - virtual table hijacking
Copyright (C) 2012-2016 Szymon Ender "Enjo" - created a framework



DOWNLOAD
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
And here it is folks. After 5 years of damn stagnation, it's finally possible to write modules whose HUD drawing internals may be compatible with each other. Bring those HUD drawing modules on!
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Need a hand, Enjo old friend!!

I wanted to do a simple demo of HUD-writing, initially to just paint a YPR XYZ offset and orientation onto the HUD, and then get a bit fancier with arrows and alignment corridors.

I have the YPR XYZ code writing to the MFD quite happily, and I have implemented a DrawHUD function to do the same on the HUD, but when I debug it, I see that the DrawHud is not being called. I suspect that I need an initialization call to hook the HUD, but I cannot see where to put it.

Here's the code:

Orientation.h:
Code:
// ==============================================================
//
// Orientation.h
//
// (c) Andrew Stokes (ADSWNJ) 2013  - licensed under LGPL
//
// All rights reserved
// ==============================================================


#include "EnjoLib/IDrawsHUD.hpp"

#ifndef __ORIENTATION_H
#define __ORIENTATION_H

class Orientation: public MFD2, public EnjoLib::IDrawsHUD {
public:
	Orientation (DWORD w, DWORD h, VESSEL *vessel);
	~Orientation ();
	char *ButtonLabel (int bt);
	int ButtonMenu (const MFDBUTTONMENU **menu) const;
	bool Update (oapi::Sketchpad *skp);
	static int MsgProc (UINT msg, UINT mfd, WPARAM wparam, LPARAM lparam);
  void IDrawsHUD();
  void DrawHUD(int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad * skp);
  bool ShouldDrawHUD() const;

protected:
	oapi::Font *font;
  VESSEL *v;

  VECTOR3 gblOri, gblPos, gblVel;
  double simT, oldSimT, simStep;
  bool firstCalc;

  OBJHANDLE hTgtV;
  VESSEL *tv;
  VECTOR3 tvPos, lcltvPos, relPos, oldRelPos;
  VECTOR3 diffPos, diffDir, diffRot, oldDiffDir, oldDiffRot;
  VECTOR3 diffDirRate;

  DOCKHANDLE hDock, hMyDock;
  VECTOR3 rtvdPos, rtvdDir, rtvdRot;
  VECTOR3 gtvdPos, gtvdDir, gtvdRot;
  VECTOR3 ltvdPos, ltvdDir, ltvdRot;
  VECTOR3 dPos, dDir, dRot;
  VECTOR3 gdPos, gdDir, gdRot;

  MATRIX3 R; // Rotation matrix
  VECTOR3 lclPos;

};

#endif // !__ORIENTATION_H


Orientation.cpp:
Code:
// ==============================================================
//
// Orientation.cpp
//
// Determines orientation of GL-02 (harcoded for now) to us.
// Use with Delta-Glider scenario Smack!
//
// Real objective - provide demonstrator HUD hooking code using Enjo's new HUDDrawerSDK v0.1
//
// (c) Andrew Stokes (ADSWNJ) 2013  - licensed under LGPL
//
// All rights reserved
// ==============================================================

#define STRICT
#define ORBITER_MODULE
#include "windows.h"
#include "stdio.h"
#include "orbitersdk.h"
#include "Orientation.h"

// ==============================================================
// Global variables

int g_MFDmode; // identifier for new MFD mode

// ==============================================================
// API interface

DLLCLBK void InitModule (HINSTANCE hDLL)
{
	static char *name = "Orientation";   // MFD mode name
	MFDMODESPECEX spec;
	spec.name = name;
	spec.key = OAPI_KEY_T;                // MFD mode selection key
	spec.context = NULL;
	spec.msgproc = Orientation::MsgProc;  // MFD mode callback function

	// Register the new MFD mode with Orbiter
	g_MFDmode = oapiRegisterMFDMode (spec);
}

DLLCLBK void ExitModule (HINSTANCE hDLL)
{
	// Unregister the custom MFD mode when the module is unloaded
	oapiUnregisterMFDMode (g_MFDmode);
}

// ==============================================================
// MFD class implementation

// Constructor
Orientation::Orientation (DWORD w, DWORD h, VESSEL *vessel)
: MFD2 (w, h, vessel)
{
	v = vessel;
  hMyDock = v->GetDockHandle(0);
  v->GetDockParams(hMyDock, dPos, dDir, dRot);

  font = oapiCreateFont (w/20, true, "Fixed", FONT_NORMAL, 0);
	// Add MFD initialisation here

  hTgtV = oapiGetVesselByName("GL-02");
  tv = oapiGetVesselInterface(hTgtV);
  firstCalc = true;

}

// Destructor
Orientation::~Orientation ()
{
	oapiReleaseFont (font);
	// Add MFD cleanup code here
}


// HUD Drawing
  bool Orientation::ShouldDrawHUD() const {
    return true;
  }
  void Orientation::DrawHUD(int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad * skp) {

    char buf[256];
    int xPix, yPix;
    union{ 
      struct SKPCHARSIZE {
      WORD ch;
      WORD cw;
      } s1;
      DWORD s2;
    } skpCS;


    if (mode==HUD_NONE) return; // HUD is off, so no drawing

    skp->Rectangle(hps->W-200,200,hps->W-20,400);

    xPix = hps->W-195;
    yPix = 205;

    skpCS.s2 = skp->GetCharSize();

    if (!firstCalc) {

	    skp->SetFont (font);
	
      sprintf_s(buf, "       Att    Rate");
      skp->Text (xPix, yPix, buf, strlen(buf));

      yPix = yPix + skpCS.s1.ch + 2;
      if (abs(diffDir.y)<0.1) {
        sprintf_s(buf, "Y  %7.2f  %6.3f     ", diffDir.y, diffDirRate.y);
      } else if (diffDir.y<0) {
        sprintf_s(buf, "Y  %7.2f  %6.3f     (yaw right)", diffDir.y, diffDirRate.y);
      } else {
        sprintf_s(buf, "Y  %7.2f  %6.3f     (yaw left)", diffDir.y, diffDirRate.y);
      }
      skp->Text (xPix, yPix, buf, strlen(buf));

      yPix = yPix + skpCS.s1.ch + 2;
      if (abs(diffDir.x)<0.1) {
        sprintf_s(buf, "P  %7.2f  %6.3f     ", diffDir.x, diffDirRate.x);
      } else if (diffDir.x<0) {
        sprintf_s(buf, "P  %7.2f  %6.3f     (pitch up)", diffDir.x, diffDirRate.x);
      } else {
        sprintf_s(buf, "P  %7.2f  %6.3f     (pitch down)", diffDir.x, diffDirRate.x);
      }
      skp->Text (xPix, yPix, buf, strlen(buf));

      yPix = yPix + skpCS.s1.ch + 2;
      if (abs(diffDir.z)<0.1) {
        sprintf_s(buf, "R  %7.2f  %6.3f     ", diffDir.z, diffDirRate.z);
      } else if (diffDir.z<0) {
        sprintf_s(buf, "R  %7.2f  %6.3f     (roll right)", diffDir.z, diffDirRate.z);
      } else {
        sprintf_s(buf, "R  %7.2f  %6.3f     (roll left)", diffDir.z, diffDirRate.z);
      }
      skp->Text (xPix, yPix, buf, strlen(buf));

      yPix = yPix + skpCS.s1.ch + 2;
      yPix = yPix + skpCS.s1.ch + 2;
      sprintf_s(buf, "       Pos    Vel");
      skp->Text (xPix, yPix, buf, strlen(buf));

      yPix = yPix + skpCS.s1.ch + 2;
      if (abs(relPos.x)<0.01) {
        sprintf_s(buf, "X  %7.2f  %6.3f     ", relPos.x, diffPos.x);
      } else if (relPos.x>0) {
        sprintf_s(buf, "X  %7.2f  %6.3f     (go left)", relPos.x, diffPos.x);
      } else {
        sprintf_s(buf, "X  %7.2f  %6.3f     (go right)", relPos.x, diffPos.x);
      }
      skp->Text (xPix, yPix, buf, strlen(buf));

      yPix = yPix + skpCS.s1.ch + 2;
      if (abs(relPos.y)<0.01) {
        sprintf_s(buf, "Y  %7.2f  %6.3f     ", relPos.y, diffPos.y);
      } else if (relPos.y>0) {
        sprintf_s(buf, "Y  %7.2f  %6.3f     (go down)", relPos.y, diffPos.y);
      } else {
        sprintf_s(buf, "Y  %7.2f  %6.3f     (go up)", relPos.y, diffPos.y);
      }
      skp->Text (xPix, yPix, buf, strlen(buf));

      yPix = yPix + skpCS.s1.ch + 2;
      if (abs(relPos.z)<0.01) {
        sprintf_s(buf, "Z  %7.2f  %6.3f     ", -relPos.z, diffPos.z);
      } else if (relPos.z>0) {
        sprintf_s(buf, "Z  %7.2f  %6.3f     (go backwards)", -relPos.z, diffPos.z);
      } else {
        sprintf_s(buf, "Z  %7.2f  %6.3f     (go forwards)", -relPos.z, diffPos.z);
      }
      skp->Text (xPix, yPix, buf, strlen(buf));

    } 

  }

// Return button labels
char *Orientation::ButtonLabel (int bt)
{
	// The labels for the two buttons used by our MFD mode
	static char *label[2] = {"UP", "DN"};
	return (bt < 2 ? label[bt] : 0);
}

// Return button menus
int Orientation::ButtonMenu (const MFDBUTTONMENU **menu) const
{
	// The menu descriptions for the two buttons
	static const MFDBUTTONMENU mnu[2] = {
		{"Move up", 0, '['},
		{"Move down", 0, ']'}
	};
	if (menu) *menu = mnu;
	return 2; // return the number of buttons used
}


// Repaint the MFD
bool Orientation::Update (oapi::Sketchpad *skp)
{
  int l;
  char buf[128];

	Title (skp, "Orientation");
	// Draws the MFD title

  simT = oapiGetSimTime();
  
  // Get oritnetaiotns, velocities and positions
  v->GetGlobalOrientation(gblOri);
  v->GetGlobalPos(gblPos);
  v->GetGlobalVel(gblVel);
  tv->GetGlobalPos(tvPos);
  hDock = tv->GetDockHandle(0);
  tv->GetDockParams(hDock, rtvdPos, rtvdDir, rtvdRot);


  // Find our dock XYZ offset in local coords
  tv->Local2Global(rtvdPos,gtvdPos);    // Make remote coord tgt vehicle dock position into a global coord
  v->Global2Local(gtvdPos,ltvdPos);     // And flip it back into a local tgt vehicle coords
  relPos = dPos - ltvdPos;              // My dock Pos is already in local coords, so the relative offset is just one minus the other


  // Find our Pitch Yaw offset in local coords
  rtvdDir = rtvdPos - rtvdDir;          // Turn direction vector into a point a unit distance inside the target dock, aligned correctly
  tv->Local2Global(rtvdDir,gtvdDir);    // Flip to global
  v->Global2Local(gtvdDir,ltvdDir);     // ... and back to local in our frame
  ltvdDir = ltvdDir - ltvdPos;          // Subtract the dock coords, to make the direction coord back into a vector (on our local origin)
  
  // For roll offset, use the Rot vector
  rtvdRot = rtvdPos + rtvdRot;          // Turn the rotation vector into a point offset from the dock
  tv->Local2Global(rtvdRot,gtvdRot);    // Flip to global
  v->Global2Local(gtvdRot,ltvdRot);     // ... and back to local in our frame
  ltvdRot = ltvdRot - ltvdPos;          // Subtract the dock coords, to make the rotation coord back into a vector (on our local origin)




  diffDir.x = DEG* (atan2(dDir.y, dDir.z) - atan2(ltvdDir.y, ltvdDir.z));    // DiffDir.x is PITCH
  diffDir.y = DEG* (atan2(dDir.x, dDir.z) - atan2(ltvdDir.x, ltvdDir.z));    // DiffDir.y is YAW
  diffDir.z = DEG * (atan2(ltvdRot.y, ltvdRot.x) - atan2(dRot.y, dRot.x));   // DiffDir.z is ROLL on the rotation alignment vector
  if (diffDir.x < -180.0) diffDir.x += 360.0;
  if (diffDir.y < -180.0) diffDir.y += 360.0;
  if (diffDir.z < -180.0) diffDir.z += 360.0;

  if (!firstCalc) {

    simStep = simT - oldSimT;
    diffPos = (relPos - oldRelPos) / simStep;


    diffDirRate = (diffDir - oldDiffDir) / simStep;

	  skp->SetFont (font);
	
    l = 2;
    sprintf_s(buf, "       Att    Rate");
    skp->Text (W*10/100, H*l/25, buf, strlen(buf));

    l++;
    if (abs(diffDir.y)<0.1) {
      sprintf_s(buf, "Y  %7.2f  %6.3f     ", diffDir.y, diffDirRate.y);
    } else if (diffDir.y<0) {
      sprintf_s(buf, "Y  %7.2f  %6.3f     (yaw right)", diffDir.y, diffDirRate.y);
    } else {
      sprintf_s(buf, "Y  %7.2f  %6.3f     (yaw left)", diffDir.y, diffDirRate.y);
    }
    skp->Text (W*10/100, H*l/25, buf, strlen(buf));

    l++;
    if (abs(diffDir.x)<0.1) {
      sprintf_s(buf, "P  %7.2f  %6.3f     ", diffDir.x, diffDirRate.x);
    } else if (diffDir.x<0) {
      sprintf_s(buf, "P  %7.2f  %6.3f     (pitch up)", diffDir.x, diffDirRate.x);
    } else {
      sprintf_s(buf, "P  %7.2f  %6.3f     (pitch down)", diffDir.x, diffDirRate.x);
    }
    skp->Text (W*10/100, H*l/25, buf, strlen(buf));

    l++;
    if (abs(diffDir.z)<0.1) {
      sprintf_s(buf, "R  %7.2f  %6.3f     ", diffDir.z, diffDirRate.z);
    } else if (diffDir.z<0) {
      sprintf_s(buf, "R  %7.2f  %6.3f     (roll right)", diffDir.z, diffDirRate.z);
    } else {
      sprintf_s(buf, "R  %7.2f  %6.3f     (roll left)", diffDir.z, diffDirRate.z);
    }
    skp->Text (W*10/100, H*l/25, buf, strlen(buf));

    l++;
    l++;
    sprintf_s(buf, "       Pos    Vel");
    skp->Text (W*10/100, H*l/25, buf, strlen(buf));

    l++;
    if (abs(relPos.x)<0.01) {
      sprintf_s(buf, "X  %7.2f  %6.3f     ", relPos.x, diffPos.x);
    } else if (relPos.x>0) {
      sprintf_s(buf, "X  %7.2f  %6.3f     (go left)", relPos.x, diffPos.x);
    } else {
      sprintf_s(buf, "X  %7.2f  %6.3f     (go right)", relPos.x, diffPos.x);
    }
    skp->Text (W*10/100, H*l/25, buf, strlen(buf));

    l++;
    if (abs(relPos.y)<0.01) {
      sprintf_s(buf, "Y  %7.2f  %6.3f     ", relPos.y, diffPos.y);
    } else if (relPos.y>0) {
      sprintf_s(buf, "Y  %7.2f  %6.3f     (go down)", relPos.y, diffPos.y);
    } else {
      sprintf_s(buf, "Y  %7.2f  %6.3f     (go up)", relPos.y, diffPos.y);
    }
    skp->Text (W*10/100, H*l/25, buf, strlen(buf));

    l++;
    if (abs(relPos.z)<0.01) {
      sprintf_s(buf, "Z  %7.2f  %6.3f     ", -relPos.z, diffPos.z);
    } else if (relPos.z>0) {
      sprintf_s(buf, "Z  %7.2f  %6.3f     (go backwards)", -relPos.z, diffPos.z);
    } else {
      sprintf_s(buf, "Z  %7.2f  %6.3f     (go forwards)", -relPos.z, diffPos.z);
    }
    skp->Text (W*10/100, H*l/25, buf, strlen(buf));

  } else {
    firstCalc = false;
  };
  oldSimT = simT;
  oldRelPos = relPos;
  oldDiffDir = diffDir;


	return true;
}

// MFD message parser
int Orientation::MsgProc (UINT msg, UINT mfd, WPARAM wparam, LPARAM lparam)
{
	switch (msg) {
	case OAPI_MSG_MFD_OPENED:
		// Our new MFD mode has been selected, so we create the MFD and
		// return a pointer to it.
		return (int)(new Orientation (LOWORD(wparam), HIWORD(wparam), (VESSEL*)lparam));
	}
	return 0;
}


I have an EnjoLib subdir for the project, with your IDrawsHUD cpp and hpp, and VesselHooking cpp and hpp.

My code is currently hardcoded to run on a Delta-Glider, on standard scenario Smack! in the Delta-Glider directory.

Can you have a play and show me what I am doing wrong?

By the way - the MFD updates seem to be working fine - i.e. put up docking MFD and Orientation MFD and they agree. Hopefully at some point, having a digital readout of orientation on the approach to a docking will be of use.
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Great! I'm happy that you've picked it up.

... but when I debug it, I see that the DrawHud is not being called. I suspect that I need an initialization call to hook the HUD, but I cannot see where to put it.

Works on my machine (TM). You need to enable HUDDrawer module in the Launchpad. The hooking is done through the module, and it's the only place where it should be done. By deriving from IDrawsHUD, you automatically register your module in the "Hooking control center", called by the HUDDrawer module. The registering is done through IDrawsHUD constructor, while deregistering through its destructor.

I have an EnjoLib subdir for the project, with your IDrawsHUD cpp and hpp, and VesselHooking cpp and hpp.
This is your mistake. The VesselHooking class should never be compiled into your project. The code is provided there only as a requirement for LGPL license. If you compile it in, you then have two "Control centers" which compete with each other, and this breaks Orbiter (or in your case, your instance wasn't called, as you noticed). To get definitions for VesselHooking and IDrawsHUD, you need to link VesselHooking.lib, that should reside in OrbiterSDK/lib after a normal installation of HUDDrawerSDK. Same goes for IDrawsHUD.hpp, that should reside in OrbiterSDK/include/EnjoLib. That's all you need. Once you activate your own module, the binary definitions of the IDrawsHUD and VesselHooking classes will be then read from VesselHooking.dll, that is stored in Modules dir, which guarantees a single instance of the VesselHooking class.

BTW, you don't need to declare void IDrawsHUD() in your header.
 
Last edited:

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Thanks Enjo :thumbup:

I stripped out all your source from my project. The one thing I missed the first time was to add VesselHooking.lib to the solution properties at Configuration Properties > Linker > Input > Additional Dependencies (alongside orbiter.lib and orbitersdk.lib).

Hey presto, I have scribbled on the HUD with my little orientation code (all misaligned for now, but working!).


So I can officially say that Enjo's HUD hooker is a super-simple piece of code to hook against. One include statement:
Code:
#include "EnjoLib/IDrawsHUD.hpp"
Extend your main MFD class definition to derive from EnjoLiv:IDrawsHUD:
Code:
class [I]yourMFD[/I]: public MFD2, public EnjoLib::IDrawsHUD { ...
Add these two functions (plus an optional one for Orbiter 2006 backward compatibility if you REALLY want your new HUD-MFD to support Orbiter 2006):
Code:
  void DrawHUD(int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad * skp);
  bool ShouldDrawHUD() const;

Make the ShoudDrawHUD() return true when you want it to show (or hardcode it to true).

Than pwn away on the DrawHUD() call just like you would on your MFD Update() call.

No initialization, hooking code or other nastiness to deal with at all - Enjo has abstracted all of that for all future HUD writing add-ons. How cool is that?
 
Last edited:

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
No initialization, hooking code or other nastiness to deal with at all - Enjo has abstracted all of that for all future HUD writing add-ons. How cool is that?

Beats me, but that was the goal - do all the dirty stuff so you don't have to!
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Just an idea for you ... if a number of addons start exploiting this hook, then the HUD may get a bit messy. Could you introduce a method for addons to request a block of space on the HUD, to play nice with other addons? eg I would ask for 150x200 pixels to put an alignment box, with a hint of right middle, and you could give me the offsets dependent on who else is on the screen. Or if you are drawing graphics, then maybe you don't mind others overwriting you, but at least you register your interest.

Likewise, you could introduce a way for addons to discover who else is on the HUD (w/versions too) and have a way to export and import data. E.g. a future glideslope talking to basesync or aerobrake, or (shock) the base Docking MFD talking to its HUD neighbors.
 

csanders

Addon Developer
Addon Developer
Joined
Jan 18, 2012
Messages
219
Reaction score
0
Points
0
Location
Plymouth
Just an idea for you ... if a number of addons start exploiting this hook, then the HUD may get a bit messy. Could you introduce a method for addons to request a block of space on the HUD, to play nice with other addons? eg I would ask for 150x200 pixels to put an alignment box, with a hint of right middle, and you could give me the offsets dependent on who else is on the screen. Or if you are drawing graphics, then maybe you don't mind others overwriting you, but at least you register your interest.

Likewise, you could introduce a way for addons to discover who else is on the HUD (w/versions too) and have a way to export and import data. E.g. a future glideslope talking to basesync or aerobrake, or (shock) the base Docking MFD talking to its HUD neighbors.

Or a HUD MFD that lets one select which hooked HUDs get drawn?
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
Enjo - Love it.

I remember the genesis of this topic and initial discussions with you and Face about it. Alas, my life moved on and I haven't had any time to develop for orbiter in far far too long (though did manage to load it the other day in an attempt to intercept 2012 DA14 (but failed!!!).

Congratulations on getting this finally packaged and released. A monumentous occasion for addon hackers! Orbiter just keeps on getting better and better - I wish I had the time to play with it like I used to.

Steve/agentgonzo

---------- Post added at 23:14 ---------- Previous post was at 23:12 ----------

PS - 2008? Wow - was it really that long ago??? :blink:
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Hi Steve! Nice to see you again.

It didn't require that much actual work to do it, only some experience and motivation. The latter is actually ADSWNJ's fault, as he's proven to be somebody who's able to do something useful with my libraries :)

PS - 2008? Wow - was it really that long ago??? :blink:
Yep. The year the world's gone broke. I think it was the investment bankers' fault :lol:

Andrew:
I'm afraid that your idea smells of a bit of overcomplexity. It's not something that could be coded in a realistic time, nor having an interface as simple as it is now. However I do like csanders' idea, which will be fairly simple to implement. Technically it could be done with the HUDDrawer module, which is already there. The IDrawsHUD interface could accept an optional unique string identifier of the client module, which when defined, would allow for (de)selecting the module from a list of active Drawers through the HUDDrawer module. I'm only wondering whether it should be done as an MFD or a WinAPI window, like the Scenario Editor is done. The 2nd option seems more appropriate for something that's not supposed to display vessel data, although I personally dislike WinAPI. Perhaps it could be done with wxWidgets? Gotta try it out.


And just to prove that the IDrawsHUD client doesn't necessarily need to be an MFD, I've just implemented it in Launch MFD as a vessel's property, so that the HUD can be drawn even when the MFD itself is disabled.

---------- Post added 03-12-13 at 06:40 AM ---------- Previous post was 03-11-13 at 07:59 PM ----------

I remember the genesis of this topic and initial discussions with you and Face about it. Alas, my life moved on and I haven't had any time to develop for orbiter in far far too long (though did manage to load it the other day in an attempt to intercept 2012 DA14 (but failed!!!).

And yeah. My life has also changed since since I've moved and got married. I hoped to get a working terrain in Orbiter for a long time and been postponing my playing with the sim because of that. My hardware is too poor for DX11 client so far. But I do find a lot of fun in coding for the sim all the time and keep returning to do it, because it's the only place where I can do things my way.
 
Last edited:

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Version 0.2 is released.

Changes:
- Ability to select active modules through HUDDrawer MFD (see attached screenshot)
- IDrawsHUD's constructor requires module's string identifier
- Changed license to GPL

I was really struggling about the license change decision. Basically I want to avoid situations similar to Axial Velocity HUD, where the author has left the scene, and although the addon was great, it's useless now.

Andrew:
To be clear, I have nothing against your MFDs being written in LGPL and linked against HUDDrawer. It's just that some people don't share the code at all. Possibly linking LGPL code with GPL library is permitted through "linking exception". I state in the manual that I have nothing against this.

Steve:
I also hope that you have nothing against GPL. After all, it's mostly your code, and only my high level design.


I've done the active drawers selection as MFD for two reasons - I know writing MFDs better than WinAPI, and it turned out that MFD gives me more flexibility, because the MFD-based drawers, like Launch MFD and Orientation MFD are not registered and visible on the list, until the MFDs themselves are activated. Once this is done, they automatically appear on the HUDDrawer MFD, which would be harder to achieve through a WinAPI window.
 

Attachments

  • HUDDrawerMFD.png
    HUDDrawerMFD.png
    39.1 KB · Views: 37
Last edited:

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Looks like the simplest thing is to ask all code linking to HUDDrawer to be GPL then. As I understand it, LGPL basically allows derivative code to be open or closed, whereas GPL forces it to be open (i.e. source released with the executable). There's issues with 'degrading' a GPL to a LGPL in a derivative work, unless expressly permitted, so let's just keep everything open and shareable.

I personally would like to see every element of Orbiter, from the core to every addon, released under GPL. It would create an explosion of new ideas and innovation. Here's wishing.
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
I see we agree here.

As I understand it, LGPL basically allows derivative code to be open or closed, whereas GPL forces it to be open (i.e. source released with the executable).

Technically speaking, linking your code with GPL library statically or dynamically, or compiling in GPL code to your project enforces the product to be GPL. LGPL is different here only in the fact that it allows you to keep your product closed source when you link an LGPL library dynamically, so that it's possible to update the product with a newer version of the library. Therefore LGPL only guarantees "Freedom" to the library itself, and it's not the only thing I'd hope to have.
Note, also, that technically it doesn't make much difference if the end product is LGPL or GPL then, because the end product won't be a subject to dynamic linking, unless you happen to create a library from it later, like it was in case of HUDDrawer's internals (now that I think of it, they were rather GPLed before, because they were part of GPLed Launch MFD anyway). So in such case, by switching from LGPL to GPL, you'd simply save some confusion later eventually.

I'd also like to note that LGPL lets some "good guys'" businesses to exist, like Linux Game Publishing, as stated in this article.
For years, LGP has been working with libraries such as SDL, ffmpeg, and others that are licensed under the LGPL (GNU Lesser General Public License). Without these invaluable tools from the open source community, LGP would not exist, and nor would hundreds of open source projects.
So no LGPL = no high quality games for Linux. Looks like a blow for the OS. In case of Orbiter, though, such a problem doesn't exist, as the addons won't be commercial anyway, so nobody's financial future is at sake, and Orbiter can't get any better anyway, like Linux got better, thanks to Linux Game Publishing. Well, there could be some exceptions, for example asmi made a case for DX11 client, that he could add some proprietary (?) graphics code if the client wasn't GPLed. But on the other hand, what would then happen to the DX11 client once asmi leaves the scene?
 

Interceptor

Well-known member
Joined
Mar 28, 2008
Messages
2,718
Reaction score
76
Points
63
Location
Michigan,Florida
Thanks,once again Enjo.

---------- Post added at 04:51 PM ---------- Previous post was at 03:44 PM ----------

Enjo,is it possible now to use the Axiel velocity hud with the XR ships using this MFD now, could you some how make a fix for this.Thanks
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Enjo,is it possible now to use the Axiel velocity hud with the XR ships using this MFD now, could you some how make a fix for this.Thanks

Unfortunately not. Reason: great add on (Axial), but released without source and then the author has stopped maintaining it. So it becomes a relic, instead of a living idea. This is exactly why Enjo is moving his code to GPL, to require derivative works to release source code as well as the add on, so in some future world, the concept can be rescued and enhanced. For Axial, we would need to start the code from scratch, as doing a byte by byte disassembly is just not practical.

This is why Enjo is leading a fight here for addons to be open.
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
So after an absence from Orbiter coding (due to Real Life), I tried putting my RV Orientation back together today. The original test rig was coded to the old HUD Drawer 0.1 (simple, solid), and now we have this pesky Module ID to worry about in version 0.2 :). Personally, I knew where I was in the first version, and I am in a world of pain with this one. Two issues - one irritating and the second fatal:

1. (Irritating) I am getting a C4251 warning on the compile, as follows:

Code:
1>  RVO_HUDHandling.cpp
1>j:\orbiter\orbitersdk\include\enjolib\idrawshud.hpp(105): warning C4251: 'EnjoLib::IDrawsHUD::m_moduleID' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'EnjoLib::IDrawsHUD'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>  RV_Orientation.vcxproj -> J:\ADSWNJ_Wkg\RV_Orientation\..\..\Orbiter\Modules\Plugin\RV_Orientation.dll

this piece of code looks like this:

Code:
// ==============================================================
//
//	Rendezvous Orientation MFD (HUD Handling)
//	=============================================
//
//	Copyright (C) 2013	Andrew (ADSWNJ) Stokes
//                   All rights reserved
//
//	See RV_Orientation.cpp
//
// ==============================================================

#include "RV_Orientation.h"

void RV_Orientation::DrawHUD (int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad * skp)
{
 
	return ;
}

bool RV_Orientation::ShouldDrawHUD () const
{
	return true;
}

and RV_Orientation.h looks like this:

Code:
// ==============================================================
//
//	Rendezvous Orientation MFD (RV_Orientation)
//	===========================================
//
//	Copyright (C) 2013	Andrew (ADSWNJ) Stokes
//                   All rights reserved
//
//	See RV_Orientation.cpp
//
// ==============================================================


#ifndef __RVO_H
#define __RVO_H


#include "RVO_Core.hpp"
#include "EnjoLib/IDrawsHUD.hpp"   

class RV_Orientation: public MFD2, public EnjoLib::IDrawsHUD
{
public:
	RV_Orientation (DWORD w, DWORD h, VESSEL *vessel, UINT mfd);
	~RV_Orientation ();
	
  char *ButtonLabel (int bt);
	int ButtonMenu (const MFDBUTTONMENU **menu) const;
  bool ConsumeKeyBuffered (DWORD key);
  bool ConsumeButton (int bt, int event);
  
  bool Update (oapi::Sketchpad *skp);
	static int MsgProc (UINT msg, UINT mfd, WPARAM wparam, LPARAM lparam);

// Button Press Handlers
  void Button_TGT();
  void Button_DPT();
  void Button_HUD();
  void Button_MOD();
  void Button_DST();
  void Button_UNT();
  void Button_APR();
  void Button_APT();
  void Button_APF();

// HUD Hookers
  void DrawHUD(int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad * skp);
  bool ShouldDrawHUD() const;

protected:
  RVO_GCore* GC;
  RVO_LCore* LC;
  RVO_MCore* MC;
  RVO_VCore* VC;

  int Line( int row );
  int Col( int pos );

};

#endif // !__RVO_H


Any ideas how to remove this warning (without just suppressing it)?


2. (fatal) On launch I get two "Orbiter Launchpad:eek:rbiter.exe - Entry Point Not Found errors ... one from Glideslope 2 (bizarre?) and the other for my RV_Orientation.dll

Error:
Code:
The procedure entry point ??0IdrawsHUD@EnjoLib@@QAE@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z could not be located in the dynamic link library J:\Orbiter\Modules\Plugin\RV_Orientation.dll

Help!! What is going on?


Thought ... could we not have a char* HUDModuleName() function, and keep the class definition as the 0.1 version?




~~~~~

Had a read of this: http://stackoverflow.com/questions/5661738/common-practice-in-dealing-with-warning-c4251-class-needs-to-have-dll-inter

I'm wondering if there is a difference in implementation between your VC2008 and my VC2010. Looks like exporting these Std Template Libraries is potentially dangerous. Make it a simple char string?
 
Last edited:

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Yup, I'll do it this way. Thanks for the tip. I didn't know about this STL ... feature.
Stay tuned for 0.3 tomorrow.
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Please try the attached version before I officially release it. The new method is:
PHP:
const char * GetModuleName() const;

For example:
PHP:
const char * MyModule::GetModuleName() const
{
   return "My Module";
}
 

Attachments

  • HUDDrawerSDK-v.0.3.zip
    219.2 KB · Views: 15

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Awesome! That fixes everything, Enjo. I have the RV Orientation code compiling and running cleanly and being recognized in your HUD Drawer MFD too. So our hypothesis of a STL implementation difference between VC++ 2008 and VC++ 2010 is probably the root cause.

Still need a final debug session and then I'll have an alpha to show.

Thanks again!
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
First off, as you might have noticed, I've officially released the v. 0.3, with updated documentation and source code. It's also been included in the latest Launch MFD release, so when you release the RV Orientation for public testing, it won't collide with Launch MFD. After you're done, I'll stop packaging HUDDrawer SDK into next releases of Launch MFD, and point to an external dependency download, like it is done with other Orbiter SDKs. I ask you to do the same, as this helps in JSGME's management system - the individual files are not overwritten this way, and you may install/deinstall the addons in any order.

Regarding building C++ libraries, I've come across some interesting articles, like this one:
http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL
However none of these articles describe exactly my case, where I export a class for deriving.
However, the common solution for C++ is exporting only interfaces - classes with pure virtual methods and no members. Which makes me wonder why my solution works, since my class has defined both constructor and destructor. On the other hand, they only call static methods of other class, and don't manipulate on own members. Well, if it works, I'm fine with it.
Another thing is, as you've pointed out, that exporting, or accepting STL classes as parameters is a bad idea because of different implementations across compiler versions.

And that would be it. A C++ library requires some love, but is perfectly doable, and allows to keep the cleanness of OOP.
 
Last edited:
Top