1 /* 2 * Copyright 2010-2013, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Deyan Genovski, deangenovski@gmail.com 7 * Geoffry Song, goffrie@gmail.com 8 */ 9 10 11 #include "Leaves.h" 12 13 #include <stdlib.h> 14 #include <time.h> 15 16 #include <AffineTransform.h> 17 #include <Catalog.h> 18 #include <GradientLinear.h> 19 #include <Shape.h> 20 #include <Slider.h> 21 #include <TextView.h> 22 23 24 #undef B_TRANSLATION_CONTEXT 25 #define B_TRANSLATION_CONTEXT "Leaves" 26 27 28 // path data for the leaf shape 29 static const BPoint kLeafBegin(56.24793f, 15.46287f); 30 static BPoint kLeafCurves[][3] = { 31 { BPoint(61.14, 28.89), BPoint(69.78, 38.25), BPoint(83.48, 44.17) }, 32 { BPoint(99.46, 37.52), BPoint(113.27, 29.61), BPoint(134.91, 30.86) }, 33 { BPoint(130.58, 36.53), BPoint(126.74, 42.44), BPoint(123.84, 48.81) }, 34 { BPoint(131.81, 42.22), BPoint(137.53, 38.33), BPoint(144.37, 33.10) }, 35 { BPoint(169.17, 23.55), BPoint(198.90, 15.55), BPoint(232.05, 10.51) }, 36 { BPoint(225.49, 18.37), BPoint(219.31, 28.17), BPoint(217.41, 40.24) }, 37 { BPoint(227.70, 26.60), BPoint(239.97, 14.63), BPoint(251.43, 8.36) }, 38 { BPoint(288.89, 9.12), BPoint(322.73, 14.33), BPoint(346.69, 31.67) }, 39 { BPoint(330.49, 37.85), BPoint(314.36, 44.25), BPoint(299.55, 54.17) }, 40 { BPoint(292.48, 52.54), BPoint(289.31, 49.70), BPoint(285.62, 47.03) }, 41 { BPoint(283.73, 54.61), BPoint(284.46, 57.94), BPoint(285.62, 60.60) }, 42 { BPoint(259.78, 76.14), BPoint(233.24, 90.54), BPoint(202.41, 98.10) }, 43 { BPoint(194.43, 95.36), BPoint(185.96, 92.39), BPoint(179.63, 88.33) }, 44 { BPoint(180.15, 94.75), BPoint(182.73, 99.76), BPoint(185.62, 104.53) }, 45 { BPoint(154.83, 119.46), BPoint(133.21, 118.97), BPoint(125.62, 94.88) }, 46 { BPoint(124.70, 98.79), BPoint(124.11, 103.67), BPoint(124.19, 110.60) }, 47 { BPoint(116.42, 111.81), BPoint(85.82, 99.60), BPoint(83.25, 51.96) }, 48 { BPoint(62.50, 42.57), BPoint(58.12, 33.18), BPoint(50.98, 23.81) } }; 49 static const int kLeafCurveCount = sizeof(kLeafCurves) / sizeof(kLeafCurves[0]); 50 static const float kLeafWidth = 372.f; 51 static const float kLeafHeight = 121.f; 52 53 // leaf colors 54 static const rgb_color kColors[][2] = { 55 { {255, 114, 0, 255}, {255, 159, 0, 255} }, 56 { {50, 160, 40, 255}, {125, 210, 32, 255} }, 57 { {250, 190, 30, 255}, {255, 214, 125, 255} } }; 58 static const int kColorCount = sizeof(kColors) / sizeof(kColors[0]); 59 60 // bounds for settings 61 static const int kMinimumDropRate = 2, kMaximumDropRate = 50; 62 static const int kMinimumLeafSize = 50, kMaximumLeafSize = 1000; 63 static const int kMaximumSizeVariation = 200; 64 65 // message constants 66 enum { 67 MSG_SET_DROP_RATE = 'drop', 68 MSG_SET_LEAF_SIZE = 'size', 69 MSG_SET_SIZE_VARIATION = 'svry', 70 }; 71 72 73 extern "C" BScreenSaver* 74 instantiate_screen_saver(BMessage* msg, image_id image) 75 { 76 return new Leaves(msg, image); 77 } 78 79 80 Leaves::Leaves(BMessage* archive, image_id id) 81 : 82 BScreenSaver(archive, id), 83 fDropRate(10), 84 fLeafSize(150), 85 fSizeVariation(50) 86 { 87 if (archive) { 88 if (archive->FindInt32("Leaves drop rate", &fDropRate) != B_OK) 89 fDropRate = 10; 90 if (archive->FindInt32("Leaves size", &fLeafSize) != B_OK) 91 fLeafSize = 150; 92 if (archive->FindInt32("Leaves variation", &fSizeVariation) != B_OK) 93 fSizeVariation = 50; 94 } 95 } 96 97 98 void 99 Leaves::StartConfig(BView* view) 100 { 101 BRect bounds = view->Bounds(); 102 bounds.InsetBy(10, 10); 103 BRect frame(0, 0, bounds.Width(), 20); 104 105 BSlider* dropRateSlider = new BSlider(frame, "drop rate", 106 B_TRANSLATE("Drop rate:"), new BMessage(MSG_SET_DROP_RATE), 107 kMinimumDropRate, kMaximumDropRate, B_BLOCK_THUMB, 108 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM); 109 dropRateSlider->SetValue(fDropRate); 110 dropRateSlider->ResizeToPreferred(); 111 bounds.bottom -= dropRateSlider->Bounds().Height() * 1.5; 112 dropRateSlider->MoveTo(bounds.LeftBottom()); 113 view->AddChild(dropRateSlider); 114 115 BSlider* leafSizeSlider = new BSlider(frame, "leaf size", 116 B_TRANSLATE("Leaf size:"), new BMessage(MSG_SET_LEAF_SIZE), 117 kMinimumLeafSize, kMaximumLeafSize, B_BLOCK_THUMB, 118 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM); 119 leafSizeSlider->SetValue(fLeafSize); 120 leafSizeSlider->ResizeToPreferred(); 121 bounds.bottom -= leafSizeSlider->Bounds().Height() * 1.5; 122 leafSizeSlider->MoveTo(bounds.LeftBottom()); 123 view->AddChild(leafSizeSlider); 124 125 BSlider* sizeVariationSlider = new BSlider(frame, "variation", 126 B_TRANSLATE("Size variation:"), new BMessage(MSG_SET_SIZE_VARIATION), 127 0, kMaximumSizeVariation, B_BLOCK_THUMB, 128 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM); 129 sizeVariationSlider->SetValue(fSizeVariation); 130 sizeVariationSlider->ResizeToPreferred(); 131 bounds.bottom -= sizeVariationSlider->Bounds().Height() * 1.5; 132 sizeVariationSlider->MoveTo(bounds.LeftBottom()); 133 view->AddChild(sizeVariationSlider); 134 135 BTextView* textView = new BTextView(bounds, B_EMPTY_STRING, 136 bounds.OffsetToCopy(0., 0.), B_FOLLOW_ALL, B_WILL_DRAW); 137 textView->SetViewColor(view->ViewColor()); 138 BString name = B_TRANSLATE("Leaves"); 139 BString text = name; 140 text << "\n\n"; 141 text << B_TRANSLATE("by Deyan Genovski, Geoffry Song"); 142 text << "\n\n"; 143 144 textView->Insert(text.String()); 145 textView->SetStylable(true); 146 textView->SetFontAndColor(0, name.Length(), be_bold_font); 147 textView->MakeEditable(false); 148 view->AddChild(textView); 149 150 BWindow* window = view->Window(); 151 if (window) window->AddHandler(this); 152 153 dropRateSlider->SetTarget(this); 154 leafSizeSlider->SetTarget(this); 155 sizeVariationSlider->SetTarget(this); 156 } 157 158 159 status_t 160 Leaves::StartSaver(BView* view, bool preview) 161 { 162 SetTickSize(10000000 / fDropRate); 163 srand48(time(NULL)); 164 165 view->SetLineMode(B_ROUND_CAP, B_ROUND_JOIN); 166 167 return B_OK; 168 } 169 170 171 status_t 172 Leaves::SaveState(BMessage* into) const 173 { 174 status_t status; 175 if ((status = into->AddInt32("Leaves drop rate", fDropRate)) != B_OK) 176 return status; 177 if ((status = into->AddInt32("Leaves size", fLeafSize)) != B_OK) 178 return status; 179 if ((status = into->AddInt32("Leaves variation", fSizeVariation)) != B_OK) 180 return status; 181 return B_OK; 182 } 183 184 185 void 186 Leaves::MessageReceived(BMessage* message) 187 { 188 switch (message->what) { 189 case MSG_SET_DROP_RATE: 190 { 191 int32 dropRate; 192 if (message->FindInt32("be:value", &dropRate) == B_OK) 193 fDropRate = dropRate; 194 break; 195 } 196 197 case MSG_SET_LEAF_SIZE: 198 { 199 int32 leafSize; 200 if (message->FindInt32("be:value", &leafSize) == B_OK) 201 fLeafSize = leafSize; 202 break; 203 } 204 205 case MSG_SET_SIZE_VARIATION: 206 { 207 int32 sizeVariation; 208 if (message->FindInt32("be:value", &sizeVariation) == B_OK) 209 fSizeVariation = sizeVariation; 210 break; 211 } 212 213 default: 214 BHandler::MessageReceived(message); 215 } 216 } 217 218 219 void 220 Leaves::Draw(BView* view, int32 frame) 221 { 222 float scale = fLeafSize / kLeafWidth / (kMaximumLeafSize * 2); 223 scale *= view->Bounds().Width(); 224 scale += scale * drand48() * fSizeVariation / 100.; 225 226 BAffineTransform transform; 227 transform.TranslateBy(-kLeafWidth / 2, -kLeafHeight / 2); 228 // draw the leaf centered on the point 229 transform.RotateBy(drand48() * 2. * M_PI); 230 if ((rand() & 64) == 0) transform.ScaleBy(-1., 1.); 231 // flip half of the time 232 transform.ScaleBy(scale); 233 transform.TranslateBy(_RandomPoint(view->Bounds())); 234 235 BPoint center = transform.Apply(BPoint(kLeafWidth / 2, kLeafHeight / 2)); 236 BPoint gradientOffset = BPoint(60 * scale, 80 * scale); 237 BGradientLinear gradient(center - gradientOffset, center + gradientOffset); 238 int color = (rand() / 7) % kColorCount; 239 gradient.AddColor(kColors[color][0], 0.f); 240 gradient.AddColor(kColors[color][1], 255.f); 241 242 BShape leafShape; 243 leafShape.MoveTo(transform.Apply(kLeafBegin)); 244 for (int i = 0; i < kLeafCurveCount; ++i) { 245 BPoint control[3]; 246 for (int j = 0; j < 3; ++j) 247 control[j] = transform.Apply(kLeafCurves[i][j]); 248 leafShape.BezierTo(control); 249 } 250 leafShape.Close(); 251 252 view->PushState(); 253 view->SetDrawingMode(B_OP_ALPHA); 254 view->SetHighColor(0, 0, 0, 50); 255 for (int i = 2; i >= 0; --i) { 256 view->SetOrigin(i * 0.1, i * 0.3); 257 view->SetPenSize(i * 2); 258 view->StrokeShape(&leafShape); 259 } 260 view->PopState(); 261 view->FillShape(&leafShape, gradient); 262 } 263 264 265 inline BPoint 266 Leaves::_RandomPoint(const BRect& bound) 267 { 268 return BPoint(drand48() * (bound.right - bound.left) + bound.left, 269 drand48() * (bound.bottom - bound.top) + bound.top); 270 } 271