My MFC/C++ application renders a sequence of 320x240
bitmap images onto the screen using bitblt. More accurately,
I have a CDialog-derived object on which I have placed a
Picture control. I associate a bitmap with this control, which is
referred to below in the code as the "stage" object. My app
bitblits a sequence of bitmaps onto the stage. And it works fine,
which is a miracle since I understand very little about the GDI
api. But now I need to scale each image to appear larger on the
screen, full screen, if possible. I know this is going to look awful.
But I need to do it anyway. And I am hoping that I don't have to
write the scaler myself. I must avoid DirectX if it means my
Win98 user will need to do a download before running my app.
Question 1: Is there a way with the GDI api to scale up my
320x240 image on the display screen to say 640x480?
Question 2: What if I didn't mind that the resulting image
would look awful and I wanted to scale up my 320x240 image
to the user's full screen. Is that possible?
Question 3: How do I get the coordinates of the user's screen?
For the full-screen rendering scenario, is it possible to just
change the user's screen resolution to my image size? (I know
I can't change the resolution of the user's screen down as low
as 320x240. But what if my native image size was 640x480, is
changing the user's screen resolution down to 640x480 the best
way to render that image full-screen?)
When I say "scale" I mean that I would double the image size on
the user's screen by taking each pixel, X, and create 3 neighbor
pixels, Y, all with that same X pixel value,
X -- becomes -> XY
YY
I just assumed that there was some GDI function for doing this
better and faster than me writing it from scratch. But I can't
find such a scaling function.
So that you will know how I am currently using GDI, I have listed
my rendering code below.
Thank you very much for your ideas and thoughts,
~Michael.
Move Networks
Use a mirror: kcod...@skrowtenevom.moc
-----------------------------------------------------------------
This is how I currently do the rendering for
one frame:
// -----------------------------------------------------------------
// The following variables are NOT declarations. I am just
// listing variables that were set up elsewhere, and for
// clarity, indicating their types.
// ----------------------------------------------------------------
CStatic stage;
RECT rectStage;
CPoint topLeftPoint;
CWnd *pConsoleCWnd;
HWND hWnd;
HDC hdcWnd;
HDC hdcBlit;
HANDLE hDibSection;
BITMAPINFOHEADER *pbmiHeader;
CPlayerConsole *pPlayerConsole;
BYTE *pbVideoFormat;
BYTE *pbBits;
LPSTR lpMyFrameData;
// -------------------------------------------------------------
// Code to set up the render stage.
// ------------------------------------------------------------
stage.GetClientRect(&rectStage);
stage.ClientToScreen(&rectStage);
stage.ScreenToClient(&rectStage);
topLeftPoint.x = stage.left;
topLeftPoint.y = stage.top;
HWND hWnd = pPlayerConsole->m_pConsoleCWnd->m_hWnd;
WMVIDEOINFOHEADER *pvih = pbVideoFormat;
BITMAPINFOHEADER *pbmi = &(pvih->bmiHeader);
// Save the bitmap info header into a member variable for later use
CopyBIH(&pbmiHeader, pbmi);
//Get the DC
hdcWnd = GetDC(hWnd);
// Create a compatible DC
hdcBlit = CreateCompatibleDC(hdcWnd);
// Create DIBSection
hDibSection = CreateDIBSection(hdcBlit,pbmiHeader,DIB_RGB_COLORS,&pbBits,NULL,NULL);
// -------------------------------------------------------
// Code to "render" a single frame
// -------------------------------------------------------
memcpy(pbBits, lpMyFrameData, dwBufferLength);
HGDIOBJ hGDIObj = SelectObject(hdcBlit, hDibSection);
BitBlit(hdcWnd,
topLeftPoint.x,
topLeftPoint.y,
pbmiHeader->biWidth,
pbmiHeader->biHeight,
hdcBlit,
0,
0,
SRCCOPY);
Yes, use StretchBlt() in place of BitBlt().
> Question 2: What if I didn't mind that the resulting image
> would look awful and I wanted to scale up my 320x240 image
> to the user's full screen. Is that possible?
Yes, see above.
> Question 3: How do I get the coordinates of the user's screen?
To get the size of the primary display then you can use GetDeviceCaps() passing in HORZRES and VERTRES flags. This however doesn't
take into account any registered toolbars such as the start bar, Office, trillian/ICQ etc, for that use SystemParametersInfo() with
the SPI_GETWORKAREA flag. Both of these methods however only take into account single displays, to support multi-monitor systems
use EnumDisplayMonitors() and GetMonitorInfo().
> For the full-screen rendering scenario, is it possible to just
> change the user's screen resolution to my image size? (I know
> I can't change the resolution of the user's screen down as low
> as 320x240. But what if my native image size was 640x480, is
> changing the user's screen resolution down to 640x480 the best
> way to render that image full-screen?)
Definitely not, most users would get somewhat annoyed if your application changed their settings every time it felt like it, and it
would likely find it's way to the recycle bin pretty quickly.
Hope this helps,
Mike
- Microsoft Visual Basic MVP -
E-Mail: ED...@mvps.org
WWW: Http://www.mvps.org/EDais/
Thanks for your help!!
> > Question 1: Is there a way with the GDI api to scale up my
> > 320x240 image on the display screen to say 640x480?
>
> Yes, use StretchBlt() in place of BitBlt().
This works great except for one thing. The only part of the image
that I now see is the fraction contained within the original size of my
CDialog window, which I didn't resize before I called stretchblt.
I didn't realize that I needed to resize my dialog box to big big enough
to hold my stretchblt'd image. I thought it would resize automatically,
which now sounds pretty dumb.
> > Question 3: How do I get the coordinates of the user's screen?
>
> To get the size of the primary display then you can use GetDeviceCaps()
> passing in HORZRES and VERTRES flags. This however doesn't
> take into account any registered toolbars such as the start bar, Office,
> trillian/ICQ etc, for that use SystemParametersInfo() with the
> SPI_GETWORKAREA flag. Both of these methods however only
> take into account single displays, to support multi-monitor systems
> use EnumDisplayMonitors() and GetMonitorInfo().
Great. So I now use GetDeviceCaps() to get my screen coordinates, which
I use as the size of the destination render rectangle in StretchBlt. In the
fullscreen
case I only want the CStatic render surface to show on the screen and not
the
whole dialog window. Do I need to change that surface size, or do I resize
my Dialog window to make that surface be the right size and the other
controls
on my Dialog are just pushed off the screen?
Thanks again for your help,
~Michael.
Yep, resize the window before drawing to it.
> Great. So I now use GetDeviceCaps() to get my screen coordinates, which
> I use as the size of the destination render rectangle in StretchBlt. In the fullscreen
> case I only want the CStatic render surface to show on the screen and not the
> whole dialog window. Do I need to change that surface size, or do I resize
> my Dialog window to make that surface be the right size and the other controls
> on my Dialog are just pushed off the screen?
Normally what I'd do in this case is to have a second window which display's full-screen and just display instead, or use
SetParent() and drop the CSatic window onto the desktop.