//greensquare.cpp is an open-source example
//screensaver by Rachel Grey, lemming@alum.mit.edu.
//Paste into an IDE to compile if desired.
//I haven't chosen to include the resource file,
//so you'd need to provide a description string
//and so forth.
#include <windows.h>
#include <scrnsave.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "resource.h"
//get rid of these warnings:
//truncation from const double to float
//conversion from double to float
#pragma warning(disable: 4305 4244)
//Define a Windows timer
#define TIMER 1
//These forward declarations are just for readability,
//so the big three functions can come first
void InitGL(HWND hWnd, HDC & hDC, HGLRC & hRC);
void CloseGL(HWND hWnd, HDC hDC, HGLRC hRC);
void GetConfig();
void WriteConfig(HWND hDlg);
void SetupAnimation(int Width, int Height);
void CleanupAnimation();
void OnTimer(HDC hDC);
int Width, Height; //globals for size of screen
//////////////////////////////////////////////////
//// INFRASTRUCTURE -- THE THREE FUNCTIONS ///
//////////////////////////////////////////////////
// Screen Saver Procedure
LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HDC hDC;
static HGLRC hRC;
static RECT rect;
switch ( message ) {
case WM_CREATE:
// get window dimensions
GetClientRect( hWnd, &rect );
Width = rect.right;
Height = rect.bottom;
//get configuration from registry
GetConfig();
// setup OpenGL, then animation
InitGL( hWnd, hDC, hRC );
SetupAnimation(Width, Height);
//set timer to tick every 10 ms
SetTimer( hWnd, TIMER, 10, NULL );
return 0;
case WM_DESTROY:
KillTimer( hWnd, TIMER );
CleanupAnimation();
CloseGL( hWnd, hDC, hRC );
return 0;
case WM_TIMER:
OnTimer(hDC); //animate!
return 0;
}
return DefScreenSaverProc(
hWnd, message, wParam, lParam );
}
bool bTumble = true;
BOOL WINAPI
ScreenSaverConfigureDialog(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
//InitCommonControls();
//would need this for slider bars or other common controls
HWND aCheck;
switch ( message )
{
case WM_INITDIALOG:
LoadString(hMainInstance, IDS_DESCRIPTION, szAppName, 40);
GetConfig();
aCheck = GetDlgItem( hDlg, IDC_TUMBLE );
SendMessage( aCheck, BM_SETCHECK,
bTumble ? BST_CHECKED : BST_UNCHECKED, 0 );
return TRUE;
case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case IDC_TUMBLE:
bTumble = (IsDlgButtonChecked( hDlg, IDC_TUMBLE ) == BST_CHECKED);
return TRUE;
//cases for other controls would go here
case IDOK:
WriteConfig(hDlg); //get info from controls
EndDialog( hDlg, LOWORD( wParam ) == IDOK );
return TRUE;
case IDCANCEL:
EndDialog( hDlg, LOWORD( wParam ) == IDOK );
return TRUE;
}
} //end command switch
return FALSE;
}
// needed for SCRNSAVE.LIB
BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
return TRUE;
}
/////////////////////////////////////////////////
//// INFRASTRUCTURE ENDS, SPECIFICS BEGIN ///
//// ///
//// In a more complex scr, I'd put all ///
//// the following into other files. ///
/////////////////////////////////////////////////
// Initialize OpenGL
static void InitGL(HWND hWnd, HDC & hDC, HGLRC & hRC)
{
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory( &pfd, sizeof pfd );
pfd.nSize = sizeof pfd;
pfd.nVersion = 1;
//pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; //blaine's
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
hDC = GetDC( hWnd );
int i = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat( hDC, i, &pfd );
hRC = wglCreateContext( hDC );
wglMakeCurrent( hDC, hRC );
}
// Shut down OpenGL
static void CloseGL(HWND hWnd, HDC hDC, HGLRC hRC)
{
wglMakeCurrent( NULL, NULL );
wglDeleteContext( hRC );
ReleaseDC( hWnd, hDC );
}
void SetupAnimation(int Width, int Height)
{
//window resizing stuff
glViewport(0, 0, (GLsizei) Width, (GLsizei) Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-300, 300, -240, 240, 25, 75);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
//camera xyz, the xyz to look at, and the up vector (+y is up)
//background
glClearColor(0.0, 0.0, 0.0, 0.0); //0.0s is black
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glShadeModel(GL_SMOOTH);
//no need to initialize any objects
//but this is where I'd do it
glColor3f(0.1, 1.0, 0.3); //green
}
static GLfloat spin=0; //a global to keep track of the square's spinning
void OnTimer(HDC hDC) //increment and display
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
spin = spin + 1;
glPushMatrix();
glRotatef(spin, 0.0, 0.0, 1.0);
glPushMatrix();
glTranslatef(150, 0, 0);
if(bTumble)
glRotatef(spin * -3.0, 0.0, 0.0, 1.0);
else
glRotatef(spin * -1.0, 0.0, 0.0, 1.0);
//draw the square (rotated to be a diamond)
float xvals[] = {-30.0, 0.0, 30.0, 0.0};
float yvals[] = {0.0, -30.0, 0.0, 30.0};
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_POLYGON);
for (int i=0; i < 4; i++)
glVertex2f(xvals[i], yvals[i]);
glEnd();
glPopMatrix();
glFlush();
SwapBuffers(hDC);
glPopMatrix();
}
void CleanupAnimation()
{
//didn't create any objects, so no need to clean them up
}
///////// REGISTRY ACCESS FUNCTIONS ///////////
void GetConfig()
{
HKEY key;
//DWORD lpdw;
if (RegOpenKeyEx( HKEY_CURRENT_USER,
"Software\\GreenSquare", //lpctstr
0, //reserved
KEY_QUERY_VALUE,
&key) == ERROR_SUCCESS)
{
DWORD dsize = sizeof(bTumble);
DWORD dwtype = 0;
RegQueryValueEx(key,"Tumble", NULL, &dwtype,
(BYTE*)&bTumble, &dsize);
//Finished with key
RegCloseKey(key);
}
else //key isn't there yet--set defaults
{
bTumble = true;
}
}
void WriteConfig(HWND hDlg)
{
HKEY key;
DWORD lpdw;
if (RegCreateKeyEx( HKEY_CURRENT_USER,
"Software\\GreenSquare", //lpctstr
0, //reserved
"", //ptr to null-term string specifying the object type of this key
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&key,
&lpdw) == ERROR_SUCCESS)
{
RegSetValueEx(key,"Tumble", 0, REG_DWORD,
(BYTE*)&bTumble, sizeof(bTumble));
//Finished with keys
RegCloseKey(key);
}
}