32da284900eb8a1ec2de0e16e8d137a848d59493
[test_compression] / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <assert.h>
6 #include <GL/freeglut.h>
7
8 #undef USE_SRGB
9
10 #ifdef USE_SRGB
11 #define COMP_FMT        GL_COMPRESSED_SRGB8_ETC2
12 #else
13 #define COMP_FMT        GL_COMPRESSED_RGB8_ETC2
14 #endif
15
16 int init(void);
17 int texcomp(unsigned char *compix, unsigned int tofmt, unsigned char *pixels,
18                 int xsz, int ysz, unsigned int fromfmt, unsigned int fromtype);
19 void disp(void);
20 void reshape(int x, int y);
21 void keyb(unsigned char key, int x, int y);
22 void gen_image(unsigned char *pixels, int xsz, int ysz);
23 unsigned char *load_compressed_image(const char *fname, int *cszptr, int *xszptr, int *yszptr);
24 int dump_compressed_image(const char *fname, unsigned char *data, int size, int w, int h);
25 void print_compressed_formats(void);
26
27 unsigned int tex, comp_tex;
28 const char *texfile;
29
30 int main(int argc, char **argv)
31 {
32         unsigned int glut_flags = GLUT_RGB | GLUT_DOUBLE;
33 #ifdef USE_SRGB
34         glut_flags |= GLUT_SRGB;
35 #endif
36
37         texfile = argv[1];
38
39         glutInit(&argc, argv);
40         glutInitWindowSize(800, 600);
41         glutInitDisplayMode(glut_flags);
42         glutCreateWindow("test");
43
44         glutDisplayFunc(disp);
45         glutReshapeFunc(reshape);
46         glutKeyboardFunc(keyb);
47
48         if(init() == -1) {
49                 return 1;
50         }
51
52         glutMainLoop();
53         return 0;
54 }
55
56 int init(void)
57 {
58         unsigned char *pixels, *buf;
59         int xsz = 512;
60         int ysz = 512;
61         int is_comp = 0;
62         int comp_size = 0;
63         int tmp;
64
65         print_compressed_formats();
66
67         if(texfile) {
68                 if(!(pixels = load_compressed_image(texfile, &comp_size, &xsz, &ysz))) {
69                         return -1;
70                 }
71                 printf("loaded compressed texture file: %s (%dx%d)\n", texfile, xsz, ysz);
72
73         } else {
74                 if(!(pixels = malloc(xsz * ysz * 3))) {
75                         abort();
76                 }
77                 gen_image(pixels, xsz, ysz);
78
79                 printf("compressing texture\n");
80                 if((comp_size = texcomp(pixels, COMP_FMT, pixels, xsz, ysz, GL_RGB, GL_UNSIGNED_BYTE)) == -1) {
81                         return -1;
82                 }
83                 printf("compressed texture is %d bytes (uncompressed was: %d)\n", comp_size, xsz * ysz * 3);
84
85                 dump_compressed_image("compressed_texture", pixels, comp_size, xsz, ysz);
86         }
87
88         glGenTextures(1, &tex);
89         glBindTexture(GL_TEXTURE_2D, tex);
90         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
91         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
92         glCompressedTexImage2D(GL_TEXTURE_2D, 0, COMP_FMT, xsz, ysz, 0, comp_size, pixels);
93         if(glGetError()) {
94                 fprintf(stderr, "failed to upload compressed texture\n");
95                 return -1;
96         }
97
98         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &is_comp);
99         if(!is_comp) {
100                 fprintf(stderr, "texture is not compressed\n");
101                 return -1;
102         }
103         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &tmp);
104         if(tmp != comp_size) {
105                 fprintf(stderr, "internal compressed size differs (expected: %d, got: %d)!\n", comp_size, tmp);
106                 return -1;
107         }
108
109         if(!(buf = malloc(comp_size))) {
110                 fprintf(stderr, "failed to allocate comparison image buffer (%d bytes)\n", comp_size);
111                 return -1;
112         }
113         glGetCompressedTexImage(GL_TEXTURE_2D, 0, buf);
114
115         if(memcmp(pixels, buf, comp_size) != 0) {
116                 fprintf(stderr, "submitted and retrieved pixel data differ!\n");
117         } else {
118                 printf("submitted and retrieved sizes match (%d bytes)\n", comp_size);
119         }
120         free(buf);
121         free(pixels);
122
123 #ifdef USE_SRGB
124         glEnable(GL_FRAMEBUFFER_SRGB);
125 #endif
126
127         glEnable(GL_TEXTURE_2D);
128         return 0;
129 }
130
131 int texcomp(unsigned char *compix, unsigned int tofmt, unsigned char *pixels,
132                 int xsz, int ysz, unsigned int fromfmt, unsigned int fromtype)
133 {
134         unsigned int tex;
135         int is_comp = 0;
136         int comp_size = 0;
137
138         glGenTextures(1, &tex);
139         glBindTexture(GL_TEXTURE_2D, tex);
140         glTexImage2D(GL_TEXTURE_2D, 0, tofmt, xsz, ysz, 0, fromfmt, fromtype, pixels);
141         if(glGetError()) {
142                 fprintf(stderr, "failed to compress texture\n");
143                 return -1;
144         }
145
146         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &is_comp);
147         if(!is_comp) {
148                 fprintf(stderr, "texture is not compressed\n");
149                 return -1;
150         }
151         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &comp_size);
152
153         glGetCompressedTexImage(GL_TEXTURE_2D, 0, compix);
154         return comp_size;
155 }
156
157 void disp(void)
158 {
159         glClear(GL_COLOR_BUFFER_BIT);
160
161         glBegin(GL_QUADS);
162         glTexCoord2f(0, 1); glVertex2f(-1, -1);
163         glTexCoord2f(1, 1); glVertex2f(1, -1);
164         glTexCoord2f(1, 0); glVertex2f(1, 1);
165         glTexCoord2f(0, 0);     glVertex2f(-1, 1);
166         glEnd();
167
168         glutSwapBuffers();
169         assert(glGetError() == GL_NO_ERROR);
170 }
171
172 void reshape(int x, int y)
173 {
174         float aspect = (float)x / (float)y;
175         glViewport(0, 0, x, y);
176
177         glMatrixMode(GL_PROJECTION);
178         glLoadIdentity();
179         glScalef(1.0 / aspect, 1, 1);
180 }
181
182 void keyb(unsigned char key, int x, int y)
183 {
184         if(key == 27) {
185                 exit(0);
186         }
187 }
188
189 void gen_image(unsigned char *pixels, int xsz, int ysz)
190 {
191         int i, j;
192
193         for(i=0; i<ysz; i++) {
194                 for(j=0; j<xsz; j++) {
195                         int xor = i ^ j;
196
197                         *pixels++ = xor & 0xff;
198                         *pixels++ = (xor << 1) & 0xff;
199                         *pixels++ = (xor << 2) & 0xff;
200                 }
201         }
202 }
203
204 unsigned char *load_compressed_image(const char *fname, int *cszptr, int *xszptr, int *yszptr)
205 {
206         unsigned char *pixels;
207         long start, comp_size;
208         int xsz, ysz;
209         FILE *fp;
210
211         if(!(fp = fopen(texfile, "rb"))) {
212                 fprintf(stderr, "failed to open compressed texture file: %s: %s\n", texfile, strerror(errno));
213                 return 0;
214         }
215
216         if(fread(&xsz, sizeof xsz, 1, fp) < 1 || fread(&ysz, sizeof ysz, 1, fp) < 1) {
217                 fprintf(stderr, "failed to read compressed texture file header: %s: %s\n", texfile, strerror(errno));
218                 fclose(fp);
219                 return 0;
220         }
221         start = ftell(fp);
222         fseek(fp, 0, SEEK_END);
223         comp_size = ftell(fp) - start;
224         fseek(fp, start, SEEK_SET);
225
226         if(!(pixels = malloc(comp_size))) {
227                 perror("failed to allocate pixel buffer");
228                 return 0;
229         }
230         if(fread(pixels, 1, comp_size, fp) < comp_size) {
231                 fprintf(stderr, "failed to read compressed texture file: %s: %s\n", texfile, strerror(errno));
232                 fclose(fp);
233                 free(pixels);
234                 return 0;
235         }
236         fclose(fp);
237
238         *cszptr = comp_size;
239         *xszptr = xsz;
240         *yszptr = ysz;
241         return pixels;
242 }
243
244 int dump_compressed_image(const char *fname, unsigned char *data, int size, int w, int h)
245 {
246         FILE *fp;
247
248         if(!(fp = fopen(fname, "wb"))) {
249                 fprintf(stderr, "failed to open compressed texture dump file: %s: %s\n", fname, strerror(errno));
250                 return -1;
251         }
252
253         if(fwrite(&w, sizeof w, 1, fp) < 1 ||
254                         fwrite(&h, sizeof h, 1, fp) < 1 ||
255                         fwrite(data, 1, size, fp) < size) {
256                 fprintf(stderr, "failed to dump compressed texture: %s\n", strerror(errno));
257         }
258         fclose(fp);
259         return 0;
260 }
261
262 const char *fmtstr(int fmt)
263 {
264         switch(fmt) {
265         case 0x86b0: return "GL_COMPRESSED_RGB_FXT1_3DFX";
266         case 0x86b1: return "GL_COMPRESSED_RGBA_FXT1_3DFX";
267         case 0x8dbb: return "GL_COMPRESSED_RED_RGTC1";
268         case 0x8dbc: return "GL_COMPRESSED_SIGNED_RED_RGTC1";
269         case 0x8dbd: return "GL_COMPRESSED_RG_RGTC2";
270         case 0x8dbe: return "GL_COMPRESSED_SIGNED_RG_RGTC2";
271         case 0x8e8c: return "GL_COMPRESSED_RGBA_BPTC_UNORM";
272         case 0x8e8d: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM";
273         case 0x8e8e: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT";
274         case 0x8e8f: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT";
275         case 0x9274: return "GL_COMPRESSED_RGB8_ETC2";
276         case 0x9275: return "GL_COMPRESSED_SRGB8_ETC2";
277         case 0x9276: return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2";
278         case 0x9277: return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2";
279         case 0x9278: return "GL_COMPRESSED_RGBA8_ETC2_EAC";
280         case 0x9279: return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC";
281         case 0x9270: return "GL_COMPRESSED_R11_EAC";
282         case 0x9271: return "GL_COMPRESSED_SIGNED_R11_EAC";
283         case 0x9272: return "GL_COMPRESSED_RG11_EAC";
284         case 0x9273: return "GL_COMPRESSED_SIGNED_RG11_EAC";
285         case 0x83F0: return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
286         case 0x83F1: return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
287         case 0x83F2: return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
288         case 0x83F3: return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT";
289         case 0x8C48: return "GL_COMPRESSED_SRGB_EXT";
290         case 0x8C49: return "GL_COMPRESSED_SRGB_ALPHA_EXT";
291         case 0x8C4A: return "GL_COMPRESSED_SLUMINANCE_EXT";
292         case 0x8C4B: return "GL_COMPRESSED_SLUMINANCE_ALPHA_EXT";
293         case 0x8C4C: return "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT";
294         case 0x8C4D: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT";
295         case 0x8C4E: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT";
296         case 0x8C4F: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT";
297         case 0x8B90: return "GL_PALETTE4_RGB8_OES";
298         case 0x8B91: return "GL_PALETTE4_RGBA8_OES";
299         case 0x8B92: return "GL_PALETTE4_R5_G6_B5_OES";
300         case 0x8B93: return "GL_PALETTE4_RGBA4_OES";
301         case 0x8B94: return "GL_PALETTE4_RGB5_A1_OES";
302         case 0x8B95: return "GL_PALETTE8_RGB8_OES";
303         case 0x8B96: return "GL_PALETTE8_RGBA8_OES";
304         case 0x8B97: return "GL_PALETTE8_R5_G6_B5_OES";
305         case 0x8B98: return "GL_PALETTE8_RGBA4_OES";
306         case 0x8B99: return "GL_PALETTE8_RGB5_A1_OES";
307         case 0x93B0: return "GL_COMPRESSED_RGBA_ASTC_4";
308         case 0x93B1: return "GL_COMPRESSED_RGBA_ASTC_5";
309         case 0x93B2: return "GL_COMPRESSED_RGBA_ASTC_5";
310         case 0x93B3: return "GL_COMPRESSED_RGBA_ASTC_6";
311         case 0x93B4: return "GL_COMPRESSED_RGBA_ASTC_6";
312         case 0x93B5: return "GL_COMPRESSED_RGBA_ASTC_8";
313         case 0x93B6: return "GL_COMPRESSED_RGBA_ASTC_8";
314         case 0x93B7: return "GL_COMPRESSED_RGBA_ASTC_8";
315         case 0x93B8: return "GL_COMPRESSED_RGBA_ASTC_10";
316         case 0x93B9: return "GL_COMPRESSED_RGBA_ASTC_10";
317         case 0x93BA: return "GL_COMPRESSED_RGBA_ASTC_10";
318         case 0x93BB: return "GL_COMPRESSED_RGBA_ASTC_10";
319         case 0x93BC: return "GL_COMPRESSED_RGBA_ASTC_12";
320         case 0x93BD: return "GL_COMPRESSED_RGBA_ASTC_12";
321         case 0x93D0: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4";
322         case 0x93D1: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5";
323         case 0x93D2: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5";
324         case 0x93D3: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6";
325         case 0x93D4: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6";
326         case 0x93D5: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
327         case 0x93D6: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
328         case 0x93D7: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
329         case 0x93D8: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
330         case 0x93D9: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
331         case 0x93DA: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
332         case 0x93DB: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
333         case 0x93DC: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12";
334         case 0x93DD: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12";
335         default:
336                 break;
337         }
338         return "unknown";
339 }
340
341 void print_compressed_formats(void)
342 {
343         int i, num_fmt;
344         int *fmtlist;
345
346         glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_fmt);
347         printf("%d generic compressed texture formats available:\n", num_fmt);
348
349         if(!(fmtlist = malloc(num_fmt * sizeof *fmtlist))) {
350                 fprintf(stderr, "failed to allocate texture formats enumeration buffer\n");
351                 return;
352         }
353         glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, fmtlist);
354
355         for(i=0; i<num_fmt; i++) {
356                 printf(" %05x: %s\n", fmtlist[i], fmtstr(fmtlist[i]));
357         }
358         free(fmtlist);
359 }