Author Topic: Visual Programming  (Read 2434 times)

Offline White Claw

  • Hero Member
  • *****
  • Posts: 854
Visual Programming
« on: March 26, 2007, 07:55:44 PM »
For those of you with visual programming experience, have you developed a method for double buffering. I'm getting the hang of dealing with bitmaps under Visual C++, but the double buffering thing it still escaping me a bit because of the way windows handles bitmaps (with handles) and DIBs. I have a bunch of old routines from plain C that I made working at the direct memory level (and even embedded in the video card), so I've got a good starting point of experience. Bitmaps seem to be the easiest to deal with natively under Windows, but you can't get to the bits without a handle.

I've been trying to figure out the DIBs, but they're a bit confusing too. I see you can access the bits directly to make modifications, but how can you get a double buffer set up. Do you have to pull from the global heap and manually assemble the DIB? Can you use StretchDIBit to blt one DIB into another DIB if needed?

It would be nice to be able to blt some graphics into the double buffer when speed isn't needed, but still be able to blast other graphics in manually when necessary. Are DIBs the way to go here or am I way off base? If I do just create a double buffer that's just empty memory (i.e. not a DIB), how do I get it onto the screen? Or is there a way to attach it to a bitmap or DIB after the fact so I can blt it to the client window?

Offline BlackBox

  • Administrator
  • Hero Member
  • *****
  • Posts: 3093
Visual Programming
« Reply #1 on: April 04, 2007, 01:07:34 PM »
Well, if you want to create a buffer, you're best to just create an offscreen device context. You can access it the exact same way you do the window's client area during painting, using BitBlt and any other command that works with DCs. You then create a bitmap the size of the screen, giving you a usable area to draw to (you can then blit the entire DC to the screen, effectively accomplishing double buffering)

It's a lot easier than drawing to DIBs for a buffer (actually, the only time it really makes sense to use DIBs is if you're loading data from a file)

Code: [Select]
HDC hdc;
HBITMAP hbmp, hbmpOld;

// Create a device context compatible with the screen
hdc = CreateCompatibleDC(NULL);

if (hdc)
{
   // Create a bitmap the size of the screen, and select it into the DC (assuming 1024x768 here, change values to suit)
   hbmp = CreateCompatibleBitmap(hdc, 1024, 768);
   if (hbmp)
   {
      hbmpOld = SelectObject(hdc, hbmp);
      // you can now use this memory DC as long as you want. it persists until you destroy it
   } else
      DeleteDC(hdc);
}

// use it here...
BitBlt(hdc, ....);

// clean-up
// select the old bitmap back in
SelectObject(hdc, hbmpOld);

// delete the screen size bitmap that was created
DeleteObject(hbmp);

// delete the offscreen DC
DeleteDC(hdc);

And there you have it. A *lot* easier than using DIBs.

Btw, you can select a DIB into a device context just as easily as a standard bitmap. That way, you can easily call BitBlt to draw it elsewhere (in this case, you can save the CreateCompatibleBitmap step because the bitmap is coming from the DIB section you already have set up, and just go straight away and select it into the device context).

-- A little note about Device Contexts, if you're not familiar. A device context in windows is basically a virtual representation of a device and all the modes it has set. A screen has a device context assigned to it, as do other bitmap-output devices (printers, etc). The client area of a window also can have a DC assigned to it (which is usually accessed via BeginPaint / EndPaint calls or GetDC / ReleaseDC calls).

A DC has objects 'selected' into it, such as bitmaps, pens, brushes, etc. All the primitives drawing functions in win32 deal with DC's. (BitBlt, LineTo, Polyline, Circle, TextOut, DrawText, ... so on).

It is possible to obtain the Device Context for the entire screen (usually it's only used to get the physical characteristics of the screen, I've never heard about drawing on it directly. If you need to draw directly to the entire screen surface, it's probably best to use DirectX or OpenGL).
« Last Edit: April 04, 2007, 01:13:24 PM by op2hacker »

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Visual Programming
« Reply #2 on: April 04, 2007, 06:46:37 PM »
I've drawn directly to the screen. Not much reason for it, other than you can. Draw outside the borders of any of your windows. :)

The one thing I learned from working with the GDI graphics API, is that I never want to have to use it again. The documentation seemed pretty obscure, and I frequently found myself with questions the documentation didn't seem to address. It left me wondering about whether or not certain code would actually make sense on all systems, or might just break for someone unknown reason because it didn't meet a standard that wasn't clear. There's also the whole device indepence thing. It's nice being able to print to the screen or print to a printer in the same way, but it seems a little overly general sometimes. There are a lot of things you usually don't want to have to deal with when drawing to the screen. Especially when it comes to efficiency. If you have a DIB (Device Independet Bitmap) than it's quite possible that it's color depth doesn't match the screen's color depth. You either have to translate on the fly while copying, which can be slow, or you have to work your graphics into the right form. Depending on how you do it, it could easily up the memory requirements. The worst case I had to deal with was when editing images at a different color depth than the display was. I had to keep the original data in memory to work with it properly, and not lose precision, but had to keep an extra copy around to draw the results fast when scrolling around. That extra copy had to be updated everytime the original changed. I guess it wouldn't be as bad if all you wanted was display, and no graphics editing capabilities though.

I worked with it long enough to understand it all once. But I think I've pretty much forgotten most of it now, and I never want to go back. DirectX strikes me as a lot easier to understand and use. There's just the slight chance that a Windows machine won't have DirectX installed.
 

Offline White Claw

  • Hero Member
  • *****
  • Posts: 854
Visual Programming
« Reply #3 on: April 05, 2007, 09:43:17 AM »
I wasn't necessarily trying to write directly to the screen. My issue with the double buffer is how to deal with using a bitmap. I'll have to go back an look more, but can you write directly into a bitmap? The documentation I was reading suggested DIBs because you can access the bits directly to make changes to the image.

I tried messing with DirectX, but that documentation was even more confusing to me. Almost everything I read about was all 3D related and didn't talk about simple device creation and sprite manipulation.

(Thanks for the snippet of code. That does help a little.)

Offline BlackBox

  • Administrator
  • Hero Member
  • *****
  • Posts: 3093
Visual Programming
« Reply #4 on: April 05, 2007, 10:16:56 AM »
Quote
I'll have to go back an look more, but can you write directly into a bitmap? The documentation I was reading suggested DIBs because you can access the bits directly to make changes to the image.
Yes you can. When you call CreateDIBSection() (which is the only way to create a DIB in windows that I can remember. The other functions are named very incorrectly -- CreateDIBitmap() actually creates a device dependent bitmap) it will give you a pointer back to the raw bitmap bits. If you keep that pointer, you can use it later to modify the bitmap data directly (which *will* be of the format that you specify in the BITMAPINFO structure -- windows does not change it into device-dependent formats).

I believe there are other functions that let you retrieve and set bits (GetDIBits / SetDIBits possibly?) They might be for DDBs though (again, the windows GDI is horrible).

Oh, by the way, I think some weird things happen if you directly write a bitmap while it's selected into a device context. And as Hooman pointed out, there is a slight performance decrease when you do this (I believe windows might even make a copy behind the scenes when a DIB is selected into a device context, and tries to map all the colors into a DDB if it's a palletized device)

As far as drawing to the entire screen goes. If I need to do this, I usually use SDL (it's a crossplatform 2D graphics/sound/input library). It was very easy to understand and I was able to start using it in after about 15 or 30 minutes of reading. I do like the fact that it's cross plaform, and you don't have to modify your code to compile it on a different platform (the SDL API works the exact same way on different platforms. It has file abstraction as well I believe (which isn't documented, but was really easy to understand from the header file) if you don't want to use the stdio way of doing things).

If you want to use DirectX to perform 2d drawing, I suggest just reading about DirectDraw from DirectX 7 (yes, it's old, but it's the last version of DirectX that has DirectDraw (which is just a hardware-accelerated 2d drawing package)). There are ways to do it with newer versions of DirectX (and with OpenGL as well), I haven't really looked into it much however.

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Visual Programming
« Reply #5 on: April 05, 2007, 06:51:55 PM »
Yeah, the 2D part of DirectX seems to have been dropped in later versions. Just create objects from earlier versions of DirectX. The 2D portion (DirectDraw) is fairly straighforward.

Sounds like Windows makes extra copies with DIBs to me too. I also wonder what happens after you've finished a write to the memory. It might need to rescan and convert the whole thing over again.

But, don't lose hope. It is entirely possible to do.
 

Offline White Claw

  • Hero Member
  • *****
  • Posts: 854
Visual Programming
« Reply #6 on: April 10, 2007, 08:19:19 PM »
I guess that's why I wanted to double buffer. So that I could modify the contents of the "bitmap" buffer and then select it to the client window's DC. I thought I downloaded DX7 to take a look at it (because that's what I was planning the first time around) but maybe I got a different version.

Anyway, I also think that a bitmap might get copied when selected into a DC, but I'm not completely sure. Because if you delete a bitmap that's selected into the DC, it causes serious problems. And I am pretty sure that if you're using palettized pictures, it does have to do some palette mapping (as was posted). But I think newer versions of windows set aside sections of the main palette so that the mapping isn't so crazy. (That's how it seems, but I'm not sure.)

I guess I'm slightly concerned about performance, but I also want to learn some API stuff in the process. I'll have to take a look at SDL too. I think I've heard of it, but I've not bothered to download it and check it out.