PDA

View Full Version : C++, win32, OpenGL screensaver preview mode



vindy
08-02-2012, 07:59 PM
I'm new here. I have written a screensaver using OpenGL and was hoping you guys could help figure out how to make it display a preview in the preview window when the user selects my screensaver. The screensaver is a simple lens effect that applies itself to the entire desktop. Its a fisheye lens effect. You've probably seen other screensavers that do the exact same thing. The problem I'm having is when my screensaver is selected the preview window remains black. I know that the command line argument /p is passed to my program when in preview mode and I'm detecting that just fine. I just don't understand why I can't grab the entire desktop and apply the effect inside the preview window. Here's some code showing how I'm going about grabbing the the desktop:




if(previewMode)
hDC = GetDC(GetDesktopWindow());
else
hDC = GetDC( hWnd );

int pf = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat( hDC, pf, &pfd );

hRC = wglCreateContext( hDC );
wglMakeCurrent( hDC, hRC );

pixelBuffer = new GLubyte[sizeof(GLubyte) * Width * Height * 4];

glReadBuffer(GL_FRONT);

GLint ReadBuffer;
glGetIntegerv(GL_READ_BUFFER, &ReadBuffer);

glPixelStorei(GL_READ_BUFFER, GL_RGBA);

GLint PackAlignment;
glGetIntegerv(GL_PACK_ALIGNMENT, &PackAlignment);
glPixelStorei(GL_PACK_ALIGNMENT, 1);

glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, pixelBuffer);



Now, pixelBuffer should have the image data for the desktop, but in preview mode it doesn't work. Have any idea as to where I'm going wrong? If you need to see all my code I'll post it but its kinda long. Thanks in advance.

Shinta
08-03-2012, 02:45 AM
In preview mode, the calling arguments also contain a handel (HWND) to the preview window; but this handel is only good for aquiring the size and position of the preview window, so don't try to set a pixelformat in this window. Instead you can create a new window as child right on top of it.

Sorry, the following code is in MFC, but I think you'll get the idea:


CWnd* pParent=CWnd::FromHandle((HWND)_atoi64(__argv[2]));
ASSERT(pParent!=NULL);

CRect rect;
pParent->GetClientRect(&rect);

CScreenSaferView* pWnd=new CScreenSaferView();
pWnd->Create(NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, rect, pParent, 0, NULL);
m_pMainWnd=pWnd;


From this window you can get your hDC.

And on the screenshot part, just make a screenshot as bitmap using the gdi and copy it into your OpenGL windows with glDrawPixels or as texture.

Making screenshots:
http://www.programmersheaven.com/mb/Win32API/416677/416679/re-grabbing-a-screenshot/?S=B20000
or
http://stackoverflow.com/questions/3370702/c-take-screenshot
or
http://stackoverflow.com/questions/7292757/how-to-get-screenshot-of-a-window-as-bitmap-object-in-c
or
Just google "screenshot windows api c"

vindy
08-03-2012, 08:21 PM
Hi Shinta. Thanks for taking the time to help me out. I tried what you suggested about making a window as a child on top of the preview window but it hung my computer. Maybe the way I went about doing it was wrong. I wasn't able to really draw on your code. CScreenSaferView doesn't appear to exist. Not for windows at least. When I googled it the closest thing google could come up with was ScreenSaverView which is used for Mac development. I'm going to try your approach again and see if I can tell where I'm going wrong. In the meantime do you think you could post a little straightforward win32 code showing how to create the child window from start to finish? If you could that would really help. And, again, thank you very much.

vindy
08-05-2012, 11:37 AM
Hi again Shinta. I found the mistake that was hanging my computer. I decided I was going to see if I could simply change the preview window white before trying to grab a desktop image and do everything else. Sadly, I failed. I was hoping you could take a look at some code and see if you can tell where I'm going wrong. In the WM_CREATE message after I've found the /p flag in the command line here is what I'm doing:



parentWnd = (HWND)atoi(&cmdLine[i + 3]);


GetClientRect(parentWnd, &rect);


Width = rect.right;
Height = rect.bottom;


LPCTSTR lpszClassName = TEXT("LensEffectScreenSaver");


WNDCLASSEX wc;

ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) ScreenSaverProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = lpszClassName;


RegisterClassEx(&wc);


hWnd = CreateWindow(lpszClassName, TEXT(""), WS_CHILD | WS_VISIBLE, 0, 0, Width, Height,
parentWnd, NULL, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);



Now, in my InitGL function here is what I'm doing:



if(previewMode)
{
hDC = GetDC(hWnd);


hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);

pixelBuffer = new GLubyte[sizeof(GLubyte) * Width * Height * 4];


for(int i = 0;i < Width * Height * 4;i++)
pixelBuffer[i] = (GLubyte)255;
}




After that I use pixelBuffer in the OnTimer function to make a white texture using glTexImage2D and slap it to the screen. But it just isn't working. The preview window remains black. Any ideas as to where I could be going wrong?

vindy
08-06-2012, 09:37 AM
Hey Shinta. I discovered a major oversight on my part. I wasn't setting a pixel format in the child window. I feel like a moron! Now I am setting a pixel format and the rendering context is valid. But the screen in the preview window still is black when I select my screensaver. However, I've noticed that when I go to choose a different screensaver for a split second from when I click on the new screensaver choice to when it actually changes over the preview window does turn white. I suspect I need to do something similar to glutPostRedisplay, but calling InvalidateRect doesn't do the trick. Any ideas as to what I should do to solve the problem?

Shinta
08-07-2012, 07:05 AM
I've cleaned up my screensaver base and added a simple rotating demo object. You'll need Visual Studio 2010 because of the project files; also, the screensaver is based on MFC.

(Warning: The screensaver creates a window for each screen, if there are multiple. And if so, it randomizes its modes.)

If you get this to work, you can base your screensaver on this and add your screencapture and effects.

vindy
08-07-2012, 09:56 AM
Thank you so much Shinta. If all else fails I'll try to make use of this, but I really would like to figure out where I'm going wrong in my code and get my program working. It'll take a little bit of work though because I have Visual Studio 2005 and I know next to nothing about MFC. Bummer, ehh? Well, I'm going to keep trying to get my program working as it is. Hopefully, someone on one of the other forums I've posted questions to will be able to point out where I'm going wrong. I'll keep you updated. And, again, thank you so much for taking time to help me.

vindy
08-08-2012, 04:19 PM
Hi Shinta. I just wanted to tell you I got it working. Thank you again for all your help!