1 /* 2 * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Copyright 2015, Augustin Cavalier <waddlesplash>. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Effect from corTeX / Optimum. 7 */ 8 9 #include <AppKit.h> 10 #include <Catalog.h> 11 #include <ControlLook.h> 12 #include <InterfaceKit.h> 13 #include <LayoutBuilder.h> 14 #include <Window.h> 15 #include <ScreenSaver.h> 16 #include <String.h> 17 #include <SupportDefs.h> 18 19 #include <math.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 25 #undef B_TRANSLATION_CONTEXT 26 #define B_TRANSLATION_CONTEXT "Nebula Screen Saver" 27 28 29 typedef struct 30 { 31 int x, y, z, r; 32 } p3; 33 34 typedef float matrix[3][3]; 35 36 #define GMAX 5000 37 p3 gal[GMAX]; 38 float precos[512]; 39 float presin[512]; 40 41 typedef unsigned short word; 42 43 extern "C" { 44 #include "Draw.h" 45 #include "DrawStars.h" 46 } 47 48 const uint32 kMsgWidth = 'widt'; 49 const uint32 kMsgColorScheme = 'cols'; 50 const uint32 kMsgBlankBorders = 'blbr'; 51 const uint32 kMsgMotionBlur = 'blur'; 52 const uint32 kMsgSpeed = 'sped'; 53 const uint32 kMsgFrames = 'mfps'; 54 55 float gSpeed; 56 bool gMotionBlur; 57 int32 gSettingsWidth; 58 int32 gWidth; 59 int32 gHeight; 60 float gMaxFramesPerSecond; 61 BBitmap* gBitmap; 62 BScreenSaver* gScreenSaver; 63 uint32 gPalette[256]; 64 int8 gPaletteScheme; 65 int8 gBlankBorders; 66 char* gBuffer8; /* working 8bit buffer */ 67 68 69 inline float 70 ocos(float a) 71 { 72 return (precos[(int)(a * 256 / M_PI) & 511]); 73 } 74 75 inline float 76 osin(float a) 77 { 78 return (presin[(int)(a * 256 / M_PI) & 511]); 79 } 80 81 82 void 83 mulmat(matrix* a, matrix* b, matrix* c) 84 { 85 int i, j; 86 87 for (i = 0; i < 3; i++) { 88 for (j = 0; j < 3; j++) { 89 (*c)[i][j] = (*a)[i][0] * (*b)[0][j] + 90 (*a)[i][1] * (*b)[1][j] + 91 (*a)[i][2] * (*b)[2][j]; 92 } 93 } 94 } 95 96 97 inline void 98 mulvec(matrix* a, float* x, float* y, float* z) 99 { 100 float nx = *x, ny = *y, nz = *z; 101 102 *x = nx * (*a)[0][0] + ny * (*a)[0][1] + nz * (*a)[0][2]; 103 *y = nx * (*a)[1][0] + ny * (*a)[1][1] + nz * (*a)[1][2]; 104 *z = nx * (*a)[2][0] + ny * (*a)[2][1] + nz * (*a)[2][2]; 105 } 106 107 108 void 109 setrmat(float a, float b, float c, matrix* m) 110 { 111 int i, j; 112 for (i = 0; i < 3; i++) 113 for (j = 0; j < 3; j++) 114 (*m)[i][j] = (float)(i == j); 115 116 if (a != 0) { 117 (*m)[0][0] = cos(a); (*m)[0][1] = sin(a); 118 (*m)[1][0] = sin(a); (*m)[1][1] = -cos(a); 119 return; 120 } 121 if (b != 0) { 122 (*m)[0][0] = cos(b); (*m)[0][2] = sin(b); 123 (*m)[2][0] = sin(b); (*m)[2][2] = -cos(b); 124 return; 125 } 126 (*m)[1][1] = cos(c); (*m)[1][2] = sin(c); 127 (*m)[2][1] = sin(c); (*m)[2][2] = -cos(c); 128 } 129 130 131 void 132 rotate3d(float* xr, float* yr, float* zr, /* point to rotate */ 133 float ax, float ay, float az) /* the 3 angles (order ?..) */ 134 { 135 float xr2, yr2, zr2; 136 137 xr2 = (*xr * ocos(az) + *yr * osin(az)); 138 yr2 = (*xr * osin(az) - *yr * ocos(az)); 139 *xr = xr2; 140 *yr = yr2; 141 142 xr2 = (*xr * ocos(ay) + *zr * osin(ay)); 143 zr2 = (*xr * osin(ay) - *zr * ocos(ay)); 144 *xr = xr2; 145 *zr = zr2; 146 147 zr2 = (*zr * ocos(ax) + *yr * osin(ax)); 148 yr2 = (*zr * osin(ax) - *yr * ocos(ax)); 149 *zr = zr2; 150 *yr = yr2; 151 } 152 153 154 void 155 drawshdisk(int x0, int y0, int r) 156 { 157 int x = 0; 158 int y; 159 int ly; /* last y */ 160 int delta; 161 int c; /* color at center */ 162 int d; /* delta */ 163 164 #define SLIMIT 17 165 #define SRANGE 15 166 167 if (r <= SLIMIT) { 168 /* range checking is already (more or less) done... */ 169 draw_stars(gWidth, &gBuffer8[x0 + gWidth * y0], 10 + r * 5); 170 //gBuffer8[x0 + W * y0] = 10 + r * 5; 171 return; 172 } 173 174 if (r < SLIMIT + SRANGE) 175 r = ((r - SLIMIT) * SLIMIT) / SRANGE + 1; 176 177 y = ly = r; /* AAaargh */ 178 delta = 3 - 2 * r; 179 180 do { 181 if (y != ly) { 182 /* dont overlap these lines */ 183 c = ((r - y + 1) << 13) / r; 184 d = -c / (x + 1); 185 186 if (y == x + 1) /* this would overlap with the next x lines */ 187 goto TOTO; /* WHY NOT */ 188 189 /* note : for "normal" numbers (not too big) : 190 (unsigned int)(x) < M <=> 0<=x<H 191 (because if x<0, then (unsigned)(x) = 2**32-|x| which is 192 BIG and thus >H ) 193 194 This is clearly a stupid, unmaintanable, unreadable 195 "optimization". But i like it :) 196 */ 197 if ((uint32)(y0 - y - 1) < gHeight - 3) 198 memshset(&gBuffer8[x0 + gWidth * (y0 - y + 1)], c, d, x); 199 200 if ((uint32)(y0 + y - 1) < gHeight - 3) 201 memshset(&gBuffer8[x0 + gWidth*(y0 + y)], c, d, x); 202 } 203 TOTO: 204 c = ((r - x + 1) << 13) / r; 205 d = -c / (y); 206 207 if ((uint32)(y0 - x - 1) < gHeight - 3) 208 memshset(&gBuffer8[x0 + gWidth*(y0 - x)], c, d, y); 209 if ((uint32)(y0 + x - 1) < gHeight - 3) 210 memshset(&gBuffer8[x0 + gWidth * (y0 + x + 1)], c, d, y); 211 212 ly = y; 213 if (delta < 0) 214 delta += 4 * x + 6; 215 else { 216 delta += 4 * (x - y) + 10; 217 y--; 218 } 219 x++; 220 } while (x < y); 221 } 222 223 224 void 225 drawGalaxy() 226 { 227 int r; 228 int x, y; 229 float rx, ry, rz; 230 int i; 231 float oa, ob, oc; 232 float t; 233 float a, b, c; 234 matrix ma, mb, mc, mr; 235 236 /* t is the parametric coordinate for the animation; 237 change the scale value to change the speed of anim 238 (independant of processor speed) 239 */ 240 static bigtime_t firstTime = system_time(); 241 t = ((double)gSpeed * system_time() - firstTime) / 1000000.0; 242 //opti_scale_time(0.418, &demo_elapsed_time); 243 244 a = 0.9 * t; 245 b = t; 246 c = 1.1 * t; 247 248 setrmat(a, 0, 0, &ma); 249 setrmat(0, b, 0, &mb); 250 mulmat(&ma, &mb, &mc); 251 setrmat(0, 0, c, &ma); 252 mulmat(&ma, &mc, &mr); 253 254 oa = 140 * osin(a); 255 ob = 140 * ocos(b); 256 oc = 240 * osin(c); 257 258 if (gMotionBlur) { 259 /* mblur does something like that: 260 * (or did, perhaps it's another version!..) 261 262 for (i = 0; i < W * H; i++) 263 gBuffer8[i]= (gBuffer8[i] >> 3) + (gBuffer8[i] >> 1); 264 */ 265 mblur (gBuffer8, gWidth * gHeight); 266 } else 267 memset(gBuffer8, 0, gWidth * gHeight); 268 269 for (i = 0; i < GMAX; i++) { 270 rx = gal[i].x; 271 ry = gal[i].y; 272 rz = gal[i].z; 273 274 mulvec(&mr, &rx, &ry, &rz); 275 276 rx += oa; 277 ry += ob; 278 rz += oc; 279 rz += 300; 280 281 if (rz > 5) { 282 x = (int)(15 * rx / (rz / 5 + 1)) + gWidth / 2; 283 /* tain jcomprend plus rien */ 284 y = (int)(15 * ry/ (rz / 5 + 1)) + gHeight / 2; 285 /* a ces formules de daube !! */ 286 r = (int)(3 * gal[i].r / (rz / 4 + 3)) + 2; 287 288 if (x > 5 && x < gWidth - 6 && y > 5 && y < gHeight - 6) 289 // if ((uint32)x < gWidth - 1 && (uint32)y < gHeight - 1) 290 drawshdisk(x, y, r); 291 } 292 } 293 } 294 295 296 void 297 setPalette() 298 { 299 int i; 300 301 switch (gPaletteScheme) { 302 case 0: // yellow 303 default: 304 for (i = 0; i < 30; i++) 305 gPalette[i] = (uint8)(i * 8 / 10) << 16 306 | (uint8)(i * 6 / 10) << 8; 307 // | (uint8)(i*3/10); 308 309 for (i = 30; i < 256; i++) { 310 uint8 r = (i); 311 uint8 g = (i * i >> 8); //(i*8/10); 312 uint8 b = i >= 240 ? (i - 240) << 3 : 0; //(i * 2 / 10); 313 314 gPalette[i] = ((r << 16) | (g << 8) | (b)); 315 } 316 break; 317 318 case 1: // blue 319 for (i = 0; i < 30; i++) 320 gPalette[i] = (uint8)(i * 8 / 10); 321 // << 16 | (uint8)(i * 6 / 10) << 8; 322 // | (uint8)(i * 3 / 10); 323 324 for (i = 30; i < 256; i++) { 325 uint8 b = (i); 326 uint8 g = (i * i >> 8); //(i * 8 / 10); 327 uint8 r = i >= 240 ? (i - 240) << 3 : 0; //(i * 2 / 10); 328 329 gPalette[i] = ((r << 16) | (g << 8) | (b)); 330 } 331 break; 332 333 case 2: // red 334 for (i = 0; i < 128; i++) 335 gPalette[i] = (uint8)i << 16; 336 // << 16 | (uint8)(i * 6/10) << 8; 337 // | (uint8)(i * 3 / 10); 338 339 for (i = 128;i < 256;i++) 340 { 341 uint8 r = i; 342 uint8 c = (uint8)((cos((i - 256) / 42.0) * 0.5 + 0.5) * 225); 343 344 gPalette[i] = ((r << 16) | (c << 8) | c); 345 } 346 /* for (i = 192; i < 224; i++) 347 { 348 uint8 c = (i - 192); 349 gPalette[i] = gPalette[i] & 0xff0000 | c << 8 | c; 350 } 351 for (i = 224; i < 256; i++) 352 { 353 uint8 c = (i-224) / 2; 354 c = 32 + c * c * 6 / 10; 355 gPalette[i] = gPalette[i] & 0xff0000 | c << 8 | c; 356 } 357 */ break; 358 359 case 3: // green 360 for (i = 0; i < 30; i++) 361 gPalette[i] = (uint8)(i * 8 / 10) << 8; 362 // << 16 | (uint8)(i * 6 / 10) << 8; 363 // | (uint8)(i * 3 / 10); 364 365 for (i = 30; i < 256; i++) { 366 uint8 g = (i); 367 uint8 r = (i * i >> 8); //(i * 8 / 10); 368 uint8 b = i >= 240 ? (i-240) << 3 : 0; //(i * 2 / 10); 369 370 gPalette[i] = ((r << 16) | (g << 8) | (b)); 371 } 372 break; 373 374 case 4: // grey 375 for (i = 0; i < 256; i++) { 376 uint8 c = i * 15 / 16 + 10; 377 gPalette[i] = c << 16 | c << 8 | c; 378 } 379 break; 380 case 5: // cold 381 for (i = 0; i < 30; i++) 382 gPalette[i] = (uint8)(i * 8 / 10) << 16; 383 // << 16 | (uint8)(i * 6 / 10) << 8; 384 // | (uint8)(i * 3 / 10); 385 386 for (i = 30; i < 256; i++) { 387 uint8 r = i; 388 uint8 c = (uint8)((cos((i - 255) / 82.0) * 0.5 + 0.5) * 255); 389 390 gPalette[i] = ((r << 16) | (c << 8) | c); 391 } 392 break; 393 394 case 6: // original 395 for (i = 0; i < 256; i++) { 396 uint32 c = *(char *)&i; 397 gPalette[i] = c << 16 | c << 8; 398 } 399 break; 400 } 401 /* for (i = 0;i < 256;i++) 402 { 403 uint8 r = (i); 404 uint8 g = (i * i >> 8); //(i * 8 / 10); 405 uint8 b = 0; //(i * 2 / 10); 406 407 gPalette[i] = ((r << 16) | (g << 8) | (b)); 408 } 409 */ 410 /* for (i = 240; i < 256; i++) 411 gPalette[i] = (uint8)i << 16 | (uint8)i << 8 | (uint8)(i * 6 / 10); 412 */ 413 } 414 415 416 // #pragma mark - SimpleSlider 417 418 419 class SimpleSlider : public BSlider { 420 public: 421 SimpleSlider(const char* label, BMessage* message) 422 : 423 BSlider(B_EMPTY_STRING, B_EMPTY_STRING, message, 1, 100, B_HORIZONTAL) 424 { 425 SetLimitLabels("1", "100"); 426 SetHashMarks(B_HASH_MARKS_BOTTOM); 427 SetHashMarkCount(11); 428 fLabel = label; 429 }; 430 431 const char* UpdateText() const 432 { 433 fText.SetToFormat("%s: %d", fLabel, Value()); 434 return fText.String(); 435 }; 436 437 private: 438 mutable BString fText; 439 const char* fLabel; 440 }; 441 442 443 // #pragma mark - SettingsView 444 445 446 class SettingsView : public BView { 447 public: 448 SettingsView(BRect frame); 449 450 virtual void AttachedToWindow(); 451 virtual void MessageReceived(BMessage* message); 452 453 private: 454 BMenuField* fWidthMenu; 455 BMenuField* fColorMenu; 456 BMenuField* fBorderMenu; 457 BCheckBox* fMotionCheck; 458 BSlider* fSpeedSlider; 459 BSlider* fFramesSlider; 460 }; 461 462 463 SettingsView::SettingsView(BRect frame) 464 : 465 BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW) 466 { 467 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 468 469 BStringView* titleString = new BStringView(B_EMPTY_STRING, 470 B_TRANSLATE("Nebula")); 471 titleString->SetFont(be_bold_font); 472 473 BStringView* copyrightString = new BStringView(B_EMPTY_STRING, 474 B_TRANSLATE("© 2001-2004 Axel Dörfler.")); 475 476 BPopUpMenu* popMenu; 477 BMenuItem* item; 478 479 int32 widths[] = { 480 0, 481 320, 482 512, 483 576, 484 640, 485 800, 486 1024, 487 1152, 488 1280, 489 1400, 490 1600 491 }; 492 493 size_t widthsLength = sizeof(widths) / sizeof(widths[0]); 494 495 popMenu = new BPopUpMenu(""); 496 for (size_t i = 0; i < widthsLength; i++) { 497 BString label; 498 if (widths[i] == 0) 499 label.SetTo("screen resolution"); 500 else 501 label.SetToFormat("%" B_PRId32 " pixels", widths[i]); 502 503 BMessage* message = new BMessage(kMsgWidth); 504 message->AddInt32("width", widths[i]); 505 506 const char* l = label.String(); 507 popMenu->AddItem(item = new BMenuItem(B_TRANSLATE(l), message)); 508 509 if (gSettingsWidth == widths[i]) 510 item->SetMarked(true); 511 } 512 513 fWidthMenu = new BMenuField("res", B_TRANSLATE("Internal width:"), 514 popMenu); 515 516 const char* colorSchemes[] = { 517 B_TRANSLATE("yellow"), 518 B_TRANSLATE("cyan"), 519 B_TRANSLATE("red"), 520 B_TRANSLATE("green"), 521 B_TRANSLATE("grey"), 522 B_TRANSLATE("cold"), 523 B_TRANSLATE("orange (original)") 524 }; 525 526 popMenu = new BPopUpMenu(""); 527 for (int i = 0; i < 7; i++) { 528 BMessage* message = new BMessage(kMsgColorScheme); 529 message->AddInt8("scheme", (int8)i); 530 popMenu->AddItem(item = new BMenuItem(colorSchemes[i], message)); 531 if (gPaletteScheme == i) 532 item->SetMarked(true); 533 } 534 535 fColorMenu = new BMenuField("col", B_TRANSLATE("Color:"), popMenu); 536 537 const char* blankBorderFormats[] = { 538 B_TRANSLATE("fullscreen, no borders"), 539 B_TRANSLATE("16:9, wide-screen"), 540 B_TRANSLATE("2:3.5, cinemascope"), 541 B_TRANSLATE("only a slit") 542 }; 543 544 popMenu = new BPopUpMenu(""); 545 for (int8 i = 0; i < 4; i++) { 546 BMessage* message = new BMessage(kMsgBlankBorders); 547 message->AddInt8("border", i); 548 popMenu->AddItem(item = new BMenuItem(blankBorderFormats[i], message)); 549 if (gBlankBorders == i) 550 item->SetMarked(true); 551 } 552 553 fBorderMenu = new BMenuField("cinema", B_TRANSLATE("Format:"), popMenu); 554 555 fMotionCheck = new BCheckBox(B_EMPTY_STRING, 556 B_TRANSLATE("Enable motion blur"), new BMessage(kMsgMotionBlur)); 557 fMotionCheck->SetValue((int)gMotionBlur); 558 559 fSpeedSlider = new SimpleSlider(B_TRANSLATE("Speed"), 560 new BMessage(kMsgSpeed)); 561 fSpeedSlider->SetValue((gSpeed - 0.002) / 0.05); 562 563 fFramesSlider = new SimpleSlider(B_TRANSLATE("Maximum Frames Per Second"), 564 new BMessage(kMsgFrames)); 565 fFramesSlider->SetValue(gMaxFramesPerSecond); 566 567 BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_HALF_ITEM_SPACING) 568 .SetInsets(B_USE_DEFAULT_SPACING) 569 .Add(titleString) 570 .Add(copyrightString) 571 .AddStrut(roundf(be_control_look->DefaultItemSpacing() / 2)) 572 .AddGlue() 573 .AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING) 574 .Add(fColorMenu->CreateLabelLayoutItem(), 0, 0) 575 .AddGroup(B_HORIZONTAL, 0.0f, 1, 0) 576 .Add(fColorMenu->CreateMenuBarLayoutItem(), 0.0f) 577 .AddGlue() 578 .End() 579 .Add(fWidthMenu->CreateLabelLayoutItem(), 0, 1) 580 .AddGroup(B_HORIZONTAL, 0.0f, 1, 1) 581 .Add(fWidthMenu->CreateMenuBarLayoutItem(), 0.0f) 582 .AddGlue() 583 .End() 584 .Add(fBorderMenu->CreateLabelLayoutItem(), 0, 2) 585 .AddGroup(B_HORIZONTAL, 0.0f, 1, 2) 586 .Add(fBorderMenu->CreateMenuBarLayoutItem(), 0.0f) 587 .AddGlue() 588 .End() 589 .Add(fMotionCheck, 1, 3) 590 .End() 591 .Add(fSpeedSlider) 592 .Add(fFramesSlider) 593 .End(); 594 } 595 596 597 void 598 SettingsView::AttachedToWindow() 599 { 600 fWidthMenu->Menu()->SetTargetForItems(this); 601 fColorMenu->Menu()->SetTargetForItems(this); 602 fBorderMenu->Menu()->SetTargetForItems(this); 603 fMotionCheck->SetTarget(this); 604 fSpeedSlider->SetTarget(this); 605 fFramesSlider->SetTarget(this); 606 } 607 608 609 void 610 SettingsView::MessageReceived(BMessage* message) 611 { 612 switch(message->what) { 613 case kMsgWidth: 614 message->FindInt32("width", &gSettingsWidth); 615 break; 616 617 case kMsgColorScheme: 618 if (message->FindInt8("scheme", &gPaletteScheme) == B_OK) 619 setPalette(); 620 break; 621 622 case kMsgBlankBorders: 623 message->FindInt8("border", &gBlankBorders); 624 break; 625 626 case kMsgMotionBlur: 627 gMotionBlur = fMotionCheck->Value() > 0; 628 break; 629 630 case kMsgSpeed: 631 gSpeed = 0.002 + 0.05 * fSpeedSlider->Value(); 632 break; 633 634 case kMsgFrames: 635 gMaxFramesPerSecond = fFramesSlider->Value(); 636 gScreenSaver->SetTickSize( 637 (bigtime_t)(1000000LL / gMaxFramesPerSecond)); 638 break; 639 } 640 } 641 642 643 644 // #pragma mark - Nebula 645 646 647 class Nebula : public BScreenSaver { 648 public: 649 Nebula(BMessage* message, image_id id); 650 651 virtual void StartConfig(BView* view); 652 virtual status_t SaveState(BMessage* state) const; 653 654 virtual status_t StartSaver(BView* view, bool preview); 655 virtual void StopSaver(); 656 virtual void Draw(BView* view, int32 frame); 657 658 private: 659 float fFactor; 660 bool fStarted; 661 }; 662 663 664 Nebula::Nebula(BMessage* message, image_id id) 665 : 666 BScreenSaver(message, id), 667 fStarted(false) 668 { 669 message->FindFloat("speed", 0, &gSpeed); 670 message->FindInt32("width", 0, &gSettingsWidth); 671 message->FindBool("motionblur", 0, &gMotionBlur); 672 message->FindFloat("max_fps", 0, &gMaxFramesPerSecond); 673 message->FindInt8("scheme", 0, &gPaletteScheme); 674 message->FindInt8("border", 0, &gBlankBorders); 675 676 if (gSpeed < 0.01f) 677 gSpeed = 0.4f; 678 679 if (gMaxFramesPerSecond < 1.f) 680 gMaxFramesPerSecond = 40.0f; 681 682 gScreenSaver = this; 683 } 684 685 686 void 687 Nebula::StartConfig(BView* view) 688 { 689 view->AddChild(new SettingsView(view->Bounds())); 690 } 691 692 693 status_t 694 Nebula::SaveState(BMessage* state) const 695 { 696 state->AddFloat("speed", gSpeed); 697 state->AddInt32("width", gSettingsWidth); 698 state->AddBool("motionblur", gMotionBlur); 699 state->AddFloat("max_fps", gMaxFramesPerSecond); 700 state->AddInt8("scheme", gPaletteScheme); 701 state->AddInt8("border", gBlankBorders); 702 703 return B_OK; 704 } 705 706 707 status_t 708 Nebula::StartSaver(BView* view, bool preview) 709 { 710 // initialize palette 711 setPalette(); 712 713 int i; 714 for (i = 0; i < 512; i++) { 715 precos[i]=cos(i * M_PI / 256); 716 presin[i]=sin(i * M_PI / 256); 717 } 718 719 // uniforme cubique 720 /* for (i = 0;i < GMAX;i++) 721 { 722 gal[i].x = 1 * ((rand()&1023) - 512); 723 gal[i].y = 1 * ((rand()&1023) - 512); 724 gal[i].z = 1 * ((rand()&1023) - 512); 725 gal[i].r = rand() & 63; 726 } 727 */ 728 729 for (i = 0; i < GMAX; i++) { 730 float r, th, h, dth; 731 732 r = rand() * 1.0 / RAND_MAX; 733 r = (1 - r) * (1 - r) + 0.05; 734 735 if (r < 0.12) 736 th = rand() * M_PI * 2 / RAND_MAX; 737 else { 738 th = (rand() & 3) * M_PI_2 + r * r * 2; 739 dth = rand() * 1.0 / RAND_MAX; 740 dth = dth * dth * 2; 741 th += dth; 742 } 743 gal[i].x = (int)(512 * r * cos(th)); 744 gal[i].z = (int)(512 * r * sin(th)); 745 h = (1 + cos(r * M_PI)) * 150; 746 dth = rand() * 1.0 / RAND_MAX; 747 gal[i].y = (int)(h * (dth - 0.5)); 748 gal[i].r = (int)((2 - r) * 60 + 31); 749 } 750 gal[0].x = gal[0].y = gal[0].z = 0; 751 gal[0].r = 320; 752 753 if (gSettingsWidth == 0) 754 gWidth = view->Bounds().Width(); 755 else 756 gWidth = gSettingsWidth; 757 758 fFactor = (view->Bounds().Width()+1) / gWidth; 759 if ((int)fFactor != fFactor) 760 fFactor += 0.01; 761 762 // 4:3 763 gHeight = (int32)((view->Bounds().Height()+1)/fFactor + 0.5f); 764 // calculate blank border format (if not in preview) 765 if (!preview) switch (gBlankBorders) { 766 case 1: // 16:9 767 gHeight = (int32)(gHeight * 0.703125 + 0.5); 768 break; 769 case 2: // 2:3.5 770 gHeight = (int32)(gHeight * 0.534 + 0.5); 771 break; 772 case 3: 773 gHeight /= 5; 774 break; 775 } 776 view->SetScale(fFactor); 777 778 gBitmap = new BBitmap(BRect(0, 0, gWidth - 1, gHeight - 1), B_RGB32); 779 gBuffer8 = (char*)malloc(gWidth * gHeight); 780 781 SetTickSize((bigtime_t)(1000000LL / gMaxFramesPerSecond)); 782 fStarted = true; 783 784 return B_OK; 785 } 786 787 788 void 789 Nebula::StopSaver() 790 { 791 free(gBuffer8); 792 gBuffer8 = NULL; 793 794 delete gBitmap; 795 gBitmap = NULL; 796 } 797 798 799 void 800 Nebula::Draw(BView* view, int32) 801 { 802 if (fStarted) { 803 view->SetHighColor(0, 0, 0, 0); 804 view->FillRect(view->Frame()); 805 view->MovePenTo(0, 806 (view->Bounds().Height() / fFactor - 1 - gHeight) / 2); 807 808 fStarted = false; 809 } 810 uint32* buffer32 = (uint32*)gBitmap->Bits(); 811 812 drawGalaxy(); 813 814 for (int x = 0, end = gWidth * gHeight; x < end; x++) 815 buffer32[x] = gPalette[(uint8)gBuffer8[x]]; 816 817 view->DrawBitmap(gBitmap); 818 } 819 820 821 // #pragma mark - instantiate_screen_saver 822 823 824 extern "C" _EXPORT BScreenSaver* 825 instantiate_screen_saver(BMessage* message, image_id image) 826 { 827 return new Nebula(message, image); 828 } 829