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 "optimization". 195 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 | (uint8)(i * 6 / 10) << 8; 306 // | (uint8)(i*3/10); 307 308 for (i = 30; i < 256; i++) { 309 uint8 r = (i); 310 uint8 g = (i * i >> 8); //(i*8/10); 311 uint8 b = i >= 240 ? (i - 240) << 3 : 0; //(i * 2 / 10); 312 313 gPalette[i] = ((r << 16) | (g << 8) | (b)); 314 } 315 break; 316 317 case 1: // blue 318 for (i = 0; i < 30; i++) 319 gPalette[i] = (uint8)(i * 8 / 10); 320 // << 16 | (uint8)(i * 6 / 10) << 8; 321 // | (uint8)(i * 3 / 10); 322 323 for (i = 30; i < 256; i++) { 324 uint8 b = (i); 325 uint8 g = (i * i >> 8); //(i * 8 / 10); 326 uint8 r = i >= 240 ? (i - 240) << 3 : 0; //(i * 2 / 10); 327 328 gPalette[i] = ((r << 16) | (g << 8) | (b)); 329 } 330 break; 331 332 case 2: // red 333 for (i = 0; i < 128; i++) 334 gPalette[i] = (uint8)i << 16; 335 // << 16 | (uint8)(i * 6/10) << 8; 336 // | (uint8)(i * 3 / 10); 337 338 for (i = 128;i < 256;i++) 339 { 340 uint8 r = i; 341 uint8 c = (uint8)((cos((i - 256) / 42.0) * 0.5 + 0.5) * 225); 342 343 gPalette[i] = ((r << 16) | (c << 8) | c); 344 } 345 /* for (i = 192; i < 224; i++) 346 { 347 uint8 c = (i - 192); 348 gPalette[i] = gPalette[i] & 0xff0000 | c << 8 | c; 349 } 350 for (i = 224; i < 256; i++) 351 { 352 uint8 c = (i-224) / 2; 353 c = 32 + c * c * 6 / 10; 354 gPalette[i] = gPalette[i] & 0xff0000 | c << 8 | c; 355 } 356 */ break; 357 358 case 3: // green 359 for (i = 0; i < 30; i++) 360 gPalette[i] = (uint8)(i * 8 / 10) << 8; 361 // << 16 | (uint8)(i * 6 / 10) << 8; 362 // | (uint8)(i * 3 / 10); 363 364 for (i = 30; i < 256; i++) { 365 uint8 g = (i); 366 uint8 r = (i * i >> 8); //(i * 8 / 10); 367 uint8 b = i >= 240 ? (i-240) << 3 : 0; //(i * 2 / 10); 368 369 gPalette[i] = ((r << 16) | (g << 8) | (b)); 370 } 371 break; 372 373 case 4: // grey 374 for (i = 0; i < 256; i++) { 375 uint8 c = i * 15 / 16 + 10; 376 gPalette[i] = c << 16 | c << 8 | c; 377 } 378 break; 379 case 5: // cold 380 for (i = 0; i < 30; i++) 381 gPalette[i] = (uint8)(i * 8 / 10) << 16; 382 // << 16 | (uint8)(i * 6 / 10) << 8; 383 // | (uint8)(i * 3 / 10); 384 385 for (i = 30; i < 256; i++) { 386 uint8 r = i; 387 uint8 c = (uint8)((cos((i - 255) / 82.0) * 0.5 + 0.5) * 255); 388 389 gPalette[i] = ((r << 16) | (c << 8) | c); 390 } 391 break; 392 393 case 6: // original 394 for (i = 0; i < 256; i++) { 395 uint32 c = *(char *)&i; 396 gPalette[i] = c << 16 | c << 8; 397 } 398 break; 399 } 400 /* for (i = 0;i < 256;i++) 401 { 402 uint8 r = (i); 403 uint8 g = (i * i >> 8); //(i * 8 / 10); 404 uint8 b = 0; //(i * 2 / 10); 405 406 gPalette[i] = ((r << 16) | (g << 8) | (b)); 407 } 408 */ 409 /* for (i = 240; i < 256; i++) 410 gPalette[i] = (uint8)i << 16 | (uint8)i << 8 | (uint8)(i * 6 / 10); 411 */ 412 } 413 414 415 /***********************************************************************************/ 416 // #pragma mark - 417 // #pragma mark SimpleSlider 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 /***********************************************************************************/ 444 // #pragma mark - 445 446 447 class SettingsView : public BView { 448 public: 449 SettingsView(BRect frame); 450 451 virtual void AttachedToWindow(); 452 virtual void MessageReceived(BMessage* message); 453 454 private: 455 BMenuField* fWidthMenu; 456 BMenuField* fColorMenu; 457 BMenuField* fBorderMenu; 458 BCheckBox* fMotionCheck; 459 BSlider* fSpeedSlider; 460 BSlider* fFramesSlider; 461 }; 462 463 464 SettingsView::SettingsView(BRect frame) 465 : 466 BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW) 467 { 468 BStringView* titleString = new BStringView(B_EMPTY_STRING, 469 B_TRANSLATE("Nebula")); 470 titleString->SetFont(be_bold_font); 471 472 BStringView* copyrightString = new BStringView(B_EMPTY_STRING, 473 B_TRANSLATE("© 2001-2004 Axel Dörfler.")); 474 475 BPopUpMenu* popMenu; 476 BMenuItem* item; 477 478 int32 widths[] = { 479 0, 480 320, 481 512, 482 576, 483 640, 484 800, 485 1024, 486 1152, 487 1280, 488 1400, 489 1600 490 }; 491 492 size_t widthsLength = sizeof(widths) / sizeof(widths[0]); 493 494 popMenu = new BPopUpMenu(""); 495 for (size_t i = 0; i < widthsLength; i++) { 496 BString label; 497 if (widths[i] == 0) 498 label.SetTo("screen resolution"); 499 else 500 label.SetToFormat("%" B_PRId32 " pixels", widths[i]); 501 502 BMessage* message = new BMessage(kMsgWidth); 503 message->AddInt32("width", widths[i]); 504 505 const char* l = label.String(); 506 popMenu->AddItem(item = new BMenuItem(B_TRANSLATE(l), message)); 507 508 if (gSettingsWidth == widths[i]) 509 item->SetMarked(true); 510 } 511 512 fWidthMenu = new BMenuField("res", B_TRANSLATE("Internal width:"), 513 popMenu); 514 515 const char* colorSchemes[] = { 516 B_TRANSLATE("yellow"), 517 B_TRANSLATE("cyan"), 518 B_TRANSLATE("red"), 519 B_TRANSLATE("green"), 520 B_TRANSLATE("grey"), 521 B_TRANSLATE("cold"), 522 B_TRANSLATE("orange (original)") 523 }; 524 525 popMenu = new BPopUpMenu(""); 526 for (int i = 0; i < 7; i++) { 527 BMessage* message = new BMessage(kMsgColorScheme); 528 message->AddInt8("scheme", (int8)i); 529 popMenu->AddItem(item = new BMenuItem(colorSchemes[i], message)); 530 if (gPaletteScheme == i) 531 item->SetMarked(true); 532 } 533 534 fColorMenu = new BMenuField("col", B_TRANSLATE("Color:"), popMenu); 535 536 const char* blankBorderFormats[] = { 537 B_TRANSLATE("fullscreen, no borders"), 538 B_TRANSLATE("16:9, wide-screen"), 539 B_TRANSLATE("2:3.5, cinemascope"), 540 B_TRANSLATE("only a slit") 541 }; 542 543 popMenu = new BPopUpMenu(""); 544 for (int8 i = 0; i < 4; i++) { 545 BMessage* message = new BMessage(kMsgBlankBorders); 546 message->AddInt8("border", i); 547 popMenu->AddItem(item = new BMenuItem(blankBorderFormats[i], message)); 548 if (gBlankBorders == i) 549 item->SetMarked(true); 550 } 551 552 fBorderMenu = new BMenuField("cinema", B_TRANSLATE("Format:"), popMenu); 553 554 fMotionCheck = new BCheckBox(B_EMPTY_STRING, 555 B_TRANSLATE("Enable motion blur"), new BMessage(kMsgMotionBlur)); 556 fMotionCheck->SetValue((int)gMotionBlur); 557 558 fSpeedSlider = new SimpleSlider(B_TRANSLATE("Speed"), new BMessage(kMsgSpeed)); 559 fSpeedSlider->SetValue((gSpeed - 0.002) / 0.05); 560 561 fFramesSlider = new SimpleSlider(B_TRANSLATE("Maximum Frames Per Second"), 562 new BMessage(kMsgFrames)); 563 fFramesSlider->SetValue(gMaxFramesPerSecond); 564 565 BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_HALF_ITEM_SPACING) 566 .SetInsets(B_USE_HALF_ITEM_INSETS, B_USE_HALF_ITEM_INSETS, 567 B_USE_BIG_INSETS, B_USE_HALF_ITEM_INSETS) 568 .Add(titleString) 569 .Add(copyrightString) 570 .AddStrut(roundf(be_control_look->DefaultItemSpacing() / 2)) 571 .AddGlue() 572 .AddGroup(B_HORIZONTAL, 0.0f) 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 .AddGlue() 592 .End() 593 .AddGlue() 594 .Add(fSpeedSlider) 595 .AddGlue() 596 .Add(fFramesSlider) 597 .AddGlue() 598 .End(); 599 600 MoveBy(0, -25); // The view is not where it should be. 601 } 602 603 604 void 605 SettingsView::AttachedToWindow() 606 { 607 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 608 609 fWidthMenu->Menu()->SetTargetForItems(this); 610 fColorMenu->Menu()->SetTargetForItems(this); 611 fBorderMenu->Menu()->SetTargetForItems(this); 612 fMotionCheck->SetTarget(this); 613 fSpeedSlider->SetTarget(this); 614 fFramesSlider->SetTarget(this); 615 } 616 617 618 void 619 SettingsView::MessageReceived(BMessage* message) 620 { 621 switch(message->what) { 622 case kMsgWidth: 623 message->FindInt32("width", &gSettingsWidth); 624 break; 625 626 case kMsgColorScheme: 627 if (message->FindInt8("scheme", &gPaletteScheme) == B_OK) 628 setPalette(); 629 break; 630 631 case kMsgBlankBorders: 632 message->FindInt8("border", &gBlankBorders); 633 break; 634 635 case kMsgMotionBlur: 636 gMotionBlur = fMotionCheck->Value() > 0; 637 break; 638 639 case kMsgSpeed: 640 gSpeed = 0.002 + 0.05 * fSpeedSlider->Value(); 641 break; 642 643 case kMsgFrames: 644 gMaxFramesPerSecond = fFramesSlider->Value(); 645 gScreenSaver->SetTickSize((bigtime_t)(1000000LL / gMaxFramesPerSecond)); 646 break; 647 } 648 } 649 650 651 652 /***********************************************************************************/ 653 // #pragma mark - 654 655 656 class Nebula : public BScreenSaver { 657 public: 658 Nebula(BMessage* message, image_id id); 659 660 virtual void StartConfig(BView* view); 661 virtual status_t SaveState(BMessage* state) const; 662 663 virtual status_t StartSaver(BView* view, bool preview); 664 virtual void StopSaver(); 665 virtual void Draw(BView* view, int32 frame); 666 667 private: 668 float fFactor; 669 bool fStarted; 670 }; 671 672 673 Nebula::Nebula(BMessage* message, image_id id) 674 : 675 BScreenSaver(message, id), 676 fStarted(false) 677 { 678 message->FindFloat("speed", 0, &gSpeed); 679 message->FindInt32("width", 0, &gSettingsWidth); 680 message->FindBool("motionblur", 0, &gMotionBlur); 681 message->FindFloat("max_fps", 0, &gMaxFramesPerSecond); 682 message->FindInt8("scheme", 0, &gPaletteScheme); 683 message->FindInt8("border", 0, &gBlankBorders); 684 685 if (gSpeed < 0.01f) 686 gSpeed = 0.4f; 687 688 if (gMaxFramesPerSecond < 1.f) 689 gMaxFramesPerSecond = 40.0f; 690 691 gScreenSaver = this; 692 } 693 694 695 void 696 Nebula::StartConfig(BView* view) 697 { 698 view->AddChild(new SettingsView(view->Frame())); 699 } 700 701 702 status_t 703 Nebula::SaveState(BMessage* state) const 704 { 705 state->AddFloat("speed", gSpeed); 706 state->AddInt32("width", gSettingsWidth); 707 state->AddBool("motionblur", gMotionBlur); 708 state->AddFloat("max_fps", gMaxFramesPerSecond); 709 state->AddInt8("scheme", gPaletteScheme); 710 state->AddInt8("border", gBlankBorders); 711 712 return B_OK; 713 } 714 715 716 status_t 717 Nebula::StartSaver(BView* view, bool preview) 718 { 719 // initialize palette 720 setPalette(); 721 722 int i; 723 for (i = 0; i < 512; i++) { 724 precos[i]=cos(i * M_PI / 256); 725 presin[i]=sin(i * M_PI / 256); 726 } 727 728 // uniforme cubique 729 /* for (i = 0;i < GMAX;i++) 730 { 731 gal[i].x = 1 * ((rand()&1023) - 512); 732 gal[i].y = 1 * ((rand()&1023) - 512); 733 gal[i].z = 1 * ((rand()&1023) - 512); 734 gal[i].r = rand() & 63; 735 } 736 */ 737 738 for (i = 0; i < GMAX; i++) { 739 float r, th, h, dth; 740 741 r = rand() * 1.0 / RAND_MAX; 742 r = (1 - r) * (1 - r) + 0.05; 743 744 if (r < 0.12) 745 th = rand() * M_PI * 2 / RAND_MAX; 746 else { 747 th = (rand() & 3) * M_PI_2 + r * r * 2; 748 dth = rand() * 1.0 / RAND_MAX; 749 dth = dth * dth * 2; 750 th += dth; 751 } 752 gal[i].x = (int)(512 * r * cos(th)); 753 gal[i].z = (int)(512 * r * sin(th)); 754 h = (1 + cos(r * M_PI)) * 150; 755 dth = rand() * 1.0 / RAND_MAX; 756 gal[i].y = (int)(h * (dth - 0.5)); 757 gal[i].r = (int)((2 - r) * 60 + 31); 758 } 759 gal[0].x = gal[0].y = gal[0].z = 0; 760 gal[0].r = 320; 761 762 if (gSettingsWidth == 0) 763 gWidth = view->Bounds().Width(); 764 else 765 gWidth = gSettingsWidth; 766 767 fFactor = (view->Bounds().Width()+1) / gWidth; 768 if ((int)fFactor != fFactor) 769 fFactor += 0.01; 770 771 // 4:3 772 gHeight = (int32)((view->Bounds().Height()+1)/fFactor + 0.5f); 773 // calculate blank border format (if not in preview) 774 if (!preview) switch (gBlankBorders) { 775 case 1: // 16:9 776 gHeight = (int32)(gHeight * 0.703125 + 0.5); 777 break; 778 case 2: // 2:3.5 779 gHeight = (int32)(gHeight * 0.534 + 0.5); 780 break; 781 case 3: 782 gHeight /= 5; 783 break; 784 } 785 view->SetScale(fFactor); 786 787 gBitmap = new BBitmap(BRect(0, 0, gWidth - 1, gHeight - 1), B_RGB32); 788 gBuffer8 = (char*)malloc(gWidth * gHeight); 789 790 SetTickSize((bigtime_t)(1000000LL / gMaxFramesPerSecond)); 791 fStarted = true; 792 793 return B_OK; 794 } 795 796 797 void 798 Nebula::StopSaver() 799 { 800 free(gBuffer8); 801 gBuffer8 = NULL; 802 803 delete gBitmap; 804 gBitmap = NULL; 805 } 806 807 808 void 809 Nebula::Draw(BView* view, int32) 810 { 811 if (fStarted) { 812 view->SetHighColor(0, 0, 0, 0); 813 view->FillRect(view->Frame()); 814 view->MovePenTo(0, (view->Bounds().Height() / fFactor - 1 - gHeight) / 2); 815 816 fStarted = false; 817 } 818 uint32* buffer32 = (uint32*)gBitmap->Bits(); 819 820 drawGalaxy(); 821 822 for (int x = 0, end = gWidth * gHeight; x < end; x++) 823 buffer32[x] = gPalette[(uint8)gBuffer8[x]]; 824 825 view->DrawBitmap(gBitmap); 826 } 827 828 829 /***********************************************************************************/ 830 // #pragma mark - 831 832 833 extern "C" _EXPORT BScreenSaver* 834 instantiate_screen_saver(BMessage* message, image_id image) 835 { 836 return new Nebula(message, image); 837 } 838