5H1N0B11 / flightgear-mirage2000

GNU General Public License v3.0
20 stars 15 forks source link

HUD too heavy on fps #141

Open 5H1N0B11 opened 3 years ago

5H1N0B11 commented 3 years ago

HUD need to use Richard's method for refreshing properties : we can take inspiration from the f16.

Zaretto commented 3 years ago

The F-15 I think is the reference implementation of my three main Nasal optimisation techniques;

  1. FrameNotification
  2. props.UpdateManager
  3. PartitionProcessor

  1. FrameNotification

The FrameNotification is a notification sent out at defined intervals that contains a hash with property values.

Use the FrameNotificationAddProperty to request that certain properties are contained within the FrameNotification.

notifications.FrameNotificationAddProperty.new("F15-HUD", [HASH-Name], [property-string])

e.g. emesary.GlobalTransmitter.NotifyAll(notifications.FrameNotificationAddProperty.new("F15-HUD", "AirspeedIndicatorIndicatedMach", "instrumentation/airspeed-indicator/indicated-mach"));

although more typically used by having a hash that contains the keys and properties that you want to monitor and then using a loop to send out the FrameNotificationAddProperty; e.g.:

input = {
        AirspeedIndicatorIndicatedMach          : "instrumentation/airspeed-indicator/indicated-mach",
        Alpha                                   : "orientation/alpha-indicated-deg",
        AltimeterIndicatedAltitudeFt            : "instrumentation/altimeter/indicated-altitude-ft",
        ArmamentAgmCount                        : "sim/model/f15/systems/armament/agm/count",
        ArmamentAim120Count                     : "sim/model/f15/systems/armament/aim120/count",
        ArmamentAim7Count                       : "sim/model/f15/systems/armament/aim7/count",
        ArmamentAim9Count                       : "sim/model/f15/systems/armament/aim9/count",
        ArmamentRounds                          : "sim/model/f15/systems/gun/rounds",
        AutopilotRouteManagerActive             : "autopilot/route-manager/active",
        AutopilotRouteManagerWpDist             : "autopilot/route-manager/wp/dist",
        AutopilotRouteManagerWpEtaSeconds       : "autopilot/route-manager/wp/eta-seconds",
        CadcOwsMaximumG                         : "fdm/jsbsim/systems/cadc/ows-maximum-g",
        ControlsArmamentMasterArmSwitch         : "sim/model/f15/controls/armament/master-arm-switch",
        ControlsArmamentWeaponSelector          : "sim/model/f15/controls/armament/weapon-selector",
        ControlsGearBrakeParking                : "controls/gear/brake-parking",
        ControlsGearGearDown                    : "controls/gear/gear-down",
        ControlsHudBrightness                   : "sim/model/f15/controls/HUD/brightness",
        ControlsHudSymRej                       : "sim/model/f15/controls/HUD/sym-rej",
        ElectricsAcLeftMainBus                  : "fdm/jsbsim/systems/electrics/ac-left-main-bus",
        HudNavRangeDisplay                      : "sim/model/f15/instrumentation/hud/nav-range-display",
        HudNavRangeETA                          : "sim/model/f15/instrumentation/hud/nav-range-eta",
        OrientationHeadingDeg                   : "orientation/heading-deg",
        OrientationPitchDeg                     : "orientation/pitch-deg",
        OrientationRollDeg                      : "orientation/roll-deg",
        OrientationSideSlipDeg                  : "orientation/side-slip-deg",
        RadarActiveTargetAvailable              : "sim/model/f15/instrumentation/radar-awg-9/active-target-available",
        RadarActiveTargetCallsign               : "sim/model/f15/instrumentation/radar-awg-9/active-target-callsign",
        RadarActiveTargetClosure                : "sim/model/f15/instrumentation/radar-awg-9/active-target-closure",
        RadarActiveTargetDisplay                : "sim/model/f15/instrumentation/radar-awg-9/active-target-display",
        RadarActiveTargetRange                  : "sim/model/f15/instrumentation/radar-awg-9/active-target-range",
        RadarActiveTargetType                   : "sim/model/f15/instrumentation/radar-awg-9/active-target-type",
        InstrumentedG                           : "instrumentation/g-meter/instrumented-g",
        VelocitiesAirspeedKt                    : "velocities/airspeed-kt",
};
foreach (var name; keys(input)) {
    emesary.GlobalTransmitter.NotifyAll(notifications.FrameNotificationAddProperty.new("F15-HUD", name, input[name]));
}

The idea of the FrameNotification is that it provides an easy way to run your update logic; simply by registering with the GlobalTransmitter and then processing the FrameNotification you can call your update logic in an efficient manner;

e.g.

var HUDRecipient =
{
    new: func(_ident)
    {
        var new_class = emesary.Recipient.new(_ident);
        new_class.MainHUD = nil;
        new_class.Receive = func(notification)
        {
            if (notification.NotificationType == "FrameNotification")
            {
                if (new_class.MainHUD == nil)
                  new_class.MainHUD = F15HUD.new("Nasal/HUD/HUD.svg", "HUDImage1");
                if (!math.mod(notifications.frameNotification.FrameCount,2)){
                    new_class.MainHUD.update(notification);
                }
                return emesary.Transmitter.ReceiptStatus_OK;
            }
            return emesary.Transmitter.ReceiptStatus_NotProcessed;
        };
        return new_class;
    },
};

and then register that function with the Emesary Global transmitter.

emesary.GlobalTransmitter.Register(HUDRecipient.new("F15-HUD"));


  1. props.UpdateManager

This will monitor one or more property, or values from a hash and call a function (or inline function) when the value or a value changes more than a defined amount.

e.g.

       obj.update_items = [
            props.UpdateManager.FromHashList(["ElectricsAcLeftMainBus","ControlsHudBrightness"] , 0.01, func(val)
                                      {
                                          if (val.ElectricsAcLeftMainBus <= 0 
                                              or val.ControlsHudBrightness <= 0) {
                                              obj.svg.setVisible(0);
                                          } else {
                                              obj.svg.setVisible(1);
                                          }
                                      }),
            props.UpdateManager.FromHashValue("AltimeterIndicatedAltitudeFt", 1, func(val)
                                             {
                                                 obj.alt_range.setTranslation(0, val * alt_range_factor);
                                             }),

            props.UpdateManager.FromHashValue("VelocitiesAirspeedKt", 0.1, func(val)
                                      {
                                          obj.ias_range.setTranslation(0, val * ias_range_factor);
                                      }),
            props.UpdateManager.FromHashValue("ControlsHudSymRej", 0.1, func(val)
                                             {
                                                 obj.symbol_reject = val;
                                             }),
...

and then in the update method

       foreach(var update_item; me.update_items)
        {
            update_item.update(notification);
        }

As you can see above the update method is called from the recipient of the frame notification.


  1. PartitionProcessor

When working with lists (arrays) of data that can get quite long (e.g. targets from radar) the partition processor is an easy way to only process a part of that list each frame.

What it does is to manage the processing of data in a manner suitable for real time operations. Given a data array [0..size] this will process a number of array elements each time it is called This allows for a simple way to split up intensive processing across multiple frames.

The limit is the number of elements to process per frame (invocation of .process method) or to limit the processing to a specified amount of time using a Nasal timestamp to measure the amount (in usec)

example usage (object);

var VSD_Device =
{
    new : func(designation, model_element, target_module_id, root_node)
    {
...
       obj.process_targets = PartitionProcessor.new("VSD-targets", 20, nil);
       obj.process_targets.set_max_time_usec(500);
...
     me.process_targets.set_timestamp(notification.Timestamp);

then invoke.

     me.process_targets.process(me, awg_9.tgts_list, 
                                func(pp, obj, data){
                                    initialisation; called before processing element[0]
                                    params
                                     pp is the partition processor that called this
                                     obj is the reference object (first argument in the .process)
                                     data is the entire data array.
                                }
                                ,
                                func(pp, obj, element){
                                    proces individual element; 
                                    params
                                     pp is the partition processor that called this
                                     obj is the reference object (first argument in the .process)
                                     element is the element data[pp.data_index]
                                    return 0 to stop processing any more elements and call the completed method
                                    return 1 to continue processing.
                                },
                                func(pp, obj, data)
                                {
                                    completed; called after the last element processed
                                    params
                                     pp is the partition processor that called this
                                     obj is the reference object (first argument in the .process)
                                     data is the entire data array.
                                });
5H1N0B11 commented 3 years ago

Awesome. Thanks. I will work on it.