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
ocos(float a)73 ocos(float a)
74 {
75 return (precos[(int)(a * 256 / M_PI) & 511]);
76 }
77
78 inline float
osin(float a)79 osin(float a)
80 {
81 return (presin[(int)(a * 256 / M_PI) & 511]);
82 }
83
84
85 void
mulmat(matrix * a,matrix * b,matrix * c)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
mulvec(matrix * a,float * x,float * y,float * z)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
setrmat(float a,float b,float c,matrix * m)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
rotate3d(float * xr,float * yr,float * zr,float ax,float ay,float az)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
drawshdisk(int x0,int y0,int r)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
drawGalaxy()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
setPalette()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:
SimpleSlider(const char * label,BMessage * message)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
UpdateText() const430 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
SettingsView(BRect frame)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
AttachedToWindow()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
MessageReceived(BMessage * message)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
Nebula(BMessage * message,image_id id)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
StartConfig(BView * view)695 Nebula::StartConfig(BView* view)
696 {
697 view->AddChild(new SettingsView(view->Bounds()));
698 }
699
700
701 status_t
SaveState(BMessage * state) const702 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
StartSaver(BView * view,bool preview)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
StopSaver()796 Nebula::StopSaver()
797 {
798 free(gBuffer8);
799 gBuffer8 = NULL;
800
801 delete gBitmap;
802 gBitmap = NULL;
803 }
804
805
806 void
Draw(BView * view,int32)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*
instantiate_screen_saver(BMessage * message,image_id image)832 instantiate_screen_saver(BMessage* message, image_id image)
833 {
834 return new Nebula(message, image);
835 }
836