![]() |
|
|||||||
| Orbiter SDK Orbiter software developers post your questions and answers about the SDK, the API interface, LUA, meshing, etc. |
![]() |
|
|
Thread Tools |
|
|
#1 |
|
Aspiring rocket scientist
![]() ![]() ![]() |
Like the title says, I'm trying to impliment a VC but need help figuring out cockpit redraw events.
Thus far I've got the MFD's up and running but haven't even been able to manage a simple "hello world" beyond that. Code:
bool LEM::clbkLoadVC (int id) // Render Virtual Cockpit
{
//Define MFDs
static VCMFDSPEC Cmd_MFD = {mesh_VC, 0}; // Define surface on which to display MFDs. [Mesh, Mesh Group #]
static VCMFDSPEC Pilot_MFD = {mesh_VC, 1};
oapiVCRegisterMFD (0, &Cmd_MFD); // Register MFDs in orbiter's interface [registry # and VCMFDSPEC]. (registry numbers start at 0 and count up)
oapiVCRegisterMFD (1, &Pilot_MFD);
//Define Other Displays
SURFHANDLE tex = oapiGetTextureHandle (mh_cockpit, 3);
oapiVCRegisterArea (AID_CLOCK, _R(0,0,256,256), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_LBDOWN, PANEL_MAP_BGONREQUEST, tex);
oapiVCSetAreaClickmode_Spherical (AID_CLOCK, _V( 0.334, 0.814, 1.789), 2.5);
return true;
}
bool LEM::clbkVCRedrawEvent (int id, int event, SURFHANDLE surf)
{
????????????????
return true;
}
Any assistance would be greatly appreciated. |
|
|
|
|
|
#2 |
|
shoemaker without legs
![]() |
You'll have to write a class that does the drawing, and call it from clbkVCRedrawEvent when the id of the element is passed to it. At least that's the most convienient option. you could do the blitting or sketchpading directly in clbkVCRedrawEvent, of course, but that will become an organisational nightmare real quick.
Here's a very good tutorial for panels, but VC works pretty similar, so you'll be able to adapt most of it: http://www.orbiter-forum.com/blog.php?b=574 |
|
|
|
|
|
#3 |
|
Aspiring rocket scientist
![]() ![]() ![]() |
How would I go about setting up the "drawing class" that you describe?
Also the tutorial describes taking a bitmap and manually defining ascii characters as x y coordinates on that bitmap. Isn't there a way to simply "sprintf" to a surface? |
|
|
|
|
|
#4 |
|
shoemaker without legs
![]() |
There is if you use sketchpad. It's slower, and can have trouble with graphics clients if you draw directly to a video surface. The best way with sketchpad is to create a new surface, do the drawing and the blit the contents of that surface onto the video surface.
On the other hand, if you make a monotype bitmap font (there are apps that can make a bitmap out of a font) and take what is already there in the tutorial, a print function almost writes itself. Here's what mine looks like (only works for monotype fonts!): Code:
void IMS_MFC::MFCprint(SURFHANDLE surf, char* text, int _length, int _x, int _y, MFC_TEXT_POS tpos)
{
int fWidth = 9;
int fHeight = 13;
int textwidth = fWidth * _length;
for (int i = 0; i < _length; ++i)
{
int srcx = (text[i] - 32) * fWidth;
int tgtx;
switch (tpos)
{
case T_LEFT:
tgtx = _x + i * fWidth;
break;
case T_RIGHT:
tgtx = _x - textwidth + i * fWidth;
break;
case T_CENTER:
tgtx = _x - textwidth / 2 + i * fWidth;
}
oapiBlt(surf, Src, tgtx, _y, srcx, 0, fWidth, fHeight);
}
}
Quote:
|
|
|
|
| Thanked by: |
|
|
#5 |
|
Orbinaut
![]() ![]() |
If its any help, I'm trying! to make a 2D panel, and an MFD using the MFD template in the samples directory. Plodding alomg slowly.
This is the thread: http://www.orbiter-forum.com/showthr...light=westcott Currently working on the panel, the MFD is finished: http://i89.photobucket.com/albums/k2...4/LoxMFD_2.jpg Code:
// ==============================================================
// ORBITER MODULE: DialogTemplate
// Part of the ORBITER SDK
// Copyright (C) 2003-2010 Martin Schweiger
// All rights reserved
//
// MFDTemplate.cpp
//
// This module demonstrates how to build an Orbiter plugin which
// inserts a new MFD (multi-functional display) mode. The code
// is not very useful in itself, but it can be used as a starting
// point for your own MFD developments.
// ==============================================================
#define STRICT
#define ORBITER_MODULE
#include "windows.h"
#include "orbitersdk.h"
#include "MFDTemplate.h"
// ==============================================================
// Global variables
int g_MFDmode; // identifier for new MFD mode
// ==============================================================
// API interface
DLLCLBK void InitModule (HINSTANCE hDLL)
{
static char *name = "MyMFD Template"; // MFD mode name
MFDMODESPECEX spec;
spec.name = name;
spec.key = OAPI_KEY_T; // MFD mode selection key
spec.context = NULL;
spec.msgproc = MFDTemplate::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
MFDTemplate::MFDTemplate (DWORD w, DWORD h, VESSEL *vessel)
: MFD2 (w, h, vessel)
{
font = oapiCreateFont (w/20, true, "Arial", FONT_NORMAL, 0);
pRed = oapiCreatePen(1, 1, MFD_RED);
pGreen = oapiCreatePen(1, 1, MFD_GREEN);
pBlue = oapiCreatePen(1,1, MFD_BLUE);
pWhite = oapiCreatePen(1,1, MFD_WHITE);
pGaslox = oapiCreatePen(2,1, MFD_GASLOX);
pControl = oapiCreatePen(2,1, MFD_Control);
bBlack = oapiCreateBrush(MFD_BLACK);
bWhite = oapiCreateBrush(MFD_WHITE);
bRed = oapiCreateBrush(MFD_RED);
bGreen = oapiCreateBrush(MFD_GREEN);
bBlue = oapiCreateBrush(MFD_BLUE);
bGaslox = oapiCreateBrush(MFD_GASLOX);
bGasnit = oapiCreateBrush(MFD_GASNIT);
bLox = oapiCreateBrush(MFD_LOX);
// Add MFD initialisation here
}
// Destructor
MFDTemplate::~MFDTemplate ()
{
oapiReleaseFont (font);
oapiReleasePen (pRed);
oapiReleasePen (pGreen);
oapiReleasePen (pBlue);
oapiReleasePen (pGaslox);
oapiReleasePen (pControl);
oapiReleaseBrush(bBlack);
oapiReleaseBrush(bWhite);
oapiReleaseBrush(bRed);
oapiReleaseBrush(bGreen);
oapiReleaseBrush(bBlue);
oapiReleaseBrush(bGaslox);
oapiReleaseBrush(bGasnit);
oapiReleaseBrush(bLox);
// Add MFD cleanup code here
}
// Return button labels
char *MFDTemplate::ButtonLabel (int bt)
{
// The labels for the four buttons used by our MFD mode
static char *label[4] = {"PRE", "HYD", "ELE", "PNE"};
return (bt < 4 ? label[bt] : 0);
}
// Return button menus
int MFDTemplate::ButtonMenu (const MFDBUTTONMENU **menu) const
{
// The menu descriptions for the four buttons
static const MFDBUTTONMENU mnu[4] = {
{"Pressurisation", 0, '['},
{"Hydraulic", 0, '['},
{"Electrical", 0, '['},
{"Pneumatic", 0, ']'}
};
if (menu) *menu = mnu;
return 4; // return the number of buttons used
}
// Repaint the MFD
bool MFDTemplate::Update (oapi::Sketchpad *skp)
{
Title (skp, "PACK A");
// Draws the MFD title
skp->SetFont (font);
skp->SetTextAlign (oapi::Sketchpad::CENTER, oapi::Sketchpad::BASELINE);
skp->SetTextColor (MFD_WHITE);
skp->Rectangle (W/4, H/128, (3*W)/4, H/16);
skp->Text (W/2, H/20,"LOX PRESSURISATION", 18);
skp->Rectangle (W/80, H/12, (21*W)/64, H/7);
skp->Text (W/6, H/8,"Main Sequencer", 14);
skp->Rectangle ((3*W)/8, H/12, (5*W)/8, H/7);
skp->Text (W/2, H/8,"- 00:00:10", 10);
skp->Rectangle ((45*W)/64, H/12, (63*W)/64, (34*H)/128);
skp->Text((27*W)/32,(9*H)/64, "Pressurisation",14);
skp->Text((27*W)/32,(12*H)/64, "Control",7);
skp->Text((27*W)/32,(30*H)/128, "Unit",4);
skp->Rectangle((11*W)/32, H/6, (21*W)/32, (27*H)/128);
skp->Text(W/2,H/5,"Ground Nitrogen",15);
skp->Rectangle((11*W)/32, (55*H)/256, (21*W)/32, (33*H)/128);
skp->Text(W/2,H/4,"Heat Exchanger", 14);
skp->Rectangle((6*W)/32, (55*H)/256, (10*W)/32, (33*H)/128);
skp->Text(W/4, (2*H)/8,"LOX", 3);
skp->SetPen(pRed);
skp->Line((21*W)/64,H/9,(3*W/8),H/9);
skp->Line((5*W)/8,H/9,(45*W/64),H/9);
skp->Line((21*W)/32,12*H/64, (45*W/64),12*H/64);
skp->Line((21*W)/32,15*H/64, (45*W/64),15*H/64);
skp->Line((10*W)/32,15*H/64, (11*W/32),15*H/64);
// ----------- end of control graphics -------------------------
// ------------- Tanks and valves ------------------------------
// --------------- Start Tank Assembly -------------------------
skp->SetPen(pWhite);
skp->Rectangle((1*W)/32, (12*H)/32, (8*W)/32, (24*H)/32); // Start Tank
skp->Text((9*W)/64, (51*H)/64, "Start Tank",10);
skp->Rectangle((2*W)/32, (9*H)/32, (3*W)/32, (12*H)/32); // Start Tank filler
skp->Rectangle((1*W)/32, (17*H)/64, (4*W)/32, (9*H)/32);
//Start Tank Pressurisation Pipe
skp->SetBrush(bGasnit);
skp->Rectangle((48*W)/64,(17*H)/64,(49*W)/64,(21*H)/64); // Pipe 1
skp->Rectangle((8*W)/64,(20*H)/64,(49*W)/64,(21*H)/64); // Pipe 2 horiz
skp->Rectangle((8*W)/64,(20*H)/64,(9*W)/64,(24*H)/64); // Pipe 3
//skp->Rectangle((8*W)/32, (27*H)/64, (10*W)/32, (14*H)/32); // Vent pipe
skp->SetBrush(NULL); // back to unfilled rectangles
skp->Rectangle((8*W)/32, (12*H)/32, (17*W)/32, (27*H)/64); // Valve border
skp->Text((23*W)/64,(53*H)/128, "Vent Valve",10);
skp->SetBrush(bGreen);
skp->Rectangle((15*W)/32, (12*H)/32, (17*W)/32, (27*H)/64); // Start Tank Vent
skp->SetBrush(NULL); // back to unfilled rectangles
skp->SetPen(pWhite);
// -------------------- Run Tank Asembly -------------------------
skp->Rectangle((16*W)/32, (16*H)/32, (24*W)/32, (24*H)/32); // Run Tank
skp->Text((10*W/16), (51*H)/64, "Run Tank",8);
//Run Tank Pressurisation Pipes
skp->SetBrush(bGaslox);
skp->Rectangle((59*W)/64,(17*H)/64,(60*W)/64,(34*H)/64); // Pipe 1 vert
skp->Rectangle((24*W)/32,(33*H)/64,(60*W)/64,(34*H)/64); // Pipe 2 horiz
skp->SetBrush(NULL); // back to unfilled rectangles
skp->Rectangle((35*W)/64,(29*H)/64,(52*W)/64,(32*H)/64); // Valve border
skp->Text((21*W)/32,(63*H)/128, "Vent Valve",10);
skp->SetBrush(bGreen);
skp->Rectangle((48*W)/64,(29*H)/64,(52*W)/64,(32*H)/64); // Run Tank Vent
skp->SetBrush(NULL); // back to unfilled rectangles
// ------------------ Valve Control -----------------------------
skp->SetPen(pControl);
skp->Line((51*W)/64,(17*H)/64,(51*W)/64,(25*H)/64);
skp->LineTo((33*W)/64,(25*H)/64);
skp->Line((57*W)/64,(17*H)/64,(57*W)/64,(30*H)/64);
skp->LineTo((52*W)/64,(30*H)/64);
skp->Line((54*W)/64,(17*H)/64,(54*W)/64,(28*H)/64);
skp->LineTo((24*W)/64,(28*H)/64);
skp->LineTo((24*W)/64,(40*H)/64);
// ------------------- end of valve control ----------------------
// ------------------- Main Pipework -----------------------------
skp->SetPen(pWhite);
skp->Rectangle((8*W)/32, (20*H)/32, (16*W)/32, (22*H)/32);
skp->Rectangle((24*W)/32, (20*H)/32, (28*W)/32, (22*H)/32);
skp->Rectangle((28*W)/32, (19*H)/32, (57*W)/64, (23*H)/32);
skp->Rectangle((57*W)/64, (19*H)/32, (58*W)/64, (23*H)/32);
skp->Line((58*W)/64, (20*H)/32, (62*W)/64, (20*H)/32);
skp->Line((58*W)/64, (22*H)/32, (62*W)/64, (22*H)/32);
skp->Ellipse((11*W)/32, (20*H)/32, (13*W)/32, (22*H)/32);
skp->Text((12*W)/32, (47*H)/64, "Fill/Check",10);
skp->Text((28*W)/32, (49*H)/64, "To Engine",9);
// ----------------------------------------------------------------
// -------------------- Data Area ---------------------------------
skp->Line(0,(52*H)/64,W, (52*H)/64);
skp->Text(W/2, (55*H)/64, "Ullage Pressure",15);
skp->Text(W/2, (58*H)/64, "Tank Volume",11);
skp->Text(W/2, (61*H)/64, "Tank Flow",9);
//--------------------- Fill/Check Valve draw ----------------------
skp->SetBrush(bGreen);
skp->Ellipse((11*W)/32, (20*H)/32, (13*W)/32, (22*H)/32);
skp->SetBrush(bBlack);
skp->Ellipse((11*W)/32, (20*H)/32, (13*W)/32, (22*H)/32);
skp->SetBrush(bRed);
skp->Rectangle((23*W)/64, (20*H)/32, (25*W)/64, (22*H)/32);
skp->SetBrush(bBlack);
skp->Rectangle((23*W)/64, (20*H)/32, (25*W)/64, (22*H)/32);
// Add MFD display routines here.
// Use the device context (hDC) for Windows GDI paint functions.
return true;
}
// MFD message parser
int MFDTemplate::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 MFDTemplate (LOWORD(wparam), HIWORD(wparam), (VESSEL*)lparam));
}
return 0;
}
Code:
// ==============================================================
// ORBITER MODULE: DialogTemplate
// Part of the ORBITER SDK
// Copyright (C) 2003 Martin Schweiger
// All rights reserved
//
// MFDTemplate.h
//
// This module demonstrates how to build an Orbiter plugin which
// inserts a new MFD (multi-functional display) mode. The code
// is not very useful in itself, but it can be used as a starting
// point for your own MFD developments.
// ==============================================================
#ifndef __MFDTEMPLATE_H
#define __MFDTEMPLATE_H
#define MFD_WHITE 0xFFFFFF
#define MFD_BLACK 0x000000
#define MFD_RED 0x0000FF
#define MFD_GREEN 0x00FF00
#define MFD_BLUE 0xFF0000
#define MFD_GASLOX 0x888888
#define MFD_GASNIT 0x88FF88
#define MFD_Control 0x8888FF
#define MFD_LOX 0xCCFFCC
class MFDTemplate: public MFD2 {
public:
MFDTemplate (DWORD w, DWORD h, VESSEL *vessel);
~MFDTemplate ();
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);
protected:
oapi::Font *font;
oapi::Pen *pRed;
oapi::Pen *pGreen;
oapi::Pen *pBlue;
oapi::Pen *pWhite;
oapi::Pen *pGaslox;
oapi::Pen *pControl;
oapi::Brush *bBlack;
oapi::Brush *bGreen;
oapi::Brush *bRed;
oapi::Brush *bBlue;
oapi::Brush *bWhite;
oapi::Brush *bGaslox;
oapi::Brush *bGasnit;
oapi::Brush *bLox;
};
#endif // !__MFDTEMPLATE_H
Last edited by Notebook; 06-26-2012 at 08:18 AM. |
|
|
|
| Thanked by: |
|
|
#6 |
|
Donator
![]() ![]() |
I can only recommend: Avoid blitting operations. They are pretty slow most of the time and use the bottleneck between GPU and CPU. There are many situations in which you can get better results with texture coordinate manipulations, than with painting on the textures.
And: Sure you can't use every surface in Sketchpad for painting. A surface for painting has to be decompressed and has to be stored in a memory location that permits such 2D operations. You can blit it to a hardware accelerated surface, but not just swap both types. |
|
|
|
|
|
#7 |
|
shoemaker without legs
![]() |
Quote:
|
|
|
|
|
|
#8 |
|
Donator
![]() ![]() |
Quote:
|
|
|
|
|
|
#9 |
|
Aspiring rocket scientist
![]() ![]() ![]() |
For some context here are some shots of what I've got so far.
For the attitude indicator I had initially intended to simply reuse the Stock DG's, but a cursory review of the code convinced me that I was in way over my head. Right now I want to focus on creating a set of simple LCD-style numeric displays, as this will give me a way to display current thrust and propellant levels wich are currently my biggest obstical to release. I generated the following Bitmap but where do I go from here? LCDfont.bmp the characters are 40x24 pixels and evenly spaced but how do I associate specific X, Y coordinates with specific characters to create a font? Last edited by Hlynkacg; 06-26-2012 at 09:21 PM. |
|
|
|
| Thanked by: |
|
|
#10 |
|
Donator
![]() ![]() |
make every digit of your display a single rectangle in the panel mesh and texture it with your character texture. Then program a list with 4 (u,v) coordinates per digit to display. each (u,v) pair defines one corner of the digit rectangle.
When changing the digit, copy the four (u,v) coordinates to the four vertexes of the rectangle in your Panel2D. This way, your digit texture can be stored in compressed form on the GPU. |
|
|
|
|
|
#11 |
|
Aspiring rocket scientist
![]() ![]() ![]() |
Having a seperate mesh group for every single character on a display sounds like it would get out of hand fast.
There's got to be a simpler way to do this. @Jedia would you mind explaining what's happening in your IMS_MFC::MFCprint function? Last edited by Hlynkacg; 06-26-2012 at 11:35 PM. |
|
|
|
|
|
#12 |
|
Donator
![]() ![]() |
Quote:
|
|
|
|
|
|
#13 |
|
Aspiring rocket scientist
![]() ![]() ![]() |
I found the following code in the stock DG which appears to have the functionality I want. Namely printing a string to a mesh surface, is there any way I can adapt this?
Code:
// --------------------------------------------------------------
// Paint individual vessel markings
// --------------------------------------------------------------
void DeltaGlider::PaintMarkings (SURFHANDLE tex)
{
oapi::Font *font = oapiCreateFont (38, true, "Sans", FONT_BOLD);
oapi::Sketchpad *skp = oapiGetSketchpad (tex);
if (skp) {
skp->SetFont (font);
skp->SetTextColor (0xD0D0D0);
skp->SetTextAlign (oapi::Sketchpad::CENTER);
char cbuf[32];
strncpy (cbuf, GetName(), 10);
int len = min(strlen(GetName()), 10);
skp->Text (196, 10, cbuf, len);
skp->Text (196, 74, cbuf, len);
skp->SetTextColor (0x808080);
skp->SetTextAlign (oapi::Sketchpad::RIGHT);
skp->Text (120, 158, cbuf, len);
skp->SetTextAlign (oapi::Sketchpad::LEFT);
skp->Text (133, 158, cbuf, len);
oapiReleaseSketchpad (skp);
}
oapiReleaseFont (font);
}
|
|
|
|
|
|
#14 |
|
Donator
![]() ![]() |
Remember that this code is extremely versatile, but also extremely slow. The Text function isn't meant for rapid update rates. A blit function with a font texture would be better then, but still slower than direct texture coordinate manipulation.
|
|
|
|
|
|
#15 |
|
Aspiring rocket scientist
![]() ![]() ![]() |
Right I'm more concerned with getting something that works.
|
|
|
|
![]() |
|
| Thread Tools | |
|
|
|||||
| Quick Links | Need Help? |