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

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