1 /* 2 * Copyright 2010-2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Geoffry Song, goffrie@gmail.com 7 * Ryan Leavengood, leavengood@gmail.com 8 */ 9 10 11 #include "Butterfly.h" 12 13 #include <math.h> 14 #include <stdlib.h> 15 16 #include <Catalog.h> 17 #include <DefaultSettingsView.h> 18 #include <OS.h> 19 #include <View.h> 20 21 #undef B_TRANSLATION_CONTEXT 22 #define B_TRANSLATION_CONTEXT "Screensaver Butterfly" 23 24 25 extern "C" BScreenSaver* 26 instantiate_screen_saver(BMessage* archive, image_id imageId) 27 { 28 return new Butterfly(archive, imageId); 29 } 30 31 32 // #pragma mark - 33 34 35 Butterfly::Butterfly(BMessage* archive, image_id imageId) 36 : 37 BScreenSaver(archive, imageId) 38 { 39 } 40 41 42 void 43 Butterfly::StartConfig(BView* view) 44 { 45 BPrivate::BuildDefaultSettingsView(view, "Butterfly", 46 B_TRANSLATE("by Geoffry Song")); 47 } 48 49 50 status_t 51 Butterfly::StartSaver(BView* view, bool preview) 52 { 53 view->SetLowColor(0, 0, 0); 54 view->FillRect(view->Bounds(), B_SOLID_LOW); 55 view->SetDrawingMode(B_OP_ALPHA); 56 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); 57 view->SetLineMode(B_ROUND_CAP, B_ROUND_JOIN); 58 if (!preview) 59 view->SetPenSize(2.0); 60 61 SetTickSize(20000); 62 63 // Set fBase to a random radian value scaled by 1000. The scaling produces 64 // more interesting results. 65 srand48(system_time()); 66 fBase = drand48() * 2 * M_PI * 1000; 67 68 // calculate transformation 69 BRect bounds = view->Bounds(); 70 fScale = MIN(bounds.Width(), bounds.Height()) * 0.1f; 71 fTrans.Set(bounds.Width() * 0.5f, bounds.Height() * 0.5f); 72 fBounds = bounds; 73 74 fLast[0] = _Iterate(); 75 fLast[1] = _Iterate(); 76 fLast[2] = _Iterate(); 77 78 return B_OK; 79 } 80 81 82 void 83 Butterfly::Draw(BView* view, int32 frame) 84 { 85 if (frame == 1024) { 86 // calculate bounding box ( (-5.92,-5.92) to (5.92, 5.92) ) 87 fBounds.Set(-5.92f * fScale + fTrans.x, -5.92f * fScale + fTrans.y, 88 5.92f * fScale + fTrans.x, 5.92f * fScale + fTrans.y); 89 } 90 if ((frame & 3) == 0) { 91 // fade out 92 view->SetHighColor(0, 0, 0, 4); 93 view->FillRect(fBounds); 94 } 95 // create a color from a hue of (fBase * 15) degrees 96 view->SetHighColor(_HueToColor(fBase * 15)); 97 BPoint p = _Iterate(); 98 99 // cubic Hermite interpolation from fLast[1] to fLast[2] 100 // calculate tangents for a Catmull-Rom spline 101 //(these values need to be halved) 102 BPoint m1 = fLast[2] - fLast[0]; // tangent for fLast[1] 103 BPoint m2 = p - fLast[1]; // tangent for fLast[2] 104 105 // draw Bezier from fLast[1] to fLast[2] with control points 106 // fLast[1] + m1/3, fLast[2] - m2/3 107 m1.x /= 6; 108 m1.y /= 6; 109 m2.x /= 6; 110 m2.y /= 6; 111 BPoint control[4] = { fLast[1], fLast[1] + m1, fLast[2] - m2, fLast[2] }; 112 view->StrokeBezier(control); 113 114 fLast[0] = fLast[1]; 115 fLast[1] = fLast[2]; 116 fLast[2] = p; 117 } 118 119 120 //! Convert from a hue in degrees to a fully saturated color 121 inline rgb_color 122 Butterfly::_HueToColor(float hue) 123 { 124 // convert from [0..360) to [0..1530) 125 int h = static_cast<int>(fmodf(hue, 360) * 4.25f); 126 int x = 255 - abs(h % 510 - 255); 127 128 rgb_color result = {0, 0, 0, 255}; 129 if (h < 255) { 130 result.red = 255; 131 result.green = x; 132 } else if (h < 510) { 133 result.red = x; 134 result.green = 255; 135 } else if (h < 765) { 136 result.green = 255; 137 result.blue = x; 138 } else if (h < 1020) { 139 result.green = x; 140 result.blue = 255; 141 } else if (h < 1275) { 142 result.red = x; 143 result.blue = 255; 144 } else { 145 result.red = 255; 146 result.blue = x; 147 } 148 return result; 149 } 150 151 152 inline BPoint 153 Butterfly::_Iterate() 154 { 155 float r = powf(M_E, cosf(fBase)) - 2 * cosf(4 * fBase) 156 - powf(sinf(fBase / 12), 5); 157 // rotate and move it a bit 158 BPoint p(sinf(fBase * 1.01f) * r + cosf(fBase * 1.02f) * 0.2f, 159 cosf(fBase * 1.01f) * r + sinf(fBase * 1.02f) * 0.2f); 160 // transform to view coordinates 161 p.x *= fScale; 162 p.y *= fScale; 163 p += fTrans; 164 // move on 165 fBase += 0.05f; 166 return p; 167 } 168