/* * libcucul Unicode canvas library * Copyright (c) 2002-2006 Sam Hocevar * All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the Do What The Fuck You Want To * Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ /** \file sprite.c * \version \$Id$ * \author Sam Hocevar * \brief Sprite loading and blitting * * This file contains a small framework for sprite loading and blitting. */ #include "config.h" #if !defined(__KERNEL__) # include # include # include #endif #include "cucul.h" #include "cucul_internals.h" #if !defined(_DOXYGEN_SKIP_ME) struct cucul_frame { int w, h; int dx, dy; char *chars; int *color; }; struct cucul_sprite { int nf; struct cucul_frame *frames; }; #endif /** * \brief Allocate a sprite loaded from a file. * * \param file The filename. * \return The sprite, or NULL if an error occured. */ struct cucul_sprite *cucul_load_sprite(cucul_t *qq, char const *file) { char buf[BUFSIZ]; struct cucul_sprite *sprite; FILE *fd; fd = fopen(file, "r"); if(fd == NULL) return NULL; sprite = malloc(sizeof(struct cucul_sprite)); if(sprite == NULL) goto sprite_alloc_failed; sprite->nf = 0; sprite->frames = NULL; while(!feof(fd)) { int x, y; int w = 0, h = 0, dx = 0, dy = 0; struct cucul_frame *frame; /* Get width and height */ if(!fgets(buf, BUFSIZ, fd)) break; sscanf(buf, "%i %i %i %i", &w, &h, &dx, &dy); if(w <= 0 || h <= 0 || w > BUFSIZ / 2) break; if(sprite->nf) { void *tmp = realloc(sprite->frames, (sprite->nf + 1) * sizeof(struct cucul_frame)); if(tmp == NULL) goto frame_failed; sprite->frames = tmp; sprite->nf++; } else { sprite->frames = malloc((sprite->nf + 1) * sizeof(struct cucul_frame)); if(sprite->frames == NULL) goto sprite_failed; sprite->nf++; } frame = &sprite->frames[sprite->nf - 1]; frame->w = w; frame->h = h; frame->dx = dx; frame->dy = dy; frame->chars = malloc(w * h * sizeof(char)); if(frame->chars == NULL) { sprite->nf--; goto frame_failed; } frame->color = malloc(w * h * sizeof(int)); if(frame->color == NULL) { free(frame->chars); sprite->nf--; goto frame_failed; } for(y = 0; y < h; y++) { if(!fgets(buf, BUFSIZ, fd)) goto frame_failed; for(x = 0; x < w && buf[x] && buf[x] != '\r' && buf[x] != '\n'; x++) frame->chars[w * y + x] = buf[x]; for(; x < w; x++) frame->chars[w * y + x] = ' '; } for(y = 0; y < h; y++) { if(!fgets(buf, BUFSIZ, fd)) goto frame_failed; for(x = 0; x < w && buf[x] && buf[x] != '\r' && buf[x] != '\n'; x++) frame->color[w * y + x] = buf[x] - 'a'; for(; x < w; x++) frame->color[w * y + x] = ' ' - 'a'; } continue; } if(sprite->nf == 0) goto sprite_failed; fclose(fd); return sprite; frame_failed: while(sprite->nf) { free(sprite->frames[sprite->nf - 1].color); free(sprite->frames[sprite->nf - 1].chars); sprite->nf--; } sprite_failed: free(sprite); sprite_alloc_failed: fclose(fd); return NULL; } /** * \brief Return the number of frames in a sprite. * * \param sprite The sprite. * \return The number of frames. */ int cucul_get_sprite_frames(cucul_t *qq, struct cucul_sprite const *sprite) { if(sprite == NULL) return 0; return sprite->nf; } /** * \brief Return the width of a sprite. * * \param sprite The sprite. * \param f The frame index. * \return The width of the given frame of the sprite. */ int cucul_get_sprite_width(cucul_t *qq, struct cucul_sprite const *sprite, int f) { if(sprite == NULL) return 0; if(f < 0 || f >= sprite->nf) return 0; return sprite->frames[f].w; } /** * \brief Return the height of a sprite. * * \param sprite The sprite. * \param f The frame index. * \return The height of the given frame of the sprite. */ int cucul_get_sprite_height(cucul_t *qq, struct cucul_sprite const *sprite, int f) { if(sprite == NULL) return 0; if(f < 0 || f >= sprite->nf) return 0; return sprite->frames[f].h; } /** * \brief Return the X coordinate of a sprite's handle. * * \param sprite The sprite. * \param f The frame index. * \return The X coordinate of the given frame's handle. */ int cucul_get_sprite_dx(cucul_t *qq, struct cucul_sprite const *sprite, int f) { if(sprite == NULL) return 0; if(f < 0 || f >= sprite->nf) return 0; return sprite->frames[f].dx; } /** * \brief Return the Y coordinate of a sprite's handle. * * \param sprite The sprite. * \param f The frame index. * \return The Y coordinate of the given frame's handle. */ int cucul_get_sprite_dy(cucul_t *qq, struct cucul_sprite const *sprite, int f) { if(sprite == NULL) return 0; if(f < 0 || f >= sprite->nf) return 0; return sprite->frames[f].dy; } /** * \brief Draw a sprite's specific frame at the given coordinates. If the * frame does not exist, nothing is displayed. * * \param x The X coordinate. * \param y The Y coordinate. * \param sprite The sprite. * \param f The frame index. * \return void */ void cucul_draw_sprite(cucul_t *qq, int x, int y, struct cucul_sprite const *sprite, int f) { int i, j; enum cucul_color oldfg, oldbg; struct cucul_frame *frame; if(sprite == NULL) return; if(f < 0 || f >= sprite->nf) return; frame = &sprite->frames[f]; oldfg = cucul_get_fg_color(qq); oldbg = cucul_get_bg_color(qq); for(j = 0; j < frame->h; j++) { for(i = 0; i < frame->w; i++) { int col = frame->color[frame->w * j + i]; if(col >= 0) { cucul_set_color(qq, col, CUCUL_COLOR_BLACK); cucul_putchar(qq, x + i - frame->dx, y + j - frame->dy, frame->chars[frame->w * j + i]); } } } cucul_set_color(qq, oldfg, oldbg); } /** * \brief Free the memory associated with a sprite. * * \param sprite The sprite to be freed. * \return void */ void cucul_free_sprite(cucul_t *qq, struct cucul_sprite *sprite) { int i; if(sprite == NULL) return; for(i = sprite->nf; i--;) { struct cucul_frame *frame = &sprite->frames[i]; free(frame->chars); free(frame->color); } free(sprite->frames); free(sprite); }