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