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