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

Last change on this file since 833 was 833, checked in by Sam Hocevar, 16 years ago
  • Got rid of cv->empty_line, it's now unused.
  • Property svn:keywords set to Id
File size: 8.0 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 833 2006-04-21 20:51:14Z 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
57    /* Initialise to a default size. 80x32 is arbitrary but matches AAlib's
58     * default X11 window. When a graphic driver attaches to us, it can set
59     * a different size. */
60    if(width && height)
61        _cucul_set_canvas_size(cv, width, height);
62    else
63        _cucul_set_canvas_size(cv, 80, 32);
64
65    if(_cucul_init_dither())
66    {
67        free(cv);
68        return NULL;
69    }
70
71    return cv;
72}
73
74/** \brief Resize a canvas.
75 *
76 *  This function sets the canvas width and height, in character cells.
77 *
78 *  The contents of the canvas are preserved to the extent of the new
79 *  canvas size. Newly allocated character cells at the right and/or at
80 *  the bottom of the canvas are filled with spaces.
81 *
82 *  It is an error to try to resize the canvas if an output driver has
83 *  been attached to the canvas using caca_create_display(). You need to
84 *  remove the output driver using caca_free_display() before you can change
85 *  the  canvas size again. However, the caca output driver can cause a
86 *  canvas resize through user interaction. See the caca_event() documentation
87 *  for more about this.
88 *
89 *  \param cv A libcucul canvas
90 *  \param width The desired canvas width
91 *  \param height The desired canvas height
92 */
93void cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
94                                               unsigned int height)
95{
96    if(cv->refcount)
97        return;
98
99    _cucul_set_canvas_size(cv, width, height);
100}
101
102/** \brief Get the canvas width.
103 *
104 *  This function returns the current canvas width, in character cells.
105 *
106 *  \param cv A libcucul canvas
107 *  \return The canvas width.
108 */
109unsigned int cucul_get_canvas_width(cucul_canvas_t *cv)
110{
111    return cv->width;
112}
113
114/** \brief Get the canvas height.
115 *
116 *  This function returns the current canvas height, in character cells.
117 *
118 *  \param cv A libcucul canvas
119 *  \return The canvas height.
120 */
121unsigned int cucul_get_canvas_height(cucul_canvas_t *cv)
122{
123    return cv->height;
124}
125
126/** \brief Translate a colour index into the colour's name.
127 *
128 *  This function translates a cucul_color enum into a human-readable
129 *  description string of the associated colour.
130 *
131 *  \param color The colour value.
132 *  \return A static string containing the colour's name.
133 */
134char const *cucul_get_color_name(unsigned int color)
135{
136    static char const *color_names[] =
137    {
138        "black",
139        "blue",
140        "green",
141        "cyan",
142        "red",
143        "magenta",
144        "brown",
145        "light gray",
146        "dark gray",
147        "light blue",
148        "light green",
149        "light cyan",
150        "light red",
151        "light magenta",
152        "yellow",
153        "white",
154    };
155
156    if(color < 0 || color > 15)
157        return "unknown";
158
159    return color_names[color];
160}
161
162/** \brief Uninitialise \e libcucul.
163 *
164 *  This function frees all resources allocated by cucul_create_canvas(). After
165 *  cucul_free_canvas() has been called, no other \e libcucul functions may be
166 *  used unless a new call to cucul_create_canvas() is done.
167 *
168 *  \param cv A libcucul canvas
169 */
170void cucul_free_canvas(cucul_canvas_t *cv)
171{
172    _cucul_end_dither();
173
174    free(cv->scratch_line);
175
176    free(cv->chars);
177    free(cv->attr);
178
179    free(cv);
180}
181
182/** \brief Generate a random integer within a range.
183 *
184 *  \param min The lower bound of the integer range.
185 *  \param max The upper bound of the integer range.
186 *  \return A random integer comprised between \p min  and \p max - 1
187 *  (inclusive).
188 */
189int cucul_rand(int min, int max)
190{
191    return min + (int)((1.0 * (max - min)) * rand() / (RAND_MAX + 1.0));
192}
193
194/*
195 * XXX: The following functions are local.
196 */
197
198void _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
199                                                unsigned int height)
200{
201    unsigned int x, y, old_width, old_height, new_size, old_size;
202
203    old_width = cv->width;
204    old_height = cv->height;
205    old_size = old_width * old_height;
206
207    cv->width = width;
208    cv->height = height;
209    new_size = width * height;
210
211    /* Step 1: if new area is bigger, resize the memory area now. */
212    if(new_size > old_size)
213    {
214        cv->chars = realloc(cv->chars, new_size * sizeof(uint32_t));
215        cv->attr = realloc(cv->attr, new_size * sizeof(uint32_t));
216    }
217
218    /* Step 2: move line data if necessary. */
219    if(width == old_width)
220    {
221        /* Width did not change, which means we do not need to move data. */
222        ;
223    }
224    else if(width > old_width)
225    {
226        /* New width is bigger than old width, which means we need to
227         * copy lines starting from the bottom of the screen otherwise
228         * we will overwrite information. */
229        for(y = height < old_height ? height : old_height; y--; )
230        {
231            for(x = old_width; x--; )
232            {
233                cv->chars[y * width + x] = cv->chars[y * old_width + x];
234                cv->attr[y * width + x] = cv->attr[y * old_width + x];
235            }
236
237            /* Zero the end of the line */
238            for(x = width - old_width; x--; )
239                cv->chars[y * width + old_width + x] = (uint32_t)' ';
240            memset(cv->attr + y * width + old_width, 0,
241                   (width - old_width) * 4);
242        }
243    }
244    else
245    {
246        /* New width is smaller. Copy as many lines as possible. Ignore
247         * the first line, it is already in place. */
248        unsigned int lines = height < old_height ? height : old_height;
249
250        for(y = 1; y < lines; y++)
251        {
252            for(x = 0; x < width; x++)
253            {
254                cv->chars[y * width + x] = cv->chars[y * old_width + x];
255                cv->attr[y * width + x] = cv->attr[y * old_width + x];
256            }
257        }
258    }
259
260    /* Step 3: fill the bottom of the new screen if necessary. */
261    if(height > old_height)
262    {
263        /* Zero the bottom of the screen */
264        for(x = (height - old_height) * width; x--; )
265            cv->chars[old_height * width + x] = (uint32_t)' ';
266        memset(cv->attr + old_height * width, 0,
267               (height - old_height) * width * 4);
268    }
269
270    /* Step 4: if new area is smaller, resize memory area now. */
271    if(new_size <= old_size)
272    {
273        cv->chars = realloc(cv->chars, new_size * sizeof(uint32_t));
274        cv->attr = realloc(cv->attr, new_size * sizeof(uint32_t));
275    }
276
277    /* Recompute the scratch line and the empty line */
278    if(width != old_width)
279        cv->scratch_line = realloc(cv->scratch_line, width + 1);
280}
281
Note: See TracBrowser for help on using the repository browser.