   Program Your Own OpenGL Screensaver
  Here i have written a very simple class that encapsulates all that you need for a simple screensaver. It was written for any OpenGL programmer that doesnt want to learn how to write a screensaver, but feels a need for turning their 3d application into one.Here is the screensaver class with code comments/***********************************************************************File: GLScreenSaver.hppJacob Bills - 2008    This program is free software: you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation, either version 3 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program.  If not, see <http://www.gnu.org/licenses/>//$--------------------------------------------------------------------- This class was written in the hopes that it would be helpful to OpenGLprogrammers to be able to convert their 3d applications to screensavers everyone can use, without having to write a single line of screensaver code.Last Modified: November 1, 2008Version: v1.0//*********************************************************************/#include <windows.h>#include <scrnsave.h>#include <commctrl.h>#include <gl\gl.h>#include <gl\glu.h>#include <gl\glaux.h>/*************************************The Following Is For Micrsoft Visual Studio(This can also be done in other IDE's)To name your screen saver, you need to add a string table resource to your project.Then you need to type in IDS_DESCRIPTION=1, hit enter, then type in the name of your scr under the caption.To associate your screensaver with an icon, you need to add an icon resourceOnce you have imported or created an icon, set its ID to ID_APP.To create a settings dialog for when a user wants to change various settings for yourscr, you need to add a dialog resource. Once you have finished your dialog, set its IDto DLG_SCRNSAVECONFIGURE=2003*************************************/#include "resource.h"// Include these libraries#pragma comment(lib, "OpenGL32.lib")#pragma comment(lib, "GLu32.lib")#pragma comment(lib, "GLaux.lib")#ifdef _UNICODE#pragma comment(lib, "ScrnSavw.lib")#endif#ifdef _MBCS#pragma comment(lib, "ScrnSave.lib")#endif#pragma comment(lib, "comctl32.lib")const int DRAW_TIMER = 1;typedef void (*II)(int,int);typedef void (*V)();typedef void (*T)(WPARAM);/************************************~*This Function Is Your Entry Point*~************************************/void screen_saver_main();class GLScreenSaver{public:GLScreenSaver() {}~GLScreenSaver() {}//functions to call from your 3d applicationvoid glSetupFunc(II ptrFunction) {SetupGL = ptrFunction;}void glUpdateFunc(V ptrFunction) {UpdateGL = ptrFunction;}void glDrawFunc(V ptrFunction) {DrawScene = ptrFunction;}void glCleanFunc(V ptrFunction) {CleanUp = ptrFunction;}void glConfigFunc(V ptrFunction) {GetConfig = ptrFunction;}void glTimerFunc(T ptrFunction) {TimerFunc = ptrFunction;}//required screensaver functionstatic LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);//window handlestatic HWND hWnd;private://callback functionsstatic II SetupGL;static V UpdateGL;static V DrawScene;static V CleanUp;static V GetConfig;static T TimerFunc;//opengl functionsstatic void InitGL(HWND hWnd);static void CloseGL(HWND hWnd);//window dimensionsstatic int windowWidth;static int windowHeight;//window variablesstatic HDC hDC;static HGLRC hRC;};II GLScreenSaver::SetupGL = NULL;V GLScreenSaver::UpdateGL = NULL;V GLScreenSaver::DrawScene = NULL;V GLScreenSaver::CleanUp = NULL;V GLScreenSaver::GetConfig = NULL;T GLScreenSaver::TimerFunc = NULL;int GLScreenSaver::windowWidth = 0;int GLScreenSaver::windowHeight = 0;HDC GLScreenSaver::hDC = NULL;HGLRC GLScreenSaver::hRC = NULL;HWND GLScreenSaver::hWnd = NULL;//begins gl, this code basically sets up fullscreenvoid GLScreenSaver::InitGL(HWND hWnd){static PIXELFORMATDESCRIPTOR pfd = {sizeof(PIXELFORMATDESCRIPTOR),1, // nVersion should be set to 1PFD_DRAW_TO_WINDOW |   // buffer can draw to windowPFD_SUPPORT_OPENGL |   // buffer supports OpenGL drawingPFD_DOUBLEBUFFER, // buffer is double bufferedPFD_TYPE_RGBA,    // rgba pixels24,// 24-bit color depth0, 0, 0, 0, 0, 0, // look up rest at MSDN, color bits ignored0, // no alpha buffer0, // shift bit ignored0, // no accumulation buffer0, 0, 0, 0,  // accumulation bits16,// 16 bit z buffer0, // no stencil buffer0, // no auxiliary bufferPFD_MAIN_PLANE,   // main drawing layer0, // reserved0, 0, 0 // layer mask ignored    };GLScreenSaver::hDC = GetDC( hWnd ); int i = ChoosePixelFormat( GLScreenSaver::hDC, &pfd ); SetPixelFormat( GLScreenSaver::hDC, i, &pfd );hRC = wglCreateContext( GLScreenSaver::hDC );wglMakeCurrent( GLScreenSaver::hDC, GLScreenSaver::hRC );}//shuts down openglvoid GLScreenSaver::CloseGL(HWND hWnd){wglMakeCurrent( NULL, NULL );wglDeleteContext( GLScreenSaver::hRC );ReleaseDC( hWnd, GLScreenSaver::hDC );}//using this to call the member screen saver procedureLRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){return GLScreenSaver::ScreenSaverProc(hWnd, message, wParam, lParam);}//member screen saver procedureLRESULT WINAPI GLScreenSaver::ScreenSaverProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){switch (message) {case WM_CREATE:{RECT rect;GLScreenSaver::hWnd = hWnd;//entry pointscreen_saver_main();// get window dimensionsGetClientRect(hWnd, &rect);GLScreenSaver::windowWidth = rect.right;GLScreenSaver::windowHeight = rect.bottom;    //get configuration from registry if applicableif (GetConfig != NULL)GetConfig();//Initialize GL WindowGLScreenSaver::InitGL(hWnd);//Setup opengl worldif (SetupGL != NULL)SetupGL(GLScreenSaver::windowWidth, GLScreenSaver::windowHeight);//create a timer that ticks every 10 millisecondsSetTimer(hWnd, DRAW_TIMER, 10, NULL);break;} case WM_DESTROY:{//stops the timerKillTimer(hWnd, DRAW_TIMER);    //call to clean up anything you createdif (CleanUp != NULL)CleanUp();//shutdown glGLScreenSaver::CloseGL(hWnd);break;}case WM_TIMER:{//if its the draw timer, this procedure handles what to doif (wParam == DRAW_TIMER){//draw sceneif (DrawScene != NULL)DrawScene();//double bufferingsSwapBuffers(GLScreenSaver::hDC);//update worldif (UpdateGL != NULL)UpdateGL();}//if its another timer id, send it to the TimerFuncelse{if (TimerFunc != NULL)TimerFunc(wParam);}break;}}//let the screensaver library take care of any other messagesreturn DefScreenSaverProc(hWnd, message, wParam, lParam);}//for the dialog when user hits settingsBOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){ // Dialog message handlingswitch(message) { case WM_COMMAND:  switch(LOWORD(wParam))  {   case IDOK:    EndDialog(hDlg, LOWORD(wParam) == IDOK);    return TRUE;  } } return FALSE;}// needed for SCRNSAVE.LIBBOOL WINAPI RegisterDialogClasses(HANDLE hInst){return TRUE;}Here is a simple screensaver that i wrote using this class, it draws two different graphs of functions./***********************************************************************File: main.cppJacob Bills - 2008    This program is free software: you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation, either version 3 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program.  If not, see <http://www.gnu.org/licenses/>//$--------------------------------------------------------------------- Main GL programming is here, this screensaver draws graphs of 2 differentfunctions.Last Modified: November 1, 2008Version: v1.0//*********************************************************************/#include <math.h>#include <ctime>#include "GLScreenSaver.hpp"const int UPDATE_INTERVAL = 5000; //5000 milliseconds = 5 secondsconst int UPDATE_TIMER = 2;//screensaver classGLScreenSaver scr;//function prototypes and stufftypedef float (*function)(float, float);typedef void (*normal) (float, float, float, float*);float f1(float x, float z);float f2(float x, float z);void normal1(float x, float y, float z, float* norm);void normal2(float x, float y, float z, float* norm);function drawFuncs[2] = {&f1, &f2};normal normFuncs[2] = {&normal1, &normal2};int curFIndex = 0;int drawMethods[3] = {GL_LINE_STRIP, GL_POLYGON, GL_POINTS};int curDrawIndex = 1;//angles to rotatefloat theta = 0, beta = 0;float thetaInc = 0.1f, betaInc = 0.05f;//window coordinatesfloat xmin=-2.0f, xmax=2.0f, ymin=-2.0f,ymax=2.0f,zmin=-2.0f,zmax=2.0f;//square grid to generateint n = 50, m = 50;//generate a random numberint random_number(int min, int max) {srand((unsigned)time(0));int random_integer;    int range=max-min+1;    random_integer = (rand()%range)+min;return random_integer;}//setup gl worldvoid Setup(int w, int h){//set the viewing areaglViewport(0, 0, w, h);glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(xmin, xmax, ymin, ymax, zmin, zmax);GLfloat mat_specular[] = {0.0f, 1.0f, 0.0f, 0.0f};GLfloat mat_diffuse[] = {1.0f, 1.0f, 1.0f, 0.0f};GLfloat mat_ambient[] = {1.0f, 1.0f, 1.0f, 0.0f};GLfloat shininess[] = {2.0f};GLfloat light_specular[] = {0.0f, 1.0f, 0.0f, 1.0f};GLfloat light_diffuse[] = {1.0f, 0.9f, 0.9f, 0.0f};GLfloat light_ambient[] = {0.1f, 0.1f, 0.1f, 0.0f};GLfloat light_position[] = {-20.0f, 4.0f, 0.0f, 0.0f};glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);glLightfv(GL_LIGHT0, GL_POSITION, light_position);glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);glMaterialfv(GL_FRONT, GL_SHININESS, shininess);glShadeModel(GL_SMOOTH);float lmodel_ambient[] = {0.4f, 0.4f, 0.4f, 0.4f};glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);glEnable(GL_LIGHTING);glEnable(GL_LIGHT0);glEnable(GL_DEPTH_TEST);glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glClearColor(0,0,0,0);glColor3f(0,0,0);}//update the worldvoid Update(){theta += thetaInc;if (theta > 360)theta = 0;beta += betaInc;if (beta > 60 || beta <= 0)betaInc *= -1;}//draw the worldvoid Draw(){glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glRotatef(beta,1,0,0);glRotatef(theta,0,1,0);float norm[3];float xgap=(xmax-xmin)/n;float zgap=(zmax-zmin)/m;for (int i = 0; i < n; i++){for (int j = 0; j < m; j++){glBegin(drawMethods[curDrawIndex]);float x = xmin+i*xgap;float z = zmin+j*zgap;float y = drawFuncs[curFIndex](x,z);glVertex3f(x,y,z);normFuncs[curFIndex](x,y,z,norm);glNormal3fv(norm);x = xmin+i*xgap;z = zmin+(j+1)*zgap;y = drawFuncs[curFIndex](x,z);glVertex3f(x,y,z);normFuncs[curFIndex](x,y,z,norm);glNormal3fv(norm);x = xmin+(i+1)*xgap;z = zmin+(j+1)*zgap;y = drawFuncs[curFIndex](x,z);glVertex3f(x,y,z);normFuncs[curFIndex](x,y,z,norm);glNormal3fv(norm);glEnd();glBegin(drawMethods[curDrawIndex]);x = xmin+(i+1)*xgap;z = zmin+j*zgap;y = drawFuncs[curFIndex](x,z);glVertex3f(x,y,z);normFuncs[curFIndex](x,y,z,norm);glNormal3fv(norm);x = xmin+i*xgap;z = zmin+j*zgap;y = drawFuncs[curFIndex](x,z);glVertex3f(x,y,z);normFuncs[curFIndex](x,y,z,norm);glNormal3fv(norm);x = xmin+(i+1)*xgap;z = zmin+(j+1)*zgap;y = drawFuncs[curFIndex](x,z);glVertex3f(x,y,z);normFuncs[curFIndex](x,y,z,norm);glNormal3fv(norm);glEnd();}}}//function 1float f1(float x, float z){return exp(-x*x-z*z);}//calculate the normal to function 1void normal1(float x, float y, float z, float* norm){norm[0] = 2*x*exp(-x*x-z*z);norm[1] = 1;norm[2] = 2*z*exp(-x*x-z*z);float d = norm[0]*norm[0]+norm[1]*norm[1]+norm[2]*norm[2];if (d>0){for (int k = 0; k < 3; k++)norm[k]/=d;}}//function 2float f2(float x, float z){return z*cos(x);}//calculate the normal to function 2void normal2(float x, float y, float z, float* norm){norm[0] = z*sin(x);norm[1] = 1;norm[2] = -1*cos(x);float d = norm[0]*norm[0]+norm[1]*norm[1]+norm[2]*norm[2];if (d>0){for (int k = 0; k < 3; k++)norm[k]/=d;}}//handles timer callsvoid Timer(WPARAM wParam){if (wParam == UPDATE_TIMER){curFIndex = random_number(0, 1);curDrawIndex = random_number(0, 2);}}//clean upvoid Clean(){KillTimer(scr.hWnd, UPDATE_TIMER);}//entry pointvoid screen_saver_main(){scr.glSetupFunc(Setup);scr.glUpdateFunc(Update);scr.glDrawFunc(Draw);scr.glTimerFunc(Timer);scr.glCleanFunc(Clean);SetTimer(scr.hWnd, UPDATE_TIMER, UPDATE_INTERVAL, NULL);}please rate my work and leave constructive criticism where necessary.thanks-b1gjo3   
  Oooh, shiny.I've often wondered how to go about making something a screensaver, but have never bothered to actually find out (I'm not into WinAPI).Unfortunately I don't really have time to look at this atm, but I've bookmarked it to play around with at some point.   ;Quote:Original post by sprite_houndOooh, shiny.I've often wondered how to go about making something a screensaver, but have never bothered to actually find out (I'm not into WinAPI).Unfortunately I don't really have time to look at this atm, but I've bookmarked it to play around with at some point.Yes, the only reason you would need to learn WinAPI in using this class is if you wanted to give the user the option to change settings in your application. It isnt necessary and i dont know that much WinAPI myself. This class goes under the assumption that all you know is how to program in opengl and c++ :)   ;Quote:Original post by sprite_houndOooh, shiny.Fan of Firely by any chance?I've always wanted to make my own screensaver as well. I'll have to take a look at this later sometime.Cheers!!