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

Last change on this file since 859 was 859, checked in by Sam Hocevar, 15 years ago
  • Removed duplicate uint*_t defines from *_internal.h and included common.h in all .c files that needed it.
  • Property svn:keywords set to Id
File size: 9.1 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 859 2006-04-24 20:35:59Z 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#endif
27
28#include "cucul.h"
29#include "cucul_internals.h"
30
31/** \brief Initialise a \e libcucul canvas.
32 *
33 *  This function initialises internal \e libcucul structures and the backend
34 *  that will be used for subsequent graphical operations. It must be the
35 *  first \e libcucul function to be called in a function. cucul_free_canvas()
36 *  should be called at the end of the program to free all allocated resources.
37 *
38 *  If one of the desired canvas coordinates is zero, a default canvas size
39 *  of 80x32 is used instead.
40 *
41 *  \param width The desired canvas width
42 *  \param height The desired canvas height
43 *  \return A libcucul canvas handle upon success, NULL if an error occurred.
44 */
45cucul_canvas_t * cucul_create_canvas(unsigned int width, unsigned int height)
46{
47    cucul_canvas_t *cv = malloc(sizeof(cucul_canvas_t));
48
49    cv->refcount = 0;
50
51    cv->fgcolor = CUCUL_COLOR_LIGHTGRAY;
52    cv->bgcolor = CUCUL_COLOR_BLACK;
53
54    cv->width = cv->height = 0;
55    cv->chars = NULL;
56    cv->attr = NULL;
57
58    cv->frame = 0;
59    cv->framecount = 1;
60    cv->allchars = malloc(sizeof(uint32_t *));
61    cv->allattr = malloc(sizeof(uint32_t *));
62    cv->allchars[0] = NULL;
63    cv->allattr[0] = NULL;
64
65    /* Initialise to a default size. 80x32 is arbitrary but matches AAlib's
66     * default X11 window. When a graphic driver attaches to us, it can set
67     * a different size. */
68    if(width && height)
69        _cucul_set_canvas_size(cv, width, height);
70    else
71        _cucul_set_canvas_size(cv, 80, 32);
72
73    if(_cucul_init_dither())
74    {
75        free(cv);
76        return NULL;
77    }
78
79    return cv;
80}
81
82/** \brief Resize a canvas.
83 *
84 *  This function sets the canvas width and height, in character cells.
85 *
86 *  The contents of the canvas are preserved to the extent of the new
87 *  canvas size. Newly allocated character cells at the right and/or at
88 *  the bottom of the canvas are filled with spaces.
89 *
90 *  It is an error to try to resize the canvas if an output driver has
91 *  been attached to the canvas using caca_create_display(). You need to
92 *  remove the output driver using caca_free_display() before you can change
93 *  the  canvas size again. However, the caca output driver can cause a
94 *  canvas resize through user interaction. See the caca_event() documentation
95 *  for more about this.
96 *
97 *  \param cv A libcucul canvas
98 *  \param width The desired canvas width
99 *  \param height The desired canvas height
100 */
101void cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
102                                               unsigned int height)
103{
104    if(cv->refcount)
105        return;
106
107    _cucul_set_canvas_size(cv, width, height);
108}
109
110/** \brief Get the canvas width.
111 *
112 *  This function returns the current canvas width, in character cells.
113 *
114 *  \param cv A libcucul canvas
115 *  \return The canvas width.
116 */
117unsigned int cucul_get_canvas_width(cucul_canvas_t *cv)
118{
119    return cv->width;
120}
121
122/** \brief Get the canvas height.
123 *
124 *  This function returns the current canvas height, in character cells.
125 *
126 *  \param cv A libcucul canvas
127 *  \return The canvas height.
128 */
129unsigned int cucul_get_canvas_height(cucul_canvas_t *cv)
130{
131    return cv->height;
132}
133
134/** \brief Translate a colour index into the colour's name.
135 *
136 *  This function translates a cucul_color enum into a human-readable
137 *  description string of the associated colour.
138 *
139 *  \param color The colour value.
140 *  \return A static string containing the colour's name.
141 */
142char const *cucul_get_color_name(unsigned int color)
143{
144    static char const *color_names[] =
145    {
146        "black",
147        "blue",
148        "green",
149        "cyan",
150        "red",
151        "magenta",
152        "brown",
153        "light gray",
154        "dark gray",
155        "light blue",
156        "light green",
157        "light cyan",
158        "light red",
159        "light magenta",
160        "yellow",
161        "white",
162    };
163
164    if(color < 0 || color > 15)
165        return "unknown";
166
167    return color_names[color];
168}
169
170/** \brief Uninitialise \e libcucul.
171 *
172 *  This function frees all resources allocated by cucul_create_canvas(). After
173 *  cucul_free_canvas() has been called, no other \e libcucul functions may be
174 *  used unless a new call to cucul_create_canvas() is done.
175 *
176 *  \param cv A libcucul canvas
177 */
178void cucul_free_canvas(cucul_canvas_t *cv)
179{
180    unsigned int f;
181
182    _cucul_end_dither();
183
184    for(f = 0; f < cv->framecount; f++)
185    {
186        free(cv->allchars[f]);
187        free(cv->allattr[f]);
188    }
189
190    free(cv);
191}
192
193/** \brief Generate a random integer within a range.
194 *
195 *  \param min The lower bound of the integer range.
196 *  \param max The upper bound of the integer range.
197 *  \return A random integer comprised between \p min  and \p max - 1
198 *  (inclusive).
199 */
200int cucul_rand(int min, int max)
201{
202    return min + (int)((1.0 * (max - min)) * rand() / (RAND_MAX + 1.0));
203}
204
205/*
206 * XXX: The following functions are local.
207 */
208
209void _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
210                                                unsigned int height)
211{
212    unsigned int x, y, f, old_width, old_height, new_size, old_size;
213
214    old_width = cv->width;
215    old_height = cv->height;
216    old_size = old_width * old_height;
217
218    cv->width = width;
219    cv->height = height;
220    new_size = width * height;
221
222    /* Step 1: if new area is bigger, resize the memory area now. */
223    if(new_size > old_size)
224    {
225        for(f = 0; f < cv->framecount; f++)
226        {
227            cv->allchars[f] = realloc(cv->allchars[f],
228                                      new_size * sizeof(uint32_t));
229            cv->allattr[f] = realloc(cv->allattr[f],
230                                     new_size * sizeof(uint32_t));
231        }
232    }
233
234    /* Step 2: move line data if necessary. */
235    if(width == old_width)
236    {
237        /* Width did not change, which means we do not need to move data. */
238        ;
239    }
240    else if(width > old_width)
241    {
242        /* New width is bigger than old width, which means we need to
243         * copy lines starting from the bottom of the screen otherwise
244         * we will overwrite information. */
245        for(f = 0; f < cv->framecount; f++)
246        {
247            uint32_t *chars = cv->allchars[f];
248            uint32_t *attr = cv->allattr[f];
249
250            for(y = height < old_height ? height : old_height; y--; )
251            {
252                for(x = old_width; x--; )
253                {
254                    chars[y * width + x] = chars[y * old_width + x];
255                    attr[y * width + x] = attr[y * old_width + x];
256                }
257
258                /* Zero the end of the line */
259                for(x = width - old_width; x--; )
260                    chars[y * width + old_width + x] = (uint32_t)' ';
261                memset(attr + y * width + old_width, 0,
262                       (width - old_width) * 4);
263            }
264        }
265    }
266    else
267    {
268        /* New width is smaller. Copy as many lines as possible. Ignore
269         * the first line, it is already in place. */
270        unsigned int lines = height < old_height ? height : old_height;
271
272        for(f = 0; f < cv->framecount; f++)
273        {
274            uint32_t *chars = cv->allchars[f];
275            uint32_t *attr = cv->allattr[f];
276
277            for(y = 1; y < lines; y++)
278            {
279                for(x = 0; x < width; x++)
280                {
281                    chars[y * width + x] = chars[y * old_width + x];
282                    attr[y * width + x] = attr[y * old_width + x];
283                }
284            }
285        }
286    }
287
288    /* Step 3: fill the bottom of the new screen if necessary. */
289    if(height > old_height)
290    {
291        for(f = 0; f < cv->framecount; f++)
292        {
293            uint32_t *chars = cv->allchars[f];
294            uint32_t *attr = cv->allattr[f];
295
296            /* Zero the bottom of the screen */
297            for(x = (height - old_height) * width; x--; )
298                chars[old_height * width + x] = (uint32_t)' ';
299            memset(attr + old_height * width, 0,
300                   (height - old_height) * width * 4);
301        }
302    }
303
304    /* Step 4: if new area is smaller, resize memory area now. */
305    if(new_size <= old_size)
306    {
307        for(f = 0; f < cv->framecount; f++)
308        {
309            cv->allchars[f] = realloc(cv->allchars[f],
310                                      new_size * sizeof(uint32_t));
311            cv->allattr[f] = realloc(cv->allattr[f],
312                                     new_size * sizeof(uint32_t));
313        }
314    }
315
316    /* Reset the current frame shortcut */
317    cv->chars = cv->allchars[cv->frame];
318    cv->attr = cv->allattr[cv->frame];
319}
320
Note: See TracBrowser for help on using the repository browser.