X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=src%2Fimage.c;fp=src%2Fimage.c;h=d4288a6e41450e5711c71f39e4226805787958fc;hp=0000000000000000000000000000000000000000;hb=dc88088aa075f2269860b89433ccf5736dab1244;hpb=7705fa326336feba1a66d5a6ca8a7c27771e4c5f diff --git a/src/image.c b/src/image.c new file mode 100644 index 0000000..d4288a6 --- /dev/null +++ b/src/image.c @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include "image.h" +#include "treestor.h" +#include "util.h" + +int load_image(struct image *img, const char *fname) +{ + FILE *fp; + char sig[8]; + uint16_t width, height; + + memset(img, 0, sizeof *img); + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "load_image: failed to open file: %s: %s\n", fname, strerror(errno)); + return -1; + } + if(fread(sig, 1, 8, fp) < 8) { + fprintf(stderr, "unexpected EOF while reading: %s\n", fname); + fclose(fp); + return -1; + } + + if(memcmp(sig, "IDUMP565", 8) != 0) { + goto not565; + } + + /* it's a 565 dump, read it and return */ + if(!fread(&width, 2, 1, fp) || !fread(&height, 2, 1, fp)) { + fprintf(stderr, "unexpected EOF while reading: %s\n", fname); + fclose(fp); + return -1; + } +#ifdef BUILD_BIGENDIAN + width = BSWAP16(width); + height = BSWAP16(height); +#endif + + if(!(img->pixels = malloc(width * height * 2))) { + fprintf(stderr, "failed to allocate %dx%d pixel buffer for %s\n", width, height, fname); + fclose(fp); + return -1; + } + if(fread(img->pixels, 2, width * height, fp) < width * height) { + fprintf(stderr, "unexpected EOF while reading: %s\n", fname); + free(img->pixels); + img->pixels = 0; + fclose(fp); + return -1; + } + +#ifdef BUILD_BIGENDIAN + { + int i, npix = width * height; + for(i=0; ipixels[i]; + img->pixels[i] = BSWAP16(p); + } + } +#endif + + fclose(fp); + img->width = width; + img->height = height; + return 0; +not565: + fclose(fp); + + if(memcmp(sig, "animtex", 7) == 0) { + /* it's an animated texture. read metadata, and recurse with the new name*/ + struct ts_node *root, *node; + const char *imgfname; + int fps, num_frames = 0; + + if(!(root = ts_load(fname))) { + fprintf(stderr, "failed to load animation %s\n", fname); + return -1; + } + if(!(imgfname = ts_lookup_str(root, "animtex.image", 0))) { + fprintf(stderr, "animtex %s missing `image` attribute\n", fname); + ts_free_tree(root); + return -1; + } + if(strcmp(imgfname, fname) == 0) { + fprintf(stderr, "animtex %s is silly...\n", fname); + ts_free_tree(root); + return -1; + } + + if(load_image(img, imgfname) == -1) { + ts_free_tree(root); + return -1; + } + + fps = ts_lookup_int(root, "animtex.framerate", 25); + img->frame_interval = 1.0f / (float)fps; + + /* count frames */ + node = root->child_list; + while(node) { + if(strcmp(node->name, "frame") == 0) { + num_frames++; + } + node = node->next; + } + + if(!(img->uoffs = malloc(2 * num_frames * sizeof *img->uoffs))) { + fprintf(stderr, "animtex %s: failed to allocate uvoffset array for %d frames\n", fname, num_frames); + free(img->pixels); + ts_free_tree(root); + return -1; + } + img->voffs = img->uoffs + num_frames; + + num_frames = 0; + node = root->child_list; + while(node) { + if(strcmp(node->name, "frame") == 0) { + float *v = ts_get_attr_vec(node, "uvoffset", 0); + if(v) { + img->uoffs[num_frames] = v[0]; + img->voffs[num_frames++] = v[1]; + } else { + fprintf(stderr, "animtex %s: ignoring frame without uvoffset\n", fname); + } + } + node = node->next; + } + + img->num_frames = num_frames; + + ts_free_tree(root); + return 0; + } + + /* just a regular image */ + if(!(img->pixels = img_load_pixels(fname, &img->width, &img->height, IMG_FMT_RGB565))) { + fprintf(stderr, "failed to load image: %s\n", fname); + return -1; + } + return 0; +} + +int dump_image(struct image *img, const char *fname) +{ + FILE *fp; + uint16_t width, height; + +#ifdef BUILD_BIGENDIAN + int i, npix = img->width * img->height; + width = BSWAP16(img->width); + height = BSWAP16(img->height); +#else + width = img->width; + height = img->height; +#endif + + if(!(fp = fopen(fname, "wb"))) { + fprintf(stderr, "dump_image: failed to open %s: %s\n", fname, strerror(errno)); + return -1; + } + fwrite("IDUMP565", 1, 8, fp); + fwrite(&width, 2, 1, fp); + fwrite(&height, 2, 1, fp); + +#ifdef BUILD_BIGENDIAN + for(i=0; ipixels[i]); + fwrite(&p, 2, 1, fp); + } +#else + fwrite(img->pixels, 2, img->width * img->height, fp); +#endif + fclose(fp); + return 0; +} + +void destroy_image(struct image *img) +{ + if(img) { + img_free_pixels(img->pixels); + img->pixels = 0; + } +} + +int load_cubemap(struct image *cube, const char *fname_fmt) +{ + int i; + char dirstr[3] = {0}; + char fname[256]; + + for(i=0; i<6; i++) { + dirstr[0] = i & 1 ? 'n' : 'p'; + dirstr[1] = i < 2 ? 'x' : (i < 4 ? 'y' : 'z'); + sprintf(fname, fname_fmt, dirstr); + if(load_image(cube + i, fname) == -1) { + while(--i >= 0) { + destroy_image(cube + i); + } + return -1; + } + } + return 0; +} + +void destroy_cubemap(struct image *cube) +{ + int i; + + if(!cube) return; + + for(i=0; i<6; i++) { + destroy_image(cube + i); + } +}