1 /* 2 * Copyright 2007-2009, 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 #include "SpiderSaver.h" 9 10 #include <math.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <Bitmap.h> 16 #include <Catalog.h> 17 #include <Message.h> 18 #include <Menu.h> 19 #include <MenuField.h> 20 #include <MenuItem.h> 21 #include <Slider.h> 22 #include <StringView.h> 23 24 #include "Polygon.h" 25 #include "PolygonQueue.h" 26 27 #undef B_TRANSLATION_CONTEXT 28 #define B_TRANSLATION_CONTEXT "Screensaver Spider" 29 30 enum { 31 MSG_QUEUE_NUMBER = 'qunm', 32 MSG_POLY_NUMBER = 'plnm', 33 MSG_QUEUE_DEPTH = 'qudp', 34 MSG_COLOR = 'colr', 35 }; 36 37 #define MIN_POLY_POINTS 3 38 #define MAX_POLY_POINTS 10 39 #define MIN_QUEUE_DEPTH 40 40 #define MAX_QUEUE_DEPTH 160 41 #define MAX_QUEUE_NUMBER 40 42 43 enum { 44 RED = 1, 45 GREEN = 2, 46 BLUE = 3, 47 YELLOW = 4, 48 PURPLE = 5, 49 CYAN = 6, 50 GRAY = 7, 51 }; 52 53 // MAIN INSTANTIATION FUNCTION 54 extern "C" _EXPORT BScreenSaver* 55 instantiate_screen_saver(BMessage *message, image_id image) 56 { 57 return new SpiderSaver(message, image); 58 } 59 60 // constructor 61 SpiderSaver::SpiderSaver(BMessage *message, image_id id) 62 : BScreenSaver(message, id), 63 fBackBitmap(NULL), 64 fBackView(NULL), 65 fQueues(new PolygonQueue*[MAX_QUEUE_NUMBER]), 66 fQueueNumber(20), 67 fMaxPolyPoints(MAX_POLY_POINTS), 68 fMaxQueueDepth(MAX_QUEUE_DEPTH), 69 fColor(RED), 70 fPreview(false) 71 { 72 for (int32 i = 0; i < MAX_QUEUE_NUMBER; i++) 73 fQueues[i] = NULL; 74 if (message) { 75 int32 value; 76 if (message->FindInt32("queue number", &value) == B_OK) 77 fQueueNumber = value; 78 if (message->FindInt32("poly points", &value) == B_OK) 79 fMaxPolyPoints = value; 80 if (message->FindInt32("queue depth", &value) == B_OK) 81 fMaxQueueDepth = value; 82 if (message->FindInt32("color", &value) == B_OK) 83 fColor = value; 84 } 85 srand48((long int)system_time()); 86 } 87 88 // destructor 89 SpiderSaver::~SpiderSaver() 90 { 91 _Cleanup(); 92 delete[] fQueues; 93 } 94 95 // StartConfig 96 void 97 SpiderSaver::StartConfig(BView *view) 98 { 99 SpiderView* configView = new SpiderView(view->Bounds(), this, 100 fQueueNumber, fMaxPolyPoints, fMaxQueueDepth, fColor); 101 view->AddChild(configView); 102 } 103 104 // StartSaver 105 status_t 106 SpiderSaver::StartSaver(BView *v, bool preview) 107 { 108 SetTickSize(50000); 109 110 fPreview = preview; 111 fBounds = v->Bounds(); 112 _Init(fBounds); 113 114 return B_OK; 115 } 116 117 // StopSaver 118 void 119 SpiderSaver::StopSaver() 120 { 121 _Cleanup(); 122 } 123 124 // Draw 125 void 126 SpiderSaver::Draw(BView *view, int32 frame) 127 { 128 fLocker.Lock(); 129 for (uint32 i = 0; i < fQueueNumber; i++) { 130 if (fQueues[i]) 131 fQueues[i]->Step(); 132 } 133 if (fBackView) { 134 if (fBackBitmap->Lock()) { 135 _DrawInto(fBackView); 136 fBackView->Sync(); 137 fBackBitmap->Unlock(); 138 } 139 view->DrawBitmap(fBackBitmap, BPoint(0.0, 0.0)); 140 } 141 fLocker.Unlock(); 142 } 143 144 // SaveState 145 status_t 146 SpiderSaver::SaveState(BMessage* into) const 147 { 148 if (into) { 149 into->AddInt32("queue number", (int32)fQueueNumber); 150 into->AddInt32("poly points", (int32)fMaxPolyPoints); 151 into->AddInt32("queue depth", (int32)fMaxQueueDepth); 152 into->AddInt32("color", (int32)fColor); 153 return B_OK; 154 } 155 return B_BAD_VALUE; 156 } 157 158 // SetQueueNumber 159 void 160 SpiderSaver::SetQueueNumber(uint32 number) 161 { 162 fLocker.Lock(); 163 _Cleanup(); 164 fQueueNumber = number; 165 _Init(fBounds); 166 fLocker.Unlock(); 167 } 168 169 // SetQueueDepth 170 void 171 SpiderSaver::SetQueueDepth(uint32 maxDepth) 172 { 173 fLocker.Lock(); 174 _Cleanup(); 175 fMaxQueueDepth = maxDepth; 176 _Init(fBounds); 177 fLocker.Unlock(); 178 } 179 180 // SetPolyPoints 181 void 182 SpiderSaver::SetPolyPoints(uint32 maxPoints) 183 { 184 fLocker.Lock(); 185 _Cleanup(); 186 fMaxPolyPoints = maxPoints; 187 _Init(fBounds); 188 fLocker.Unlock(); 189 } 190 191 // SetColor 192 void 193 SpiderSaver::SetColor(uint32 color) 194 { 195 fLocker.Lock(); 196 _Cleanup(); 197 fColor = color; 198 _Init(fBounds); 199 fLocker.Unlock(); 200 } 201 202 // _Init 203 void 204 SpiderSaver::_Init(BRect bounds) 205 { 206 _AllocBackBitmap(bounds.Width(), bounds.Height()); 207 uint32 minPoints = fMaxPolyPoints / 2; 208 uint32 maxPoints = fMaxPolyPoints; 209 uint32 minQueueDepth = fMaxQueueDepth / 2; 210 uint32 maxQueueDepth = fMaxQueueDepth; 211 if (fPreview) { 212 minQueueDepth /= 4; 213 maxQueueDepth /= 4; 214 } 215 for (uint32 i = 0; i < fQueueNumber; i++) 216 fQueues[i] = new PolygonQueue(new Polygon(bounds, minPoints 217 + lrand48() 218 % (maxPoints 219 - minPoints)), 220 minQueueDepth + lrand48() % (maxQueueDepth 221 - minQueueDepth)); 222 } 223 224 // _Cleanup 225 void 226 SpiderSaver::_Cleanup() 227 { 228 _FreeBackBitmap(); 229 for (int32 i = 0; i < MAX_QUEUE_NUMBER; i++) { 230 delete fQueues[i]; 231 fQueues[i] = NULL; 232 } 233 } 234 235 // _AllocBackBitmap 236 void 237 SpiderSaver::_AllocBackBitmap(float width, float height) 238 { 239 // sanity check 240 if (width <= 0.0 || height <= 0.0) 241 return; 242 243 BRect b(0.0, 0.0, width, height); 244 fBackBitmap = new BBitmap(b, B_RGB32, true); 245 if (!fBackBitmap) 246 return; 247 if (fBackBitmap->IsValid()) { 248 fBackView = new BView(b, 0, B_FOLLOW_NONE, B_WILL_DRAW); 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 // _FreeBackBitmap 258 void 259 SpiderSaver::_FreeBackBitmap() 260 { 261 if (fBackBitmap) { 262 delete fBackBitmap; 263 fBackBitmap = NULL; 264 fBackView = NULL; 265 } 266 } 267 268 // _DrawInto 269 void 270 SpiderSaver::_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 case BLUE: 278 view->SetHighColor(1, 1, 2, 255); 279 break; 280 case YELLOW: 281 view->SetHighColor(2, 2, 1, 255); 282 break; 283 case PURPLE: 284 view->SetHighColor(2, 1, 2, 255); 285 break; 286 case CYAN: 287 view->SetHighColor(1, 2, 2, 255); 288 break; 289 case GRAY: 290 view->SetHighColor(2, 2, 2, 255); 291 break; 292 case RED: 293 default: 294 view->SetHighColor(2, 1, 1, 255); 295 break; 296 } 297 298 if (fQueues[i] == NULL) 299 continue; 300 301 if (Polygon* p = fQueues[i]->Head()) { 302 view->SetDrawingMode(B_OP_ADD); 303 _DrawPolygon(p, view); 304 } 305 if (Polygon* p = fQueues[i]->Tail()) { 306 view->SetDrawingMode(B_OP_SUBTRACT); 307 _DrawPolygon(p, view); 308 } 309 } 310 } 311 312 // _DrawPolygon 313 void 314 SpiderSaver::_DrawPolygon(Polygon* polygon, BView *view) 315 { 316 int32 pointCount = polygon->CountPoints(); 317 if (pointCount > 1) { 318 BPoint p = polygon->PointAt(0); 319 view->MovePenTo(p); 320 for (int32 i = 1; i < pointCount; i++) 321 view->StrokeLine(polygon->PointAt(i)); 322 view->StrokeLine(p); 323 } 324 } 325 326 // constructor 327 SpiderView::SpiderView(BRect frame, SpiderSaver* saver, 328 uint32 queueNumber, uint32 maxPolyPoints, 329 uint32 maxQueueDepth, uint32 color) 330 : BView(frame, "spider view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED), 331 fSaver(saver) 332 { 333 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 334 335 frame.OffsetTo(0.0, 0.0); 336 frame.InsetBy(10.0, 5.0); 337 338 float viewHeight = floorf(frame.Height() / 5.0); 339 340 // title stuff 341 font_height fh; 342 be_bold_font->GetHeight(&fh); 343 float fontHeight = fh.ascent + fh.descent + 5.0; 344 frame.bottom = frame.top + fontHeight; 345 BStringView* title = new BStringView(frame, B_EMPTY_STRING, 346 B_TRANSLATE("Spider by stippi")); 347 title->SetFont(be_bold_font); 348 AddChild(title); 349 350 be_plain_font->GetHeight(&fh); 351 fontHeight = fh.ascent + fh.descent + 5.0; 352 frame.top = frame.bottom; 353 frame.bottom = frame.top + fontHeight; 354 title = new BStringView(frame, B_EMPTY_STRING, B_TRANSLATE("for bonefish")); 355 BFont font(be_plain_font); 356 font.SetShear(110.0); 357 title->SetFont(&font); 358 title->SetAlignment(B_ALIGN_CENTER); 359 AddChild(title); 360 361 // controls 362 frame.top = 10.0; 363 frame.bottom = frame.top + viewHeight; 364 frame.OffsetBy(0.0, viewHeight); 365 fQueueNumberS = new BSlider(frame, "queue number", 366 B_TRANSLATE("Max. polygon count"), new BMessage(MSG_QUEUE_NUMBER), 367 1, MAX_QUEUE_NUMBER); 368 fQueueNumberS->SetHashMarks(B_HASH_MARKS_BOTTOM); 369 fQueueNumberS->SetHashMarkCount((MAX_QUEUE_NUMBER - 1) / 2 + 1); 370 fQueueNumberS->SetValue(queueNumber); 371 AddChild(fQueueNumberS); 372 frame.OffsetBy(0.0, viewHeight); 373 fPolyNumberS = new BSlider(frame, "poly points", 374 B_TRANSLATE("Max. points per polygon"), new BMessage(MSG_POLY_NUMBER), 375 MIN_POLY_POINTS, MAX_POLY_POINTS); 376 fPolyNumberS->SetHashMarks(B_HASH_MARKS_BOTTOM); 377 fPolyNumberS->SetHashMarkCount(MAX_POLY_POINTS - MIN_POLY_POINTS + 1); 378 fPolyNumberS->SetValue(maxPolyPoints); 379 AddChild(fPolyNumberS); 380 frame.OffsetBy(0.0, viewHeight); 381 fQueueDepthS = new BSlider(frame, "queue depth", B_TRANSLATE("Trail depth"), 382 new BMessage(MSG_QUEUE_DEPTH), MIN_QUEUE_DEPTH, MAX_QUEUE_DEPTH); 383 fQueueDepthS->SetHashMarks(B_HASH_MARKS_BOTTOM); 384 fQueueDepthS->SetHashMarkCount((MAX_QUEUE_DEPTH - MIN_QUEUE_DEPTH) / 4 + 1); 385 fQueueDepthS->SetValue(maxQueueDepth); 386 AddChild(fQueueDepthS); 387 388 BMenu* menu = new BMenu(B_TRANSLATE("Color")); 389 BMessage* message = new BMessage(MSG_COLOR); 390 message->AddInt32("color", RED); 391 BMenuItem* item = new BMenuItem(B_TRANSLATE("Red"), message); 392 if (color == RED) 393 item->SetMarked(true); 394 menu->AddItem(item); 395 message = new BMessage(MSG_COLOR); 396 message->AddInt32("color", GREEN); 397 item = new BMenuItem(B_TRANSLATE("Green"), message); 398 if (color == GREEN) 399 item->SetMarked(true); 400 menu->AddItem(item); 401 message = new BMessage(MSG_COLOR); 402 message->AddInt32("color", BLUE); 403 item = new BMenuItem(B_TRANSLATE("Blue"), message); 404 if (color == BLUE) 405 item->SetMarked(true); 406 menu->AddItem(item); 407 message = new BMessage(MSG_COLOR); 408 message->AddInt32("color", YELLOW); 409 item = new BMenuItem(B_TRANSLATE("Yellow"), message); 410 if (color == YELLOW) 411 item->SetMarked(true); 412 menu->AddItem(item); 413 message = new BMessage(MSG_COLOR); 414 message->AddInt32("color", PURPLE); 415 item = new BMenuItem(B_TRANSLATE("Purple"), message); 416 if (color == PURPLE) 417 item->SetMarked(true); 418 menu->AddItem(item); 419 message = new BMessage(MSG_COLOR); 420 message->AddInt32("color", CYAN); 421 item = new BMenuItem(B_TRANSLATE("Cyan"), message); 422 if (color == CYAN) 423 item->SetMarked(true); 424 menu->AddItem(item); 425 message = new BMessage(MSG_COLOR); 426 message->AddInt32("color", GRAY); 427 item = new BMenuItem(B_TRANSLATE("Gray"), message); 428 if (color == GRAY) 429 item->SetMarked(true); 430 menu->AddItem(item); 431 432 menu->SetLabelFromMarked(true); 433 menu->SetRadioMode(true); 434 435 frame.OffsetBy(0.0, viewHeight); 436 fColorMF = new BMenuField(frame, "color", B_TRANSLATE("Color"), menu); 437 fColorMF->SetDivider(fColorMF->StringWidth(B_TRANSLATE("Color")) + 5.0); 438 AddChild(fColorMF); 439 } 440 441 // destructor 442 SpiderView::~SpiderView() 443 { 444 } 445 446 // AttachedToWindow 447 void 448 SpiderView::AttachedToWindow() 449 { 450 fQueueNumberS->SetTarget(this); 451 fPolyNumberS->SetTarget(this); 452 fQueueDepthS->SetTarget(this); 453 fColorMF->Menu()->SetTargetForItems(this); 454 } 455 456 // MessageReceived 457 void 458 SpiderView::MessageReceived(BMessage* message) 459 { 460 switch (message->what) { 461 case MSG_QUEUE_NUMBER: 462 fSaver->SetQueueNumber(fQueueNumberS->Value()); 463 break; 464 case MSG_POLY_NUMBER: 465 fSaver->SetPolyPoints(fPolyNumberS->Value()); 466 break; 467 case MSG_QUEUE_DEPTH: 468 fSaver->SetQueueDepth(fQueueDepthS->Value()); 469 break; 470 case MSG_COLOR: { 471 uint32 color; 472 if (message->FindInt32("color", (int32*)&color) == B_OK) 473 fSaver->SetColor(color); 474 break; 475 } 476 default: 477 BView::MessageReceived(message); 478 break; 479 } 480 } 481 482