Advertisment

Coding Screen Savers 

author-image
PCQ Bureau
New Update

In this article we show you how to use OpenGL to create a screen saver; you may use .NET if you want. The code shown here can be adapted to work with any rendering tool such as DirectX or even GDI. For this the knowledge of Win32 and some OpenGL is a prerequisite, although you can get along just fine learning from the provided source code. A Windows screen saver is a normal executable file (yes, a '.exe' file) with a .scr extension, the only difference lies in the way a program is launched and the program's response to the arguments that have been passed to it. The table given below lists the arguments passed to the screen saver and their meanings.

Advertisment

Another factor that differentiates a screen saver from a regular application program is the way in which it responds to certain messages, such as pressing the key and moving or clicking the mouse.This message handling is done in the message loop of the Windows procedure. We can generate a full screen display by getting the screen resolution, creating a window with no borders or title (pop-up style) and using an API (OpenGL in this case). Though Visual Studio also provides the functionality to create screen savers in the 'scrnsave' library, not too many people may have its licensed version. On the other hand, the code shown here will run on any free compiler for Windows (such as BC 5.5) and produce the same effect although with a little extra effort.

Direct Hit!
Applies to: Windows application programmers
USP:

Create a solar system screen saver using OpenGL
Links:

www.opengl.org 

Let's first create a full screen OpenGL application using Win32. After this, initiate the appropriate action according to the command-line arguments passed when the application is launched. The OpenGL specific code, which draws a part of a solar system, is written first.

Advertisment

#define THRESHHOLD 1



#include


#include


#include


int firstTime,curx,cury;


//------------------------OpenGL specific code-----------------


// Lighting values


GLfloat whiteLight<> = { 0.2f, 0.2f, 0.2f, 1.0f };


.


.


void renderscene(void)


{


.


.


// Set material color, Red


// Sun


.


.


// Rotate coordinate system


glRotatef(fEarthRot, 0.0f, 1.0f, 0.0f);


.


.


fEarthRot += 2.0f;


if(fEarthRot > 360.0f)


fEarthRot = 0.0f;


}


void Init()


{


// Light values and coordinates


glEnable(GL_DEPTH_TEST); // Hidden surface removal


glFrontFace(GL_CCW);


.


.


}


void resize(GLsizei w,GLsizei h)


{


.


.


glMatrixMode(GL_MODELVIEW);


glLoadIdentity();


}














































Let's now look at handling the Win32 specific code, which consists of the function that gets a pixelformat, the window callback procedure and the WinMain function. Since the function that gets the pixelformat is straightforward and documented well in the program, we will not discuss that; instead talk about the other two.

// Window procedure, handles all messages for this program



LRESULT CALLBACK WndProc( HWND hWnd,UINT message,WPARAM wParam, LPARAM lParam)


{


static HGLRC hRC; // Permenant Rendering context


static HDC hDC; // Private GDI Device context


static POINT pt;


static int mx,my;


switch (message)


{


// ------------------Window creation----------------------------


case WM_CREATE:


// Store the device context


hDC = GetDC(hWnd);


.


.


break;


//----------- Window is being destroyed, cleanup------------- case WM_DESTROY:


.


.


resize(LOWORD(lParam), HIWORD(lParam));


break;


case WM_TIMER:


InvalidateRect(hWnd,NULL,FALSE);


break;


case WM_PAINT:


renderscene();


.


.


//-----these are messages that cause the screensaver to be terminated--


case WM_MOUSEMOVE:


if(firstTime)


{


GetCursorPos(&pt);


curx=pt.x;


cury=pt.y;


firstTime=0;


}


else


{


GetCursorPos(&pt);


mx=curx - pt.x;


my=cury-pt.y;


if(my<0)


my=my*-1;


if(mx<0)


mx*=-1;


}


if(mx>THRESHHOLD || my >THRESHHOLD)


PostQuitMessage(0);


break;


case WM_LBUTTONDOWN:


case WM_MBUTTONDOWN:


case WM_RBUTTONDOWN:


case WM_KEYDOWN:


case WM_SYSKEYDOWN:


PostQuitMessage(0);


default: // Passes it on if unproccessed


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


}


return (0L);


}


























































The code for message loop differentiates this screen saver from a Windows application. Each of WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_KEYDOWN, WM_SYSKEYDOWN (all have self explanatory names) should cause the screen saver to stop. Each message should terminate the application, which is done by issuing the PostQuitMessage() function. The WM_MOUSEMOVE message is a little different though. If you terminate the application when this message is received, the screen saver becomes too sensitive. You can counter this by calculating the movement of the mouse by getting the new mouse coordinates and comparing them with the old coordinates. If the difference is greater than a given threshold then you can safely post a quit message.

Advertisment
Argument What it means

passed
/c or

-c or c
Open

the screen saver configu-ration dialog with the

parent set to the handle of the calling program. This is used

when configured from the control panel
/p or

-p or p
Preview

mode. It is followed by a handle to a window where a screensaver preview

can be rendered
/s or

-s or s
Run

the actual screen saver None Run the configuration dialog for the screen

saver

int APIENTRY WinMain(HINSTANCE hinstance,HINSTANCE hprevinstance,LPSTR lpcmdline,int

ncmdshow) 



{


.


.


//what have i been called as?


if(strcmpi(lpcmdline,"/s")!=0&&strcmpi(lpcmdline,"-s")!=0&& strcmpi(lpcmdline,"s")!=0)


{


if(strcmpi(lpcmdline,"/c")==0||strcmpi(lpcmdline,"-c")==0||strcmpi(lpcmdline,"c")==0)


{


MessageBox(GetParent(NULL),"You can create the config window and put it right here","Supposed ScreenSaver Configuration Dialog",MB_OK);


return 0;


}


else if(lpcmdline<1>=='p')


{


return 0;


}


else


{


MessageBox(NULL,"You can create the config window and put it right here","Supposed ScreenSaver Configuration Dialog",MB_OK);


return 0;


}


}


firstTime=1;


.


.


// Create the main application window


hWnd = CreateWindow(


"Test ScreenSaver",


"Test ScreenSaver",


// OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,


// Window position and size


.


.


NULL);


.


.


// Process application messages until the application closes


while( GetMessage(&msg, NULL, 0, 0))


.


.


return msg.wParam;


}







































Now let's write the WinMain() function. We have only shown the parts that handle the command-line arguments. The entire code is available in a ready to compile form as myss.c along with the compiled version as myss.scr. The code shown here checks for whether it has been launched in the screen saver mode/s. If yes, run the animation and if no, check for other options (/c and /p). The configuration dialog box is not needed but can be launched from the place currently held by the message box. You can also implement the preview mode optionally. If these options fail, the configuration dialog is launched.Now you have a screen saver skeleton. To compile this under BC 5.5, use the command line 'bcc32 -6 -tW -e"myss.scr" myss.c'.Once you have built it, you have to right click on the output file in explorer to either test the screen saver, configure it or install it.

Rakesh Iyer

Advertisment