• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

Custom Visibility Variables

Messages
35
Country
germany
Hello People,

I need to define custom visibility elements/variables to hide/unhide certain parts of a model. The XML element should look like:
Code:
<PartInfo>
   <Name>Custom_Visibility_Var_1_key</Name>
    <Visibility>
      <Parameter>
        <Code>
          (A:CUSTOM VAR 1, Bool) 0 &gt; if{ 1 } els{ 0 }
        </Code>
      </Parameter>
    </Visibility>
  </PartInfo>
Any idea how to define "CUSTOM VAR 1" and access it through C++ gauge?

There's a range from 0x00011000 to 0x0001FFFF in GAUGES.h reserved for custom events. I don't know if we can use this range to define custom variables to be checked inside modeldef.xml the way I wrote.
 
Last edited:
I presume a possible solution would be the usage of a local variable in modeldef.xml. Something like:
Code:
(L:GENERAL_VAR_1, number)

And since I control the visibility On C/Gauge side I could do something like that:
Code:
	ID GENERAL_VAR_1_id = check_named_variable( "GENERAL_VAR_1" );
	set_named_variable_value( GENERAL_VAR_1_id, (FLOAT64)1 );

Does that make sense?
If it does, then next dumb question would be: how do I define a local variable in modeldef.xml?
Or maybe an expression in <CODE></CODE> scope itself defines a variable???:eek: That is:
Code:
<PartInfo>
   <Name>Custom_Visibility_Var_1_key</Name>
    <Visibility>
      <Parameter>
        <Code>
          (L:GENERAL_VAR_1, number) 0 &gt; if{ 1 } els{ 0 }
        </Code>
      </Parameter>
    </Visibility>
  </PartInfo>

would simply do the job???
 
Last edited:
Hi Bill,

Sure, to name variables carefully is always a good practice no matter what language is used.

As to the execute_calculator_code function. I don't know much about the code behind this call,
but I assume the function makes progressive comparison of the first parameter (which is string) against the list
of the present expressions/variables or whatever they have there.

Let's say in my case of simply toggling the visibility it is not time critical since it doesn't happen too often,
but in general I expect set_named_variable_value must perform better since it uses the variable's ID
in order to quickly set the value through the lookup table (I guess).

So, I thought it would be optimal to retrieve all necessary IDs whenever the gauge initializes and then
refer to this variables via their IDs until the gauge is released.
But again, I can only speculate about all pros and cons of these methods.

Valery.
 
As I explain in the Wiki article, this technique makes use of a single function(); to handle all three of the data types used by XML variables: float, integer, and string.

Code:
execute_calculator_code(PCSTRINGZ code, FLOAT64* fvalue, SINT32* ivalue, PCSTRINGZ* svalue);

If you use this function in a mouse callback, then it will of course only be executed on "command," meaning that it has zero impact on performance when idle. ;)

The real "key" to using this function(); is understanding that the first parameter passed to the function is the same, precise literal XML script expression one would use in an XML gauge script...;)

Effectively, what the execute_calculator_code(); function does is cause the compiler to generate the identical .asm code as would be created by the more explicit/verbose method described in the first part of my Wiki article (using the method you've implemented).
 
Effectively, what the execute_calculator_code(); function does is cause the compiler to generate the identical .asm code as would be created by the more explicit/verbose method described in the first part of my Wiki article (using the method you've implemented).
Bill, I'm not sure I understand you right. Do you mean the function execute_calculator_code() HAS identical .asm code? Or the compiler does inject something gauge-specific apart from what we code? Although all panel handling functions declared in GAUGES.h are function pointers, I wouldn't expect the compiler to generate any additional black-box code every time I recompile my stuff...


Let's take it step-by-step:
1. In first method you've described on http://forums.flightsim.com/fswiki/i...es_in_C_Gauges
We (a) define our C variable, define the ID of an XML variable to be referenced from C code and register this XML variable,
then we (b) call set_named_variable_value() in our gauge callback in the event of PANEL_SERVICE_PRE_UPDATE. This way we get XML variable to automatically reflect the state of our C variable because PANEL_SERVICE_PRE_UPDATE comes every time the gauge is to be redrawn. Everything is clear and logical.

2. In the second method we use execute_calculator_code() with the "Expression" (As a String Parameter). The question still is what the function really does. I don't think the compiler makes something magic with the code and injects something ACES's specific which eventually performs the same way as the first method does. Correct me if I'm wrong.

One important question. If I use execute_calculator_code() method just to control the value of an L:var from C, like:
Code:
execute_calculator_code("(L:MyCustomVariable,bool)",NULL,&my_custom_variable,NULL);
Do I have to call this function every time I want to change the state of the XML variable? Or it is enough to only set corresponding C variable (my_custom_variable) afterwards and expect the XML variable to automaticvally reflect this change probably because ACES saves the variable's pointer and checks its state every time the gauge is redrawn???
I don't really think so... Because the function takes a pointer of a C variable which could point into our function's local stack. Nobody would implement that. This could only work with C variables defined in global context. So, in general, execute_calculator_code() has to be called every time I've changed the value of a C variable, or if we set XML variables without the use of C variables:
Code:
execute_calculator_code("1(>L:MyCustomVariable,bool)", NULL, NULL, NULL);


The execute_calculator_code() function clearly seems very handy since it relieves you from having to write all the code from first method, but since the function evaluates a string <CODE>expression</CODE> I would be very carefull about its usage especially in time critical domains.
I'd really like to know your opinion.
 
You're right in assuming that you do have to call execute_calculator_code() whenever you want the xml variable to be updated. (It does not set up any permanent link between the XML variable and the C pointer to update it automatically.)

As for performance trade-offs, I imagine that parsing XML at runtime would be slower than the other method. However, considering many very complicated gauges use XML exclusively, MS's parsing algorithms must be pretty efficient.

I've used execute_calculator_code() an awful lot and do not notice a perceptible performance reduction. Considering gauge code runs at a maximum of 18Hz anyway, unless your visual settings are bogging the frame rate below that, then your gauge code should have plenty of time to complete each cycle.

Si
 
Does FS parse gauge's XML code during run-time at all or it precompiles the code during gauge initialization?
 
Bill, I'm not sure I understand you right. Do you mean the function execute_calculator_code() HAS identical .asm code? Or the compiler does inject something gauge-specific apart from what we code? Although all panel handling functions declared in GAUGES.h are function pointers, I wouldn't expect the compiler to generate any additional black-box code every time I recompile my stuff...

Do I have to call this function every time I want to change the state of the XML variable? Or it is enough to only set corresponding C variable (my_custom_variable) afterwards and expect the XML variable to automaticvally reflect this change probably because ACES saves the variable's pointer and checks its state every time the gauge is redrawn???
Code:
[/QUOTE]

What I am saying is that when functions(); are expanded during compilation, the resulting code is essentially the same as it would be had you written them in "expanded form" to begin with.  After all, that [b]is[/b] one of the major points for using functions... :D

As for keeping your C variable in synch with the XML variable, it is trivial to incorporate some conditional which would only invoke the function(); when required.

[code]
if (my_custom_variable has changed) 
{
     execute_calculator_code("(L:MyCustomVariable,bool)",NULL,&my_custom_variable,NULL);
}

As a practical experiment, I've used both methods for different builds of the otherwise identical gauge code. I noticed absolutely no difference whatever in sim performance.

As far as I'm concerned, for only a handful of C<=>XML translations, there isn't that much difference in the amount of "effort involved"...

...however, if you have an entire panel full of bi-directional C<=>XML translations, using the function(); is a clear winner in terms of effort involved, not to mention the ease of debugging and maintainability. :D
 
the functions are expanded during compilation....:rolleyes:
to my knowledge the only way to expand the function is to define it as a macro or declare it inline inside the class...
...and with all due respect I see now way the declaration inside the PANELS struct:
Code:
    BOOL  (FSAPI *execute_calculator_code) (PCSTRINGZ code, FLOAT64* fvalue, SINT32* ivalue, PCSTRINGZ* svalue);
could in someway instruct the compiler to expand its code. Anyway, the function looks like a convinient way to avoid all the coding of a method (ONE),
and... it seems to be fast enough, and helps keeping the code compact and clear.

Bill, thanks a lot for the help.
 
Last edited:
Does FS parse gauge's XML code during run-time at all or it precompiles the code during gauge initialization?

Script code is parsed at runtime only, being called just either from XML or C gauges.

and execute_calculator_code is indeed a powerful function, which is linked with the script parsing functions that handles XML gauges' code.
Not only can be used to assign/retrieve aircraft(A,P)/local(L)/custom (C) variables, but also obtain a result from any simple/complex calculation (up to 256 Kb of script text), and this value returned in one of the three types (int,float,string) supported, or on each one is you pass them all at once.

Tom
 
Back
Top