You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

322 lines
7.1 KiB

  1. /*
  2. * libcucul Unicode canvas library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the Do What The Fuck You Want To
  8. * Public License, Version 2, as published by Sam Hocevar. See
  9. * http://sam.zoy.org/wtfpl/COPYING for more details.
  10. */
  11. /** \file sprite.c
  12. * \version \$Id$
  13. * \author Sam Hocevar <sam@zoy.org>
  14. * \brief Sprite loading and blitting
  15. *
  16. * This file contains a small framework for sprite loading and blitting.
  17. */
  18. #include "config.h"
  19. #if !defined(__KERNEL__)
  20. # include <stdio.h>
  21. # include <stdlib.h>
  22. # include <string.h>
  23. #endif
  24. #include "cucul.h"
  25. #include "cucul_internals.h"
  26. #if !defined(_DOXYGEN_SKIP_ME)
  27. struct cucul_frame
  28. {
  29. int w, h;
  30. int dx, dy;
  31. char *chars;
  32. int *color;
  33. };
  34. struct cucul_sprite
  35. {
  36. int nf;
  37. struct cucul_frame *frames;
  38. };
  39. #endif
  40. /**
  41. * \brief Allocate a sprite loaded from a file.
  42. *
  43. * \param file The filename.
  44. * \return The sprite, or NULL if an error occured.
  45. */
  46. struct cucul_sprite *cucul_load_sprite(cucul_t *qq, char const *file)
  47. {
  48. char buf[BUFSIZ];
  49. struct cucul_sprite *sprite;
  50. FILE *fd;
  51. fd = fopen(file, "r");
  52. if(fd == NULL)
  53. return NULL;
  54. sprite = malloc(sizeof(struct cucul_sprite));
  55. if(sprite == NULL)
  56. goto sprite_alloc_failed;
  57. sprite->nf = 0;
  58. sprite->frames = NULL;
  59. while(!feof(fd))
  60. {
  61. int x, y;
  62. int w = 0, h = 0, dx = 0, dy = 0;
  63. struct cucul_frame *frame;
  64. /* Get width and height */
  65. if(!fgets(buf, BUFSIZ, fd))
  66. break;
  67. sscanf(buf, "%i %i %i %i", &w, &h, &dx, &dy);
  68. if(w <= 0 || h <= 0 || w > BUFSIZ / 2)
  69. break;
  70. if(sprite->nf)
  71. {
  72. void *tmp = realloc(sprite->frames,
  73. (sprite->nf + 1) * sizeof(struct cucul_frame));
  74. if(tmp == NULL)
  75. goto frame_failed;
  76. sprite->frames = tmp;
  77. sprite->nf++;
  78. }
  79. else
  80. {
  81. sprite->frames = malloc((sprite->nf + 1) * sizeof(struct cucul_frame));
  82. if(sprite->frames == NULL)
  83. goto sprite_failed;
  84. sprite->nf++;
  85. }
  86. frame = &sprite->frames[sprite->nf - 1];
  87. frame->w = w;
  88. frame->h = h;
  89. frame->dx = dx;
  90. frame->dy = dy;
  91. frame->chars = malloc(w * h * sizeof(char));
  92. if(frame->chars == NULL)
  93. {
  94. sprite->nf--;
  95. goto frame_failed;
  96. }
  97. frame->color = malloc(w * h * sizeof(int));
  98. if(frame->color == NULL)
  99. {
  100. free(frame->chars);
  101. sprite->nf--;
  102. goto frame_failed;
  103. }
  104. for(y = 0; y < h; y++)
  105. {
  106. if(!fgets(buf, BUFSIZ, fd))
  107. goto frame_failed;
  108. for(x = 0; x < w && buf[x] && buf[x] != '\r' && buf[x] != '\n'; x++)
  109. frame->chars[w * y + x] = buf[x];
  110. for(; x < w; x++)
  111. frame->chars[w * y + x] = ' ';
  112. }
  113. for(y = 0; y < h; y++)
  114. {
  115. if(!fgets(buf, BUFSIZ, fd))
  116. goto frame_failed;
  117. for(x = 0; x < w && buf[x] && buf[x] != '\r' && buf[x] != '\n'; x++)
  118. frame->color[w * y + x] = buf[x] - 'a';
  119. for(; x < w; x++)
  120. frame->color[w * y + x] = ' ' - 'a';
  121. }
  122. continue;
  123. }
  124. if(sprite->nf == 0)
  125. goto sprite_failed;
  126. fclose(fd);
  127. return sprite;
  128. frame_failed:
  129. while(sprite->nf)
  130. {
  131. free(sprite->frames[sprite->nf - 1].color);
  132. free(sprite->frames[sprite->nf - 1].chars);
  133. sprite->nf--;
  134. }
  135. sprite_failed:
  136. free(sprite);
  137. sprite_alloc_failed:
  138. fclose(fd);
  139. return NULL;
  140. }
  141. /**
  142. * \brief Return the number of frames in a sprite.
  143. *
  144. * \param sprite The sprite.
  145. * \return The number of frames.
  146. */
  147. int cucul_get_sprite_frames(cucul_t *qq, struct cucul_sprite const *sprite)
  148. {
  149. if(sprite == NULL)
  150. return 0;
  151. return sprite->nf;
  152. }
  153. /**
  154. * \brief Return the width of a sprite.
  155. *
  156. * \param sprite The sprite.
  157. * \param f The frame index.
  158. * \return The width of the given frame of the sprite.
  159. */
  160. int cucul_get_sprite_width(cucul_t *qq, struct cucul_sprite const *sprite, int f)
  161. {
  162. if(sprite == NULL)
  163. return 0;
  164. if(f < 0 || f >= sprite->nf)
  165. return 0;
  166. return sprite->frames[f].w;
  167. }
  168. /**
  169. * \brief Return the height of a sprite.
  170. *
  171. * \param sprite The sprite.
  172. * \param f The frame index.
  173. * \return The height of the given frame of the sprite.
  174. */
  175. int cucul_get_sprite_height(cucul_t *qq, struct cucul_sprite const *sprite, int f)
  176. {
  177. if(sprite == NULL)
  178. return 0;
  179. if(f < 0 || f >= sprite->nf)
  180. return 0;
  181. return sprite->frames[f].h;
  182. }
  183. /**
  184. * \brief Return the X coordinate of a sprite's handle.
  185. *
  186. * \param sprite The sprite.
  187. * \param f The frame index.
  188. * \return The X coordinate of the given frame's handle.
  189. */
  190. int cucul_get_sprite_dx(cucul_t *qq, struct cucul_sprite const *sprite, int f)
  191. {
  192. if(sprite == NULL)
  193. return 0;
  194. if(f < 0 || f >= sprite->nf)
  195. return 0;
  196. return sprite->frames[f].dx;
  197. }
  198. /**
  199. * \brief Return the Y coordinate of a sprite's handle.
  200. *
  201. * \param sprite The sprite.
  202. * \param f The frame index.
  203. * \return The Y coordinate of the given frame's handle.
  204. */
  205. int cucul_get_sprite_dy(cucul_t *qq, struct cucul_sprite const *sprite, int f)
  206. {
  207. if(sprite == NULL)
  208. return 0;
  209. if(f < 0 || f >= sprite->nf)
  210. return 0;
  211. return sprite->frames[f].dy;
  212. }
  213. /**
  214. * \brief Draw a sprite's specific frame at the given coordinates. If the
  215. * frame does not exist, nothing is displayed.
  216. *
  217. * \param x The X coordinate.
  218. * \param y The Y coordinate.
  219. * \param sprite The sprite.
  220. * \param f The frame index.
  221. * \return void
  222. */
  223. void cucul_draw_sprite(cucul_t *qq, int x, int y, struct cucul_sprite const *sprite, int f)
  224. {
  225. int i, j;
  226. enum cucul_color oldfg, oldbg;
  227. struct cucul_frame *frame;
  228. if(sprite == NULL)
  229. return;
  230. if(f < 0 || f >= sprite->nf)
  231. return;
  232. frame = &sprite->frames[f];
  233. oldfg = cucul_get_fg_color(qq);
  234. oldbg = cucul_get_bg_color(qq);
  235. for(j = 0; j < frame->h; j++)
  236. {
  237. for(i = 0; i < frame->w; i++)
  238. {
  239. int col = frame->color[frame->w * j + i];
  240. if(col >= 0)
  241. {
  242. cucul_set_color(qq, col, CUCUL_COLOR_BLACK);
  243. cucul_putchar(qq, x + i - frame->dx, y + j - frame->dy,
  244. frame->chars[frame->w * j + i]);
  245. }
  246. }
  247. }
  248. cucul_set_color(qq, oldfg, oldbg);
  249. }
  250. /**
  251. * \brief Free the memory associated with a sprite.
  252. *
  253. * \param sprite The sprite to be freed.
  254. * \return void
  255. */
  256. void cucul_free_sprite(cucul_t *qq, struct cucul_sprite *sprite)
  257. {
  258. int i;
  259. if(sprite == NULL)
  260. return;
  261. for(i = sprite->nf; i--;)
  262. {
  263. struct cucul_frame *frame = &sprite->frames[i];
  264. free(frame->chars);
  265. free(frame->color);
  266. }
  267. free(sprite->frames);
  268. free(sprite);
  269. }