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

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