vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / screen_savers / nebula / Nebula.cpp
blob3c88883510b02c476dd33a591ea6a1117bf70ce6
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.
6 * Effect from corTeX / Optimum.
7 */
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>
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "Nebula Screen Saver"
32 typedef struct
34 int x, y, z, r;
35 } p3;
37 typedef float matrix[3][3];
39 #define GMAX 5000
40 p3 gal[GMAX];
41 float precos[512];
42 float presin[512];
44 typedef unsigned short word;
46 extern "C" {
47 #include "Draw.h"
48 #include "DrawStars.h"
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';
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 */
72 inline float
73 ocos(float a)
75 return (precos[(int)(a * 256 / M_PI) & 511]);
78 inline float
79 osin(float a)
81 return (presin[(int)(a * 256 / M_PI) & 511]);
85 void
86 mulmat(matrix* a, matrix* b, matrix* c)
88 int i, j;
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];
100 inline void
101 mulvec(matrix* a, float* x, float* y, float* z)
103 float nx = *x, ny = *y, nz = *z;
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];
111 void
112 setrmat(float a, float b, float c, matrix* m)
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);
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;
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;
129 (*m)[1][1] = cos(c); (*m)[1][2] = sin(c);
130 (*m)[2][1] = sin(c); (*m)[2][2] = -cos(c);
134 void
135 rotate3d(float* xr, float* yr, float* zr, /* point to rotate */
136 float ax, float ay, float az) /* the 3 angles (order ?..) */
138 float xr2, yr2, zr2;
140 xr2 = (*xr * ocos(az) + *yr * osin(az));
141 yr2 = (*xr * osin(az) - *yr * ocos(az));
142 *xr = xr2;
143 *yr = yr2;
145 xr2 = (*xr * ocos(ay) + *zr * osin(ay));
146 zr2 = (*xr * osin(ay) - *zr * ocos(ay));
147 *xr = xr2;
148 *zr = zr2;
150 zr2 = (*zr * ocos(ax) + *yr * osin(ax));
151 yr2 = (*zr * osin(ax) - *yr * ocos(ax));
152 *zr = zr2;
153 *yr = yr2;
157 void
158 drawshdisk(int x0, int y0, int r)
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 */
167 #define SLIMIT 17
168 #define SRANGE 15
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;
177 if (r < SLIMIT + SRANGE)
178 r = ((r - SLIMIT) * SLIMIT) / SRANGE + 1;
180 y = ly = r; /* AAaargh */
181 delta = 3 - 2 * r;
183 do {
184 if (y != ly) {
185 /* dont overlap these lines */
186 c = ((r - y + 1) << 13) / r;
187 d = -c / (x + 1);
189 if (y == x + 1) /* this would overlap with the next x lines */
190 goto TOTO; /* WHY NOT */
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 )
197 This is clearly a stupid, unmaintanable, unreadable
198 "optimization". But i like it :)
200 if ((uint32)(y0 - y - 1) < gHeight - 3)
201 memshset(&gBuffer8[x0 + gWidth * (y0 - y + 1)], c, d, x);
203 if ((uint32)(y0 + y - 1) < gHeight - 3)
204 memshset(&gBuffer8[x0 + gWidth*(y0 + y)], c, d, x);
206 TOTO:
207 c = ((r - x + 1) << 13) / r;
208 d = -c / (y);
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);
215 ly = y;
216 if (delta < 0)
217 delta += 4 * x + 6;
218 else {
219 delta += 4 * (x - y) + 10;
220 y--;
222 x++;
223 } while (x < y);
227 void
228 drawGalaxy()
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;
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)
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);
247 a = 0.9 * t;
248 b = t;
249 c = 1.1 * t;
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);
257 oa = 140 * osin(a);
258 ob = 140 * ocos(b);
259 oc = 240 * osin(c);
261 if (gMotionBlur) {
262 /* mblur does something like that:
263 * (or did, perhaps it's another version!..)
265 for (i = 0; i < W * H; i++)
266 gBuffer8[i]= (gBuffer8[i] >> 3) + (gBuffer8[i] >> 1);
268 mblur (gBuffer8, gWidth * gHeight);
269 } else
270 memset(gBuffer8, 0, gWidth * gHeight);
272 for (i = 0; i < GMAX; i++) {
273 rx = gal[i].x;
274 ry = gal[i].y;
275 rz = gal[i].z;
277 mulvec(&mr, &rx, &ry, &rz);
279 rx += oa;
280 ry += ob;
281 rz += oc;
282 rz += 300;
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;
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);
299 void
300 setPalette()
302 int i;
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);
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);
317 gPalette[i] = ((r << 16) | (g << 8) | (b));
319 break;
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);
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);
332 gPalette[i] = ((r << 16) | (g << 8) | (b));
334 break;
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);
342 for (i = 128;i < 256;i++)
344 uint8 r = i;
345 uint8 c = (uint8)((cos((i - 256) / 42.0) * 0.5 + 0.5) * 225);
347 gPalette[i] = ((r << 16) | (c << 8) | c);
349 /* for (i = 192; i < 224; i++)
351 uint8 c = (i - 192);
352 gPalette[i] = gPalette[i] & 0xff0000 | c << 8 | c;
354 for (i = 224; i < 256; i++)
356 uint8 c = (i-224) / 2;
357 c = 32 + c * c * 6 / 10;
358 gPalette[i] = gPalette[i] & 0xff0000 | c << 8 | c;
360 */ break;
362 case 3: // green
363 for (i = 0; i < 30; i++)
364 gPalette[i] = (uint8)(i * 8 / 10) << 8;
365 // << 16 | (uint8)(i * 6 / 10) << 8;
366 // | (uint8)(i * 3 / 10);
368 for (i = 30; i < 256; i++) {
369 uint8 g = (i);
370 uint8 r = (i * i >> 8); //(i * 8 / 10);
371 uint8 b = i >= 240 ? (i-240) << 3 : 0; //(i * 2 / 10);
373 gPalette[i] = ((r << 16) | (g << 8) | (b));
375 break;
377 case 4: // grey
378 for (i = 0; i < 256; i++) {
379 uint8 c = i * 15 / 16 + 10;
380 gPalette[i] = c << 16 | c << 8 | c;
382 break;
383 case 5: // cold
384 for (i = 0; i < 30; i++)
385 gPalette[i] = (uint8)(i * 8 / 10) << 16;
386 // << 16 | (uint8)(i * 6 / 10) << 8;
387 // | (uint8)(i * 3 / 10);
389 for (i = 30; i < 256; i++) {
390 uint8 r = i;
391 uint8 c = (uint8)((cos((i - 255) / 82.0) * 0.5 + 0.5) * 255);
393 gPalette[i] = ((r << 16) | (c << 8) | c);
395 break;
397 case 6: // original
398 for (i = 0; i < 256; i++) {
399 uint32 c = *(char *)&i;
400 gPalette[i] = c << 16 | c << 8;
402 break;
404 /* for (i = 0;i < 256;i++)
406 uint8 r = (i);
407 uint8 g = (i * i >> 8); //(i * 8 / 10);
408 uint8 b = 0; //(i * 2 / 10);
410 gPalette[i] = ((r << 16) | (g << 8) | (b));
413 /* for (i = 240; i < 256; i++)
414 gPalette[i] = (uint8)i << 16 | (uint8)i << 8 | (uint8)(i * 6 / 10);
419 // #pragma mark - SimpleSlider
422 class SimpleSlider : public BSlider {
423 public:
424 SimpleSlider(const char* label, BMessage* message)
426 BSlider(B_EMPTY_STRING, B_EMPTY_STRING, message, 1, 100, B_HORIZONTAL)
428 SetLimitLabels("1", "100");
429 SetHashMarks(B_HASH_MARKS_BOTTOM);
430 SetHashMarkCount(11);
431 fLabel = label;
434 const char* UpdateText() const
436 fText.SetToFormat("%s: %d", fLabel, Value());
437 return fText.String();
440 private:
441 mutable BString fText;
442 const char* fLabel;
446 // #pragma mark - SettingsView
449 class SettingsView : public BView {
450 public:
451 SettingsView(BRect frame);
453 virtual void AttachedToWindow();
454 virtual void MessageReceived(BMessage* message);
456 private:
457 BMenuField* fWidthMenuField;
458 BMenuField* fColorMenuField;
459 BMenuField* fBorderMenuField;
460 BCheckBox* fMotionCheck;
461 BSlider* fSpeedSlider;
462 BSlider* fFramesSlider;
466 SettingsView::SettingsView(BRect frame)
468 BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW)
470 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
472 BStringView* titleString = new BStringView(B_EMPTY_STRING,
473 B_TRANSLATE("Nebula"));
474 titleString->SetFont(be_bold_font);
476 BStringView* copyrightString = new BStringView(B_EMPTY_STRING,
477 B_TRANSLATE("© 2001-2004 Axel Dörfler."));
479 BPopUpMenu* popUpMenu;
481 int32 widths[] = {
483 320,
484 512,
485 576,
486 640,
487 800,
488 1024,
489 1152,
490 1280,
491 1400,
492 1600
495 size_t widthsLength = sizeof(widths) / sizeof(widths[0]);
497 popUpMenu = new BPopUpMenu("");
498 for (size_t i = 0; i < widthsLength; i++) {
499 BString label;
500 if (widths[i] == 0)
501 label.SetTo("screen resolution");
502 else
503 label.SetToFormat("%" B_PRId32 " pixels", widths[i]);
505 BMessage* message = new BMessage(kMsgWidth);
506 message->AddInt32("width", widths[i]);
508 const char* l = label.String();
509 BMenuItem* item = new BMenuItem(B_TRANSLATE(l), message);
510 popUpMenu->AddItem(item);
511 item->SetMarked(gSettingsWidth == widths[i]);
514 fWidthMenuField = new BMenuField("res", B_TRANSLATE("Internal width:"),
515 popUpMenu);
517 const char* colorSchemeLabels[] = {
518 B_TRANSLATE("yellow"),
519 B_TRANSLATE("cyan"),
520 B_TRANSLATE("red"),
521 B_TRANSLATE("green"),
522 B_TRANSLATE("grey"),
523 B_TRANSLATE("cold"),
524 B_TRANSLATE("orange (original)")
527 rgb_color colorSchemeColors[] = {
528 (rgb_color){ 255, 220, 0 },
529 (rgb_color){ 127, 219, 255 },
530 (rgb_color){ 255, 65, 54 },
531 (rgb_color){ 46, 204, 64 },
532 (rgb_color){ 170, 170, 170 },
533 (rgb_color){ 234, 234, 234 },
534 (rgb_color){ 255, 133, 27 }
537 popUpMenu = new BPopUpMenu("");
538 for (int i = 0; i < 7; i++) {
539 BMessage* message = new BMessage(kMsgColorScheme);
540 message->AddInt8("scheme", (int8)i);
541 BColorMenuItem* item = new BColorMenuItem(colorSchemeLabels[i],
542 message, colorSchemeColors[i]);
543 popUpMenu->AddItem(item);
544 item->SetMarked(gPaletteScheme == i);
547 fColorMenuField = new BMenuField("col", B_TRANSLATE("Color:"), popUpMenu);
549 const char* blankBorderFormats[] = {
550 B_TRANSLATE("fullscreen, no borders"),
551 B_TRANSLATE("16:9, wide-screen"),
552 B_TRANSLATE("2:3.5, cinemascope"),
553 B_TRANSLATE("only a slit")
556 popUpMenu = new BPopUpMenu("");
557 for (int8 i = 0; i < 4; i++) {
558 BMessage* message = new BMessage(kMsgBlankBorders);
559 message->AddInt8("border", i);
560 BMenuItem* item = new BMenuItem(blankBorderFormats[i], message);
561 popUpMenu->AddItem(item);
562 item->SetMarked(gBlankBorders == i);
565 fBorderMenuField = new BMenuField("cinema", B_TRANSLATE("Format:"),
566 popUpMenu);
568 fMotionCheck = new BCheckBox(B_EMPTY_STRING,
569 B_TRANSLATE("Enable motion blur"), new BMessage(kMsgMotionBlur));
570 fMotionCheck->SetValue((int)gMotionBlur);
572 fSpeedSlider = new SimpleSlider(B_TRANSLATE("Speed"),
573 new BMessage(kMsgSpeed));
574 fSpeedSlider->SetValue((gSpeed - 0.002) / 0.05);
576 fFramesSlider = new SimpleSlider(B_TRANSLATE("Maximum Frames Per Second"),
577 new BMessage(kMsgFrames));
578 fFramesSlider->SetValue(gMaxFramesPerSecond);
580 BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_HALF_ITEM_SPACING)
581 .SetInsets(B_USE_DEFAULT_SPACING)
582 .Add(titleString)
583 .Add(copyrightString)
584 .AddStrut(roundf(be_control_look->DefaultItemSpacing() / 2))
585 .AddGlue()
586 .AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING)
587 .Add(fColorMenuField->CreateLabelLayoutItem(), 0, 0)
588 .AddGroup(B_HORIZONTAL, 0.0f, 1, 0)
589 .Add(fColorMenuField->CreateMenuBarLayoutItem(), 0.0f)
590 .AddGlue()
591 .End()
592 .Add(fWidthMenuField->CreateLabelLayoutItem(), 0, 1)
593 .AddGroup(B_HORIZONTAL, 0.0f, 1, 1)
594 .Add(fWidthMenuField->CreateMenuBarLayoutItem(), 0.0f)
595 .AddGlue()
596 .End()
597 .Add(fBorderMenuField->CreateLabelLayoutItem(), 0, 2)
598 .AddGroup(B_HORIZONTAL, 0.0f, 1, 2)
599 .Add(fBorderMenuField->CreateMenuBarLayoutItem(), 0.0f)
600 .AddGlue()
601 .End()
602 .Add(fMotionCheck, 1, 3)
603 .End()
604 .Add(fSpeedSlider)
605 .Add(fFramesSlider)
606 .End();
610 void
611 SettingsView::AttachedToWindow()
613 fWidthMenuField->Menu()->SetTargetForItems(this);
614 fColorMenuField->Menu()->SetTargetForItems(this);
615 fBorderMenuField->Menu()->SetTargetForItems(this);
616 fMotionCheck->SetTarget(this);
617 fSpeedSlider->SetTarget(this);
618 fFramesSlider->SetTarget(this);
622 void
623 SettingsView::MessageReceived(BMessage* message)
625 switch(message->what) {
626 case kMsgWidth:
627 message->FindInt32("width", &gSettingsWidth);
628 break;
630 case kMsgColorScheme:
631 if (message->FindInt8("scheme", &gPaletteScheme) == B_OK)
632 setPalette();
633 break;
635 case kMsgBlankBorders:
636 message->FindInt8("border", &gBlankBorders);
637 break;
639 case kMsgMotionBlur:
640 gMotionBlur = fMotionCheck->Value() > 0;
641 break;
643 case kMsgSpeed:
644 gSpeed = 0.002 + 0.05 * fSpeedSlider->Value();
645 break;
647 case kMsgFrames:
648 gMaxFramesPerSecond = fFramesSlider->Value();
649 gScreenSaver->SetTickSize(
650 (bigtime_t)(1000000LL / gMaxFramesPerSecond));
651 break;
657 // #pragma mark - Nebula
660 class Nebula : public BScreenSaver {
661 public:
662 Nebula(BMessage* message, image_id id);
664 virtual void StartConfig(BView* view);
665 virtual status_t SaveState(BMessage* state) const;
667 virtual status_t StartSaver(BView* view, bool preview);
668 virtual void StopSaver();
669 virtual void Draw(BView* view, int32 frame);
671 private:
672 float fFactor;
673 bool fStarted;
677 Nebula::Nebula(BMessage* message, image_id id)
679 BScreenSaver(message, id),
680 fStarted(false)
682 message->FindFloat("speed", 0, &gSpeed);
683 message->FindInt32("width", 0, &gSettingsWidth);
684 message->FindBool("motionblur", 0, &gMotionBlur);
685 message->FindFloat("max_fps", 0, &gMaxFramesPerSecond);
686 message->FindInt8("scheme", 0, &gPaletteScheme);
687 message->FindInt8("border", 0, &gBlankBorders);
689 if (gSpeed < 0.01f)
690 gSpeed = 0.4f;
692 if (gMaxFramesPerSecond < 1.f)
693 gMaxFramesPerSecond = 40.0f;
695 gScreenSaver = this;
699 void
700 Nebula::StartConfig(BView* view)
702 view->AddChild(new SettingsView(view->Bounds()));
706 status_t
707 Nebula::SaveState(BMessage* state) const
709 state->AddFloat("speed", gSpeed);
710 state->AddInt32("width", gSettingsWidth);
711 state->AddBool("motionblur", gMotionBlur);
712 state->AddFloat("max_fps", gMaxFramesPerSecond);
713 state->AddInt8("scheme", gPaletteScheme);
714 state->AddInt8("border", gBlankBorders);
716 return B_OK;
720 status_t
721 Nebula::StartSaver(BView* view, bool preview)
723 // initialize palette
724 setPalette();
726 int i;
727 for (i = 0; i < 512; i++) {
728 precos[i]=cos(i * M_PI / 256);
729 presin[i]=sin(i * M_PI / 256);
732 // uniforme cubique
733 /* for (i = 0;i < GMAX;i++)
735 gal[i].x = 1 * ((rand()&1023) - 512);
736 gal[i].y = 1 * ((rand()&1023) - 512);
737 gal[i].z = 1 * ((rand()&1023) - 512);
738 gal[i].r = rand() & 63;
742 for (i = 0; i < GMAX; i++) {
743 float r, th, h, dth;
745 r = rand() * 1.0 / RAND_MAX;
746 r = (1 - r) * (1 - r) + 0.05;
748 if (r < 0.12)
749 th = rand() * M_PI * 2 / RAND_MAX;
750 else {
751 th = (rand() & 3) * M_PI_2 + r * r * 2;
752 dth = rand() * 1.0 / RAND_MAX;
753 dth = dth * dth * 2;
754 th += dth;
756 gal[i].x = (int)(512 * r * cos(th));
757 gal[i].z = (int)(512 * r * sin(th));
758 h = (1 + cos(r * M_PI)) * 150;
759 dth = rand() * 1.0 / RAND_MAX;
760 gal[i].y = (int)(h * (dth - 0.5));
761 gal[i].r = (int)((2 - r) * 60 + 31);
763 gal[0].x = gal[0].y = gal[0].z = 0;
764 gal[0].r = 320;
766 if (gSettingsWidth == 0)
767 gWidth = view->Bounds().Width();
768 else
769 gWidth = gSettingsWidth;
771 fFactor = (view->Bounds().Width()+1) / gWidth;
772 if ((int)fFactor != fFactor)
773 fFactor += 0.01;
775 // 4:3
776 gHeight = (int32)((view->Bounds().Height()+1)/fFactor + 0.5f);
777 // calculate blank border format (if not in preview)
778 if (!preview) switch (gBlankBorders) {
779 case 1: // 16:9
780 gHeight = (int32)(gHeight * 0.703125 + 0.5);
781 break;
782 case 2: // 2:3.5
783 gHeight = (int32)(gHeight * 0.534 + 0.5);
784 break;
785 case 3:
786 gHeight /= 5;
787 break;
789 view->SetScale(fFactor);
791 gBitmap = new BBitmap(BRect(0, 0, gWidth - 1, gHeight - 1), B_RGB32);
792 gBuffer8 = (char*)malloc(gWidth * gHeight);
794 SetTickSize((bigtime_t)(1000000LL / gMaxFramesPerSecond));
795 fStarted = true;
797 return B_OK;
801 void
802 Nebula::StopSaver()
804 free(gBuffer8);
805 gBuffer8 = NULL;
807 delete gBitmap;
808 gBitmap = NULL;
812 void
813 Nebula::Draw(BView* view, int32)
815 if (fStarted) {
816 view->SetHighColor(0, 0, 0, 0);
817 view->FillRect(view->Frame());
818 view->MovePenTo(0,
819 (view->Bounds().Height() / fFactor - 1 - gHeight) / 2);
821 fStarted = false;
823 uint32* buffer32 = (uint32*)gBitmap->Bits();
825 drawGalaxy();
827 for (int x = 0, end = gWidth * gHeight; x < end; x++)
828 buffer32[x] = gPalette[(uint8)gBuffer8[x]];
830 view->DrawBitmap(gBitmap);
834 // #pragma mark - instantiate_screen_saver
837 extern "C" _EXPORT BScreenSaver*
838 instantiate_screen_saver(BMessage* message, image_id image)
840 return new Nebula(message, image);