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