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