1/*
2 * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
3 * Copyright 2006-2014, Haiku, Inc. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 *
7 * Authors:
8 *		Stephan A��mus, superstippi@gmx.de
9 *		Massimino Pascal, Pascal.Massimon@ens.fr
10 *		John Scipione, jscipione@gmail.com
11 */
12#include <math.h>
13#include <stdio.h>
14
15#include <Catalog.h>
16#include <CheckBox.h>
17#include <Slider.h>
18#include <TextView.h>
19
20#include "IFSSaver.h"
21
22
23#undef B_TRANSLATION_CONTEXT
24#define B_TRANSLATION_CONTEXT "Screensaver IFS"
25
26
27static const uint32 kMsgToggleAdditive		= 'tgad';
28static const uint32 kMsgSetSpeed			= 'stsp';
29
30
31//	#pragma mark - Instantiation function
32
33
34extern "C" _EXPORT BScreenSaver*
35instantiate_screen_saver(BMessage *message, image_id image)
36{
37	return new IFSSaver(message, image);
38}
39
40
41//	#pragma mark - IFSSaver
42
43
44IFSSaver::IFSSaver(BMessage* message, image_id id)
45	:
46	BScreenSaver(message, id),
47	BHandler("IFS Saver"),
48	fIFS(NULL),
49	fIsPreview(false),
50	fLastDrawnFrame(0),
51	fAdditive(false),
52	fSpeed(6)
53{
54	fDirectInfo.bits = NULL;
55	fDirectInfo.bytesPerRow = 0;
56
57	if (message == NULL)
58		return;
59
60	if (message->FindBool("IFS additive", &fAdditive) != B_OK)
61		fAdditive = false;
62	if (message->FindInt32("IFS speed", &fSpeed) != B_OK)
63		fSpeed = 6;
64}
65
66
67IFSSaver::~IFSSaver()
68{
69	if (Looper() != NULL)
70		Looper()->RemoveHandler(this);
71
72	_Cleanup();
73}
74
75
76void
77IFSSaver::StartConfig(BView* view)
78{
79	BRect bounds = view->Bounds();
80	bounds.InsetBy(10.0f, 10.0f);
81	BRect frame(0.0f, 0.0f, bounds.Width(), 20.0f);
82
83	// the additive check box
84	fAdditiveCB = new BCheckBox(frame, "additive setting",
85		B_TRANSLATE("Render dots additive"), new BMessage(kMsgToggleAdditive),
86		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
87
88	fAdditiveCB->SetValue(fAdditive);
89
90	fAdditiveCB->ResizeToPreferred();
91	bounds.bottom -= fAdditiveCB->Bounds().Height() * 2.0f;
92	fAdditiveCB->MoveTo(bounds.LeftBottom());
93
94	view->AddChild(fAdditiveCB);
95
96	// the additive check box
97	fSpeedS = new BSlider(frame, "speed setting",
98		B_TRANSLATE("Morphing speed:"), new BMessage(kMsgSetSpeed), 1, 12,
99		B_BLOCK_THUMB, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
100
101	fSpeedS->SetValue(fSpeed);
102	fSpeedS->SetHashMarks(B_HASH_MARKS_BOTTOM);
103	fSpeedS->SetHashMarkCount(12);
104
105	fSpeedS->ResizeToPreferred();
106	bounds.bottom -= fSpeedS->Bounds().Height() + 15.0f;
107	fSpeedS->MoveTo(bounds.LeftBottom());
108
109	view->AddChild(fSpeedS);
110
111	// the info text view
112	BRect textRect = bounds;
113	textRect.OffsetTo(0.0, 0.0);
114	BTextView* textView = new BTextView(bounds, B_EMPTY_STRING, textRect,
115		B_FOLLOW_ALL, B_WILL_DRAW);
116	textView->SetViewColor(view->ViewColor());
117
118	BString aboutScreenSaver(B_TRANSLATE("%screenSaverName%\n\n"
119		B_UTF8_COPYRIGHT " 1997 Massimino Pascal\n\n"
120		"xscreensaver port by Stephan A��mus\n"
121		"<stippi@yellowbites.com>"));
122	BString screenSaverName(B_TRANSLATE("Iterated Function System"));
123
124	aboutScreenSaver.ReplaceFirst("%screenSaverName%", screenSaverName);
125	textView->Insert(aboutScreenSaver);
126
127	textView->SetStylable(true);
128	textView->SetFontAndColor(0, screenSaverName.Length(), be_bold_font);
129
130	textView->MakeEditable(false);
131
132	view->AddChild(textView);
133
134	// make sure we receive messages from the views we added
135	if (BWindow* window = view->Window())
136		window->AddHandler(this);
137
138	fAdditiveCB->SetTarget(this);
139	fSpeedS->SetTarget(this);
140}
141
142
143status_t
144IFSSaver::StartSaver(BView* view, bool preview)
145{
146	display_mode mode;
147	BScreen screen(B_MAIN_SCREEN_ID);
148	screen.GetMode(&mode);
149	float totalSize = mode.timing.h_total * mode.timing.v_total;
150	float fps = mode.timing.pixel_clock * 1000.0f / totalSize;
151
152	SetTickSize((bigtime_t)floor(1000000.0 / fps + 0.5));
153
154	fIsPreview = preview;
155
156	if (view == NULL)
157		return B_BAD_VALUE;
158
159	_Init(view->Bounds());
160	if (fIFS == NULL)
161		return B_ERROR;
162
163	fIFS->SetAdditive(fAdditive || fIsPreview);
164	fIFS->SetSpeed(fSpeed);
165
166	return B_OK;
167}
168
169
170void
171IFSSaver::StopSaver()
172{
173	_Cleanup();
174}
175
176
177void
178IFSSaver::DirectConnected(direct_buffer_info* info)
179{
180	int32 request = info->buffer_state & B_DIRECT_MODE_MASK;
181
182	switch (request) {
183		case B_DIRECT_START:
184			fDirectInfo.bits = info->bits;
185			fDirectInfo.bytesPerRow = info->bytes_per_row;
186			fDirectInfo.bits_per_pixel = info->bits_per_pixel;
187			fDirectInfo.format = info->pixel_format;
188			fDirectInfo.bounds = info->window_bounds;
189			break;
190
191		case B_DIRECT_STOP:
192			fDirectInfo.bits = NULL;
193			break;
194	}
195}
196
197
198void
199IFSSaver::Draw(BView* view, int32 frame)
200{
201	if (frame == 0) {
202		fLastDrawnFrame = -1;
203		view->SetHighColor(0, 0, 0);
204		view->FillRect(view->Bounds());
205	}
206
207	int32 frames = frame - fLastDrawnFrame;
208	if ((fIsPreview || fDirectInfo.bits == NULL) && fLocker.Lock()) {
209		fIFS->Draw(view, NULL, frames);
210
211		fLastDrawnFrame = frame;
212		fLocker.Unlock();
213	}
214}
215
216
217void
218IFSSaver::DirectDraw(int32 frame)
219{
220	if (frame == 0)
221		fLastDrawnFrame = -1;
222
223	if (!fIsPreview && fDirectInfo.bits != NULL) {
224		fIFS->Draw(NULL, &fDirectInfo, frame - fLastDrawnFrame);
225		fLastDrawnFrame = frame;
226	}
227}
228
229
230status_t
231IFSSaver::SaveState(BMessage* into) const
232{
233	status_t ret = B_BAD_VALUE;
234	if (into != NULL) {
235		ret = into->AddBool("IFS additive", fAdditive);
236		if (ret >= B_OK)
237			ret = into->AddInt32("IFS speed", fSpeed);
238	}
239
240	return ret;
241}
242
243
244void
245IFSSaver::MessageReceived(BMessage* message)
246{
247	switch (message->what) {
248		case kMsgToggleAdditive:
249			if (fLocker.Lock() && fIFS != NULL) {
250				fAdditive = fAdditiveCB->Value() == B_CONTROL_ON;
251				fIFS->SetAdditive(fAdditive || fIsPreview);
252				fLocker.Unlock();
253			}
254			break;
255
256		case kMsgSetSpeed:
257			if (fLocker.Lock() && fIFS != NULL) {
258				fSpeed = fSpeedS->Value();
259				fIFS->SetSpeed(fSpeed);
260				fLocker.Unlock();
261			}
262			break;
263
264		default:
265			BHandler::MessageReceived(message);
266	}
267}
268
269
270void
271IFSSaver::_Init(BRect bounds)
272{
273	if (fLocker.Lock()) {
274		delete fIFS;
275		fIFS = new IFS(bounds);
276		fLocker.Unlock();
277	}
278}
279
280
281void
282IFSSaver::_Cleanup()
283{
284	if (fLocker.Lock()) {
285		delete fIFS;
286		fIFS = NULL;
287		fLocker.Unlock();
288	}
289}
290