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