source: libcaca/trunk/caca/attr.c @ 3583

Last change on this file since 3583 was 3583, checked in by Sam Hocevar, 10 years ago

Allow to temporarily disable dirty rectangle handling. This allows for huge
speedups when the calling application knows the dirty rectangle covered by
a complex operation.

  • Property svn:keywords set to Id
File size: 15.5 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2009 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  $Id: attr.c 3583 2009-07-26 19:17:35Z sam $
7 *
8 *  This library is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  This file contains functions for attribute management and colourspace
17 *  conversions.
18 */
19
20#include "config.h"
21
22#include "caca.h"
23#include "caca_internals.h"
24
25static uint8_t nearest_ansi(uint16_t);
26
27/* RGB colours for the ANSI palette. There is no real standard, so we
28 * use the same values as gnome-terminal. The 7th colour (brown) is a bit
29 * special: 0xfa50 instead of 0xfaa0. */
30static const uint16_t ansitab16[16] =
31{
32    0xf000, 0xf00a, 0xf0a0, 0xf0aa, 0xfa00, 0xfa0a, 0xfa50, 0xfaaa,
33    0xf555, 0xf55f, 0xf5f5, 0xf5ff, 0xff55, 0xff5f, 0xfff5, 0xffff,
34};
35
36/* Same table, except on 14 bits (3-4-4-3) */
37static const uint16_t ansitab14[16] =
38{
39    0x3800, 0x3805, 0x3850, 0x3855, 0x3d00, 0x3d05, 0x3d28, 0x3d55,
40    0x3aaa, 0x3aaf, 0x3afa, 0x3aff, 0x3faa, 0x3faf, 0x3ffa, 0x3fff,
41};
42
43/** \brief Get the text attribute at the given coordinates.
44 *
45 *  Get the internal \e libcaca attribute value of the character at the
46 *  given coordinates. The attribute value has 32 significant bits,
47 *  organised as follows from MSB to LSB:
48 *  - 3 bits for the background alpha
49 *  - 4 bits for the background red component
50 *  - 4 bits for the background green component
51 *  - 3 bits for the background blue component
52 *  - 3 bits for the foreground alpha
53 *  - 4 bits for the foreground red component
54 *  - 4 bits for the foreground green component
55 *  - 3 bits for the foreground blue component
56 *  - 4 bits for the bold, italics, underline and blink flags
57 *
58 *  If the coordinates are outside the canvas boundaries, the current
59 *  attribute is returned.
60 *
61 *  This function never fails.
62 *
63 *  \param cv A handle to the libcaca canvas.
64 *  \param x X coordinate.
65 *  \param y Y coordinate.
66 *  \return The requested attribute.
67 */
68uint32_t caca_get_attr(caca_canvas_t const *cv, int x, int y)
69{
70    if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
71        return cv->curattr;
72
73    return cv->attrs[x + y * cv->width];
74}
75
76/** \brief Set the default character attribute.
77 *
78 *  Set the default character attribute for drawing. Attributes define
79 *  foreground and background colour, transparency, bold, italics and
80 *  underline styles, as well as blink. String functions such as
81 *  caca_printf() and graphical primitive functions such as caca_draw_line()
82 *  will use this attribute.
83 *
84 *  The value of \e attr is either:
85 *  - a 32-bit integer as returned by caca_get_attr(), in which case it
86 *    also contains colour information,
87 *  - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
88 *    \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
89 *    setting the attribute does not modify the current colour information.
90 *
91 *  To retrieve the current attribute value, use caca_get_attr(-1,-1).
92 *
93 *  This function never fails.
94 *
95 *  \param cv A handle to the libcaca canvas.
96 *  \param attr The requested attribute value.
97 *  \return This function always returns 0.
98 */
99int caca_set_attr(caca_canvas_t *cv, uint32_t attr)
100{
101    if(attr < 0x00000010)
102        attr = (cv->curattr & 0xfffffff0) | attr;
103
104    cv->curattr = attr;
105
106    return 0;
107}
108
109/** \brief Set the character attribute at the given coordinates.
110 *
111 *  Set the character attribute, without changing the character's value. If
112 *  the character at the given coordinates is a fullwidth character, both
113 *  cells' attributes are replaced.
114 *
115 *  The value of \e attr is either:
116 *  - a 32-bit integer as returned by caca_get_attr(), in which case it
117 *    also contains colour information,
118 *  - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
119 *    \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
120 *    setting the attribute does not modify the current colour information.
121 *
122 *  This function never fails.
123 *
124 *  \param cv A handle to the libcaca canvas.
125 *  \param x X coordinate.
126 *  \param y Y coordinate.
127 *  \param attr The requested attribute value.
128 *  \return This function always returns 0.
129 */
130int caca_put_attr(caca_canvas_t *cv, int x, int y, uint32_t attr)
131{
132    uint32_t *curattr, *curchar;
133    int xmin, xmax;
134
135    if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
136        return 0;
137
138    xmin = xmax = x;
139
140    curchar = cv->chars + x + y * cv->width;
141    curattr = cv->attrs + x + y * cv->width;
142
143    if(attr < 0x00000010)
144        curattr[0] = (curattr[0] & 0xfffffff0) | attr;
145    else
146        curattr[0] = attr;
147
148    if(x && curchar[0] == CACA_MAGIC_FULLWIDTH)
149    {
150        curattr[-1] = curattr[0];
151        xmin--;
152    }
153    else if(x + 1 < (int)cv->width && curchar[1] == CACA_MAGIC_FULLWIDTH)
154    {
155        curattr[1] = curattr[0];
156        xmax++;
157    }
158
159    if(!cv->dirty_disabled)
160        caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1);
161
162    return 0;
163}
164
165/** \brief Set the default colour pair for text (ANSI version).
166 *
167 *  Set the default ANSI colour pair for text drawing. String functions such
168 *  as caca_printf() and graphical primitive functions such as caca_draw_line()
169 *  will use these attributes.
170 *
171 *  Color values are those defined in caca.h, such as CACA_RED
172 *  or CACA_TRANSPARENT.
173 *
174 *  If an error occurs, 0 is returned and \b errno is set accordingly:
175 *  - \c EINVAL At least one of the colour values is invalid.
176 *
177 *  \param cv A handle to the libcaca canvas.
178 *  \param fg The requested ANSI foreground colour.
179 *  \param bg The requested ANSI background colour.
180 *  \return 0 in case of success, -1 if an error occurred.
181 */
182int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
183{
184    uint32_t attr;
185
186    if(fg > 0x20 || bg > 0x20)
187    {
188        seterrno(EINVAL);
189        return -1;
190    }
191
192    attr = ((uint32_t)(bg | 0x40) << 18) | ((uint32_t)(fg | 0x40) << 4);
193    cv->curattr = (cv->curattr & 0x0000000f) | attr;
194
195    return 0;
196}
197
198/** \brief Set the default colour pair for text (truecolor version).
199 *
200 *  Set the default ARGB colour pair for text drawing. String functions such
201 *  as caca_printf() and graphical primitive functions such as caca_draw_line()
202 *  will use these attributes.
203 *
204 *  Colors are 16-bit ARGB values, each component being coded on 4 bits. For
205 *  instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
206 *  white with 50% alpha (A=8 R=15 G=15 B=15).
207 *
208 *  This function never fails.
209 *
210 *  \param cv A handle to the libcaca canvas.
211 *  \param fg The requested ARGB foreground colour.
212 *  \param bg The requested ARGB background colour.
213 *  \return This function always returns 0.
214 */
215int caca_set_color_argb(caca_canvas_t *cv, uint16_t fg, uint16_t bg)
216{
217    uint32_t attr;
218
219    if(fg < 0x100)
220        fg += 0x100;
221
222    if(bg < 0x100)
223        bg += 0x100;
224
225    fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
226    bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);
227
228    attr = ((uint32_t)bg << 18) | ((uint32_t)fg << 4);
229    cv->curattr = (cv->curattr & 0x0000000f) | attr;
230
231    return 0;
232}
233
234/** \brief Get DOS ANSI information from attribute.
235 *
236 *  Get the ANSI colour pair for a given attribute. The returned value is
237 *  an 8-bit value whose higher 4 bits are the background colour and lower
238 *  4 bits are the foreground colour.
239 *
240 *  If the attribute has ARGB colours, the nearest colour is used. Special
241 *  attributes such as \e CACA_DEFAULT and \e CACA_TRANSPARENT are not
242 *  handled and are both replaced with \e CACA_LIGHTGRAY for the foreground
243 *  colour and \e CACA_BLACK for the background colour.
244 *
245 *  This function never fails. If the attribute value is outside the expected
246 *  32-bit range, higher order bits are simply ignored.
247 *
248 *  \param attr The requested attribute value.
249 *  \return The corresponding DOS ANSI value.
250 */
251uint8_t caca_attr_to_ansi(uint32_t attr)
252{
253    uint8_t fg = nearest_ansi((attr >> 4) & 0x3fff);
254    uint8_t bg = nearest_ansi(attr >> 18);
255
256    return (fg < 0x10 ? fg : CACA_LIGHTGRAY)
257            | ((bg < 0x10 ? bg : CACA_BLACK) << 4);
258}
259
260/** \brief Get ANSI foreground information from attribute.
261 *
262 *  Get the ANSI foreground colour value for a given attribute. The returned
263 *  value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
264 *  colours, or the special value \e CACA_DEFAULT meaning the media's
265 *  default foreground value, or the special value \e CACA_TRANSPARENT.
266 *
267 *  If the attribute has ARGB colours, the nearest colour is returned.
268 *
269 *  This function never fails. If the attribute value is outside the expected
270 *  32-bit range, higher order bits are simply ignored.
271 *
272 *  \param attr The requested attribute value.
273 *  \return The corresponding ANSI foreground value.
274 */
275uint8_t caca_attr_to_ansi_fg(uint32_t attr)
276{
277    return nearest_ansi(((uint16_t)attr >> 4) & 0x3fff);
278}
279
280/** \brief Get ANSI background information from attribute.
281 *
282 *  Get the ANSI background colour value for a given attribute. The returned
283 *  value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
284 *  colours, or the special value \e CACA_DEFAULT meaning the media's
285 *  default background value, or the special value \e CACA_TRANSPARENT.
286 *
287 *  If the attribute has ARGB colours, the nearest colour is returned.
288 *
289 *  This function never fails. If the attribute value is outside the expected
290 *  32-bit range, higher order bits are simply ignored.
291 *
292 *  \param attr The requested attribute value.
293 *  \return The corresponding ANSI background value.
294 */
295uint8_t caca_attr_to_ansi_bg(uint32_t attr)
296{
297    return nearest_ansi(attr >> 18);
298}
299
300/** \brief Get 12-bit RGB foreground information from attribute.
301 *
302 *  Get the 12-bit foreground colour value for a given attribute. The returned
303 *  value is a native-endian encoded integer with each red, green and blue
304 *  values encoded on 8 bits in the following order:
305 *   - 8-11 most significant bits: red
306 *   - 4-7 most significant bits: green
307 *   - least significant bits: blue
308 *
309 *  This function never fails. If the attribute value is outside the expected
310 *  32-bit range, higher order bits are simply ignored.
311 *
312 *  \param attr The requested attribute value.
313 *  \return The corresponding 12-bit RGB foreground value.
314 */
315uint16_t caca_attr_to_rgb12_fg(uint32_t attr)
316{
317    uint16_t fg = (attr >> 4) & 0x3fff;
318
319    if(fg < (0x10 | 0x40))
320        return ansitab16[fg ^ 0x40] & 0x0fff;
321
322    if(fg == (CACA_DEFAULT | 0x40))
323        return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
324
325    if(fg == (CACA_TRANSPARENT | 0x40))
326        return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
327
328    return (fg << 1) & 0x0fff;
329}
330
331/** \brief Get 12-bit RGB background information from attribute.
332 *
333 *  Get the 12-bit background colour value for a given attribute. The returned
334 *  value is a native-endian encoded integer with each red, green and blue
335 *  values encoded on 8 bits in the following order:
336 *   - 8-11 most significant bits: red
337 *   - 4-7 most significant bits: green
338 *   - least significant bits: blue
339 *
340 *  This function never fails. If the attribute value is outside the expected
341 *  32-bit range, higher order bits are simply ignored.
342 *
343 *  \param attr The requested attribute value.
344 *  \return The corresponding 12-bit RGB background value.
345 */
346uint16_t caca_attr_to_rgb12_bg(uint32_t attr)
347{
348    uint16_t bg = attr >> 18;
349
350    if(bg < (0x10 | 0x40))
351        return ansitab16[bg ^ 0x40] & 0x0fff;
352
353    if(bg == (CACA_DEFAULT | 0x40))
354        return ansitab16[CACA_BLACK] & 0x0fff;
355
356    if(bg == (CACA_TRANSPARENT | 0x40))
357        return ansitab16[CACA_BLACK] & 0x0fff;
358
359    return (bg << 1) & 0x0fff;
360}
361
362/** \brief Get 64-bit ARGB information from attribute.
363 *
364 *  Get the 64-bit colour and alpha values for a given attribute. The values
365 *  are written as 8-bit integers in the \e argb array in the following order:
366 *   - \e argb[0]: background alpha value
367 *   - \e argb[1]: background red value
368 *   - \e argb[2]: background green value
369 *   - \e argb[3]: background blue value
370 *   - \e argb[4]: foreground alpha value
371 *   - \e argb[5]: foreground red value
372 *   - \e argb[6]: foreground green value
373 *   - \e argb[7]: foreground blue value
374 *
375 *  This function never fails. If the attribute value is outside the expected
376 *  32-bit range, higher order bits are simply ignored.
377 *
378 *  \param attr The requested attribute value.
379 *  \param argb An array of 8-bit integers.
380 */
381void caca_attr_to_argb64(uint32_t attr, uint8_t argb[8])
382{
383    uint16_t fg = (attr >> 4) & 0x3fff;
384    uint16_t bg = attr >> 18;
385
386    if(bg < (0x10 | 0x40))
387        bg = ansitab16[bg ^ 0x40];
388    else if(bg == (CACA_DEFAULT | 0x40))
389        bg = ansitab16[CACA_BLACK];
390    else if(bg == (CACA_TRANSPARENT | 0x40))
391        bg = 0x0fff;
392    else
393        bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);
394
395    argb[0] = bg >> 12;
396    argb[1] = (bg >> 8) & 0xf;
397    argb[2] = (bg >> 4) & 0xf;
398    argb[3] = bg & 0xf;
399
400    if(fg < (0x10 | 0x40))
401        fg = ansitab16[fg ^ 0x40];
402    else if(fg == (CACA_DEFAULT | 0x40))
403        fg = ansitab16[CACA_LIGHTGRAY];
404    else if(fg == (CACA_TRANSPARENT | 0x40))
405        fg = 0x0fff;
406    else
407        fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);
408
409    argb[4] = fg >> 12;
410    argb[5] = (fg >> 8) & 0xf;
411    argb[6] = (fg >> 4) & 0xf;
412    argb[7] = fg & 0xf;
413}
414
415/*
416 * XXX: the following functions are local
417 */
418
419static uint8_t nearest_ansi(uint16_t argb14)
420{
421    unsigned int i, best, dist;
422
423    if(argb14 < (0x10 | 0x40))
424        return argb14 ^ 0x40;
425
426    if(argb14 == (CACA_DEFAULT | 0x40) || argb14 == (CACA_TRANSPARENT | 0x40))
427        return argb14 ^ 0x40;
428
429    if(argb14 < 0x0fff) /* too transparent */
430        return CACA_TRANSPARENT;
431
432    best = CACA_DEFAULT;
433    dist = 0x3fff;
434    for(i = 0; i < 16; i++)
435    {
436        unsigned int d = 0;
437        int a, b;
438
439        a = (ansitab14[i] >> 7) & 0xf;
440        b = (argb14 >> 7) & 0xf;
441        d += (a - b) * (a - b);
442
443        a = (ansitab14[i] >> 3) & 0xf;
444        b = (argb14 >> 3) & 0xf;
445        d += (a - b) * (a - b);
446
447        a = (ansitab14[i] << 1) & 0xf;
448        b = (argb14 << 1) & 0xf;
449        d += (a - b) * (a - b);
450
451        if(d < dist)
452        {
453            dist = d;
454            best = i;
455        }
456    }
457
458    return best;
459}
460
461#define RGB12TO24(i) \
462   (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
463  | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
464  | ((uint32_t)(i & 0x00f) * 0x000011))
465
466uint32_t _caca_attr_to_rgb24fg(uint32_t attr)
467{
468    return RGB12TO24(caca_attr_to_rgb12_fg(attr));
469}
470
471uint32_t _caca_attr_to_rgb24bg(uint32_t attr)
472{
473    return RGB12TO24(caca_attr_to_rgb12_bg(attr));
474}
475
476/*
477 * XXX: The following functions are aliases.
478 */
479
480uint32_t cucul_get_attr(cucul_canvas_t const *, int, int)
481         CACA_ALIAS(caca_get_attr);
482int cucul_set_attr(cucul_canvas_t *, uint32_t) CACA_ALIAS(caca_set_attr);
483int cucul_put_attr(cucul_canvas_t *, int, int, uint32_t)
484         CACA_ALIAS(caca_put_attr);
485int cucul_set_color_ansi(cucul_canvas_t *, uint8_t, uint8_t)
486         CACA_ALIAS(caca_set_color_ansi);
487int cucul_set_color_argb(cucul_canvas_t *, uint16_t, uint16_t)
488         CACA_ALIAS(caca_set_color_argb);
489uint8_t cucul_attr_to_ansi(uint32_t) CACA_ALIAS(caca_attr_to_ansi);
490uint8_t cucul_attr_to_ansi_fg(uint32_t) CACA_ALIAS(caca_attr_to_ansi_fg);
491uint8_t cucul_attr_to_ansi_bg(uint32_t) CACA_ALIAS(caca_attr_to_ansi_bg);
492uint16_t cucul_attr_to_rgb12_fg(uint32_t) CACA_ALIAS(caca_attr_to_rgb12_fg);
493uint16_t cucul_attr_to_rgb12_bg(uint32_t) CACA_ALIAS(caca_attr_to_rgb12_bg);
494void cucul_attr_to_argb64(uint32_t, uint8_t[8]) CACA_ALIAS(caca_attr_to_argb64);
495
Note: See TracBrowser for help on using the repository browser.