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