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

Last change on this file since 1267 was 1267, checked in by Sam Hocevar, 16 years ago
  • Got rid of cucul_ansi_to_attr() and cucul_argb_to_attr() and restored cucul_set_color() and cucul_set_truecolor() under the new names cucul_set_color_ansi() and cucul_set_color_argb().
  • Renamed cucul_get_color_name() into cucul_ansi_to_str().
  • Property svn:keywords set to Id
File size: 11.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 *  $Id: cucul.c 1267 2006-10-31 13:29:48Z 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#include "common.h"
21
22#if !defined(__KERNEL__)
23#   include <stdio.h>
24#   include <stdlib.h>
25#   include <string.h>
26#   include <time.h>
27#   if defined(HAVE_ERRNO_H)
28#       include <errno.h>
29#   endif
30#   include <sys/types.h>
31#   if defined(HAVE_UNISTD_H)
32#       include <unistd.h>
33#   endif
34#endif
35
36#include "cucul.h"
37#include "cucul_internals.h"
38
39/** \brief Initialise a \e libcucul canvas.
40 *
41 *  Initialise internal \e libcucul structures and the backend that will
42 *  be used for subsequent graphical operations. It must be the first
43 *  \e libcucul function to be called in a function. cucul_free_canvas()
44 *  should be called at the end of the program to free all allocated resources.
45 *
46 *  If an error occurs, NULL is returned and \b errno is set accordingly:
47 *  - \c ENOMEM Not enough memory for the requested canvas size.
48 *
49 *  \param width The desired canvas width
50 *  \param height The desired canvas height
51 *  \return A libcucul canvas handle upon success, NULL if an error occurred.
52 */
53cucul_canvas_t * cucul_create_canvas(unsigned int width, unsigned int height)
54{
55    cucul_canvas_t *cv = malloc(sizeof(cucul_canvas_t));
56
57    if(!cv)
58        goto nomem;
59
60    cv->refcount = 0;
61
62    cv->curattr = (CUCUL_DEFAULT << 20) | (CUCUL_TRANSPARENT < 4);
63
64    cv->width = cv->height = 0;
65    cv->chars = NULL;
66    cv->attrs = NULL;
67
68    cv->frame = 0;
69    cv->framecount = 1;
70    cv->allchars = malloc(sizeof(uint32_t *));
71    if(!cv->allchars)
72    {
73        free(cv);
74        goto nomem;
75    }
76    cv->allattrs = malloc(sizeof(uint32_t *));
77    if(!cv->allattrs)
78    {
79        free(cv->allchars);
80        free(cv);
81        goto nomem;
82    }
83    cv->allchars[0] = NULL;
84    cv->allattrs[0] = NULL;
85
86    if(_cucul_set_canvas_size(cv, width, height) < 0)
87    {
88#if defined(HAVE_ERRNO_H)
89        int saved_errno = errno;
90#endif
91        free(cv->allattrs);
92        free(cv->allchars);
93        free(cv);
94#if defined(HAVE_ERRNO_H)
95        errno = saved_errno;
96#endif
97        return NULL;
98    }
99
100    /* FIXME: this shouldn't happen here */
101    _cucul_init_dither();
102
103    return cv;
104
105nomem:
106#if defined(HAVE_ERRNO_H)
107    errno = ENOMEM;
108#endif
109    return NULL;
110}
111
112/** \brief Resize a canvas.
113 *
114 *  Set the canvas' width and height, in character cells.
115 *
116 *  The contents of the canvas are preserved to the extent of the new
117 *  canvas size. Newly allocated character cells at the right and/or at
118 *  the bottom of the canvas are filled with spaces.
119 *
120 *  It is an error to try to resize the canvas if an output driver has
121 *  been attached to the canvas using caca_create_display(). You need to
122 *  remove the output driver using caca_free_display() before you can change
123 *  the  canvas size again. However, the caca output driver can cause a
124 *  canvas resize through user interaction. See the caca_event() documentation
125 *  for more about this.
126 *
127 *  If an error occurs, -1 is returned and \b errno is set accordingly:
128 *  - \c EBUSY The canvas is in use by a display driver and cannot be resized.
129 *  - \c ENOMEM Not enough memory for the requested canvas size. If this
130 *    happens, the canvas handle becomes invalid and should not be used.
131 *
132 *  \param cv A libcucul canvas
133 *  \param width The desired canvas width
134 *  \param height The desired canvas height
135 *  \return 0 in case of success, -1 if an error occurred.
136 */
137int cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
138                                              unsigned int height)
139{
140    if(cv->refcount)
141    {
142#if defined(HAVE_ERRNO_H)
143        errno = EBUSY;
144#endif
145        return -1;
146    }
147
148    return _cucul_set_canvas_size(cv, width, height);
149}
150
151/** \brief Get the canvas width.
152 *
153 *  Return the current canvas' width, in character cells.
154 *
155 *  This function never fails.
156 *
157 *  \param cv A libcucul canvas
158 *  \return The canvas width.
159 */
160unsigned int cucul_get_canvas_width(cucul_canvas_t *cv)
161{
162    return cv->width;
163}
164
165/** \brief Get the canvas height.
166 *
167 *  Returns the current canvas' height, in character cells.
168 *
169 *  This function never fails.
170 *
171 *  \param cv A libcucul canvas
172 *  \return The canvas height.
173 */
174unsigned int cucul_get_canvas_height(cucul_canvas_t *cv)
175{
176    return cv->height;
177}
178
179/** \brief Translate an ANSI colour index into the colour's name.
180 *
181 *  Translate an ANSI colour index such as \e CUCUL_RED or \e CUCUL_WHITE
182 *  into a human-readable string describing the corresponding colour.
183 *
184 *  This function never fails.
185 *
186 *  \param color The colour value.
187 *  \return A static string containing the colour's name, or \c "unknown" if
188 *  the colour is unknown.
189 */
190char const *cucul_ansi_to_str(unsigned char color)
191{
192    static char const *color_names[] =
193    {
194        "black",
195        "blue",
196        "green",
197        "cyan",
198        "red",
199        "magenta",
200        "brown",
201        "light gray",
202        "dark gray",
203        "light blue",
204        "light green",
205        "light cyan",
206        "light red",
207        "light magenta",
208        "yellow",
209        "white",
210    };
211
212    if(color > 15)
213        return "unknown";
214
215    return color_names[(unsigned int)color];
216}
217
218/* Legacy function for old programs */
219char const *cucul_get_color_name(unsigned int color)
220{
221    return cucul_ansi_to_str(color > 15 ? 15 : color);
222}
223
224/** \brief Uninitialise \e libcucul.
225 *
226 *  Free all resources allocated by cucul_create_canvas(). After
227 *  this function has been called, no other \e libcucul functions may be
228 *  used unless a new call to cucul_create_canvas() is done.
229 *
230 *  If an error occurs, -1 is returned and \b errno is set accordingly:
231 *  - \c EBUSY The canvas is in use by a display driver and cannot be freed.
232 *
233 *  \param cv A libcucul canvas
234 *  \return 0 in case of success, -1 if an error occurred.
235 */
236int cucul_free_canvas(cucul_canvas_t *cv)
237{
238    unsigned int f;
239
240    if(cv->refcount)
241    {
242#if defined(HAVE_ERRNO_H)
243        errno = EBUSY;
244#endif
245        return -1;
246    }
247
248    /* FIXME: this shouldn't be here either (see above) */
249    _cucul_end_dither();
250
251    for(f = 0; f < cv->framecount; f++)
252    {
253        free(cv->allchars[f]);
254        free(cv->allattrs[f]);
255    }
256
257    free(cv->allchars);
258    free(cv->allattrs);
259    free(cv);
260
261    return 0;
262}
263
264/** \brief Generate a random integer within a range.
265 *
266 *  Generate a random integer within the given range.
267 *
268 *  This function never fails.
269 *
270 *  \param min The lower bound of the integer range.
271 *  \param max The upper bound of the integer range.
272 *  \return A random integer comprised between \p min  and \p max - 1
273 *  (inclusive).
274 */
275int cucul_rand(int min, int max)
276{
277    static int need_init = 1;
278
279    if(need_init)
280    {
281        srand(getpid() + time(NULL));
282        need_init = 0;
283    }
284
285    return min + (int)((1.0 * (max - min)) * rand() / (RAND_MAX + 1.0));
286}
287
288/*
289 * XXX: The following functions are local.
290 */
291
292int _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
293                                               unsigned int height)
294{
295    unsigned int x, y, f, old_width, old_height, new_size, old_size;
296
297    old_width = cv->width;
298    old_height = cv->height;
299    old_size = old_width * old_height;
300
301    cv->width = width;
302    cv->height = height;
303    new_size = width * height;
304
305    /* Step 1: if new area is bigger, resize the memory area now. */
306    if(new_size > old_size)
307    {
308        for(f = 0; f < cv->framecount; f++)
309        {
310            cv->allchars[f] = realloc(cv->allchars[f],
311                                      new_size * sizeof(uint32_t));
312            cv->allattrs[f] = realloc(cv->allattrs[f],
313                                     new_size * sizeof(uint32_t));
314            if(!cv->allchars[f] || !cv->allattrs[f])
315            {
316#if defined(HAVE_ERRNO_H)
317                errno = ENOMEM;
318#endif
319                return -1;
320            }
321        }
322    }
323
324    /* Step 2: move line data if necessary. */
325    if(width == old_width)
326    {
327        /* Width did not change, which means we do not need to move data. */
328        ;
329    }
330    else if(width > old_width)
331    {
332        /* New width is bigger than old width, which means we need to
333         * copy lines starting from the bottom of the screen otherwise
334         * we will overwrite information. */
335        for(f = 0; f < cv->framecount; f++)
336        {
337            uint32_t *chars = cv->allchars[f];
338            uint32_t *attrs = cv->allattrs[f];
339
340            for(y = height < old_height ? height : old_height; y--; )
341            {
342                uint32_t attr = cv->curattr;
343
344                for(x = old_width; x--; )
345                {
346                    chars[y * width + x] = chars[y * old_width + x];
347                    attrs[y * width + x] = attrs[y * old_width + x];
348                }
349
350                /* Zero the end of the line */
351                for(x = width - old_width; x--; )
352                {
353                    chars[y * width + old_width + x] = (uint32_t)' ';
354                    attrs[y * width + old_width + x] = attr;
355                }
356            }
357        }
358    }
359    else
360    {
361        /* New width is smaller. Copy as many lines as possible. Ignore
362         * the first line, it is already in place. */
363        unsigned int lines = height < old_height ? height : old_height;
364
365        for(f = 0; f < cv->framecount; f++)
366        {
367            uint32_t *chars = cv->allchars[f];
368            uint32_t *attrs = cv->allattrs[f];
369
370            for(y = 1; y < lines; y++)
371            {
372                for(x = 0; x < width; x++)
373                {
374                    chars[y * width + x] = chars[y * old_width + x];
375                    attrs[y * width + x] = attrs[y * old_width + x];
376                }
377            }
378        }
379    }
380
381    /* Step 3: fill the bottom of the new screen if necessary. */
382    if(height > old_height)
383    {
384        for(f = 0; f < cv->framecount; f++)
385        {
386            uint32_t *chars = cv->allchars[f];
387            uint32_t *attrs = cv->allattrs[f];
388            uint32_t attr = cv->curattr;
389
390            /* Zero the bottom of the screen */
391            for(x = (height - old_height) * width; x--; )
392            {
393                chars[old_height * width + x] = (uint32_t)' ';
394                attrs[old_height * width + x] = attr;
395            }
396        }
397    }
398
399    /* Step 4: if new area is smaller, resize memory area now. */
400    if(new_size <= old_size)
401    {
402        for(f = 0; f < cv->framecount; f++)
403        {
404            cv->allchars[f] = realloc(cv->allchars[f],
405                                      new_size * sizeof(uint32_t));
406            cv->allattrs[f] = realloc(cv->allattrs[f],
407                                     new_size * sizeof(uint32_t));
408            if(!cv->allchars[f] || !cv->allattrs[f])
409            {
410#if defined(HAVE_ERRNO_H)
411                errno = ENOMEM;
412#endif
413                return -1;
414            }
415        }
416    }
417
418    /* Reset the current frame shortcut */
419    cv->chars = cv->allchars[cv->frame];
420    cv->attrs = cv->allattrs[cv->frame];
421
422    return 0;
423}
424
Note: See TracBrowser for help on using the repository browser.