1 /*
2  * Copyright (C) 2002  Terence M. Welsh
3  * Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
4  *
5  * Plasma is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Plasma is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 // Plasma screen saver
20 
21 #include <math.h>
22 #include <stdio.h>
23 #include <GL/gl.h>
24 #include <GL/glu.h>
25 
26 #include "driver.h"
27 #include "rsDefines.h"
28 #include "rsRand.h"
29 
30 const char *hack_name = "plasma";
31 
32 #define NUMCONSTS 18
33 #define MAXTEXSIZE 1024
34 
35 // Globals
36 float aspectRatio;
37 float wide;
38 float high;
39 float c[NUMCONSTS];		// constant
40 float ct[NUMCONSTS];		// temporary value of constant
41 float cv[NUMCONSTS];		// velocity of constant
42 float ***position;
43 float ***plasma;
44 unsigned int tex;
45 int texsize = 256;
46 int plasmaWidth, plasmaHeight;
47 float texright, textop;
48 float *plasmamap;
49 
50 // Parameters edited in the dialog box
51 int dZoom;
52 int dFocus;
53 int dSpeed;
54 int dResolution;
55 
56 // Find absolute value and truncate to 1.0
57 #define fabstrunc(f) (f >= 0.0f ? (f <= 1.0f ? f : 1.0f) : (f >= -1.0f ? -f : 1.0f))
58 
59 /*
60 float fabstrunc (float f)
61 {
62 	if (f >= 0.0f) {
63 		return (f <= 1.0f ? f : 1.0f);
64 	} else {
65 		return (f >= -1.0f ? -f : 1.0f);
66 	}
67 }
68 */
69 
hack_draw(xstuff_t * XStuff,double currentTime,float frameTime)70 void hack_draw (xstuff_t * XStuff, double currentTime, float frameTime)
71 {
72 	int i, j;
73 	float rgb[3];
74 	float temp;
75 	static float focus = float (dFocus) / 50.0f + 0.3f;
76 	static float maxdiff = 0.004f * float (dSpeed);
77 	static int index;
78 
79 	// Update constants
80 	for (i = 0; i < NUMCONSTS; i++) {
81 		ct[i] += cv[i];
82 		if (ct[i] > PIx2)
83 			ct[i] -= PIx2;
84 		c[i] = sin (ct[i]) * focus;
85 	}
86 
87 	// Update colors
88 	for (i = 0; i < plasmaHeight; i++) {
89 		for (j = 0; j < plasmaWidth; j++) {
90 			// Calculate vertex colors
91 			rgb[0] = plasma[i][j][0];
92 			rgb[1] = plasma[i][j][1];
93 			rgb[2] = plasma[i][j][2];
94 			plasma[i][j][0] = 0.7f * (c[0] * position[i][j][0] + c[1] * position[i][j][1]
95 						  + c[2] * (position[i][j][0] * position[i][j][0] + 1.0f)
96 						  + c[3] * position[i][j][0] * position[i][j][1]
97 						  + c[4] * rgb[1] + c[5] * rgb[2]);
98 			plasma[i][j][1] = 0.7f * (c[6] * position[i][j][0] + c[7] * position[i][j][1]
99 						  + c[8] * position[i][j][0] * position[i][j][0]
100 						  + c[9] * (position[i][j][1] * position[i][j][1] - 1.0f)
101 						  + c[10] * rgb[0] + c[11] * rgb[2]);
102 			plasma[i][j][2] = 0.7f * (c[12] * position[i][j][0] + c[13] * position[i][j][1]
103 						  + c[14] * (1.0f - position[i][j][0] * position[i][j][1])
104 						  + c[15] * position[i][j][1] * position[i][j][1]
105 						  + c[16] * rgb[0] + c[17] * rgb[1]);
106 
107 			// Don't let the colors change too much
108 			temp = plasma[i][j][0] - rgb[0];
109 			if (temp > maxdiff)
110 				plasma[i][j][0] = rgb[0] + maxdiff;
111 			if (temp < -maxdiff)
112 				plasma[i][j][0] = rgb[0] - maxdiff;
113 			temp = plasma[i][j][1] - rgb[1];
114 			if (temp > maxdiff)
115 				plasma[i][j][1] = rgb[1] + maxdiff;
116 			if (temp < -maxdiff)
117 				plasma[i][j][1] = rgb[1] - maxdiff;
118 			temp = plasma[i][j][2] - rgb[2];
119 			if (temp > maxdiff)
120 				plasma[i][j][2] = rgb[2] + maxdiff;
121 			if (temp < -maxdiff)
122 				plasma[i][j][2] = rgb[2] - maxdiff;
123 
124 			// Put colors into texture
125 			index = (i * texsize + j) * 3;
126 			plasmamap[index] = fabstrunc (plasma[i][j][0]);
127 			plasmamap[index + 1] = fabstrunc (plasma[i][j][1]);
128 			plasmamap[index + 2] = fabstrunc (plasma[i][j][2]);
129 		}
130 	}
131 
132 	// Update texture
133 	glPixelStorei(GL_UNPACK_ROW_LENGTH, texsize);
134 	glBindTexture(GL_TEXTURE_2D, tex);
135 	glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, plasmaWidth, plasmaHeight, GL_RGB, GL_FLOAT, plasmamap);
136 
137 	// Draw it
138 	glBegin (GL_TRIANGLE_STRIP);
139 	glTexCoord2f (0.0f, 0.0f);
140 	glVertex2f (0.0f, 0.0f);
141 	glTexCoord2f (0.0f, texright);
142 	glVertex2f (1.0f, 0.0f);
143 	glTexCoord2f (textop, 0.0f);
144 	glVertex2f (0.0f, 1.0f);
145 	glTexCoord2f (textop, texright);
146 	glVertex2f (1.0f, 1.0f);
147 	glEnd ();
148 }
149 
hack_reshape(xstuff_t * XStuff)150 void hack_reshape (xstuff_t * XStuff)
151 {
152 	// Window initialization
153 	glViewport (0, 0, XStuff->windowWidth, XStuff->windowHeight);
154 
155 	glMatrixMode (GL_PROJECTION);
156 	glLoadIdentity ();
157 	gluOrtho2D (0.0f, 1.0f, 0.0f, 1.0f);
158 	glMatrixMode (GL_MODELVIEW);
159 	glLoadIdentity ();
160 }
161 
hack_init(xstuff_t * XStuff)162 void hack_init (xstuff_t * XStuff)
163 {
164 	int i, j;
165 
166 	hack_reshape (XStuff);
167 
168 	aspectRatio = float (XStuff->windowWidth) / float (XStuff->windowHeight);
169 
170 	if (aspectRatio >= 1.0f) {
171 		wide = 30.0f / float (dZoom);
172 
173 		high = wide / aspectRatio;
174 	} else {
175 		high = 30.0f / float (dZoom);
176 
177 		wide = high * aspectRatio;
178 	}
179 
180 	// Set resolution of plasma
181 	if (aspectRatio >= 1.0f)
182 		plasmaHeight = (dResolution * MAXTEXSIZE) / 100;
183 	else
184 		plasmaHeight = int (float (dResolution * MAXTEXSIZE) * aspectRatio * 0.01f);
185 
186 	plasmaWidth = int (float (plasmaHeight) / aspectRatio);
187 
188 	// Set resolution of texture
189 	texsize = 16;
190 	if (aspectRatio >= 1.0f)
191 		while (plasmaHeight > texsize)
192 			texsize *= 2;
193 	else
194 		while (plasmaWidth > texsize)
195 			texsize *= 2;
196 
197 	// The "- 1" cuts off right and top edges to get rid of blending to black
198 	texright = float (plasmaHeight - 1) / float (texsize);
199 	textop = texright / aspectRatio;
200 
201 	// Initialize memory and positions
202 	plasmamap = new float[texsize * texsize * 3];
203 
204 	for (i = 0; i < texsize * texsize * 3; i++)
205 		plasmamap[i] = 0.0f;
206 	plasma = new float **[plasmaHeight];
207 	position = new float **[plasmaHeight];
208 
209 	for (i = 0; i < plasmaHeight; i++) {
210 		plasma[i] = new float *[plasmaWidth];
211 		position[i] = new float *[plasmaWidth];
212 
213 		for (j = 0; j < plasmaWidth; j++) {
214 			plasma[i][j] = new float[3];
215 			position[i][j] = new float[2];
216 
217 			plasma[i][j][0] = 0.0f;
218 			plasma[i][j][1] = 0.0f;
219 			plasma[i][j][2] = 0.0f;
220 			position[i][j][0] = float (i * wide) / float (plasmaHeight - 1) - (wide * 0.5f);
221 			position[i][j][1] = float (j * high) / (float(plasmaHeight) / aspectRatio - 1.0f) - (high * 0.5f);
222 		}
223 	}
224 	// Initialize constants
225 	for (i = 0; i < NUMCONSTS; i++) {
226 		ct[i] = rsRandf (PIx2);
227 		cv[i] = rsRandf (0.005f * dSpeed) + 0.0001f;
228 	}
229 
230 	// Make texture
231 	glGenTextures(1, &tex);
232 	glBindTexture(GL_TEXTURE_2D, tex);
233 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
234 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
235 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
236 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
237 	glTexImage2D (GL_TEXTURE_2D, 0, 3, texsize, texsize, 0, GL_RGB, GL_FLOAT, plasmamap);
238 	glEnable (GL_TEXTURE_2D);
239 	glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
240 }
241 
hack_cleanup(xstuff_t * XStuff)242 void hack_cleanup (xstuff_t * XStuff)
243 {
244 }
245 
hack_handle_opts(int argc,char ** argv)246 void hack_handle_opts (int argc, char **argv)
247 {
248 	dZoom = 10;
249 	dFocus = 30;
250 	dSpeed = 20;
251 	dResolution = 25;
252 
253 	while (1) {
254 		int c;
255 
256 #ifdef HAVE_GETOPT_H
257 		static struct option long_options[] = {
258 			{"help", 0, 0, 'h'},
259 			DRIVER_OPTIONS_LONG
260 			{"zoom", 1, 0, 'z'},
261 			{"focus", 1, 0, 'f'},
262 			{"speed", 1, 0, 's'},
263 			{"resolution", 1, 0, 'R'},
264 			{0, 0, 0, 0}
265 		};
266 
267 		c = getopt_long (argc, argv, DRIVER_OPTIONS_SHORT "hz:f:s:R:", long_options, NULL);
268 #else
269 		c = getopt (argc, argv, DRIVER_OPTIONS_SHORT "hz:f:s:R:");
270 #endif
271 		if (c == -1)
272 			break;
273 
274 		switch (c) {
275 			DRIVER_OPTIONS_CASES case 'h':printf ("%s:"
276 #ifndef HAVE_GETOPT_H
277 							      " Not built with GNU getopt.h, long options *NOT* enabled."
278 #endif
279 							      "\n" DRIVER_OPTIONS_HELP "\t--zoom/-z <arg>\n" "\t--focus/-f <arg>\n" "\t--speed/-s <arg>\n"
280 							      "\t--resolution/-R <arg>\n", argv[0]);
281 			exit (1);
282 		case 'z':
283 			dZoom = strtol_minmaxdef (optarg, 10, 1, 100, 1, 10, "--zoom: ");
284 			break;
285 		case 'f':
286 			dFocus = strtol_minmaxdef (optarg, 10, 1, 100, 1, 30, "--focus: ");
287 			break;
288 		case 's':
289 			dSpeed = strtol_minmaxdef (optarg, 10, 1, 100, 1, 20, "--speed: ");
290 			break;
291 		case 'R':
292 			dResolution = strtol_minmaxdef (optarg, 10, 1, 100, 1, 25, "--resolution: ");
293 			break;
294 		}
295 	}
296 }
297