xref: /haiku/src/add-ons/screen_savers/flurry/Flurry.cpp (revision 579f1dbca962a2a03df54f69fdc6e9423f91f20e)
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 <new>
39 #include <sys/time.h>
40 #include <time.h>
41 #include <unistd.h>
42 
43 #include <Catalog.h>
44 
45 #include "Shared.h"
46 #include "Smoke.h"
47 #include "Spark.h"
48 #include "Star.h"
49 #include "Texture.h"
50 
51 
52 using namespace BPrivate;
53 
54 
55 FlurryView::FlurryView(BRect bounds)
56 	:
57 	BGLView(bounds, (const char *)NULL, B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW,
58 		BGL_RGB | BGL_ALPHA | BGL_DEPTH | BGL_DOUBLE),
59 	fOldFrameTime(-1.0),
60 	fFlurryInfo_t(NULL)
61 {
62 	B_TRANSLATE_MARK_SYSTEM_NAME_VOID("Flurry");
63 
64 	fWidth = bounds.Width();
65 	fHeight = bounds.Height();
66 	fStartTime = _CurrentTime();
67 
68 	LockGL();
69 	_SetupFlurryBaseInfo();
70 	UnlockGL();
71 
72 
73 }
74 
75 
76 FlurryView::~FlurryView()
77 {
78 	if (fFlurryInfo_t) {
79 		LockGL();
80 
81 		free(fFlurryInfo_t->s);
82 		free(fFlurryInfo_t->star);
83 		for (int32 i = 0; i < MAX_SPARKS; ++i)
84 			free(fFlurryInfo_t->spark[i]);
85 		free(fFlurryInfo_t);
86 
87 		UnlockGL();
88 	}
89 }
90 
91 
92 status_t
93 FlurryView::InitCheck() const
94 {
95 	return (fFlurryInfo_t != NULL) ? B_OK : B_ERROR;
96 }
97 
98 
99 void
100 FlurryView::AttachedToWindow()
101 {
102 	LockGL();
103 
104 	BGLView::AttachedToWindow();
105 
106 	MakeTexture();
107 
108 	glDisable(GL_DEPTH_TEST);
109 	glAlphaFunc(GL_GREATER, 0.0);
110 	glEnable(GL_ALPHA_TEST);
111 	glShadeModel(GL_FLAT);
112 	glDisable(GL_LIGHTING);
113 	glDisable(GL_CULL_FACE);
114 	glEnable(GL_BLEND);
115 
116 	glViewport(0, 0, int(fWidth), int(fHeight));
117 	glMatrixMode(GL_PROJECTION);
118 	glLoadIdentity();
119 	gluOrtho2D(0.0, fWidth, 0.0, fHeight);
120 	glMatrixMode(GL_MODELVIEW);
121 	glLoadIdentity();
122 
123 	glClearColor(0.0, 0.0, 0.0, 1.0);
124 	glClear(GL_COLOR_BUFFER_BIT);
125 
126 	glEnableClientState(GL_COLOR_ARRAY);
127 	glEnableClientState(GL_VERTEX_ARRAY);
128 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
129 
130 	UnlockGL();
131 }
132 
133 
134 void
135 FlurryView::DrawFlurryScreenSaver()
136 {
137 	double deltaFrameTime = 0.0;
138 	const double newFrameTime = _CurrentTime();
139 
140 	GLfloat alpha = 1.0;
141 	if (fOldFrameTime >= 0.0) {
142 		deltaFrameTime = newFrameTime - fOldFrameTime;
143 		alpha = 5.0 * deltaFrameTime;
144 
145 		if (alpha > 0.2)
146 			alpha = 0.2;
147 	}
148 
149 	fOldFrameTime = newFrameTime;
150 
151 	LockGL();
152 
153 	// TODO: enable once double buffering is supported
154 	//glDrawBuffer(GL_BACK);
155 
156 	glEnable(GL_BLEND);
157 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
158 
159 	glColor4f(0.0, 0.0, 0.0, alpha);
160 	glRectd(0.0, 0.0, fWidth, fHeight);
161 
162 	fFlurryInfo_t->dframe++;
163 	fFlurryInfo_t->fOldTime = fFlurryInfo_t->fTime;
164 	fFlurryInfo_t->fTime = _SecondsSinceStart() + fFlurryInfo_t->randomSeed;
165 	fFlurryInfo_t->fDeltaTime = fFlurryInfo_t->fTime - fFlurryInfo_t->fOldTime;
166 	fFlurryInfo_t->drag = (float)pow(0.9965, fFlurryInfo_t->fDeltaTime * 85.0);
167 
168 	UpdateStar(fFlurryInfo_t, fFlurryInfo_t->star);
169 
170 	glEnable(GL_BLEND);
171 	glShadeModel(GL_SMOOTH);
172 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
173 
174 	for (int32 i = 0; i < fFlurryInfo_t->numStreams; ++i) {
175 		fFlurryInfo_t->spark[i]->color[0] = 1.0;
176 		fFlurryInfo_t->spark[i]->color[1] = 1.0;
177 		fFlurryInfo_t->spark[i]->color[2] = 1.0;
178 		fFlurryInfo_t->spark[i]->color[3] = 1.0;
179 
180 		UpdateSpark(fFlurryInfo_t, fFlurryInfo_t->spark[i]);
181 	}
182 
183 	UpdateSmoke_ScalarBase(fFlurryInfo_t, fFlurryInfo_t->s);
184 
185 	glEnable(GL_BLEND);
186 	glEnable(GL_TEXTURE_2D);
187 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
188 
189 	const double brite = pow(deltaFrameTime, 0.75) * 10.0;
190 	DrawSmoke_Scalar(fFlurryInfo_t, fFlurryInfo_t->s,
191 		brite * fFlurryInfo_t->briteFactor);
192 
193 	glDisable(GL_TEXTURE_2D);
194 	glDisable(GL_BLEND);
195 
196 	glFinish();
197 
198 	SwapBuffers();
199 	UnlockGL();
200 }
201 
202 
203 void
204 FlurryView::FrameResized(float newWidth, float newHeight)
205 {
206 	LockGL();
207 
208 	BGLView::FrameResized(newWidth, newHeight);
209 
210 	if (fFlurryInfo_t) {
211 		fWidth = newWidth;
212 		fHeight = newHeight;
213 
214 		fFlurryInfo_t->sys_glWidth = fWidth;
215 		fFlurryInfo_t->sys_glHeight = fHeight;
216 
217 		glViewport(0, 0, int(fWidth), int(fHeight));
218 		glMatrixMode(GL_PROJECTION);
219 		glLoadIdentity();
220 		gluOrtho2D(0.0, fWidth, 0.0, fHeight);
221 		glMatrixMode(GL_MODELVIEW);
222 
223 		glClearColor(0.0, 0.0, 0.0, 1.0);
224 		glClear(GL_COLOR_BUFFER_BIT);
225 
226 		glFlush();
227 	}
228 
229 	UnlockGL();
230 }
231 
232 
233 void
234 FlurryView::_SetupFlurryBaseInfo()
235 {
236 	fFlurryInfo_t = (flurry_info_t *)malloc(sizeof(flurry_info_t));
237 
238 	if (!fFlurryInfo_t)
239 		return;
240 
241 	fFlurryInfo_t->next = NULL;
242 	fFlurryInfo_t->randomSeed = RandFlt(0.0, 300.0);
243 
244 	fFlurryInfo_t->dframe = 0;
245 	fFlurryInfo_t->fOldTime = 0.0;
246 	fFlurryInfo_t->sys_glWidth = fWidth;
247 	fFlurryInfo_t->sys_glHeight = fHeight;
248 	fFlurryInfo_t->fTime = _SecondsSinceStart() + fFlurryInfo_t->randomSeed;
249 	fFlurryInfo_t->fDeltaTime = fFlurryInfo_t->fTime - fFlurryInfo_t->fOldTime;
250 
251 	fFlurryInfo_t->numStreams = 5;
252 	fFlurryInfo_t->briteFactor = 1.0;
253 	fFlurryInfo_t->streamExpansion = 10000.0;
254 	fFlurryInfo_t->currentColorMode = tiedyeColorMode;
255 
256 	fFlurryInfo_t->s = (SmokeV*)malloc(sizeof(SmokeV));
257 	InitSmoke(fFlurryInfo_t->s);
258 
259 	fFlurryInfo_t->star = (Star*)malloc(sizeof(Star));
260 	InitStar(fFlurryInfo_t->star);
261 
262 	fFlurryInfo_t->star->rotSpeed = 1.0;
263 
264 	for (int32 i = 0; i < MAX_SPARKS; ++i) {
265 		fFlurryInfo_t->spark[i] = (Spark*)malloc(sizeof(Spark));
266 		InitSpark(fFlurryInfo_t->spark[i]);
267 		fFlurryInfo_t->spark[i]->mystery = 1800 * (i + 1) / 13;
268 		UpdateSpark(fFlurryInfo_t, fFlurryInfo_t->spark[i]);
269 	}
270 
271 	for (int32 i = 0; i < NUMSMOKEPARTICLES / 4; ++i) {
272 		for (int32 k = 0; k < 4; ++k)
273 			fFlurryInfo_t->s->p[i].dead.i[k] = 1;
274 	}
275 }
276 
277 
278 double
279 FlurryView::_CurrentTime() const
280 {
281 	return double(BDateTime::CurrentDateTime(B_LOCAL_TIME).Time_t() +
282 		double(BTime::CurrentTime(B_LOCAL_TIME).Millisecond() / 1000.0));
283 }
284 
285 
286 double
287 FlurryView::_SecondsSinceStart() const
288 {
289 	return _CurrentTime() - fStartTime;
290 }
291 
292 
293 // #pragma mark - Flurry
294 
295 
296 extern "C" BScreenSaver*
297 instantiate_screen_saver(BMessage* archive, image_id imageId)
298 {
299 	return new Flurry(archive, imageId);
300 }
301 
302 
303 Flurry::Flurry(BMessage* archive, image_id imageId)
304 	: BScreenSaver(archive, imageId),
305 	  fFlurryView(NULL)
306 {
307 	struct timeval tv;
308 	gettimeofday(&tv, NULL);
309 
310 	srand((999 * tv.tv_sec) + (1001 * tv.tv_usec) + (1003 * getpid()));
311 }
312 
313 
314 Flurry::~Flurry()
315 {
316 }
317 
318 
319 status_t
320 Flurry::InitCheck()
321 {
322 	return B_OK;
323 }
324 
325 
326 status_t
327 Flurry::StartSaver(BView* view, bool preview)
328 {
329 	status_t status = B_ERROR;
330 
331 	if (preview)
332 		return status;
333 
334 	SetTickSize(50000);
335 
336 	fFlurryView = new (std::nothrow) FlurryView(view->Bounds());
337 	if (fFlurryView) {
338 		if (fFlurryView->InitCheck() != B_OK) {
339 			delete fFlurryView;
340 			fFlurryView = NULL;
341 		} else {
342 			status = B_OK;
343 			view->AddChild(fFlurryView);
344 		}
345 	}
346 
347 	return status;
348 }
349 
350 
351 void
352 Flurry::StopSaver()
353 {
354 	if (fFlurryView != NULL)
355 		fFlurryView->EnableDirectMode(false);
356 }
357 
358 
359 void
360 Flurry::DirectDraw(int32 frame)
361 {
362 	fFlurryView->DrawFlurryScreenSaver();
363 }
364 
365 
366 void
367 Flurry::DirectConnected(direct_buffer_info* info)
368 {
369 	// Enable or disable direct rendering
370 	#if 1
371 	if (fFlurryView != NULL) {
372 		fFlurryView->DirectConnected(info);
373 		fFlurryView->EnableDirectMode(true);
374 	}
375 	#endif
376 }
377 
378 
379 void
380 Flurry::StartConfig(BView* configView)
381 {
382 }
383 
384 
385 void
386 Flurry::StopConfig()
387 {
388 }
389 
390 
391 status_t
392 Flurry::SaveState(BMessage* into) const
393 {
394 	return B_ERROR;
395 }
396