1 /*
2 * hat_grp.c
3 * decode GRP format images in the `Hatsune no Naisho!'.
4 * 1998/03/12 by TF
5 * 1999/05/08 updated
6 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "hat_grp.h"
10 #include "leaf_util.h"
11
12 #define RING_BUF_SIZ 0x1000
13
14 static GRP *grp_new(void);
15 static int set_palette_from_data(GRP *, unsigned char *, int);
16 static void get_plain_palette(GRP *, unsigned char *, int, int);
17 static void get_compressed_palette(GRP *, unsigned char *, int, int);
18 static int extract_image(GRP *, unsigned char *, int);
19 static void optimize_palette(GRP *);
20
read_grp(const char * filename)21 GRP *read_grp(const char *filename)
22 {
23 return NULL;
24 }
25
grp_free(GRP * grp)26 void grp_free(GRP *grp)
27 {
28 if (grp == NULL) {
29 return;
30 }
31 if (grp->image != NULL) {
32 free(grp->image);
33 }
34 if (grp != NULL) {
35 free(grp);
36 }
37 }
38
read_grp_from_data(unsigned char * palette,int psize,unsigned char * body,int bsize)39 GRP *read_grp_from_data(unsigned char *palette, int psize, unsigned char *body, int bsize)
40 {
41 GRP *grp;
42
43 grp = grp_new();
44 if (set_palette_from_data(grp, palette, psize) < 0) {
45 fprintf(stderr, "read_grp_from_data: Can't read palette.\n");
46 grp_free(grp);
47 return NULL;
48 }
49 if (extract_image(grp, body, bsize) < 0) {
50 fprintf(stderr, "read_grp_from_data: Can't decode body.\n");
51 grp_free(grp);
52 return NULL;
53 }
54
55 optimize_palette(grp);
56
57 return grp;
58 }
59
grp_new(void)60 static GRP *grp_new(void)
61 {
62 int i;
63 GRP *grp;
64
65 grp = (GRP *)malloc(sizeof(GRP));
66 if (grp == NULL) {
67 fprintf(stderr, "grp_new: memory allocation error.\n");
68 exit(1);
69 }
70 grp->width = 0;
71 grp->height = 0;
72 grp->color_num = 0;
73 grp->transparent = -1;
74 for (i = 0; i < 256; i++) {
75 grp->palette[i][GRP_R] = -1;
76 grp->palette[i][GRP_G] = -1;
77 grp->palette[i][GRP_B] = -1;
78 }
79 grp->image = NULL;
80 return grp;
81 }
82
set_palette_from_data(GRP * grp,unsigned char * palette,int psize)83 static int set_palette_from_data(GRP *grp, unsigned char *palette, int psize)
84 {
85 if (palette[1] == 0) {
86 /* plain palette */
87 grp->color_num = palette[0];
88 get_plain_palette(grp, palette, psize, 2);
89 #ifdef DEBUG
90 fprintf(stderr, " plain palette(size=%d)\n", grp->color_num);
91 #endif
92 } else {
93 /* compressed palette */
94 get_compressed_palette(grp, palette, psize, 0);
95 #ifdef DEBUG
96 fprintf(stderr, " compressed palette(size=%d)\n", grp->color_num);
97 #endif
98 }
99 return 0;
100 }
101
get_plain_palette(GRP * grp,unsigned char * palette,int psize,int idx)102 static void get_plain_palette(GRP *grp, unsigned char *palette, int psize, int idx)
103 {
104 int i, id;
105
106 for (i = 0; i < grp->color_num; i++) {
107 id = palette[idx++]; /* palette ID */
108 /*
109 * Does the palette order(B-G-R) differ with 'Saorin to issho(R-G-B)'?
110 */
111 grp->palette[id][GRP_B] = palette[idx++];
112 grp->palette[id][GRP_G] = palette[idx++];
113 grp->palette[id][GRP_R] = palette[idx++];
114
115 if (grp->color_num < 16) {
116 /* should we change a palette on 16 colors? */
117 grp->palette[id][GRP_B] = (grp->palette[id][GRP_R] & 0xf0) + (grp->palette[id][GRP_R] >> 4);
118 grp->palette[id][GRP_G] = (grp->palette[id][GRP_G] & 0xf0) + (grp->palette[id][GRP_G] >> 4);
119 grp->palette[id][GRP_R] = (grp->palette[id][GRP_B] & 0xf0) + (grp->palette[id][GRP_B] >> 4);
120 }
121 }
122 }
123
get_compressed_palette(GRP * grp,unsigned char * palette,int psize,int idx)124 static void get_compressed_palette(GRP *grp, unsigned char *palette, int psize, int idx)
125 {
126 int osize, esize;
127 unsigned char *dst;
128 int i;
129
130 osize = LONGWORD(palette[idx], palette[idx + 1], palette[idx + 2], palette[idx + 3]);
131 esize = LONGWORD(palette[idx + 4], palette[idx + 5], palette[idx + 6], palette[idx + 7]);
132
133 if (osize != psize) {
134 fprintf(stderr, "get_compressed_palette: Invalid header.\n");
135 }
136 dst = (unsigned char *)calloc(esize, sizeof(unsigned char));
137 if (dst == NULL) {
138 perror("calloc");
139 exit(1);
140 }
141
142 extract_lz77(palette + 8, osize - 8, dst, esize, RING_BUF_SIZ);
143
144 grp->color_num = dst[0];
145
146 for (i = 2; i < esize; i += 4) {
147 grp->palette[dst[i]][GRP_B] = dst[i + 1];
148 grp->palette[dst[i]][GRP_G] = dst[i + 2];
149 grp->palette[dst[i]][GRP_R] = dst[i + 3];
150 /* printf("%02x: %02x, %02x, %02x\n",
151 dst[i], dst[i + 1], dst[i + 2], dst[i + 3]); */
152 }
153 free(dst);
154 }
155
extract_image(GRP * grp,unsigned char * body,int bsize)156 static int extract_image(GRP *grp, unsigned char *body, int bsize)
157 {
158 int i, j;
159 int idx = 4;
160 unsigned char *dst;
161
162 grp->orig_size = LONGWORD(body[0], body[1], body[2], body[3]);
163 grp->extracted_size = LONGWORD(body[4], body[5], body[6], body[7]);
164
165 dst = (unsigned char *)calloc(grp->extracted_size, sizeof(unsigned char));
166 if (dst == NULL) {
167 perror("calloc");
168 exit(1);
169 }
170 extract_lz77(body + 8, bsize - 8, dst, grp->extracted_size, RING_BUF_SIZ);
171
172 grp->width = WORD(dst[0], dst[1]);
173 grp->height = WORD(dst[2], dst[3]);
174 grp->image = (int *)calloc(grp->width * grp->height, sizeof(int));
175 if (grp->image == NULL) {
176 perror("calloc");
177 exit(1);
178 }
179
180 for (i = 0; i < grp->height; i++) {
181 for (j = 0; j < grp->width; j++) {
182 grp->image[i * grp->width + j] = dst[idx++];
183 }
184 }
185 free(dst);
186
187 /* transparent specification may be embedded in the game's executable. */
188 grp->transparent = grp->image[0];
189
190 return 0;
191 }
192
optimize_palette(GRP * grp)193 static void optimize_palette(GRP *grp)
194 {
195 int col[256];
196 int idx[256];
197 int i, j;
198
199 for (i = 0; i < 256; i++) {
200 col[i] = -1;
201 idx[i] = 0;
202 }
203
204 for (i = 0; i < grp->width * grp->height; i++) {
205 col[grp->image[i]] = 0;
206 }
207
208 for (i = 0, j = 0; i < 256; i++) {
209 if (col[i] == 0) {
210 grp->palette[j][GRP_R] = grp->palette[i][GRP_R];
211 grp->palette[j][GRP_G] = grp->palette[i][GRP_G];
212 grp->palette[j][GRP_B] = grp->palette[i][GRP_B];
213 idx[i] = j;
214 j++;
215 }
216 }
217 if (grp->transparent >= j) {
218 if (j < 256) {
219 grp->transparent = j;
220 grp->color_num = j + 1;
221 } else {
222 grp->transparent = 255;
223 }
224 } else {
225 grp->transparent = idx[grp->transparent];
226 }
227
228 for (i = 0; i < grp->width * grp->height; i++) {
229 if (grp->image[i] < 0) {
230 grp->image[i] = idx[grp->image[0]];
231 } else {
232 grp->image[i] = idx[grp->image[i]];
233 }
234 }
235 }
236