xref: /haiku/src/add-ons/screen_savers/butterfly/Butterfly.cpp (revision 323b65468e5836bb27a5e373b14027d902349437)
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