Add more structure constructor tests.
[piglit/hramrach.git] / tests / glean / ttexenv.cpp
blobd9f16a50f02deac1d815436703aab3ed11cd0db5
1 // BEGIN_COPYRIGHT -*- glean -*-
2 //
3 // Copyright (C) 1999 Allen Akin All Rights Reserved.
4 //
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
12 // conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
16 // Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
26 //
27 // END_COPYRIGHT
30 // ttexenv.cpp: Test the basic texture env modes
31 // Author: Brian Paul (brianp@valinux.com) April 2001
33 // Test procedure:
34 // Setup a texture with 81 columns of unique RGBA colors, 3 texels each.
35 // Draw a 81 uniquely-colored flat-shaded quads as wide horizontal bands,
36 // with the above texture. This makes a matrix of 81*81 colored squares
37 // for which we test that the current texture environment mode and texture
38 // format produced the correct color.
39 // Finally, we blend over a gray background in order to verify that the
40 // post-texture alpha value is correct.
41 //
43 #include <stdlib.h>
44 #include <cassert>
45 #include <cstdio>
46 #include <cstdlib>
47 #include <cmath>
48 #include "ttexenv.h"
51 namespace GLEAN {
54 // If this is true, we enable blending over a gray background in order
55 // to test the alpha results of the texture env. If this is false,
56 // we don't blend. It might be useful to disable blending in order to
57 // diagnose failures
58 #define BLEND_WITH_BACKGROUND 1
60 static GLfloat BgColor[4] = { 0.5, 0.5, 0.5, 0.5 };
63 static const GLenum FormatEnums[] = {
64 GL_ALPHA,
65 GL_LUMINANCE,
66 GL_LUMINANCE_ALPHA,
67 GL_INTENSITY,
68 GL_RGB,
69 GL_RGBA
72 static const char *FormatNames[] = {
73 "GL_ALPHA",
74 "GL_LUMINANCE",
75 "GL_LUMINANCE_ALPHA",
76 "GL_INTENSITY",
77 "GL_RGB",
78 "GL_RGBA"
81 static const GLenum EnvModeEnums[] = {
82 GL_REPLACE,
83 GL_MODULATE,
84 GL_DECAL,
85 GL_BLEND,
86 GL_ADD
89 static const char *EnvModeNames[] = {
90 "GL_REPLACE",
91 "GL_MODULATE",
92 "GL_DECAL",
93 "GL_BLEND",
94 "GL_ADD"
99 // Test if two colors are close enough to be considered the same
101 bool
102 TexEnvTest::TestColor(const GLfloat c1[3], const GLfloat c2[3]) {
103 if (fabs(c1[0] - c2[0]) <= mTolerance[0] &&
104 fabs(c1[1] - c2[1]) <= mTolerance[1] &&
105 fabs(c1[2] - c2[2]) <= mTolerance[2])
106 return true;
107 else
108 return false;
112 // Compute expected texenv result given the texture env mode, the texture
113 // base format, texture color, fragment color, and texture env color.
114 // This also blends the result with the background color if that option
115 // is enabled (see above).
117 void
118 TexEnvTest::ComputeExpectedColor(GLenum envMode, GLenum texFormat,
119 const GLfloat texColor[4], const GLfloat fragColor[4],
120 const GLfloat envColor[4], GLfloat result[4]) {
122 switch (envMode) {
123 case GL_REPLACE:
124 switch (texFormat) {
125 case GL_ALPHA:
126 result[0] = fragColor[0];
127 result[1] = fragColor[1];
128 result[2] = fragColor[2];
129 result[3] = texColor[3]; // alpha
130 break;
131 case GL_LUMINANCE:
132 result[0] = texColor[0]; // lum
133 result[1] = texColor[0];
134 result[2] = texColor[0];
135 result[3] = fragColor[3];
136 break;
137 case GL_LUMINANCE_ALPHA:
138 result[0] = texColor[0]; // lum
139 result[1] = texColor[0];
140 result[2] = texColor[0];
141 result[3] = texColor[3]; // alpha
142 break;
143 case GL_INTENSITY:
144 result[0] = texColor[0]; // intensity
145 result[1] = texColor[0];
146 result[2] = texColor[0];
147 result[3] = texColor[0];
148 break;
149 case GL_RGB:
150 result[0] = texColor[0]; // r
151 result[1] = texColor[1]; // g
152 result[2] = texColor[2]; // b
153 result[3] = fragColor[3];
154 break;
155 case GL_RGBA:
156 result[0] = texColor[0]; // r
157 result[1] = texColor[1]; // g
158 result[2] = texColor[2]; // b
159 result[3] = texColor[3]; // a
160 break;
161 default:
162 abort(); // implementation error
164 break;
165 case GL_MODULATE:
166 switch (texFormat) {
167 case GL_ALPHA:
168 result[0] = fragColor[0];
169 result[1] = fragColor[1];
170 result[2] = fragColor[2];
171 result[3] = fragColor[3] * texColor[3];
172 break;
173 case GL_LUMINANCE:
174 result[0] = fragColor[0] * texColor[0];
175 result[1] = fragColor[1] * texColor[0];
176 result[2] = fragColor[2] * texColor[0];
177 result[3] = fragColor[3];
178 break;
179 case GL_LUMINANCE_ALPHA:
180 result[0] = fragColor[0] * texColor[0];
181 result[1] = fragColor[1] * texColor[0];
182 result[2] = fragColor[2] * texColor[0];
183 result[3] = fragColor[3] * texColor[3];
184 break;
185 case GL_INTENSITY:
186 result[0] = fragColor[0] * texColor[0];
187 result[1] = fragColor[1] * texColor[0];
188 result[2] = fragColor[2] * texColor[0];
189 result[3] = fragColor[3] * texColor[0];
190 break;
191 case GL_RGB:
192 result[0] = fragColor[0] * texColor[0];
193 result[1] = fragColor[1] * texColor[1];
194 result[2] = fragColor[2] * texColor[2];
195 result[3] = fragColor[3];
196 break;
197 case GL_RGBA:
198 result[0] = fragColor[0] * texColor[0];
199 result[1] = fragColor[1] * texColor[1];
200 result[2] = fragColor[2] * texColor[2];
201 result[3] = fragColor[3] * texColor[3];
202 break;
203 default:
204 abort(); // implementation error
206 break;
207 case GL_DECAL:
208 switch (texFormat) {
209 case GL_ALPHA:
210 result[0] = 0; // undefined
211 result[1] = 0;
212 result[2] = 0;
213 result[3] = 0;
214 break;
215 case GL_LUMINANCE:
216 result[0] = 0; // undefined
217 result[1] = 0;
218 result[2] = 0;
219 result[3] = 0;
220 break;
221 case GL_LUMINANCE_ALPHA:
222 result[0] = 0; // undefined
223 result[1] = 0;
224 result[2] = 0;
225 result[3] = 0;
226 break;
227 case GL_INTENSITY:
228 result[0] = 0; // undefined
229 result[1] = 0;
230 result[2] = 0;
231 result[3] = 0;
232 break;
233 case GL_RGB:
234 result[0] = texColor[0];
235 result[1] = texColor[1];
236 result[2] = texColor[2];
237 result[3] = fragColor[3];
238 break;
239 case GL_RGBA: {
240 const GLfloat a = texColor[3];
241 const GLfloat oma = 1.0 - a;
242 result[0] = fragColor[0] * oma + texColor[0] * a;
243 result[1] = fragColor[1] * oma + texColor[1] * a;
244 result[2] = fragColor[2] * oma + texColor[2] * a;
245 result[3] = fragColor[3];
246 } break;
247 default:
248 abort(); // implementation error
250 break;
251 case GL_BLEND:
252 switch (texFormat) {
253 case GL_ALPHA:
254 result[0] = fragColor[0];
255 result[1] = fragColor[1];
256 result[2] = fragColor[2];
257 result[3] = fragColor[3] * texColor[3];
258 break;
259 case GL_LUMINANCE: {
260 const GLfloat l = texColor[0];
261 const GLfloat oml = 1.0 - l;
262 result[0] = fragColor[0] * oml + envColor[0] * l;
263 result[1] = fragColor[1] * oml + envColor[1] * l;
264 result[2] = fragColor[2] * oml + envColor[2] * l;
265 result[3] = fragColor[3];
266 } break;
267 case GL_LUMINANCE_ALPHA: {
268 const GLfloat l = texColor[0];
269 const GLfloat oml = 1.0 - l;
270 result[0] = fragColor[0] * oml + envColor[0] * l;
271 result[1] = fragColor[1] * oml + envColor[1] * l;
272 result[2] = fragColor[2] * oml + envColor[2] * l;
273 result[3] = fragColor[3] * texColor[3];
274 } break;
275 case GL_INTENSITY: {
276 const GLfloat i = texColor[0];
277 const GLfloat omi = 1.0 - i;
278 result[0] = fragColor[0] * omi + envColor[0] * i;
279 result[1] = fragColor[1] * omi + envColor[1] * i;
280 result[2] = fragColor[2] * omi + envColor[2] * i;
281 result[3] = fragColor[3] * omi + envColor[3] * i;
282 } break;
283 case GL_RGB: {
284 const GLfloat r = texColor[0];
285 const GLfloat omr = 1.0 - r;
286 const GLfloat g = texColor[1];
287 const GLfloat omg = 1.0 - g;
288 const GLfloat b = texColor[2];
289 const GLfloat omb = 1.0 - b;
290 result[0] = fragColor[0] * omr + envColor[0] * r;
291 result[1] = fragColor[1] * omg + envColor[1] * g;
292 result[2] = fragColor[2] * omb + envColor[2] * b;
293 result[3] = fragColor[3];
294 } break;
295 case GL_RGBA: {
296 const GLfloat r = texColor[0];
297 const GLfloat omr = 1.0 - r;
298 const GLfloat g = texColor[1];
299 const GLfloat omg = 1.0 - g;
300 const GLfloat b = texColor[2];
301 const GLfloat omb = 1.0 - b;
302 result[0] = fragColor[0] * omr + envColor[0] * r;
303 result[1] = fragColor[1] * omg + envColor[1] * g;
304 result[2] = fragColor[2] * omb + envColor[2] * b;
305 result[3] = fragColor[3] * texColor[3];
306 } break;
307 default:
308 abort(); // implementation error
310 break;
311 case GL_ADD:
312 switch (texFormat) {
313 case GL_ALPHA:
314 result[0] = fragColor[0];
315 result[1] = fragColor[1];
316 result[2] = fragColor[2];
317 result[3] = fragColor[3] * texColor[3];
318 break;
319 case GL_LUMINANCE:
320 result[0] = fragColor[0] + texColor[0];
321 result[1] = fragColor[1] + texColor[0];
322 result[2] = fragColor[2] + texColor[0];
323 result[3] = fragColor[3];
324 break;
325 case GL_LUMINANCE_ALPHA:
326 result[0] = fragColor[0] + texColor[0];
327 result[1] = fragColor[1] + texColor[0];
328 result[2] = fragColor[2] + texColor[0];
329 result[3] = fragColor[3] * texColor[3];
330 break;
331 case GL_INTENSITY:
332 result[0] = fragColor[0] + texColor[0];
333 result[1] = fragColor[1] + texColor[0];
334 result[2] = fragColor[2] + texColor[0];
335 result[3] = fragColor[3] + texColor[0];
336 break;
337 case GL_RGB:
338 result[0] = fragColor[0] + texColor[0];
339 result[1] = fragColor[1] + texColor[1];
340 result[2] = fragColor[2] + texColor[2];
341 result[3] = fragColor[3];
342 break;
343 case GL_RGBA:
344 result[0] = fragColor[0] + texColor[0];
345 result[1] = fragColor[1] + texColor[1];
346 result[2] = fragColor[2] + texColor[2];
347 result[3] = fragColor[3] * texColor[3];
348 break;
349 default:
350 abort(); // implementation error
352 // clamping
353 if (result[0] > 1.0) result[0] = 1.0;
354 if (result[1] > 1.0) result[1] = 1.0;
355 if (result[2] > 1.0) result[2] = 1.0;
356 if (result[3] > 1.0) result[3] = 1.0;
357 break;
358 default:
359 // implementation error
360 abort();
363 #if BLEND_WITH_BACKGROUND
364 // now blend result over a gray background
365 const GLfloat alpha = result[3];
366 const GLfloat omAlpha = 1.0 - alpha;
367 result[0] = result[0] * alpha + BgColor[0] * omAlpha;
368 result[1] = result[1] * alpha + BgColor[1] * omAlpha;
369 result[2] = result[2] * alpha + BgColor[2] * omAlpha;
370 result[3] = result[3] * alpha + BgColor[3] * omAlpha;
371 #endif
375 // Make a texture in which the colors vary along the length
376 // according to the colors[] array. For example, we use
377 // 243 columns of the texture to store 81 colors, 3 texels each.
378 void
379 TexEnvTest::MakeTexImage(GLenum baseFormat, int numColors,
380 const GLfloat colors[][4]) {
382 const int width = 256;
383 const int height = 4;
384 GLfloat img[width * height][4];
386 assert(numColors == 81); // for now
388 for (int i = 0; i < height; i++) {
389 for (int j = 0; j < width; j++) {
390 int c = j / 3;
391 if (c >= numColors) {
392 img[i * width + j][0] = 0.0;
393 img[i * width + j][1] = 0.0;
394 img[i * width + j][2] = 0.0;
395 img[i * width + j][3] = 0.0;
397 else {
398 img[i * width + j][0] = colors[c][0];
399 img[i * width + j][1] = colors[c][1];
400 img[i * width + j][2] = colors[c][2];
401 img[i * width + j][3] = colors[c][3];
405 glTexImage2D(GL_TEXTURE_2D, 0, baseFormat, width, height, 0,
406 GL_RGBA, GL_FLOAT, (void *) img);
408 // Recompute color tolerance now because it depends on the
409 // texel resolution in the new texture.
411 // Get fb resolution
412 GLint rBits, gBits, bBits;
413 glGetIntegerv(GL_RED_BITS, &rBits);
414 glGetIntegerv(GL_GREEN_BITS, &gBits);
415 glGetIntegerv(GL_BLUE_BITS, &bBits);
416 // Get tex resolution
417 GLint rTexBits, gTexBits, bTexBits, aTexBits;
418 GLint iTexBits, lTexBits;
419 glGetTexLevelParameteriv(GL_TEXTURE_2D,
420 0, GL_TEXTURE_RED_SIZE, &rTexBits);
421 glGetTexLevelParameteriv(GL_TEXTURE_2D,
422 0, GL_TEXTURE_GREEN_SIZE, &gTexBits);
423 glGetTexLevelParameteriv(GL_TEXTURE_2D,
424 0, GL_TEXTURE_BLUE_SIZE, &bTexBits);
425 glGetTexLevelParameteriv(GL_TEXTURE_2D,
426 0, GL_TEXTURE_ALPHA_SIZE, &aTexBits);
427 glGetTexLevelParameteriv(GL_TEXTURE_2D,
428 0, GL_TEXTURE_INTENSITY_SIZE, &iTexBits);
429 glGetTexLevelParameteriv(GL_TEXTURE_2D,
430 0, GL_TEXTURE_LUMINANCE_SIZE, &lTexBits);
431 // Special cases
432 if (baseFormat == GL_INTENSITY) {
433 rTexBits = gTexBits = bTexBits = iTexBits;
435 if (baseFormat == GL_ALPHA) {
436 rTexBits = gTexBits = bTexBits = aTexBits;
438 else if (baseFormat == GL_LUMINANCE ||
439 baseFormat == GL_LUMINANCE_ALPHA) {
440 rTexBits = gTexBits = bTexBits = lTexBits;
442 // Find smaller of frame buffer and texture bits
443 rBits = (rBits < rTexBits) ? rBits : rTexBits;
444 gBits = (gBits < gTexBits) ? gBits : gTexBits;
445 bBits = (bBits < bTexBits) ? bBits : bTexBits;
446 // If these fail, something's seriously wrong.
447 assert(rBits > 0);
448 assert(gBits > 0);
449 assert(bBits > 0);
450 mTolerance[0] = 3.0 / (1 << rBits);
451 mTolerance[1] = 3.0 / (1 << gBits);
452 mTolerance[2] = 3.0 / (1 << bBits);
453 //printf("tol: %g %g %g\n", mTolerance[0],
454 // mTolerance[1], mTolerance[2]);
461 // Do numColors * numColors tests in one batch.
462 // Setup a texture in which the colors vary by column.
463 // Draw a quadstrip in which we draw horizontal bands of colors.
464 // Drawing the textured quadstrips will fill the window with
465 // numColors * numColors test squares.
466 // Verify that they're all correct.
467 // Return: true = pass, false = fail
468 bool
469 TexEnvTest::MatrixTest(GLenum envMode, GLenum texFormat,
470 const char *envName, const char *formatName,
471 int numColors, const GLfloat colors[][4],
472 const GLfloat envColor[4], Window &w) {
474 if (envMode == GL_DECAL && (texFormat != GL_RGB &&
475 texFormat != GL_RGBA)) {
476 // undefined mode
477 return true;
480 glClear(GL_COLOR_BUFFER_BIT);
482 // The texture colors are the columns
483 MakeTexImage(texFormat, numColors, colors);
485 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, envMode);
486 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor);
488 // The fragment colors are the rows
489 GLfloat W = numColors * 3;
490 GLfloat S = (float) (numColors*3) / (float) 256;
491 glBegin(GL_QUAD_STRIP);
492 glTexCoord2f(0, 0); glVertex2f(0, 0);
493 glTexCoord2f(S, 0); glVertex2f(W, 0);
494 for (int i = 0; i < numColors; i++) {
495 glColor4fv(colors[i]);
496 GLfloat y = i * 3 + 3;
497 GLfloat t = y / (numColors * 3);
498 glTexCoord2f(0, t); glVertex2f(0, y);
499 glTexCoord2f(S, t); glVertex2f(W, y);
501 glEnd();
503 const GLsizei width = 256;
504 const GLsizei height = 256;
505 GLfloat *image = new GLfloat[width*height*4];
506 glReadPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, image);
508 w.swap(); // lets us watch the progress
510 // Check results
511 for (int row = 0; row < numColors; row++) {
512 for (int col = 0; col < numColors; col++) {
514 // compute expected
515 GLfloat expected[4];
516 ComputeExpectedColor(envMode, texFormat,
517 colors[col], colors[row],
518 envColor, expected);
520 // fetch actual pixel
521 int x = col * 3 + 1;
522 int y = row * 3 + 1;
523 const GLfloat *actual = image + y*width*4 + x*4;
525 // compare
526 if (!TestColor(expected, actual)) {
527 // Report the error
528 env->log << name
529 << ": FAIL: GL_TEXTURE_ENV_MODE="
530 << envName
531 << " Texture Format="
532 << formatName
533 << " Fragment Color=("
534 << colors[row][0] << ", "
535 << colors[row][1] << ", "
536 << colors[row][2] << ", "
537 << colors[row][3] << ") "
538 << " Texture Color=("
539 << colors[col][0] << ", "
540 << colors[col][1] << ", "
541 << colors[col][2] << ", "
542 << colors[col][3] << ") "
543 << " Tex Env Color=("
544 << envColor[0] << ", "
545 << envColor[1] << ", "
546 << envColor[2] << ", "
547 << envColor[3] << ") "
548 #if BLEND_WITH_BACKGROUND
549 << " Blend over=("
550 << BgColor[0] << ", "
551 << BgColor[1] << ", "
552 << BgColor[2] << ", "
553 << BgColor[3] << ") "
554 #endif
555 << " Expected=("
556 << expected[0] << ", "
557 << expected[1] << ", "
558 << expected[2] << ", "
559 << expected[3] << ") "
560 << " Measured=("
561 << actual[0] << ", "
562 << actual[1] << ", "
563 << actual[2] << ", "
564 << actual[3] << ")\n";
565 delete[] image;
566 return false;
570 delete[] image;
571 return true;
575 void
576 TexEnvTest::runOne(BasicResult& r, Window& w) {
578 (void) w;
580 #define COLORS (3*3*3*3)
582 GLfloat colors[COLORS][4];
584 // colors[] is an array of all possible RGBA colors with component
585 // values of 0, 0.5, and 1.0
586 for (int i = 0; i < COLORS; i++) {
587 GLint r = i % 3;
588 GLint g = (i / 3) % 3;
589 GLint b = (i / 9) % 3;
590 GLint a = (i / 27) % 3;
591 colors[i][0] = (float) r / 2.0;
592 colors[i][1] = (float) g / 2.0;
593 colors[i][2] = (float) b / 2.0;
594 colors[i][3] = (float) a / 2.0;
597 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
598 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
599 glEnable(GL_TEXTURE_2D);
601 #if BLEND_WITH_BACKGROUND
602 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
603 glEnable(GL_BLEND);
604 #endif
606 glClearColor(BgColor[0], BgColor[1], BgColor[2], BgColor[3]);
607 glShadeModel(GL_FLAT);
609 glViewport(0, 0, 256, 256);
610 glMatrixMode(GL_PROJECTION);
611 glLoadIdentity();
612 glOrtho(0, 256, 0, 256, -1, 1);
613 glMatrixMode(GL_MODELVIEW);
614 glLoadIdentity();
615 glTranslatef(0.375, 0.375, 0.0);
617 int numModes;
618 if (GLUtils::haveExtensions("GL_EXT_texture_env_add") ||
619 GLUtils::haveExtensions("GL_ARB_texture_env_add"))
620 numModes = 5;
621 else
622 numModes = 4;
624 r.pass = true;
626 for (int fmt = 0; fmt < 6; fmt++) {
627 const GLenum format = FormatEnums[fmt];
628 const char *formatName = FormatNames[fmt];
629 for (int mode = 0; mode < numModes; mode++) {
630 const GLenum envMode = EnvModeEnums[mode];
631 const char *envName = EnvModeNames[mode];
632 //printf("format %s mode %s\n", FormatNames[fmt],
633 // EnvModeNames[mode]);
634 if (envMode == GL_BLEND && format != GL_ALPHA) {
635 // also vary texenv color, every 5th is OK.
636 for (int eCol = 0; eCol < COLORS; eCol += 5) {
637 const GLfloat *envColor = colors[eCol];
638 if (!MatrixTest(envMode, format,
639 envName, formatName,
640 COLORS, colors, envColor, w)) {
641 r.pass = false;
642 break;
646 else {
647 // texenv color not significant
648 if (!MatrixTest(envMode, format,
649 envName, formatName,
650 COLORS, colors, colors[0], w)) {
651 r.pass = false;
656 } // TexEnvTest::runOne
659 void
660 TexEnvTest::logOne(BasicResult& r) {
661 logPassFail(r);
662 logConcise(r);
663 } // TexEnvTest::logOne
666 ///////////////////////////////////////////////////////////////////////////////
667 // The test object itself:
668 ///////////////////////////////////////////////////////////////////////////////
669 TexEnvTest texEnvTest("texEnv", "window, rgb",
671 "Test basic texture env modes for all base texture formats.\n");
674 } // namespace GLEAN