You are on page 1of 11

N0801

--------------Point Of
How To
View
Control a
SimConnect
Custom
Tutorial
Camera
For Flight
in FSX SDK
Simulator X ---------------

N0801 Tutorial

Lets give us a challenge to continue to learn SimConnect with our tutorials.

What is this tutorial for? The tutorial is to understand how we can control a camera
using SimConnect. The camera can be moved using the keyboard or using pre-recorded
paths. This allows to show points of view not accessible with the default cameras.

The image on the left is a standard screenshot from FSX (the external spot view). In
this type of view, the camera is linked to the aircraft (distance and angle), the camera is
centered on the aircraft (the camera is tracking the center of the plane). In addition the
view is always aligned with the horizon, whatever the bank amount of the aircraft.

What do you need to complete this tutorial? MS FSX SDK, which is on the CD
of MS FSX Professional. A compiler, which can be MS Visual Studio C++, C# or VB,
which is available for free at Microsoft.
Suggested pre-read: We wont re-explain in detail how SimConnect clients talk with
FSX, nor what are the basic events sent by SimConnect. This was the goal of the previous
tutorial N0800, Follow This Plane - How to fly AI Aircrafts Using Waypoints in FSX SDK.

Our Goal

The image on the right shows what we can do with SimConnect: we can use the six
degrees of freedom of the camera, i.e. we can move at any distance from the aircraft on
each of the three axes X, Y, Z; and we can rotate the camera any angle around the three
same axes (giving the camera some pitch, bank and heading). This way we can center the
camera on any point, not only the aircraft.
Each default camera has some degrees of freedom frozen or locked to something. Well
create a new camera in the list of global cameras . Well link the camera to the aircraft
and using appropriate commands, place the camera at some distance. Using the same
commands, well orient it. Well change the settings for each frame, according to some
law. This will create a camera movement...

From previous tutorial, SimConnect Overview


SimConnect is a gateway that allows external programs to interact with FSX.
SimConnect is part of FSX SDK. So you need to install the SDK if you want to use
SimConnect. It displays itself as a server and the external programs are clients.
SimConnect allows the client to receive information about FSX simulation. The
client may ask details of the current state of the simulation, for instance which objects,
like aircrafts, are currently simulated; or what are the parameters, like the altitude, of
these objects.
An asynchronous request / reply mechanism is used to obtain data. The client
usually sends a request to SimConnect, SimConnect replies to this request later. The client
hasnt to wait for the reply, it can perform other tasks in the meantime. When SimConnect
is ready to reply, it sends an event message to the client, using a messaging system.
The client needs to receive all event messages, and dispatch them according
to their nature. To do that it monitors continuously for new SimConnect messages thru
an endless loop. When a message is available, the loop transfers the control to a callback
routine designed to handle these messages in a specific way.
The callback procedure is the core of the client design. It identifies the type of
message received, and execute appropriate calls so that the application is aware of replies
to previous requests. Basically a SimConnect client application is a program that sends
requests to SimConnect and manage replies in an asynchronous way in the callback
procedure.
The client may also subscribe for events notification. It informs SimConnect
of its interest in being informed about changes, e.g. the simulation being paused, or
an object being removed from the simulation. When such event occurs, SimConnect
just sends an event message to be received and processed by the client in the callback
procedure.
SimConnect allows the client to change the status of the simulation. The client
can move objects, create new ones, control cameras, modify FSX menus, display dialog
boxes, etc. To do that, the client sends data, aimed to some object in the simulation.
SimConnect receives these data asynchronously too. It processes them when possible, and
according to some priority set by the client.
SimConnect manages multiple clients. Clients may reside on the same computer or

void C A LL B A C K

P ro g ra m S ta rt

M yD isp atch P ro c
(S IM C O N N E C T_ R E C V * pD ata)

C ontinue = true
s w itc h(pD ata->dw ID )

S im C onnect_C a llD isp atc h


(M yD is patc hP ro c)

S leep()

C ontinue = = true

{
c a se S IM C O N N EC T_R E C V_ ID _ E XC E P T IO N :

bre a k;
c a se S IM C O N N EC T_R E C V_ ID _ E V EN T :

bre a k;
c a se S IM C O N N EC T_R E C V_ ID _ E V EN T _O BJ E C T _ AD D R EM O V E :

bre a k;
c a se S IM C O N N EC T_R E C V_ ID _ S IM O BJ EC T_ D AT A :

bre a k;
c a se

P ro g ra m E n d

R o u tin e E n d

not. The connection between the server and the clients relies on IP streams and pipes,
but these details are mostly transparent to the clients programmers. The SimConnect
API manages the communication when data transfers are needed. Clients may ask other
clients to be notified of what they send to SimConnect. The FSX simulation engine by itself
is also a SimConnect client. All messages inbound and outbound are processed by the
server based on priorities that may be assigned by clients. The final order for processing
messages of identical priority is managed by SimConnect.

Camera position parameters


To place the camera at a specific position, we need to provide the value for the
translation on X, Y and Z axes. This is the distance relative to the center of the aircraft. The
center of the camera will follow the center of the airplane.

If we want to rotate the camera relatively to the aircraft, we need to provide the desired
values for Heading, Pitch, and Bank. SimConnect provides a function to control the active
camera position:
SimConnect_CameraSetRelative6DOF(
hConnection, X, Y, Z, P, B, H)

You may have noticed that the angle are not provided in a range 0 to 360. Instead there
are given using -180 to 180. For the pitch value, we are even limited to look forward.
To hide this limitation to the user, well need to perform some adjustments when looking
behind.

How to manipulate the camera


Well give the user a way to increase and decrease the amount of translation along the 3
axes, and the amount of rotation around the three axes. Well ask SimConnect to notify
our client when the user presses the assigned keys.
Well offer a possibility to send predetermined paths to the camera. As this is only a
tutorial, we wont try to offer powerful recording functions, only a way to move and rotate
at some fixed rate, according to time, and switch instantaneously from a position to
another.
Since we dont want to move the camera while the simulation is paused (we could), well
also request SimConnect to nofify our program when the Pause function is used.

Classes
We have different tasks to do, i.e. listening to incoming notifications, controlling the
camera position based on users inputs, and playing back the pre-recorded paths. We keep
these functions separate in different classes of C++.
RecordedPath holds a pre-recorded path, its task is to feed the camera with a position
for a given frame number.
If we want to move the camera in the direction of an arrow, the translation amount is a
positive number, it is negative if we want to move in the opposite direction.

PathPlayer manage all required RecordedPath, and ensure all paths are replayed one
after the other.
Camera maintains the current cameras position, taking care of updating it when the user

presses assigned keys, and also requesting position from the PathPlayer when the user
selects the automatic mode.
PointOfView is the entry point with the message loop, and also contains the callback
procedure. The callback procedure transfer non trivial actions to the Camera object.

Adding a camera to FSX

SnapPbhAdjust = Swivel
PanPbhAdjust = Swivel
SnapPbhReturn = FALSE
PanPbhReturn = FALSE
AllowZoom = Yes
InitialZoom = 2
SmoothZoomTime = 0
ShowWeather = Yes
ShowLensFlare=TRUE

We create this camera because default cameras dont have the criteria we are looking for.
The camera must be an external view, adjustable on its 6 degrees of freedom (swivel),
and tracking no object. To facilitate its positionning relative to the users aircraft, it will
have its origin at the aircrafts center. Well have it displayed in the list of views, at the
root level.

After saving the file and re-starting FSX, you should have a new camera named Moving
Camera. You wont see your airplane first, because the external camera is in the aircraft.
Youll have to move it outside in the direction of the rear (repeat Ctrl + Enter a zillion
times, default motion is sloooow). Alternatively you may create it with a different initial
position InitialXyz = 0, 0, -30.

Cameras can be described at FSX level, at aircraft level and at mission / flight level. Our
camera is at FSX level, available anytime. Locate your cameras.cfg file in

Lets define now what will be our camera keyboard. We use the numeric keypad. We will
define our key mapping in a way that the initial function of the key will be deactivated.
We need three translations and three rotations. in addition well have a key that toggles
on / off the automatic replay of paths:

\Documents and Settings\{your users name}\Application Data\


Microsoft\FSX

Make a copy before modying the original file. Add a section


[Cameradefinition.012] at the end of the file (ensure the number 012 is available
for you too, else use the first available). Each camera must have a unique identifier
(GUID). You can create a GUID with a tool from MS (GUIDGen). The GUID should be
generated on your computer to ensure its uniqueness in your environment. It is very
unlikely the one I provide exists on your computer, so you may want to use it as is if you
dont have GUIDGen.
[Cameradefinition.012]
Title=Moving Camera
Guid={9CD147F2-C6C8-4f52-9B65-C24D83A47D98}
Description = This camera moves around the aircraft
Category = Custom
Origin = Center
InstancedBased = No
XyzAdjust = TRUE
InitialXyz = 0, 0, 0
Transition = No
Track = None
AllowPbhAdjust = TRUE
InitialPbh = 0, 0, 0

+X
6
+Bank
Shift+6

-X
4
-Bank
Shift +4

+Y
9
+Head.
Shift +9

-Y
7
-Head.
Shift +7

+Z
8
+Pitch
Shift +8

-Z
2
-Pitch
Shift +2

Replay
5

Well ask SimConnect to notify our client when the user presses these keys. SimConnect
will need to associate an event number of our choice (but unique) with such event, so lets
define our events IDs in PointOfView.cpp:
// clients events triggered by key inputs
enum EVENTS {
EVENT_CAMERA_XP, EVENT_CAMERA_XM,
EVENT_CAMERA_YP, EVENT_CAMERA_YM,
EVENT_CAMERA_ZP, EVENT_CAMERA_ZM,
EVENT_CAMERA_PP, EVENT_CAMERA_PM,
EVENT_CAMERA_BP, EVENT_CAMERA_BM,
EVENT_CAMERA_HP, EVENT_CAMERA_HM,
EVENT_CAMERA_AUTO_TOGGLE,
};

Well also need a notification group ID, the only requirement is still it must be unique

among notification group IDs. Weve talked about these kind of IDs in the first tutorial
N0800 - Follow This Plane, so if youre not confortable, try it before going further with
this one. Well need another group, not for notification of events, but for toggling On / Off
our key access. Our groups:
enum GROUPS {
CAMERA_KEYS,
EVENTS_CAMERA,
};

Client Initialization
We have an initial function called when our client is launched. Itll contain all the code
that is necessary for the initialization:
void PointOfView() { ... }

The first important thing we need in this function is to establish a connection with the
SimConnect server (refer to the first tutorial for details). The connection handle is defined
as a global variable:
HANDLE

hSimConnect = NULL;

and it is initialized when requesting the connection:


if (SUCCEEDED(
SimConnect_Open(
&hSimConnect, PointOfView, NULL, 0, 0, 0))) {
printf(\nConnected.);
...
}

This if will contains most of our intialization code. For instance we need to create
private events. Private events are events that are defined by the client, and which are
not mapped (bound) to server events. At some point in time, we need to be inform that
the user has pressed the key for incrementing the pitch, or decrementing the X axis value,
etc. Private events are defined on the server like other events, with a map function, but
we dont provide an argument for the server event mapped. We suffix the name of our
event with P for Plus (increment the value) or M for Minus (decrement):
// Let SimConnect register these private events
SimConnect_MapClientEventToSimEvent(

hSimConnect, EVENT_CAMERA_XP);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_XM);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_YP);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_YM);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_ZP);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_ZM);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_PP);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_PM);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_BP);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_BM);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_HP);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_HM);
SimConnect_MapClientEventToSimEvent(
hSimConnect, EVENT_CAMERA_AUTO_TOGGLE);

These private events need to be given a priority, but this is done by inserting them in
groups, which are given a priority. Well need to provide the ID of a group later, so we
have no choice, we need to include our events in a group:
// include all events into an event notification group
SimConnect_AddClientEventToNotificationGroup(
hSimConnect, EVENTS_CAMERA, EVENT_CAMERA_XP);
SimConnect_AddClientEventToNotificationGroup(
hSimConnect, EVENTS_CAMERA, EVENT_CAMERA_XM);
SimConnect_AddClientEventToNotificationGroup(
hSimConnect, EVENTS_CAMERA, EVENT_CAMERA_YP);
... etc ...
SimConnect_AddClientEventToNotificationGroup(
hSimConnect, EVENTS_CAMERA, EVENT_CAMERA_HM);
SimConnect_AddClientEventToNotificationGroup(
hSimConnect, EVENTS_CAMERA, EVENT_CAMERA_AUTO_TOGGLE);

Now we need to bind the assigned keys with our private events. This way SimConnect will

notify us of the occurence of a private event when the corresponding key is pressed. The
key detection by SimConnect is named an InputEvent. An input event must be assigned
an InputGroup as said earlier, this is done while mapping it to the client private event.
When notifying the client, SimConnect will provide a value. We dont need it, so well ask
to return 0. When mapping a key to a client event, we have actually two events to map,
one when the key is pressed, one when the key is released. We are not interested in the
key released detection, so normally we would just request our mapping this way:

EVENT_CAMERA_AUTO_TOGGLE, 0,
(SIMCONNECT_CLIENT_EVENT_ID)SIMCONNECT_UNUSED, 0,
true);

Lets assign a priority to our input group, and also lets switch it on (when on, the
detection of the keys is allowed):

SimConnect_MapInputEventToClientEvent(
hSimConnect, CAMERA_KEYS, Num_6,
EVENT_CAMERA_XP, 0);

SimConnect_SetInputGroupPriority(
hSimConnect, CAMERA_KEYS, SIMCONNECT_GROUP_PRIORITY_
HIGHEST);
SimConnect_SetInputGroupState(hSimConnect,
CAMERA_KEYS, SIMCONNECT_STATE_ON);

But, because we need to specify the last parameter of the mapping function (maskable),
we are requiered to specificy all the optional parameters before it, and the event ID and
value for the key release are part of them, so we just put here dummy values:

When we will replay a pre-recorded set of positions, well need to take into consideration
the current status of the simulation (paused or unpaused). We need to be notified of pause
events. This is how we subscribe to these notifications (explained in the first tutorial):

SimConnect_MapInputEventToClientEvent(
hSimConnect, CAMERA_KEYS, Num_6,
EVENT_CAMERA_XP, 0,
(SIMCONNECT_CLIENT_EVENT_ID)SIMCONNECT_UNUSED, 0,
true);

// subscribe to Pause events


HRESULT hr = SimConnect_SubscribeToSystemEvent(hSimConnect,
EVENT_PAUSE_TOGGLE, Pause);
// set initial pause status
pause = (! hr == 0);

maskable = true will instruct SimConnect to stop notififying other clients after us,

The variable pause is a bool member which stores the current state of the simulation.

because we completely take care of this event ourselves. The notification of an event is
done by decreasing priority order. So clients that have associated this input event Num_
6 with a group with a higher priority than our CAMERA_KEYS group will anyway receive
it.

In replay mode, well also need to be informed about the rendering of frames. For each
frame, well provide a new camera position. We also explained how to do in the first
tutorial:

We mask the event here, in the sole purpose of preventing it to be given to FSX itself.
This way FSX will not interpret the key. All the keys are mapped the same way, we dont
provide all the code, just this addional example:
SimConnect_MapInputEventToClientEvent(
hSimConnect, CAMERA_KEYS, Shift+Num_8,
EVENT_CAMERA_PP, 0,
(SIMCONNECT_CLIENT_EVENT_ID)SIMCONNECT_UNUSED, 0,
true);

to illustrate how we define the event input Shift + 8 on the keypad. We finish with our
Start / Stop replay key:
SimConnect_MapInputEventToClientEvent(
hSimConnect, CAMERA_KEYS, Num_5,

// subscribe to SimConnect timer events


SimConnect_SubscribeToSystemEvent(
hSimConnect, TIMER_FRAME, Frame);

The event ID TIMER_FRAME has been added to our existing list of event IDs.

Creation of the Camera Object


We also include the code to create and initialize our camera object. The object is declared
before the function PointOfView():
Camera camera;

We use it later in this function:

// Move camera to initial location


camera.sendPosition();
printf(\nCamera initialized);

Well look at the Camera object shortly.


The last portion of the code placed in the initial function is related to managing the
SimConnect message queue and closing the connection when FSX is quitting (see in first
tutorial for further details):
// loop while FSX active
while( 0 == quit ) {
// monitor incoming messages
SimConnect_CallDispatch(hSimConnect, MyDispatchProc, NULL);
// give time to other processes
Sleep(1);
}
// now leaving
SimConnect_Close(hSimConnect);

Callback Procedure
We have subscribed to a number of events. SimConnect will send us messages to notify
about some event having occurred. All notifications are passed by SimConnect to the
callback procedure. We put some code here to process these notifications:
void CALLBACK MyDispatchProc(
SIMCONNECT_RECV* pData,
DWORD cbData, void *pContext) {
switch(pData->dwID) {

As already seen in the first tutorial, this procedure is a giant switch based on the value of
pData->dwID which identifies the type of notification received. Well look at these case
in particular:
case
case
case
case

SIMCONNECT_RECV_ID_EVENT:
SIMCONNECT_RECV_ID_EVENT_FRAME:
SIMCONNECT_RECV_ID_EXCEPTION:
SIMCONNECT_RECV_ID_QUIT:

The two last ones are special cases we need to detect errors reported by SimConnect,
and the moment it is terminating. Youll be able to look at the related code in the files,
well only talk about the others cases here. The second is to process the notification of the

rendering of a new frame by the simulation. We put here the code we need to update our
camera position if we are in replay mode.
if (moving && !pause) {
camera.computeAutoForFrame(frame);
camera.sendPosition();
++frame;
if (frame >= maxFrame) {
frame = 0;
}
}
break;

Well see later that moving is a flag to remember when we are in replay mode. pause
is another flag to remember when the simulation is paused. frame is an integer holding
the next frame number to be computed by the replay system. Our Camera object will
contain the code needed to generate the position of the camera at any time during the
replay. The replay itself will demonstrate a number of recorded camera paths, totalizing
a few hundred of frames. When the camera object reaches the end of this sequence, the
sequence is restarted at the beginning.
camera.computeAutoForFrame(frame);

sets the camera position in our client, but doesnt send it to SimConnect. This is done by:
camera.sendPosition();

Well see the code for the Camera class after we have completed our callback procedure
discussion. We already talked about case SIMCONNECT_RECV_ID_EVENT_FRAME,
lets see what we do for case SIMCONNECT_RECV_ID_EVENT. First we cast the
notification data structure to the appropriate one:
SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData;

and then we identify the event we are notified using switch(evt->uEventID). Well
be notified for any input event that was mapped to one of our private events. For instance,
when the user wants to increase the distance on X axis:
case EVENT_CAMERA_XP:
camera.incX();
camera.sendPosition();
printf(\nCamera X = %f, camera.getcX());
break;

When we are notified, we request the Camera object to compute the position of the
camera after adding some value to the X axis. Then we ask to send this position to
SimConnect.
If the user asks to decrease the X value, well have a similar code:
case EVENT_CAMERA_XM:
camera.decX();
camera.sendPosition();
printf(\nCamera X = %f, camera.getcX());
break;

and actually well have such code for all keys, with a corresponding method for Camera.
If the user presses the replay start / stop key, we register the current state of the replay:
case EVENT_CAMERA_AUTO_TOGGLE:
moving = !moving;
printf(\nMove = %s, moving ? Yes : No);
break;

Similarly when the user pauses or unpauses the simulation:


case EVENT_PAUSE_TOGGLE:
pause = !(evt->dwData == 0);
printf(\n%s, pause ? Paused : Unpaused);
break;

And this is it! The rest is mostly how to actually do computation of the camera position. It
has been moved to the Camera class and the two other classes it uses.

float cX, cY, cZ; cP, cH, cB;


void setPositionXYZPHB(
float x, float y, float z, float p, float h, float b);
float getcX(void); float getcY(void); float getcZ(void);
float getcP(void); float getcH(void); float getcB(void);

We delegate to the camera the task of processing users inputs and translating them into
appropriate changes to the camera position. For that we call methods associated with
requests for incrementing or decrementing values:
void
void
void
void

incX(void);
incP(void);
decX(void);
decP(void);

void
void
void
void

incY(void);
incH(void);
decY(void);
decH(void);

void
void
void
void

incZ(void);
incB(void);
decZ(void);
decB(void);

The amount that needs to be used to increment and decrement is also provided to the
camera object:
float dX, dY, dZ; float dP, dH, dB;
void setIncrementsXYZPHB(
float dx, float dy, float dz,
float dp, float dh, float db);

Replay of recorded paths is handled by a dedicated object:


PathPlayer pathPlayer;

The camera object manages this player and can tell how much frames it can deliver
before restarting to the first one:
int getAutoFrames();

Camera Class
We split our class between a header (camera.h) and a body (camera.cpp) though the
split is not emphasized in this explanation.
The camera object will have to send commands to SimConnect. We also need to store a
connection handle to SimConnect:
HANDLE hConnection;
void setConnection(HANDLE hConnection);
void sendPosition(void);

The camera object needs to store the current position of the camera:

The camera may be requested to calculate the position for any frame number in this
sequence:
void computeAutoForFrame(int frame);

The camera object is created with the default constructor Camera(void). This allows to
create it while we declare it. Later we initialize it by using setConnection(HANDLE
hConnection) which contains only:
this->hConnection = hConnection;

Some requests are directly transferred to the player:


int Camera::getAutoFrames(void) {
return pathPlayer.framesCount();

if (cP >= -90 && cP <= 90) { return; }


// correct heading if pitch not in range -90 +90
cP -= 2*(cP + (cP < 0 ? 90 : -90));
cH += 180;
cB += 180;
normalizeInRange180(&cH);
normalizeInRange180(&cB);

void Camera::computeAutoForFrame(int frame) {


pathPlayer.setPositionForFrame(
frame, &cX, &cY, &cZ, &cP, &cH, &cB);
}

Other requests are processed entirely by the camera object:


void Camera::sendPosition(void) {
SimConnect_CameraSetRelative6DOF(
hConnection, cX, cY, cZ, cP, cB, cH);
}
void Camera::incX(void) { cX += dX; }

You may remember we called this method in our callback procedure:


case EVENT_CAMERA_XP:
camera.incX();
...

Changing the angles requires an additional step to ensure the values are in the
appropriate range which is -180 +180 for heading and bank:
void Camera::decH(void) { cH -= dH; normalizeInRange180(&cH); }
void Camera::normalizeInRange180(float *angle) {
while (*angle < -180) { *angle += 360; }
while (*angle > 180) { *angle -= 360; }
}

The pitch value has to be managed differently because it has a range -90 to 90 only, and
if when incrementing / decrementing the pitch, we are suddenlty looking backward (i.e.
outside this range), we need to change the heading by 180 and get back the pitch to a
value in the -90 +90 range. To do that we have appropriate functions:
void Camera::incPitch(float delta) {
float inc;
if (cH > -90 && cH <= 90) { inc = delta; }
else { inc = -delta; }
cP += inc;
normalizePitch();
void Camera::normalizePitch() {
// first, normalize pitch to 180
normalizeInRange180(&cP);
// then get it back within -90 +90

The pitch normalization also restores a normal up-down direction by changing the bank
by 180 if the heading has been reversed.
We also use the normalization step after the camera obtains a new position from the path
player, because we allow the player to just increment the current values by some quantity,
without checking itself for staying safely in the allowed interval. The camera always takes
care of this adjustment.

Path Player and Path objects


As replaying pre-recorded sets of camera coordinates (paths) is not really related to
SimConnect, well not enter in the details of the code. You can review the PathPlayer
and RecordedPath class files for details.
The PathPlayer could easily be extended to record user defined paths. Each path is stored
in a RecordedPath object. A path is this tutorial is defined by the initial value for each
translation and rotation (X, Y, Z, pitch, bank and heading), the increment for each of these
values and the number of frames to be played. The camera location for a given frame of
the path replay (starting from 0) will be the initial location plus the frame number times
the increment (for each of the six camera parameters). For instance, we can have a path
defined this way for the X axis:
path_cX = 120; // initial value for X
path_dX = -1.0f; // increment per frame
frames = 130; // number of frames

for the first frame (frame 0), the X value would be the initial value 120. for the frame n
(between 1 and 129), X would be equal to 120 + n * -1.0f.
For the outside, the path player has two methods:
int framesCount();

bool setPositionForFrame(int frame,


float *cX, float *cY, float *cZ,
float *cP, float *cH, float *cB);

The first method returns the number of frames the player can render. In turn the
player can compute this number by asking each path object the length of its
sequence and summing the lengths. The second method allows the camera object to
request that the player updates the current position to reflect the values for a given
frame. In this case the player has to find which path this frame number belongs to,
and then ask the camera position to the related path object.

Testing our SimConnect Client


Use the files provided to build your C++ project. Ensure the new camera description
exists in the FSX camera configuration file, as explained earlier. Take off your aircraft
and when at a stable altitude, set a heading and the altitude in the autopilot, so that
you can watch what happens without having to look at the instruments and thru the
windshield.
Select your customized view, launch the client program. Ensure you select the view
first, because when launched the client will change the position of the camera. If
you have the cockpit view active, the camera will be moved, but as this is a cockpit
camera, the rendering from the outside will not be nice.
The view will show the aircraft from the left side. You can start using the keyboard to
change the camera position (without shift) or the angles (with shift). Not bad, isnt it?
The keys 8 / 2 and 4 / 6 will work as you would expect. In addition 7 / 9 will either
change the heading of the camera, or its altitude, depending if you have shift active
or not.
Start the path player with the 5 key (no shift), and see the view suddenly having
its own life, the camera moving nearby the aircraft. The nice part if the view point
changing location without transition. This is a bit like editing a movie and it can help
when creating FSX video clips.
( c ) 2009, RWY Ahead
As usual, you can do whatever you want with this tutorial and its code. Its public domain.
The code is for simulation only. Dont use it for Space Exploration without advice from Quality Assurance folks.

You might also like