Need some help with Windows bitmaps...

BlitzPlus Forums/BlitzPlus Programming/Need some help with Windows bitmaps...

sswift(Posted 2005) [#1]
I think I know what I need to do now in order to scale my images quickly without having a polygon drawn on top of them scale with it, but I'm not quite there yet and I'm hoping someone knows what I should do.

This is what I think I should do:

1. Create a hidden canvas at the full size of my image. Blit image I have loaded to it normally.

2. Create a bitmap at the same size as the canvas.

3. Get the device context of the canvas using GetDC().

4. Use Bitblt to copy the image from the canvas's device context to my bitmap.

5. Create a bitmap at the scale I want my final image to be at.

6. Use StretchBlt to blit the image from the first bitmap to the second, scaling it up or down.

7. Draw my non-scaled polygon onto this image using SetPixelV().

8. Create a bitmap that will actually be displayed on the screen. Make this a child of the panel I want to display my image in.

9. Blit the scaled bitmap that I created in step 5 to the visible bitmap I just created. I do this instead of displaying the scaled bitmap because the scaled bitmap won't have the polygon drawn on it at all times and it could cause the polygon to flicker if sometimes the bitmap is updated and it doesn't have the corrrect final appearance.


Now my problem here is when I say bitmaps, I'm not sure if I mean bitmaps, or maybe a "device context in memory" or what.

I also don't know which type of bitmap to use. I need something that will work regardless of whether the user is in 24bit color, or 16bit color. But my program will always work internally with 24bit color so I want to be able to always write 24bit color out to these bitmaps.

Here are some links to some information I was looking at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/devcons_7e2b.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_0c1f.asp

I hope someone here has dealt with coding windows stuff before and knows what I should do here.


Grey Alien(Posted 2005) [#2]
I did a lot of Delphi programming which used a Canvas. This was just a wrapper around a windows device context which could be the printer, screen or an image in memory. You couldn't ever assign a bitmap directly to a Canvas as they weren't the same thing. I don't know if this helps but here is the help text for Canvas.Handle in Delphi:


Handle is the Windows GDI handle to the device context for this canvas.

property Handle: HDC;

Description

Set Handle to the HDC for the device context the canvas must draw into. When a windowed control responds to a Windows paint message, the HDC for drawing is passed in to the PaintWindow method. In other cases, an HDC can be obtained for a window by calling the GetDeviceContext method of a control. Additionally, Windows provides API calls to obtain an HDC for a printer or for a memory image.
Read the Handle property to supplement the drawing services provided by the TCanvas object with API calls that require a handle to a device context. Most of the Windows GDI calls require an HDC.

TCanvas does not own the HDC. Applications must create an HDC and set the Handle property. Applications must release the HDC when it is no longer needed by the canvas. Setting the Handle property of a canvas that already has a valid HDC will not automatically release the initial HDC.




Grey Alien(Posted 2005) [#3]
Think you probably should make your bitmaps with CreateBitmap and then copy them onto your device context with BitBlt. Hopefully this should convert to the correct bit depth automatically. then you can work with a 24bit bitmap in memory and not worry about the output (screen)bit depth. Suppose if you use CreateCompatibleBitmap you might end up with a 16bit bitmap which may not be desireable! I don't really know a whole lot about this I am afraid, but the MSDN website is pretty good.


Mr. Write Errors Man(Posted 2005) [#4]
I have coded a lot with Windows GDI, but I am not sure I understand what your question really is.

You can create a memory bitmap with DC handle like this (pseudocode):


; SomehDC is the DC of some bitmap with desired properties (bit depth etc)

Bitmap = CreateCompatibleBitmap(SomehDC,Width,Height)

hBitmap = GetObjectA(Bitmap,Len(SampleBitmap),SampleBitmap)


; Let's make a DC for the bitmap
hDC = CreateCompatibleDC(SomehDC)
SelectObject(hDC,Bitmap)



SampleBitmap is just an empty variable of this 14 byte long (Visual Basic) type:

    Type
            bmType As Long
            bmWidth As Long
            bmHeight As Long
            bmWidthBytes As Long
            bmPlanes As Integer
            bmBitsPixel As Integer
            bmBits As Long
    End Type




sswift(Posted 2005) [#5]
"I have coded a lot with Windows GDI, but I am not sure I understand what your question really is."


I am trying to put a image on the screen which I can scale using GDI commands.

Here's what I need to do:

First, I need to make a DIB which is visible in my window. It needs to be clipped by a panel.

Second, I need to know how to create a DIB in memory. I need to know how to write pixels to it, and how to copy the device context of a canvas to it.

Third, I need to know how to make a second smaller DIB in memory which I can scaleblt the first to to make a smaller copy of the image I want to display.

And finally, I need to know how to bitblt the smaller DIB to the DIB on the screen.

I guess I also need to know how to change the size of the DIB on the screen, or at least, how to free it and create a new one.


This is why I need to do this:

I am making a program that displays a texture. I want the user to be able to zoom in and out of this texture.

But on top of this zoomed texture, I want to draw a polygon, and I don't want the polygon to also be scaled.

So, what I need to do in simple terms is load an image, make a copy of it, scale the copy down, draw a polygon on top of the scaled copy, then copy the scaled copy to the screen.


I can't do this with Blitz commands because it is too slow, even with a custom image scaling function I wrote that only scales images in multiples of the original size.

But I found that I can scale a canvas with GDI commands and the image scales instantly. So I'm guessing that if I use the GDI commands to do the scaling, it will use hardware acceleration to do it and be very fast.


Kevin_(Posted 2005) [#6]
sswift, I must admit, I admire your persistance on this problem.

Have you tried the OpenGLDirect functions. They allow you to use your 3D card to perform 2d functions which will allow you to do a fast bitmap scale.

http://www.blitzcoder.com/cgi-bin/showcase/showcase_showentry.pl?id=peter__scheutz02202003193552&comments=no


sswift(Posted 2005) [#7]
Prof:
Nice idea, but there's way too much crap in there. I'll figure out how to make this GDI stuff work long before figuring that out and I won't have huge source files with tons of functions I don't need clogging my program up. :-)


Mr. Write Errors Man(Posted 2005) [#8]
You can create and use DIBs with GDI API functions like CreateDIBSection(), GetDIBits(), SetDIBits(), SetDIBitsToDevice() and StretchDIBits().

See e.g. www.allapi.net for Visual Basic examples on how to use these functions.


Mr. Write Errors Man(Posted 2005) [#9]
I am still new to B+ but am I right that there is no StretchBlt equivalent in Blitz+? You need to resize the image itself?

If so, it's a surprising shortcoming.


Mr. Write Errors Man(Posted 2005) [#10]
If you have hDC handle of the canvas, can't you simply use StretchBlt so that both source and target hDC is the one of the canvas?

Something like:

1. Draw the picture on the canvas in 1:1.
2. Call StretchBlt on the canvas to zoom part of the canvas to cover all the canvas.
2b. If user zooms out more than 1:1 then draw some border on the rest of the canvas.
3. Draw the polygon.


sswift(Posted 2005) [#11]
"You can create and use DIBs with GDI API functions like CreateDIBSection(), GetDIBits(), SetDIBits(), SetDIBitsToDevice() and StretchDIBits()."

I know that, I've been researching it extensively, but there's a lot more to it than that and I'm only barely beginning to grasp what device contexts are, and what can be blitted onto what and how and such. There is a ton of stuff to learn to do even the most basic bitmap manipulation. At this point I don't even know how to modify the pixels in a DIB.


"If you have hDC handle of the canvas, can't you simply use StretchBlt so that both source and target hDC is the one of the canvas?"

I have tried drawing pixels to the canvas DC using SetPixelV(), and I have noticed that any time a window moves over the canvas, or I flip it, all those pixels dossapear.

I do not think your suggestion will work therefore, because I think Blitz is buffering the image data for the canvas outside the canvas, and updating the image data from this buffer whenever the canvas needs to redraw. As I cannot access this offscreen buffer, I cannot modify it, and any changes I make directly to the canvas will be erased at some points... And I can't redrawfast enough to avoid flicker in those cases.

So I need to avoid the canvas altogether.


Mr. Write Errors Man(Posted 2005) [#12]
I see. I agree that DC etc are hard to grasp at first. I hope you have some language you can toy with them in practice to make the learning faster.

With GetDIBits() you get the pixel data of a DIB as a byte array. Then you simply alter the byte array as you wish. Once you are done you can draw the DIB (the byte array you edited) with functions like StretchDIBits() or SetDIBitsToDevice().

Yeah, DIB drawings most likely won't "stick" in Blitz canvas. Are you sure you really need them to stick? Will your window have other windows on top of it by design?

I am still too new to Blitz to know how fast it would be to make a Blitz image with the DIB byte array you have. Some time ago I checked some alpha blending routines from code archives and they were surprisingly fast, considering the way they worked. Judging from that experience I would expect simple byte copy to be pretty quick... something like 256 or 512 sized textures could be done multiple times per second.


sswift(Posted 2005) [#13]
"Are you sure you really need them to stick? Will your window have other windows on top of it by design?"

Moving the scrollbars also causes problems. Moving them causes the canvas to redraw, and no drawing operations will take place while they are being moved, so the selection area dissapears completely.

I also have to flip the canvas to erase my quad... Though I suppose I might be able to just save the pixels and redraw them.

But even simply drawing to the canvas has problems. For some reason when I draw my vertices on top of my lines, some of the pixels of the lines decide to draw on top of my vertices. I can't figure THAT one out, and I'm almost positive it's not a bug in my rectangle drawing code. That code is pretty simple.

Anyway, I don't want to do a half-assed job of it. I'm fairly sure I can get it working the way I want it to, it's just a matter of figuting out the GDI calls.

Right now I don't even know how to make a DIB display in a window though. That at least would point me in the right direction.

"I am still too new to Blitz to know how fast it would be to make a Blitz image with the DIB byte array you have."

I don't need it to be super fast. I'm counting on windows to be super fast. And I'm not dealing with measly 256x256 images, I'm dealing with 2048x2048 images.

I plan to fill the array for displaying the image, and then use the windows functions to make copies of it and scale the copies and display them. So after theinitial filling of the image with the data, which should not take a noticeable amount of time, everything should go fast.