1 /* 2 * Copyright (C) 2011 Paul Davis <paul@linuxaudiosystems.com> 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 of the License, or 7 * (at your option) 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 along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 */ 18 19 #ifndef __gtkmm2ext_rgb_macros_h__ 20 #define __gtkmm2ext_rgb_macros_h__ 21 22 /* 23 Some convenient macros for drawing into an RGB buffer. 24 Beware of side effects, code-bloat, and all of the other classic 25 cpp-perils... 26 */ 27 28 #define RGB_TO_UINT(r,g,b) ((((guint)(r))<<16)|(((guint)(g))<<8)|((guint)(b))) 29 #define RGB_TO_RGBA(x,a) (((x) << 8) | ((((guint)a) & 0xff))) 30 #define RGBA_TO_UINT(r,g,b,a) RGB_TO_RGBA(RGB_TO_UINT(r,g,b), a) 31 #define RGB_WHITE RGB_TO_UINT(0xff, 0xff, 0xff) 32 #define RGB_BLACK RGB_TO_UINT(0x00, 0x00, 0x00) 33 #define RGB_RED RGB_TO_UINT(0xff, 0x00, 0x00) 34 #define RGB_GREEN RGB_TO_UINT(0x00, 0xff, 0x00) 35 #define RGB_BLUE RGB_TO_UINT(0x00, 0x00, 0xff) 36 #define RGB_YELLOW RGB_TO_UINT(0xff, 0xff, 0x00) 37 #define RGB_VIOLET RGB_TO_UINT(0xff, 0x00, 0xff) 38 #define RGB_CYAN RGB_TO_UINT(0x00, 0xff, 0xff) 39 #define RGBA_WHITE RGB_TO_RGBA(RGB_WHITE, 0xff) 40 #define RGBA_BLACK RGB_TO_RGBA(RGB_BLACK, 0xff) 41 #define RGBA_RED RGB_TO_RGBA(RGB_RED, 0xff) 42 #define RGBA_GREEN RGB_TO_RGBA(RGB_GREEN, 0xff) 43 #define RGBA_BLUE RGB_TO_RGBA(RGB_BLUE, 0xff) 44 #define RGBA_YELLOW RGB_TO_RGBA(RGB_YELLOW, 0xff) 45 #define RGBA_VIOLET RGB_TO_RGBA(RGB_VIOLET, 0xff) 46 #define RGBA_CYAN RGB_TO_RGBA(RGB_CYAN, 0xff) 47 #define RGB_GREY(x) RGB_TO_UINT(x,x,x) 48 #define RGBA_GREY(x) RGB_TO_RGBA(RGB_GREY(x), 0xff) 49 #define UINT_RGBA_R(x) (((guint)(x))>>24) 50 #define UINT_RGBA_G(x) ((((guint)(x))>>16)&0xff) 51 #define UINT_RGBA_B(x) ((((guint)(x))>>8)&0xff) 52 #define UINT_RGBA_A(x) (((guint)(x))&0xff) 53 #define UINT_RGBA_R_FLT(x) ((((guint)(x))>>24)/255.0) 54 #define UINT_RGBA_G_FLT(x) (((((guint)(x))>>16)&0xff)/255.0) 55 #define UINT_RGBA_B_FLT(x) (((((guint)(x))>>8)&0xff)/255.0) 56 #define UINT_RGBA_A_FLT(x) ((((guint)(x))&0xff)/255.0) 57 #define UINT_RGBA_CHANGE_R(x, r) (((x)&(~(0xff<<24)))|(((r)&0xff)<<24)) 58 #define UINT_RGBA_CHANGE_G(x, g) (((x)&(~(0xff<<16)))|(((g)&0xff)<<16)) 59 #define UINT_RGBA_CHANGE_B(x, b) (((x)&(~(0xff<<8)))|(((b)&0xff)<<8)) 60 #define UINT_RGBA_CHANGE_A(x, a) (((x)&(~0xff))|((a)&0xff)) 61 #define UINT_TO_RGB(u,r,g,b) \ 62 { (*(r)) = ((u)>>16)&0xff; (*(g)) = ((u)>>8)&0xff; (*(b)) = (u)&0xff; } 63 #define UINT_TO_RGBA(u,r,g,b,a) \ 64 { UINT_TO_RGB(((u)>>8),r,g,b); (*(a)) = (u)&0xff; } 65 #define MONO_INTERPOLATE(v1, v2, t) ((gint)rint((v2)*(t)+(v1)*(1-(t)))) 66 #define UINT_INTERPOLATE(c1, c2, t) \ 67 RGBA_TO_UINT( MONO_INTERPOLATE(UINT_RGBA_R(c1), UINT_RGBA_R(c2), t), \ 68 MONO_INTERPOLATE(UINT_RGBA_G(c1), UINT_RGBA_G(c2), t), \ 69 MONO_INTERPOLATE(UINT_RGBA_B(c1), UINT_RGBA_B(c2), t), \ 70 MONO_INTERPOLATE(UINT_RGBA_A(c1), UINT_RGBA_A(c2), t) ) 71 #define PIXEL_RGB(p, r, g, b) \ 72 {((guchar*)(p))[0]=(r); ((guchar*)(p))[1]=(g); ((guchar*)(p))[2]=(b);} 73 #define PIXEL_RGBA(p, r, g, b, a) \ 74 { if ((a)>=0xff) { PIXEL_RGB(p,r,g,b) } \ 75 else if ((a)>0) { \ 76 guint pixel_tmp; \ 77 pixel_tmp = ((guchar*)(p))[0]; \ 78 ((guchar*)(p))[0] = pixel_tmp + ((((r)-pixel_tmp)*(a)+0x80) >> 8); \ 79 pixel_tmp = ((guchar*)(p))[1]; \ 80 ((guchar*)(p))[1] = pixel_tmp + ((((g)-pixel_tmp)*(a)+0x80) >> 8); \ 81 pixel_tmp = ((guchar*)(p))[2]; \ 82 ((guchar*)(p))[2] = pixel_tmp + ((((b)-pixel_tmp)*(a)+0x80) >> 8); }} 83 #define PIXEL_RGB_UINT(p, i) \ 84 UINT_TO_RGB((i), ((guchar*)p), ((guchar*)p)+1, ((guchar*)p)+2) 85 #define PIXEL_RGBA_UINT(p, i) \ 86 PIXEL_RGBA((p), ((i)>>24)&0xff, ((i)>>16)&0xff, ((i)>>8)&0xff, (i)&0xff) 87 #define PIXEL_BLACK(p) PIXEL_RGB(p,0,0,0) 88 #define PIXEL_WHITE(p) PIXEL_RGB(p,0xff,0xff,0xff) 89 #define PIXEL_GREY(p,g) PIXEL_RGB(p,g,g,g) 90 #define PIXEL_GREYA(p,g,a) PIXEL_RGBA(p,g,g,g,a) 91 #define BUF_PTR(inbuf, ptx, pty) \ 92 ((inbuf)->buf + 3*((ptx)-(inbuf)->rect.x0) + (inbuf)->buf_rowstride*((pty)-(inbuf)->rect.y0)) 93 #define BUF_INBOUNDS_X(inbuf, ptx) \ 94 ((inbuf)->rect.x0 <= (ptx) && (ptx) < (inbuf)->rect.x1) 95 #define BUF_INBOUNDS_Y(inbuf, pty) \ 96 ((inbuf)->rect.y0 <= (pty) && (pty) < (inbuf)->rect.y1) 97 #define PAINT_DOT(inbuf, colr, colg, colb,ptx, pty) \ 98 { \ 99 guchar* pd_p; \ 100 if (BUF_INBOUNDS_X(inbuf, ptx) && BUF_INBOUNDS_Y(inbuf, pty)) { \ 101 pd_p = BUF_PTR(inbuf, ptx, pty); \ 102 PIXEL_RGB(pd_p, (colr), (colg), (colb)); \ 103 } \ 104 } 105 #define FAST_PAINT_DOT(inbuf, colr, colg, colb,ptx, pty) \ 106 { \ 107 guchar* pd_p; \ 108 pd_p = BUF_PTR(inbuf, ptx, pty); \ 109 PIXEL_RGB(pd_p, (colr), (colg), (colb)); \ 110 } 111 #define PAINT_DOTA(inbuf, colr, colg, colb, cola, ptx, pty) \ 112 { \ 113 guchar* pd_p; \ 114 if (BUF_INBOUNDS_X(inbuf, ptx) && BUF_INBOUNDS_Y(inbuf, pty)) { \ 115 pd_p = BUF_PTR(inbuf, ptx, pty); \ 116 PIXEL_RGBA(pd_p, (colr), (colg), (colb), (cola)); \ 117 } \ 118 } 119 #define FAST_PAINT_DOTA(inbuf, colr, colg, colb, cola, ptx, pty) \ 120 { \ 121 guchar* pd_p; \ 122 pd_p = BUF_PTR(inbuf, ptx, pty); \ 123 PIXEL_RGBA(pd_p, (colr), (colg), (colb), (cola)); \ 124 } 125 #define PAINT_HORIZ(inbuf, colr, colg, colb, ptx0, ptx1, pty) \ 126 { \ 127 GnomeCanvasBuf* ph_buf = (inbuf); \ 128 guchar* ph_p; \ 129 gint ph_a0, ph_a1; \ 130 gint ph_colr=(colr), ph_colg=(colg), ph_colb=(colb); \ 131 \ 132 ph_a0 = MAX(ph_buf->rect.x0, (gint)(ptx0)); \ 133 ph_a1 = MIN(ph_buf->rect.x1, (gint)(ptx1)); \ 134 \ 135 if (ph_a0 < ph_a1 && BUF_INBOUNDS_Y(ph_buf, (gint)(pty))) { \ 136 ph_p = BUF_PTR(ph_buf, ph_a0, pty); \ 137 while (ph_a0 < ph_a1) { \ 138 PIXEL_RGB(ph_p, ph_colr, ph_colg, ph_colb); \ 139 ++ph_a0; \ 140 ph_p += 3; \ 141 } \ 142 } \ 143 } 144 #define FAST_PAINT_HORIZ(inbuf, colr, colg, colb, ptx0, ptx1, pty) \ 145 { \ 146 GnomeCanvasBuf* ph_buf = (inbuf); \ 147 guchar* ph_p; \ 148 gint ph_a0, ph_a1; \ 149 gint ph_colr=(colr), ph_colg=(colg), ph_colb=(colb); \ 150 \ 151 ph_a0 = MAX(ph_buf->rect.x0, (gint)(ptx0)); \ 152 ph_a1 = MIN(ph_buf->rect.x1, (gint)(ptx1)); \ 153 \ 154 if (ph_a0 < ph_a1 && BUF_INBOUNDS_Y(ph_buf, (gint)(pty))) { \ 155 ph_p = BUF_PTR(ph_buf, ph_a0, pty); \ 156 while (ph_a0 < ph_a1) { \ 157 PIXEL_RGB(ph_p, ph_colr, ph_colg, ph_colb); \ 158 ++ph_a0; \ 159 ph_p += 3; \ 160 } \ 161 } \ 162 } 163 #define PAINT_HORIZA(inbuf, colr, colg, colb, cola, ptx0, ptx1, pty) \ 164 { \ 165 GnomeCanvasBuf* ph_buf = (inbuf); \ 166 guchar* ph_p; \ 167 gint ph_a0, ph_a1; \ 168 gint ph_colr=(colr), ph_colg=(colg), ph_colb=(colb), ph_cola=(cola); \ 169 \ 170 ph_a0 = MAX(ph_buf->rect.x0, (gint)(ptx0)); \ 171 ph_a1 = MIN(ph_buf->rect.x1, (gint)(ptx1)); \ 172 \ 173 if (ph_a0 < ph_a1 && BUF_INBOUNDS_Y(ph_buf, (gint)(pty))) { \ 174 ph_p = BUF_PTR(ph_buf, ph_a0, pty); \ 175 while (ph_a0 < ph_a1) { \ 176 PIXEL_RGBA(ph_p, ph_colr, ph_colg, ph_colb, ph_cola); \ 177 ++ph_a0; \ 178 ph_p += 3; \ 179 } \ 180 } \ 181 } 182 #define PAINT_VERT(inbuf, colr, colg, colb, ptx, pty0, pty1) \ 183 { \ 184 GnomeCanvasBuf* pv_buf = (inbuf); \ 185 guchar* pv_p; \ 186 gint pv_b0, pv_b1; \ 187 gint pv_colr=(colr), pv_colg=(colg), pv_colb=(colb);\ 188 \ 189 pv_b0 = MAX(pv_buf->rect.y0, (gint)(pty0)); \ 190 pv_b1 = MIN(pv_buf->rect.y1, (gint)(pty1)); \ 191 \ 192 if (pv_b0 < pv_b1 && BUF_INBOUNDS_X(pv_buf, (gint)(ptx))) { \ 193 pv_p = BUF_PTR(pv_buf, ptx, pv_b0); \ 194 while (pv_b0 < pv_b1) { \ 195 PIXEL_RGB(pv_p, pv_colr, pv_colg, pv_colb); \ 196 ++pv_b0; \ 197 pv_p += pv_buf->buf_rowstride; \ 198 } \ 199 } \ 200 } 201 #define FAST_PAINT_VERT(inbuf, colr, colg, colb, ptx, pty0, pty1) \ 202 { \ 203 GnomeCanvasBuf* fpv_buf = (inbuf); \ 204 guchar* fpv_p; \ 205 gint fpv_b0, fpv_b1; \ 206 \ 207 fpv_b0 = MAX(fpv_buf->rect.y0, (gint)(pty0)); \ 208 fpv_b1 = MIN(fpv_buf->rect.y1, (gint)(pty1)); \ 209 \ 210 fpv_p = BUF_PTR(fpv_buf, ptx, fpv_b0); \ 211 \ 212 while (fpv_b0 < fpv_b1) { \ 213 PIXEL_RGB(fpv_p, colr, colg, colb); \ 214 ++fpv_b0; \ 215 fpv_p += fpv_buf->buf_rowstride; \ 216 } \ 217 } 218 #define PAINT_VERTA(inbuf, colr, colg, colb, cola, ptx, pty0, pty1) \ 219 { \ 220 GnomeCanvasBuf* pv_buf = (inbuf); \ 221 guchar* pv_p; \ 222 gint pv_b0, pv_b1; \ 223 gint pv_colr=(colr), pv_colg=(colg), pv_colb=(colb), pv_cola=(cola);\ 224 \ 225 pv_b0 = MAX(pv_buf->rect.y0, (pty0)); \ 226 pv_b1 = MIN(pv_buf->rect.y1, (pty1)); \ 227 \ 228 if (pv_b0 < pv_b1 && BUF_INBOUNDS_X(pv_buf, ptx)) { \ 229 pv_p = BUF_PTR(pv_buf, ptx, pv_b0); \ 230 while (pv_b0 < pv_b1) { \ 231 PIXEL_RGBA(pv_p, pv_colr, pv_colg, pv_colb, pv_cola); \ 232 ++pv_b0; \ 233 pv_p += pv_buf->buf_rowstride; \ 234 } \ 235 } \ 236 } 237 238 #define PAINT_VERTA_GR(inbuf, colr, colg, colb, cola, ptx, pty0, pty1, origin_y, obj_top) \ 239 { \ 240 GnomeCanvasBuf* pv_buf = (inbuf); \ 241 guchar* pv_p; \ 242 gint pv_b0, pv_b1; \ 243 gint pv_colr=(colr), pv_colg=(colg), pv_colb=(colb), pv_cola=(cola); \ 244 gint y_fract; \ 245 gint y_span = (origin_y - obj_top); \ 246 gint sat; \ 247 \ 248 pv_b0 = MAX(pv_buf->rect.y0, (pty0)); \ 249 pv_b1 = MIN(pv_buf->rect.y1, (pty1)); \ 250 \ 251 if (pv_b0 < pv_b1 && BUF_INBOUNDS_X(pv_buf, ptx)) { \ 252 pv_p = BUF_PTR(pv_buf, ptx, pv_b0); \ 253 while (pv_b0 < pv_b1) { \ 254 y_fract = (abs(origin_y - pv_b0)) * 0xFF; \ 255 y_fract = y_fract / y_span; \ 256 sat = 0xFF - (y_fract); \ 257 PIXEL_RGBA(pv_p, (((pv_colr << 8) * sat) >> 16), (((pv_colg << 8) * sat) >> 16), (((pv_colb << 8) * sat) >> 16), pv_cola); \ 258 ++pv_b0; \ 259 pv_p += pv_buf->buf_rowstride; \ 260 } \ 261 } \ 262 } 263 264 /* Paint a solid-colored box into a GnomeCanvasBuf (clipping as necessary). 265 The box contains (ptx0,pty0), but not (ptx1, pty1). 266 Each macro arg should appear exactly once in the body of the code. */ 267 #define PAINT_BOX(inbuf, colr, colg, colb, cola, ptx0, pty0, ptx1, pty1) \ 268 { \ 269 GnomeCanvasBuf* pb_buf = (inbuf); \ 270 guchar* pb_p; \ 271 guchar* pb_pp; \ 272 gint pb_a0, pb_a1, pb_b0, pb_b1, pb_i, pb_j; \ 273 gint pb_colr=(colr), pb_colg=(colg), pb_colb=(colb), pb_cola=(cola); \ 274 \ 275 pb_a0 = MAX(pb_buf->rect.x0, (ptx0)); \ 276 pb_a1 = MIN(pb_buf->rect.x1, (ptx1)); \ 277 pb_b0 = MAX(pb_buf->rect.y0, (pty0)); \ 278 pb_b1 = MIN(pb_buf->rect.y1, (pty1)); \ 279 \ 280 if (pb_a0 < pb_a1 && pb_b0 < pb_b1) { \ 281 pb_p = BUF_PTR(pb_buf, pb_a0, pb_b0); \ 282 for (pb_j=pb_b0; pb_j<pb_b1; ++pb_j) { \ 283 pb_pp = pb_p; \ 284 for (pb_i=pb_a0; pb_i<pb_a1; ++pb_i) { \ 285 PIXEL_RGBA(pb_pp, pb_colr, pb_colg, pb_colb, pb_cola); \ 286 pb_pp += 3; \ 287 } \ 288 pb_p += pb_buf->buf_rowstride; \ 289 } \ 290 } \ 291 } 292 293 /* Paint a gradient-colored box into a GnomeCanvasBuf (clipping as necessary). 294 The box contains (ptx0,pty0), but not (ptx1, pty1). 295 Each macro arg should appear exactly once in the body of the code. */ 296 #define PAINT_BOX_GR(inbuf, colr, colg, colb, cola, ptx0, pty0, ptx1, pty1, v_span) \ 297 { \ 298 GnomeCanvasBuf* pb_buf = (inbuf); \ 299 guchar* pb_p; \ 300 guchar* pb_pp; \ 301 gint pb_a0, pb_a1, pb_b0, pb_b1, pb_i, pb_j; \ 302 gint pb_colr=(colr), pb_colg=(colg), pb_colb=(colb), pb_cola=(cola); \ 303 gint sat; \ 304 gint y_fract; \ 305 gint y_span = MAX(abs(v_span), 1); \ 306 \ 307 pb_a0 = MAX(pb_buf->rect.x0, (ptx0)); \ 308 pb_a1 = MIN(pb_buf->rect.x1, (ptx1)); \ 309 pb_b0 = MAX(pb_buf->rect.y0, (pty0)); \ 310 pb_b1 = MIN(pb_buf->rect.y1, (pty1)); \ 311 \ 312 if (pb_a0 < pb_a1 && pb_b0 < pb_b1) { \ 313 pb_p = BUF_PTR(pb_buf, pb_a0, pb_b0); \ 314 for (pb_j=pb_b0; pb_j<pb_b1; ++pb_j) { \ 315 y_fract = 0xFF * (abs(pb_j - pty0)); \ 316 y_fract = y_fract / y_span; \ 317 sat = 0xFF - (y_fract >> 1); \ 318 pb_pp = pb_p; \ 319 for (pb_i=pb_a0; pb_i<pb_a1; ++pb_i) { \ 320 PIXEL_RGBA(pb_pp, (((pb_colr << 8) * sat) >> 16), (((pb_colg << 8) * sat) >> 16), (((pb_colb << 8) * sat) >> 16), pb_cola); \ 321 pb_pp += 3; \ 322 } \ 323 pb_p += pb_buf->buf_rowstride; \ 324 } \ 325 } \ 326 } 327 328 329 /* No bounds checking in this version */ 330 331 #define FAST_PAINT_BOX(inbuf, colr, colg, colb, cola, ptx0, pty0, ptx1, pty1) \ 332 { \ 333 GnomeCanvasBuf* pb_buf = (inbuf); \ 334 guchar* pb_p; \ 335 guchar* pb_pp; \ 336 gint pb_i, pb_j; \ 337 \ 338 pb_p = BUF_PTR(pb_buf, ptx0, pty0); \ 339 for (pb_j=pty0; pb_j<pty1; ++pb_j) { \ 340 pb_pp = pb_p; \ 341 for (pb_i=ptx0; pb_i<ptx1; ++pb_i) { \ 342 PIXEL_RGBA(pb_pp, colr, colg, colb, cola); \ 343 pb_pp += 3; \ 344 } \ 345 pb_p += pb_buf->buf_rowstride; \ 346 } \ 347 } 348 349 #endif /* __gtkmm2ext_rgb_macros_h__ */ 350