Removed the automatic textures generation
[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/glew.h>
7 #include <GL/freeglut.h>
8
9 struct texture {
10         unsigned int id;
11         int width, height;
12         unsigned int fmt;
13         unsigned int compsize;
14         void *data;
15 };
16
17 int init(void);
18 void disp(void);
19 void reshape(int x, int y);
20 void keyb(unsigned char key, int x, int y);
21 void idle(void);
22 int load_texture(const char *fname, struct texture *tex);
23 const char *fmtstr(int fmt);
24 void print_compressed_formats(void);
25
26 struct texture tex;
27 unsigned int tex2;
28 const char *texfile;
29 int subtest, copytest;
30
31 int main(int argc, char **argv)
32 {
33         int i, loop = 0;
34         unsigned int glut_flags = GLUT_RGB | GLUT_DOUBLE;
35
36         for(i=1; i<argc; i++) {
37                 if(argv[i][0] == '-') {
38                         if(strcmp(argv[i], "-subtest") == 0) {
39                                 subtest = 1;
40                         } else if(strcmp(argv[i], "-copytest") == 0) {
41                                 copytest = 1;
42                         } else if(strcmp(argv[i], "-copytest-loop") == 0) {
43                                 copytest = 1;
44                                 loop = 1;
45                         } else {
46                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
47                                 return 1;
48                         }
49                 } else {
50                         if(texfile) {
51                                 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
52                                 return 1;
53                         }
54                         texfile = argv[i];
55                 }
56         }
57
58         if(!texfile) {
59                 fprintf(stderr, "you must specify a compressed texture file\n");
60                 return 1;
61         }
62
63         glutInit(&argc, argv);
64         glutInitDisplayMode(glut_flags);
65         glutCreateWindow("test");
66
67         glutDisplayFunc(disp);
68         glutReshapeFunc(reshape);
69         glutKeyboardFunc(keyb);
70
71         if (loop)
72                 glutIdleFunc(idle);
73
74         glewInit();
75
76         if(init() == -1) {
77                 return 1;
78         }
79
80         glutMainLoop();
81         return 0;
82 }
83
84 int init(void)
85 {
86         unsigned char *buf;
87         int is_comp = 0;
88         int tmp;
89         unsigned int intfmt;
90
91         print_compressed_formats();
92
93         if(load_texture(texfile, &tex) == -1) {
94                 fprintf(stderr, "failed to load texture %s\n", texfile);
95                 return -1;
96         }
97
98         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (int*)&intfmt);
99         if(intfmt != tex.fmt) {
100                 fprintf(stderr, "internal format differs (expected: %s [%x], got: %s [%x])\n",
101                                 fmtstr(tex.fmt), tex.fmt, fmtstr(intfmt), intfmt);
102                 return -1;
103         }
104         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &is_comp);
105         if(!is_comp) {
106                 fprintf(stderr, "texture is not compressed\n");
107                 return -1;
108         }
109         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &tmp);
110         if(tmp != tex.compsize) {
111                 fprintf(stderr, "internal compressed size differs (expected: %d, got: %d)!\n", tex.compsize, tmp);
112                 return -1;
113         }
114
115         if(!(buf = malloc(tex.compsize))) {
116                 fprintf(stderr, "failed to allocate comparison image buffer (%d bytes)\n", tex.compsize);
117                 return -1;
118         }
119         glGetCompressedTexImage(GL_TEXTURE_2D, 0, buf);
120
121         if(memcmp(tex.data, buf, tex.compsize) != 0) {
122                 int i;
123                 unsigned char *a = tex.data, *b = buf;
124
125                 for(i=0; i<tex.compsize; i++) {
126                         if(*a++ != *b++) break;
127                 }
128                 assert(i < tex.compsize);
129                 fprintf(stderr, "submitted and retrieved pixel data differ! (at offset %d)\n", i);
130         } else {
131                 printf("submitted and retrieved sizes match (%d bytes)\n", tex.compsize);
132         }
133
134         if(subtest) {
135                 printf("testing glGetCompressedTextureSubImage and glCompressedTexSubImage2D\n");
136                 memset(buf, 0, tex.compsize);
137                 glGetCompressedTextureSubImage(tex.id, 0, 192, 64, 0, 64, 64, 1, tex.compsize, buf);
138                 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, tex.fmt, 2048, buf);
139         }
140
141         if(copytest) {
142                 printf("testing glCopyImageSubData\n");
143
144                 glGenTextures(1, &tex2);
145                 glBindTexture(GL_TEXTURE_2D, tex2);
146                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
147                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
148                 glCompressedTexImage2D(GL_TEXTURE_2D, 0, tex.fmt, tex.width, tex.height, 0, tex.compsize, tex.data);
149                 glBindTexture(GL_TEXTURE_2D, 0);
150
151                 glCopyImageSubData(tex2, GL_TEXTURE_2D, 0, 128, 64, 0,
152                                 tex.id, GL_TEXTURE_2D, 0, 32, 32, 0, 64, 64, 1);
153
154                 glBindTexture(GL_TEXTURE_2D, tex.id);
155         }
156
157         free(buf);
158
159         glEnable(GL_TEXTURE_2D);
160         return 0;
161 }
162
163 void disp(void)
164 {
165         int x = 0, y = 0;
166         int xsz = tex.width;
167         int ysz = tex.height;
168
169         glClear(GL_COLOR_BUFFER_BIT);
170
171         glBindTexture(GL_TEXTURE_2D, tex.id);
172         glEnable(GL_TEXTURE_2D);
173
174         glBegin(GL_QUADS);
175         glTexCoord2f(0, 1); glVertex2f(0, 0);
176         glTexCoord2f(1, 1); glVertex2f(xsz, 0);
177         glTexCoord2f(1, 0); glVertex2f(xsz, ysz);
178         glTexCoord2f(0, 0);     glVertex2f(0, ysz);
179
180         x += xsz;
181         xsz /= 2;
182         ysz /= 2;
183
184         while(xsz & ysz) {
185                 glTexCoord2f(0, 1); glVertex2f(x, y);
186                 glTexCoord2f(1, 1); glVertex2f(x + xsz, y);
187                 glTexCoord2f(1, 0); glVertex2f(x + xsz, y + ysz);
188                 glTexCoord2f(0, 0);     glVertex2f(x, y + ysz);
189
190                 y += ysz;
191
192                 xsz /= 2;
193                 ysz /= 2;
194         }
195         glEnd();
196
197         glutSwapBuffers();
198         assert(glGetError() == GL_NO_ERROR);
199 }
200
201 void reshape(int x, int y)
202 {
203         glViewport(0, 0, x, y);
204
205         glMatrixMode(GL_PROJECTION);
206         glLoadIdentity();
207         glOrtho(0, x, 0, y, -1, 1);
208 }
209
210 void keyb(unsigned char key, int x, int y)
211 {
212         if(key == 27) {
213                 exit(0);
214         }
215 }
216
217 void idle(void)
218 {
219         glutPostRedisplay();
220 }
221
222 void gen_image(unsigned char *pixels, int xsz, int ysz)
223 {
224         int i, j;
225
226         for(i=0; i<ysz; i++) {
227                 for(j=0; j<xsz; j++) {
228                         int xor = i ^ j;
229
230                         *pixels++ = xor & 0xff;
231                         *pixels++ = (xor << 1) & 0xff;
232                         *pixels++ = (xor << 2) & 0xff;
233                 }
234         }
235 }
236
237 struct header {
238         char magic[8];
239         uint32_t glfmt;
240         uint16_t flags;
241         uint16_t levels;
242         uint32_t width, height;
243         struct {
244                 uint32_t offset, size;
245         } datadesc[20];
246         char unused[8];
247 };
248
249 int load_texture(const char *fname, struct texture *tex)
250 {
251         int i;
252         FILE *fp;
253         struct header hdr;
254         void *buf;
255
256         if(!(fp = fopen(fname, "rb"))) {
257                 fprintf(stderr, "failed to open file: %s: %s\n", fname, strerror(errno));
258                 return -1;
259         }
260         if(fread(&hdr, 1, sizeof hdr, fp) != sizeof hdr) {
261                 fprintf(stderr, "failed to read image file header: %s: %s\n", fname, strerror(errno));
262                 fclose(fp);
263                 return -1;
264         }
265         if(memcmp(hdr.magic, "COMPTEX0", sizeof hdr.magic) != 0 || hdr.levels < 0 ||
266                         hdr.levels > 20 || !hdr.datadesc[0].size) {
267                 fprintf(stderr, "%s is not a compressed texture file, or is corrupted\n", fname);
268                 fclose(fp);
269                 return -1;
270         }
271
272         if(!(buf = malloc(hdr.datadesc[0].size))) {
273                 fprintf(stderr, "failed to allocate compressed texture buffer (%d bytes): %s\n",
274                                 hdr.datadesc[0].size, strerror(errno));
275                 fclose(fp);
276                 return -1;
277         }
278         if(!(tex->data = malloc(hdr.datadesc[0].size))) {
279                 fprintf(stderr, "failed to allocate data buffer\n");
280                 fclose(fp);
281                 free(buf);
282                 return -1;
283         }
284
285
286         glGenTextures(1, &tex->id);
287         glBindTexture(GL_TEXTURE_2D, tex->id);
288         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
289                         hdr.levels > 1 ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
290         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
291
292         tex->fmt = hdr.glfmt;
293         tex->width = hdr.width;
294         tex->height = hdr.height;
295         tex->compsize = hdr.datadesc[0].size;
296
297         printf("%s: %dx%d format: %s\n", fname, tex->width, tex->height, fmtstr(tex->fmt));
298         glutReshapeWindow(tex->width + tex->width / 2, tex->height);
299
300         for(i=0; i<hdr.levels; i++) {
301                 if(!hdr.datadesc[i].size) {
302                         continue;
303                 }
304
305                 if(fread(buf, 1, hdr.datadesc[i].size, fp) != hdr.datadesc[i].size) {
306                         fprintf(stderr, "unexpected EOF while reading texture: %s\n", fname);
307                         fclose(fp);
308                         free(buf);
309                         glDeleteTextures(1, &tex->id);
310                         return -1;
311                 }
312                 if(i == 0) {
313                         memcpy(tex->data, buf, hdr.datadesc[0].size);
314                 }
315                 glCompressedTexImage2D(GL_TEXTURE_2D, i, hdr.glfmt, hdr.width, hdr.height, 0,
316                                 hdr.datadesc[i].size, buf);
317
318                 hdr.width /= 2;
319                 hdr.height /= 2;
320         }
321
322         free(buf);
323         fclose(fp);
324         return 0;
325 }
326
327 const char *fmtstr(int fmt)
328 {
329         switch(fmt) {
330         case 0x86b0: return "GL_COMPRESSED_RGB_FXT1_3DFX";
331         case 0x86b1: return "GL_COMPRESSED_RGBA_FXT1_3DFX";
332         case 0x8dbb: return "GL_COMPRESSED_RED_RGTC1";
333         case 0x8dbc: return "GL_COMPRESSED_SIGNED_RED_RGTC1";
334         case 0x8dbd: return "GL_COMPRESSED_RG_RGTC2";
335         case 0x8dbe: return "GL_COMPRESSED_SIGNED_RG_RGTC2";
336         case 0x8e8c: return "GL_COMPRESSED_RGBA_BPTC_UNORM";
337         case 0x8e8d: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM";
338         case 0x8e8e: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT";
339         case 0x8e8f: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT";
340         case 0x9274: return "GL_COMPRESSED_RGB8_ETC2";
341         case 0x9275: return "GL_COMPRESSED_SRGB8_ETC2";
342         case 0x9276: return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2";
343         case 0x9277: return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2";
344         case 0x9278: return "GL_COMPRESSED_RGBA8_ETC2_EAC";
345         case 0x9279: return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC";
346         case 0x9270: return "GL_COMPRESSED_R11_EAC";
347         case 0x9271: return "GL_COMPRESSED_SIGNED_R11_EAC";
348         case 0x9272: return "GL_COMPRESSED_RG11_EAC";
349         case 0x9273: return "GL_COMPRESSED_SIGNED_RG11_EAC";
350         case 0x83F0: return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
351         case 0x83F1: return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
352         case 0x83F2: return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
353         case 0x83F3: return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT";
354         case 0x8C48: return "GL_COMPRESSED_SRGB_EXT";
355         case 0x8C49: return "GL_COMPRESSED_SRGB_ALPHA_EXT";
356         case 0x8C4A: return "GL_COMPRESSED_SLUMINANCE_EXT";
357         case 0x8C4B: return "GL_COMPRESSED_SLUMINANCE_ALPHA_EXT";
358         case 0x8C4C: return "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT";
359         case 0x8C4D: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT";
360         case 0x8C4E: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT";
361         case 0x8C4F: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT";
362         case 0x8B90: return "GL_PALETTE4_RGB8_OES";
363         case 0x8B91: return "GL_PALETTE4_RGBA8_OES";
364         case 0x8B92: return "GL_PALETTE4_R5_G6_B5_OES";
365         case 0x8B93: return "GL_PALETTE4_RGBA4_OES";
366         case 0x8B94: return "GL_PALETTE4_RGB5_A1_OES";
367         case 0x8B95: return "GL_PALETTE8_RGB8_OES";
368         case 0x8B96: return "GL_PALETTE8_RGBA8_OES";
369         case 0x8B97: return "GL_PALETTE8_R5_G6_B5_OES";
370         case 0x8B98: return "GL_PALETTE8_RGBA4_OES";
371         case 0x8B99: return "GL_PALETTE8_RGB5_A1_OES";
372         case 0x93B0: return "GL_COMPRESSED_RGBA_ASTC_4";
373         case 0x93B1: return "GL_COMPRESSED_RGBA_ASTC_5";
374         case 0x93B2: return "GL_COMPRESSED_RGBA_ASTC_5";
375         case 0x93B3: return "GL_COMPRESSED_RGBA_ASTC_6";
376         case 0x93B4: return "GL_COMPRESSED_RGBA_ASTC_6";
377         case 0x93B5: return "GL_COMPRESSED_RGBA_ASTC_8";
378         case 0x93B6: return "GL_COMPRESSED_RGBA_ASTC_8";
379         case 0x93B7: return "GL_COMPRESSED_RGBA_ASTC_8";
380         case 0x93B8: return "GL_COMPRESSED_RGBA_ASTC_10";
381         case 0x93B9: return "GL_COMPRESSED_RGBA_ASTC_10";
382         case 0x93BA: return "GL_COMPRESSED_RGBA_ASTC_10";
383         case 0x93BB: return "GL_COMPRESSED_RGBA_ASTC_10";
384         case 0x93BC: return "GL_COMPRESSED_RGBA_ASTC_12";
385         case 0x93BD: return "GL_COMPRESSED_RGBA_ASTC_12";
386         case 0x93D0: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4";
387         case 0x93D1: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5";
388         case 0x93D2: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5";
389         case 0x93D3: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6";
390         case 0x93D4: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6";
391         case 0x93D5: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
392         case 0x93D6: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
393         case 0x93D7: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
394         case 0x93D8: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
395         case 0x93D9: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
396         case 0x93DA: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
397         case 0x93DB: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
398         case 0x93DC: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12";
399         case 0x93DD: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12";
400         case GL_LUMINANCE:
401         case 1:
402                 return "GL_LUMINANCE";
403         case GL_RGB:
404         case 3:
405                 return "GL_RGB";
406         case GL_RGBA:
407         case 4:
408                 return "GL_RGBA";
409         case GL_BGR: return "GL_BGR";
410         case GL_BGRA: return "GL_BGRA";
411         case GL_SLUMINANCE: return "GL_SLUMINANCE";
412         case GL_SLUMINANCE8: return "GL_SLUMINANCE8";
413         case GL_SLUMINANCE_ALPHA: return "GL_SLUMINANCE_ALPHA";
414         case GL_SLUMINANCE8_ALPHA8: return "GL_SLUMINANCE8_ALPHA8";
415         case GL_SRGB: return "GL_SRGB";
416         case GL_SRGB8: return "GL_SRGB8";
417         case GL_SRGB_ALPHA: return "GL_SRGB_ALPHA";
418         case GL_SRGB8_ALPHA8: return "GL_SRGB8_ALPHA8";
419         default:
420                 break;
421         }
422         return "unknown";
423 }
424
425 void print_compressed_formats(void)
426 {
427         int i, num_fmt;
428         int *fmtlist;
429
430         glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_fmt);
431         printf("%d generic compressed texture formats available:\n", num_fmt);
432
433         if(!(fmtlist = malloc(num_fmt * sizeof *fmtlist))) {
434                 fprintf(stderr, "failed to allocate texture formats enumeration buffer\n");
435                 return;
436         }
437         glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, fmtlist);
438
439         for(i=0; i<num_fmt; i++) {
440                 printf(" %05x: %s ", fmtlist[i], fmtstr(fmtlist[i]));
441                 GLint params;
442                 glGetInternalformativ(GL_TEXTURE_2D, fmtlist[i], GL_TEXTURE_COMPRESSED, 1, &params);
443                 printf("(%s format)\n", params == GL_TRUE ? "compressed" : "not compressed");
444         }
445         free(fmtlist);
446 }