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

Last change on this file since 3448 was 3448, checked in by Sam Hocevar, 11 years ago

Finish the dirty rectangle architecture. They are now reliable in the sense
that anything outside the dirty rectangle is guaranteed to be unchanged, but
we currently mark far too many cells as dirty. This must be optimised.

  • Property svn:keywords set to Id
File size: 15.5 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: attr.c 3448 2009-05-14 00:18:23Z 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    caca_add_dirty_rectangle(cv, xmin, xmax, y, y);
160
161    return 0;
162}
163
164/** \brief Set the default colour pair for text (ANSI version).
165 *
166 *  Set the default ANSI colour pair for text drawing. String functions such
167 *  as caca_printf() and graphical primitive functions such as caca_draw_line()
168 *  will use these attributes.
169 *
170 *  Color values are those defined in caca.h, such as CACA_RED
171 *  or CACA_TRANSPARENT.
172 *
173 *  If an error occurs, 0 is returned and \b errno is set accordingly:
174 *  - \c EINVAL At least one of the colour values is invalid.
175 *
176 *  \param cv A handle to the libcaca canvas.
177 *  \param fg The requested ANSI foreground colour.
178 *  \param bg The requested ANSI background colour.
179 *  \return 0 in case of success, -1 if an error occurred.
180 */
181int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
182{
183    uint32_t attr;
184
185    if(fg > 0x20 || bg > 0x20)
186    {
187        seterrno(EINVAL);
188        return -1;
189    }
190
191    attr = ((uint32_t)(bg | 0x40) << 18) | ((uint32_t)(fg | 0x40) << 4);
192    cv->curattr = (cv->curattr & 0x0000000f) | attr;
193
194    return 0;
195}
196
197/** \brief Set the default colour pair for text (truecolor version).
198 *
199 *  Set the default ARGB colour pair for text drawing. String functions such
200 *  as caca_printf() and graphical primitive functions such as caca_draw_line()
201 *  will use these attributes.
202 *
203 *  Colors are 16-bit ARGB values, each component being coded on 4 bits. For
204 *  instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
205 *  white with 50% alpha (A=8 R=15 G=15 B=15).
206 *
207 *  This function never fails.
208 *
209 *  \param cv A handle to the libcaca canvas.
210 *  \param fg The requested ARGB foreground colour.
211 *  \param bg The requested ARGB background colour.
212 *  \return This function always returns 0.
213 */
214int caca_set_color_argb(caca_canvas_t *cv, uint16_t fg, uint16_t bg)
215{
216    uint32_t attr;
217
218    if(fg < 0x100)
219        fg += 0x100;
220
221    if(bg < 0x100)
222        bg += 0x100;
223
224    fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
225    bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);
226
227    attr = ((uint32_t)bg << 18) | ((uint32_t)fg << 4);
228    cv->curattr = (cv->curattr & 0x0000000f) | attr;
229
230    return 0;
231}
232
233/** \brief Get DOS ANSI information from attribute.
234 *
235 *  Get the ANSI colour pair for a given attribute. The returned value is
236 *  an 8-bit value whose higher 4 bits are the background colour and lower
237 *  4 bits are the foreground colour.
238 *
239 *  If the attribute has ARGB colours, the nearest colour is used. Special
240 *  attributes such as \e CACA_DEFAULT and \e CACA_TRANSPARENT are not
241 *  handled and are both replaced with \e CACA_LIGHTGRAY for the foreground
242 *  colour and \e CACA_BLACK for the background colour.
243 *
244 *  This function never fails. If the attribute value is outside the expected
245 *  32-bit range, higher order bits are simply ignored.
246 *
247 *  \param attr The requested attribute value.
248 *  \return The corresponding DOS ANSI value.
249 */
250uint8_t caca_attr_to_ansi(uint32_t attr)
251{
252    uint8_t fg = nearest_ansi((attr >> 4) & 0x3fff);
253    uint8_t bg = nearest_ansi(attr >> 18);
254
255    return (fg < 0x10 ? fg : CACA_LIGHTGRAY)
256            | ((bg < 0x10 ? bg : CACA_BLACK) << 4);
257}
258
259/** \brief Get ANSI foreground information from attribute.
260 *
261 *  Get the ANSI foreground colour value for a given attribute. The returned
262 *  value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
263 *  colours, or the special value \e CACA_DEFAULT meaning the media's
264 *  default foreground value, or the special value \e CACA_TRANSPARENT.
265 *
266 *  If the attribute has ARGB colours, the nearest colour is returned.
267 *
268 *  This function never fails. If the attribute value is outside the expected
269 *  32-bit range, higher order bits are simply ignored.
270 *
271 *  \param attr The requested attribute value.
272 *  \return The corresponding ANSI foreground value.
273 */
274uint8_t caca_attr_to_ansi_fg(uint32_t attr)
275{
276    return nearest_ansi(((uint16_t)attr >> 4) & 0x3fff);
277}
278
279/** \brief Get ANSI background information from attribute.
280 *
281 *  Get the ANSI background colour value for a given attribute. The returned
282 *  value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
283 *  colours, or the special value \e CACA_DEFAULT meaning the media's
284 *  default background value, or the special value \e CACA_TRANSPARENT.
285 *
286 *  If the attribute has ARGB colours, the nearest colour is returned.
287 *
288 *  This function never fails. If the attribute value is outside the expected
289 *  32-bit range, higher order bits are simply ignored.
290 *
291 *  \param attr The requested attribute value.
292 *  \return The corresponding ANSI background value.
293 */
294uint8_t caca_attr_to_ansi_bg(uint32_t attr)
295{
296    return nearest_ansi(attr >> 18);
297}
298
299/** \brief Get 12-bit RGB foreground information from attribute.
300 *
301 *  Get the 12-bit foreground colour value for a given attribute. The returned
302 *  value is a native-endian encoded integer with each red, green and blue
303 *  values encoded on 8 bits in the following order:
304 *   - 8-11 most significant bits: red
305 *   - 4-7 most significant bits: green
306 *   - least significant bits: blue
307 *
308 *  This function never fails. If the attribute value is outside the expected
309 *  32-bit range, higher order bits are simply ignored.
310 *
311 *  \param attr The requested attribute value.
312 *  \return The corresponding 12-bit RGB foreground value.
313 */
314uint16_t caca_attr_to_rgb12_fg(uint32_t attr)
315{
316    uint16_t fg = (attr >> 4) & 0x3fff;
317
318    if(fg < (0x10 | 0x40))
319        return ansitab16[fg ^ 0x40] & 0x0fff;
320
321    if(fg == (CACA_DEFAULT | 0x40))
322        return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
323
324    if(fg == (CACA_TRANSPARENT | 0x40))
325        return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
326
327    return (fg << 1) & 0x0fff;
328}
329
330/** \brief Get 12-bit RGB background information from attribute.
331 *
332 *  Get the 12-bit background colour value for a given attribute. The returned
333 *  value is a native-endian encoded integer with each red, green and blue
334 *  values encoded on 8 bits in the following order:
335 *   - 8-11 most significant bits: red
336 *   - 4-7 most significant bits: green
337 *   - least significant bits: blue
338 *
339 *  This function never fails. If the attribute value is outside the expected
340 *  32-bit range, higher order bits are simply ignored.
341 *
342 *  \param attr The requested attribute value.
343 *  \return The corresponding 12-bit RGB background value.
344 */
345uint16_t caca_attr_to_rgb12_bg(uint32_t attr)
346{
347    uint16_t bg = attr >> 18;
348
349    if(bg < (0x10 | 0x40))
350        return ansitab16[bg ^ 0x40] & 0x0fff;
351
352    if(bg == (CACA_DEFAULT | 0x40))
353        return ansitab16[CACA_BLACK] & 0x0fff;
354
355    if(bg == (CACA_TRANSPARENT | 0x40))
356        return ansitab16[CACA_BLACK] & 0x0fff;
357
358    return (bg << 1) & 0x0fff;
359}
360
361/** \brief Get 64-bit ARGB information from attribute.
362 *
363 *  Get the 64-bit colour and alpha values for a given attribute. The values
364 *  are written as 8-bit integers in the \e argb array in the following order:
365 *   - \e argb[0]: background alpha value
366 *   - \e argb[1]: background red value
367 *   - \e argb[2]: background green value
368 *   - \e argb[3]: background blue value
369 *   - \e argb[4]: foreground alpha value
370 *   - \e argb[5]: foreground red value
371 *   - \e argb[6]: foreground green value
372 *   - \e argb[7]: foreground blue value
373 *
374 *  This function never fails. If the attribute value is outside the expected
375 *  32-bit range, higher order bits are simply ignored.
376 *
377 *  \param attr The requested attribute value.
378 *  \param argb An array of 8-bit integers.
379 */
380void caca_attr_to_argb64(uint32_t attr, uint8_t argb[8])
381{
382    uint16_t fg = (attr >> 4) & 0x3fff;
383    uint16_t bg = attr >> 18;
384
385    if(bg < (0x10 | 0x40))
386        bg = ansitab16[bg ^ 0x40];
387    else if(bg == (CACA_DEFAULT | 0x40))
388        bg = ansitab16[CACA_BLACK];
389    else if(bg == (CACA_TRANSPARENT | 0x40))
390        bg = 0x0fff;
391    else
392        bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);
393
394    argb[0] = bg >> 12;
395    argb[1] = (bg >> 8) & 0xf;
396    argb[2] = (bg >> 4) & 0xf;
397    argb[3] = bg & 0xf;
398
399    if(fg < (0x10 | 0x40))
400        fg = ansitab16[fg ^ 0x40];
401    else if(fg == (CACA_DEFAULT | 0x40))
402        fg = ansitab16[CACA_LIGHTGRAY];
403    else if(fg == (CACA_TRANSPARENT | 0x40))
404        fg = 0x0fff;
405    else
406        fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);
407
408    argb[4] = fg >> 12;
409    argb[5] = (fg >> 8) & 0xf;
410    argb[6] = (fg >> 4) & 0xf;
411    argb[7] = fg & 0xf;
412}
413
414/*
415 * XXX: the following functions are local
416 */
417
418static uint8_t nearest_ansi(uint16_t argb14)
419{
420    unsigned int i, best, dist;
421
422    if(argb14 < (0x10 | 0x40))
423        return argb14 ^ 0x40;
424
425    if(argb14 == (CACA_DEFAULT | 0x40) || argb14 == (CACA_TRANSPARENT | 0x40))
426        return argb14 ^ 0x40;
427
428    if(argb14 < 0x0fff) /* too transparent */
429        return CACA_TRANSPARENT;
430
431    best = CACA_DEFAULT;
432    dist = 0x3fff;
433    for(i = 0; i < 16; i++)
434    {
435        unsigned int d = 0;
436        int a, b;
437
438        a = (ansitab14[i] >> 7) & 0xf;
439        b = (argb14 >> 7) & 0xf;
440        d += (a - b) * (a - b);
441
442        a = (ansitab14[i] >> 3) & 0xf;
443        b = (argb14 >> 3) & 0xf;
444        d += (a - b) * (a - b);
445
446        a = (ansitab14[i] << 1) & 0xf;
447        b = (argb14 << 1) & 0xf;
448        d += (a - b) * (a - b);
449
450        if(d < dist)
451        {
452            dist = d;
453            best = i;
454        }
455    }
456
457    return best;
458}
459
460#define RGB12TO24(i) \
461   (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
462  | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
463  | ((uint32_t)(i & 0x00f) * 0x000011))
464
465uint32_t _caca_attr_to_rgb24fg(uint32_t attr)
466{
467    return RGB12TO24(caca_attr_to_rgb12_fg(attr));
468}
469
470uint32_t _caca_attr_to_rgb24bg(uint32_t attr)
471{
472    return RGB12TO24(caca_attr_to_rgb12_bg(attr));
473}
474
475/*
476 * XXX: The following functions are aliases.
477 */
478
479uint32_t cucul_get_attr(cucul_canvas_t const *, int, int)
480         CACA_ALIAS(caca_get_attr);
481int cucul_set_attr(cucul_canvas_t *, uint32_t) CACA_ALIAS(caca_set_attr);
482int cucul_put_attr(cucul_canvas_t *, int, int, uint32_t)
483         CACA_ALIAS(caca_put_attr);
484int cucul_set_color_ansi(cucul_canvas_t *, uint8_t, uint8_t)
485         CACA_ALIAS(caca_set_color_ansi);
486int cucul_set_color_argb(cucul_canvas_t *, uint16_t, uint16_t)
487         CACA_ALIAS(caca_set_color_argb);
488uint8_t cucul_attr_to_ansi(uint32_t) CACA_ALIAS(caca_attr_to_ansi);
489uint8_t cucul_attr_to_ansi_fg(uint32_t) CACA_ALIAS(caca_attr_to_ansi_fg);
490uint8_t cucul_attr_to_ansi_bg(uint32_t) CACA_ALIAS(caca_attr_to_ansi_bg);
491uint16_t cucul_attr_to_rgb12_fg(uint32_t) CACA_ALIAS(caca_attr_to_rgb12_fg);
492uint16_t cucul_attr_to_rgb12_bg(uint32_t) CACA_ALIAS(caca_attr_to_rgb12_bg);
493void cucul_attr_to_argb64(uint32_t, uint8_t[8]) CACA_ALIAS(caca_attr_to_argb64);
494
Note: See TracBrowser for help on using the repository browser.