per-line scrolling test
[mdlife] / tools / pngdump / tiles.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include "tiles.h"
6 #include "image.h"
7
8 static int matchtile(struct image *img, int toffs, int th);
9
10 int img2tiles(struct tilemap *tmap, struct image *img, int tw, int th, int dedup)
11 {
12         int i, j, x, y, tx, ty, tileoffs, xtiles, ytiles, ntiles, tileno, tid;
13         struct image orig;
14         unsigned int pix;
15
16         if(alloc_image(&orig, img->width, img->height, img->bpp) == -1) {
17                 fprintf(stderr, "img2tiles: failed to allocate temporary image\n");
18                 return -1;
19         }
20         memcpy(orig.pixels, img->pixels, img->scansz * img->height);
21
22         xtiles = (img->width + tw - 1) / tw;
23         ytiles = (img->height + th - 1) / th;
24         ntiles = xtiles * ytiles;
25
26         img->width = tw;
27         img->height = ntiles * th;
28         img->pitch = img->scansz = tw * img->bpp / 8;
29
30         if(tmap) {
31                 tmap->width = xtiles;
32                 tmap->height = ytiles;
33                 if(!(tmap->map = malloc(ntiles * sizeof *tmap->map))) {
34                         fprintf(stderr, "failed to allocate tilemap\n");
35                         free(orig.pixels);
36                         return -1;
37                 }
38         }
39
40         tileno = 0;
41         tileoffs = 0;
42         y = 0;
43         for(i=0; i<ytiles; i++) {
44                 x = 0;
45                 for(j=0; j<xtiles; j++) {
46                         for(ty=0; ty<th; ty++) {
47                                 for(tx=0; tx<tw; tx++) {
48                                         pix = get_pixel(&orig, x + tx, y + ty);
49                                         put_pixel(img, tx, ty + tileoffs, pix);
50                                 }
51                         }
52
53                         if(dedup) {
54                                 if((tid = matchtile(img, tileoffs, th)) == -1) {
55                                         if(tmap) {
56                                                 tmap->map[tileno++] = tileoffs / th;
57                                         }
58                                         tileoffs += th; /* destination Y offset, inc by th for every tile */
59                                 } else {
60                                         if(tmap) {
61                                                 tmap->map[tileno++] = tid;
62                                         }
63                                 }
64                         } else {
65                                 tileoffs += th; /* destination Y offset, inc by th for every tile */
66                         }
67                         x += tw;
68                 }
69                 y += th;
70         }
71
72         if(dedup) {
73                 putchar('\n');
74                 img->height = tileoffs;
75         }
76
77         free(orig.pixels);
78         return 0;
79 }
80
81 static int matchtile(struct image *img, int toffs, int th)
82 {
83         int i, tilesz;
84         int ntiles = toffs / th;
85         unsigned char *pa, *pb;
86
87         tilesz = img->pitch * th;
88         pa = (unsigned char*)img->pixels;
89         pb = (unsigned char*)img->pixels + toffs * img->pitch;
90
91         for(i=0; i<ntiles; i++) {
92                 if(memcmp(pa, pb, tilesz) == 0) {
93                         return i;
94                 }
95                 pa += tilesz;
96         }
97
98         return -1;
99 }
100
101 int dump_tilemap(struct tilemap *tmap, const char *fname)
102 {
103         FILE *fp;
104         int i, sz = tmap->width * tmap->height;
105         uint16_t id;
106
107         if(sz <= 0) return -1;
108
109         if(!(fp = fopen(fname, "wb"))) {
110                 fprintf(stderr, "dump_tilemap: failed to open %s for writing\n", fname);
111                 return -1;
112         }
113
114         for(i=0; i<sz; i++) {
115                 /* XXX dump in 16bit big endian for the megadrive */
116                 id = (tmap->map[i] << 8) | (tmap->map[i] >> 8);
117                 fwrite(&id, sizeof id, 1, fp);
118         }
119
120         fclose(fp);
121         return 0;
122 }