Well, its been a while since I've started a thread.
I've been playing around the last few days with fading graphics in an image so today, as sort of a demo, I decided to take an old VB6 whimsical piece of code (last updated about six years ago), and sort of port it to VB.Net.
The original code was probably around 100 lines total, and this code is also just over 100 lines, but in this case I've added a couple of slider type controls to adjust things, which I didn't have in the original VB6 (and probably originally an earlier version).
The program was just a simple thing, and I've posted a couple versions of it, the one I'm currently looking at was posted in this post.
There it has 100 "worms" made up of 50 points (3 pixel sized point), and the speed varied so the worm would kind of gather together when it slowed down, and stretch out (2 pixels max between points so there was always at least some overlap).
They would turn left and right and slow down and speed up.
Just a simple example using a circular buffer mechanism so was only actually drawing one point for each worm per frame.
In the .Net case, the objective isn't really the same.
I'm not keeping track of a number of segments to give the "worm" length, I'm just varying the "persistence" of the bitmap so that as the single point is being moved around, a fading trail is left behind it, sort of comet like.
You can vary the persistence with one control to change how long it takes the tail to fade (if you reduce the Alpha very near 1, it pretty much never fades). If you adjust the Alpha high, the it fades almost immediately.
I also added another control to allow varying the number of active points moving around. It allows selecting from 1 to 900.
I'm regulating the update rate by a timer, so it should probably be 64hz on most machines, since that is the most common base clock tick that I've found on all Windows machines that I've worked on for the last six years or so.
Even at 900 points moving around, it isn't taxing the machine I'm working on, which isn't that high end.
The CPU usage for the task goes to about 10% when doing 900.
But it is easier to watch the movement of individual points when doing a lot fewer points per frame.
I believe if I let it run flat out, without a timer, it would do around 200 fps with 900 points.
The reason I'm posting is that I think the fade out effect is kind of neat, so I thought others might be interested in seeing it as well.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
I decided to take an old VB6 whimsical piece of code..and sort of port it to VB.Net.
The reason I'm posting is that I think the fade out effect is kind of neat, so I thought others might be interested in seeing it as well.
Very neat.
Your screenshot failed to show the wide variations that were possible with different trackbar-slider control settings, so I attached a dual screenshot showing the ends of the ranges.
I've noted that many of the samples in the Matrix Transforms thread use a picturebox control as a value slider instead of a trackbar control, so I guess this time you decided to go a more "formal" way of adjusting things for this standalone sample.
The effect can almost be like creating a procedural texture.
It could be used as an animated fill (using just shades of blue) for a
waterfall on game map.
Since you are using BufferedGraphics, does that mean that unmanaged bitblt is being used as per this post?
Your are drawing the worms with a FillEllipse,
but the alpha FadeBrush is being applied with an every-other-pass FillRectangle.
You get a interesting cameo-shaped framing effect if you use FillEllipse for both.
Quote:
The CPU usage for the task goes to about 10% when doing 900.
I'm getting less than that for an iCore 7 CPU overclocked above 4.0Ghz.
...I've noted that many of the samples in the Matrix Transforms thread use a picturebox control as a value slider instead of a trackbar control, so I guess this time you decided to go a more "formal" way of adjusting things for this standalone sample.
The range of the values were not that large and the values selected did not have to be that precise, so I used the trackbars.
Using the picturebox's is just a hold over from VB6.
Actually, in VB.Net a label might be a better choice, assuming it is more lightweight than a picturebox.
I find just plopping a control I can drag on, with a little bit of code behind it is usally quicker for me to setup, and is more flexible.
You can click anywhere on the control and move one way to increase the value, or the other to decrease.
You can adjust the preciseness needed easily. In the Ovoid dragging, some of the values, like scaling, were adjusted in very small increments, which is why it was displayed out to the 1/1000ths position.
You can have preciseness and range by doing repeated drags in the same direction, and you can drag well outside the control, all over the whole desktop to extend the range of what you're controlling.
The regular scrollbar and trackbar just don't have that flexibility, when you need it.
Quote:
Originally Posted by hDC_0
Since you are using BufferedGraphics, does that mean that unmanaged bitblt is being used as per this post?
I suppose it is, but it is a class provided by Microsoft for use in .Net languages. Whether it is using unmanaged resources under the hood, I don't know that I really care.
My understanding is than many of the classes are using unmanaged resources, which is why they have to implement Idisposable and you have to call Dispose on them, so the unmanaged resources can be returned to Windows.
Many of the graphic class objects are using unmanaged resource, like brushes you create, or Graphics objects you create, so you have to call the .Dispose method on them to free those unmanaged resource.
Managed code that is generated and compiled in the intermediary language and runs under the Common Language Runtime, are controlled by the CLR, protected and cleaned up by the CLR, so do not need or implement a .Dispose method.
It doesn't matter to me if, to interact with Windows, some Managed Classes have to be built by Microsoft, and others, to wrap around unmanaged resource to get the job done. Windows is not running under the CLR so at somepoint someone has to make the connection.
The bottom line for me, and you can try the code in this post, if you haven't already, is speed and ease of use.
The code is the latest in the ultrasonic thread, and was the basis for the code posted in this thread.
That code has another Test capability built into it, so you can compare the same code being used to draw into a bitmap buffer and then drawing it to the picturebox using DrawImage, or using the BufferedGraphics Class.
On the machine I was on, the BufferedGraphics Class gives 300% to 400% improvement in how fast that job can get done.
That is an excellent boost, and I don't see that there is a simpler way to get that much bang for the buck with backbuffered drawing.
I'm now pretty much as convinced as I can be, that if you are going to use the Windows.Forms class for drawing, then to get the best speed, using the BufferedGraphics Class is going to be optimization item #1.
Quote:
Originally Posted by hDC_0
I'm getting less {cpu utilization} than that for an iCore 7 CPU overclocked above 4.0Ghz.
I would surely expect so. My values were from an old Dell Latitude business class laptop.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
On the machine I was on, the BufferedGraphics Class gives 300% to 400% improvement in how fast that job can get done.
That is an excellent boost, and I don't see that there is a simpler way to get that much bang for the buck with backbuffered drawing.
I'm now pretty much as convinced as I can be, that if you are going to use the Windows.Forms class for drawing, then to get the best speed, using the BufferedGraphics Class is going to be optimization item #1.
I'm surprised at you passel,
I download ALL your attachments with the greediest of anticipation for more...<*thumbs up*>
The latest ultrasonic post is definitely fast (with BufferedGraphics),
but the sonar screen effect is I remember had more or a green gradient
sweep behind -- like this or this.
However I admit I haven't been following the thread that closely
(except for your attachments),
so I don't know if what you posted is closer to what the original poster was looking for..
I know you will let us know if BufferedGraphics gets surpassed by some other method that is faster.
Well, what you see on the scope depends on the speed and range of the radar, and whether you've offset your sweep or not.
In the case of that thread, and the poster didn't really specify what he wanted exactly, so I said there were a number of ways to display the data, one which I had already given an example of.
He then mentioned just showing maybe the last five points as it swept, removing the last as you show the newest, so I mentioned a number of ways you might want to implement that, one being you don't track and remove the previous points, but just fade them out like the old RADAR repeaters.
So, I decided to do the example of the fading out method, as it is probably easier to show then have to explain a number of times.
In his case, the sensor steps, and triggers a reading 250 times around a 360 degree circle, so yes, the Beams are spokey.
You can get the effect of what you've show easily enough.
Since there are only 250 divisions to the circle, and the radius is 283, if you used a pen with a width of 7 for the beam, that would fill in most of the gap and give you a much smoother looking sweep.
I originally had a GreenPen defined at the top with a width of 6 and used it to draw the beam, and I thought about adding more things, like range rings and bearing markers, and generating an "envionment" for the beam to reflect against so it would be a more interesting visual, but that would detract from the basic simplicity of the core issue which was how to plot data points on a "RADAR" type display in real time.
Novice coders are easily overwhelmed by looking at a large amount of code trying to decipher the parts they want to use from the mass of code they're looking at.
So, I tried to pare the example back to the minimum.
Used a stock pen, rather than creating a custom pen.
Reduce the process to just position the coordinate system at the center, rotate the coordinate system, draw beam, plot point, done.
Once that is working, if other embellishements are desired, they can be added.
If you want to make a few quick changes, try added a custom pen at the top
Dim greenPen As New Pen(Color.Green, 7)
Use that pen in the beam draw and make the "blip" bigger so it isn't damaged too much by the overlapping wide pen strokes.
g.DrawLine(greenPen, 0.0F, 0.0F, 0.0F, -283.0F)
g.FillEllipse(Brushes.Yellow, -4, -pseudoDistance, 8, 4) 'a slightly wider than thick blip
Change the persistence Alpha down so you get a slower fade, from 16 down to 4 should be good.
Dim fadeBrush As New SolidBrush(Color.FromArgb(4, 0, 0, 0)) 'very dark, but mostly transparent black
See how that looks. The background should not be completely gone by the time the beam comes around to refresh it.
The first image you posted looks more like a real RADAR repeater to me.
The second is probably an emulation, or a digital repeater.
The old, standard RADAR, worked by spinning around and emitting a pulse at a prescribed rate, and listening for reflections. When the pulse was triggered, a signal called the Master Trigger happened simultaneously so that the repeaters were sync'd with the beam.
I won't go into the raw Radar Repeater methods (i.e. like the old SPA-25 repeaters used when I was in the Navy), but cover the method used to display the RADAR on the operator stations, where operators tracked, classified, etc. the "blips" returned by the RADAR.
As the RADAR spun around, synchro signals were transmitted down to a "RAC" (RADAR Azimuth Converter), which spun a couple of synchro receivers in a box which was connected by a number of gears to a 10-bit Gray Scale encoder.
Gray Scale, if you're not familiar with it, is a way of counting in binary in such a way that only 1-bit at a time ever changes from one number to the next.
Normal Binary counting can involve a large number of bits changing simultaneously from one number to the next, i.e to go from 31 (011111) to 32 (100000) all six bits have to change.
In a mechanical sensor, such as an encoder, that is sensing a moving pattern and encoding that pattern into bits, you can't ensure all the sensors will detect the change in their pattern at exactly the same time so that all six bits change together. The result is the transition from 31 to 32 may have a number of random numbers generated during the transition period, ranging from 0 to 63.
So, Gray Scale eliminates that. Since only one bit will change, the worse that will happen is the number might flip between 31 and 32 a number of times during the transition, but you won't have large random errors.
Anyway, the 10-bit encoder essentially divides the 360 degree sweep into 1024 parts (10^2 = 1024).
When the MasterTrigger occurs, the value from the encoder is latched, this gives us the angle (in 1024ths of a circle) of the beam, relative to the ship.
In the case of the system I'm describing, that value from 0 to 1023, was used to index into two tables and pull out values that went into two countdown registers. Essentially, what the values were is the Sine and CoSine of the angle of the beam.
Now, the pulse of radiated energy will travel at a speed of around 6ns (nano seconds) per nautical mile.
The RAC would decrement the countdown registers and when each wrapped, would increment the value in another pair of counters, one being X, the other Y.
The X counter fed a DAC (Digital to Analog Converter) and that Analog voltage was applied to the X deflection amplifier of the scope.
Likewise, the Y counter fed a DAC that drove the Y deflection amplifier.
The result is, the beam would travel out from the center of the scope out at an angle matching the angle of the RADAR beam.
Basically, a mechanized Bresenham's line drawing algorithm.
The counters were clocked so that the beam on the scope took 12ns per nautical mile to draw. The reason there, of course, is that any reflection from the RADAR beam traveling out would have to travel the same distance (and time) back to the receiver so the beam being drawn on the scope would be at the position when the return was received at the point where the return was reflected.
The reflected energy as it is received simply drives the electron beam intensity of the scope, so the beam as it is drawn moving out at 12ns per nautical mile varies in brightness depending on the strength of the reflected energy.
The reason I said the first image looks like a real image, is that after the master trigger from the radar, there is normally a "blanking" period, where the electron beam intensity of the scope is suppressed so that the beam is not visible.
This leaves a empty circle of "blanking" period radius at the center of the scope.
This is done to prevent the radiating beam being drawn from "burning" a hole in the phosphor at the center of the scope since that area would constantly, brightly illuminated, from the beam originating there.
It's hard to tell, but your first image looks like it has that dark, unused area, in the center of the sweep, whereas the second image has some round blip right at the center.
Quote:
I know you will let us know if BufferedGraphics gets surpassed by some other method that is faster.
Intuitively, my first approach to fast updating was simply to have a picturebox with a bitmap loaded in the .Image property of the picturebox.
My code would simply modify the existing bitmap, whenever and whereever I needed, then just trigger the paint event of the picturebox.
I didn't put any code in the paint event.
The Picturebox just updated the screen from the .Image object it was maintaining.
I assumed since we didn't do anything in the Paint event itself, that having the control do its normal repainting from its image would be as fast as it could get.
Plus, we had the side benefit of the image being automatically persistent so the control updated the screen from the image whenever necessary.
A win-win situation in my book.
But, later when I actually did some detailed timing, is when (on the particular machine I was on), I discovered it took around 6 to 8 ms just to have the picturebox repaint itself from the .Image object.
I don't know why that is the case, but that struck me as being (relatively) very slow, for essentially just "flipping" buffers.
That is when I specifically search for backbuffer support in .Net and came across the BackBufferedGraphics Class.
As reported, when I used the BackBufferedGraphics Class in that application, the time to "flip" buffers went from 6 to 8 ms, to 2 to 3 ms, a huge difference.
So, I'm pretty sure the BackBufferedGraphics Class is going to be fastest implementation.
What may add a little more speed is using it in conjunction with your own user created control, rather than a Picturebox.
With your own control, there may be some additional overhead that the Picturebox control is doing behind the scenes when it processes the OnPaint event that you can skip with your own control. Might save a millisecond.
I've been looking around, but haven't come across any good disection on just how resource heavy a picturebox is compared to a panel, or a label, or a button, for that matter.
Creating a user control that you can reuse is always going to be a bit more work than using a pre-existing control, and I can't find a good analysis of what the trade offs are.
Abusing the control, by using many of them, doesn't make sense of course, but just using one to designate a drawing area on the form, doesn't seem unreasonable.
It may be heavier than you need, but if you don't load stuff in the .Image and .BackgroundImage properties, just how heavy are the unused objects?
<Shorten post here, over 10000 characters>
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
That is when I specifically search for backbuffer support in .Net and came across the BackBufferedGraphics Class..
As reported, when I used the BackBufferedGraphics Class in that application, the time to "flip" buffers went from 6 to 8 ms, to 2 to 3 ms, a huge difference.
So, I'm pretty sure the BackBufferedGraphics Class is going to be fastest implementation.
This is great but left me guessing what class code specifically you were referring to?
I did a google search for "BackBufferedGraphics Class" and got nothing.
For more advanced double buffering scenarios, you can use the .NET Framework classes to implement your own double-buffering logic. The class responsible for allocating and managing individual graphics buffers is the BufferedGraphicsContext class.
Following the BufferedGraphicsContext class link
leads you to an MSDN page that says:
Quote:
You can retrieve the BufferedGraphicsContext for the current application domain from the static BufferedGraphicsManager.Current property. For graphically intensive applications such as animation, you can create a dedicated BufferedGraphicsContext using the constructor..
..of course a sample of designing the most optimized custom dedicated BufferedGraphicsContext is not described..
I looked into the "Object.MemberwiseClone Method" and it had some code
for "Shallow Copy" versus "Deep Copy",
but I was confused as to which "cases" might demand one versus another?
Quote:
There are numerous ways to implement a deep copy operation if the shallow copy operation performed by the MemberwiseClone method does not meet your needs.
How would I design some structured exception handling
(Try...Catch) to decide at runtime if the "needs are being met"?
Doesn't give any clue if one is actually faster than the other,
but I would imagine a deepcopy cloning might take more time?
This almost seems like a "ByVal" versus "ByRef" thing..
Yes, you got me. Didn't catch that I was adding the word "Back" a few times in this last post.
I assume (hope) I didn't do that in previous posts.
Of course, the code has the correct class since it wouldn't compile otherwise.
As for the BufferedGraphicsContext class, I've done it both ways.
Probably all the code I've posted just uses the .Current to set the manager to the current application manager.
Any Windows.Forms application is going to have a BufferedGraphicsContext object included to handle all the double buffering objects for the application.
When you create your own double buffering using the BufferedGraphics class you either have to create a manager of your own, to handle just your doublebuffered buffer (I don't know off the top of my head, if you have several BufferedGraphics objects, whether you can share a manager you created between them),
or you can use the current application wide manager to service your doublebuffer.
What the ramifications of all that is, I'm not sure.
I haven't see much difference when I was originally playing around with this, but I also didn't have applications that had a lot of double buffered controls that might slow down my buffer because the manager is shared.
Perhaps with a more complex combination of many controls, having a dedicated manager for an animation window might reveal itself to be important.
As for shallow copy vs deep copy, I don't think it would be a matter of trapping anything, but rather a design consideration at the start, given what you expect your program to do with objects it copies.
Bottom line, reference objects (classes, arrays, etc..) embeded in an object that is shallow copied are going to be reference to the same object.
If you modify the original embedded reference object, the cloned object will also be "changed" (not really, but it points to something that was changed), so shows the same information.
The design consideration is why are you cloning the object?
If you're not going to be modifying the original or copies reference objects,
say you have an object that contains an image of a symbol that you may want to draw many times in many places. So, part of the object contains the "static" (that was the term they used, not my general understanding of static) parts, which you can modify independly in the shallow copies, without conflict, such as the location and size of the symbol, but all the objects would reference the same image, so you're talking a minumum of storage to hold the reference, rather than each object holding a copy of the image.
If, on the other hand, you plan on modifying the image in the copies (or original), then you would have to implement a deep copy, so that each object has a reference to a unique image, somewhere.
And yes, doing a deep copy is going to have the overhead of creating the additional things the references are pointing to, as the example does, by using New to create a new object for the reference in the Deep Copy function.
In the example they imbedded a Class, which only had an Integer in it (an Integer is not a reference type), thus made access to the Integer have to go through a reference type (the embedded Class).
So, in the example the ID changed in the second object when the first object was modified.
The third object showed that by doing a deep copy, when you modified the first object, the third object's ID was not affected (although if you printed the second object again, you would see it was once again "updated" when the first object was modified).
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Managing multiple BufferedGraphics buffers and good BufferedGraphics Manager example?
Quote:
When you create your own double buffering using the BufferedGraphics class you either have to create a manager of your own, to handle just your doublebuffered buffer (I don't know off the top of my head, if you have several BufferedGraphics objects, whether you can share a manager you created between them),
or you can use the current application wide manager to service your doublebuffer.
What the ramifications of all that is, I'm not sure.
I haven't see much difference when I was originally playing around with this, but I also didn't have applications that had a lot of double buffered controls that might slow down my buffer because the manager is shared.
Perhaps with a more complex combination of many controls, having a dedicated manager for an animation window might reveal itself to be important.
Yes..I definitely agree.
Since the BufferedGraphics class has been shown (by you)
to be one of the fastest way of manipulating graphics in .Net,
then being able to managed multiple instances of this class
has potentially important implications for scaling
multi-layer graphics-heavy apps.
I don't if any of your attachments offers any such dedicated manager, though?
If not, do you know of any good examples
(other than the "Manually Manage Buffered Graphics"
cited by above by surfR2911)?
Found this msdn forum post an interesting read through.
But I wonder if his recommendation is really valid:
Quote:
Conclusion
Although it is possible to use BufferedGraphics to speed up Graphic Display over several paint invocations, it is not recommendable. Unfortunately, Microsoft's documentation of BufferedGraphics and BufferedGraphicsContext is sadly lacking the following information:
BufferedGraphicsContext manages memory which all controls can use to draw first to and then copy the result to the screen in one operation (render). This prevents flickering when the control writes to the same location several times, like painting first the background, then the foreground.
The important assumption here is that the control redraws the complete content during every paint. No need to keep the BufferedGraphics content between two paints.
Once the paint of a control is over, the paint of the next control starts, which can use the same memory managed by BufferedGraphicsContext.
Because of this, a separate BufferedGraphicsContext is needed for every BufferedGraphics that should store the graphics for longer than just one paint. The advantage would be that the control doesn't need to reconstruct everything for every paint.
Recommendation: I will try to store the graphic information between 2 paints in a bitmap object.
He also says:
Quote:
..you'll also need a BufferedGraphicsContext. BufferedGraphicsManager.Current is only good if you just make temporary use of the buffer (OnPaintBackground to OnPaint, presumably). The Graphics reference you pass to Allocate() is stored but only used in Render() (not Render(Graphics)). You can dispose that reference after Allocate() if you never use Render(). Or dispose it if you re-allocate the buffer; BufferedGraphicsContext does not dispose it.
(emphasis mine)
Many examples that I have seen that use
"BufferedGraphicsContext",
(instead of "BufferedGraphicsManager.Current.Allocate"),
go something like the sequence seen in this post:
1.) CreateCompatibleDIB
2.) CreateBuffer
3.) AllocBuffer
4.) AllocBufferInTempManager
5.) Allocate
Here's my question, though:
Would using a carefully designed, manually managed BufferedGraphic class
offer a better approach that using (and having to manually manage)
multiple BufferedGraphicsContexts?
I'm not sure what multiple BufferedGraphicsContexts would gain you in most uses.
The BufferedGraphic class is used to implement double buffering, so in the normal case, would not be faster than drawing straight to the control, which has double-buffering turned on, (which the Picturebox does, by default).
So, in at least one of my posts, probably early in the ultrasonic one, I said drawing directly in the paint event everything would be the quickest way to update the control.
Where the BufferedGrapihcs helps is when you need a persistent buffer, where you can't redraw everything in the paint event.
If you need, for speed sake, to just add new information, or redraw a portion of an existing image, the BufferedGraphics class will move that buffer from memory to the screen quicker than any other method you could use.
But since the BufferedGraphics is pretty much dedicated to that task, it isn't of use for much else, such as maintaining multiple buffers for layering, compositing, etc.
You can't make the background of a BufferedGraphic buffer transparent, so if you tried to layer render two or more on top of each other, you would only see the top one.
Rendering of a BufferedGraphic to the control (or other device), can't be done piecemeal (only a part transferred), offset, rotated, etc.
The whole buffer is transferred a quick as possible aligned with the upper left of the control. It is not effected by transforms of the device it is being rendered on.
All transforms are applied to the backbuffer, which represents the soon to be forebuffer, so is just replicated from memory to screen unmodified.
If you want to maintain multiple layers of image data (with some transparency, I expect), then those would be maintained in bitmaps, or images, and combined into the backbuffer.
If you are always going to be building the backbuffer from scratch, combining all the stuff whenever you get a paint event, then you probably don't need the BufferedGraphics Class.
As for creating your own manager, rather than use the current one, it is just a matter of changing the one line, i.e. in the "fading worms" attachment in the first post, just change
screenImage = BufferedGraphicsManager.Current 'initialize a BufferedGraphics manager
.to.
screenImage = New BufferedGraphicsContext()
Now you have a dedicated manager. I'm sure you won't see any difference in this example.
Might as well dispose of those objects as well in the Form closing event.
Code:
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
For i As Integer = 0 To 15 'Dispose of all the brushes we create and cached in our table
BrushTable(i).Dispose()
Next
gScreen.Dispose()
screenImage.Dispose()
End Sub
Assuming you created your own manager. Don't know if you should dispose of it if you use the current manager.
As for the "Temporary" allocation of memory, I think they may be mis-interpreting what the MSDN says.
When you allocate a buffer with the manager, if the amount of buffer you need exceeds the amount he as permanently allocated for his use, then he allocates more buffer space for your use, but it is "temporary" in that the manager will release it when you are done with it (in our case, we are never done with it durning the life of the application). The manage will not release permanently allocated memory, even if no object is using it.
The default "permanent" allocation is pretty small, so in most cases, you are given your own "temporarily" allocated memory when doing a large backbuffer for an image.
I assume, most controls, like buttons, labels, etc. have a pretty small footprint, so when they need to be painted, they get the buffer from the permanent memory, do their update, and dispose of the graphics object, so the permanent memory is available for the next control in line to be painted.
That is also the reason you can't cache a graphics object in the paint event for later use, since that one will be disposed of when the paint event is done, and a new one gotten from the manager the next time it needs to be painted.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
multi-layer buffering for dynamic compositing and pipelining
Quote:
But since the BufferedGraphics is pretty much dedicated to that task, it isn't of use for much else, such as maintaining multiple buffers for layering, compositing, etc.
You can't make the background of a BufferedGraphic buffer transparent, so if you tried to layer render two or more on top of each other, you would only see the top one.
Rendering of a BufferedGraphic to the control (or other device), can't be done piecemeal (only a part transferred), offset, rotated, etc.
The whole buffer is transferred a quick as possible aligned with the upper left of the control. It is not effected by transforms of the device it is being rendered on.
All transforms are applied to the backbuffer, which represents the soon to be forebuffer, so is just replicated from memory to screen unmodified.
If you want to maintain multiple layers of image data (with some transparency, I expect), then those would be maintained in bitmaps, or images, and combined into the backbuffer.
Your insights are most valuable,
but in terms of maintaining these multiple layers with alpha transparency:
If images/bitmaps are stored separately as
a non-static, dynamically-changing-at-runtime bitmaps (dibs?)
(i.e. not in a BufferedGraphics context),
can they still be altered in a bitmap stored state
if they need to have combinatorial masking done on them
(via a separate maintained and
dynamically altered-at-runtime greyscale alpha images)?
Would it not be better for pipe-lining purposes,
to have separate "transparency masking compositional"
type BufferedGraphics contexts maintained for each layer
(each "layer consisting of a bitmap and
a greyscale gradient image
used for multi-level opacity alphamasking).
Then have a transfer-to-paint graphics buffer
(where various layers can be shown or not shown,
turned off and on for animation purposes)
acting as the final "flip" buffer?
As an example:
Imagine multiple layers of amoeboid shapes.
Each shape's outline is fluid and undergoing
real time undulating animation.
In this liquid environment there are floating patches of "cloudiness"
interstitially dispersed between the layers,
which mask out some of the shapes internal organelle-type features
as they float around in some type of Brownian motion.
For such a scenario some sort of code mechanism per pixel alphablending
for each layer might be necessary -hopefully
buffered to whatever extend possible for
speed/performance optimization.
I'm not sure I understand the question.
Bitmaps in memory can be modified all you want.
Bitmaps in memory can have whatever opacity you want, so can be combined in layers to wherever you need
The BufferedGraphics Buffer does not support opacity, so can only be the bottom layer (background) of whatever you may be accumlating (layering) on top of it.
It's sole purpose is to back an area of screen so that that area of the screen can be updated all at once. And by area of the screen, I mean the area behind a control. You can't force the BufferedGraphics to render anywhere, at any size, other than at the upper-left of a control and at whatever size the buffer is.
So, the BufferedGrapihcs can act as the final flip buffer, where all the layers are accumulated, but can't be used to hold any of those layers, since any transfer from a BufferedGraphics buffer to anywhere is going to be an opaque, fixed position, fixed size transfer of the bits front the BufferedGraphics buffer to the destination buffer, replacing any bits that were there before. That is why the transfer occurs in 2ms instead of 8ms on my machine (other machines may be faster or slower). The other methods of transferring image data, i.e. drawimage or TextureBrush, are subject to supporting opacity and transforms, so are going to be slower, but with the flexibility necessary to do those things you need opacity and transforms for.
If you had a scenario where you were trying to meet a certain frame rate, and you could mathematically pre-compute future frames independ of the current frame, then in a multi-core situation, it could help to process a given frames graphics in its own buffer on its own thread, so you would benefit from parallel rendering of different frames, and then the GUI would be cycling through and rendering from those buffers.
A bitmap can be shared between threads, but controls can't. I haven't tried a BufferedGraphics object, so don't if it could or not. It seems likely that it shouldn't be.
But I have tested a background thread updating a bitmap at a high rate of speed, while the GUI periodically updates a control with the contents of the bitmap independently (without invocation from the background thread), and that works fine.
If there was a convenient way to vsync without DirectX in the Windows.Forms GUI thread, then the updates from the GUI could look a lot smoother since we could avoid the tearing associated with different frames being displayed at the same time in different sections of the window.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
From what you said about BufferedGraphics in your last post their speed
and performance are trade offs with a lacking of flexibility in building
a multi-stage rendering pipeline with per alpha masking for each layer,
while:
Quote:
Bitmaps in memory can have whatever opacity you want, so can be combined in layers to wherever you need
Quote:
..it could help to process a given frames graphics in its own buffer on its own thread, so you would benefit from parallel rendering of different frames, and then the GUI would be cycling through and rendering from those buffers..
If there was a convenient way to vsync without DirectX in the Windows.Forms GUI thread, then the updates from the GUI could look a lot smoother since we could avoid the tearing associated with different frames being displayed at the same time in different sections of the window.
So the drawback in parallel rendering, unless a non-DirectX way is found for sync-ing, is tearing.
Could parallel rendering be used to create a series of ray traced bitmap scene frames in memory..perhaps in a non-real-time way?
The "smoothing" of animation could be down by interpolated tween-morphing between frames perhaps..
No I haven't played around with any of those.
And it is not by coincidence, that most of those examples use WPF.
Since WPF is using directX under the hood, it will give you the best GUI performance, so is the best platform for demonstrating quick and interesting GUI eye candy.
In searching around for a way to do alpha gradient masking, you may come across Opacity masks, which sound great, but then realize it is WPF again, not in the Drawing2D class.
And you'll get tearing regardless of whether you're doing parallel rendering or not, with Windows.forms.
If you're doing single updates from a backbuffer, you probably won't notice.
If you doing something like a sidescroller, where the whole background is moving, then you're most likely to see it, although many don't really pay it any mind. I'm tired, I guess I'll head to bed "early".
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET. subscribe