source: libcaca/trunk/cucul/cucul.c @ 734

Last change on this file since 734 was 734, checked in by Sam Hocevar, 15 years ago
  • Renamed *bitmap to *dither. Ben ouais connard, je fais ce que je veux.
  • Property svn:keywords set to Id
File size: 10.3 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the Do What The Fuck You Want To
8 *  Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12/** \file cucul.c
13 *  \version \$Id: cucul.c 734 2006-04-10 20:02:38Z sam $
14 *  \author Sam Hocevar <sam@zoy.org>
15 *  \brief Main \e libcucul functions
16 *
17 *  This file contains the main functions used by \e libcucul applications
18 *  to initialise a drawing context.
19 */
20
21#include "config.h"
22
23#if !defined(__KERNEL__)
24#   include <stdio.h>
25#   include <stdlib.h>
26#   include <string.h>
27#endif
28
29#include "cucul.h"
30#include "cucul_internals.h"
31
32/** \brief Initialise a \e libcucul canvas.
33 *
34 *  This function initialises internal \e libcucul structures and the backend
35 *  that will be used for subsequent graphical operations. It must be the
36 *  first \e libcucul function to be called in a function. cucul_free() should
37 *  be called at the end of the program to free all allocated resources.
38 *
39 *  If one of the desired canvas coordinates is zero, a default canvas size
40 *  of 80x32 is used instead.
41 *
42 *  \param width The desired canvas width
43 *  \param height The desired canvas height
44 *  \return 0 upon success, a non-zero value if an error occurs.
45 */
46cucul_t * cucul_create(unsigned int width, unsigned int height)
47{
48    cucul_t *qq = malloc(sizeof(cucul_t));
49
50    qq->refcount = 0;
51
52    qq->fgcolor = CUCUL_COLOR_LIGHTGRAY;
53    qq->bgcolor = CUCUL_COLOR_BLACK;
54
55    qq->width = qq->height = 0;
56    qq->chars = NULL;
57    qq->attr = NULL;
58    qq->empty_line = qq->scratch_line = NULL;
59
60    /* Initialise to a default size. 80x32 is arbitrary but matches AAlib's
61     * default X11 window. When a graphic driver attaches to us, it can set
62     * a different size. */
63    if(width && height)
64        _cucul_set_size(qq, width, height);
65    else
66        _cucul_set_size(qq, 80, 32);
67
68    if(_cucul_init_dither())
69    {
70        free(qq);
71        return NULL;
72    }
73
74    return qq;
75}
76
77cucul_t *cucul_load(void *data, unsigned int size)
78{
79    cucul_t *qq;
80    uint8_t *buf = (uint8_t *)data;
81    unsigned int width, height, n;
82
83    if(size < 12)
84        return NULL;
85
86    if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
87        return NULL;
88
89    width = ((uint32_t)buf[4] << 24) | ((uint32_t)buf[5] << 16)
90          | ((uint32_t)buf[6] << 8) | (uint32_t)buf[7];
91    height = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
92           | ((uint32_t)buf[10] << 8) | (uint32_t)buf[11];
93
94    if(!width || !height)
95        return NULL;
96
97    if(size != 12 + width * height * 8 + 4)
98        return NULL;
99
100    if(buf[size - 4] != 'A' || buf[size - 3] != 'C'
101        || buf[size - 2] != 'A' || buf[size - 1] != 'C')
102        return NULL;
103
104    qq = cucul_create(width, height);
105
106    if(!qq)
107        return NULL;
108
109    for(n = height * width; n--; )
110    {
111        qq->chars[n] = ((uint32_t)buf[12 + 8 * n] << 24)
112                     | ((uint32_t)buf[13 + 8 * n] << 16)
113                     | ((uint32_t)buf[14 + 8 * n] << 8)
114                     | (uint32_t)buf[15 + 8 * n];
115        qq->attr[n] = ((uint32_t)buf[16 + 8 * n] << 24)
116                    | ((uint32_t)buf[17 + 8 * n] << 16)
117                    | ((uint32_t)buf[18 + 8 * n] << 8)
118                    | (uint32_t)buf[19 + 8 * n];
119    }
120
121    return qq;
122}
123
124/** \brief Resize a canvas.
125 *
126 *  This function sets the canvas width and height, in character cells.
127 *
128 *  The contents of the canvas are preserved to the extent of the new
129 *  canvas size. Newly allocated character cells at the right and/or at
130 *  the bottom of the canvas are filled with spaces.
131 *
132 *  It is an error to try to resize the canvas if an output driver has
133 *  been attached to the canvas using caca_attach(). You need to remove
134 *  the output driver using caca_detach() before you can change the
135 *  canvas size again. However, the caca output driver can cause a canvas
136 *  resize through user interaction. See the caca_event() documentation
137 *  for more about this.
138 *
139 *  \param width The desired canvas width
140 *  \param height The desired canvas height
141 */
142void cucul_set_size(cucul_t *qq, unsigned int width, unsigned int height)
143{
144    if(qq->refcount)
145        return;
146
147    _cucul_set_size(qq, width, height);
148}
149
150/** \brief Get the canvas width.
151 *
152 *  This function returns the current canvas width, in character cells.
153 *
154 *  \return The canvas width.
155 */
156unsigned int cucul_get_width(cucul_t *qq)
157{
158    return qq->width;
159}
160
161/** \brief Get the canvas height.
162 *
163 *  This function returns the current canvas height, in character cells.
164 *
165 *  \return The canvas height.
166 */
167unsigned int cucul_get_height(cucul_t *qq)
168{
169    return qq->height;
170}
171
172/** \brief Translate a colour index into the colour's name.
173 *
174 *  This function translates a cucul_color enum into a human-readable
175 *  description string of the associated colour.
176 *
177 *  \param color The colour value.
178 *  \return A static string containing the colour's name.
179 */
180char const *cucul_get_color_name(unsigned int color)
181{
182    static char const *color_names[] =
183    {
184        "black",
185        "blue",
186        "green",
187        "cyan",
188        "red",
189        "magenta",
190        "brown",
191        "light gray",
192        "dark gray",
193        "light blue",
194        "light green",
195        "light cyan",
196        "light red",
197        "light magenta",
198        "yellow",
199        "white",
200    };
201
202    if(color < 0 || color > 15)
203        return "unknown";
204
205    return color_names[color];
206}
207
208/** \brief Uninitialise \e libcucul.
209 *
210 *  This function frees all resources allocated by cucul_create(). After
211 *  cucul_free() has been called, no other \e libcucul functions may be used
212 *  unless a new call to cucul_create() is done.
213 */
214void cucul_free(cucul_t *qq)
215{
216    _cucul_end_dither();
217
218    free(qq->empty_line);
219    free(qq->scratch_line);
220
221    free(qq->chars);
222    free(qq->attr);
223
224    free(qq);
225}
226
227struct cucul_export * cucul_create_export(cucul_t *qq, char const *format)
228{
229    struct cucul_export *ex;
230
231    ex = malloc(sizeof(struct cucul_export));
232
233    if(!strcasecmp("ansi", format))
234        _cucul_get_ansi(qq, ex);
235    else if(!strcasecmp("html", format))
236        _cucul_get_html(qq, ex);
237    else if(!strcasecmp("html3", format))
238        _cucul_get_html3(qq, ex);
239    else if(!strcasecmp("irc", format))
240        _cucul_get_irc(qq, ex);
241    else if(!strcasecmp("ps", format))
242        _cucul_get_ps(qq, ex);
243    else if(!strcasecmp("svg", format))
244        _cucul_get_svg(qq, ex);
245    else
246    {
247        free(ex);
248        return NULL;
249    }
250
251    return ex;
252}
253
254/**
255 * \brief Get available export formats
256 *
257 * Return a list of available export formats. The list is a NULL-terminated
258 * array of strings, interleaving a string containing the internal value for
259 * the export format, to be used with \e cucul_export(), and a string
260 * containing the natural language description for that export format.
261 *
262 * \return An array of strings.
263 */
264char const * const * cucul_get_export_list(void)
265{
266    static char const * const list[] =
267    {
268        "ansi", "ANSI",
269        "html", "HTML",
270        "html3", "backwards-compatible HTML",
271        "irc", "IRC (mIRC colours)",
272        "ps", "PostScript",
273        "svg", "SVG",
274        NULL, NULL
275    };
276
277    return list;
278}
279
280void cucul_free_export(struct cucul_export *ex)
281{
282    free(ex->buffer);
283    free(ex);
284}
285
286/*
287 * XXX: The following functions are local.
288 */
289
290void _cucul_set_size(cucul_t *qq, unsigned int width, unsigned int height)
291{
292    unsigned int x, y, old_width, old_height, new_size, old_size;
293
294    old_width = qq->width;
295    old_height = qq->height;
296    old_size = old_width * old_height;
297
298    qq->width = width;
299    qq->height = height;
300    new_size = width * height;
301
302    /* Step 1: if new area is bigger, resize the memory area now. */
303    if(new_size > old_size)
304    {
305        qq->chars = realloc(qq->chars, new_size * sizeof(uint32_t));
306        qq->attr = realloc(qq->attr, new_size * sizeof(uint32_t));
307    }
308
309    /* Step 2: move line data if necessary. */
310    if(width == old_width)
311    {
312        /* Width did not change, which means we do not need to move data. */
313        ;
314    }
315    else if(width > old_width)
316    {
317        /* New width is bigger than old width, which means we need to
318         * copy lines starting from the bottom of the screen otherwise
319         * we will overwrite information. */
320        for(y = height < old_height ? height : old_height; y--; )
321        {
322            for(x = old_width; x--; )
323            {
324                qq->chars[y * width + x] = qq->chars[y * old_width + x];
325                qq->attr[y * width + x] = qq->attr[y * old_width + x];
326            }
327
328            /* Zero the end of the line */
329            for(x = width - old_width; x--; )
330                qq->chars[y * width + old_width + x] = (uint32_t)' ';
331            memset(qq->attr + y * width + old_width, 0,
332                   (width - old_width) * 4);
333        }
334    }
335    else
336    {
337        /* New width is smaller. Copy as many lines as possible. Ignore
338         * the first line, it is already in place. */
339        unsigned int lines = height < old_height ? height : old_height;
340
341        for(y = 1; y < lines; y++)
342        {
343            for(x = 0; x < width; x++)
344            {
345                qq->chars[y * width + x] = qq->chars[y * old_width + x];
346                qq->attr[y * width + x] = qq->attr[y * old_width + x];
347            }
348        }
349    }
350
351    /* Step 3: fill the bottom of the new screen if necessary. */
352    if(height > old_height)
353    {
354        /* Zero the bottom of the screen */
355        for(x = (height - old_height) * width; x--; )
356            qq->chars[old_height * width + x] = (uint32_t)' ';
357        memset(qq->attr + old_height * width, 0,
358               (height - old_height) * width * 4);
359    }
360
361    /* Step 4: if new area is smaller, resize memory area now. */
362    if(new_size <= old_size)
363    {
364        qq->chars = realloc(qq->chars, new_size * sizeof(uint32_t));
365        qq->attr = realloc(qq->attr, new_size * sizeof(uint32_t));
366    }
367
368    /* Recompute the scratch line and the empty line */
369    if(width != old_width)
370    {
371        qq->empty_line = realloc(qq->empty_line, width + 1);
372        memset(qq->empty_line, ' ', width);
373        qq->empty_line[width] = '\0';
374
375        qq->scratch_line = realloc(qq->scratch_line, width + 1);
376    }
377}
378
Note: See TracBrowser for help on using the repository browser.