Sign in to follow this  
n4gix

Owner drawn gauge help

Recommended Posts

Hi,I have an owner drawn gauge that consists of a static lib containing the instrument logic (C++), a C wrapper, and a DLL project that builds the gauge. The gauge has a digital screen that is green and part of the background bitmap. I'm trying to load a gauge background from a bitmap using MAKE_STATIC and pass the DC into my C++ object to render the contents of the gauge 'screen', effectively writing black pixels on top of the green background of the gauge bitmap. I have used the Flightmap example from the SDK and gotten only so far, but I don't see the data that I'm writing to the element dc. I write to the dc prior to passing it off to SET_OFF_SCREEN(). I intentionally isolated the gauge logic to a lib so that I could build a win32 test harness for it. The win32 app works fine and I'm kinda confused. Does anyone have an example that might help?Thanks!

Share this post


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

check that you have set IMAGE_CREATE_DIBSECTION flag and no IMAGE_USE_TRANSPARENCY flag

Share this post


Link to post
Share on other sites

Thanks for the reply. I was using IMAGE_USE_TRANSPARENCY, and I changed this to IMAGE_CREATE_DIBSECTION for my background static. Now, FS is dumping to desktop when I start a flight. I'm not sure if the change cause this or not, I've edited a panel in Panel Studio and seen it change FS behavior from won't start to starts fine.:(

Share this post


Link to post
Share on other sites

There's a very good chance it is your gauge causing the crash :-)I would make sure that you are getting the DC for the correct element in your gauge. If you have a debugger it should be easy to find out where the problem is.

Share this post


Link to post
Share on other sites

Oh, I'm positive it's my gauge :) I just can't seem to attach to the fs9 process or the tmpxxxx process that seems to be a child. I've tried starting fs9.exe as the debug executable for my gauge dll, but it complains that the debugger is running and exits (fs9 does).How do you launch or attach to fs9 to debug your gauge? I'm using VS.NET2003 Enterprise.Thanks!

Share this post


Link to post
Share on other sites

The protection used to detect a debugger is the same used to look for CD number 4. Find yourself a no cd crack and then you will be able to debug using fs9.exe as the debug executable.

Share this post


Link to post
Share on other sites

I finally found a no CD crack for fs9.exe, but I have a problem debugging the gauge. I can set a breakpoint in the gauge during initialization when FS is loading and this stops fine. Unfortunately, this is not where I need to break. If I try to stop in the gauge code during rendering, etc, FS hangs as if it hit a BP, but I can't get the IDE to draw and I've forced to kill one of the processes. I'm guessing this is related to direct x and the fact that the app is full screen, but I'm not sure. Any ideas?

Share this post


Link to post
Share on other sites

Hi,I'm no expert, but try windowed mode??Could you get it to dump to a file the info that you need, like a trace log?Best regards,Vulcan.

Share this post


Link to post
Share on other sites

I did try that to no avail, but found a mutex to be at fault after all. This doesn't solve my gauge problem, but I did find myself able to debug it finally. It looks like it might be related to DLL relocation as I have an object allocated behind the scenes and a thread that calls it on a regular basis. The thread was created when the object was initialized and the data passed was the object's 'this pointer'. Every so often, the thread wakes up and calls (typecast)this->threadfunc(). Problem is, once I start a flight, a call to threadfunc() reveals an invalid instance pointer and all instance data is invalid. The address of the allocated block for the instance is correct and a destructor for the object was never called, so I'm assuming that the object's base address changed and the thread didn't know about it.The reason I did this was that I have no idea how often FS will call me for 'processing'. The gauge I'm writing needs to update its state in a time-sensitive manner, so a thread seemed like a good idea since the only call I know will come is a PRE_DRAW and I don't know how often that's called or if the interval is predictable.It's been a while since I ran into a DLL issue (like allocation/deletion of c++ objects from in/out side the library, etc), so I'll have to think on this one. Any insight on how I might handle time-sensitive processing in my gauge would be appreciated.Thanks for all the advice!

Share this post


Link to post
Share on other sites

PRE_DRAW is called once each FS frame, but only when the gauge is actually being drawn on the screen. PRE_UPDATE is called at a fixed rate of 18Hz, regardless of whether the gauge is visible or not.Doug

Share this post


Link to post
Share on other sites

I've ditched the threaded approach and handled my processing using PRE_UPDATE. I'm having problems drawing on my dc and having it show up. I load the DC from my STATIC image and draw directly on it like this: pBackground = (PELEMENT_STATIC_IMAGE)(pgauge->elements_list[0]->next_element[0]); if(pBackground) { HDC hdc = pBackground->hdc; drawsomething(hdc); SET_OFF_SCREEN(pBackground); }Just the background bitmap shows up, nothing that I've drawn over it.Does someone have a simple example of an owner drawn control that provides a background bitmap and draws on top of it using basic GDI?Thanks for all the help!

Share this post


Link to post
Share on other sites

I've made progress on this gauge, but I'm still having problems coming up with a workable solution for drawing on a static bitmap. Here's what I'm doing currently: I create two static images, one is a bezel for the gauge and the other is a bogus background that is empty:MAKE_STATIC( bezel, IDB_BEZEL, NULL, NULL, IMAGE_USE_TRANSPARENCY, 0, 0,0)PELEMENT_HEADER static_elements[] = { &bezel.header, NULL };MAKE_STATIC ( blankscreen, IDB_BLANK, static_elements, NULL, IMAGE_CREATE_DIBSECTION, 0, 0,0 )PELEMENT_HEADER render_list = &blankscreen.header;The first MAKE_STATIC is the gauge bezel and has a transparent center where the digital screen will go. It's like a picture frame. This draws correctly (transparent in the middle) if I use only one static image and just draw it by itself on the panel. In my callback, I do this: case PANEL_SERVICE_PRE_UPDATE: if(++updateCount > 17) { gauge_process(); updateCount = 0; bezel = (PELEMENT_STATIC_IMAGE) (pgauge->elements_list[0]->next_element[0]); screen = (PELEMENT_STATIC_IMAGE) (pgauge->elements_list[0]); if(bezel&&screen) { HDC hdc = screen->hdc; PIXPOINT dim = bezel->image_data.final->dim; int result = gauge_draw(hdc, dim.x, dim.y); SHOW_IMAGE(screen); SET_OFF_SCREEN(bezel); } } break;I need the gauge to redraw itself once per second. In case it's not obvious, I'm trying to always overlay the static bezel on top of the blank image. I'm trying to first draw on the blank STATIC using my gauge. Inside the gauge_draw() function, I'm creating a DC compatible to the hdc arg, loading a bitmap resource that's linked to the DLL and selecting it into the new DC. This image represents the digital screen. I then draw 'pixels' on the screen and, finally, StretchBlt it to the DC passed to the function using the x and y dims, intending to overwrite the MAKE_STATIC blank image with an image that consists of a bitmap that's drawn on.What shows up in FS is the screen image, then one that apparently drew on, looking the same as the original image loaded in MAKE_STATIC, as if the StretchBlt() failed, although it didn't.Sorry to be long winded, but I'm losing hope here. Any help is appreciated. Am I going about this the wrong way?Thanks

Share this post


Link to post
Share on other sites

"Sorry to be long winded, but I'm losing hope here. Any helpis appreciated. Am I going about this the wrong way?"Since it doesn't work, apparently so... ;)You can draw directly ON a bitmap, and don't really need a transparent background. Also, if you wish to overlay a final "frame" as the last draw element, it is much simpler to use the MAKE_SLIDER macro rather than another MAKE_STATIC element, although it is possible that way as well.Here's the way I draw the elements in such a gauge:////////////////////////////////////////Used to mask drawing when power OFF!MAKE_SLIDER(vision_Slider3,BMP_VT_BG,NULL,NULL,IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT7,0,0,0,MODULE_VAR_NONE,vision_callback3,0,MODULE_VAR_NONE,vision_callbackS3,0)PELEMENT_HEADER vision_ElementList2[] = {&vision_Slider3.header,NULL};//Bezel only; transparent center, allows drawing surface to be seen!MAKE_SLIDER(vision_Slider2,BMP_VT_COVER,&vision_ElementList2,NULL,IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT7,0,0,0,MODULE_VAR_NONE,vision_callback2,0,MODULE_VAR_NONE,vision_callbackS2,0)PELEMENT_HEADER vision_ElementList3[] = {&vision_Slider2.header,NULL};MAKE_STATIC( vision_image, BMP_VT_LM, //GDI+ drawing surface &vision_ElementList3, NULL, IMAGE_USE_ERASE|IMAGE_USE_BRIGHT|IMAGE_CREATE_DIBSECTION, 0, MAP_LEFT_BORDER,MAP_TOP_BORDER)PELEMENT_HEADER vision_next[] = { &vision_image.header, NULL };MAKE_STATIC( vision_background, BMP_VT_BG, //background image vision_next, NULL, IMAGE_USE_TRANSPARENCY, 0, 0,0)PELEMENT_HEADER vision_list = &vision_background.header;//////////////////////////////////////In my case PANEL_SERVICE_PRE_DRAW: section, I use a copy of the drawing surface to 'erase' the previous cycle's drawing, and prepare the surface for a fresh draw: Image image(L"AircraftMy Secret Aircrafttexturevision.bmp"); Rect destinationRect(0, 0, 600 * dx, 590 * dy); graphics.DrawImage(ℑ,destinationRect,0, 0, 600, 590, UnitPixel);Background Image / Gauge "OFF" coverhttp://img336.imageshack.us/img336/6015/vision9hr.th.pngDrawing Surface (DIBSECTION)visionlightmask3lc.th.png"Frame/Bezel with transparent screen"visioncover4km.th.pngThe final product...http://img495.imageshack.us/img495/5229/li...ontech011uv.jpg

Share this post


Link to post
Share on other sites

Do you use SET_OFF_SCREEN() or SHOW_IMAGE() when you finish drawing? What's the difference?Also, I've tried using PRE_DRAW, but it seemed like there were times where this wasn't being called very often, so I started using PRE_UPDATE and counting 1/18ths of second. Should PANEL_SERVICE_PRE_DRAW be sent to your callback on a regular basis (ie: meaning should you expect it constantly, not necessarily at a particular interval)Thanks

Share this post


Link to post
Share on other sites

I use SET_OFF_SCREEN as that is the way I was taught... ;) The way I understand it, this will force the gauge to redraw if the gauge is resized (i.e., undocked and enlarged, moved, or shrunk). /* Define the Small Arrow structure */ Point AMPS_1(-10 * dx, 8 * dy); Point AMPS_2(-9 * dx, 9 * dy); Point AMPS_3(-19 * dx, 24 * dy); Point AMPS_4(-24 * dx, 24 * dy); Point AMPS_5(-24 * dx, 19 * dy); Point AMPS_blade[6] = {AMPS_1, AMPS_2, AMPS_3, AMPS_4, AMPS_5, AMPS_1}; graphics.FillPolygon(&blackBrush, AMPS_blade, 6); graphics.ResetTransform(); } PointF pointLA(467*dx, 418*dy); graphics.DrawString(load_amps_wch, -1, &SmallNumbers, pointLA, &blackBrush); } //end gauge_draw else clause } SET_OFF_SCREEN (pelement); } } break;As Doug wrote previously, PANEL_SERVICE_PREDRAW is called once each frame, which means that it is updated according to the frame rate. PANEL_SERVICE_PREUPDATE is performed 18 times per second, which means that the gauge is being drawn even if the result is 'discarded.'My own experience has been that using PREDRAW results in less of a 'performance hit' on the sim... YMMV, or course... ;)

Share this post


Link to post
Share on other sites

I guess the only thing that I can't deduce from your example is the content of your STATIC images. I'm assuming that the BMP_VT_LM image is similar to the background image and that you are drawing on it.I don't suppose it's possible to draw an image with transparency, is it? I've tried drawing on a STATIC that's USE_TRANSPARENCY, but the DC is invalid. I've also |'ed USE_DIBSECTION and gotten a valid dc from the static, but when it's drawn, it's just the original image without any dynamic content, although I'm sure I wrote successfully to the DC. Makes me think that USE_TRANSPARENT images are reloaded before they are rendered or something like that.Another issue I have when drawing on a USE_DIBSECTION STATIC is that the contents of the previous rendering are not lost between frames/changes, so what I draw is never 'erased' if you will. I can Blt stuff to it fine, but it stays throughout the life of the gauge.The short of it is that it would make things a lot easier if I could use a drawing surface with transparency. I'm expecting this is impossible.Thanks for all the input.

Share this post


Link to post
Share on other sites

>I guess the only thing that I can't deduce from your example>is the content of your STATIC images. I'm assuming that the>BMP_VT_LM image is similar to the background image and that>you are drawing on it.What is unclear? I posted a picture of BMP_VT_LM image? (Hint: it's the second picture!) ;)>I don't suppose it's possible to draw an image with>transparency, is it?I know that some few people have advanced the claim that it's possible, but AFAIK no one has shared their procedure... >Another issue I have when drawing on a USE_DIBSECTION STATIC>is that the contents of the previous rendering are not lost>between frames/changes, so what I draw is never 'erased' if>you will. I can Blt stuff to it fine, but it stays throughout>the life of the gauge.I've already provided this example, but here it is again:Image image(L"AircraftEaglesoft Liberty XL2texturevision.bmp");Rect destinationRect(0, 0, 600 * dx, 590 * dy);graphics.DrawImage(ℑ,destinationRect,0, 0, 600, 590, UnitPixel);The image loaded/painted is a copy of the BMP_VT_LM bitmap that is placed in the aircraft's texture folder. This routine is performed every drawing cycle before any other gauge drawing occurs. The purpose of course is to 'erase the slate' and provide a clean drawing surface... ;)If you are drawing on a blank "LCD screen display," then the clearing routine is much simpler:Color Black(0,0,0);graphics.Clear(Black);Simply substitute whatever color you desire instead of Black(0,0,0)...

Share this post


Link to post
Share on other sites

>>I don't suppose it's possible to draw an image with>>transparency, is it?Yes, and it's not hard with GDI+.You basically adjust the alpha of an ARGB color. 255 is opaque, and 0 is fully transparent. howBrt = 2.55 * brtness; StaticObj::brushTxtGold.SetColor(Color(int(howBrt), byte(StaticObj::txtGold.GetRed()), byte(StaticObj::txtGold.GetGreen()), byte(StaticObj::txtGold.GetBlue()))); StaticObj::brushTxtLime.SetColor(Color(int(howBrt), byte(StaticObj::txtLime.GetRed()), byte(StaticObj::txtLime.GetGreen()), byte(StaticObj::txtLime.GetBlue()))); g->FillRectangle(&StaticObj::brushTxtLime, POS_X, POS_Y + 8, int(barWidth), 16);and whatever you draw with the colors you have adjusted will use that alpha (transparency).

Share this post


Link to post
Share on other sites

When FS creates the DC it prefills it with a black background.To prove my statement, simply do no drawing whatever. It will always, always display black.There are ways to render bitmaps with transparency... but since FS always fills the DC passed before passing it, you can not get the DC as a 'blank' slate.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this