7 #include <GL/freeglut.h>
13 unsigned int compsize;
19 void reshape(int x, int y);
20 void keyb(unsigned char key, int x, int y);
22 int load_texture(const char *fname, struct texture *tex);
23 const char *fmtstr(int fmt);
24 void print_compressed_formats(void);
29 int subtest, copytest;
31 int main(int argc, char **argv)
34 unsigned int glut_flags = GLUT_RGB | GLUT_DOUBLE;
36 for(i=1; i<argc; i++) {
37 if(argv[i][0] == '-') {
38 if(strcmp(argv[i], "-subtest") == 0) {
40 } else if(strcmp(argv[i], "-copytest") == 0) {
42 } else if(strcmp(argv[i], "-copytest-loop") == 0) {
46 fprintf(stderr, "invalid option: %s\n", argv[i]);
51 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
59 fprintf(stderr, "you must specify a compressed texture file\n");
63 glutInit(&argc, argv);
64 glutInitDisplayMode(glut_flags);
65 glutCreateWindow("test");
67 glutDisplayFunc(disp);
68 glutReshapeFunc(reshape);
69 glutKeyboardFunc(keyb);
91 print_compressed_formats();
93 if(load_texture(texfile, &tex) == -1) {
94 fprintf(stderr, "failed to load texture %s\n", texfile);
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);
104 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &is_comp);
106 fprintf(stderr, "texture is not compressed\n");
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);
115 if(!(buf = malloc(tex.compsize))) {
116 fprintf(stderr, "failed to allocate comparison image buffer (%d bytes)\n", tex.compsize);
119 glGetCompressedTexImage(GL_TEXTURE_2D, 0, buf);
121 if(memcmp(tex.data, buf, tex.compsize) != 0) {
123 unsigned char *a = tex.data, *b = buf;
125 for(i=0; i<tex.compsize; i++) {
126 if(*a++ != *b++) break;
128 assert(i < tex.compsize);
129 fprintf(stderr, "submitted and retrieved pixel data differ! (at offset %d)\n", i);
131 printf("submitted and retrieved sizes match (%d bytes)\n", tex.compsize);
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);
142 printf("testing glCopyImageSubData\n");
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);
151 glCopyImageSubData(tex2, GL_TEXTURE_2D, 0, 128, 64, 0,
152 tex.id, GL_TEXTURE_2D, 0, 32, 32, 0, 64, 64, 1);
154 glBindTexture(GL_TEXTURE_2D, tex.id);
159 glEnable(GL_TEXTURE_2D);
167 int ysz = tex.height;
169 glClear(GL_COLOR_BUFFER_BIT);
171 glBindTexture(GL_TEXTURE_2D, tex.id);
172 glEnable(GL_TEXTURE_2D);
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);
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);
198 assert(glGetError() == GL_NO_ERROR);
201 void reshape(int x, int y)
203 glViewport(0, 0, x, y);
205 glMatrixMode(GL_PROJECTION);
207 glOrtho(0, x, 0, y, -1, 1);
210 void keyb(unsigned char key, int x, int y)
222 void gen_image(unsigned char *pixels, int xsz, int ysz)
226 for(i=0; i<ysz; i++) {
227 for(j=0; j<xsz; j++) {
230 *pixels++ = xor & 0xff;
231 *pixels++ = (xor << 1) & 0xff;
232 *pixels++ = (xor << 2) & 0xff;
242 uint32_t width, height;
244 uint32_t offset, size;
249 int load_texture(const char *fname, struct texture *tex)
256 if(!(fp = fopen(fname, "rb"))) {
257 fprintf(stderr, "failed to open file: %s: %s\n", fname, strerror(errno));
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));
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);
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));
278 if(!(tex->data = malloc(hdr.datadesc[0].size))) {
279 fprintf(stderr, "failed to allocate data buffer\n");
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);
292 tex->fmt = hdr.glfmt;
293 tex->width = hdr.width;
294 tex->height = hdr.height;
295 tex->compsize = hdr.datadesc[0].size;
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);
300 for(i=0; i<hdr.levels; i++) {
301 if(!hdr.datadesc[i].size) {
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);
309 glDeleteTextures(1, &tex->id);
313 memcpy(tex->data, buf, hdr.datadesc[0].size);
315 glCompressedTexImage2D(GL_TEXTURE_2D, i, hdr.glfmt, hdr.width, hdr.height, 0,
316 hdr.datadesc[i].size, buf);
327 const char *fmtstr(int 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";
402 return "GL_LUMINANCE";
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";
425 void print_compressed_formats(void)
430 glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_fmt);
431 printf("%d generic compressed texture formats available:\n", num_fmt);
433 if(!(fmtlist = malloc(num_fmt * sizeof *fmtlist))) {
434 fprintf(stderr, "failed to allocate texture formats enumeration buffer\n");
437 glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, fmtlist);
439 for(i=0; i<num_fmt; i++) {
440 printf(" %05x: %s ", fmtlist[i], fmtstr(fmtlist[i]));
442 glGetInternalformativ(GL_TEXTURE_2D, fmtlist[i], GL_TEXTURE_COMPRESSED, 1, ¶ms);
443 printf("(%s format)\n", params == GL_TRUE ? "compressed" : "not compressed");