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

Last change on this file since 813 was 813, checked in by Sam Hocevar, 15 years ago
  • Renamed main canvas-related functions so that they have "canvas" in their name, eg. cucul_create() -> cucul_create_canvas() etc.
  • Moved buffer-related functions to cucul/buffer.c.
  • Property svn:keywords set to Id
File size: 9.8 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 813 2006-04-18 15:54:33Z 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_canvas()
35 *  should 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 A libcucul canvas handle upon success, NULL if an error occurred.
43 */
44cucul_canvas_t * cucul_create_canvas(unsigned int width, unsigned int height)
45{
46    cucul_canvas_t *cv = malloc(sizeof(cucul_canvas_t));
47
48    cv->refcount = 0;
49
50    cv->fgcolor = CUCUL_COLOR_LIGHTGRAY;
51    cv->bgcolor = CUCUL_COLOR_BLACK;
52
53    cv->width = cv->height = 0;
54    cv->chars = NULL;
55    cv->attr = NULL;
56    cv->empty_line = cv->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_canvas_size(cv, width, height);
63    else
64        _cucul_set_canvas_size(cv, 80, 32);
65
66    if(_cucul_init_dither())
67    {
68        free(cv);
69        return NULL;
70    }
71
72    return cv;
73}
74
75/** \brief Load a memory area into a canvas.
76 *
77 *  This function loads a memory area containing an exported canvas into
78 *  a new \e libcucul canvas.
79 *
80 *  \param data The memory area to be loaded into a canvas.
81 *  \param size The length of the memory area.
82 *  \return A libcucul canvas, or NULL in case of error.
83 */
84cucul_canvas_t *cucul_load_canvas(void *data, unsigned int size)
85{
86    cucul_canvas_t *cv;
87    uint8_t *buf = (uint8_t *)data;
88    unsigned int width, height, n;
89
90    if(size < 12)
91        return NULL;
92
93    if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
94        return NULL;
95
96    width = ((uint32_t)buf[4] << 24) | ((uint32_t)buf[5] << 16)
97          | ((uint32_t)buf[6] << 8) | (uint32_t)buf[7];
98    height = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
99           | ((uint32_t)buf[10] << 8) | (uint32_t)buf[11];
100
101    if(!width || !height)
102        return NULL;
103
104    if(size != 12 + width * height * 8 + 4)
105        return NULL;
106
107    if(buf[size - 4] != 'A' || buf[size - 3] != 'C'
108        || buf[size - 2] != 'A' || buf[size - 1] != 'C')
109        return NULL;
110
111    cv = cucul_create_canvas(width, height);
112
113    if(!cv)
114        return NULL;
115
116    for(n = height * width; n--; )
117    {
118        cv->chars[n] = ((uint32_t)buf[12 + 8 * n] << 24)
119                     | ((uint32_t)buf[13 + 8 * n] << 16)
120                     | ((uint32_t)buf[14 + 8 * n] << 8)
121                     | (uint32_t)buf[15 + 8 * n];
122        cv->attr[n] = ((uint32_t)buf[16 + 8 * n] << 24)
123                    | ((uint32_t)buf[17 + 8 * n] << 16)
124                    | ((uint32_t)buf[18 + 8 * n] << 8)
125                    | (uint32_t)buf[19 + 8 * n];
126    }
127
128    return cv;
129}
130
131/** \brief Resize a canvas.
132 *
133 *  This function sets the canvas width and height, in character cells.
134 *
135 *  The contents of the canvas are preserved to the extent of the new
136 *  canvas size. Newly allocated character cells at the right and/or at
137 *  the bottom of the canvas are filled with spaces.
138 *
139 *  It is an error to try to resize the canvas if an output driver has
140 *  been attached to the canvas using caca_attach(). You need to remove
141 *  the output driver using caca_detach() before you can change the
142 *  canvas size again. However, the caca output driver can cause a canvas
143 *  resize through user interaction. See the caca_event() documentation
144 *  for more about this.
145 *
146 *  \param cv A libcucul canvas
147 *  \param width The desired canvas width
148 *  \param height The desired canvas height
149 */
150void cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
151                                               unsigned int height)
152{
153    if(cv->refcount)
154        return;
155
156    _cucul_set_canvas_size(cv, width, height);
157}
158
159/** \brief Get the canvas width.
160 *
161 *  This function returns the current canvas width, in character cells.
162 *
163 *  \param cv A libcucul canvas
164 *  \return The canvas width.
165 */
166unsigned int cucul_get_canvas_width(cucul_canvas_t *cv)
167{
168    return cv->width;
169}
170
171/** \brief Get the canvas height.
172 *
173 *  This function returns the current canvas height, in character cells.
174 *
175 *  \param cv A libcucul canvas
176 *  \return The canvas height.
177 */
178unsigned int cucul_get_canvas_height(cucul_canvas_t *cv)
179{
180    return cv->height;
181}
182
183/** \brief Translate a colour index into the colour's name.
184 *
185 *  This function translates a cucul_color enum into a human-readable
186 *  description string of the associated colour.
187 *
188 *  \param color The colour value.
189 *  \return A static string containing the colour's name.
190 */
191char const *cucul_get_color_name(unsigned int color)
192{
193    static char const *color_names[] =
194    {
195        "black",
196        "blue",
197        "green",
198        "cyan",
199        "red",
200        "magenta",
201        "brown",
202        "light gray",
203        "dark gray",
204        "light blue",
205        "light green",
206        "light cyan",
207        "light red",
208        "light magenta",
209        "yellow",
210        "white",
211    };
212
213    if(color < 0 || color > 15)
214        return "unknown";
215
216    return color_names[color];
217}
218
219/** \brief Uninitialise \e libcucul.
220 *
221 *  This function frees all resources allocated by cucul_create_canvas(). After
222 *  cucul_free_canvas() has been called, no other \e libcucul functions may be
223 *  used unless a new call to cucul_create_canvas() is done.
224 *
225 *  \param cv A libcucul canvas
226 */
227void cucul_free_canvas(cucul_canvas_t *cv)
228{
229    _cucul_end_dither();
230
231    free(cv->empty_line);
232    free(cv->scratch_line);
233
234    free(cv->chars);
235    free(cv->attr);
236
237    free(cv);
238}
239
240/** \brief Generate a random integer within a range.
241 *
242 *  \param min The lower bound of the integer range.
243 *  \param max The upper bound of the integer range.
244 *  \return A random integer comprised between \p min and \p max, inclusive.
245 */
246int cucul_rand(int min, int max)
247{
248    return min + (int)((1.0*(max-min+1)) * rand() / (RAND_MAX+1.0));
249}
250
251/*
252 * XXX: The following functions are local.
253 */
254
255void _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
256                                                unsigned int height)
257{
258    unsigned int x, y, old_width, old_height, new_size, old_size;
259
260    old_width = cv->width;
261    old_height = cv->height;
262    old_size = old_width * old_height;
263
264    cv->width = width;
265    cv->height = height;
266    new_size = width * height;
267
268    /* Step 1: if new area is bigger, resize the memory area now. */
269    if(new_size > old_size)
270    {
271        cv->chars = realloc(cv->chars, new_size * sizeof(uint32_t));
272        cv->attr = realloc(cv->attr, new_size * sizeof(uint32_t));
273    }
274
275    /* Step 2: move line data if necessary. */
276    if(width == old_width)
277    {
278        /* Width did not change, which means we do not need to move data. */
279        ;
280    }
281    else if(width > old_width)
282    {
283        /* New width is bigger than old width, which means we need to
284         * copy lines starting from the bottom of the screen otherwise
285         * we will overwrite information. */
286        for(y = height < old_height ? height : old_height; y--; )
287        {
288            for(x = old_width; x--; )
289            {
290                cv->chars[y * width + x] = cv->chars[y * old_width + x];
291                cv->attr[y * width + x] = cv->attr[y * old_width + x];
292            }
293
294            /* Zero the end of the line */
295            for(x = width - old_width; x--; )
296                cv->chars[y * width + old_width + x] = (uint32_t)' ';
297            memset(cv->attr + y * width + old_width, 0,
298                   (width - old_width) * 4);
299        }
300    }
301    else
302    {
303        /* New width is smaller. Copy as many lines as possible. Ignore
304         * the first line, it is already in place. */
305        unsigned int lines = height < old_height ? height : old_height;
306
307        for(y = 1; y < lines; y++)
308        {
309            for(x = 0; x < width; x++)
310            {
311                cv->chars[y * width + x] = cv->chars[y * old_width + x];
312                cv->attr[y * width + x] = cv->attr[y * old_width + x];
313            }
314        }
315    }
316
317    /* Step 3: fill the bottom of the new screen if necessary. */
318    if(height > old_height)
319    {
320        /* Zero the bottom of the screen */
321        for(x = (height - old_height) * width; x--; )
322            cv->chars[old_height * width + x] = (uint32_t)' ';
323        memset(cv->attr + old_height * width, 0,
324               (height - old_height) * width * 4);
325    }
326
327    /* Step 4: if new area is smaller, resize memory area now. */
328    if(new_size <= old_size)
329    {
330        cv->chars = realloc(cv->chars, new_size * sizeof(uint32_t));
331        cv->attr = realloc(cv->attr, new_size * sizeof(uint32_t));
332    }
333
334    /* Recompute the scratch line and the empty line */
335    if(width != old_width)
336    {
337        cv->empty_line = realloc(cv->empty_line, width + 1);
338        memset(cv->empty_line, ' ', width);
339        cv->empty_line[width] = '\0';
340
341        cv->scratch_line = realloc(cv->scratch_line, width + 1);
342    }
343}
344
Note: See TracBrowser for help on using the repository browser.