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 // ttexcombine.cpp: Test the GL_EXT_texture_env_combine extension
31 // Author: Brian Paul (brianp@valinux.com) September 2000
33 // GL_EXT_texture_env_dot3 extension test
34 // Author: Gareth Hughes (gareth@valinux.com) January 2001
36 // GL_ARB_texture_env_crossbar extension test
37 // Author: Brian Paul (brian@tungstengraphics.com) December 2002
39 // The challenge with testing this extension is dealing with combinatorial
40 // explosion. There are 16 state variables in this extension:
42 // GL_COMBINE_RGB_EXT which has 5 possible values
43 // GL_COMBINE_ALPHA_EXT which has 5 possible values
44 // GL_SOURCE0_RGB_EXT which has 4 possible values
45 // GL_SOURCE1_RGB_EXT which has 4 possible values
46 // GL_SOURCE2_RGB_EXT which has 4 possible values
47 // GL_SOURCE0_ALPHA_EXT which has 4 possible values
48 // GL_SOURCE1_ALPHA_EXT which has 4 possible values
49 // GL_SOURCE2_ALPHA_EXT which has 4 possible values
50 // GL_OPERAND0_RGB_EXT which has 4 possible values
51 // GL_OPERAND1_RGB_EXT which has 4 possible values
52 // GL_OPERAND2_RGB_EXT which has 2 possible values
53 // GL_OPERAND0_ALPHA_EXT which has 2 possible values
54 // GL_OPERAND1_ALPHA_EXT which has 2 possible values
55 // GL_OPERAND2_ALPHA_EXT which has 1 possible value
56 // GL_RGB_SCALE_EXT which has 3 possible values
57 // GL_ALPHA_SCALE which has 3 possible values
59 // The product of those values is 117,964,800. And that's just for one
60 // texture unit! If we wanted to fully exercise N texture units we'd
61 // need to run 117,964,800 ^ N tests! Ideally we'd also like to test
62 // with a number of different fragment, texenv and texture colors.
63 // Clearly we can't test everything.
65 // So, we've partitioned the combination space into subsets defined
66 // by the ReplaceParams[], AddParams[], InterpolateParams[], etc arrays.
67 // For multitexture, we do an even more limited set of tests: testing
68 // all permutations of the 5 combine modes on all texture units.
70 // In the future we might look at programs that use the combine
71 // extension to see which mode combination are important to them and
72 // put them into this test.
75 #include "ttexcombine.h"
80 #define CLAMP(VAL, MIN, MAX) \
81 ((VAL) < (MIN) ? (MIN) : ((VAL) > (MAX) ? (MAX) : (VAL)))
83 #define COPY4(DST, SRC) \
85 (DST)[0] = (SRC)[0]; \
86 (DST)[1] = (SRC)[1]; \
87 (DST)[2] = (SRC)[2]; \
88 (DST)[3] = (SRC)[3]; \
95 // These objects define the space of tex-env combinations that we exercise.
96 // Each array element is { state-var, { list of possible values, 0 } }.
99 TexCombineTest::test_param
TexCombineTest::ReplaceParams
[] = {
100 { GL_COMBINE_RGB_EXT
, { GL_REPLACE
, 0 } },
101 { GL_COMBINE_ALPHA_EXT
, { GL_REPLACE
, 0 } },
102 { GL_SOURCE0_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
103 { GL_SOURCE0_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
104 { GL_OPERAND0_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
105 { GL_OPERAND0_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
106 { GL_RGB_SCALE_EXT
, { 1, 2, 4, 0 } },
107 { GL_ALPHA_SCALE
, { 1, 2, 4, 0 } },
108 { 0, { 0, 0, 0, 0, 0 } }
111 TexCombineTest::test_param
TexCombineTest::AddParams
[] = {
112 { GL_COMBINE_RGB_EXT
, { GL_ADD
, 0 } },
113 { GL_COMBINE_ALPHA_EXT
, { GL_ADD
, 0 } },
114 { GL_SOURCE0_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
115 { GL_SOURCE1_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PREVIOUS_EXT
, 0 } },
116 { GL_SOURCE0_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
117 { GL_SOURCE1_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PREVIOUS_EXT
, 0 } },
118 { GL_OPERAND0_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
119 { GL_OPERAND1_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
120 { GL_OPERAND0_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
121 { GL_OPERAND1_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
122 { GL_RGB_SCALE_EXT
, { 1, 2, 4, 0 } },
123 { GL_ALPHA_SCALE
, { 1, 2, 4, 0 } },
124 { 0, { 0, 0, 0, 0, 0 } }
127 TexCombineTest::test_param
TexCombineTest::ModulateParams
[] = {
128 { GL_COMBINE_RGB_EXT
, { GL_MODULATE
, 0 } },
129 { GL_COMBINE_ALPHA_EXT
, { GL_MODULATE
, 0 } },
130 { GL_SOURCE0_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, 0 } },
131 { GL_SOURCE1_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
132 { GL_SOURCE0_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, 0 } },
133 { GL_SOURCE1_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
134 { GL_OPERAND0_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
135 { GL_OPERAND1_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
136 { GL_OPERAND0_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
137 { GL_OPERAND1_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
138 { GL_RGB_SCALE_EXT
, { 1, 2, 4, 0 } },
139 { GL_ALPHA_SCALE
, { 1, 2, 4, 0 } },
140 { 0, { 0, 0, 0, 0, 0 } }
143 TexCombineTest::test_param
TexCombineTest::AddSignedParams
[] = {
144 { GL_COMBINE_RGB_EXT
, { GL_ADD_SIGNED_EXT
, 0 } },
145 { GL_COMBINE_ALPHA_EXT
, { GL_ADD_SIGNED_EXT
, 0 } },
146 { GL_SOURCE0_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, 0 } },
147 { GL_SOURCE1_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
148 { GL_SOURCE0_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, 0 } },
149 { GL_SOURCE1_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
150 { GL_OPERAND0_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
151 { GL_OPERAND1_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
152 { GL_OPERAND0_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
153 { GL_OPERAND1_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
154 { GL_RGB_SCALE_EXT
, { 1, 2, 4, 0 } },
155 { GL_ALPHA_SCALE
, { 1, 2, 4, 0 } },
156 { 0, { 0, 0, 0, 0, 0 } }
159 TexCombineTest::test_param
TexCombineTest::InterpolateParams
[] = {
160 { GL_COMBINE_RGB_EXT
, { GL_INTERPOLATE_EXT
, 0 } },
161 { GL_COMBINE_ALPHA_EXT
, { GL_INTERPOLATE_EXT
, 0 } },
162 { GL_SOURCE0_RGB_EXT
, { GL_TEXTURE
, GL_PRIMARY_COLOR_EXT
, 0 } },
163 { GL_SOURCE1_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
164 { GL_SOURCE2_RGB_EXT
, { GL_TEXTURE
, GL_PRIMARY_COLOR_EXT
, 0 } },
165 { GL_SOURCE0_ALPHA_EXT
, { GL_TEXTURE
, GL_PRIMARY_COLOR_EXT
, 0 } },
166 { GL_SOURCE1_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
167 { GL_SOURCE2_ALPHA_EXT
, { GL_TEXTURE
, GL_PRIMARY_COLOR_EXT
, 0 } },
168 { GL_OPERAND0_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
169 { GL_OPERAND1_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
170 { GL_OPERAND2_RGB_EXT
, { GL_SRC_ALPHA
, 0 } },
171 { GL_OPERAND0_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
172 { GL_OPERAND1_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
173 { GL_OPERAND2_ALPHA_EXT
, { GL_SRC_ALPHA
, 0 } },
174 { GL_RGB_SCALE_EXT
, { 1, 4, 0 } },
175 { GL_ALPHA_SCALE
, { 1, 2, 0 } },
176 { 0, { 0, 0, 0, 0, 0 } }
179 TexCombineTest::test_param
TexCombineTest::Dot3RGBParams
[] = {
180 { GL_COMBINE_RGB_EXT
, { GL_DOT3_RGB_EXT
, 0 } },
181 { GL_COMBINE_ALPHA_EXT
, { GL_MODULATE
, 0 } },
182 { GL_SOURCE0_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, 0 } },
183 { GL_SOURCE1_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
184 { GL_SOURCE0_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, 0 } },
185 { GL_SOURCE1_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
186 { GL_OPERAND0_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
187 { GL_OPERAND1_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
188 { GL_OPERAND0_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
189 { GL_OPERAND1_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
190 { GL_RGB_SCALE_EXT
, { 1, 2, 4, 0 } },
191 { GL_ALPHA_SCALE
, { 1, 2, 4, 0 } },
192 { 0, { 0, 0, 0, 0, 0 } }
195 TexCombineTest::test_param
TexCombineTest::Dot3RGBAParams
[] = {
196 { GL_COMBINE_RGB_EXT
, { GL_DOT3_RGBA_EXT
, 0 } },
197 { GL_COMBINE_ALPHA_EXT
, { GL_MODULATE
, 0 } },
198 { GL_SOURCE0_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, 0 } },
199 { GL_SOURCE1_RGB_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
200 { GL_SOURCE0_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, 0 } },
201 { GL_SOURCE1_ALPHA_EXT
, { GL_TEXTURE
, GL_CONSTANT_EXT
, GL_PRIMARY_COLOR_EXT
, GL_PREVIOUS_EXT
, 0 } },
202 { GL_OPERAND0_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
203 { GL_OPERAND1_RGB_EXT
, { GL_SRC_COLOR
, GL_ONE_MINUS_SRC_COLOR
, GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
204 { GL_OPERAND0_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
205 { GL_OPERAND1_ALPHA_EXT
, { GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, 0 } },
206 { GL_RGB_SCALE_EXT
, { 1, 2, 4, 0 } },
207 { GL_ALPHA_SCALE
, { 1, 2, 4, 0 } },
208 { 0, { 0, 0, 0, 0, 0 } }
213 problem(const char *s
) {
214 cerr
<< "Problem in combine():" << s
<< "\n";
219 // Set machine parameters to default values.
222 TexCombineTest::ResetMachine(glmachine
&machine
) {
223 for (int u
= 0; u
< MAX_TEX_UNITS
; u
++) {
224 machine
.COMBINE_RGB
[u
] = GL_MODULATE
;
225 machine
.COMBINE_ALPHA
[u
] = GL_MODULATE
;
226 machine
.SOURCE0_RGB
[u
] = GL_TEXTURE
;
227 machine
.SOURCE1_RGB
[u
] = GL_PREVIOUS_EXT
;
228 machine
.SOURCE2_RGB
[u
] = GL_CONSTANT_EXT
;
229 machine
.SOURCE0_ALPHA
[u
] = GL_TEXTURE
;
230 machine
.SOURCE1_ALPHA
[u
] = GL_PREVIOUS_EXT
;
231 machine
.SOURCE2_ALPHA
[u
] = GL_CONSTANT_EXT
;
232 machine
.OPERAND0_RGB
[u
] = GL_SRC_COLOR
;
233 machine
.OPERAND1_RGB
[u
] = GL_SRC_COLOR
;
234 machine
.OPERAND2_RGB
[u
] = GL_SRC_ALPHA
;
235 machine
.OPERAND0_ALPHA
[u
] = GL_SRC_ALPHA
;
236 machine
.OPERAND1_ALPHA
[u
] = GL_SRC_ALPHA
;
237 machine
.OPERAND2_ALPHA
[u
] = GL_SRC_ALPHA
;
238 machine
.RGB_SCALE
[u
] = 1.0;
239 machine
.ALPHA_SCALE
[u
] = 1.0;
240 machine
.TexFormat
[u
] = GL_RGBA
;
246 // This computes the expected texcombine result for one texture unit.
249 TexCombineTest::ComputeTexCombine(const glmachine
&machine
, int texUnit
,
250 const GLfloat prevColor
[4],
251 GLfloat result
[4]) const {
252 GLfloat term0
[4], term1
[4], term2
[4], dot
;
253 const GLfloat
*colorSrc0
, *colorSrc1
, *colorSrc2
;
254 const GLfloat
*alphaSrc0
, *alphaSrc1
= NULL
, *alphaSrc2
= NULL
;
255 const GLfloat
*fragColor
= machine
.FragColor
;
256 const GLfloat
*constColor
= machine
.EnvColor
[texUnit
];
257 const GLfloat
*texColor
= machine
.TexColor
[texUnit
];
260 switch (machine
.SOURCE0_RGB
[texUnit
]) {
261 case GL_PRIMARY_COLOR_EXT
:
262 colorSrc0
= fragColor
;
265 colorSrc0
= texColor
;
267 case GL_CONSTANT_EXT
:
268 colorSrc0
= constColor
;
270 case GL_PREVIOUS_EXT
:
271 colorSrc0
= prevColor
;
273 case GL_TEXTURE0_ARB
:
274 case GL_TEXTURE1_ARB
:
275 case GL_TEXTURE2_ARB
:
276 case GL_TEXTURE3_ARB
:
277 case GL_TEXTURE4_ARB
:
278 case GL_TEXTURE5_ARB
:
279 case GL_TEXTURE6_ARB
:
280 case GL_TEXTURE7_ARB
:
281 /* GL_ARB_texture_env_crossbar */
282 srcUnit
= machine
.SOURCE0_RGB
[texUnit
] - GL_TEXTURE0_ARB
;
283 colorSrc0
= machine
.TexColor
[srcUnit
];
286 problem("bad rgbSource0");
290 switch (machine
.SOURCE0_ALPHA
[texUnit
]) {
291 case GL_PRIMARY_COLOR_EXT
:
292 alphaSrc0
= fragColor
;
295 alphaSrc0
= texColor
;
297 case GL_CONSTANT_EXT
:
298 alphaSrc0
= constColor
;
300 case GL_PREVIOUS_EXT
:
301 alphaSrc0
= prevColor
;
303 case GL_TEXTURE0_ARB
:
304 case GL_TEXTURE1_ARB
:
305 case GL_TEXTURE2_ARB
:
306 case GL_TEXTURE3_ARB
:
307 case GL_TEXTURE4_ARB
:
308 case GL_TEXTURE5_ARB
:
309 case GL_TEXTURE6_ARB
:
310 case GL_TEXTURE7_ARB
:
311 /* GL_ARB_texture_env_crossbar */
312 srcUnit
= machine
.SOURCE0_ALPHA
[texUnit
] - GL_TEXTURE0_ARB
;
313 alphaSrc0
= machine
.TexColor
[srcUnit
];
316 problem("bad alphaSource0");
320 switch (machine
.SOURCE1_RGB
[texUnit
]) {
321 case GL_PRIMARY_COLOR_EXT
:
322 colorSrc1
= fragColor
;
325 colorSrc1
= texColor
;
327 case GL_CONSTANT_EXT
:
328 colorSrc1
= constColor
;
330 case GL_PREVIOUS_EXT
:
331 colorSrc1
= prevColor
;
333 case GL_TEXTURE0_ARB
:
334 case GL_TEXTURE1_ARB
:
335 case GL_TEXTURE2_ARB
:
336 case GL_TEXTURE3_ARB
:
337 case GL_TEXTURE4_ARB
:
338 case GL_TEXTURE5_ARB
:
339 case GL_TEXTURE6_ARB
:
340 case GL_TEXTURE7_ARB
:
341 /* GL_ARB_texture_env_crossbar */
342 srcUnit
= machine
.SOURCE1_RGB
[texUnit
] - GL_TEXTURE0_ARB
;
343 colorSrc1
= machine
.TexColor
[srcUnit
];
346 problem("bad rgbSource1");
350 switch (machine
.SOURCE1_ALPHA
[texUnit
]) {
351 case GL_PRIMARY_COLOR_EXT
:
352 alphaSrc1
= fragColor
;
355 alphaSrc1
= texColor
;
357 case GL_CONSTANT_EXT
:
358 alphaSrc1
= constColor
;
360 case GL_PREVIOUS_EXT
:
361 alphaSrc1
= prevColor
;
363 case GL_TEXTURE0_ARB
:
364 case GL_TEXTURE1_ARB
:
365 case GL_TEXTURE2_ARB
:
366 case GL_TEXTURE3_ARB
:
367 case GL_TEXTURE4_ARB
:
368 case GL_TEXTURE5_ARB
:
369 case GL_TEXTURE6_ARB
:
370 case GL_TEXTURE7_ARB
:
371 /* GL_ARB_texture_env_crossbar */
372 srcUnit
= machine
.SOURCE1_ALPHA
[texUnit
] - GL_TEXTURE0_ARB
;
373 alphaSrc1
= machine
.TexColor
[srcUnit
];
376 problem("bad alphaSource1");
380 switch (machine
.SOURCE2_RGB
[texUnit
]) {
381 case GL_PRIMARY_COLOR_EXT
:
382 colorSrc2
= fragColor
;
385 colorSrc2
= texColor
;
387 case GL_CONSTANT_EXT
:
388 colorSrc2
= constColor
;
390 case GL_PREVIOUS_EXT
:
391 colorSrc2
= prevColor
;
393 case GL_TEXTURE0_ARB
:
394 case GL_TEXTURE1_ARB
:
395 case GL_TEXTURE2_ARB
:
396 case GL_TEXTURE3_ARB
:
397 case GL_TEXTURE4_ARB
:
398 case GL_TEXTURE5_ARB
:
399 case GL_TEXTURE6_ARB
:
400 case GL_TEXTURE7_ARB
:
401 /* GL_ARB_texture_env_crossbar */
402 srcUnit
= machine
.SOURCE2_RGB
[texUnit
] - GL_TEXTURE0_ARB
;
403 colorSrc2
= machine
.TexColor
[srcUnit
];
406 problem("bad rgbSource2");
410 switch (machine
.SOURCE2_ALPHA
[texUnit
]) {
411 case GL_PRIMARY_COLOR_EXT
:
412 alphaSrc2
= fragColor
;
415 alphaSrc2
= texColor
;
417 case GL_CONSTANT_EXT
:
418 alphaSrc2
= constColor
;
420 case GL_PREVIOUS_EXT
:
421 alphaSrc2
= prevColor
;
423 case GL_TEXTURE0_ARB
:
424 case GL_TEXTURE1_ARB
:
425 case GL_TEXTURE2_ARB
:
426 case GL_TEXTURE3_ARB
:
427 case GL_TEXTURE4_ARB
:
428 case GL_TEXTURE5_ARB
:
429 case GL_TEXTURE6_ARB
:
430 case GL_TEXTURE7_ARB
:
431 /* GL_ARB_texture_env_crossbar */
432 srcUnit
= machine
.SOURCE2_ALPHA
[texUnit
] - GL_TEXTURE0_ARB
;
433 alphaSrc2
= machine
.TexColor
[srcUnit
];
436 problem("bad alphaSource2");
440 switch (machine
.OPERAND0_RGB
[texUnit
]) {
442 term0
[0] = colorSrc0
[0];
443 term0
[1] = colorSrc0
[1];
444 term0
[2] = colorSrc0
[2];
446 case GL_ONE_MINUS_SRC_COLOR
:
447 term0
[0] = 1.0 - colorSrc0
[0];
448 term0
[1] = 1.0 - colorSrc0
[1];
449 term0
[2] = 1.0 - colorSrc0
[2];
452 term0
[0] = colorSrc0
[3];
453 term0
[1] = colorSrc0
[3];
454 term0
[2] = colorSrc0
[3];
456 case GL_ONE_MINUS_SRC_ALPHA
:
457 term0
[0] = 1.0 - colorSrc0
[3];
458 term0
[1] = 1.0 - colorSrc0
[3];
459 term0
[2] = 1.0 - colorSrc0
[3];
462 problem("bad rgbOperand0");
466 switch (machine
.OPERAND0_ALPHA
[texUnit
]) {
468 term0
[3] = alphaSrc0
[3];
470 case GL_ONE_MINUS_SRC_ALPHA
:
471 term0
[3] = 1.0 - alphaSrc0
[3];
474 problem("bad alphaOperand0");
478 switch (machine
.OPERAND1_RGB
[texUnit
]) {
480 term1
[0] = colorSrc1
[0];
481 term1
[1] = colorSrc1
[1];
482 term1
[2] = colorSrc1
[2];
484 case GL_ONE_MINUS_SRC_COLOR
:
485 term1
[0] = 1.0 - colorSrc1
[0];
486 term1
[1] = 1.0 - colorSrc1
[1];
487 term1
[2] = 1.0 - colorSrc1
[2];
490 term1
[0] = colorSrc1
[3];
491 term1
[1] = colorSrc1
[3];
492 term1
[2] = colorSrc1
[3];
494 case GL_ONE_MINUS_SRC_ALPHA
:
495 term1
[0] = 1.0 - colorSrc1
[3];
496 term1
[1] = 1.0 - colorSrc1
[3];
497 term1
[2] = 1.0 - colorSrc1
[3];
500 problem("bad rgbOperand1");
504 switch (machine
.OPERAND1_ALPHA
[texUnit
]) {
506 term1
[3] = alphaSrc1
[3];
508 case GL_ONE_MINUS_SRC_ALPHA
:
509 term1
[3] = 1.0 - alphaSrc1
[3];
512 problem("bad alphaOperand1");
516 switch (machine
.OPERAND2_RGB
[texUnit
]) {
518 term2
[0] = colorSrc2
[3];
519 term2
[1] = colorSrc2
[3];
520 term2
[2] = colorSrc2
[3];
523 problem("bad rgbOperand2");
527 switch (machine
.OPERAND2_ALPHA
[texUnit
]) {
529 term2
[3] = alphaSrc2
[3];
532 problem("bad alphaOperand2");
537 switch (machine
.COMBINE_RGB
[texUnit
]) {
539 result
[0] = term0
[0];
540 result
[1] = term0
[1];
541 result
[2] = term0
[2];
544 result
[0] = term0
[0] * term1
[0];
545 result
[1] = term0
[1] * term1
[1];
546 result
[2] = term0
[2] * term1
[2];
549 result
[0] = term0
[0] + term1
[0];
550 result
[1] = term0
[1] + term1
[1];
551 result
[2] = term0
[2] + term1
[2];
553 case GL_ADD_SIGNED_EXT
:
554 result
[0] = term0
[0] + term1
[0] - 0.5;
555 result
[1] = term0
[1] + term1
[1] - 0.5;
556 result
[2] = term0
[2] + term1
[2] - 0.5;
558 case GL_INTERPOLATE_EXT
:
559 result
[0] = term0
[0] * term2
[0] + term1
[0] * (1.0 - term2
[0]);
560 result
[1] = term0
[1] * term2
[1] + term1
[1] * (1.0 - term2
[1]);
561 result
[2] = term0
[2] * term2
[2] + term1
[2] * (1.0 - term2
[2]);
563 case GL_DOT3_RGB_EXT
:
564 case GL_DOT3_RGBA_EXT
:
565 dot
= ((term0
[0] - 0.5) * (term1
[0] - 0.5) +
566 (term0
[1] - 0.5) * (term1
[1] - 0.5) +
567 (term0
[2] - 0.5) * (term1
[2] - 0.5));
571 if (machine
.COMBINE_RGB
[texUnit
] == GL_DOT3_RGBA_EXT
)
575 problem("bad rgbCombine");
579 switch (machine
.COMBINE_ALPHA
[texUnit
]) {
581 result
[3] = term0
[3];
584 result
[3] = term0
[3] * term1
[3];
587 result
[3] = term0
[3] + term1
[3];
589 case GL_ADD_SIGNED_EXT
:
590 result
[3] = term0
[3] + term1
[3] - 0.5;
592 case GL_INTERPOLATE_EXT
:
593 result
[3] = term0
[3] * term2
[3] + term1
[3] * (1.0 - term2
[3]);
596 problem("bad alphaCombine");
600 if (machine
.COMBINE_RGB
[texUnit
] == GL_DOT3_RGBA_EXT
) {
601 result
[3] = result
[0];
606 // GH: Remove this crud when the ARB extension is done. It
607 // most likely won't have this scale factor restriction.
608 switch (machine
.COMBINE_RGB
[texUnit
]) {
609 case GL_DOT3_RGB_EXT
:
610 case GL_DOT3_RGBA_EXT
:
616 result
[0] *= machine
.RGB_SCALE
[texUnit
];
617 result
[1] *= machine
.RGB_SCALE
[texUnit
];
618 result
[2] *= machine
.RGB_SCALE
[texUnit
];
621 switch (machine
.COMBINE_RGB
[texUnit
]) {
622 case GL_DOT3_RGBA_EXT
:
626 result
[3] *= machine
.ALPHA_SCALE
[texUnit
];
631 result
[0] = CLAMP(result
[0], 0.0, 1.0);
632 result
[1] = CLAMP(result
[1], 0.0, 1.0);
633 result
[2] = CLAMP(result
[2], 0.0, 1.0);
634 result
[3] = CLAMP(result
[3], 0.0, 1.0);
639 // Return string for an enum value.
642 EnumString(GLenum pname
)
646 case GL_COMBINE_RGB_EXT
:
647 return "GL_COMBINE_RGB_EXT";
648 case GL_COMBINE_ALPHA_EXT
:
649 return "GL_COMBINE_ALPHA_EXT";
653 return "GL_MODULATE";
656 case GL_ADD_SIGNED_EXT
:
657 return "GL_ADD_SIGNED_EXT";
658 case GL_INTERPOLATE_EXT
:
659 return "GL_INTERPOLATE_EXT";
660 case GL_DOT3_RGB_EXT
:
661 return "GL_DOT3_RGB_EXT";
662 case GL_DOT3_RGBA_EXT
:
663 return "GL_DOT3_RGBA_EXT";
666 case GL_CONSTANT_EXT
:
667 return "GL_CONSTANT_EXT";
668 case GL_PRIMARY_COLOR_EXT
:
669 return "GL_PRIMARY_COLOR_EXT";
670 case GL_PREVIOUS_EXT
:
671 return "GL_PREVIOUS_EXT";
673 return "GL_SRC_COLOR";
674 case GL_ONE_MINUS_SRC_COLOR
:
675 return "GL_ONE_MINUS_SRC_COLOR";
677 return "GL_SRC_ALPHA";
678 case GL_ONE_MINUS_SRC_ALPHA
:
679 return "GL_ONE_MINUS_SRC_ALPHA";
680 case GL_TEXTURE0_ARB
:
681 return "GL_TEXTURE0_ARB";
682 case GL_TEXTURE1_ARB
:
683 return "GL_TEXTURE1_ARB";
684 case GL_TEXTURE2_ARB
:
685 return "GL_TEXTURE2_ARB";
686 case GL_TEXTURE3_ARB
:
687 return "GL_TEXTURE3_ARB";
688 case GL_TEXTURE4_ARB
:
689 return "GL_TEXTURE4_ARB";
690 case GL_TEXTURE5_ARB
:
691 return "GL_TEXTURE5_ARB";
692 case GL_TEXTURE6_ARB
:
693 return "GL_TEXTURE6_ARB";
694 case GL_TEXTURE7_ARB
:
695 return "GL_TEXTURE7_ARB";
697 sprintf(s
, "0x%04x", (unsigned int) pname
);
704 // Print current values of all machine state vars.
705 // Used when reporting failures.
708 TexCombineTest::PrintMachineState(const glmachine
&machine
) const {
710 env
->log
<< "\tCurrent combine state:\n";
711 env
->log
<< "\tIncoming Fragment RGBA = "
712 << machine
.FragColor
[0] << ", "
713 << machine
.FragColor
[1] << ", "
714 << machine
.FragColor
[2] << ", "
715 << machine
.FragColor
[3] << "\n";
716 for (int u
= 0; u
< machine
.NumTexUnits
; u
++) {
717 env
->log
<< "\tTexture Unit " << u
<< ":\n";
718 env
->log
<< "\t GL_COMBINE_RGB_EXT = "
719 << EnumString(machine
.COMBINE_RGB
[u
]) << "\n";
720 env
->log
<< "\t GL_COMBINE_ALPHA_EXT = "
721 << EnumString(machine
.COMBINE_ALPHA
[u
]) << "\n";
722 env
->log
<< "\t GL_SOURCE0_RGB_EXT = "
723 << EnumString(machine
.SOURCE0_RGB
[u
]) << "\n";
724 env
->log
<< "\t GL_SOURCE1_RGB_EXT = "
725 << EnumString(machine
.SOURCE1_RGB
[u
]) << "\n";
726 env
->log
<< "\t GL_SOURCE2_RGB_EXT = "
727 << EnumString(machine
.SOURCE2_RGB
[u
]) << "\n";
728 env
->log
<< "\t GL_SOURCE0_ALPHA_EXT = "
729 << EnumString(machine
.SOURCE0_ALPHA
[u
]) << "\n";
730 env
->log
<< "\t GL_SOURCE1_ALPHA_EXT = "
731 << EnumString(machine
.SOURCE1_ALPHA
[u
]) << "\n";
732 env
->log
<< "\t GL_SOURCE2_ALPHA_EXT = "
733 << EnumString(machine
.SOURCE2_ALPHA
[u
]) << "\n";
734 env
->log
<< "\t GL_OPERAND0_RGB_EXT = "
735 << EnumString(machine
.OPERAND0_RGB
[u
]) << "\n";
736 env
->log
<< "\t GL_OPERAND1_RGB_EXT = "
737 << EnumString(machine
.OPERAND1_RGB
[u
]) << "\n";
738 env
->log
<< "\t GL_OPERAND2_RGB_EXT = "
739 << EnumString(machine
.OPERAND2_RGB
[u
]) << "\n";
740 env
->log
<< "\t GL_OPERAND0_ALPHA_EXT = "
741 << EnumString(machine
.OPERAND0_ALPHA
[u
]) << "\n";
742 env
->log
<< "\t GL_OPERAND1_ALPHA_EXT = "
743 << EnumString(machine
.OPERAND1_ALPHA
[u
]) << "\n";
744 env
->log
<< "\t GL_OPERAND2_ALPHA_EXT = "
745 << EnumString(machine
.OPERAND2_ALPHA
[u
]) << "\n";
746 env
->log
<< "\t GL_RGB_SCALE_EXT = "
747 << machine
.RGB_SCALE
[u
] << "\n";
748 env
->log
<< "\t GL_ALPHA_SCALE = "
749 << machine
.ALPHA_SCALE
[u
] << "\n";
750 env
->log
<< "\t Tex Env RGBA = "
751 << machine
.EnvColor
[u
][0] << ", "
752 << machine
.EnvColor
[u
][1] << ", "
753 << machine
.EnvColor
[u
][2] << ", "
754 << machine
.EnvColor
[u
][3] << "\n";
755 switch (machine
.TexFormat
[u
]) {
757 env
->log
<< "\t Texture ALPHA = "
758 << machine
.TexColor
[u
][3] << "\n";
761 env
->log
<< "\t Texture LUMINANCE = "
762 << machine
.TexColor
[u
][0] << "\n";
764 case GL_LUMINANCE_ALPHA
:
765 env
->log
<< "\t Texture RGBA = "
766 << machine
.TexColor
[u
][0] << ", "
767 << machine
.TexColor
[u
][3] << "\n";
770 env
->log
<< "\t Texture INTENSITY = "
771 << machine
.TexColor
[u
][0] << "\n";
774 env
->log
<< "\t Texture RGB = "
775 << machine
.TexColor
[u
][0] << ", "
776 << machine
.TexColor
[u
][1] << ", "
777 << machine
.TexColor
[u
][2] << "\n";
780 env
->log
<< "\t Texture RGBA = "
781 << machine
.TexColor
[u
][0] << ", "
782 << machine
.TexColor
[u
][1] << ", "
783 << machine
.TexColor
[u
][2] << ", "
784 << machine
.TexColor
[u
][3] << "\n";
793 // Check that the actual GL implementation's texture state matches what's
794 // in the given glean machine state. This is only used for debugging.
797 TexCombineTest::VerifyMachineState(const glmachine
&machine
) const {
799 #define VERIFY(var, expected) \
800 glGetTexEnviv(GL_TEXTURE_ENV, var, &actual); \
801 if ((GLint) (expected) != (actual)) { \
802 cerr << "Expected " << var << " = " \
803 << EnumString(expected) \
805 << EnumString(actual) \
809 #define VERIFYF(var, expected) \
810 glGetTexEnvfv(GL_TEXTURE_ENV, var, &actualf); \
811 if ((expected) != (actualf)) { \
812 cerr << "Expected " << var << " = " \
821 for (int u
= 0; u
< machine
.NumTexUnits
; u
++) {
824 VERIFY(GL_COMBINE_RGB_EXT
, machine
.COMBINE_RGB
[u
]);
825 VERIFY(GL_COMBINE_ALPHA_EXT
, machine
.COMBINE_ALPHA
[u
]);
826 VERIFY(GL_SOURCE0_RGB_EXT
, machine
.SOURCE0_RGB
[u
]);
827 VERIFY(GL_SOURCE1_RGB_EXT
, machine
.SOURCE1_RGB
[u
]);
828 VERIFY(GL_SOURCE2_RGB_EXT
, machine
.SOURCE2_RGB
[u
]);
829 VERIFY(GL_OPERAND0_RGB_EXT
, machine
.OPERAND0_RGB
[u
]);
830 VERIFY(GL_OPERAND1_RGB_EXT
, machine
.OPERAND1_RGB
[u
]);
831 VERIFY(GL_OPERAND2_RGB_EXT
, machine
.OPERAND2_RGB
[u
]);
832 VERIFYF(GL_RGB_SCALE_EXT
, machine
.RGB_SCALE
[u
]);
833 VERIFYF(GL_ALPHA_SCALE
, machine
.ALPHA_SCALE
[u
]);
836 return true; // state is AOK
841 // Print an error report.
844 TexCombineTest::ReportFailure(const glmachine
&machine
,
845 const GLfloat expected
[4],
846 const GLfloat rendered
[4],
850 env
->log
<< name
<< ": FAIL "
851 << r
.config
->conciseDescription() << '\n'
853 << expected
[0] << ", "
854 << expected
[1] << ", "
855 << expected
[2] << ", "
856 << expected
[3] << ", got "
857 << rendered
[0] << ", "
858 << rendered
[1] << ", "
859 << rendered
[2] << ", "
861 << " in " << where
<< "\n";
862 PrintMachineState(machine
);
867 // Examine a set of test params and compute the number of possible
868 // state combinations.
871 TexCombineTest::CountTestCombinations(const test_param testParams
[]) const {
874 for (int t
= 0; testParams
[t
].target
; t
++) {
876 for (int val
= 0; testParams
[t
].validValues
[val
]; val
++) {
881 return numTests
/ testStride
;
886 // Setup the actual GL state and our internal simulated GL state.
889 TexCombineTest::TexEnv(glmachine
&machine
, int texUnit
,
890 GLenum target
, GLenum value
) {
892 if (machine
.NumTexUnits
> 1)
893 p_glActiveTextureARB(GL_TEXTURE0_ARB
+ texUnit
);
895 glTexEnvi(GL_TEXTURE_ENV
, target
, value
);
896 int err
= glGetError();
897 if (err
!= GL_NO_ERROR
)
898 printf("Problem: glTexEnvi() generated error 0x%x\n", err
);
901 case GL_COMBINE_RGB_EXT
:
902 machine
.COMBINE_RGB
[texUnit
] = value
;
904 case GL_COMBINE_ALPHA_EXT
:
905 machine
.COMBINE_ALPHA
[texUnit
] = value
;
907 case GL_SOURCE0_RGB_EXT
:
908 machine
.SOURCE0_RGB
[texUnit
] = value
;
910 case GL_SOURCE1_RGB_EXT
:
911 machine
.SOURCE1_RGB
[texUnit
] = value
;
913 case GL_SOURCE2_RGB_EXT
:
914 machine
.SOURCE2_RGB
[texUnit
] = value
;
916 case GL_SOURCE0_ALPHA_EXT
:
917 machine
.SOURCE0_ALPHA
[texUnit
] = value
;
919 case GL_SOURCE1_ALPHA_EXT
:
920 machine
.SOURCE1_ALPHA
[texUnit
] = value
;
922 case GL_SOURCE2_ALPHA_EXT
:
923 machine
.SOURCE2_ALPHA
[texUnit
] = value
;
925 case GL_OPERAND0_RGB_EXT
:
926 machine
.OPERAND0_RGB
[texUnit
] = value
;
928 case GL_OPERAND1_RGB_EXT
:
929 machine
.OPERAND1_RGB
[texUnit
] = value
;
931 case GL_OPERAND2_RGB_EXT
:
932 machine
.OPERAND2_RGB
[texUnit
] = value
;
934 case GL_OPERAND0_ALPHA_EXT
:
935 machine
.OPERAND0_ALPHA
[texUnit
] = value
;
937 case GL_OPERAND1_ALPHA_EXT
:
938 machine
.OPERAND1_ALPHA
[texUnit
] = value
;
940 case GL_OPERAND2_ALPHA_EXT
:
941 machine
.OPERAND2_ALPHA
[texUnit
] = value
;
943 case GL_RGB_SCALE_EXT
:
944 machine
.RGB_SCALE
[texUnit
] = value
;
947 machine
.ALPHA_SCALE
[texUnit
] = value
;
954 // Make the glTexEnv calls to setup one particular set of test parameters
955 // from <testParams>.
956 // <testNum> must be between 0 and CountTestCombinations(testParams)-1.
959 TexCombineTest::SetupTestEnv(struct glmachine
&machine
, int texUnit
,
960 int testNum
, const struct test_param testParams
[]) {
963 for (int t
= 0; testParams
[t
].target
; t
++) {
965 for (int val
= 0; testParams
[t
].validValues
[val
]; val
++) {
968 int v
= (testNum
/ divisor
) % numValues
;
969 GLenum target
= testParams
[t
].target
;
970 GLenum value
= testParams
[t
].validValues
[v
];
971 TexEnv(machine
, texUnit
, target
, value
);
972 divisor
*= numValues
;
978 // Set the fragment, texenv (constant), and texture colors for all the
979 // machine's texture units.
982 TexCombineTest::SetupColors(glmachine
&machine
) {
984 static const GLfloat fragColor
[4] = { 0.00, 0.25, 0.50, 0.75 };
985 static const GLfloat envColors
[][4] = {
986 { 0.25, 0.50, 0.75, 1.00 },
987 { 0.50, 0.75, 1.00, 0.00 },
988 { 0.75, 1.00, 0.00, 0.25 },
989 { 1.00, 0.00, 0.25, 0.50 }
991 static const GLfloat texColors
[][8] = {
992 { 1.00, 0.00, 0.25, 0.50 },
993 { 0.75, 1.00, 0.00, 0.25 },
994 { 0.50, 0.75, 1.00, 0.00 },
995 { 0.25, 0.50, 0.75, 1.00 },
996 // extra colors that'll only be used for crossbar test
997 { 0.00, 0.00, 0.00, 0.00 },
998 { 0.25, 0.50, 0.50, 0.00 },
999 { 0.50, 0.25, 0.75, 0.25 },
1000 { 0.75, 1.00, 0.25, 0.00 }
1003 COPY4(machine
.FragColor
, fragColor
);
1004 glColor4fv(fragColor
);
1006 for (int u
= 0; u
< machine
.NumTexUnits
; u
++) {
1007 if (machine
.NumTexUnits
> 1)
1008 p_glActiveTextureARB(GL_TEXTURE0_ARB
+ u
);
1009 glBindTexture(GL_TEXTURE_2D
, mTextures
[u
]);
1010 glEnable(GL_TEXTURE_2D
);
1011 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
1013 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
1015 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_COMBINE_EXT
);
1016 machine
.EnvColor
[u
][0] = envColors
[u
% 4][0];
1017 machine
.EnvColor
[u
][1] = envColors
[u
% 4][1];
1018 machine
.EnvColor
[u
][2] = envColors
[u
% 4][2];
1019 machine
.EnvColor
[u
][3] = envColors
[u
% 4][3];
1020 glTexEnvfv(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_COLOR
,
1023 const GLfloat
*texCol
= texColors
[u
% 8];
1025 // Setup texture color, according to texture format
1026 switch (machine
.TexFormat
[u
]) {
1028 machine
.TexColor
[u
][0] = texCol
[0];
1029 machine
.TexColor
[u
][1] = texCol
[1];
1030 machine
.TexColor
[u
][2] = texCol
[2];
1031 machine
.TexColor
[u
][3] = texCol
[3];
1034 machine
.TexColor
[u
][0] = texCol
[0];
1035 machine
.TexColor
[u
][1] = texCol
[1];
1036 machine
.TexColor
[u
][2] = texCol
[2];
1037 machine
.TexColor
[u
][3] = 1.0;
1040 machine
.TexColor
[u
][0] = 0.0;
1041 machine
.TexColor
[u
][1] = 0.0;
1042 machine
.TexColor
[u
][2] = 0.0;
1043 machine
.TexColor
[u
][3] = texCol
[3];
1046 machine
.TexColor
[u
][0] = texCol
[0];
1047 machine
.TexColor
[u
][1] = texCol
[0];
1048 machine
.TexColor
[u
][2] = texCol
[0];
1049 machine
.TexColor
[u
][3] = 1.0;
1051 case GL_LUMINANCE_ALPHA
:
1052 machine
.TexColor
[u
][0] = texCol
[0];
1053 machine
.TexColor
[u
][1] = texCol
[0];
1054 machine
.TexColor
[u
][2] = texCol
[0];
1055 machine
.TexColor
[u
][3] = texCol
[3];
1058 machine
.TexColor
[u
][0] = texCol
[0];
1059 machine
.TexColor
[u
][1] = texCol
[0];
1060 machine
.TexColor
[u
][2] = texCol
[0];
1061 machine
.TexColor
[u
][3] = texCol
[0];
1064 problem("bad texture format");
1068 // Make a 4x4 solid color texture
1069 GLfloat image
[16][4];
1071 for (i
= 0; i
< 16; i
++) {
1072 image
[i
][0] = texColors
[u
% 8][0];
1073 image
[i
][1] = texColors
[u
% 8][1];
1074 image
[i
][2] = texColors
[u
% 8][2];
1075 image
[i
][3] = texColors
[u
% 8][3];
1077 glTexImage2D(GL_TEXTURE_2D
, 0, machine
.TexFormat
[u
],
1078 4, 4, 0, GL_RGBA
, GL_FLOAT
, image
);
1081 GLfloat check
[16][4];
1083 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
1084 GL_TEXTURE_RED_SIZE
, &r
);
1085 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
1086 GL_TEXTURE_GREEN_SIZE
, &g
);
1087 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
1088 GL_TEXTURE_BLUE_SIZE
, &b
);
1089 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
1090 GL_TEXTURE_ALPHA_SIZE
, &a
);
1091 printf("Texture bits: %d %d %d %d\n", r
, g
, b
, a
);
1092 glGetTexImage(GL_TEXTURE_2D
, 0, GL_RGBA
, GL_FLOAT
,
1094 for (i
= 0;i
< 16; i
++) {
1095 printf("%2d: %4f %4f %4f %4f %4f %4f %4f %4f\n", i
,
1096 image
[i
][0], image
[i
][1],
1097 image
[i
][2], image
[i
][3],
1098 check
[i
][0], check
[i
][1],
1099 check
[i
][2], check
[i
][3]);
1107 // Test texenv-combine with a single texture unit.
1110 TexCombineTest::RunSingleTextureTest(glmachine
&machine
,
1111 const test_param testParams
[], BasicResult
&r
, Window
& w
) {
1113 assert(machine
.NumTexUnits
== 1);
1114 SetupColors(machine
);
1116 const int numTests
= CountTestCombinations(testParams
);
1117 //printf("Testing %d combinations\n", numTests);
1119 for (int test
= 0; test
< numTests
; test
+= testStride
) {
1121 ResetMachine(machine
);
1122 SetupTestEnv(machine
, 0, test
, testParams
);
1124 // 1. Render with OpenGL
1125 GLfloat renderedResult
[4];
1126 glTexCoord2f(0, 0); // use texcoord (0,0) for all vertices
1127 glBegin(GL_POLYGON
);
1128 glVertex2f(-1.0, -1.0);
1129 glVertex2f( 1.0, -1.0);
1130 glVertex2f( 1.0, 1.0);
1131 glVertex2f(-1.0, 1.0);
1133 glReadPixels(0, 0, 1, 1, GL_RGBA
, GL_FLOAT
, renderedResult
);
1136 // 2. Compute expected result
1137 GLfloat expected
[4];
1138 ComputeTexCombine(machine
, 0, machine
.FragColor
, expected
);
1140 // 3. Compare rendered result to expected result
1141 const GLfloat dr
= fabs(expected
[0] - renderedResult
[0]);
1142 const GLfloat dg
= fabs(expected
[1] - renderedResult
[1]);
1143 const GLfloat db
= fabs(expected
[2] - renderedResult
[2]);
1144 const GLfloat da
= fabs(expected
[3] - renderedResult
[3]);
1145 if (dr
> mTolerance
[0] || dg
> mTolerance
[1] ||
1146 db
> mTolerance
[2] || da
> mTolerance
[3]) {
1147 ReportFailure(machine
, expected
, renderedResult
, r
,
1148 "Single Texture Test");
1150 VerifyMachineState(machine
);
1151 // For debugging, printing the state of the previous
1152 // test is useful to see what's changed when we've
1153 // failed a test but passed the previous one.
1154 printf("single-texture test %d failed\n", test
);
1156 printf("prev test:\n");
1157 SetupTestEnv(machine
, 0, test
- 1, testParams
);
1158 PrintMachineState(machine
);
1165 printf("PASSED test %d!\n", test
);
1166 env
->log
<< "\texpected "
1167 << expected
[0] << ", "
1168 << expected
[1] << ", "
1169 << expected
[2] << ", "
1170 << expected
[3] << ", got "
1171 << renderedResult
[0] << ", "
1172 << renderedResult
[1] << ", "
1173 << renderedResult
[2] << ", "
1174 << renderedResult
[3] << "\n";
1175 // PrintMachineState(machine);
1185 // For each texture unit, test each texenv-combine mode.
1186 // That's 5 ^ NumTexUnits combinations.
1187 // Or 7 ^ numTexUnits if DOT3 combine mode is supported
1190 TexCombineTest::CountMultiTextureTestCombinations(const glmachine
&machine
) const {
1193 int numUnits
= machine
.NumTexUnits
> 4 ? 4 : machine
.NumTexUnits
;
1194 for (int i
= 0; i
< numUnits
; i
++)
1195 numTests
*= (haveDot3
? 7 : 5);
1197 return numTests
/ testStride
;
1202 // Test texenv-combine with multiple texture units.
1205 TexCombineTest::RunMultiTextureTest(glmachine
&machine
, BasicResult
&r
,
1208 static const GLenum combineModes
[7] = {
1217 static const int numModes
= haveDot3
? 7 : 5;
1219 // four texture units is enough to test
1220 if (machine
.NumTexUnits
> 4)
1221 machine
.NumTexUnits
= 4;
1223 const int numTests
= CountMultiTextureTestCombinations(machine
);
1224 //printf("Testing %d multitexture combinations\n", numTests);
1226 SetupColors(machine
);
1227 for (int testNum
= 0; testNum
< numTests
; testNum
+= testStride
) {
1228 // 0. Set up texture units
1229 ResetMachine(machine
);
1232 for (u
= 0; u
< machine
.NumTexUnits
; u
++) {
1233 const int m
= (testNum
/ divisor
) % numModes
;
1234 const GLenum mode
= combineModes
[m
];
1236 // Set GL_COMBINE_RGB_EXT and GL_COMBINE_ALPHA_EXT
1237 TexEnv(machine
, u
, GL_COMBINE_RGB_EXT
, mode
);
1238 TexEnv(machine
, u
, GL_COMBINE_ALPHA_EXT
,
1239 (mode
== GL_DOT3_RGB_EXT
||
1240 mode
== GL_DOT3_RGBA_EXT
) ? GL_REPLACE
: mode
);
1241 TexEnv(machine
, u
, GL_SOURCE0_RGB_EXT
, GL_PREVIOUS_EXT
);
1242 TexEnv(machine
, u
, GL_SOURCE1_RGB_EXT
, GL_PREVIOUS_EXT
);
1243 TexEnv(machine
, u
, GL_SOURCE2_RGB_EXT
, GL_TEXTURE
);
1244 TexEnv(machine
, u
, GL_SOURCE0_ALPHA_EXT
, GL_PREVIOUS_EXT
);
1245 TexEnv(machine
, u
, GL_SOURCE1_ALPHA_EXT
, GL_PREVIOUS_EXT
);
1246 TexEnv(machine
, u
, GL_SOURCE2_ALPHA_EXT
, GL_TEXTURE
);
1247 TexEnv(machine
, u
, GL_OPERAND0_RGB_EXT
, GL_SRC_COLOR
);
1248 TexEnv(machine
, u
, GL_OPERAND1_RGB_EXT
, GL_ONE_MINUS_SRC_COLOR
);
1249 TexEnv(machine
, u
, GL_OPERAND2_RGB_EXT
, GL_SRC_ALPHA
);
1250 TexEnv(machine
, u
, GL_OPERAND0_ALPHA_EXT
, GL_SRC_ALPHA
);
1251 TexEnv(machine
, u
, GL_OPERAND1_ALPHA_EXT
, GL_ONE_MINUS_SRC_ALPHA
);
1252 TexEnv(machine
, u
, GL_OPERAND2_ALPHA_EXT
, GL_SRC_ALPHA
);
1253 TexEnv(machine
, u
, GL_RGB_SCALE_EXT
, 1);
1254 TexEnv(machine
, u
, GL_ALPHA_SCALE
, 1);
1256 //printf("texenv%d = %s ", u, EnumString(mode));
1257 divisor
*= numModes
;
1261 // 1. Render with OpenGL
1262 GLfloat renderedResult
[4];
1263 // use texcoord (0,0) for all vertices
1264 for (int u
= 0; u
< machine
.NumTexUnits
; u
++)
1265 p_glMultiTexCoord2fARB(GL_TEXTURE0_ARB
+ u
, 0, 0);
1266 glBegin(GL_POLYGON
);
1267 glVertex2f(-1.0, -1.0);
1268 glVertex2f( 1.0, -1.0);
1269 glVertex2f( 1.0, 1.0);
1270 glVertex2f(-1.0, 1.0);
1272 glReadPixels(0, 0, 1, 1, GL_RGBA
, GL_FLOAT
, renderedResult
);
1275 // 2. Compute expected result
1276 GLfloat prevColor
[4];
1277 GLfloat expected
[4];
1278 for (u
= 0; u
< machine
.NumTexUnits
; u
++) {
1280 COPY4(prevColor
, machine
.FragColor
);
1282 COPY4(prevColor
, expected
);
1284 ComputeTexCombine(machine
, u
, prevColor
, expected
);
1287 // 3. Compare rendered result to expected result
1288 const GLfloat dr
= fabs(expected
[0] - renderedResult
[0]);
1289 const GLfloat dg
= fabs(expected
[1] - renderedResult
[1]);
1290 const GLfloat db
= fabs(expected
[2] - renderedResult
[2]);
1291 const GLfloat da
= fabs(expected
[3] - renderedResult
[3]);
1292 if (dr
> mTolerance
[0] || dg
> mTolerance
[1] ||
1293 db
> mTolerance
[2] || da
> mTolerance
[3]) {
1294 ReportFailure(machine
, expected
, renderedResult
, r
,
1295 "Multi-texture test");
1297 printf("multitex test %d failed\n", testNum
);
1299 printf("prev test:\n");
1300 SetupTestEnv(machine
, 0, testNum
- 1, testParams
);
1301 PrintMachineState(machine
);
1313 TexCombineTest::CountCrossbarCombinations() const
1316 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB
, &numUnits
);
1322 TexCombineTest::RunCrossbarTest(glmachine
&machine
, BasicResult
&r
, Window
& w
) {
1323 // We do a really short, simple test for GL_ARB_texture_env_crossbar
1324 // since the preceeding tests are pretty comprehensive and the
1325 // crossbar feature is just an incremental addition.
1326 // Basically, if we have N texture units we run N tests.
1327 // For test [i] we set texture unit [i] to fetch the texture color
1328 // from unit [numUnits - i - 1]. For units != i we use the constant
1329 // color (0,0,0,0). We use GL_ADD mode to compute the sum over all units.
1330 // So effectively, the result of texture combine is simply the incoming
1331 // fragment color plus unit [numUnits - test - 1]'s texture color.
1335 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB
, (GLint
*) &Machine
.NumTexUnits
);
1337 // Set up constant texture state for all tests
1338 ResetMachine(machine
);
1339 SetupColors(machine
);
1340 for (unit
= 0; unit
< machine
.NumTexUnits
; unit
++) {
1341 TexEnv(machine
, unit
, GL_COMBINE_RGB_EXT
, GL_ADD
);
1342 TexEnv(machine
, unit
, GL_COMBINE_ALPHA_EXT
, GL_ADD
);
1343 TexEnv(machine
, unit
, GL_SOURCE0_RGB_EXT
, GL_PREVIOUS_EXT
);
1344 TexEnv(machine
, unit
, GL_SOURCE0_ALPHA_EXT
, GL_PREVIOUS_EXT
);
1345 // SOURCE1_RGB/ALPHA is set below, per test
1346 TexEnv(machine
, unit
, GL_OPERAND0_RGB_EXT
, GL_SRC_COLOR
);
1347 TexEnv(machine
, unit
, GL_OPERAND1_RGB_EXT
, GL_SRC_COLOR
);
1348 TexEnv(machine
, unit
, GL_OPERAND2_RGB_EXT
, GL_SRC_ALPHA
);
1349 TexEnv(machine
, unit
, GL_OPERAND0_ALPHA_EXT
, GL_SRC_ALPHA
);
1350 TexEnv(machine
, unit
, GL_OPERAND1_ALPHA_EXT
, GL_SRC_ALPHA
);
1351 TexEnv(machine
, unit
, GL_OPERAND2_ALPHA_EXT
, GL_SRC_ALPHA
);
1352 TexEnv(machine
, unit
, GL_RGB_SCALE_EXT
, 1);
1353 TexEnv(machine
, unit
, GL_ALPHA_SCALE
, 1);
1355 machine
.EnvColor
[unit
][0] = 0.0F
;
1356 machine
.EnvColor
[unit
][1] = 0.0F
;
1357 machine
.EnvColor
[unit
][2] = 0.0F
;
1358 machine
.EnvColor
[unit
][3] = 0.0F
;
1359 p_glActiveTextureARB(GL_TEXTURE0_ARB
+ unit
);
1360 glTexEnvfv(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_COLOR
,
1361 machine
.EnvColor
[unit
]);
1364 for (int test
= 0; test
< machine
.NumTexUnits
; test
++) {
1365 // 1. Set up texture state
1366 for (unit
= 0; unit
< machine
.NumTexUnits
; unit
++) {
1368 const int revUnit
= machine
.NumTexUnits
- unit
- 1;
1369 TexEnv(machine
, unit
, GL_SOURCE1_RGB_EXT
,
1370 GL_TEXTURE0_ARB
+ revUnit
);
1371 TexEnv(machine
, unit
, GL_SOURCE1_ALPHA_EXT
,
1372 GL_TEXTURE0_ARB
+ revUnit
);
1375 TexEnv(machine
, unit
, GL_SOURCE1_RGB_EXT
, GL_CONSTANT_EXT
);
1376 TexEnv(machine
, unit
, GL_SOURCE1_ALPHA_EXT
, GL_CONSTANT_EXT
);
1380 // 2. Render with OpenGL
1381 GLfloat renderedResult
[4];
1382 // texcoord (0,) for all vertices is OK
1383 for (unit
= 0; unit
< machine
.NumTexUnits
; unit
++)
1384 p_glMultiTexCoord2fARB(GL_TEXTURE0_ARB
+ unit
, 0, 0);
1385 glColor4fv(machine
.FragColor
);
1386 glBegin(GL_POLYGON
);
1387 glVertex2f(-1.0, -1.0);
1388 glVertex2f( 1.0, -1.0);
1389 glVertex2f( 1.0, 1.0);
1390 glVertex2f(-1.0, 1.0);
1392 glReadPixels(0, 0, 1, 1, GL_RGBA
, GL_FLOAT
, renderedResult
);
1395 // 3. Compute expected result
1396 GLfloat prevColor
[4];
1397 GLfloat expected
[4];
1398 for (unit
= 0; unit
< machine
.NumTexUnits
; unit
++) {
1400 COPY4(prevColor
, machine
.FragColor
);
1402 COPY4(prevColor
, expected
);
1404 ComputeTexCombine(machine
, unit
, prevColor
, expected
);
1407 // 4. Compare rendered result to expected result
1408 const GLfloat dr
= fabs(expected
[0] - renderedResult
[0]);
1409 const GLfloat dg
= fabs(expected
[1] - renderedResult
[1]);
1410 const GLfloat db
= fabs(expected
[2] - renderedResult
[2]);
1411 const GLfloat da
= fabs(expected
[3] - renderedResult
[3]);
1412 if (dr
> mTolerance
[0] || dg
> mTolerance
[1] ||
1413 db
> mTolerance
[2] || da
> mTolerance
[3]) {
1414 ReportFailure(machine
, expected
, renderedResult
, r
,
1415 "Texture crossbar test");
1417 printf("crossbar test %d failed\n", testNum
);
1418 PrintMachineState(machine
);
1426 ///////////////////////////////////////////////////////////////////////////////
1427 // runOne: Run a single test case
1428 ///////////////////////////////////////////////////////////////////////////////
1430 // XXX should we run a number of individual tests instead?
1432 TexCombineTest::runOne(BasicResult
& r
, Window
& w
) {
1433 // Grab pointers to the extension functions. It's safe to use
1434 // these without testing them because we already know that we
1435 // won't be invoked except on contexts that support the
1437 p_glActiveTextureARB
= (PFNGLACTIVETEXTUREARBPROC
)
1438 (GLUtils::getProcAddress("glActiveTextureARB"));
1439 p_glMultiTexCoord2fARB
= (PFNGLMULTITEXCOORD2FARBPROC
)
1440 (GLUtils::getProcAddress("glMultiTexCoord2fARB"));
1442 // Test the availability of the DOT3 extenstion
1443 haveDot3
= GLUtils::haveExtensions("GL_EXT_texture_env_dot3");
1445 haveCrossbar
= GLUtils::haveExtensions("GL_ARB_texture_env_crossbar")
1446 && GLUtils::haveExtensions("GL_ARB_texture_env_combine");
1448 // compute RGB error tolerance
1450 GLint rBits
, gBits
, bBits
, aBits
;
1451 GLint rTexBits
, gTexBits
, bTexBits
, aTexBits
;
1452 GLfloat texImage
[4][4][4];
1453 // Make dummy texture image
1454 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, 4, 4, 0,
1455 GL_RGBA
, GL_FLOAT
, texImage
);
1456 glGetIntegerv(GL_RED_BITS
, &rBits
);
1457 glGetIntegerv(GL_GREEN_BITS
, &gBits
);
1458 glGetIntegerv(GL_BLUE_BITS
, &bBits
);
1459 glGetIntegerv(GL_ALPHA_BITS
, &aBits
);
1460 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
1461 GL_TEXTURE_RED_SIZE
, &rTexBits
);
1462 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
1463 GL_TEXTURE_GREEN_SIZE
, &gTexBits
);
1464 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
1465 GL_TEXTURE_BLUE_SIZE
, &bTexBits
);
1466 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
1467 GL_TEXTURE_ALPHA_SIZE
, &aTexBits
);
1468 // find smaller of frame buffer and texture bits
1469 rBits
= (rBits
< rTexBits
) ? rBits
: rTexBits
;
1470 gBits
= (gBits
< gTexBits
) ? gBits
: gTexBits
;
1471 bBits
= (bBits
< bTexBits
) ? bBits
: bTexBits
;
1472 aBits
= (aBits
< aTexBits
) ? aBits
: aTexBits
;
1473 // tolerance is 3 bits of error
1474 mTolerance
[0] = 8.0 / (1 << rBits
);
1475 mTolerance
[1] = 8.0 / (1 << gBits
);
1476 mTolerance
[2] = 8.0 / (1 << bBits
);
1478 mTolerance
[3] = 1.0;
1480 mTolerance
[3] = 8.0 / (1 << aBits
);
1482 printf("Tolerance: %g %g %g %g\n",
1483 mTolerance[0], mTolerance[1],
1484 mTolerance[2], mTolerance[3]);
1488 // Allocate our textures
1489 glGenTextures(MAX_TEX_UNITS
, mTextures
);
1491 // We'll only render a 4-pixel polygon
1492 glViewport(0, 0, 2, 2);
1494 ResetMachine(Machine
);
1495 Machine
.NumTexUnits
= 1;
1497 // If quick mode, run fewer tests
1498 if (env
->options
.quick
)
1499 testStride
= 11; // a prime number
1503 // Do single texture unit tests first.
1504 bool passed
= RunSingleTextureTest(Machine
, ReplaceParams
, r
, w
);
1506 passed
= RunSingleTextureTest(Machine
, AddParams
, r
, w
);
1508 passed
= RunSingleTextureTest(Machine
, AddSignedParams
, r
, w
);
1510 passed
= RunSingleTextureTest(Machine
, ModulateParams
, r
, w
);
1512 passed
= RunSingleTextureTest(Machine
, InterpolateParams
, r
, w
);
1513 if (passed
&& haveDot3
)
1514 passed
= RunSingleTextureTest(Machine
, Dot3RGBParams
, r
, w
);
1515 if (passed
&& haveDot3
)
1516 passed
= RunSingleTextureTest(Machine
, Dot3RGBAParams
, r
, w
);
1518 // Now do some multi-texture tests
1520 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB
,
1521 (GLint
*) &Machine
.NumTexUnits
);
1522 if (Machine
.NumTexUnits
> 1) {
1523 passed
= RunMultiTextureTest(Machine
, r
, w
);
1527 // Do crossbar tests
1528 if (passed
&& haveCrossbar
) {
1529 passed
= RunCrossbarTest(Machine
, r
, w
);
1534 // Delete our textures
1535 glDeleteTextures(MAX_TEX_UNITS
, mTextures
);
1537 } // TexCombineTest::runOne
1540 TexCombineTest::logOne(BasicResult
& r
) {
1544 env
->log
<< "\tTested "
1545 << CountTestCombinations(ReplaceParams
)
1546 << " GL_REPLACE combinations\n";
1547 env
->log
<< "\tTested "
1548 << CountTestCombinations(AddParams
)
1549 << " GL_ADD combinations\n";
1550 env
->log
<< "\tTested "
1551 << CountTestCombinations(AddSignedParams
)
1552 << " GL_ADD_SIGNED_EXT combinations\n";
1553 env
->log
<< "\tTested "
1554 << CountTestCombinations(ModulateParams
)
1555 << " GL_MODULATE combinations\n";
1556 env
->log
<< "\tTested "
1557 << CountTestCombinations(InterpolateParams
)
1558 << " GL_INTERPOLATE_EXT combinations\n";
1560 env
->log
<< "\tTested "
1561 << CountTestCombinations(Dot3RGBParams
)
1562 << " GL_DOT3_RGB_EXT combinations\n";
1563 env
->log
<< "\tTested "
1564 << CountTestCombinations(Dot3RGBAParams
)
1565 << " GL_DOT3_RGBA_EXT combinations\n";
1567 env
->log
<< "\tTested "
1568 << CountMultiTextureTestCombinations(Machine
)
1569 << " multitexture combinations\n";
1571 env
->log
<< "\tTested "
1572 << CountCrossbarCombinations()
1573 << " crossbar combinations\n";
1576 } // TexCombineTest::logOne
1579 ///////////////////////////////////////////////////////////////////////////////
1580 // The test object itself:
1581 ///////////////////////////////////////////////////////////////////////////////
1582 TexCombineTest
texCombTest("texCombine", "window, rgb",
1584 "GL_EXT_texture_env_combine verification test.\n"
1585 "We only test a subset of all possible texture env combinations\n"
1586 "because there's simply too many to exhaustively test them all.\n");
1589 } // namespace GLEAN