Merge remote branch 'upstream/gallium-0.1' into nouveau-gallium-0.1
[mesa.git] / progs / tests / texfilt.c
1 /*
2 * (C) Copyright IBM Corporation 2005
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <GL/glut.h>
31
32 const GLenum filter_modes[] = {
33 GL_NEAREST,
34 GL_LINEAR,
35 GL_NEAREST_MIPMAP_NEAREST,
36 GL_NEAREST_MIPMAP_LINEAR,
37 GL_LINEAR_MIPMAP_NEAREST,
38 GL_LINEAR_MIPMAP_LINEAR,
39 };
40
41 static GLenum min_filter = GL_LINEAR_MIPMAP_LINEAR;
42 static GLenum mag_filter = GL_LINEAR;
43
44 static unsigned segments = 64;
45 static GLfloat * position_data = NULL;
46 static GLfloat * texcoord_data = NULL;
47 static GLfloat max_anisotropy = 0.0;
48 static GLfloat anisotropy = 1.0;
49
50 static void generate_tunnel( unsigned num_segs, GLfloat ** pos_data,
51 GLfloat ** tex_data );
52 static void generate_textures( unsigned mode );
53
54 #define min(a,b) ( (a) < (b) ) ? (a) : (b)
55 #define max(a,b) ( (a) > (b) ) ? (a) : (b)
56
57
58 static void Display( void )
59 {
60 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter );
61 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter );
62
63 if ( max_anisotropy > 0.0 ) {
64 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
65 anisotropy );
66 }
67
68 glClear( GL_COLOR_BUFFER_BIT );
69 glLoadIdentity();
70 glTranslatef( 0.0f, 0.0f, -19.0f );
71
72 glVertexPointer( 4, GL_FLOAT, 0, position_data );
73 glTexCoordPointer( 2, GL_FLOAT, 0, texcoord_data );
74 glEnableClientState( GL_VERTEX_ARRAY );
75 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
76 glDrawArrays( GL_QUADS, 0, 4 * segments );
77 glutSwapBuffers();
78 }
79
80
81 static void Reshape( int width, int height )
82 {
83 glViewport(0, 0, width, height);
84 glMatrixMode(GL_PROJECTION);
85 glLoadIdentity();
86 gluPerspective(45.0f, (GLfloat)(width)/(GLfloat)(height), 0.1f, 100.0f);
87 glMatrixMode(GL_MODELVIEW);
88 glLoadIdentity();
89 }
90
91
92 static void Key( unsigned char key, int x, int y )
93 {
94 GLfloat new_anisotropy = anisotropy;
95
96 (void) x;
97 (void) y;
98
99
100 switch( key ) {
101 case 'a': {
102 new_anisotropy = anisotropy - 1.0;
103 break;
104 }
105
106 case 'A': {
107 new_anisotropy = anisotropy + 1.0;
108 break;
109 }
110
111 case 's': {
112 segments--;
113 if ( segments < 3 ) {
114 segments = 3;
115 }
116 generate_tunnel( segments, & position_data, & texcoord_data );
117 break;
118 }
119
120 case 'S': {
121 segments++;
122 if ( segments > 128 ) {
123 segments = 128;
124 }
125 generate_tunnel( segments, & position_data, & texcoord_data );
126 break;
127 }
128 case 'q':
129 case 'Q':
130 case 27:
131 exit(0);
132 break;
133 }
134
135 new_anisotropy = max( new_anisotropy, 1.0 );
136 new_anisotropy = min( new_anisotropy, max_anisotropy );
137 if ( new_anisotropy != anisotropy ) {
138 anisotropy = new_anisotropy;
139 printf( "Texture anisotropy: %f%s\n", anisotropy,
140 (anisotropy == 1.0) ? " (disabled)" : "" );
141 }
142
143 glutPostRedisplay();
144 }
145
146
147 static void SpecialKey( int key, int x, int y )
148 {
149 (void) x;
150 (void) y;
151 (void) key;
152 glutPostRedisplay();
153 }
154
155
156 static void menu_handler( int selection )
157 {
158 switch( selection >> 3 ) {
159 case 0:
160 glBindTexture( GL_TEXTURE_2D, selection );
161 break;
162
163 case 1:
164 min_filter = filter_modes[ selection & 7 ];
165 break;
166
167 case 2:
168 mag_filter = filter_modes[ selection & 7 ];
169 break;
170 }
171
172 glutPostRedisplay();
173 }
174
175
176 static void Init( void )
177 {
178 glDisable(GL_CULL_FACE);
179 glEnable(GL_TEXTURE_2D);
180 glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
181 glShadeModel(GL_SMOOTH);
182 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
183
184 generate_tunnel( segments, & position_data, & texcoord_data );
185
186 glBindTexture( GL_TEXTURE_2D, 1 );
187 generate_textures(1);
188
189 glBindTexture( GL_TEXTURE_2D, 2 );
190 generate_textures(2);
191
192 glBindTexture( GL_TEXTURE_2D, 3 );
193 generate_textures(3);
194
195 if ( glutExtensionSupported( "GL_EXT_texture_filter_anisotropic" ) ) {
196 glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, & max_anisotropy );
197 }
198
199 printf("Maximum texture anisotropy: %f\n", max_anisotropy );
200
201 /* Create the menus. */
202
203 glutCreateMenu( menu_handler );
204 glutAddMenuEntry( "Min filter: GL_NEAREST", 8 + 0 );
205 glutAddMenuEntry( "Min filter: GL_LINEAR", 8 + 1 );
206 glutAddMenuEntry( "Min filter: GL_NEAREST_MIMMAP_NEAREST", 8 + 2 );
207 glutAddMenuEntry( "Min filter: GL_NEAREST_MIMMAP_LINEAR", 8 + 3 );
208 glutAddMenuEntry( "Min filter: GL_LINEAR_MIMMAP_NEAREST", 8 + 4 );
209 glutAddMenuEntry( "Min filter: GL_LINEAR_MIMMAP_LINEAR", 8 + 5 );
210 glutAddMenuEntry( "Mag filter: GL_NEAREST", 16 + 0 );
211 glutAddMenuEntry( "Mag filter: GL_LINEAR", 16 + 1 );
212 glutAddMenuEntry( "Texture: regular mipmaps", 1 );
213 glutAddMenuEntry( "Texture: blended mipmaps", 2 );
214 glutAddMenuEntry( "Texture: color mipmaps", 3 );
215 glutAttachMenu( GLUT_RIGHT_BUTTON );
216 }
217
218
219 static void generate_tunnel( unsigned num_segs, GLfloat ** pos_data,
220 GLfloat ** tex_data )
221 {
222 const GLfloat far = 20.0f;
223 const GLfloat near = -90.0f;
224 const GLfloat far_tex = 30.0f;
225 const GLfloat near_tex = 0.0f;
226 const GLfloat angle_step = (2 * M_PI) / num_segs;
227 const GLfloat tex_coord_step = 2.0 / num_segs;
228 GLfloat angle = 0.0f;
229 GLfloat tex_coord = 0.0f;
230 unsigned i;
231 GLfloat * position;
232 GLfloat * texture;
233
234
235 position = realloc( *pos_data, sizeof( GLfloat ) * num_segs * 4 * 4 );
236 texture = realloc( *tex_data, sizeof( GLfloat ) * num_segs * 4 * 2 );
237
238 *pos_data = position;
239 *tex_data = texture;
240
241 for ( i = 0 ; i < num_segs ; i++ ) {
242 position[0] = 2.5 * sinf( angle );
243 position[1] = 2.5 * cosf( angle );
244 position[2] = (i & 1) ? far : near;
245 position[3] = 1.0f;
246
247 position[4] = position[0];
248 position[5] = position[1];
249 position[6] = (i & 1) ? near : far;
250 position[7] = 1.0f;
251
252 position += 8;
253
254 texture[0] = tex_coord;
255 texture[1] = (i & 1) ? far_tex : near_tex;
256 texture += 2;
257
258 texture[0] = tex_coord;
259 texture[1] = (i & 1) ? near_tex : far_tex;
260 texture += 2;
261
262 angle += angle_step;
263 tex_coord += tex_coord_step;
264
265 position[0] = 2.5 * sinf( angle );
266 position[1] = 2.5 * cosf( angle );
267 position[2] = (i & 1) ? near : far;
268 position[3] = 1.0f;
269
270 position[4] = position[0];
271 position[5] = position[1];
272 position[6] = (i & 1) ? far : near;
273 position[7] = 1.0f;
274
275 position += 8;
276
277 texture[0] = tex_coord;
278 texture[1] = (i & 1) ? near_tex : far_tex;
279 texture += 2;
280
281 texture[0] = tex_coord;
282 texture[1] = (i & 1) ? far_tex : near_tex;
283 texture += 2;
284 }
285 }
286
287
288 static void generate_textures( unsigned mode )
289 {
290 #define LEVEL_COLORS 6
291 const GLfloat colors[LEVEL_COLORS][3] = {
292 { 1.0, 0.0, 0.0 }, /* 32 x 32 */
293 { 0.0, 1.0, 0.0 }, /* 16 x 16 */
294 { 0.0, 0.0, 1.0 }, /* 8 x 8 */
295 { 1.0, 0.0, 1.0 }, /* 4 x 4 */
296 { 1.0, 1.0, 1.0 }, /* 2 x 2 */
297 { 1.0, 1.0, 0.0 } /* 1 x 1 */
298 };
299 const unsigned checkers_per_level = 2;
300 GLfloat * tex;
301 unsigned level;
302 unsigned size;
303 GLint max_size;
304
305
306 glGetIntegerv( GL_MAX_TEXTURE_SIZE, & max_size );
307 if ( max_size > 512 ) {
308 max_size = 512;
309 }
310
311 tex = malloc( sizeof( GLfloat ) * 3 * max_size * max_size );
312
313 level = 0;
314 for ( size = max_size ; size > 0 ; size >>= 1 ) {
315 unsigned divisor = size / checkers_per_level;
316 unsigned i;
317 unsigned j;
318 GLfloat checkers[2][3];
319
320
321 if ((level == 0) || (mode == 1)) {
322 checkers[0][0] = 1.0;
323 checkers[0][1] = 1.0;
324 checkers[0][2] = 1.0;
325 checkers[1][0] = 0.0;
326 checkers[1][1] = 0.0;
327 checkers[1][2] = 0.0;
328 }
329 else if (mode == 2) {
330 checkers[0][0] = colors[level % LEVEL_COLORS][0];
331 checkers[0][1] = colors[level % LEVEL_COLORS][1];
332 checkers[0][2] = colors[level % LEVEL_COLORS][2];
333 checkers[1][0] = colors[level % LEVEL_COLORS][0] * 0.5;
334 checkers[1][1] = colors[level % LEVEL_COLORS][1] * 0.5;
335 checkers[1][2] = colors[level % LEVEL_COLORS][2] * 0.5;
336 }
337 else {
338 checkers[0][0] = colors[level % LEVEL_COLORS][0];
339 checkers[0][1] = colors[level % LEVEL_COLORS][1];
340 checkers[0][2] = colors[level % LEVEL_COLORS][2];
341 checkers[1][0] = colors[level % LEVEL_COLORS][0];
342 checkers[1][1] = colors[level % LEVEL_COLORS][1];
343 checkers[1][2] = colors[level % LEVEL_COLORS][2];
344 }
345
346 if ( divisor == 0 ) {
347 divisor = 1;
348
349 checkers[0][0] = (checkers[0][0] + checkers[1][0]) / 2;
350 checkers[0][1] = (checkers[0][0] + checkers[1][0]) / 2;
351 checkers[0][2] = (checkers[0][0] + checkers[1][0]) / 2;
352 checkers[1][0] = checkers[0][0];
353 checkers[1][1] = checkers[0][1];
354 checkers[1][2] = checkers[0][2];
355 }
356
357
358 for ( i = 0 ; i < size ; i++ ) {
359 for ( j = 0 ; j < size ; j++ ) {
360 const unsigned idx = ((i ^ j) / divisor) & 1;
361
362 tex[ ((i * size) + j) * 3 + 0] = checkers[ idx ][0];
363 tex[ ((i * size) + j) * 3 + 1] = checkers[ idx ][1];
364 tex[ ((i * size) + j) * 3 + 2] = checkers[ idx ][2];
365 }
366 }
367
368 glTexImage2D( GL_TEXTURE_2D, level, GL_RGB, size, size, 0,
369 GL_RGB, GL_FLOAT, tex );
370 level++;
371 }
372
373 free( tex );
374 }
375
376
377 int main( int argc, char ** argv )
378 {
379 glutInit( &argc, argv );
380 glutInitWindowPosition( 0, 0 );
381 glutInitWindowSize( 800, 600 );
382 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
383 glutCreateWindow( "Texture Filter Test" );
384 glutReshapeFunc( Reshape );
385 glutKeyboardFunc( Key );
386 glutSpecialFunc( SpecialKey );
387 glutDisplayFunc( Display );
388
389 Init();
390
391 printf("\nUse the right-button menu to select the texture and filter mode.\n");
392 printf("Use 'A' and 'a' to increase and decrease the aniotropy.\n");
393 printf("Use 'S' and 's' to increase and decrease the number of cylinder segments.\n");
394 printf("Use 'q' to exit.\n\n");
395
396 glutMainLoop();
397 return 0;
398 }