xref: /haiku/src/add-ons/screen_savers/ifs/IFSSaver.cpp (revision 3e216965baa8d58a67bf7372e2bfa13d999f5a9d)
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) {
194 		fIFS->Draw(view, NULL, frames);
195 
196 		fLastDrawnFrame = frame;
197 	}
198 }
199 
200 // DirectDraw
201 void
202 IFSSaver::DirectDraw(int32 frame)
203 {
204 //bigtime_t now = system_time();
205 //printf("IFSSaver::DirectDraw(%ld)\n", frame);
206 	if (frame == 0)
207 		fLastDrawnFrame = -1;
208 	int32 frames = frame - fLastDrawnFrame;
209 	if (fDirectInfo.bits) {
210 		fIFS->Draw(NULL, &fDirectInfo, frames);
211 //printf("DirectDraw(): %lldµs\n", system_time() - now);
212 		fLastDrawnFrame = frame;
213 	}
214 }
215 
216 // SaveState
217 status_t
218 IFSSaver::SaveState(BMessage* into) const
219 {
220 	status_t ret = B_BAD_VALUE;
221 	if (into) {
222 		ret = into->AddBool("IFS additive", fAdditive);
223 		if (ret >= B_OK)
224 			ret = into->AddInt32("IFS speed", fSpeed);
225 	}
226 	return ret;
227 }
228 
229 // MessageReceived
230 void
231 IFSSaver::MessageReceived(BMessage* message)
232 {
233 	switch (message->what) {
234 		case MSG_TOGGLE_ADDITIVE:
235 			if (fLocker.Lock() && fIFS) {
236 				fAdditive = fAdditiveCB->Value() == B_CONTROL_ON;
237 				fIFS->SetAdditive(fAdditive || fIsPreview);
238 				fLocker.Unlock();
239 			}
240 			break;
241 		case MSG_SET_SPEED:
242 			if (fLocker.Lock() && fIFS) {
243 				fSpeed = fSpeedS->Value();
244 				fIFS->SetSpeed(fSpeed);
245 				fLocker.Unlock();
246 			}
247 			break;
248 		default:
249 			BHandler::MessageReceived(message);
250 	}
251 }
252 
253 // _Init
254 void
255 IFSSaver::_Init(BRect bounds)
256 {
257 	if (fLocker.Lock()) {
258 		delete fIFS;
259 		fIFS = new IFS(bounds);
260 		fLocker.Unlock();
261 	}
262 }
263 
264 // _Cleanup
265 void
266 IFSSaver::_Cleanup()
267 {
268 	if (fLocker.Lock()) {
269 		delete fIFS;
270 		fIFS = NULL;
271 		fLocker.Unlock();
272 	}
273 }
274 
275