/*--------------------------------------------------------------------------*/ /* sprite management */ /*--------------------------------------------------------------------------*/ #include #include #include #include #include #include #include "sprite.h" #include "canvas.h" #include "list.h" /*--------------------------------------------------------------------------*/ /* structures */ /*--------------------------------------------------------------------------*/ typedef struct { LIST_ELEM list_elem; int id; /* state id */ char *name; } STATE; typedef struct { LIST_ELEM list_elem; int state, stepping; /* map identifier */ IMAGE *image; /* if inode == -1, image points */ int inode; /* to the image of another map */ } MAP; typedef struct { char *name; /* sprite name */ int state, stepping; /* current state and stepping */ LIST maps; /* all the maps of the sprite */ int copy; /* if copy of another sprite */ } SPRITE; /*--------------------------------------------------------------------------*/ /* functions */ /*--------------------------------------------------------------------------*/ static void load_state(LIST *maps, char *sprname, STATE *state); static IMAGE *sprite_find_image(void *_sprite, int state); /*--------------------------------------------------------------------------*/ /* variables */ /*--------------------------------------------------------------------------*/ static LIST *states = NULL; static char *sprites_path = NULL; /*--------------------------------------------------------------------------*/ /* sprite_set_path */ /*--------------------------------------------------------------------------*/ void sprite_set_path(char *path) { if (sprites_path == NULL) sprites_path = malloc(PATH_MAX); strcpy(sprites_path, path); } /*--------------------------------------------------------------------------*/ /* sprite_add_state */ /*--------------------------------------------------------------------------*/ void sprite_add_state(int id, char *name) { STATE *state; if (states == NULL) { states = malloc(sizeof(LIST)); list_create(states); } state = list_insert_after(states, NULL, sizeof(STATE)); state->id = id; state->name = strdup(name); } /*--------------------------------------------------------------------------*/ /* load_state */ /*--------------------------------------------------------------------------*/ static void load_state(LIST *maps, char *sprname, STATE *state) { char *path; int stepping = 0; struct stat st; MAP *newmap, *oldmap; path = malloc(PATH_MAX); while (1) { sprintf(path, "%s/%s/%s.%d.xpm", sprites_path, sprname, state->name, stepping); if (stat(path, &st) == -1) break; newmap = list_insert_after(maps, NULL, sizeof(MAP)); newmap->state = state->id; newmap->stepping = stepping; stepping++; for (oldmap = list_head(maps); oldmap != NULL; oldmap = list_next(oldmap)) if (st.st_ino == oldmap->inode) { newmap->image = oldmap->image; newmap->inode = -1; break; } if (oldmap == NULL) { newmap->image = malloc(sizeof(IMAGE)); canvas_image_load(path, newmap->image); newmap->inode = st.st_ino; } } free(path); } /*--------------------------------------------------------------------------*/ /* sprite_load */ /*--------------------------------------------------------------------------*/ void *sprite_load(char *name) { SPRITE *sprite; STATE *state; sprite = malloc(sizeof(SPRITE)); sprite->name = strdup(name); sprite->state = -1; /* dummy state */ list_create(&sprite->maps); for (state = list_head(states); state != NULL; state = list_next(state)) load_state(&sprite->maps, name, state); sprite->copy = 0; /* indicate non-copy sprite */ return sprite; } /*--------------------------------------------------------------------------*/ /* sprite_copy */ /*--------------------------------------------------------------------------*/ void *sprite_copy(void *_sprite, int full_copy) { SPRITE *sprite, *newspr; MAP *map, *newmap; sprite = (SPRITE *)_sprite; newspr = malloc(sizeof(SPRITE)); newspr->name = sprite->name; newspr->state = -1; /* dummy state */ list_create(&newspr->maps); for (map = list_head(&sprite->maps); map != NULL; map = list_next(map)) { newmap = list_insert_after(&newspr->maps, NULL, sizeof(MAP)); newmap->state = map->state; newmap->stepping = map->stepping; if (full_copy) { newmap->image = malloc(sizeof(IMAGE)); canvas_image_copy(map->image, newmap->image); newmap->inode = 0; /* indicate image is "real" */ } else { newmap->image = map->image; newmap->inode = -1; /* indicate image is just a link */ } } newspr->copy = 1; /* indicate name/maps are copied */ return newspr; } /*--------------------------------------------------------------------------*/ /* sprite_modify */ /*--------------------------------------------------------------------------*/ void sprite_modify(void *_sprite, canvas_modify_func func) { SPRITE *sprite; MAP *map; sprite = (SPRITE *)_sprite; for (map = list_head(&sprite->maps); map != NULL; map = list_next(map)) canvas_image_modify(map->image, func); } /*--------------------------------------------------------------------------*/ /* sprite_free */ /*--------------------------------------------------------------------------*/ void sprite_free(void *_sprite) { SPRITE *sprite; MAP *map; STATE *state; sprite = (SPRITE *)_sprite; if (!sprite->copy) /* only if name was not copied */ free(sprite->name); for (map = list_head(&sprite->maps); map != NULL; map = list_delete(&sprite->maps, map)) if (!sprite->copy) /* only if maps were not copied */ for (state = list_head(states); state != NULL; state = list_next(state)) if (state->id == map->state) { if (map->inode != -1) { /* if "real" map */ canvas_image_free(map->image); free(map->image); } break; } free(sprite); } /*--------------------------------------------------------------------------*/ /* sprite_set_state */ /*--------------------------------------------------------------------------*/ void sprite_set_state(void *_sprite, int state, int stepping) { if (state != SPRITE_STOP) ((SPRITE *)_sprite)->state = state; ((SPRITE *)_sprite)->stepping = stepping; } /*--------------------------------------------------------------------------*/ /* sprite_get_state */ /*--------------------------------------------------------------------------*/ int sprite_get_state(void *_sprite) { return ((SPRITE *)_sprite)->state; } /*--------------------------------------------------------------------------*/ /* sprite_get_stepping */ /*--------------------------------------------------------------------------*/ int sprite_get_stepping(void *_sprite) { return ((SPRITE *)_sprite)->stepping; } /*--------------------------------------------------------------------------*/ /* sprite_find_image */ /*--------------------------------------------------------------------------*/ IMAGE *sprite_find_image(void *_sprite, int state) { SPRITE *sprite; MAP *map, *paintmap = NULL; sprite = (SPRITE *)_sprite; if (state != sprite->state) { if (state != SPRITE_STOP) sprite->state = state; sprite->stepping = 0; } for(map = list_head(&sprite->maps); map != NULL; map = list_next(map)) if (map->state == sprite->state) { if (map->stepping == sprite->stepping) { /* found our map */ paintmap = map; break; } if (map->stepping == 0) /* first map for state */ paintmap = map; } if (paintmap == NULL) { fprintf(stderr, "sprite.c/sprite_paint(): requested state %d not found for sprite %s\n", sprite->state, sprite->name); exit(EXIT_FAILURE); } sprite->stepping = paintmap->stepping + 1; return paintmap->image; } /*--------------------------------------------------------------------------*/ /* sprite_paint */ /*--------------------------------------------------------------------------*/ void sprite_paint(void *sprite, int state, int x, int y) { IMAGE *image; image = sprite_find_image(sprite, state); canvas_image_paint(image, x, y, 0, 0, image->width, image->height); } /*--------------------------------------------------------------------------*/ /* sprite_paint_clipped */ /*--------------------------------------------------------------------------*/ void sprite_paint_clipped(void *sprite, int state, int x, int y, int sx, int sy, int sw, int sh) { IMAGE *image; image = sprite_find_image(sprite, state); canvas_image_paint(image, x, y, sx, sy, sw, sh); } /*--------------------------------------------------------------------------*/ /* sprite_get_image */ /*--------------------------------------------------------------------------*/ IMAGE *sprite_get_image(void *_sprite, int state, int stepping) { SPRITE *sprite; MAP *map; sprite = (SPRITE *)_sprite; for(map = list_head(&sprite->maps); map != NULL; map = list_next(map)) if (map->stepping == stepping && map->state == state) return map->image; fprintf(stderr, "sprite.c/sprite_pixmap(): requested state %d stepping %d not found for sprite %s\n", state, stepping, sprite->name); exit(EXIT_FAILURE); }