Archived

This topic is now archived and is closed to further replies.

WarpD

Gauge with Bitmaps

Recommended Posts

Hi,I am programming a gauge that makes heavy use of bitmaps with rotation. GDI+ seems very slow for bitmap processing. Is there a better library to use for bitmap calculations?

Share this post


Link to post
Share on other sites
Help AVSIM continue to serve you!
Please donate today!

>Hi,>>I am programming a gauge that makes heavy use of bitmaps with>rotation. Programming in what langauge with what API?>GDI+ seems very slow for bitmap processing. Is there>a better library to use for bitmap calculations?Slow relative to what?What are you trying to do? Why are you not just using the standard methods using the gauge macros provided in the gauges.h?

Share this post


Link to post
Share on other sites

I use C++ currently with GDI+And I'd like to rotate bitmaps as fast as possible. GDI+ is just slow compared to what I think would be fast :DThe gauges macros are not flexible enough.

Share this post


Link to post
Share on other sites

>I use C++ currently with GDI+>>And I'd like to rotate bitmaps as fast as possible. GDI+ is>just slow compared to what I think would be fast :DWhat exactly are you rotating/doing?>The gauges macros are not flexible enough.Are you sure? I have not run across a single case yet where they could not be used. If you are rotating only use MAKE_NEEDLE, but if you are needing to both rotate and translate then you'll need to use MAKE_MOVING. If ACES can do it, so can you. ;)You could also look into use AGG (http://antigrain.com) which is what ACES used (in part) for the terrain. Without more details, it is really hard to say. You might want to look at Boost (Google it).

Share this post


Link to post
Share on other sites

>>What exactly are you rotating/doing?>GDI+ bitmap rotation can indeed be rather slow.>>You could also look into use AGG (http://antigrain.com) which>is what ACES used (in part) for the terrain. >Where did you get the information they used AGG? Also, the current version of AGG is no longer suitable for commercial use to do licensing restrictions.

Share this post


Link to post
Share on other sites

Hi,I have been using the default FSX MACROS but also want to get away from those. One of the biggest problems I see it that the needles, movings, sliders etc... are only updated now and again. The PRE_DRAW event in the main gauge callback, doesn't happen each tick (as you would expect) but only every 4-5 ticks at best and even only every 20 ticks at worst. This is probably due to some resource optimizing done by FSX but in my case this means that almost none of the needles are moving smoothly but rather in discrete steps, which of course has a major negative impact on the realism effect.I've done tests on the speed gauge for instance, the needle callback is called every tick and I see the return value increasing in very small decimal increments. The PRE_DRAW event in the main gauge callback however is only called every so often and by then the AIRSPEED value has increased in steps of around 1 knots (not exactly 1 knot btw). I thought that maybe the needle element only takes the integer part of return value or the gauge would only update when it considers the changes to be "significant" so as a test I multiplied the airspeed by 10 and off course updated the non-linearity table likewise. That didn't have any effect ! In stead of incrementing in 1 knot steps the needle was now updated in around 10 unit steps.Another test that I did was to reduce the number of elements inside a gauge. For that I tested my RMI gauge. I removed all the elements but for the static and 1 needle ==> no effect whatsover, still get the same lousy update rates...So to put your results into perspective, the actual update rates for some of the gauges using standard MACROS is approx 5-1x per second. Not sure what you get using GDI+ but I can't imagine it being that bad !

Share this post


Link to post
Share on other sites

>Hi,>>I have been using the default FSX MACROS but also want to get>away from those. One of the biggest problems I see it that the>needles, movings, sliders etc... are only updated now and>again. The PRE_DRAW event in the main gauge callback, doesn't>happen each tick (as you would expect) but only every 4-5>ticks at best and even only every 20 ticks at worst. This is>probably due to some resource optimizing done by FSX but in my>case this means that almost none of the needles are moving>smoothly but rather in discrete steps, which of course has a>major negative impact on the realism effect.Which is why the PRE_DRAW event is not used in the way you are attempting. If you choose to attempt to program in C++, your gauges performance is going to be GREATLY affected by your skill and knowledge in how to code it "correctly". You will note other C gauges on your system do not have this problem, and this is why.>I've done tests on the speed gauge for instance, the needle>callback is called every tick and I see the return value>increasing in very small decimal increments. The PRE_DRAW>event in the main gauge callback however is only called every>so often and by then the AIRSPEED value has increased in steps>of around 1 knots (not exactly 1 knot btw). I thought that>maybe the needle element only takes the integer part of return>value or the gauge would only update when it considers the>changes to be "significant" so as a test I multiplied the>airspeed by 10 and off course updated the non-linearity table>likewise. That didn't have any effect ! In stead of>incrementing in 1 knot steps the needle was now updated in>around 10 unit steps.Yeap, it doesn't work that way.>Another test that I did was to reduce the number of elements>inside a gauge. For that I tested my RMI gauge. I removed all>the elements but for the static and 1 needle ==> no effect>whatsover, still get the same lousy update rates...Again, this is because the lousy update rate is due to how you are programming, not the SDK's fault.>So to put your results into perspective, the actual update>rates for some of the gauges using standard MACROS is approx>5-1x per second. Not sure what you get using GDI+ but I can't>imagine it being that bad !Well, not sure how you are doing things, but if you are getting only 1-5 updates per second (and not intending to do so) then you are doing things wrong. :DIf anything, I have to go back and slow gauges down that do not need to be updated so many times per second. You might want to consider asking what others are doing to accomplish whatever you are trying to do in the gauge callback.Patrick

Share this post


Link to post
Share on other sites

Patrick,"Which is why the PRE_DRAW event is not used in the way you are attempting. If you choose to attempt to program in C++, your gauges performance is going to be GREATLY affected by your skill and knowledge in how to code it "correctly". You will note other C gauges on your system do not have this problem, and this is why."You speak in riddles, what do you mean by this ? Here's a for instance, I have a NEEDLE macro that uses the AIRSPEED variable as input. The NEEDLE callback simply reads:if ( rvalue < 60 ) rvalue = 60;if ( rvalue > 450) rvalue = 450;return rvalue;That's it... nothing in the PRE_DRAW callback or anything. I've also tried:MODULE_VAR_NONE in the NEEDLE MACRO and then rvalue = AIRSPEED.var_value.n ;if ( rvalue < 60 ) rvalue = 60;if ( rvalue > 450) rvalue = 450;return rvalue;Same thing happens, the NEEDLE CALLBACK is called every tick, PRE_DRAW skips a few ticks.How would you code this ? You are right, I am probably doing something wrong, but I can't find what it could be. Kind regards,Bj

Share this post


Link to post
Share on other sites

Patrick,I may have missed your point but are you saying the problem is related to using C++ vs C or a mixture of both ?Bj

Share this post


Link to post
Share on other sites

What are you computer specs? What FPS are you getting with your current display settings?Try PRE_UPDATE instead of PRE_DRAW.Are you using C++ (.cpp vs. .c)? Which compiler are you using? Let's see your entire MAKE_NEEDLE callback function. Is this for FSX?To help you we need more info, that is why it seems like riddles.

Share this post


Link to post
Share on other sites

No, but if you are coding for FSX you should be using C++ entirely now.

Share this post


Link to post
Share on other sites

Patrick,- The "problem" has been seen by various users with all kinds of specs so it is not PC related. I get 15-20fps on the ground in the 2D panel view- I am not using PRE_DRAW nor any other event in the main gauge callback, so I'm not entirely sure why switching to another event would change anything and what would need to be switched...- I am using mixed cpp and c files since this panel was originally developed for FS2004 and is now used in FSX (after lots and lots and lots of changes though). The main gauge file (its a multigauge setup with approx 97 subgauges inside) is a cpp file. I think (but I don't have access to my PC now so I'm not 100% certain) this particular airspeed gauge file is a .c file. Will change the file extension just in case.- I am using VC2005- Will need to get to my PC for the complete callback functionI have browsed through the SDK again and noticed that in many samples no main gauge callback is used at all. Maybe that has something to do with it ?Will do some tials this evening (time permitting) and let you know the results.Bj

Share this post


Link to post
Share on other sites

Patrick,Here is some code for the airspeed gauge...Needle callback:FLOAT64 FSAPI CBAirspeed( PELEMENT_NEEDLE pelement){lookup_var(&AIRSPEEDvar);float rvalue=AIRSPEEDvar.var_value.n;if ( rvalue < 60 ) { rvalue = 60 ; } if ( rvalue > 450 ) { rvalue = 450 ; } if ( lights_on == 1 ) { LIGHT_IMAGE(pelement) ; } else { DARKEN_IMAGE(pelement) ; } return rvalue;}This is the needle MAKROMAKE_NEEDLE(NeedleASI,RecourceASNeedle,&ElementList6ASI,fail1ASI,IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT7,0,149,149,12,12,MODULE_VAR_NONE,CBAirspeed,NonlinASI,0)I have now changed the file extension to .cpp and I have removed the main gauge callback. I also tried adding the AIRSPEED var to the NEEDLE macro. But this all has no effect whatsoever on the smoothness of the gauge. One of the strange things is that the AIRSPEED value itself doesn't change continuously but rather in descrete steps.I don't see anything wrong with this code so if you can make this needle move smoother, please let me know !Bj

Share this post


Link to post
Share on other sites

Bjorn, (hey, how do I do the cool o thingy?)>Needle callback:>>FLOAT64 FSAPI CBAirspeed( PELEMENT_NEEDLE pelement)>{>lookup_var(&AIRSPEEDvar);>>float rvalue=AIRSPEEDvar.var_value.n;>>if ( rvalue < 60 ) { rvalue = 60 ; } >if ( rvalue > 450 ) { rvalue = 450 ; } >if ( lights_on == 1 ) { LIGHT_IMAGE(pelement) ; } else {>DARKEN_IMAGE(pelement) ; } >>return rvalue;}Ok, you have a few problems with the above code. First, you should not have the lookup_var() in the callback. Why? Because, instead of MODULE_VAR_NONE in the MAKE_NEEDLE macro below, you should have AIRSPEED. The MODULE_VAR is then sent as the pelement to the callback, making it available for you to modify, which is the point of the callback function. Next, your way of coding the test conditions with an extra local variable makes it hard to see what the code is doing. Also, you are forcing a lot of automatic conversions in the above code which slow things down even more.This is the way to make it clear:FLOAT64 FSAPI AirspeedNeedle_cb(PELEMENT_NEEDLE pelement){ static short maxIAS = 150; if (pelement->source_var.var_value.n > maxIAS) { return maxIAS; } else if(pelement->source_var.var_value.n < 15) { return 15; } return pelement->source_var.var_value.n;}Note the difference between the top if() and the bottom. The top makes it clear that you are checking to see if the airspeed is greater than the maxIAS the indicator can display. The bottom does not make it clear that the "magic" number 15 is the minIAS the indicator can display, and so will be harder to maintain later when you have forgotten what you were doing. Do it the first way. As an exercise you can convert this code to the "proper" way. Read "Code Complete" for more tips like this.Also, note that the above uses the variable directly which is faster than creating an rvalue which then also requires another conversion.>This is the needle MAKRO>>MAKE_NEEDLE(NeedleASI,RecourceASNeedle,&ElementList6ASI,fail1ASI,>IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT7,>0,149,149,12,12,MODULE_VAR_NONE,CBAirspeed,NonlinASI,0)As stated above, MODULE_VAR_NONE should only be used when there is no FS var for what you are after, or you really want to ignore it. In your case it should be AIRSPEED. Also, you don't need the BIT7, and the final 0 could really be like 6, but zero is fine.Generally, you should code MACROs to look like this:#pragma region AIRSPEEDMAKE_NEEDLE( airspeedNeedle, BMP_NEEDLE_AIRSPEED, NULL, airspeed_fail, IMAGE_USE_TRANSPARENCY | IMAGE_USE_ERASE | IMAGE_USE_LUMINOUS, 0, 128, 128, // Needle center on BG 41, 10, // Center position on Needle AIRSPEED, AirspeedNeedle_cb, airspeed_nonLinearity, 6)PELEMENT_HEADER airspeedNeedle_list[] = { &airspeedNeedle.header, NULL };#pragma endregion /*Needle*/>I have now changed the file extension to .cpp and I have>removed the main gauge callback. I also tried adding the>AIRSPEED var to the NEEDLE macro. But this all has no effect>whatsoever on the smoothness of the gauge. One of the strange>things is that the AIRSPEED value itself doesn't change>continuously but rather in descrete steps.Also, if you really do need to use a lookup_var(), I would put that code in PRE_UPDATE, to ensure it gets updated each tick.>I don't see anything wrong with this code so if you can make>this needle move smoother, please let me know !That's why when you ask a question, it is best to post code. =)Glad I could help you.Patrick

Share this post


Link to post
Share on other sites

Hi Patrick,I had in fact used AIRSPEED in the MACRO but I was hoping the doing an explicit lookup_var() would force a new value. Anyway, I tried all the suggestions that you made but they absolutely no effect whatsoever.When I follow the AIRSPEED variable in the debugger it increments in distinct steps and not continuously with each tick or call to the NEEDLE callback. If its any comfort, I just checked and the airspeed needle in the default C172 in FSX also moves in steps and not smoothly.Bj

Share this post


Link to post
Share on other sites

Well, of course, it moves in steps. It is a discontinuous simulation of a continous variable. Well, actually, according to quantum mechanics everything is discontinuous! =)Anyway, the code I gave you works, and I'm not sure what you are thinking is wrong. Perhaps you have a problem in your non-linearity table. =)Good luck.

Share this post


Link to post
Share on other sites

Just a small note... regarding the last value in the MAKE_NEEDLE macro... it should not always be a value other than 0. Here's why, it's definition:"Determines the refresh rate for the macro. Gauges are refreshed 18 times per second, so a value of 0 means update every cycle; a value of 6 means update every third of a second. You trade off gauge display quality versus frame rate

Share this post


Link to post
Share on other sites

Great in theory, but in fact, it works perfectly fine and the needle moves smoothly and accurately. There is no need to update stuff at 18 Hz. In fact, you will get better performance from a panel that has maintained control of how fast things update vs. trying to let them all update at 18 Hz. :DOne always has to rememeber the difference between statistical and clinical effectiveness. :D

Share this post


Link to post
Share on other sites

>As stated above, MODULE_VAR_NONE should only be used when>there is no FS var for what you are after, or you really want>to ignore it. In your case it should be AIRSPEED. Also, you>don't need the BIT7, and the final 0 could really be like 6,>but zero is fine.Patrick, do you even know what the "BIT7 IMAGE_FLAG" is used for?If you don't I won't be surprised since it's not documented in the SDK...However, from Dai's excellent tutorial:"In addition there is one undocumented flag and another use for one of the documented ones. Each of them are in the gauges.h file but neither has an explanation anywhere."BIT7: Using this flag anti-aliases needles and sprites i.e it smooths the edges of the bitmaps.The #define is for IMAGE_BILINEAR_COLOR which provides a clue......the new flag name replaces the old one, IMAGE_ANTI_ALIAS which is certainly more descriptive! ;)Here is a comparison showing what happens when BIT7 image flag is omitted:http://forums.avsim.net/user_files/184586.jpgBTW, the other "undocumented image flag" is BIT15, but you can read Dia's tutorial if you want further details on when/how it may be used to good advantage... ;)

Share this post


Link to post
Share on other sites

>Great in theory, but in fact, it works perfectly fine and the>needle moves smoothly and accurately. There is no need to>update stuff at 18 Hz. In fact, you will get better>performance from a panel that has maintained control of how>fast things update vs. trying to let them all update at 18 Hz.> :D>>One always has to rememeber the difference between statistical>and clinical effectiveness. :D>>>Well, I don't want my ILS needles updating 1 or 2 times per second. The granularity of such a display would make tracking the ILS at jet speeds extremely difficult.Like I said... primary instrument needles need to be updated as often as it can be done.

Share this post


Link to post
Share on other sites

Yes, but if you start with good artwork, then you don't need to make the computer do extra work. :)I guess if you have a really kick-a** computer, but then I like using every available frame for flight.

Share this post


Link to post
Share on other sites

I agree with you Ed but... when I look at the actual number of times for instance the AIRSPEED value is updated in FSX then you don't get anywhere near 18x/second. But rather close to 4-5 imes per second at best. My LLZ and GS needles don't move smooth at all but rather in steps which makes them very unrealistic.Then there is another problem apparently, I get the impression that needles, sliders and in fact all MACRO elements seem to have a rather crude resolution. What I'm mean is that a needle will only turn once a minimum delta angle is reached. For a GA aircraft that flies at low speed and where the whole dial may only cover 160 knots this will not be that visible (although it is visible once you start looking at it). But for jet aircraft with their non-linear speed dials for instance, once you fly at say 280-290 knots the needle will only move every extra 1 knot in speed change or even in larger steps.It tried something very simple, in stead of sending the AIRSPEED to my ASI needle, I just send a float value that is increasing by 0.2 every tick. When you look at the needle though you will notice a complete lack of smoothness ! In stead of elegantly moving over the ASI dial the needle will still move in discreet and visible steps !Maybe you guys don't have this problem and if so, then I would be really intersted to know why that is, but I see it in all but a few panels. So somebody must have figured out how to avoid this, I certainly haven't...Bj

Share this post


Link to post
Share on other sites

I thought about this more, and I think I'm not seeing it for a couple reasons. a) I fly low and slow, esp. in helos. :( I only get 15 fps anyway c) I use the smoothing provided by the degrees per sec parameter.As far as I know, the ultra smooth gauges you see are indeed not done with the macros, but I just have never run into that limitation and have always stayed within the SDK whenever possible.I have also done GDI+, but found that it was overkill in most cases. Was useful for a CDU, and things like that, but for standard instruments I use the macros.If you aren't getting the higher resolution of data from FS, having an ultra accurate gauge won't help, which is why it is easier to use the MS approach and "fake" it. =)Yes, for an ILS I'd go for 18 Hz too. =)Just my two cents.Patrick

Share this post


Link to post
Share on other sites

>Patrick,>>What do you mean by the "degrees per second parameter" ?>>Bj

Share this post


Link to post
Share on other sites