Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - cal1.jpg

Introduction

This article explains the basics of pixel graphics programming on Pocket PC/SmartPhone devices. I've collected the information you may need when starting graphics programming on Pocket PC. I've written an example Caleidoscope application, that demonstrates how to make your window full-screen, and how to access the video memory of your handheld device. I'm not going to discuss how to program graphics using the Windows GDI functions. I think it is a lot faster, yet relatively simple, to put your pixels right into the video memory. I'm aware that there are some free and commercial graphics libraries for Windows Mobile. However, they might use device-dependent tricks, and they might or might not be free for personal use. I think once you get an understanding of how Windows Mobile graphics works, you won't want to pay for any libraries. I admit some libraries might be faster than the approach explained here, but I really had no speed problems with any of my PDAs. And, the code still could be optimized for speed in many ways.

I've put all graphics handling routines into the ZGfx class, which can easily be used in other pixel-graphics applications, both on Pocket PC and SmartPhone. This class is not intended to be a complete graphics library; it is merely a set of handy routines to speed up graphics development.

I assume you are familiar with Visual Studio and the C language, I also assume you know what a pointer and a window handle is.

Pixels, pitches, and frame buffers

Pocket PC/SmartPhone does not support selectable video modes; instead, there are fixed, device-dependent video modes. As of today (October 2006), most  Pocket PC devices that you can get your hands on have one of these resolutions:

And SmartPhones can be:

There are also square screen devs (QGVA: 240x240, VGA: 480x480). A couple of things about pixel formats. I'll discuss the 16 bpp format called RGB-565. There are (were?) other, older pixel formats and I'm sure there will be soon 24 bpp devices with RGB-888 colors. So be careful with assumptions and always check the hardware your program runs on, and be prepared that new devices might support different pixel formats.

So, these days the majority of devices support 16 bits per pixel: 5 bits red, 6 bits green and 5 bits blue. 16 bits make 2 bytes, and here is how are they stored in video memory:

A value of 0xffff means a white pixel, a value of 0x0000 means black, and 0xf800 means red. Simple, isn't it? Here is a macro that converts a 24-bit RGB color to RGB-565:

#define RGB_TO_565(r,g,b) (WORD) ((r & 0xf8 )<<8) | ((g&0xfc)<<3) | ((b&0xf8)>>3)

Now, what do we need to display a pixel? The answer is, write a 16-bit value into the graphics memory. The graphics memory is called the frame buffer. Once you have the frame buffer pointer, you can write pixel data directly to video memory. What is the frame buffer address? This depends on the device. There are three documented ways to get the desired frame buffer address. I recommend combining them, so in case one is not supported, there is still another to try. These ways are:

  1. Using the ExtEscape() GDI function. This Windows function returns the frame buffer address along with other parameters. It's simple, but it's not the best approach and it's likely that future devices will not support this. 
  2. Using GAPI. GAPI is a graphics helper library (GX.dll) provided by Microsoft. Works fine with QVGA devices, but does not support the capabilities of VGA devices (only pixel doubling, which scales the display up), and it seems Microsoft will not update it any more.
  3. Using DirectDraw. This is the best option, but it is only supported on Windows Mobile 5.0 devices.

I recommend using DirectDraw, and if it's not available on the device, using the others as a fallback. I'll show an example of these methods later.

There is one more thing to be aware of: pitches. I would assume, if I have a frame buffer pointer, and a certain fixed resolution, I can fill the screen, line by line using code like this:

int x, y;
WORD *p;

p=GetFramebuffer();

for(x=0; x<WIDTH; x++)
 for(y=0; y<HEIGHT; y++)
  *p++=0xffff;

This assumes that if you increment the buffer pointer by 2 (the size of a WORD), the pointer moves right one pixel. Also, this assumes that if you add WIDTH * 2, the pointer moves one pixel down. These assumptions are wrong, because of different frame buffer orientations. Without going into very much detail, what you have to keep in mind is:

  1. The number of bytes to add to the pointer to move to the next pixel in a row is called XPitch.
  2. The number of bytes to add to move to the next row (that is, one pixel down) is called YPitch.

So when calculating the pointer for pixel position (x, y), you have to include the pitch values:

pxy = pbuffer + x * xpitch + y * ypitch;

Let's see an example. The framebuffer pointer could be 0x10000000. For a VGA device, X and Y pitch values could be 2 and 960 (0x3c0). So the address of pixel (1,1) is:

0x10000000 + 1 * 2 + 1 * 960 = 0x100003c2.

On most systems, XPitch is 2 (the size of a pixel, in bytes). But in all cases, you have to query the pitch values. Pitch values also can be negative, so use a signed variable! How to get the pitch values? I'll explain in the next section.

Initializing graphics

I'll summarize the steps necessary to display some graphics:

I think the first step needs no explanation; if you need help, use the Visual Studio AppWizard. It will create a fully functional application along with a nice window for you.

To make the window full-screen, let's use the following code:

RECT rc;

//hide task bar and other icons

SHFullScreen(g_hWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | 
             SHFS_HIDESIPBUTTON);

//resize window to cover screen

SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), 
        GetSystemMetrics(SM_CYSCREEN));
MoveWindow(g_hWnd, rc.left, rc.top, rc.right-rc.left, 
           rc.bottom-rc.top, false);

The code above will hide the Task Bar and the Start icon, by moving them "behind" your window, then, it will resize the window to cover the entire screen. Let's get device-dependent parameters. As said before, this can be done three ways. The first and in my opinion the simplest is, the Windows GDI function, ExtEscape(). Here is how I use it in the graphics class:

bool ZGfx::GfxInitRawFrameBufferAccess()
{
    RawFrameBufferInfo rfbi;
    HDC hdc;
    bool retval;
    retval=false;
    hdc=GetDC(m_hwnd);
    if(hdc)
    {
        if(ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, 0, 
            sizeof(RawFrameBufferInfo), (char *) &rfbi))
        {
            if(rfbi.wFormat==FORMAT_565)
            {
                m_framebufwidth=rfbi.cxPixels; //store width

                m_framebufheight=rfbi.cyPixels; //store height


                m_xpitch=rfbi.cxStride; //store xpitch


                m_ypitch=rfbi.cyStride; //store ypitch


                m_cbpp=rfbi.wBPP; //store bits per pixel value


                m_framebuf=rfbi.pFramePointer; //store pointer


                retval=true;
            }
        }
        ReleaseDC(m_hwnd,hdc);
    }
    return retval;
}

The call returns all data in a structure, which is quite handy. The RawFrameBufferInfo structure is defined in GX.h. Please note that not all devices support this simple method. Also note that for performance reasons, it's recommended to use DirectDraw if it's available.

Let's have a look at DirectDraw. This approach needs a bit of caution. Even 1-2 year old devices running Pocket PC 2003 operating system do not support this feature. So if you want to be compatible with these devices (and you surely do!), you can't link to ddraw.dll (the DirectDraw library). This means, you can't call DirectDraw functions directly, as you usually call any other system function! Here is a typical way of calling a Windows API function:

MessageBox(hWnd, "Text", "Caption", MB_OK);

You simply type the function name, along with the parameters. I bet you've done this a million times before. As a result, the compiler/linker will include an import reference in your EXE file, to the system .dll file that contains the MessageBox() function. If the referenced .dll file can not be found, Windows will not load your EXE. In other words, an EXE containing DirectDraw calls, won't start if a device does not have DirectDraw, because there will be no ddraw.dll on the system. How to call DirectDraw while maintaining the compatibility with pre-WM5 devices? The answer is, you have to load the DirectDraw dll file manually using the LoadLibrary() API, then you have to find the entry point of the required DirectDraw function (namely, DirectDrawCreate()) with GetProcAddress(), then call the function through a pointer. No panic, it's simpler than it sounds:

//declare the DirectDrawCreate() function

typedef LONG (*DIRECTDRAWCREATE)(LPGUID, LPUNKNOWN *, LPUNKNOWN *); 

...
//load the library and look up the function


bool ZGfx::GfxLoadDirectDraw()
{
    m_hDD=LoadLibrary(L"ddraw.dll");
    if(m_hDD)
    {
        m_DirectDrawCreate=(DIRECTDRAWCREATE)
            GetProcAddress(m_hDD, L"DirectDrawCreate");
        return true;
    }
    else return false;
}

(Note: To use DirectDraw, you need the DirectDraw main header file, ddraw.h from the Windows Mobile 5.0 SDK. It's located in the ZGfx folder of the source codes pack. But to use the ZGfx class, there's no need to use the WM 5 SDK for your project. The Pocket PC 2003 SDK will do just fine. The Caleidoscope example uses the Pocket PC 2003 SDK, too.)

Okay, we have loaded DirectDraw, now let's get the display properties:

DIRECTDRAWCREATE m_DirectDrawCreate;    //our function declaration


IDirectDraw *m_pdd;
DDSURFACEDESC m_ddsd;
IDirectDrawSurface *m_psurf; 

...

bool ZGfx::GfxInitDirectDraw()
{
LONG hr;
    
    //create surface

    hr=m_DirectDrawCreate(0, (IUnknown **)&m_pdd, 0);
    if(hr!=DD_OK)
     return false;    //failed

    hr=m_pdd->SetCooperativeLevel(m_hwnd, DDSCL_FULLSCREEN);
    if(hr!=DD_OK)
    {
        m_pdd->Release();
        m_pdd=0;
        return false;
    }
    //create a simple buffer

    memset((void *)&m_ddsd, 0, sizeof(m_ddsd));
    m_ddsd.dwSize = sizeof(m_ddsd);
    m_ddsd.dwFlags = DDSD_CAPS;
    //no back buffering, only use the visible display area

    m_ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    //create surface (entire screen)


    hr=m_pdd->CreateSurface(&m_ddsd, &m_psurf, NULL);
    if(hr!=DD_OK )
    {
        m_pdd->Release();
        m_pdd=0;
        return false;
    }
    //get parameters with locking

    
    memset((void *)&m_ddsd, 0, sizeof(m_ddsd));
    m_ddsd.dwSize = sizeof(m_ddsd);
    hr=m_psurf->Lock(0, &m_ddsd, DDLOCK_WAITNOTBUSY, 0);
    if(hr!=DD_OK)
    {
        //locking failed!



        m_psurf->Release();
        m_psurf=0;
        m_pdd->Release();
        m_pdd=0;
        return false;
    }
    //store data

    m_cbpp=m_ddsd.ddpfPixelFormat.dwRGBBitCount;
    m_xpitch=m_ddsd.lXPitch;
    m_ypitch=m_ddsd.lPitch;
    m_framebufwidth=m_ddsd.dwWidth;
    m_framebufheight=m_ddsd.dwHeight;
    //finally unlock surface


    m_psurf->Unlock(0);
    return true;
}

The code above creates a simple buffer with size of the entire screen. It's important to note that with DirectDraw, if you want to do anything with the display buffer, first you have to call the Lock() function, and once you're finished you must call Unlock(). In other words, you don't get a buffer pointer unless you lock the buffer! The code above needs locking only to get screen parameters, it does not draw anything yet.

The third way of getting display props is using GAPI. GAPI is Microsoft's graphics helper library, located in GX.dll. MSDN documentation describes all structures and functions provided by GAPI, so I'm not going into details. For initializing graphics, you only need two functions: GXGetDisplayProperties() and GXBeginDraw(). The former function returns a structure of type GXDisplayProperties. This structure contains the screen width, height values as well as the pitches. The second function returns a void *, which points to the frame buffer. When using GAPI, you must call GXBeginDraw() only before updating the screen, and after the drawing work is done, you must call GXEndDraw(). (This is the same idea as with DirectDraw locking.)

This is how I perform GAPI init:

bool ZGfx::GfxInitGAPI()
{
GXDisplayProperties prop;
int sw, sh;
    prop=m_GXGetDisplayProperties();
    m_cbpp=prop.cBPP;
    m_ypitch=prop.cbyPitch;
    m_xpitch=prop.cbxPitch;
    m_framebufheight=prop.cyHeight;
    m_framebufwidth=prop.cxWidth;
    if(!(prop.ffFormat&kfDirect565)) //verify pixel format


     return false; 
    //if it is a vga device, we have to check 

    //if GAPI's not messing it up


    sw=GetSystemMetrics(SM_CXSCREEN);
    sh=GetSystemMetrics(SM_CYSCREEN);
    if(sw!=prop.cxWidth || sh!=prop.cyHeight)
     return false;
    return true;
}
 

Don't use GAPI if it returns a screen resolution other than reported by GetSystemMetrics(). Note that GAPI does not support VGA devices. It supports a technique called pixel doubling. This means that the 240x320 display can be scaled up to 480x640 on a VGA device. But it's not VGA graphics!

Using the ZGfx class

The purpose of this class is to provide a basic level of abstraction and to make it easier to access the video memory. The class creates a software buffer, where all drawing can be performed. It also takes care of GAPI or DirectDraw initialization, whichever appropriate. You can safely assume that the software buffer XPitch will always be 2 (remember, the size of a pixel in bytes). Also you can assume that YPitch will be, two times the buffer width, that is, 960 for a 480-pixel wide buffer. To use the class, first add the zgfx.h and zgfx.cpp files to your project. For the .cpp file, disable using precompiled headers in the file properties section. Then add a global variable of type ZGfx to your application:

ZGfx g_gfx;

After your main application window has been created, you need to create a display buffer:

GfxRetval gr;
GfxSubsys gs;

gr=g_gfx.GfxCreateSurface(g_hWnd, g_screen_w, g_screen_h, &gs);

Parameters are: handle to the main window, requested buffer width and height, and a variable for the returned subsystem type. The return value will indicate success or failure (see the GfxRetval enum), and in case of success, the used subsystem (Raw frame buffer access, GAPI, or DirectDraw) will be returned (GfxSubsys). The routine will use DirectDraw (the best option) if available; if not, it will fall back to GAPI or Raw frame buffer access.

If the buffer is smaller than the screen resolution, it will be centered on the screen. A buffer cannot be larger than the device resolution. You can clear the entire display area, even if it is larger than your buffer, with the GfxClearHWBuffer() or GfxFillHWBuffer() functions. The latter takes a RGB-565 color value, which can be created with the RGB_TO_565() macro. To clear the software buffer, use the GfxClearScreen() function. The function takes a bool parameter that specifies whether the display should be updated. To update the display (that is, copy the software buffer contents to the video memory), use the GfxUpdateScreen() function.

You can access the software buffer with the GfxGetPixelAddress() function:

unsigned short *pbuffer;
GfxRetval gr;
gr=g_gfx.GfxGetPixelAddress(0, 0, &pbuffer);

The call above will return the address of pixel (0,0), that is, the beginning of the buffer (the upper-left corner). The most important functions of the class are:

There is a number of handy functions that should be added, I agree. For example, text output, drawing shapes or displaying bitmaps. I've written separate routines for these tasks, but they should be integrated into the graphics class.

To use this class in your application, you have to apply a slight modification to your window message handlers. Replace the WM_PAINT handler with this piece of code:

 case WM_PAINT: 
 {
    if(g_gfx.GfxIsInitialized())
    {
        ValidateRect(hWnd, 0); //no repaint


    }
    else
    {
        //gfx not yet inited, let windows draw


        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    break;
 } 

I also recommend handling the WM_SETFOCUS and WM_KILLFOCUS messages, so if eg. a low battery warning pops up, you can suspend and resume drawing operations properly:

 case WM_SETFOCUS:
 {
    if(g_gfx.GfxIsInitialized())
    {
        g_gfx.GfxResume();
        g_gfx.GfxClearHWBuffer(); //clear & redraw screen


        g_gfx.GfxUpdateScreen();
    }
    g_focus++;
    break;
 }
 case WM_KILLFOCUS:
 {
    g_focus--;
    g_gfx.GfxSuspend();
    break;
 }

About the Caleidoscope application

I've provided a sample graphics application created with Visual Studio 2005, which draws a symmetric kaleidoscope-like image. This program illustrates the use of the graphics functions. I've commented the code so it should be a quick and easy reading. The application is based on a Windows GUI program created by the Visual Studio AppWizard. It creates an application window, and then periodically calls the DrawFrame() function, which renders the kaleidoscope image. The displayed gems are in fact small, filled rectangles. The gems are moved slowly in the upper-left quarter of the screen, and this quarter is mirrored to the right, pixel-by-pixel. Then the upper half of the screen is mirrored bottom, line by line. The DoMirror() function is a good example of pixel and line manipulations using pointers, and block movement with memcpy(). Upon key press or screen tap, the application will exit. It should work not only on Pocket PC 2003 and Windows Mobile 5.0, but also on SmartPhone too, because it does not use anything device-specific.

TODOs

The graphics routines could be improved in a number of ways:

Any comments, suggestions are welcome.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralNot receiving WM_SETFOCUS
Edyb
3:32 11 Feb '09  
Hi again,

I have difficulties managing my app when system messages interfere (like incoming call). I receive the WM_KILLFOCUS message, i pause the app, but then no WM_SETFOCUS. The screen freezes with the last frame from my app, which is blended with the system window containing the "Incoming call..." message and the phone number calling.

Although the phone is not completely frozen (i can still receive phonecalls/messages), it can't update the screen and the app is still in suspend mode.

I've also tryed with the WM_ACTIVATE message, but no success.

Do you have any suggestions?

Thank you.
GeneralRe: Not receiving WM_SETFOCUS
Edyb
3:36 11 Feb '09  
P.S.: if i pop a message box on the WM_KILLFOCUS or WM_CANCEL messages, after i click OK on the message box, the app receives focus and it's all ok.
GeneralRe: Not receiving WM_SETFOCUS
dzolee
2:53 12 Feb '09  
I think you should have a look at Windows messages with Spy, maybe you could use WM_ACTIVATEAPP as a last resort?
GeneralRe: Not receiving WM_SETFOCUS
Edyb
4:50 12 Feb '09  
Sorry, it was a coding bug Smile ...it's all working fine now.

But i do have another issue, if i may...After ai exit the app, the status bar doesn't update...so i have, all over the start button and the rest of the icons, pieces of the texture that was last drawn in my app.

I tryed calling InvalidateRect() using the entire screen area on WM_DESTROY and WM_QUIT messages.

Any idea?

Thanks.
GeneralRe: Not receiving WM_SETFOCUS
dzolee
4:56 12 Feb '09  
Do you call ShowWindow with SW_HIDE on the taskbar at startup? And do you call it with SW_SHOW at exit?
GeneralRe: Not receiving WM_SETFOCUS
Edyb
23:01 12 Feb '09  
Ah, yes...thank you. After FindWindow and ShowWindow, i had to call InvalidateRect on the entire taskbar also. Now there are no more artifacts.

Cheers.
GeneralHow would you do clipping?
ajovanov
0:15 1 Sep '08  
How would you do clipping with Graphics Pixel Programming?
Sorry to ask so many questions but if you know something it would be greatly appreciated.
GeneralRe: How would you do clipping?
dzolee
2:06 1 Sep '08  
In your loop that displays pixels, check for every pixel if it is on the screen or should be clipped.
You can make it a bit faster if you first decide if there is anything to clip, or you can safely display the whole image.

For example:

if(screen_width >= image_width + destination_x &&
screen_height >= image_height + destination_y)
{
//fast display with no clipping
}
else {
//bit slower display with clipping
}

GeneralDDSCAPS_VIDEOMEMORY vs DDSCAPS_PRIMARYSURFACE
ajovanov
3:20 29 Aug '08  
Another question as I'm new to DDraw.
I've used DD with GDI functions but it's almost the same as GDI, speed wise.
If using pixel programming should I be using DDSCAPS_VIDEOMEMORY to boost performance or using your functions with DDSCAPS_PRIMARYSURFACE will be just fine. I need to draw a lot of Rects on the screen and blit lot of images?
If you have any taught on this let me know as I have't done low level graphics programming before.
GeneralRe: DDSCAPS_VIDEOMEMORY vs DDSCAPS_PRIMARYSURFACE
dzolee
3:23 29 Aug '08  
I'm not really into DirectDraw. My knowledge ends somewhere at getting the framebuffer pointer.
GeneralLandscape Mode
ajovanov
0:46 29 Aug '08  
Is there possibility to do Landscape mode in DDraw?
GeneralRe: Landscape Mode
Alex Cohn
23:59 13 Jan '09  
The native frame buffer ignores the landscape mode, so coordinates (0,0) point to the same pixel in portrait and landscape mode. But your application may understand the landscape mode and manage its rendering accordingly.
GeneralRMS
Edyb
3:39 25 Aug '08  
Hello,

Any idea on using RMS on windows mobile phones?

Thank you.
GeneralRe: RMS
dzolee
4:01 25 Aug '08  
Sorry, no, don't have the slightest inkling.
QuestionLoad Image, Put in the Buffer, and Show it
chernobyl
19:45 21 Jul '08  
Great tutorial for "painting" pixels on Windows Mobile screen!

How can we make an "image loader" for a list of images?

So, I just want to have a class for loading images governed by list in a text file and then buffer the loaded image into memory (so we will have pointer to the image data). Afterward, shows that buffered image on the screen.

Can we do this using DirectDraw or DirectShow?

Could you help me with code snippet? Thank you!

Dio
Generalmultiple draw surfaces
mdanh2002
4:44 15 Jun '08  
Hi

Thanks for your previous reply on my message about camera.

Now I have another question, I want to have 2 "layers" of graphics on screen. The bottom one shows the camera preview and the top one shows the application UI (buttons, text, graphics, etc.) What I want is that whatever actions taken to the bottom layer (which changes frequently since the preview needs to be refreshed) will not affect the top layer (which change less frequently). How do I do that? I have tried creating 2 different draw surfaces by calling GfxCreateSurface method of 2 different ZGfx objects but this results in application crash (access violation is displayed).

I hope you can provide me some hints. Thanks again.
GeneralRe: multiple draw surfaces
dzolee
11:45 15 Jun '08  
Basically you have a motion picture, or animation, and above that some buttons. You have to draw the UI on top of every frame. You can make it simpler if the preview is not fullscreen, so you have a designated area for the UI. A preview is a preview, after all.
GeneralRe: multiple draw surfaces
mdanh2002
3:50 16 Jun '08  
Thanks for the reply.

Do you have any idea if I can display the preview via hardware overlay and draw the UI using your method? So basically I do not have to redraw the UI after every frame. This is what most camera app is doing. The easily visible effect is that, if the user does a screenshot (or use a tool for remote viewing such as ActiveSync remote display), he will only be able to see the UI and not the preview, which is displayed via hardware overlay and is not accessible.
GeneralRe: multiple draw surfaces
dzolee
4:10 16 Jun '08  
Please make a screenshot with ActiveSync (or Remote Zoom In tool in VS2005).
Also make a photo if the remote screenshot does not look the same. You can upload the files to any free 1-click host like mediafire.com or rapidshare.de.
I would like to see this "UI over camera preview" stuff in action!
GeneralRe: multiple draw surfaces
mdanh2002
4:33 16 Jun '08  
I'll upload one soon if you want to, but meanwhile, you can try launching the camera app on your PocketPC and let the preview running. Use ActiveSync Remote Display to display and you'll only see the UI elements displayed on top of a black window. The preview is not captured!

Even simpler, try playing a video file with Windows Media Player on your desktop (not PocketPC) (in windowed mode) and do a PrintScreen. On most modern video cards, you won't be able to capture the video, but instead, only a black window.

This technique is known as hardware overlay. It is preferable over manually drawing the frame due to (I think) speed and simplicity. It is only supported on PocketPC and not on smartphone.
GeneralRe: multiple draw surfaces
dzolee
4:41 16 Jun '08  
Oops, I know how it looks when you make a screenshot but the video area is blank. It is the same on PC. For example Windows media player, or the PocketPC emulator. My question was not about this, but about UI elements drawn over the video window. With Windows media player on PocketPC, there is a rectangular video window and there is a designated area for controls. Same with other players I've seen so far. No UI elements drawn over the video.
GeneralRe: multiple draw surfaces
mdanh2002
4:45 16 Jun '08  
Have you tried with your built-in camera application? On my HTC Dopod 838Pro the built-in camera application has UI elements drawn over the video. If yours don't have, you can tried CoolCamera, it's a 3rd party camera product that has the same behaviour.

I spent a lot of time reverse engineering to figure out how this is achieved. As of now, no luckFrown
GeneralRe: multiple draw surfaces
dzolee
4:52 16 Jun '08  
Aha! I thought I have made myself clear, I have no device with a camera, and also no experience with such devices. Smile
Hmm, what do you think, those controls on your HTC are drawn by Windows or are custom drawn? You could tell by the looks.
GeneralRe: multiple draw surfaces
mdanh2002
17:33 16 Jun '08  
Obviously it's custom drawn (doesn't look like the standard Windows forms [button, checkbox, etc.] at all). All those controls are actually bitmaps embedded inside the .EXE file and drawn at runtime.

Too bad, noone can provide me with any hints on this.Frown
GeneralRe: multiple draw surfaces
dzolee
21:19 16 Jun '08  
Let's sum up where are you now:

-you need to get the camera preview (sequence of bitmaps) from the camera
-you want to display it
-you also want to display some controls on top of it

Once you figure out the first, the rest is "just coding", right? You can display anything, and also draw your controls, if they are simple bitmaps, that's even better. If you intend to use custom drawn stuff, which you draw entirely without Windows (look at your favorite satnav software, I bet it is all custom drawn!), then you can draw it to your second buffer and you can merge the buffers too.

You can, in theory, finish most of the above, even if you don't have the camera image. Just return the same bitmap (eg. contents of "test.bmp") in your GetCameraPic() function.


Last Updated 16 Nov 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010