source: libcaca/trunk/cucul/sprite.c @ 773

Last change on this file since 773 was 773, checked in by Sam Hocevar, 15 years ago
  • Improved documentation in many places.
  • Property svn:keywords set to Id
File size: 6.9 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: sprite.c 773 2006-04-14 12:10:18Z 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 a small framework for sprite loading and blitting.
16 */
17
18#include "config.h"
19
20#if !defined(__KERNEL__)
21#   include <stdio.h>
22#   include <stdlib.h>
23#   include <string.h>
24#endif
25
26#include "cucul.h"
27#include "cucul_internals.h"
28
29#if !defined(_DOXYGEN_SKIP_ME)
30struct cucul_frame
31{
32    int w, h;
33    int dx, dy;
34    char *chars;
35    int *color;
36};
37
38struct cucul_sprite
39{
40    int nf;
41    struct cucul_frame *frames;
42};
43#endif
44
45/** \brief Allocate a sprite loaded from a file.
46 *
47 *  \param file The filename.
48 *  \return The sprite, or NULL if an error occured.
49 */
50struct cucul_sprite *cucul_load_sprite(char const *file)
51{
52    char buf[BUFSIZ];
53    struct cucul_sprite *sprite;
54    FILE *fd;
55
56    fd = fopen(file, "r");
57    if(fd == NULL)
58        return NULL;
59
60    sprite = malloc(sizeof(struct cucul_sprite));
61    if(sprite == NULL)
62        goto sprite_alloc_failed;
63
64    sprite->nf = 0;
65    sprite->frames = NULL;
66
67    while(!feof(fd))
68    {
69        int x, y;
70        int w = 0, h = 0, dx = 0, dy = 0;
71        struct cucul_frame *frame;
72
73        /* Get width and height */
74        if(!fgets(buf, BUFSIZ, fd))
75            break;
76
77        sscanf(buf, "%i %i %i %i", &w, &h, &dx, &dy);
78        if(w <= 0 || h <= 0 || w > BUFSIZ / 2)
79            break;
80
81        if(sprite->nf)
82        {
83            void *tmp = realloc(sprite->frames,
84                                (sprite->nf + 1) * sizeof(struct cucul_frame));
85            if(tmp == NULL)
86                goto frame_failed;
87            sprite->frames = tmp;
88            sprite->nf++;
89        }
90        else
91        {
92            sprite->frames = malloc((sprite->nf + 1) * sizeof(struct cucul_frame));
93            if(sprite->frames == NULL)
94                goto sprite_failed;
95            sprite->nf++;
96        }
97
98        frame = &sprite->frames[sprite->nf - 1];
99
100        frame->w = w;
101        frame->h = h;
102        frame->dx = dx;
103        frame->dy = dy;
104        frame->chars = malloc(w * h * sizeof(char));
105        if(frame->chars == NULL)
106        {
107            sprite->nf--;
108            goto frame_failed;
109        }
110        frame->color = malloc(w * h * sizeof(int));
111        if(frame->color == NULL)
112        {
113            free(frame->chars);
114            sprite->nf--;
115            goto frame_failed;
116        }
117
118        for(y = 0; y < h; y++)
119        {
120            if(!fgets(buf, BUFSIZ, fd))
121                goto frame_failed;
122
123            for(x = 0; x < w && buf[x] && buf[x] != '\r' && buf[x] != '\n'; x++)
124                frame->chars[w * y + x] = buf[x];
125
126            for(; x < w; x++)
127                frame->chars[w * y + x] = ' ';
128        }
129
130        for(y = 0; y < h; y++)
131        {
132            if(!fgets(buf, BUFSIZ, fd))
133                goto frame_failed;
134
135            for(x = 0; x < w && buf[x] && buf[x] != '\r' && buf[x] != '\n'; x++)
136                frame->color[w * y + x] = buf[x] - 'a';
137
138            for(; x < w; x++)
139                frame->color[w * y + x] = ' ' - 'a';
140        }
141
142        continue;
143    }
144
145    if(sprite->nf == 0)
146        goto sprite_failed;
147
148    fclose(fd);
149    return sprite;
150
151frame_failed:
152    while(sprite->nf)
153    {
154        free(sprite->frames[sprite->nf - 1].color);
155        free(sprite->frames[sprite->nf - 1].chars);
156        sprite->nf--;
157    }
158sprite_failed:
159    free(sprite);
160sprite_alloc_failed:
161    fclose(fd);
162    return NULL;
163}
164
165/** \brief Return the number of frames in a sprite.
166 *
167 *  \param sprite The sprite.
168 *  \return The number of frames.
169 */
170int cucul_get_sprite_frames(struct cucul_sprite const *sprite)
171{
172    if(sprite == NULL)
173        return 0;
174
175    return sprite->nf;
176}
177
178/** \brief Return the width of a sprite.
179 *
180 *  \param sprite The sprite.
181 *  \param f The frame index.
182 *  \return The width of the given frame of the sprite.
183 */
184int cucul_get_sprite_width(struct cucul_sprite const *sprite, int f)
185{
186    if(sprite == NULL)
187        return 0;
188
189    if(f < 0 || f >= sprite->nf)
190        return 0;
191
192    return sprite->frames[f].w;
193}
194
195/** \brief Return the height of a sprite.
196 *
197 *  \param sprite The sprite.
198 *  \param f The frame index.
199 *  \return The height of the given frame of the sprite.
200 */
201int cucul_get_sprite_height(struct cucul_sprite const *sprite, int f)
202{
203    if(sprite == NULL)
204        return 0;
205
206    if(f < 0 || f >= sprite->nf)
207        return 0;
208
209    return sprite->frames[f].h;
210}
211
212/** \brief Return the X coordinate of a sprite's handle.
213 *
214 *  \param sprite The sprite.
215 *  \param f The frame index.
216 *  \return The X coordinate of the given frame's handle.
217 */
218int cucul_get_sprite_dx(struct cucul_sprite const *sprite, int f)
219{
220    if(sprite == NULL)
221        return 0;
222
223    if(f < 0 || f >= sprite->nf)
224        return 0;
225
226    return sprite->frames[f].dx;
227}
228
229/** \brief Return the Y coordinate of a sprite's handle.
230 *
231 *  \param sprite The sprite.
232 *  \param f The frame index.
233 *  \return The Y coordinate of the given frame's handle.
234 */
235int cucul_get_sprite_dy(struct cucul_sprite const *sprite, int f)
236{
237    if(sprite == NULL)
238        return 0;
239
240    if(f < 0 || f >= sprite->nf)
241        return 0;
242
243    return sprite->frames[f].dy;
244}
245
246/** \brief Draw a sprite's specific frame at the given coordinates. If the
247 *         frame does not exist, nothing is displayed.
248 *
249 *  \param qq A libcucul canvas
250 *  \param x The X coordinate.
251 *  \param y The Y coordinate.
252 *  \param sprite The sprite.
253 *  \param f The frame index.
254 *  \return void
255 */
256void cucul_draw_sprite(cucul_t *qq, int x, int y, struct cucul_sprite const *sprite, int f)
257{
258    int i, j;
259    unsigned int oldfg, oldbg;
260    struct cucul_frame *frame;
261
262    if(sprite == NULL)
263        return;
264
265    if(f < 0 || f >= sprite->nf)
266        return;
267
268    frame = &sprite->frames[f];
269
270    oldfg = qq->fgcolor;
271    oldbg = qq->bgcolor;
272
273    for(j = 0; j < frame->h; j++)
274    {
275        for(i = 0; i < frame->w; i++)
276        {
277            int col = frame->color[frame->w * j + i];
278            if(col >= 0)
279            {
280                cucul_set_color(qq, col, CUCUL_COLOR_BLACK);
281                cucul_putchar(qq, x + i - frame->dx, y + j - frame->dy,
282                              frame->chars[frame->w * j + i]);
283            }
284        }
285    }
286
287    cucul_set_color(qq, oldfg, oldbg);
288}
289
290/** \brief Free the memory associated with a sprite.
291 *
292 *  \param sprite The sprite to be freed.
293 *  \return void
294 */
295void cucul_free_sprite(struct cucul_sprite *sprite)
296{
297    int i;
298
299    if(sprite == NULL)
300        return;
301
302    for(i = sprite->nf; i--;)
303    {
304        struct cucul_frame *frame = &sprite->frames[i];
305        free(frame->chars);
306        free(frame->color);
307    }
308
309    free(sprite->frames);
310    free(sprite);
311}
312
Note: See TracBrowser for help on using the repository browser.