I have some text flicker too, but that probably results from rounding/truncation errors that stem from the changing "shape" sizes that I base the text positioning on.
flicker is because gdi dont have monitor sync.
that is the reason i moved to direct2d as the flickering/stuttering is getting annoying when dealing with moving objects/animation.
I have some text flicker too, but that probably results from rounding/truncation errors that stem from the changing "shape" sizes that I base the text positioning on.
It seems to flicker worse than a very similar program that uses VB6's GDI methods instead. But yes, if you want smooth motion then alternatives are obviously better.
I'm less concerned about animation and flickering than the drawing operations themselves though. I was hoping to get smoother looking lines.
Cruddy drawing? For me, it's usually trial & error. May also want to play with GdipSetPixelOffsetMode in conjunction with GdipSetSmoothingMode.
Flicker. Well, you are performing dozens of rendering operations where each create GDI+ graphics context around your form's hDC and then releases it. I'd imagine that the release method likely triggers a WM_Paint or some other message that indicates DC changed. Is it possible VB is processing these changes, sometimes, before all of them are finished? Also you are toggling AutoRedraw and call CLS. When AutoRedraw is True & CLS is called, VB dumps the previous .Image and creates a new one. Toggling AutoRedraw may also do that. This toggling back & forth along with CLS may be a contributing factor?
Edited: Others have posted ideas on the flicker. Obviously buffer would be better as could be doing all the drawing in a single graphics context.
P.S. I did not run your project, am not on a VB machine. Just reviewed your code.
Insomnia is just a byproduct of, "It can't be done"
even with double buffering its not perfect.
when i created my game in gdi32, i needed to increase fps to 125 to make it somehow smooth, even then it showed stuttering here and there.
now with direct2d i use the monitor sync rate (60-70) and its smooth and show no stuttering.
sure, this kind of program, with lines and some boxes, im sure gdi+ is ok with double buffering, but more stuff you have moving and if you use bitmaps, that will increase the stuttering no matter the fps.
Well the Graphics objects are created and destroyed frequently in response to dire warnings not to cache DC handles of VB6 UI elements (Forms, controls, etc.).
But a lot could be improved by creating/destroying the Graphics object once within an event handler by adding separate calls for that. That is probably a worthwhile optimization in any case, and I could optimize GDI+ Font object creation too by handling StdFont.FontChange for the class's Font Property.
GdipSetPixelOffsetMode is something I should probably look at too since it probably has a lot of impact on the smoothness of antialiased lines.
Well the Graphics objects are created and destroyed frequently in response to dire warnings not to cache DC handles of VB6 UI elements (Forms, controls, etc.).
Oh, agreed 100000%
When I suggested one context, was leaning to something like this: Get GDI+ context on form's hDC, then perform all the drawing in your routine to that context. This would mean maybe having an "Ex" type function that receives a GDI+ context parameter vs an hDC parameter. When all drawing is done, then destroy the context. Tip to clear a context: GdipGraphicsClear. GDI+ can be used as a double buffer too by creating an 24bpp bitmap same size as form doing all the drawing on it, then rendering the final result to the form.
Insomnia is just a byproduct of, "It can't be done"
when i work with animations, you dont destroy the memorydc after each render, but on exit. the memorydc you keep as long the animation is going,
you can clear the memorydc after each circle of course.
i keep in memory everything that i will reuse, and sometimes i also "build" the objects before rendering in the picturebox.
so, i could create 10 memorydc that contains 10 frames that i will render later, so that only thing i do is a copy bitmap instead of drawing, anti-alias and effects, if possible.
when using bitblt, u set autoredraw to false, even hdc to false. bitblt will render and refresh the hdc when calling.
but i recommend using direct2d. dont understand why u keep using gdi and its inferior.
This was really just a bit of playing around with antialiasing for drawing a few simple things. I wasn't pretending to create some Great Gdip Solution class for anyone else to use.
Once I can draw a smooth looking straight line I'll be happy.
i find direct2d easier then gdi+ for this purpose.
u dont need to think about double buffer or create/destroy.
if u are scared of testing it, i cant force u. but i would think that an expert like u would want to try just to get experience of it and compare and analyze if direct2d is good or bad and when its good or not to use it.
its not that we need to use a 3rd party dll/ocx or register anything or closed source, its available in windows 7-10 like gdi32/+
Well GdipSetPixelOffsetMode() doesn't seem to change anything no matter what PixelOffsetMode I choose. I may have been expecting too much though.
I'm just not that interested in Direct2D. If Windows provided a type library I might be more likely to consider it, but probably not even then.
Most of my programs don't do any significant drawing. I get caught up in a thread here now and then, but that's just for lack of interesting questions to try to help with.
Well GdipSetPixelOffsetMode() doesn't seem to change anything no matter what PixelOffsetMode I choose. I may have been expecting too much though.
...
Yeah, I wondered about that. Running the code and capturing the form, and zooming it in a paint program, I can see the lines are being anti-aliased, it just isn't doing that well at some angles. Perhaps it is just the combination of line color and background color make it hard for the pixel blending choices made, by whatever algorithm is used, to visually look appealing. It might be interesting to try to manually adjust the color of the pixels chosen in the "blend" zones over a short segment of the line where the pixels tend to fade too quickly, or where some pixels appear too bright to see if one could do a better job visually. Of course it would help to know what computation is used to choose the partial pixels colors to determine if there would be a way to improve the calculation for given condition and not make other conditions look worse.
It seems like this sort of thing might also be subject to the accuracy of the pixel color temperature setting of the monitor. I have a couple of ASUS ProArt "Superior Color Accuracy" monitors (1920x1200) on my desk as a left and right monitor in a three monitor setup, and the center "monitor" is a 43" 4K Smart TV (a cheap Westinghouse one). The lines do appear to anti-alias a little better on the expensive ProArt monitors, but still look like they could be improved.
I guess a test would be to turn the anti-aliasing off for comparison and see that it probably will look much worse, so the lines are arguably "better" with anti-aliasing on, but probably not as close to the theoretical ideal as we would hope.
That may be bang on. I suspected that at least part of the problem stems from color contrast and some lines' angles. They also look (to my eye) slightly smoother when the lines are more than one pixel wide.
I just thought I had gotten better results in the past but that was long ago and I don't have any of my old code that tried it.
Another thing I haven't tried is rendering with GDI at twice the resolution and then StretchBlitting down to final size with halftone dithering turned on. Better? Worse? No idea without trying but I thought that gave decent results in the past.
Another silly example, but a static one that isn't trying to layer the drawing.
The main points being that it cleaned up font handling a little, removed the hDC parameter from drawing calls, and addressed a serious bug:
GdipDeleteStringFormat was declared with a ByRef argument instead of ByVal. This error means the GDI+ object never got deleted and could have caused access violation crashes. It's a small miracle that the other program wasn't crashing.
That's what I get for trusting a non-Microsoft information source.
If anyone wants to play with this code the earlier versions should be avoided or at least corrected.
Shows that thicker lines antialias a bit more acceptably.
BTW: The attachment is large because of the backdrop image it is using.
Last edited by dilettante; Feb 6th, 2019 at 01:13 PM.
The crashes I experienced were all access violations 0xC0000005, most likely because an address in the program taken as an object address by GDI+ sent it off to limbo.
I didn't mean to imply that a leak caused a crash.
However from what I can find in the documentation cleaning these up is pretty important too. You don't see a lot on this because they don't say much about the Flat API at all. Using the class-based API deals with that through implicit operations when the class instances are destroyed.
I sort of expected all of my questions here to be pretty old hat and almost too embarrassing to ask. I don't work with graphics much but I had the impression that GDI and GDI+ APIs were both heavily used by VB6 programmers who do.
I would say GDI, yeah, but GDI+ is a bit more recent so not as heavily used at this point by comparison. I haven't done any development with GDI+ and VB6, and most posts that I might answer concerning VB6 and GDI or built in graphics capability is primarily based on stuff I did 10 years or more ago.
gdi+ is cpu hungry and because of that people tend to search some something else or gdi32 when dealing with animation.
when i used gdi, the gdi+ part is mostly used for loading/saving and pre-work while gdi32 is used to render as its much faster.
when you work with graphics, you want something that you can depend on, that can do things fast and with good quality.
but to just show a picture, we dont need gdi+, and to use alpha, gdi32 is good enough.
gdi+ is too good to do simple stuff and too bad to do complex stuff.
programming is time and to put that much work into something that is limited and slow is a waste of time.
the vb6 community have lost a lot of programmers because of the limitations of gdi.
direct2d is quite amazing but too late, i feel theres only a few that is using it and its a pity.
i mean, a lot of you have knowledge of gdi32/plus and u feel its enough, no reason learning direct2d now.
if we did have the typelib many years ago, im sure we would discuss direct2d issues not gdi+.
Given that D2D is an API that is COM based, it's actually easier to use in VB6 than in C++. (The resource management part is automatically handled) No need to wrap a flat API, like they did with GDI+ and .NET.
Attached is my attempt at recreating dilettante's GDI+ project using a backbuffer.
I'm not even sure I did/use the backbuffer correctly.
I've been staring at the animation so long I'm going a bit cross-eyed, but I think the flickering disappears (not definitively sure).
What I have added however, is a "tearing" of the moving objects, and this looks a lot worse.
GdipDeleteStringFormat was declared with a ByRef argument instead of ByVal. This error means the GDI+ object never got deleted and could have caused access violation crashes. It's a small miracle that the other program wasn't crashing.
FYI, I just reminded myself that SSPI/Schannel uses *8-byte handles* which are passed *ByRef*. . . I find this extremely bizarre and have never seen other APIs using anything remotely similar.
But a lot could be improved by creating/destroying the Graphics object once within an event handler by adding separate calls for that.
Sometimes you can get the strange bugs when for example you create a buffer HDC at startup and the associated graphics object. When you need to resize the bitmap you need to recreate the compatible bitmap and select it again to the HDC but these changes isn't reflected in the graphics and you need to recreate it once again.
So I added another memory DC to the project, not to make it faster,
but so that I could have only one memory DC to flip to screen.
I added a command button to do this from.
Clicking this button at different intervals, one can see that sometimes the image is "torn" and sometimes not.
If you get into a rhythm when clicking, you can get image to always "tear" or never "tear".
This says to me that "tearing" (in this project anyway) is not a function of GDI+ drawing speed,
but rather when it is drawn.
From my reading on the web, if drawing takes place during a monitor refresh, tearing will occur.
So solution would be to control when drawing (flipping of memory DC to screen) takes place.
I was thinking, if something like InvalidateRect function was used,
Windows might put the event in a queue and Windows might take responsibility of timing,
and time it so it takes place after a Monitor refresh and not during one???