source: libcaca/trunk/caca/frame.c @ 4148

Last change on this file since 4148 was 3583, checked in by Sam Hocevar, 11 years ago

Allow to temporarily disable dirty rectangle handling. This allows for huge
speedups when the calling application knows the dirty rectangle covered by
a complex operation.

  • Property svn:keywords set to Id
File size: 7.8 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2009 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  $Id: frame.c 3583 2009-07-26 19:17:35Z sam $
7 *
8 *  This library is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  This file contains a small framework for canvas frame management.
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 "caca.h"
28#include "caca_internals.h"
29
30/** \brief Get the number of frames in a canvas.
31 *
32 *  Return the current canvas' frame count.
33 *
34 *  This function never fails.
35 *
36 *  \param cv A libcaca canvas
37 *  \return The frame count
38 */
39int caca_get_frame_count(caca_canvas_t const *cv)
40{
41    return cv->framecount;
42}
43
44/** \brief Activate a given canvas frame.
45 *
46 *  Set the active canvas frame. All subsequent drawing operations will
47 *  be performed on that frame. The current painting context set by
48 *  caca_set_attr() is inherited.
49 *
50 *  If the frame index is outside the canvas' frame range, nothing happens.
51 *
52 *  If an error occurs, -1 is returned and \b errno is set accordingly:
53 *  - \c EINVAL Requested frame is out of range.
54 *
55 *  \param cv A libcaca canvas
56 *  \param id The canvas frame to activate
57 *  \return 0 in case of success, -1 if an error occurred.
58 */
59int caca_set_frame(caca_canvas_t *cv, int id)
60{
61    if(id < 0 || id >= cv->framecount)
62    {
63        seterrno(EINVAL);
64        return -1;
65    }
66
67    /* Bail out if no operation is required */
68    if(id == cv->frame)
69        return 0;
70
71    _caca_save_frame_info(cv);
72    cv->frame = id;
73    _caca_load_frame_info(cv);
74
75    if(!cv->dirty_disabled)
76        caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
77
78    return 0;
79}
80
81/** \brief Get the current frame's name.
82 *
83 *  Return the current frame's name. The returned string is valid until
84 *  the frame is deleted or caca_set_frame_name() is called to change
85 *  the frame name again.
86 *
87 *  This function never fails.
88 *
89 *  \param cv A libcaca canvas.
90 *  \return The current frame's name.
91 */
92char const *caca_get_frame_name(caca_canvas_t const *cv)
93{
94    return cv->frames[cv->frame].name;
95}
96
97/** \brief Set the current frame's name.
98 *
99 *  Set the current frame's name. Upon creation, a frame has a default name
100 *  of \c "frame#xxxxxxxx" where \c xxxxxxxx is a self-incrementing
101 *  hexadecimal number.
102 *
103 *  If an error occurs, -1 is returned and \b errno is set accordingly:
104 *  - \c ENOMEM Not enough memory to allocate new frame.
105 *
106 *  \param cv A libcaca canvas.
107 *  \param name The name to give to the current frame.
108 *  \return 0 in case of success, -1 if an error occurred.
109 */
110int caca_set_frame_name(caca_canvas_t *cv, char const *name)
111{
112    char *newname = strdup(name);
113
114    if(!newname)
115    {
116        seterrno(ENOMEM);
117        return -1;
118    }
119
120    free(cv->frames[cv->frame].name);
121    cv->frames[cv->frame].name = newname;
122
123    return 0;
124}
125
126/** \brief Add a frame to a canvas.
127 *
128 *  Create a new frame within the given canvas. Its contents and attributes
129 *  are copied from the currently active frame.
130 *
131 *  The frame index indicates where the frame should be inserted. Valid
132 *  values range from 0 to the current canvas frame count. If the frame
133 *  index is greater than or equals the current canvas frame count, the new
134 *  frame is appended at the end of the canvas. If the frame index is less
135 *  than zero, the new frame is inserted at index 0.
136 *
137 *  The active frame does not change, but its index may be renumbered due
138 *  to the insertion.
139 *
140 *  If an error occurs, -1 is returned and \b errno is set accordingly:
141 *  - \c ENOMEM Not enough memory to allocate new frame.
142 *
143 *  \param cv A libcaca canvas
144 *  \param id The index where to insert the new frame
145 *  \return 0 in case of success, -1 if an error occurred.
146 */
147int caca_create_frame(caca_canvas_t *cv, int id)
148{
149    int size = cv->width * cv->height;
150    int f;
151
152    if(id < 0)
153        id = 0;
154    else if(id > cv->framecount)
155        id = cv->framecount;
156
157    cv->framecount++;
158    cv->frames = realloc(cv->frames,
159                         sizeof(struct caca_frame) * cv->framecount);
160
161    for(f = cv->framecount - 1; f > id; f--)
162        cv->frames[f] = cv->frames[f - 1];
163
164    if(cv->frame >= id)
165        cv->frame++;
166
167    cv->frames[id].width = cv->width;
168    cv->frames[id].height = cv->height;
169    cv->frames[id].chars = malloc(size * sizeof(uint32_t));
170    memcpy(cv->frames[id].chars, cv->chars, size * sizeof(uint32_t));
171    cv->frames[id].attrs = malloc(size * sizeof(uint32_t));
172    memcpy(cv->frames[id].attrs, cv->attrs, size * sizeof(uint32_t));
173    cv->frames[id].curattr = cv->curattr;
174
175    cv->frames[id].x = cv->frames[cv->frame].x;
176    cv->frames[id].y = cv->frames[cv->frame].y;
177    cv->frames[id].handlex = cv->frames[cv->frame].handlex;
178    cv->frames[id].handley = cv->frames[cv->frame].handley;
179
180    cv->frames[id].name = strdup("frame#--------");
181    sprintf(cv->frames[id].name + 6, "%.08x", ++cv->autoinc);
182
183    return 0;
184}
185
186/** \brief Remove a frame from a canvas.
187 *
188 *  Delete a frame from a given canvas.
189 *
190 *  The frame index indicates the frame to delete. Valid values range from
191 *  0 to the current canvas frame count minus 1. If the frame index is
192 *  greater than or equals the current canvas frame count, the last frame
193 *  is deleted.
194 *
195 *  If the active frame is deleted, frame 0 becomes the new active frame.
196 *  Otherwise, the active frame does not change, but its index may be
197 *  renumbered due to the deletion.
198 *
199 *  If an error occurs, -1 is returned and \b errno is set accordingly:
200 *  - \c EINVAL Requested frame is out of range, or attempt to delete the
201 *    last frame of the canvas.
202 *
203 *  \param cv A libcaca canvas
204 *  \param id The index of the frame to delete
205 *  \return 0 in case of success, -1 if an error occurred.
206 */
207int caca_free_frame(caca_canvas_t *cv, int id)
208{
209    int f;
210
211    if(id < 0 || id >= cv->framecount)
212    {
213        seterrno(EINVAL);
214        return -1;
215    }
216
217    if(cv->framecount == 1)
218    {
219        seterrno(EINVAL);
220        return -1;
221    }
222
223    free(cv->frames[id].chars);
224    free(cv->frames[id].attrs);
225    free(cv->frames[id].name);
226
227    for(f = id + 1; f < cv->framecount; f++)
228        cv->frames[f - 1] = cv->frames[f];
229
230    cv->framecount--;
231    cv->frames = realloc(cv->frames,
232                         sizeof(struct caca_frame) * cv->framecount);
233
234    if(cv->frame > id)
235        cv->frame--;
236    else if(cv->frame == id)
237    {
238        cv->frame = 0;
239        _caca_load_frame_info(cv);
240        if(!cv->dirty_disabled)
241            caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height);
242    }
243
244    return 0;
245}
246
247/*
248 * XXX: the following functions are local.
249 */
250
251void _caca_save_frame_info(caca_canvas_t *cv)
252{
253    cv->frames[cv->frame].width = cv->width;
254    cv->frames[cv->frame].height = cv->height;
255
256    cv->frames[cv->frame].curattr = cv->curattr;
257}
258
259void _caca_load_frame_info(caca_canvas_t *cv)
260{
261    cv->width = cv->frames[cv->frame].width;
262    cv->height = cv->frames[cv->frame].height;
263
264    cv->chars = cv->frames[cv->frame].chars;
265    cv->attrs = cv->frames[cv->frame].attrs;
266
267    cv->curattr = cv->frames[cv->frame].curattr;
268}
269
270/*
271 * XXX: The following functions are aliases.
272 */
273
274int cucul_get_frame_count(cucul_canvas_t const *)
275         CACA_ALIAS(caca_get_frame_count);
276int cucul_set_frame(cucul_canvas_t *, int) CACA_ALIAS(caca_set_frame);
277char const *cucul_get_frame_name(cucul_canvas_t const *)
278         CACA_ALIAS(caca_get_frame_name);
279int cucul_set_frame_name(cucul_canvas_t *, char const *)
280         CACA_ALIAS(caca_set_frame_name);
281int cucul_create_frame(cucul_canvas_t *, int) CACA_ALIAS(caca_create_frame);
282int cucul_free_frame(cucul_canvas_t *, int) CACA_ALIAS(caca_free_frame);
283
Note: See TracBrowser for help on using the repository browser.