1/*
2 * Copyright 2007-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan A��mus, superstippi@gmx.de
7 */
8
9
10#include "SpiderSaver.h"
11
12#include <math.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include <Bitmap.h>
18#include <Catalog.h>
19#include <Message.h>
20
21#include "Polygon.h"
22#include "PolygonQueue.h"
23#include "SpiderView.h"
24
25
26#undef B_TRANSLATION_CONTEXT
27#define B_TRANSLATION_CONTEXT "Screensaver Spider"
28
29
30//	#pragma mark - Instantiation function
31
32
33extern "C" _EXPORT BScreenSaver*
34instantiate_screen_saver(BMessage* message, image_id image)
35{
36	return new SpiderSaver(message, image);
37}
38
39
40//	#pragma mark - SpiderSaver
41
42
43SpiderSaver::SpiderSaver(BMessage* message, image_id id)
44	:
45	BScreenSaver(message, id),
46	fBackBitmap(NULL),
47	fBackView(NULL),
48	fQueues(new PolygonQueue*[MAX_QUEUE_NUMBER]),
49	fQueueNumber(20),
50	fMaxPolyPoints(MAX_POLY_POINTS),
51	fMaxQueueDepth(MAX_QUEUE_DEPTH),
52	fColor(RED),
53	fPreview(false)
54{
55	for (int32 i = 0; i < MAX_QUEUE_NUMBER; i++)
56		fQueues[i] = NULL;
57
58	if (message != NULL) {
59		int32 value;
60		if (message->FindInt32("queue number", &value) == B_OK)
61			fQueueNumber = value;
62
63		if (message->FindInt32("poly points", &value) == B_OK)
64			fMaxPolyPoints = value;
65
66		if (message->FindInt32("queue depth", &value) == B_OK)
67			fMaxQueueDepth = value;
68
69		if (message->FindInt32("color", &value) == B_OK)
70			fColor = value;
71	}
72
73	srand48((long int)system_time());
74}
75
76
77SpiderSaver::~SpiderSaver()
78{
79	_Cleanup();
80	delete[] fQueues;
81}
82
83
84void
85SpiderSaver::StartConfig(BView* view)
86{
87	SpiderView* configView = new SpiderView(view->Bounds(), this,
88		fQueueNumber, fMaxPolyPoints, fMaxQueueDepth, fColor);
89	view->AddChild(configView);
90}
91
92
93status_t
94SpiderSaver::StartSaver(BView* view, bool preview)
95{
96	SetTickSize(50000);
97
98	fPreview = preview;
99	fBounds = view->Bounds();
100	_Init(fBounds);
101
102	return B_OK;
103}
104
105
106void
107SpiderSaver::StopSaver()
108{
109	_Cleanup();
110}
111
112
113void
114SpiderSaver::Draw(BView* view, int32 frame)
115{
116	fLocker.Lock();
117	for (uint32 i = 0; i < fQueueNumber; i++) {
118		if (fQueues[i])
119			fQueues[i]->Step();
120	}
121	if (fBackView) {
122		if (fBackBitmap->Lock()) {
123			_DrawInto(fBackView);
124			fBackView->Sync();
125			fBackBitmap->Unlock();
126		}
127		view->DrawBitmap(fBackBitmap, BPoint(0.0, 0.0));
128	}
129	fLocker.Unlock();
130}
131
132
133status_t
134SpiderSaver::SaveState(BMessage* into) const
135{
136	if (into != NULL) {
137		into->AddInt32("queue number", (int32)fQueueNumber);
138		into->AddInt32("poly points", (int32)fMaxPolyPoints);
139		into->AddInt32("queue depth", (int32)fMaxQueueDepth);
140		into->AddInt32("color", (int32)fColor);
141
142		return B_OK;
143	}
144
145	return B_BAD_VALUE;
146}
147
148
149void
150SpiderSaver::SetQueueNumber(uint32 number)
151{
152	fLocker.Lock();
153	_Cleanup();
154	fQueueNumber = number;
155	_Init(fBounds);
156	fLocker.Unlock();
157}
158
159
160void
161SpiderSaver::SetQueueDepth(uint32 maxDepth)
162{
163	fLocker.Lock();
164	_Cleanup();
165	fMaxQueueDepth = maxDepth;
166	_Init(fBounds);
167	fLocker.Unlock();
168}
169
170
171void
172SpiderSaver::SetPolyPoints(uint32 maxPoints)
173{
174	fLocker.Lock();
175	_Cleanup();
176	fMaxPolyPoints = maxPoints;
177	_Init(fBounds);
178	fLocker.Unlock();
179}
180
181
182void
183SpiderSaver::SetColor(uint32 color)
184{
185	fLocker.Lock();
186	_Cleanup();
187	fColor = color;
188	_Init(fBounds);
189	fLocker.Unlock();
190}
191
192
193//	#pragma mark - SpiderSaver private methods
194
195
196void
197SpiderSaver::_Init(BRect bounds)
198{
199	_AllocBackBitmap(bounds.Width(), bounds.Height());
200	uint32 minPoints = fMaxPolyPoints / 2;
201	uint32 maxPoints = fMaxPolyPoints;
202	uint32 minQueueDepth = fMaxQueueDepth / 2;
203	uint32 maxQueueDepth = fMaxQueueDepth;
204
205	if (fPreview) {
206		minQueueDepth /= 4;
207		maxQueueDepth /= 4;
208	}
209
210	for (uint32 i = 0; i < fQueueNumber; i++) {
211		fQueues[i] = new PolygonQueue(new Polygon(bounds,
212			minPoints + lrand48() % (maxPoints - minPoints)),
213			minQueueDepth + lrand48() % (maxQueueDepth - minQueueDepth));
214	}
215}
216
217
218void
219SpiderSaver::_Cleanup()
220{
221	_FreeBackBitmap();
222	for (int32 i = 0; i < MAX_QUEUE_NUMBER; i++) {
223		delete fQueues[i];
224		fQueues[i] = NULL;
225	}
226}
227
228
229void
230SpiderSaver::_AllocBackBitmap(float width, float height)
231{
232	// sanity check
233	if (width <= 0.0 || height <= 0.0)
234		return;
235
236	BRect b(0.0, 0.0, width, height);
237	fBackBitmap = new(std::nothrow) BBitmap(b, B_RGB32, true);
238	if (!fBackBitmap)
239		return;
240
241	if (fBackBitmap->IsValid()) {
242		fBackView = new(std::nothrow) BView(b, 0, B_FOLLOW_NONE, B_WILL_DRAW);
243		if (fBackView == NULL) {
244			_FreeBackBitmap();
245			fprintf(stderr,
246				"SpiderSaver::_AllocBackBitmap(): view allocation failed\n");
247			return;
248		}
249		fBackBitmap->AddChild(fBackView);
250		memset(fBackBitmap->Bits(), 0, fBackBitmap->BitsLength());
251	} else {
252		_FreeBackBitmap();
253		fprintf(stderr, "SpiderSaver::_AllocBackBitmap(): bitmap invalid\n");
254	}
255}
256
257
258void
259SpiderSaver::_FreeBackBitmap()
260{
261	if (fBackBitmap) {
262		delete fBackBitmap;
263		fBackBitmap = NULL;
264		fBackView = NULL;
265	}
266}
267
268
269void
270SpiderSaver::_DrawInto(BView* view)
271{
272	for (uint32 i = 0; i < fQueueNumber; i++) {
273		switch (fColor) {
274			case GREEN:
275				view->SetHighColor(1, 2, 1, 255);
276				break;
277
278			case BLUE:
279				view->SetHighColor(1, 1, 2, 255);
280				break;
281
282			case YELLOW:
283				view->SetHighColor(2, 2, 1, 255);
284				break;
285
286			case PURPLE:
287				view->SetHighColor(2, 1, 2, 255);
288				break;
289
290			case CYAN:
291				view->SetHighColor(1, 2, 2, 255);
292				break;
293
294			case GRAY:
295				view->SetHighColor(2, 2, 2, 255);
296				break;
297
298			case RED:
299			default:
300				view->SetHighColor(2, 1, 1, 255);
301				break;
302		}
303
304		if (fQueues[i] == NULL)
305			continue;
306
307		if (Polygon* p = fQueues[i]->Head()) {
308			view->SetDrawingMode(B_OP_ADD);
309			_DrawPolygon(p, view);
310		}
311
312		if (Polygon* p = fQueues[i]->Tail()) {
313			view->SetDrawingMode(B_OP_SUBTRACT);
314			_DrawPolygon(p, view);
315		}
316	}
317}
318
319
320void
321SpiderSaver::_DrawPolygon(Polygon* polygon, BView* view)
322{
323	int32 pointCount = polygon->CountPoints();
324	if (pointCount > 1) {
325		BPoint p = polygon->PointAt(0);
326		view->MovePenTo(p);
327		for (int32 i = 1; i < pointCount; i++)
328			view->StrokeLine(polygon->PointAt(i));
329
330		view->StrokeLine(p);
331	}
332}
333