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

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

Starting refactoring to get rid of libcucul. The initial reason for the
split is rendered moot by the plugin system: when enabled, binaries do
not link directly with libX11 or libGL. I hope this is a step towards
more consisteny and clarity.

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