Simplify graph gradient stuff.
[monky] / src / colours.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Any original torsmo code is licensed under the BSD license
4  *
5  * All code written since the fork of torsmo is licensed under the GPL
6  *
7  * Please see COPYING for details
8  *
9  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
10  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
11  *      (see AUTHORS)
12  * All rights reserved.
13  *
14  * This program is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  *
26  */
27 #include "conky.h"
28 #include "logging.h"
29 #ifdef X11
30 #include "x11.h"
31 #endif
32
33 /* precalculated: 31/255, and 63/255 */
34 #define CONST_8_TO_5_BITS 0.12156862745098
35 #define CONST_8_TO_6_BITS 0.247058823529412
36
37 static short colour_depth = 0;
38 static long redmask, greenmask, bluemask;
39
40 static void set_up_gradient(void)
41 {
42         int i;
43 #ifdef X11
44         if (output_methods & TO_X) {
45                 colour_depth = DisplayPlanes(display, screen);
46         } else
47 #endif /* X11 */
48         {
49                 colour_depth = 16;
50         }
51         if (colour_depth != 24 && colour_depth != 16) {
52                 ERR("using non-standard colour depth, gradients may look like a "
53                         "lolly-pop");
54         }
55
56         redmask = 0;
57         greenmask = 0;
58         bluemask = 0;
59         for (i = (colour_depth / 3) - 1; i >= 0; i--) {
60                 redmask |= 1 << i;
61                 greenmask |= 1 << i;
62                 bluemask |= 1 << i;
63         }
64         if (colour_depth % 3 == 1) {
65                 greenmask |= 1 << (colour_depth / 3);
66         }
67         redmask = redmask << (2 * colour_depth / 3 + colour_depth % 3);
68         greenmask = greenmask << (colour_depth / 3);
69 }
70
71 /* adjust colour values depending on colour depth */
72 unsigned int adjust_colours(unsigned int colour)
73 {
74         double r, g, b;
75
76         if (colour_depth == 0) {
77                 set_up_gradient();
78         }
79         if (colour_depth == 16) {
80                 r = (colour & 0xff0000) >> 16;
81                 g = (colour & 0xff00) >> 8;
82                 b =  colour & 0xff;
83                 colour  = (int) (r * CONST_8_TO_5_BITS) << 11;
84                 colour |= (int) (g * CONST_8_TO_6_BITS) << 5;
85                 colour |= (int) (b * CONST_8_TO_5_BITS);
86         }
87         return colour;
88 }
89
90 /* this function returns the next colour between two colours for a gradient */
91 unsigned long *do_gradient(int width, unsigned long first_colour, unsigned long last_colour)
92 {
93         int red1, green1, blue1;                                // first colour
94         int red2, green2, blue2;                                // last colour
95         int reddiff, greendiff, bluediff;               // difference
96         short redshift = (2 * colour_depth / 3 + colour_depth % 3);
97         short greenshift = (colour_depth / 3);
98         unsigned long *colours = malloc(width * sizeof(unsigned long));
99         int i;
100
101         if (colour_depth == 0) {
102                 set_up_gradient();
103         }
104         red1 = (first_colour & redmask) >> redshift;
105         green1 = (first_colour & greenmask) >> greenshift;
106         blue1 = first_colour & bluemask;
107         red2 = (last_colour & redmask) >> redshift;
108         green2 = (last_colour & greenmask) >> greenshift;
109         blue2 = last_colour & bluemask;
110         reddiff = abs(red1 - red2);
111         greendiff = abs(green1 - green2);
112         bluediff = abs(blue1 - blue2);
113 #ifdef HAVE_OPENMP
114 #pragma omp parallel for
115 #endif /* HAVE_OPENMP */
116         for (i = 0; i < width; i++) {
117                 int red3 = 0, green3 = 0, blue3 = 0;    // colour components
118
119                 float factor = ((float)(i + 1) / width);
120
121                 /* the '+ 0.5' bit rounds our floats to ints properly */
122                 if (red1 >= red2) {
123                         red3 = -(factor * reddiff) - 0.5;
124                 } else if (red1 < red2) {
125                         red3 = factor * reddiff + 0.5;
126                 }
127                 if (green1 >= green2) {
128                         green3 = -(factor * greendiff) - 0.5;
129                 } else if (green1 < green2) {
130                         green3 = factor * greendiff + 0.5;
131                 }
132                 if (blue1 >= blue2) {
133                         blue3 = -(factor * bluediff) - 0.5;
134                 } else if (blue1 < blue2) {
135                         blue3 = factor * bluediff + 0.5;
136                 }
137                 red3 += red1;
138                 green3 += green1;
139                 blue3 += blue1;
140                 if (red3 < 0) {
141                         red3 = 0;
142                 }
143                 if (green3 < 0) {
144                         green3 = 0;
145                 }
146                 if (blue3 < 0) {
147                         blue3 = 0;
148                 }
149                 if (red3 > bluemask) {
150                         red3 = bluemask;
151                 }
152                 if (green3 > bluemask) {
153                         green3 = bluemask;
154                 }
155                 if (blue3 > bluemask) {
156                         blue3 = bluemask;
157                 }
158                 colours[i] = (red3 << redshift) | (green3 << greenshift) | blue3;
159         }
160         return colours;
161 }
162