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