1 #include <windows.h>
2 #include <scrnsave.h>
3 #include <tchar.h>
4 #include <math.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <GL/gl.h>
8 #include <GL/glu.h>
9 #include <GL/glext.h>
10 #include "resource.h"
11 
12 HINSTANCE		hInstance;			// Holds The Instance Of The Application
13 
14 GLuint texture[3];	                //stores texture objects and display list
15 HDC hdcOpenGL;
16 
17 LPCTSTR registryPath = _T("Software\\Microsoft\\ScreenSavers\\Butterflies");
18 BOOL dRotate;
19 
20 
21 struct object						// Create A Structure Called Object
22 {
23 	int   tex;						// Integer Used To Select Our Texture
24 	float x;						// X Position
25 	float y;						// Y Position
26 	float z;						// Z Position
27 	float yi;						// Y Increase Speed (Fall Speed)
28 	float spinz;					// Z Axis Spin
29 	float spinzi;					// Z Axis Spin Speed
30 	float flap;						// Flapping Triangles :)
31 	float fi;						// Flap Direction (Increase Value)
32 };
33 
34 struct object obj[50];
35 //object obj[50];						// Create 50 Objects Using The Object Structure
36 
37 void SetDefaults()
38 {
39 	dRotate = TRUE;
40 }
41 
42 void ReadRegistry(){
43 	LONG result;
44 	HKEY skey;
45 	DWORD valtype, valsize, val;
46 
47 	SetDefaults();
48 
49 	result = RegOpenKeyEx(HKEY_CURRENT_USER, registryPath, 0, KEY_READ, &skey);
50 	if(result != ERROR_SUCCESS)
51 		return;
52 
53 	valsize=sizeof(val);
54 
55 	result = RegQueryValueEx(skey, _T("Rotate"), 0, &valtype, (LPBYTE)&val, &valsize);
56 	if(result == ERROR_SUCCESS)
57 		dRotate = val;
58 	RegCloseKey(skey);
59 }
60 
61 void WriteRegistry(){
62     LONG result;
63 	HKEY skey;
64 	DWORD val, disp;
65 
66 	result = RegCreateKeyEx(HKEY_CURRENT_USER, registryPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &skey, &disp);
67 	if(result != ERROR_SUCCESS)
68 		return;
69 
70 	val = dRotate;
71 	RegSetValueEx(skey, _T("Rotate"), 0, REG_DWORD, (CONST BYTE*)&val, sizeof(val));
72 
73 	RegCloseKey(skey);
74 }
75 
76 void SetObject(int loop)										// Sets The Initial Value Of Each Object (Random)
77 {
78 	obj[loop].tex=rand()%3;										// Texture Can Be One Of 3 Textures
79 	obj[loop].x=rand()%34-17.0f;								// Random x Value From -17.0f To 17.0f
80 	obj[loop].y=18.0f;											// Set y Position To 18 (Off Top Of Screen)
81 	obj[loop].z=-((rand()%30000/1000.0f)+10.0f);				// z Is A Random Value From -10.0f To -40.0f
82 	obj[loop].spinzi=(rand()%10000)/5000.0f-1.0f;				// spinzi Is A Random Value From -1.0f To 1.0f
83 	obj[loop].flap=0.0f;										// flap Starts Off At 0.0f;
84 	obj[loop].fi=0.05f+(rand()%100)/1000.0f;					// fi Is A Random Value From 0.05f To 0.15f
85 	obj[loop].yi=0.001f+(rand()%1000)/10000.0f;					// yi Is A Random Value From 0.001f To 0.101f
86 }
87 
88 void LoadGLTextures()											// Creates Textures From Bitmaps In The Resource File
89 {
90 	HBITMAP hBMP;												// Handle Of The Bitmap
91 	BITMAP	BMP;												// Bitmap Structure
92     int loop;
93 
94 	// The ID Of The 3 Bitmap Images We Want To Load From The Resource File
95 	byte	Texture[]={	IDB_BUTTERFLY1,	IDB_BUTTERFLY2,	IDB_BUTTERFLY3 };
96 
97 	glGenTextures(sizeof(Texture), &texture[0]);				// Generate 3 Textures (sizeof(Texture)=3 ID's)
98 	for (loop=0; loop<sizeof(Texture); loop++)				// Loop Through All The ID's (Bitmap Images)
99 	{
100 		hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(Texture[loop]), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
101 		if (hBMP)												// Does The Bitmap Exist?
102 		{														// If So...
103 			GetObject(hBMP,sizeof(BMP), &BMP);					// Get The Object
104 																// hBMP: Handle To Graphics Object
105 																// sizeof(BMP): Size Of Buffer For Object Information
106 																// Buffer For Object Information
107 			glPixelStorei(GL_UNPACK_ALIGNMENT,4);				// Pixel Storage Mode (Word Alignment / 4 Bytes)
108 			glBindTexture(GL_TEXTURE_2D, texture[loop]);		// Bind Our Texture
109 			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);	// Linear Filtering
110 			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); // Mipmap Linear Filtering
111 
112 			// Generate Mipmapped Texture (3 Bytes, Width, Height And Data From The BMP)
113 			gluBuild2DMipmaps(GL_TEXTURE_2D, 3, BMP.bmWidth, BMP.bmHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
114 		}
115 	}
116 }
117 
118 HGLRC InitOGLWindow(HWND hWnd)
119 {
120 	HDC hDC = GetDC(hWnd);
121 	HGLRC hRC = 0;
122 	PIXELFORMATDESCRIPTOR pfd;
123 	int nFormat;
124 
125 	ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
126 
127 	pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
128 	pfd.nVersion = 1;
129 	pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
130 	pfd.cColorBits = 24;
131 	pfd.cDepthBits = 24;
132 
133 	nFormat = ChoosePixelFormat(hDC, &pfd);
134 	DescribePixelFormat(hDC, nFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
135 	SetPixelFormat(hDC, nFormat, &pfd);
136 
137 	hRC = wglCreateContext(hDC);
138 	wglMakeCurrent(hDC, hRC);
139 
140 	hdcOpenGL = hDC;
141 
142 	return hRC;
143 }
144 
145 void InitOpenGL(GLsizei width, GLsizei height)
146 {
147     int loop;
148 
149 	if (height==0)										// Prevent A Divide By Zero By
150 	{
151 		height=1;										// Making Height Equal One
152 	}
153 
154 	glViewport(0,0,width,height);						// Reset The Current Viewport
155 
156 	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
157 	glLoadIdentity();									// Reset The Projection Matrix
158 
159 	// Calculate The Aspect Ratio Of The Window
160 	gluPerspective (45.0f, (GLfloat)(width)/(GLfloat)(height),1.0f, 1000.0f);
161 
162 	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
163 	glLoadIdentity();
164 		// Start Of User Initialization
165 	LoadGLTextures();									// Load The Textures From Our Resource File
166 
167 	glClearColor (0.0f, 0.0f, 0.0f, 0.5f);				// Black Background
168 	glClearDepth (1.0f);								// Depth Buffer Setup
169 	glDepthFunc (GL_LEQUAL);							// The Type Of Depth Testing (Less Or Equal)
170 	glDisable(GL_DEPTH_TEST);							// Disable Depth Testing
171 	glShadeModel (GL_SMOOTH);							// Select Smooth Shading
172 	glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Set Perspective Calculations To Most Accurate
173 	glEnable(GL_TEXTURE_2D);							// Enable Texture Mapping
174 	glBlendFunc(GL_ONE,GL_SRC_ALPHA);					// Set Blending Mode (Cheap / Quick)
175 	glEnable(GL_BLEND);
176 
177 
178 	for (loop=0; loop<50; loop++)					// Loop To Initialize 50 Objects
179 	{
180 		SetObject(loop);										// Call SetObject To Assign New Random Values
181 	}
182 
183 }
184 
185 void Display()
186 {
187     int loop;
188 	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear Screen And Depth Buffer
189 
190 	for (loop=0; loop<50; loop++)							// Loop Of 50 (Draw 50 Objects)
191 	{
192 		glLoadIdentity ();										// Reset The Modelview Matrix
193 		glBindTexture(GL_TEXTURE_2D, texture[obj[loop].tex]);	// Bind Our Texture
194 		glTranslatef(obj[loop].x,obj[loop].y,obj[loop].z);		// Position The Object
195 		glRotatef(45.0f,1.0f,0.0f,0.0f);						// Rotate On The X-Axis
196 		if (dRotate)
197 		{
198 			glRotatef((obj[loop].spinz),0.0f,0.0f,1.0f);			// Spin On The Z-Axis
199 		}
200 		glBegin(GL_TRIANGLES);									// Begin Drawing Triangles
201 			// First Triangle														    _____
202 			glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);				//	(2)|    / (1)
203 			glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f, obj[loop].flap);	//	   |  /
204 			glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);				//	(3)|/
205 
206 			// Second Triangle
207 			glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);				//	       /|(1)
208 			glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);				//	     /  |
209 			glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f,-1.0f, obj[loop].flap);	//	(2)/____|(3)
210 
211 		glEnd();												// Done Drawing Triangles
212 
213 		obj[loop].y-=obj[loop].yi;								// Move Object Down The Screen
214 		obj[loop].spinz+=obj[loop].spinzi;						// Increase Z Rotation By spinzi
215 		obj[loop].flap+=obj[loop].fi;							// Increase flap Value By fi
216 
217 		if (obj[loop].y<-18.0f)									// Is Object Off The Screen?
218 		{
219 			SetObject(loop);									// If So, Reassign New Values
220 		}
221 
222 		if ((obj[loop].flap>1.0f) || (obj[loop].flap<-1.0f))	// Time To Change Flap Direction?
223 		{
224 			obj[loop].fi=-obj[loop].fi;							// Change Direction By Making fi = -fi
225 		}
226 	}
227 
228 	Sleep(15);													// Create A Short Delay (15 Milliseconds)
229 
230 	glFlush ();
231 
232 }
233 
234 INT_PTR CALLBACK AboutProc(HWND hdlg, UINT msg, WPARAM wpm, LPARAM lpm){
235 
236 	switch(msg){
237 	case WM_CTLCOLORSTATIC:
238 		if(((HWND)lpm == GetDlgItem(hdlg, WEBPAGE1)) || ((HWND)lpm == GetDlgItem(hdlg, WEBPAGE2)))
239 		{
240 			SetTextColor((HDC)wpm, RGB(0,0,255));
241 			SetBkColor((HDC)wpm, (COLORREF)GetSysColor(COLOR_3DFACE));
242 			return (INT_PTR)GetSysColorBrush(COLOR_3DFACE);
243 		}
244 		break;
245     case WM_COMMAND:
246 		switch(LOWORD(wpm)){
247 		case IDOK:
248 			EndDialog(hdlg, LOWORD(wpm));
249 			break;
250 		case WEBPAGE1:
251 			ShellExecute(NULL, _T("open"), _T("http://nehe.gamedev.net"), NULL, NULL, SW_SHOWNORMAL);
252 			break;
253 		case WEBPAGE2:
254 			ShellExecute(NULL, _T("open"), _T("http://www.thaputer.com"), NULL, NULL, SW_SHOWNORMAL);
255 			break;
256 		}
257 	}
258 	return FALSE;
259 }
260 
261 LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT message,
262 					 WPARAM wParam, LPARAM lParam)
263 {
264 	static HGLRC hRC;
265 	static DWORD timer = 1;
266 	HDC hDC;
267     RECT WindowRect;
268 	int width;
269 	int height;
270 
271 	switch (message)
272 	{
273 	case WM_CREATE:
274 		ReadRegistry();
275 		hRC = InitOGLWindow(hWnd);
276 		GetClientRect (hWnd, &WindowRect);
277 		width = WindowRect.right - WindowRect.left;
278 		height = WindowRect.bottom - WindowRect.top;
279 		InitOpenGL(width,height);
280 		SetTimer(hWnd, timer, 5, NULL);
281 		break;
282 	case WM_TIMER:
283 		hDC = GetDC(hWnd);
284 		Display();
285 		SwapBuffers(hDC);
286 		ReleaseDC(hWnd, hDC);
287 		break;
288 	case WM_DESTROY:
289 		wglMakeCurrent(NULL, NULL);
290 		wglDeleteContext(hRC);
291 		ReleaseDC(hWnd, hdcOpenGL);
292 		break;
293 	}
294 
295 	return DefScreenSaverProc(hWnd, message, wParam, lParam);
296 }
297 
298 BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT message,
299 								WPARAM wParam, LPARAM lParam)
300 {
301 	switch (message)
302 	{
303         case WM_INITDIALOG:
304 	        ReadRegistry();
305 	        CheckDlgButton(hDlg, ROTATE, dRotate);
306 	        return TRUE;
307 	    case WM_COMMAND:
308 		    switch (LOWORD(wParam))
309 		    {
310 		        case IDOK:
311 			        dRotate = (IsDlgButtonChecked(hDlg, ROTATE) == BST_CHECKED);
312 			        WriteRegistry();
313 			        EndDialog(hDlg, TRUE);
314 			        return TRUE;
315 		        case IDCANCEL:
316 			        EndDialog(hDlg, TRUE);
317 			        break;
318 		        case IDABOUT:
319 			        DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLG_ABOUT), hDlg, AboutProc);
320                     break;
321 		    }
322 	}
323 
324 	return FALSE;
325 }
326 
327 BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
328 {
329 	return TRUE;
330 }
331 
332