1/*
2
3Copyright (c) 2002, Calum Robinson
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, 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
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
24ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27ANY 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
29SOFTWARE, 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
55using namespace BPrivate;
56
57
58//	#pragma mark - FlurryView
59
60
61FlurryView::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
81FlurryView::~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
97status_t
98FlurryView::InitCheck() const
99{
100	return (fFlurryInfo != NULL) ? B_OK : B_ERROR;
101}
102
103
104void
105FlurryView::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
139void
140FlurryView::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
208void
209FlurryView::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
238void
239FlurryView::_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
283double
284FlurryView::_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
291double
292FlurryView::_SecondsSinceStart() const
293{
294	return _CurrentTime() - fStartTime;
295}
296
297
298// #pragma mark - Flurry
299
300
301extern "C" BScreenSaver*
302instantiate_screen_saver(BMessage* archive, image_id imageId)
303{
304	return new Flurry(archive, imageId);
305}
306
307
308Flurry::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
320Flurry::~Flurry()
321{
322}
323
324
325status_t
326Flurry::InitCheck()
327{
328	return B_OK;
329}
330
331
332status_t
333Flurry::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
354void
355Flurry::StopSaver()
356{
357	if (fFlurryView != NULL)
358		fFlurryView->EnableDirectMode(false);
359}
360
361
362void
363Flurry::Draw(BView*, int32 frame)
364{
365	fFlurryView->DrawFlurryScreenSaver();
366}
367
368
369void
370Flurry::DirectConnected(direct_buffer_info* info)
371{
372	if (fFlurryView != NULL) {
373		fFlurryView->DirectConnected(info);
374		fFlurryView->EnableDirectMode(true);
375	}
376}
377
378
379void
380Flurry::StartConfig(BView* configView)
381{
382}
383
384
385void
386Flurry::StopConfig()
387{
388}
389
390
391status_t
392Flurry::SaveState(BMessage* into) const
393{
394	return B_ERROR;
395}
396