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, 217 minPoints + lrand48() % (maxPoints - minPoints)), 218 minQueueDepth + lrand48() % (maxQueueDepth - minQueueDepth)); 219 } 220 221 222 // _Cleanup 223 void 224 SpiderSaver::_Cleanup() 225 { 226 _FreeBackBitmap(); 227 for (int32 i = 0; i < MAX_QUEUE_NUMBER; i++) { 228 delete fQueues[i]; 229 fQueues[i] = NULL; 230 } 231 } 232 233 234 // _AllocBackBitmap 235 void 236 SpiderSaver::_AllocBackBitmap(float width, float height) 237 { 238 // sanity check 239 if (width <= 0.0 || height <= 0.0) 240 return; 241 242 BRect b(0.0, 0.0, width, height); 243 fBackBitmap = new(std::nothrow) BBitmap(b, B_RGB32, true); 244 if (!fBackBitmap) 245 return; 246 247 if (fBackBitmap->IsValid()) { 248 fBackView = new(std::nothrow) BView(b, 0, B_FOLLOW_NONE, B_WILL_DRAW); 249 if (fBackView == NULL) { 250 _FreeBackBitmap(); 251 fprintf(stderr, 252 "SpiderSaver::_AllocBackBitmap(): view allocation failed\n"); 253 return; 254 } 255 fBackBitmap->AddChild(fBackView); 256 memset(fBackBitmap->Bits(), 0, fBackBitmap->BitsLength()); 257 } else { 258 _FreeBackBitmap(); 259 fprintf(stderr, "SpiderSaver::_AllocBackBitmap(): bitmap invalid\n"); 260 } 261 } 262 263 264 // _FreeBackBitmap 265 void 266 SpiderSaver::_FreeBackBitmap() 267 { 268 if (fBackBitmap) { 269 delete fBackBitmap; 270 fBackBitmap = NULL; 271 fBackView = NULL; 272 } 273 } 274 275 276 // _DrawInto 277 void 278 SpiderSaver::_DrawInto(BView *view) 279 { 280 for (uint32 i = 0; i < fQueueNumber; i++) { 281 switch (fColor) { 282 case GREEN: 283 view->SetHighColor(1, 2, 1, 255); 284 break; 285 case BLUE: 286 view->SetHighColor(1, 1, 2, 255); 287 break; 288 case YELLOW: 289 view->SetHighColor(2, 2, 1, 255); 290 break; 291 case PURPLE: 292 view->SetHighColor(2, 1, 2, 255); 293 break; 294 case CYAN: 295 view->SetHighColor(1, 2, 2, 255); 296 break; 297 case GRAY: 298 view->SetHighColor(2, 2, 2, 255); 299 break; 300 case RED: 301 default: 302 view->SetHighColor(2, 1, 1, 255); 303 break; 304 } 305 306 if (fQueues[i] == NULL) 307 continue; 308 309 if (Polygon* p = fQueues[i]->Head()) { 310 view->SetDrawingMode(B_OP_ADD); 311 _DrawPolygon(p, view); 312 } 313 if (Polygon* p = fQueues[i]->Tail()) { 314 view->SetDrawingMode(B_OP_SUBTRACT); 315 _DrawPolygon(p, view); 316 } 317 } 318 } 319 320 // _DrawPolygon 321 void 322 SpiderSaver::_DrawPolygon(Polygon* polygon, BView *view) 323 { 324 int32 pointCount = polygon->CountPoints(); 325 if (pointCount > 1) { 326 BPoint p = polygon->PointAt(0); 327 view->MovePenTo(p); 328 for (int32 i = 1; i < pointCount; i++) 329 view->StrokeLine(polygon->PointAt(i)); 330 view->StrokeLine(p); 331 } 332 } 333 334 // constructor 335 SpiderView::SpiderView(BRect frame, SpiderSaver* saver, 336 uint32 queueNumber, uint32 maxPolyPoints, 337 uint32 maxQueueDepth, uint32 color) 338 : BView(frame, "spider view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED), 339 fSaver(saver) 340 { 341 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 342 343 frame.OffsetTo(0.0, 0.0); 344 frame.InsetBy(10.0, 5.0); 345 346 float viewHeight = floorf(frame.Height() / 5.0); 347 348 // title stuff 349 font_height fh; 350 be_bold_font->GetHeight(&fh); 351 float fontHeight = fh.ascent + fh.descent + 5.0; 352 frame.bottom = frame.top + fontHeight; 353 BStringView* title = new BStringView(frame, B_EMPTY_STRING, 354 B_TRANSLATE("Spider by stippi")); 355 title->SetFont(be_bold_font); 356 AddChild(title); 357 358 be_plain_font->GetHeight(&fh); 359 fontHeight = fh.ascent + fh.descent + 5.0; 360 frame.top = frame.bottom; 361 frame.bottom = frame.top + fontHeight; 362 title = new BStringView(frame, B_EMPTY_STRING, B_TRANSLATE("for bonefish")); 363 BFont font(be_plain_font); 364 font.SetShear(110.0); 365 title->SetFont(&font); 366 title->SetAlignment(B_ALIGN_CENTER); 367 AddChild(title); 368 369 // controls 370 frame.top = 10.0; 371 frame.bottom = frame.top + viewHeight; 372 frame.OffsetBy(0.0, viewHeight); 373 fQueueNumberS = new BSlider(frame, "queue number", 374 B_TRANSLATE("Max. polygon count"), new BMessage(MSG_QUEUE_NUMBER), 375 1, MAX_QUEUE_NUMBER); 376 fQueueNumberS->SetHashMarks(B_HASH_MARKS_BOTTOM); 377 fQueueNumberS->SetHashMarkCount((MAX_QUEUE_NUMBER - 1) / 2 + 1); 378 fQueueNumberS->SetValue(queueNumber); 379 AddChild(fQueueNumberS); 380 frame.OffsetBy(0.0, viewHeight); 381 fPolyNumberS = new BSlider(frame, "poly points", 382 B_TRANSLATE("Max. points per polygon"), new BMessage(MSG_POLY_NUMBER), 383 MIN_POLY_POINTS, MAX_POLY_POINTS); 384 fPolyNumberS->SetHashMarks(B_HASH_MARKS_BOTTOM); 385 fPolyNumberS->SetHashMarkCount(MAX_POLY_POINTS - MIN_POLY_POINTS + 1); 386 fPolyNumberS->SetValue(maxPolyPoints); 387 AddChild(fPolyNumberS); 388 frame.OffsetBy(0.0, viewHeight); 389 fQueueDepthS = new BSlider(frame, "queue depth", B_TRANSLATE("Trail depth"), 390 new BMessage(MSG_QUEUE_DEPTH), MIN_QUEUE_DEPTH, MAX_QUEUE_DEPTH); 391 fQueueDepthS->SetHashMarks(B_HASH_MARKS_BOTTOM); 392 fQueueDepthS->SetHashMarkCount((MAX_QUEUE_DEPTH - MIN_QUEUE_DEPTH) / 4 + 1); 393 fQueueDepthS->SetValue(maxQueueDepth); 394 AddChild(fQueueDepthS); 395 396 BMenu* menu = new BMenu(B_TRANSLATE("Color")); 397 BMessage* message = new BMessage(MSG_COLOR); 398 message->AddInt32("color", RED); 399 BMenuItem* item = new BMenuItem(B_TRANSLATE("Red"), message); 400 if (color == RED) 401 item->SetMarked(true); 402 menu->AddItem(item); 403 message = new BMessage(MSG_COLOR); 404 message->AddInt32("color", GREEN); 405 item = new BMenuItem(B_TRANSLATE("Green"), message); 406 if (color == GREEN) 407 item->SetMarked(true); 408 menu->AddItem(item); 409 message = new BMessage(MSG_COLOR); 410 message->AddInt32("color", BLUE); 411 item = new BMenuItem(B_TRANSLATE("Blue"), message); 412 if (color == BLUE) 413 item->SetMarked(true); 414 menu->AddItem(item); 415 message = new BMessage(MSG_COLOR); 416 message->AddInt32("color", YELLOW); 417 item = new BMenuItem(B_TRANSLATE("Yellow"), message); 418 if (color == YELLOW) 419 item->SetMarked(true); 420 menu->AddItem(item); 421 message = new BMessage(MSG_COLOR); 422 message->AddInt32("color", PURPLE); 423 item = new BMenuItem(B_TRANSLATE("Purple"), message); 424 if (color == PURPLE) 425 item->SetMarked(true); 426 menu->AddItem(item); 427 message = new BMessage(MSG_COLOR); 428 message->AddInt32("color", CYAN); 429 item = new BMenuItem(B_TRANSLATE("Cyan"), message); 430 if (color == CYAN) 431 item->SetMarked(true); 432 menu->AddItem(item); 433 message = new BMessage(MSG_COLOR); 434 message->AddInt32("color", GRAY); 435 item = new BMenuItem(B_TRANSLATE("Gray"), message); 436 if (color == GRAY) 437 item->SetMarked(true); 438 menu->AddItem(item); 439 440 menu->SetLabelFromMarked(true); 441 menu->SetRadioMode(true); 442 443 frame.OffsetBy(0.0, viewHeight); 444 fColorMF = new BMenuField(frame, "color", B_TRANSLATE("Color"), menu); 445 fColorMF->SetDivider(fColorMF->StringWidth(B_TRANSLATE("Color")) + 5.0); 446 AddChild(fColorMF); 447 } 448 449 // destructor 450 SpiderView::~SpiderView() 451 { 452 } 453 454 // AttachedToWindow 455 void 456 SpiderView::AttachedToWindow() 457 { 458 fQueueNumberS->SetTarget(this); 459 fPolyNumberS->SetTarget(this); 460 fQueueDepthS->SetTarget(this); 461 fColorMF->Menu()->SetTargetForItems(this); 462 } 463 464 // MessageReceived 465 void 466 SpiderView::MessageReceived(BMessage* message) 467 { 468 switch (message->what) { 469 case MSG_QUEUE_NUMBER: 470 fSaver->SetQueueNumber(fQueueNumberS->Value()); 471 break; 472 case MSG_POLY_NUMBER: 473 fSaver->SetPolyPoints(fPolyNumberS->Value()); 474 break; 475 case MSG_QUEUE_DEPTH: 476 fSaver->SetQueueDepth(fQueueDepthS->Value()); 477 break; 478 case MSG_COLOR: { 479 uint32 color; 480 if (message->FindInt32("color", (int32*)&color) == B_OK) 481 fSaver->SetColor(color); 482 break; 483 } 484 default: 485 BView::MessageReceived(message); 486 break; 487 } 488 } 489 490