xref: /haiku/src/add-ons/screen_savers/flurry/Flurry.cpp (revision 16d5c24e533eb14b7b8a99ee9f3ec9ba66335b1e)
1 /*
2 
3 Copyright (c) 2002, Calum Robinson
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9 * Redistributions of source code must retain the above copyright notice, this
10   list of conditions and the following disclaimer.
11 
12 * Redistributions in binary form must reproduce the above copyright notice,
13   this list of conditions and the following disclaimer in the documentation
14   and/or other materials provided with the distribution.
15 
16 * Neither the name of the author nor the names of its contributors may be used
17   to endorse or promote products derived from this software without specific
18   prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
24 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 */
32 /*
33  * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved.
34  * Distributed under the terms of the MIT License.
35  */
36 #include "Flurry.h"
37 
38 #include "Shared.h"
39 #include "Smoke.h"
40 #include "Spark.h"
41 #include "Star.h"
42 #include "Texture.h"
43 
44 
45 #include <new>
46 #include <time.h>
47 #include <unistd.h>
48 #include <sys/time.h>
49 
50 
51 using namespace BPrivate;
52 
53 
54 FlurryView::FlurryView(BRect bounds)
55 	: BGLView(bounds, NULL, B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW,
56 		BGL_RGB | BGL_ALPHA | BGL_DEPTH | BGL_DOUBLE),
57 	  fOldFrameTime(-1.0),
58 	  fFlurryInfo_t(NULL)
59 {
60 	fWidth = bounds.Width();
61 	fHeight = bounds.Height();
62 	fStartTime = _CurrentTime();
63 
64 	LockGL();
65 	_SetupFlurryBaseInfo();
66 	UnlockGL();
67 
68 
69 }
70 
71 
72 FlurryView::~FlurryView()
73 {
74 	if (fFlurryInfo_t) {
75 		LockGL();
76 
77 		free(fFlurryInfo_t->s);
78 		free(fFlurryInfo_t->star);
79 		for (int32 i = 0; i < MAX_SPARKS; ++i)
80 			free(fFlurryInfo_t->spark[i]);
81 		free(fFlurryInfo_t);
82 
83 		UnlockGL();
84 	}
85 }
86 
87 
88 status_t
89 FlurryView::InitCheck() const
90 {
91 	return (fFlurryInfo_t != NULL) ? B_OK : B_ERROR;
92 }
93 
94 
95 void
96 FlurryView::AttachedToWindow()
97 {
98 	LockGL();
99 
100 	BGLView::AttachedToWindow();
101 
102 	MakeTexture();
103 
104 	glDisable(GL_DEPTH_TEST);
105 	glAlphaFunc(GL_GREATER, 0.0);
106 	glEnable(GL_ALPHA_TEST);
107 	glShadeModel(GL_FLAT);
108 	glDisable(GL_LIGHTING);
109 	glDisable(GL_CULL_FACE);
110 	glEnable(GL_BLEND);
111 
112 	glViewport(0, 0, int(fWidth), int(fHeight));
113 	glMatrixMode(GL_PROJECTION);
114 	glLoadIdentity();
115 	gluOrtho2D(0.0, fWidth, 0.0, fHeight);
116 	glMatrixMode(GL_MODELVIEW);
117 	glLoadIdentity();
118 
119 	glClearColor(0.0, 0.0, 0.0, 1.0);
120 	glClear(GL_COLOR_BUFFER_BIT);
121 
122 	glEnableClientState(GL_COLOR_ARRAY);
123 	glEnableClientState(GL_VERTEX_ARRAY);
124 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
125 
126 	UnlockGL();
127 }
128 
129 
130 void
131 FlurryView::DrawFlurryScreenSaver()
132 {
133 	double deltaFrameTime = 0.0;
134 	const double newFrameTime = _CurrentTime();
135 
136 	GLfloat alpha = 1.0;
137 	if (fOldFrameTime >= 0.0) {
138 		deltaFrameTime = newFrameTime - fOldFrameTime;
139 		alpha = 5.0 * deltaFrameTime;
140 
141 		if (alpha > 0.2)
142 			alpha = 0.2;
143 	}
144 
145 	fOldFrameTime = newFrameTime;
146 
147 	LockGL();
148 
149 	// TODO: enable once double buffering is supported
150 	//glDrawBuffer(GL_BACK);
151 
152 	glEnable(GL_BLEND);
153 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
154 
155 	glColor4f(0.0, 0.0, 0.0, alpha);
156 	glRectd(0.0, 0.0, fWidth, fHeight);
157 
158 	fFlurryInfo_t->dframe++;
159 	fFlurryInfo_t->fOldTime = fFlurryInfo_t->fTime;
160 	fFlurryInfo_t->fTime = _SecondsSinceStart() + fFlurryInfo_t->randomSeed;
161 	fFlurryInfo_t->fDeltaTime = fFlurryInfo_t->fTime - fFlurryInfo_t->fOldTime;
162 	fFlurryInfo_t->drag = (float)pow(0.9965, fFlurryInfo_t->fDeltaTime * 85.0);
163 
164 	UpdateStar(fFlurryInfo_t, fFlurryInfo_t->star);
165 
166 	glEnable(GL_BLEND);
167 	glShadeModel(GL_SMOOTH);
168 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
169 
170 	for (int32 i = 0; i < fFlurryInfo_t->numStreams; ++i) {
171 		fFlurryInfo_t->spark[i]->color[0] = 1.0;
172 		fFlurryInfo_t->spark[i]->color[1] = 1.0;
173 		fFlurryInfo_t->spark[i]->color[2] = 1.0;
174 		fFlurryInfo_t->spark[i]->color[3] = 1.0;
175 
176 		UpdateSpark(fFlurryInfo_t, fFlurryInfo_t->spark[i]);
177 	}
178 
179 	UpdateSmoke_ScalarBase(fFlurryInfo_t, fFlurryInfo_t->s);
180 
181 	glEnable(GL_BLEND);
182 	glEnable(GL_TEXTURE_2D);
183 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
184 
185 	const double brite = pow(deltaFrameTime, 0.75) * 10.0;
186 	DrawSmoke_Scalar(fFlurryInfo_t, fFlurryInfo_t->s,
187 		brite * fFlurryInfo_t->briteFactor);
188 
189 	glDisable(GL_TEXTURE_2D);
190 	glDisable(GL_BLEND);
191 
192 	glFinish();
193 
194 	SwapBuffers();
195 	UnlockGL();
196 }
197 
198 
199 void
200 FlurryView::FrameResized(float newWidth, float newHeight)
201 {
202 	LockGL();
203 
204 	BGLView::FrameResized(newWidth, newHeight);
205 
206 	if (fFlurryInfo_t) {
207 		fWidth = newWidth;
208 		fHeight = newHeight;
209 
210 		fFlurryInfo_t->sys_glWidth = fWidth;
211 		fFlurryInfo_t->sys_glHeight = fHeight;
212 
213 		glViewport(0, 0, int(fWidth), int(fHeight));
214 		glMatrixMode(GL_PROJECTION);
215 		glLoadIdentity();
216 		gluOrtho2D(0.0, fWidth, 0.0, fHeight);
217 		glMatrixMode(GL_MODELVIEW);
218 
219 		glClearColor(0.0, 0.0, 0.0, 1.0);
220 		glClear(GL_COLOR_BUFFER_BIT);
221 
222 		glFlush();
223 	}
224 
225 	UnlockGL();
226 }
227 
228 
229 void
230 FlurryView::_SetupFlurryBaseInfo()
231 {
232 	fFlurryInfo_t = (flurry_info_t *)malloc(sizeof(flurry_info_t));
233 
234 	if (!fFlurryInfo_t)
235 		return;
236 
237 	fFlurryInfo_t->next = NULL;
238 	fFlurryInfo_t->randomSeed = RandFlt(0.0, 300.0);
239 
240 	fFlurryInfo_t->dframe = 0;
241 	fFlurryInfo_t->fOldTime = 0.0;
242 	fFlurryInfo_t->sys_glWidth = fWidth;
243 	fFlurryInfo_t->sys_glHeight = fHeight;
244 	fFlurryInfo_t->fTime = _SecondsSinceStart() + fFlurryInfo_t->randomSeed;
245 	fFlurryInfo_t->fDeltaTime = fFlurryInfo_t->fTime - fFlurryInfo_t->fOldTime;
246 
247 	fFlurryInfo_t->numStreams = 5;
248 	fFlurryInfo_t->briteFactor = 1.0;
249 	fFlurryInfo_t->streamExpansion = 10000.0;
250 	fFlurryInfo_t->currentColorMode = tiedyeColorMode;
251 
252 	fFlurryInfo_t->s = (SmokeV*)malloc(sizeof(SmokeV));
253 	InitSmoke(fFlurryInfo_t->s);
254 
255 	fFlurryInfo_t->star = (Star*)malloc(sizeof(Star));
256 	InitStar(fFlurryInfo_t->star);
257 
258 	fFlurryInfo_t->star->rotSpeed = 1.0;
259 
260 	for (int32 i = 0; i < MAX_SPARKS; ++i) {
261 		fFlurryInfo_t->spark[i] = (Spark*)malloc(sizeof(Spark));
262 		InitSpark(fFlurryInfo_t->spark[i]);
263 		fFlurryInfo_t->spark[i]->mystery = 1800 * (i + 1) / 13;
264 		UpdateSpark(fFlurryInfo_t, fFlurryInfo_t->spark[i]);
265 	}
266 
267 	for (int32 i = 0; i < NUMSMOKEPARTICLES / 4; ++i) {
268 		for (int32 k = 0; k < 4; ++k)
269 			fFlurryInfo_t->s->p[i].dead.i[k] = 1;
270 	}
271 }
272 
273 
274 double
275 FlurryView::_CurrentTime() const
276 {
277 	return double(fDateTime.CurrentDateTime(B_LOCAL_TIME).Time_t() +
278 		double(fTime.CurrentTime(B_LOCAL_TIME).Millisecond() / 1000.0));
279 }
280 
281 
282 double
283 FlurryView::_SecondsSinceStart() const
284 {
285 	return _CurrentTime() - fStartTime;
286 }
287 
288 
289 // #pragma mark - Flurry
290 
291 
292 extern "C" BScreenSaver*
293 instantiate_screen_saver(BMessage* archive, image_id imageId)
294 {
295 	return new Flurry(archive, imageId);
296 }
297 
298 
299 Flurry::Flurry(BMessage* archive, image_id imageId)
300 	: BScreenSaver(archive, imageId),
301 	  fFlurryView(NULL)
302 {
303 	struct timeval tv;
304 	gettimeofday(&tv, NULL);
305 
306 	srand((999 * tv.tv_sec) + (1001 * tv.tv_usec) + (1003 * getpid()));
307 }
308 
309 
310 Flurry::~Flurry()
311 {
312 }
313 
314 
315 status_t
316 Flurry::InitCheck()
317 {
318 	return B_OK;
319 }
320 
321 
322 status_t
323 Flurry::StartSaver(BView* view, bool preview)
324 {
325 	status_t status = B_ERROR;
326 
327 	if (preview)
328 		return status;
329 
330 	SetTickSize(50000);
331 
332 	fFlurryView = new (std::nothrow) FlurryView(view->Bounds());
333 	if (fFlurryView) {
334 		if (fFlurryView->InitCheck() != B_OK) {
335 			delete fFlurryView;
336 			fFlurryView = NULL;
337 		} else {
338 			status = B_OK;
339 			view->AddChild(fFlurryView);
340 		}
341 	}
342 
343 	return status;
344 }
345 
346 
347 void
348 Flurry::StopSaver()
349 {
350 	if (fFlurryView)
351 		fFlurryView->EnableDirectMode(false);
352 }
353 
354 
355 void
356 Flurry::DirectDraw(int32 frame)
357 {
358 	fFlurryView->DrawFlurryScreenSaver();
359 }
360 
361 
362 void
363 Flurry::DirectConnected(direct_buffer_info* info)
364 {
365 	if (fFlurryView) {
366 		fFlurryView->DirectConnected(info);
367 		fFlurryView->EnableDirectMode(true);
368 	}
369 }
370 
371 
372 void
373 Flurry::StartConfig(BView* configView)
374 {
375 }
376 
377 
378 void
379 Flurry::StopConfig()
380 {
381 }
382 
383 
384 status_t
385 Flurry::SaveState(BMessage* into) const
386 {
387 	return B_ERROR;
388 }
389