1 /*
2 * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <time.h>
21 #include <math.h>
22 #include <cairo/cairo.h>
23
rounded_rectangle(cairo_t * cr,double x,double y,double w,double h,double r)24 static void rounded_rectangle (cairo_t* cr, double x, double y, double w, double h, double r) {
25 double degrees = M_PI / 180.0;
26
27 cairo_new_sub_path (cr);
28 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees);
29 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees);
30 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees);
31 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees);
32 cairo_close_path (cr);
33 }
34
random1()35 static float random1 () {
36 return rand () / (float)RAND_MAX;
37 }
38
random2()39 static float random2 () {
40 return 1.f - 2.f * random1 ();
41 }
42
make_box(cairo_t * cr,int w,int h)43 static void make_box (cairo_t* cr, int w, int h) {
44 int b = 16;
45 int t = 6;
46 int r0 = 17;
47 int r1 = 6;
48
49 // outer box (borders/shade)
50 rounded_rectangle (cr, 0.5, 0.5, w - 1, h - 1, r0);
51 cairo_set_source_rgba (cr, .93, .93, .93, 1.0);
52 cairo_fill_preserve (cr);
53 cairo_clip (cr);
54
55 // payload
56 rounded_rectangle (cr, b, t, w - 2 * b, h - 2 * b, r1);
57 cairo_set_source_rgba (cr, .95, .95, .95, 1.0);
58 cairo_fill (cr);
59
60 cairo_pattern_t* pat;
61
62 // right side shadow
63 pat = cairo_pattern_create_linear (0.0, 0.0, b, 0.0);
64 cairo_pattern_add_color_stop_rgba (pat, 0.00, .9, .9, .9, 0.0);
65 cairo_pattern_add_color_stop_rgba (pat, 0.20, .0, .0, .0, 0.1);
66 cairo_pattern_add_color_stop_rgba (pat, 0.60, .0, .0, .0, 0.4);
67 cairo_pattern_add_color_stop_rgba (pat, 1.00, .0, .0, .0, 0.6);
68
69 cairo_save (cr);
70 cairo_translate (cr, w - b, 0);
71 cairo_rectangle (cr, 0, 0, b, h);
72 cairo_set_source (cr, pat);
73 cairo_fill (cr);
74 cairo_restore (cr);
75 cairo_pattern_destroy (pat);
76
77 // bottom shadow
78 int bb = 2 * b - t;
79 pat = cairo_pattern_create_linear (0.0, 0.0, 0, bb);
80 cairo_pattern_add_color_stop_rgba (pat, 0.00, .9, .9, .9, 0.0);
81 cairo_pattern_add_color_stop_rgba (pat, 0.10, .0, .0, .0, 0.1);
82 cairo_pattern_add_color_stop_rgba (pat, 0.30, .0, .0, .0, 0.4);
83 cairo_pattern_add_color_stop_rgba (pat, 1.00, .0, .0, .0, 0.7);
84
85 cairo_save (cr);
86 cairo_translate (cr, 0, h - bb);
87 cairo_rectangle (cr, 0, 0, w, bb);
88 cairo_set_source (cr, pat);
89 cairo_fill (cr);
90 cairo_restore (cr);
91 cairo_pattern_destroy (pat);
92
93 // bottom edge
94 pat = cairo_pattern_create_linear (0.0, 0.0, 0, bb);
95 cairo_pattern_add_color_stop_rgba (pat, 0.00, .0, .0, .0, 0.0);
96 cairo_pattern_add_color_stop_rgba (pat, 0.20, .0, .0, .0, 0.15);
97 cairo_pattern_add_color_stop_rgba (pat, 0.30, .0, .0, .0, 0.0);
98 cairo_pattern_add_color_stop_rgba (pat, 1.00, .0, .0, .0, 0.0);
99
100 cairo_save (cr);
101 cairo_translate (cr, 0, h - bb - 4); // TODO unhardcode
102 cairo_rectangle (cr, b + 1.5, 0, w - b, bb);
103 cairo_set_source (cr, pat);
104 cairo_fill (cr);
105 cairo_restore (cr);
106 cairo_pattern_destroy (pat);
107
108 // left light
109 pat = cairo_pattern_create_linear (0.0, 0.0, b, 0.0);
110 cairo_pattern_add_color_stop_rgba (pat, 0.00, 1, 1, 1, 0.9);
111 cairo_pattern_add_color_stop_rgba (pat, 1.00, 1, 1, 1, 0.0);
112
113 cairo_rectangle (cr, 0, 0, b, h);
114 cairo_set_source (cr, pat);
115 cairo_fill (cr);
116 cairo_pattern_destroy (pat);
117
118 // top light
119 pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, t);
120 cairo_pattern_add_color_stop_rgba (pat, 0.00, 1, 1, 1, 0.9);
121 cairo_pattern_add_color_stop_rgba (pat, 1.00, 1, 1, 1, 0.0);
122
123 cairo_rectangle (cr, 0, 0, w, t);
124 cairo_set_source (cr, pat);
125 cairo_fill (cr);
126 cairo_pattern_destroy (pat);
127
128 // top-edge highlight
129 pat = cairo_pattern_create_linear (0.0, 0.0, 0, t);
130 cairo_pattern_add_color_stop_rgba (pat, 0.00, 1, 1, 1, 0.0);
131 cairo_pattern_add_color_stop_rgba (pat, 0.50, 1, 1, 1, 1.0);
132 cairo_pattern_add_color_stop_rgba (pat, 1.00, 1, 1, 1, 0.0);
133
134 cairo_rectangle (cr, b + 0.5, 4, w - 2 * b - 1, t);
135 cairo_set_source (cr, pat);
136 cairo_fill (cr);
137 cairo_pattern_destroy (pat);
138
139 // bottom left corner
140 cairo_arc_negative (cr, 0.5 + r0, 0.5 + h - bb - r0 - 3, r0 + 3, M_PI, 0.5 * M_PI);
141 cairo_set_line_width (cr, 3.0);
142 cairo_set_source_rgba (cr, 0, 0, 0, 0.07);
143 cairo_stroke (cr);
144
145 cairo_arc_negative (cr, 0.5 + r0, 0.5 + h - bb - r0 + 6, r0 + 1, M_PI, 0.5 * M_PI);
146 cairo_set_line_width (cr, 3.0);
147 cairo_set_source_rgba (cr, 0, 0, 0, 0.1);
148 cairo_stroke (cr);
149
150 // bottom left corner shade
151 cairo_arc (cr, 0.5 + r0, 0.5 + h - r0, r0, 0.5 * M_PI, M_PI);
152 cairo_arc_negative (cr, 0.5 + r0, 0.5 + h - bb - r0, r0 + 4, M_PI, 0.5 * M_PI);
153
154 pat = cairo_pattern_create_linear (b, h - bb - r0, b * .5, h);
155 cairo_pattern_add_color_stop_rgba (pat, 0.50, 1, 1, 1, 0.0);
156 cairo_pattern_add_color_stop_rgba (pat, 1.00, 0, 0, 0, 0.4);
157 cairo_set_source (cr, pat);
158 cairo_fill (cr);
159 }
160
scratch_pattern(float x,float y,float dx,float dy,float m)161 static cairo_pattern_t* scratch_pattern (float x, float y, float dx, float dy, float m) {
162 int j;
163 cairo_pattern_t* pat;
164 pat = cairo_pattern_create_linear (x, y, x + dx, y + dy);
165 cairo_pattern_add_color_stop_rgba (pat, 0.00, .9, .9, .9, 0.0);
166 for (j = 1 ; j < 9; ++j) {
167 cairo_pattern_add_color_stop_rgba (pat, j/10.f, .6, .6, .6, .01 + m * random1 ());
168 }
169 cairo_pattern_add_color_stop_rgba (pat, 1.00, .9, .9, .9, 0.0);
170 return pat;
171 }
172
173
add_scratches(cairo_t * cr,int w,int h)174 static void add_scratches (cairo_t* cr, int w, int h) {
175 int b = 16;
176 int t = 6;
177 int r1 = 6;
178 rounded_rectangle (cr, b, t, w - 2 * b, h - 2 * b, r1);
179 cairo_clip (cr);
180
181 float ww = w - b * 2;
182 float hh = h - b * 2;
183
184 float ww2 = ww * .4;
185 float hh2 = hh * .4;
186 float ww4 = ww2 * .5;
187 float hh4 = hh2 * .5;
188
189 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
190
191 float maxlen = sqrt (ww2 * ww2 + hh2 * hh2);
192 int deep = 0;
193 fprintf (stderr, "D: %.1f\n", maxlen);
194
195 cairo_pattern_t* pat;
196 int i, j;
197
198 for (i = 0; i < ceil (maxlen); ++i) {
199 float x = b + ww * random1 ();
200 float y = t + hh * random1 ();
201 float dx = ww4 - ww2 * random1 ();
202 float dy = hh4 - hh2 * random1 ();
203
204
205 cairo_move_to (cr, x, y);
206 if (random1 () > .5) {
207 cairo_rel_line_to (cr, dx, dy);
208 } else {
209 cairo_rel_curve_to (cr, 0, 0, dx * .5 * random2 (), dy * .5 * random2 (), dx, dy);
210 }
211
212 pat = scratch_pattern (x, y, dx, dy, .07);
213 cairo_set_source (cr, pat);
214 cairo_set_line_width (cr, 0.5 + 1.5 * random1 ());
215 cairo_stroke (cr);
216 cairo_pattern_destroy (pat);
217 }
218
219 // short & deep
220 for (i = 0; i < ceil (maxlen * .1); ++i) {
221 float x = b + ww * random1 ();
222 float y = t + hh * random1 ();
223 float dx = .7 * ww4 * random2 ();
224 float dy = .7 * ww4 * random2 ();
225
226 float len = sqrt (dx * dx + dy * dy);
227
228 pat = scratch_pattern (x, y, dx, dy, .2);
229
230 cairo_move_to (cr, x, y);
231 if (random1 () > .5) {
232 cairo_rel_line_to (cr, dx, dy);
233 } else {
234 cairo_rel_curve_to (cr, 0, 0, dx * .5 * random2 (), dy * .5 * random2 (), dx, dy);
235 }
236
237 cairo_set_source (cr, pat);
238 cairo_set_line_width (cr, 0.5 + 1.5 * random1 ());
239
240 if (len < maxlen * .04) {
241 ++deep;
242 for (j = 0 ; j < 4; ++j) {
243 cairo_stroke_preserve (cr);
244 cairo_stroke_preserve (cr);
245 cairo_pattern_destroy (pat);
246 pat = scratch_pattern (x, y, dx, dy, .9);
247 cairo_set_line_width (cr, 2.5 + 1.5 * random1 ());
248 }
249 cairo_stroke_preserve (cr);
250 }
251 cairo_stroke (cr);
252 cairo_pattern_destroy (pat);
253 }
254 fprintf (stderr, "ADDED %d deep bump(s)\n", deep);
255 }
256
main(int argc,char ** argv)257 int main (int argc, char **argv) {
258 int n_steps = 8;
259 int n_notes = 8;
260 srand (time (NULL));
261 char* fn = "../modgui/box.png";
262
263 if (argc > 1) {
264 fn = argv[1];
265 }
266 if (argc > 2) {
267 n_steps = atoi (argv[2]);
268 }
269 if (argc > 3) {
270 n_notes = atoi (argv[3]);
271 }
272
273 /* see gridgen.sh */
274 int w = 250 + 46 * n_steps;
275 int h = 192 + 46 * n_notes;
276 fprintf (stderr, "G: %d x %d F: %s\n", w, h, fn);
277
278 cairo_surface_t* cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
279 cairo_t* cr = cairo_create (cs);
280
281 make_box (cr, w, h);
282 add_scratches (cr, w, h);
283
284 cairo_surface_write_to_png (cs, fn);
285 cairo_destroy (cr);
286 cairo_surface_destroy (cs);
287 return 0;
288 }
289