1 // BEGIN_COPYRIGHT -*- glean -*-
3 // Copyright (C) 1999 Allen Akin All Rights Reserved.
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
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
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.
30 // ttexenv.cpp: Test the basic texture env modes
31 // Author: Brian Paul (brianp@valinux.com) April 2001
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.
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
58 #define BLEND_WITH_BACKGROUND 1
60 static GLfloat BgColor
[4] = { 0.5, 0.5, 0.5, 0.5 };
63 static const GLenum FormatEnums
[] = {
72 static const char *FormatNames
[] = {
81 static const GLenum EnvModeEnums
[] = {
89 static const char *EnvModeNames
[] = {
99 // Test if two colors are close enough to be considered the same
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])
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).
118 TexEnvTest::ComputeExpectedColor(GLenum envMode
, GLenum texFormat
,
119 const GLfloat texColor
[4], const GLfloat fragColor
[4],
120 const GLfloat envColor
[4], GLfloat result
[4]) {
126 result
[0] = fragColor
[0];
127 result
[1] = fragColor
[1];
128 result
[2] = fragColor
[2];
129 result
[3] = texColor
[3]; // alpha
132 result
[0] = texColor
[0]; // lum
133 result
[1] = texColor
[0];
134 result
[2] = texColor
[0];
135 result
[3] = fragColor
[3];
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
144 result
[0] = texColor
[0]; // intensity
145 result
[1] = texColor
[0];
146 result
[2] = texColor
[0];
147 result
[3] = texColor
[0];
150 result
[0] = texColor
[0]; // r
151 result
[1] = texColor
[1]; // g
152 result
[2] = texColor
[2]; // b
153 result
[3] = fragColor
[3];
156 result
[0] = texColor
[0]; // r
157 result
[1] = texColor
[1]; // g
158 result
[2] = texColor
[2]; // b
159 result
[3] = texColor
[3]; // a
162 abort(); // implementation error
168 result
[0] = fragColor
[0];
169 result
[1] = fragColor
[1];
170 result
[2] = fragColor
[2];
171 result
[3] = fragColor
[3] * texColor
[3];
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];
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];
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];
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];
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];
204 abort(); // implementation error
210 result
[0] = 0; // undefined
216 result
[0] = 0; // undefined
221 case GL_LUMINANCE_ALPHA
:
222 result
[0] = 0; // undefined
228 result
[0] = 0; // undefined
234 result
[0] = texColor
[0];
235 result
[1] = texColor
[1];
236 result
[2] = texColor
[2];
237 result
[3] = fragColor
[3];
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];
248 abort(); // implementation error
254 result
[0] = fragColor
[0];
255 result
[1] = fragColor
[1];
256 result
[2] = fragColor
[2];
257 result
[3] = fragColor
[3] * texColor
[3];
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];
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];
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
;
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];
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];
308 abort(); // implementation error
314 result
[0] = fragColor
[0];
315 result
[1] = fragColor
[1];
316 result
[2] = fragColor
[2];
317 result
[3] = fragColor
[3] * texColor
[3];
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];
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];
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];
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];
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];
350 abort(); // implementation error
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;
359 // implementation error
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
;
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.
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
++) {
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;
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.
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
);
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.
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
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
)) {
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
);
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
511 for (int row
= 0; row
< numColors
; row
++) {
512 for (int col
= 0; col
< numColors
; col
++) {
516 ComputeExpectedColor(envMode
, texFormat
,
517 colors
[col
], colors
[row
],
520 // fetch actual pixel
523 const GLfloat
*actual
= image
+ y
*width
*4 + x
*4;
526 if (!TestColor(expected
, actual
)) {
529 << ": FAIL: GL_TEXTURE_ENV_MODE="
531 << " Texture Format="
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
550 << BgColor
[0] << ", "
551 << BgColor
[1] << ", "
552 << BgColor
[2] << ", "
553 << BgColor
[3] << ") "
556 << expected
[0] << ", "
557 << expected
[1] << ", "
558 << expected
[2] << ", "
559 << expected
[3] << ") "
564 << actual
[3] << ")\n";
576 TexEnvTest::runOne(BasicResult
& r
, Window
& 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
++) {
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
);
606 glClearColor(BgColor
[0], BgColor
[1], BgColor
[2], BgColor
[3]);
607 glShadeModel(GL_FLAT
);
609 glViewport(0, 0, 256, 256);
610 glMatrixMode(GL_PROJECTION
);
612 glOrtho(0, 256, 0, 256, -1, 1);
613 glMatrixMode(GL_MODELVIEW
);
615 glTranslatef(0.375, 0.375, 0.0);
618 if (GLUtils::haveExtensions("GL_EXT_texture_env_add") ||
619 GLUtils::haveExtensions("GL_ARB_texture_env_add"))
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
,
640 COLORS
, colors
, envColor
, w
)) {
647 // texenv color not significant
648 if (!MatrixTest(envMode
, format
,
650 COLORS
, colors
, colors
[0], w
)) {
656 } // TexEnvTest::runOne
660 TexEnvTest::logOne(BasicResult
& 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");