PDA

Click to See Complete Forum and Search --> : BitBlt Assistance with Pixel Array


tinman_22
Oct 20th, 2000, 03:06 PM
I have been doing a small VB app to plot simple pixel array. The array contains the pixel values. I can blit it once but I would like to refresh the screen with a new array about 30times a second. This is what I do:

1- I set the color table
2- I set the array with pixel values
3- I create the bitmap:
set the infoheader
get the screens device context
create the DIB using the CreateDIBitmap API
4- Using a picture box using the Paint event I draw the bitmap by:
Creating the device context
selecting the bitmap into the dc
applying bitblt
deleting the dc


alone this flow chart works great and I get results but when I put 2,3,4 in loop of lets say 10 frames it seems that the system is working hard on those 10 frames and only displays the last one. Is there a way to improve this or is there another way that this can be done. It's relatively a simple concept. Take a calculated array, blit it to the screen, and refresh the screen everytime the array has changed. Most of the help that I have found only shows loaded bmp files but not array and the code does not apply or does not work. Please help.

kedaman
Oct 20th, 2000, 03:36 PM
First of all, don't delete the DC all the time, use the same. Second, how big is the array, how many colors do you use and what type of animation are you trying to do? If it's an iterative one you could as well store the bitmaps for further performance. I believe the calculations for the array would be the worst performance-eaters.

tinman_22
Oct 20th, 2000, 03:50 PM
There is no math yet and the array can be anything from 600x480 to 1024x768

I tried to not delete the DC but it seems that then the image just does not appear. I followed the following code. This is a piece of code that I got from another help and tweaked it for myself: (I did not include the initialization on top for the api calls)

Dim Pixels() As Byte ' Pixel data.
Dim bm_info As BITMAPINFO_256 ' DIB bitmap info.
Dim hDIB As Long ' Bitmap handle.
Dim wid As Integer ' Size of the bitmap.
Dim hgt As Integer

' Create the DIB.
Private Sub CreateDIB()
Dim screen_hdc As Long

With bm_info.bmiHeader
.biSize = Len(bm_info.bmiHeader)
.biWidth = wid ' Width in pixels.
.biHeight = hgt ' Height in pixels.
.biPlanes = 1 ' 1 color plane.
.biBitCount = 8 ' 8 bits per pixel.
.biCompression = BI_RGB ' No compression.
.biSizeImage = 0 ' Unneeded with no compression.
.biXPelsPerMeter = 0 ' Unneeded.
.biYPelsPerMeter = 0 ' Unneeded.
.biClrUsed = 256 ' # colors in color table that are used by the image. 0 means all.
.biClrImportant = 256 ' # important colors. 0 means all.
End With

' Get the screen's device context.
screen_hdc = GetDC(0)

' Create the DIB.
hDIB = CreateDIBitmap(screen_hdc, _
bm_info.bmiHeader, CBM_INIT, Pixels(0, 0), _
bm_info, DIB_RGB_COLORS)
End Sub

' Draw the DIB onto the form.
Private Sub DrawDIB()
Dim compat_dc As Long

' Create a compatible device context.
compat_dc = CreateCompatibleDC(hdc)

' Select the DIB into the compatible DC.
SelectObject compat_dc, hDIB

' Copy the compatible DC's image onto the form.
StretchBlt Picture1.hdc, 0, 0, _
Picture1.ScaleWidth, Picture1.ScaleHeight, _
compat_dc, 0, 0, wid, hgt, _
SRCCOPY

' Destroy the compatible DC.
DeleteDC compat_dc
End Sub

' Initialize 256 shades of gray.
Private Sub SetColorTable()
Dim i As Integer

For i = 0 To 255
bm_info.bmiColors(i).rgbRed = i
bm_info.bmiColors(i).rgbGreen = i
bm_info.bmiColors(i).rgbBlue = i
bm_info.bmiColors(i).rgbReserved = 0
Next i
End Sub
' Create a drawing.
Private Sub SetPixels()
Dim X As Integer
Dim Y As Integer

wid = 800
hgt = 600
ReDim Pixels(0 To wid - 1, 0 To hgt - 1)
For Y = 0 To hgt - 1
For X = 0 To wid - 1
' Creates a random array
Pixels(X, Y) = 255 - Int(Rnd() * 255)
Next X
Next Y
End Sub


Private Sub Form_Load()
Dim i As Integer

SetColorTable
SetPixels
CreateDIB

End Sub

Private Sub Form_Resize()
Picture1.Move 0, 0, ScaleWidth, ScaleHeight
Picture1.Refresh
End Sub


Private Sub Picture1_Paint()
DrawDIB
End Sub

kedaman
Oct 20th, 2000, 04:26 PM
You should have, i tried to put all those apis, the type bitmapinfo, you had renamed and some stuff i'm not sure if żou had changed. But when i finally got it work, nothing shows up. Could you send me the whole project?

tinman_22
Oct 20th, 2000, 04:31 PM
I guarentee that this one will work as long as you draw a picture box no matter what size on the form.

thx


Option Explicit

Private Const BI_RGB = 0&
Private Const CBM_INIT = &H4
Private Const DIB_RGB_COLORS = 0
Private Const SRCCOPY = &HCC0020

Private Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type RGBQUAD
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Private Type BITMAPINFO_256
bmiHeader As BITMAPINFOHEADER
bmiColors(0 To 255) As RGBQUAD
End Type

Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateDIBitmap Lib "gdi32" (ByVal hdc As Long, lpInfoHeader As BITMAPINFOHEADER, ByVal dwUsage As Long, lpInitBits As Any, lpInitInfo As BITMAPINFO_256, ByVal wUsage As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long

Dim Pixels() As Byte ' Pixel data.
Dim bm_info As BITMAPINFO_256 ' DIB bitmap info.
Dim hDIB As Long ' Bitmap handle.
Dim wid As Integer ' Size of the bitmap.
Dim hgt As Integer

' Create the DIB.
Private Sub CreateDIB()
Dim screen_hdc As Long

With bm_info.bmiHeader
.biSize = Len(bm_info.bmiHeader)
.biWidth = wid ' Width in pixels.
.biHeight = hgt ' Height in pixels.
.biPlanes = 1 ' 1 color plane.
.biBitCount = 8 ' 8 bits per pixel.
.biCompression = BI_RGB ' No compression.
.biSizeImage = 0 ' Unneeded with no compression.
.biXPelsPerMeter = 0 ' Unneeded.
.biYPelsPerMeter = 0 ' Unneeded.
.biClrUsed = 256 ' # colors in color table that are used by the image. 0 means all.
.biClrImportant = 256 ' # important colors. 0 means all.
End With

' Get the screen's device context.
screen_hdc = GetDC(0)

' Create the DIB.
hDIB = CreateDIBitmap(screen_hdc, _
bm_info.bmiHeader, CBM_INIT, Pixels(0, 0), _
bm_info, DIB_RGB_COLORS)
End Sub

' Draw the DIB onto the form.
Private Sub DrawDIB()
Dim compat_dc As Long

' Create a compatible device context.
compat_dc = CreateCompatibleDC(hdc)

' Select the DIB into the compatible DC.
SelectObject compat_dc, hDIB

' Copy the compatible DC's image onto the form.
StretchBlt Picture1.hdc, 0, 0, _
Picture1.ScaleWidth, Picture1.ScaleHeight, _
compat_dc, 0, 0, wid, hgt, _
SRCCOPY

' Destroy the compatible DC.
'DeleteDC compat_dc
End Sub

' Initialize 256 shades of gray.
Private Sub SetColorTable()
Dim i As Integer

For i = 0 To 255
bm_info.bmiColors(i).rgbRed = i
bm_info.bmiColors(i).rgbGreen = i
bm_info.bmiColors(i).rgbBlue = i
bm_info.bmiColors(i).rgbReserved = 0
Next i
End Sub
' Create a drawing.
Private Sub SetPixels()
Dim X As Integer
Dim Y As Integer

wid = 800
hgt = 600
ReDim Pixels(0 To wid - 1, 0 To hgt - 1)
For Y = 0 To hgt - 1
For X = 0 To wid - 1
Pixels(X, Y) = 255 - Int(Rnd() * 255)
Next X
Next Y
End Sub


Private Sub Form_Load()
Dim i As Integer

SetColorTable

SetPixels
CreateDIB

End Sub

Private Sub Form_Resize()
Picture1.Move 0, 0, ScaleWidth, ScaleHeight
Picture1.Refresh
End Sub


Private Sub Picture1_Paint()
DrawDIB
End Sub

kedaman
Oct 20th, 2000, 06:03 PM
Problem 1: Stretchblt, the biggest one, it's really slow especially if you have a screen like mine: 1280*1024.
But anyway it would only update max 5fps with 800*600.
Problem 2: Autoredraw will take it's time to store the picture but on the other hand if you don't use it, it will redpaint the screen all the time, also making it slow.
Problem 3: The array is calculated in about 350 ms on my comp, (I have an Athlon 600 and hardware acceleration for most graphical apis too) If you want to have some mathematical operations, or just copying data, there might be other solutions like copymemory and bitblt with other comparation flags.
In general I can say this:
I don't know what youre trying to accomplish (that would also help if you told me) But if the performance is the problem you could switch to DirectDraw.

tinman_22
Oct 20th, 2000, 11:02 PM
Well, is BitBlt faster than StretchBlt and by how much. The application that I am trying to accomplish is for a school project. I have an aquisition card that takes in analog data in a certain period of time. I can do most of the of the tasks except the graphical display. I plan to take a 1024samples of the card and convert it to an equivalent pixel in 256 grayscale (hence you see on the display) for reasons of simplicity I only use a random function instead of the real calls to the a/d card. I just want to display the darn thing on the screen. This 1024line array is a single line and I want to apply scrolling on the screen so that when the system is initialized the first line shows up (due to the first set of samples), the second set is sampled (displaying the new line and the old line on the bottom) then the third set and displaying the older two stored lines until the complete screen is filled with the 728 lines for a full screen at a resolution of 1024x768, it's almost like a scanner system when you think of it but I am simply looking at signals. I want to implement a waterfall effect.

Like this:
(1)
-------------- 1st call

(2)
-------------- 2nd call
-------------- 1st call stored

(3)
-------------- 3rd call
-------------- 2nd call stored
-------------- 1st call stored

.....

(n)
-------------- n call
-------------- n-1 call stored
..............
-------------- 3rd call stored
-------------- 2nd call stored
-------------- 1st call stored

FULL SCREEN

And as the subsequent lines come the first line disapears and makes place for the screen to accomodate line 2 to n+1

This is essentially what I want to accomplish. Everything is done up to this point and I just want to get this done.

You speak of DirectDraw, does this have to do with DirectX and since I am inexperienced with this what is the best way approach this.

Thanks

kedaman
Oct 21st, 2000, 08:38 AM
Stretchblt is slower, in fact very slow if you compare to Bitblt, but that depends on the machine. On my machine Bitblitting takes 0.3-0.4 ms while stretchblt takes about 100 ms. Yes I meant DirectX of which the DirectDraw component allows you to manipulate the screen with much more performance and in more complications than simply blitting or stretching. Since the array calculations takes the majority of the time, i would consider that to be the one you should change first. You want a waterfal effect? This is just perfect for speeding up your app. Only calculate the first row, then use bitblt to copy the part from (0 to n) to (1 to n+1), incease n and draw draw the row again. When n comes to the bottom of the screen you just don't let it increase any more and keep the waterfall running.

tinman_22
Oct 21st, 2000, 03:34 PM
Yes good idea, I noticed a huge difference in time of display. I replace the sub with this

' Draw the DIB onto the form.
Private Sub DrawDIB()
Dim compat_dc As Long

' Create a compatible device context.
compat_dc = CreateCompatibleDC(hdc)

' Select the DIB into the compatible DC.
SelectObject compat_dc, hDIB

' Copy the compatible DC's image onto the form.
BitBlt Picture1.hdc, 0, 0, _
Picture1.ScaleWidth, Picture1.ScaleHeight, _
compat_dc, 0, 0, SRCCOPY

' Destroy the compatible DC.
DeleteDC compat_dc
End Sub

Now being BitBlt the best way to go great. A little problem that I am still having is in the sequence of code here and above. This is what I beleive, I add the new line at the end of the generated array say, line 768 and the rest holds all the older information. Now, at start up and even when the screen is full I have to recreate the bitmap every time since it's an array of values. I can't seem to be able to redisplay the new data. I must be doing something wrong because when I loop the 'form load()' portion to lets say display 10 random images in sequence it seems that it calculates the 10 in memory and only displays the last one. Like this:

Private Sub Form_Load()
Dim i As Integer

SetColorTable

For i = 0 To 9
SetPixels
CreateDIB
Next
End Sub

Does it have something to do with the Paint event of the screen? I just want to lets say display the random screen 10 time in sequence without flickering - then I will know this will work for my small app.

Thanks

kedaman
Oct 21st, 2000, 05:59 PM
Ok well theres still some problems:

Problem 1: Youre doing it the wrong way, create the smallest possible bitmap, that means a bitmap only containing that line. Then blit to the form, from it's own DC, but to one step lower, making the waterfall effect as quick as possible. Then you blit from the bitmap youve created, to the top of the form.

Problem 2: Don't draw the animation during form load event since the form wont show up until it's finnished, put it in a timer or a loop in form_activate. And don't put anything in form paint event either.

hope you get it work :)

tinman_22
Oct 21st, 2000, 07:05 PM
Thanks for the info man, I really got it to work.

One quickie, is there any way to get a hold of a ressource document that lists the timings of various VB functions and API calls. This would be helpful in choosing the right things to speed up an application.

Thanks

kedaman
Oct 21st, 2000, 07:26 PM
eeh, not what i know, i'm just doing these tests myself :) BTW, the timing would be affected by various factors, what you pass to the apis, on what objects you use them on and what machine you have ans so on... But if you really want you could do these test yourself too, using Gettickcount Api you can check time each call, or if they run fast you can put them in loops and divide the result with the loop count.

tinman_22
Oct 21st, 2000, 11:08 PM
Good tip.

One thing that i am noticing when I do this is that after a while the screen freezes. I am doing what you suggested, using BitBlt and making my routines into a timer and after about a minute it seems that the screen does not refresh anymore. It does not slow down and stop, it just stops. Is there a limit to the timer or is there a buffer that I don't know about that seems to be filling and when full pauses the screen. or should I clear some buffer before I display a screen.

kedaman
Oct 22nd, 2000, 04:50 AM
I'm not sure what you mean by timer, you should not use a loop, with a single doevents or something since that freezes your app by causing a huge message queue for the refreshments that bitblt needs. A normal timer shouldn't have that problem, if it has, then try to set a bit larger interval. If you have hardware supported blitting, then the blitting will be a lot faster than the refeshing (at least it's so on my computer) that causes the message queue to get huge and blocks all other messages.

tinman_22
Oct 24th, 2000, 01:19 PM
I have done what you suggested and am blitting one line at a time until the entire screen is filled. I am using a timer and the sequence is acceptable. The only thing is I notice that when I place a dialog (like explorer or anything else) and then minimize that dialog the rectangle that the dialog took is not blank on my image as if it deleted the memory locations of that block - it that the accurate desctiption of this. what would an efficient method be for taking the old data that has been put on the screen and then placing it back without slowing down a system. Should I blit twice, one visible to the screen and another invisible where I simply copy or is that too ineficient.

kedaman
Oct 24th, 2000, 02:04 PM
Usually autoredraw would fix this problem, but since you're using bitblt frequently it may slow down the process and build up that message queue anyway. You could of course try it, the other solution is to set image picture to image property after each blit:

Set Picture1.picture = Picture1.image

tinman_22
Oct 29th, 2000, 11:49 PM
Your advice worked and whenever the image would not be lost when I would have an overlaping window on top of it. One thing is that that line really slows things down.

what I am doing is blitting the first line and then for the rest of the screen i am taking the hdc of the form and reblitting it one step lower. This process is really fast and I am really satisfied with the scrolling effect is just when I insert the Set Form1.picture = Form1.image command I get really crappy speeds (at least 7-10 times slower).

If you want I can show you my project and you can see for yourself. I feel that I am really close if it were not for the resetting of the pixels when I overlap the active form with another application (like calculator of even explorer). It should be simple yet I can't seem to find what's wrong.

Thanks

kedaman
Oct 30th, 2000, 03:44 AM
I think that could help a bit if i had a look at the project, but i'm not sure wheather i could avoid the slowness if you want to keep the drawn image even if it's behind a window. Did you try Autoredraw? (i forgot which one was faster) but i'm sure the second is more sensitive to huge message buffer. At least on my computer.

tinman_22
Oct 30th, 2000, 01:00 PM
The project is on it's way, let me know what you think

thanks

tinman_22
Oct 30th, 2000, 02:29 PM
Hello,

I posted the project on my web account with geocities and anyone who wants to learn can get it at:

http://www.geocities.com/tinman_22/scrolling.zip

Thanks

kedaman
Oct 30th, 2000, 02:32 PM
it just drained all my resources and crashed, i'll search what's being left in memory...

tinman_22
Oct 30th, 2000, 02:59 PM
It's really ODD, it seems to be working on my PC and never crashed once.

Is it giving you any messages?

kedaman
Oct 30th, 2000, 03:03 PM
Well you know what happens if you run ouf of resources, everything starts to act weird and out of memory messages appears, text gets bold and menus disappear...

Well anyway i found about four points where DeleteObject was missing and + i added two DeleteDc's and now it works just fine. Also i put autoredraw on and put a refresh in the timer and everything seems to work just fine.

I'll send you it.

kedaman
Oct 30th, 2000, 08:54 PM
The running out of resources means that.. actually don't really know what it means but it has something to do with not freeing up the handles. Refresh should refer to the form from it's being called from, in this case Form1. SelectObject returns the object that is freed from the DC when selecting another bitmap, i've noticed that was one of the memory leaks, so i used Deleteobject to remove it.