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