summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolai Hähnle <nh@annarchy.freedesktop.org>2007-03-24 17:20:31 -0700
committerNicolai Hähnle <nh@annarchy.freedesktop.org>2007-03-24 17:20:31 -0700
commit22fbbb5e8679ddf91532cb10eaa31be533383b48 (patch)
treecb43f83fe997f166f297dad671ddf04e2f601be4
Initial commit
-rw-r--r--CMakeLists.txt8
-rw-r--r--HACKING85
-rw-r--r--README146
-rw-r--r--framework/__init__.py22
-rw-r--r--framework/core.py350
-rwxr-xr-xpiglit-run.py101
-rwxr-xr-xpiglit-summary-html.py414
-rw-r--r--templates/index.css89
-rw-r--r--templates/index.html40
-rw-r--r--templates/index_group.html6
-rw-r--r--templates/index_group_testrun.html1
-rw-r--r--templates/index_groupgroup.html1
-rw-r--r--templates/index_test.html5
-rw-r--r--templates/index_test_testrun.html1
-rw-r--r--templates/index_testrun.html1
-rw-r--r--templates/index_testrunb.html1
-rw-r--r--templates/result.css35
-rw-r--r--templates/result.html28
-rw-r--r--templates/result_detail.html4
-rw-r--r--templates/result_list.html3
-rw-r--r--templates/result_listitem.html1
-rw-r--r--templates/result_mstring.html1
-rw-r--r--tests/CMakeLists.txt5
-rw-r--r--tests/all.tests97
-rw-r--r--tests/bugs/CMakeLists.txt21
-rw-r--r--tests/bugs/fdo10370.c178
-rw-r--r--tests/bugs/fdo9833.c51
-rw-r--r--tests/glean/CMakeLists.txt69
-rw-r--r--tests/glean/basic.cpp64
-rw-r--r--tests/glean/codedid.cpp146
-rw-r--r--tests/glean/codedid.h92
-rw-r--r--tests/glean/dsconfig.cpp881
-rw-r--r--tests/glean/dsconfig.h210
-rw-r--r--tests/glean/dsfilt.cpp690
-rw-r--r--tests/glean/dsfilt.h268
-rw-r--r--tests/glean/dsurf.cpp263
-rw-r--r--tests/glean/dsurf.h103
-rw-r--r--tests/glean/environ.cpp161
-rw-r--r--tests/glean/environ.h111
-rw-r--r--tests/glean/geomrend.cpp504
-rw-r--r--tests/glean/geomrend.h146
-rw-r--r--tests/glean/geomutil.cpp360
-rw-r--r--tests/glean/geomutil.h100
-rw-r--r--tests/glean/gl.cpp82
-rw-r--r--tests/glean/glutils.cpp325
-rw-r--r--tests/glean/glutils.h111
-rw-r--r--tests/glean/glwrap.h784
-rw-r--r--tests/glean/image.h250
-rw-r--r--tests/glean/image_misc.cpp210
-rw-r--r--tests/glean/lex.cpp167
-rw-r--r--tests/glean/lex.h128
-rw-r--r--tests/glean/main.cpp347
-rw-r--r--tests/glean/misc.cpp82
-rw-r--r--tests/glean/misc.h50
-rw-r--r--tests/glean/options.cpp66
-rw-r--r--tests/glean/options.h97
-rw-r--r--tests/glean/pack.cpp262
-rw-r--r--tests/glean/rand.h125
-rw-r--r--tests/glean/rc.cpp159
-rw-r--r--tests/glean/rc.h68
-rw-r--r--tests/glean/rdtiff.cpp156
-rw-r--r--tests/glean/reg.cpp176
-rw-r--r--tests/glean/stats.h91
-rw-r--r--tests/glean/tbase.h414
-rw-r--r--tests/glean/tbasic.cpp68
-rw-r--r--tests/glean/tbasic.h69
-rw-r--r--tests/glean/tbasicperf.cpp189
-rw-r--r--tests/glean/tbasicperf.h85
-rw-r--r--tests/glean/tbinding.cpp199
-rw-r--r--tests/glean/tbinding.h73
-rw-r--r--tests/glean/tblend.cpp621
-rw-r--r--tests/glean/tblend.h69
-rw-r--r--tests/glean/tchgperf.cpp317
-rw-r--r--tests/glean/tchgperf.h72
-rw-r--r--tests/glean/tdepthstencil.cpp422
-rw-r--r--tests/glean/tdepthstencil.h80
-rw-r--r--tests/glean/test.cpp134
-rw-r--r--tests/glean/test.h152
-rw-r--r--tests/glean/tfpexceptions.cpp602
-rw-r--r--tests/glean/tfpexceptions.h78
-rw-r--r--tests/glean/tfragprog1.cpp1056
-rw-r--r--tests/glean/tfragprog1.h94
-rw-r--r--tests/glean/tgetstr.cpp167
-rw-r--r--tests/glean/tgetstr.h75
-rw-r--r--tests/glean/timer.cpp232
-rw-r--r--tests/glean/timer.h74
-rw-r--r--tests/glean/tlogicop.cpp573
-rw-r--r--tests/glean/tlogicop.h66
-rw-r--r--tests/glean/tmaskedclear.cpp266
-rw-r--r--tests/glean/tmaskedclear.h62
-rw-r--r--tests/glean/tmultitest.cpp109
-rw-r--r--tests/glean/tmultitest.h77
-rw-r--r--tests/glean/torthpos.cpp1159
-rw-r--r--tests/glean/torthpos.h103
-rw-r--r--tests/glean/tpaths.cpp373
-rw-r--r--tests/glean/tpaths.h79
-rw-r--r--tests/glean/tpgos.cpp735
-rw-r--r--tests/glean/tpgos.h124
-rw-r--r--tests/glean/tpixelformats.cpp1405
-rw-r--r--tests/glean/tpixelformats.h85
-rw-r--r--tests/glean/tpointatten.cpp259
-rw-r--r--tests/glean/tpointatten.h78
-rw-r--r--tests/glean/treadpix.cpp970
-rw-r--r--tests/glean/treadpix.h322
-rw-r--r--tests/glean/treadpixperf.cpp548
-rw-r--r--tests/glean/treadpixperf.h88
-rw-r--r--tests/glean/trgbtris.cpp196
-rw-r--r--tests/glean/trgbtris.h63
-rw-r--r--tests/glean/tscissor.cpp188
-rw-r--r--tests/glean/tscissor.h52
-rw-r--r--tests/glean/tteapot.cpp3215
-rw-r--r--tests/glean/tteapot.h63
-rw-r--r--tests/glean/ttexcombine.cpp1584
-rw-r--r--tests/glean/ttexcombine.h135
-rw-r--r--tests/glean/ttexcube.cpp426
-rw-r--r--tests/glean/ttexcube.h65
-rw-r--r--tests/glean/ttexenv.cpp667
-rw-r--r--tests/glean/ttexenv.h68
-rw-r--r--tests/glean/ttexgen.cpp371
-rw-r--r--tests/glean/ttexgen.h67
-rw-r--r--tests/glean/ttexrect.cpp217
-rw-r--r--tests/glean/ttexrect.h61
-rw-r--r--tests/glean/ttexture_srgb.cpp373
-rw-r--r--tests/glean/ttexture_srgb.h73
-rw-r--r--tests/glean/tvertattrib.cpp1620
-rw-r--r--tests/glean/tvertattrib.h93
-rw-r--r--tests/glean/tvertprog1.cpp1042
-rw-r--r--tests/glean/tvertprog1.h85
-rw-r--r--tests/glean/tvtxperf.cpp1424
-rw-r--r--tests/glean/tvtxperf.h147
-rw-r--r--tests/glean/unpack.cpp271
-rw-r--r--tests/glean/version.h47
-rw-r--r--tests/glean/winsys.cpp273
-rw-r--r--tests/glean/winsys.h117
-rw-r--r--tests/glean/wrtiff.cpp134
-rw-r--r--tests/mesa/CMakeLists.txt3
-rw-r--r--tests/mesa/tests/CMakeLists.txt23
-rw-r--r--tests/mesa/tests/afsmultiarb.c469
-rw-r--r--tests/mesa/tests/antialias.c229
-rw-r--r--tests/mesa/tests/api_speed.c146
-rw-r--r--tests/mesa/tests/arbfpspec.c192
-rw-r--r--tests/mesa/tests/arbfptest1.c210
-rw-r--r--tests/mesa/tests/arbfptexture.c153
-rw-r--r--tests/mesa/tests/arbfptrig.c156
-rw-r--r--tests/mesa/tests/arbnpot-mipmap.c184
-rw-r--r--tests/mesa/tests/arbnpot.c174
-rw-r--r--tests/mesa/tests/arbvptest1.c164
-rw-r--r--tests/mesa/tests/arbvptest3.c127
-rw-r--r--tests/mesa/tests/arbvptorus.c186
-rw-r--r--tests/mesa/tests/arbvpwarpmesh.c246
-rw-r--r--tests/mesa/tests/auxbuffer.c499
-rw-r--r--tests/mesa/tests/blendminmax.c209
-rw-r--r--tests/mesa/tests/blendsquare.c178
-rw-r--r--tests/mesa/tests/bufferobj.c371
-rw-r--r--tests/mesa/tests/bug_3050.c162
-rw-r--r--tests/mesa/tests/bug_3101.c128
-rw-r--r--tests/mesa/tests/bug_3195.c275
-rw-r--r--tests/mesa/tests/copypixrate.c259
-rw-r--r--tests/mesa/tests/crossbar.c305
-rw-r--r--tests/mesa/tests/cva.c164
-rw-r--r--tests/mesa/tests/debugger.c733
-rw-r--r--tests/mesa/tests/dinoshade.c914
-rw-r--r--tests/mesa/tests/ext422square.c258
-rw-r--r--tests/mesa/tests/fbotest1.c206
-rw-r--r--tests/mesa/tests/fbotest2.c199
-rw-r--r--tests/mesa/tests/fbotexture.c407
-rw-r--r--tests/mesa/tests/floattex.c169
-rw-r--r--tests/mesa/tests/fog.c199
-rw-r--r--tests/mesa/tests/fogcoord.c102
-rw-r--r--tests/mesa/tests/fptest1.c225
-rw-r--r--tests/mesa/tests/fptexture.c151
-rw-r--r--tests/mesa/tests/getprocaddress.c530
-rw-r--r--tests/mesa/tests/interleave.c406
-rw-r--r--tests/mesa/tests/invert.c195
-rw-r--r--tests/mesa/tests/jkrahntest.c181
-rw-r--r--tests/mesa/tests/manytex.c382
-rw-r--r--tests/mesa/tests/mipmap_limits.c252
-rw-r--r--tests/mesa/tests/multipal.c377
-rw-r--r--tests/mesa/tests/multitexarray.c238
-rw-r--r--tests/mesa/tests/multiwindow.c169
-rw-r--r--tests/mesa/tests/no_s3tc.c97
-rw-r--r--tests/mesa/tests/packedpixels.c342
-rw-r--r--tests/mesa/tests/pbo.c296
-rw-r--r--tests/mesa/tests/prog_parameter.c285
-rw-r--r--tests/mesa/tests/projtex.c1028
-rw-r--r--tests/mesa/tests/readrate.c285
-rw-r--r--tests/mesa/tests/seccolor.c145
-rw-r--r--tests/mesa/tests/sharedtex.c440
-rw-r--r--tests/mesa/tests/stencil_wrap.c257
-rw-r--r--tests/mesa/tests/stencilwrap.c281
-rw-r--r--tests/mesa/tests/subtexrate.c350
-rw-r--r--tests/mesa/tests/tex1d.c139
-rw-r--r--tests/mesa/tests/texcmp.c414
-rw-r--r--tests/mesa/tests/texcompress2.c273
-rw-r--r--tests/mesa/tests/texfilt.c398
-rw-r--r--tests/mesa/tests/texgenmix.c640
-rw-r--r--tests/mesa/tests/texline.c269
-rw-r--r--tests/mesa/tests/texobjshare.c219
-rw-r--r--tests/mesa/tests/texrect.c360
-rw-r--r--tests/mesa/tests/texwrap.c304
-rw-r--r--tests/mesa/tests/vao-01.c177
-rw-r--r--tests/mesa/tests/vao-02.c205
-rw-r--r--tests/mesa/tests/vparray.c294
-rw-r--r--tests/mesa/tests/vpeval.c231
-rw-r--r--tests/mesa/tests/vptest1.c170
-rw-r--r--tests/mesa/tests/vptest2.c151
-rw-r--r--tests/mesa/tests/vptest3.c120
-rw-r--r--tests/mesa/tests/vptorus.c174
-rw-r--r--tests/mesa/tests/vpwarpmesh.c236
-rw-r--r--tests/mesa/tests/yuvrect.c193
-rw-r--r--tests/mesa/tests/yuvsquare.c232
-rw-r--r--tests/mesa/tests/zreaddraw.c116
-rw-r--r--tests/mesa/util/CMakeLists.txt21
-rw-r--r--tests/mesa/util/dumpstate.c1958
-rw-r--r--tests/mesa/util/errcheck.c27
-rw-r--r--tests/mesa/util/glstate.c506
-rw-r--r--tests/mesa/util/glstate.h53
-rw-r--r--tests/mesa/util/glutskel.c139
-rw-r--r--tests/mesa/util/idproj.c26
-rw-r--r--tests/mesa/util/imagesgi.cpp369
-rw-r--r--tests/mesa/util/imagesgi.h55
-rw-r--r--tests/mesa/util/matrix.c181
-rw-r--r--tests/mesa/util/mwmborder.c91
-rw-r--r--tests/mesa/util/readtex.c454
-rw-r--r--tests/mesa/util/readtex.h26
-rw-r--r--tests/mesa/util/showbuffer.c192
-rw-r--r--tests/mesa/util/showbuffer.h36
-rw-r--r--tests/mesa/util/trackball.c338
-rw-r--r--tests/mesa/util/trackball.h84
-rw-r--r--tests/mesa/util/winpos.c43
-rw-r--r--tests/r300.tests26
-rw-r--r--tests/sanity.tests10
-rw-r--r--tests/shaders/CMakeLists.txt24
-rw-r--r--tests/shaders/fp-fragment-position.c498
-rw-r--r--tests/shaders/fp-incomplete-tex.c367
-rw-r--r--tests/shaders/fp-kil.c465
-rw-r--r--tests/shaders/fp-lit-mask.c282
-rw-r--r--tests/shaders/trinity-fp1.c438
238 files changed, 62894 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..d04be207
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+project (piglit)
+
+include(${CMAKE_ROOT}/Modules/FindOpenGL.cmake)
+include(${CMAKE_ROOT}/Modules/FindTIFF.cmake)
+include(${CMAKE_ROOT}/Modules/FindGLUT.cmake)
+
+add_subdirectory (tests)
diff --git a/HACKING b/HACKING
new file mode 100644
index 00000000..46c78c5a
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,85 @@
+
+
+\ Initial design decisions
+ -------------------------
+
+Before I started working on Piglit, I asked around for OpenGL testing methods.
+There were basically two kinds of tests:
+
+1. Glean, which is fully automatic and intends to test the letter of the
+ OpenGL specification (at least partially).
+
+2. Manual tests using Mesa samples or third-party software.
+
+The weakness of Glean is that it is not flexible, not pragmatic enough for
+driver development. For example, it tests for precision requirements in
+blending, where a driver just cannot reasonably improve on what the hardware
+delivers. As a driver developer, one wants to consider a test successful
+when it reaches the optimal results that the hardware can give, even when
+these results may be non-compliant.
+
+Manual tests are not well repeatable. They require a considerable amount of
+work on the part of the developer, so most of the time they aren't done at all.
+On the other hand, those manual tests have sometimes been created to test for
+a particular weakness in implementations, so they may be very suitable to
+detect future, similar weaknesses.
+
+Due to these weaknesses, the test coverage of open source OpenGL drivers
+is suboptimal at best. My goal for Piglit is to create a useful test system
+that helps driver developers in improving driver quality.
+
+With that in mind, my sub-goals are:
+
+1. Combine the strengths of the two kinds of tests (Glean, manual tests)
+ into a single framework.
+
+2. Provide concise, human readable summaries of the test results, with the
+ option to increase the detail of the report when desired.
+
+3. Allow easy visualization of regressions.
+
+4. Allow easy detection of performance regressions.
+
+I briefly considered extending Glean, but then decided for creating an
+entirely new project. The most important reasons are:
+
+1. I do not want to pollute the very clean philosophy behind Glean.
+
+2. The model behind Glean is that one process runs all the tests.
+ During driver development, one often gets bugs that cause tests to crash.
+ This means that one failed test can disrupt the entire test batch.
+ I want to use a more robust model, where each test runs in its own process.
+ This model does not easily fit onto Glean.
+
+3. The amount of code duplication and forking overhead is minimal because
+ a) I can use Glean as a "subroutine", so no code is actually duplicated,
+ there's just a tiny amount of additional Python glue code.
+ b) It's unlikely that this project makes significant changes to Glean
+ that need to be merged upstream.
+
+4. While it remains reasonable to use C++ for the actual OpenGL tests,
+ it is easier to use a higher level language like Python for the framework
+ (summary processing etc.)
+
+
+
+
+\ Ugly Things (or: Coding style)
+ -------------------------------
+
+As a rule of thumb, coding style should be preserved in test code taken from
+other projects, as long as that code is self-contained.
+
+Apart from that, the following rules are cast in stone:
+
+1. Use tabulators for indentation
+2. Use spaces for alignment
+3. No whitespace at the end of a line
+
+See http://electroly.com/mt/archives/000002.html for a well-written rationale.
+
+Use whatever tabulator size you want:
+If you adhere to the rules above, the tab size does not matter. Tab size 4
+is recommended because it keeps the line lengths reasonable, but in the end,
+that's purely a matter of personal taste.
+
diff --git a/README b/README
new file mode 100644
index 00000000..bf927e5f
--- /dev/null
+++ b/README
@@ -0,0 +1,146 @@
+
+Piglit
+------
+1. About
+2. Setup
+3. How to run tests
+4. How to write tests
+5. Todo
+
+
+1. About
+--------
+
+Piglit is a collection of automated tests for OpenGL implementations.
+
+The goal of Piglit is to help improve the quality of open source
+OpenGL drivers by providing developers with a simple means to
+perform regression tests.
+
+The original tests have been taken from
+- Glean ( http://glean.sf.net/ ) and
+- Mesa ( http://www.mesa3d.org/ )
+
+
+2. Setup
+--------
+
+First of all, you need to make sure that the following are installed:
+
+ - Python 2.4 or greater
+ - cmake (http://www.cmake.org)
+ - GL, glu and glut libraries and development packages (i.e. headers)
+ - X11 libraries and development packages (i.e. headers)
+ - libtiff
+
+Now configure the build system:
+
+ $ ccmake .
+
+This will start cmake's configuration tool, just follow the onscreen
+instructions. The default settings should be fine, but I recommend you:
+ - Press 'c' once (this will also check for dependencies) and then
+ - Set "CMAKE_BUILD_TYPE" to "Debug"
+Now you can press 'c' again and then 'g' to generate the build system.
+Now build everything:
+
+ $ make
+
+
+
+3. How to run tests
+-------------------
+
+Make sure that everything is set up correctly:
+
+ $ ./piglit-run.py tests/sanity.tests results/sanity.results
+
+This will run some minimal tests. Use
+
+ $ ./piglit-run.py
+
+to learn more about the command's syntax. Have a look into the tests/
+directory to see what test profiles are available:
+
+ $ cd tests
+ $ ls *.tests
+ ...
+ $ cd ..
+
+To create some nice formatted test summaries, run
+
+ $ ./piglit-summary-html.py summary/sanity results/sanity.results
+
+Hint: You can combine multiple test results into a single summary.
+ During development, you can use this to watch for regressions:
+
+ $ ./piglit-summary-html.py summary/compare results/baseline.results results/current.results
+
+ You can combine as many testruns as you want this way(in theory;
+ the HTML layout becomes awkward when the number of testruns increases)
+
+Have a look at the results with a browser:
+
+ $ xdg-open summary/sanity/index.html
+
+The summary shows the 'status' of a test:
+
+ pass This test has completed successfully.
+
+ warn The test completed successfully, but something unexpected happened.
+ Look at the details for more information.
+
+ fail The test failed.
+
+ skip The test was skipped.
+
+[Note: Once performance tests are implemented, 'fail' will mean that the test
+ rendered incorrectly or didn't complete, while 'warn' will indicate a
+ performance regression]
+[Note: For performance tests, result and status will be different concepts.
+ While status is always restricted to one of the four values above,
+ the result can contain a performance number like frames per second]
+
+
+4. How to write tests
+---------------------
+
+Every test is run as a separate process. This minimizes the impact that
+severe bugs like memory corruption have on the testing process.
+
+Therefore, tests can be implemented in an arbitrary standalone language.
+I recommend C, C++ and Python, as these are the languages that are already
+used in Piglit.
+
+All new tests must be added to the all.tests profile. The test profiles
+are simply Python scripts. There are currently two supported test types:
+
+ PlainExecTest
+ This test starts a new process and watches the process output (stdout and
+ stderr). Lines that start with "PIGLIT:" are collected and interpreted as
+ a Python dictionary that contains test result details.
+
+ GleanTest
+ This is a test that is only used to integrate Glean tests
+
+Additional test types (e.g. for automatic image comparison) would have to
+be added to core.py.
+
+Rules of thumb:
+ Test process that exit with a nonzero returncode are considered to have
+ failed.
+
+ Output on stderr causes a warning.
+
+
+5. Todo
+-------
+
+ Get automated tests into widespread use ;)
+
+ Automate and integrate tests and demos from Mesa
+ Add code that automatically tests whether the test has rendered correctly
+
+ Performance regression tests
+ Ideally, this should be done by summarizing / comparing a history of
+ test results
diff --git a/framework/__init__.py b/framework/__init__.py
new file mode 100644
index 00000000..51a5fed7
--- /dev/null
+++ b/framework/__init__.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# This permission notice shall be included in all copies or
+# substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
diff --git a/framework/core.py b/framework/core.py
new file mode 100644
index 00000000..053c75be
--- /dev/null
+++ b/framework/core.py
@@ -0,0 +1,350 @@
+#!/usr/bin/python
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# This permission notice shall be included in all copies or
+# substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+# Piglit core
+
+import errno
+import os
+import re
+import subprocess
+import sys
+import traceback
+
+__all__ = [
+ 'Environment',
+ 'loadTestProfile',
+ 'testPathToResultName',
+ 'GroupResult',
+ 'TestResult'
+]
+
+
+#############################################################################
+##### Helper functions
+#############################################################################
+
+# Ensure the given directory exists
+def checkDir(dirname, failifexists):
+ exists = True
+ try:
+ os.stat(dirname)
+ except OSError, e:
+ if e.errno == errno.ENOENT or e.errno == errno.ENOTDIR:
+ exists = False
+
+ if exists and failifexists:
+ print >>sys.stderr, "%(dirname)s exists already.\nUse --overwrite if you want to overwrite it.\n" % locals()
+ exit(1)
+
+ try:
+ os.makedirs(dirname)
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+
+def testPathToResultName(path):
+ elems = filter(lambda s: len(s) > 0, path.split('/'))
+ pyname = 'testrun.results' + "".join(map(lambda s: "['"+s+"']", elems))
+ return pyname
+
+
+#############################################################################
+##### Result classes
+#############################################################################
+
+
+class TestResult(dict):
+ def __init__(self, *args):
+ dict.__init__(self)
+
+ assert(len(args) == 0 or len(args) == 2)
+
+ if len(args) == 2:
+ for k in args[0]:
+ self.__setattr__(k, args[0][k])
+
+ self.update(args[1])
+
+ def __repr__(self):
+ attrnames = set(dir(self)) - set(dir(self.__class__()))
+ return '%(class)s(%(dir)s,%(dict)s)' % {
+ 'class': self.__class__.__name__,
+ 'dir': dict([(k, self.__getattribute__(k)) for k in attrnames]),
+ 'dict': dict.__repr__(self)
+ }
+
+
+class GroupResult(dict):
+ def __init__(self, *args):
+ dict.__init__(self)
+
+ assert(len(args) == 0 or len(args) == 2)
+
+ if len(args) == 2:
+ for k in args[0]:
+ self.__setattr__(k, args[0][k])
+
+ self.update(args[1])
+
+ def __repr__(self):
+ attrnames = set(dir(self)) - set(dir(self.__class__()))
+ return '%(class)s(%(dir)s,%(dict)s)' % {
+ 'class': self.__class__.__name__,
+ 'dir': dict([(k, self.__getattribute__(k)) for k in attrnames]),
+ 'dict': dict.__repr__(self)
+ }
+
+class TestrunResult:
+ def __init__(self, *args):
+ self.name = ''
+ self.results = GroupResult()
+
+
+
+#############################################################################
+##### Generic Test classes
+#############################################################################
+
+class Environment:
+ def __init__(self):
+ self.file = sys.stdout
+ self.execute = True
+ self.filter = []
+
+class Test:
+ ignoreErrors = []
+
+ def doRun(self, env, path):
+ # Filter
+ if len(env.filter) > 0:
+ if not True in map(lambda f: f.search(path) != None, env.filter):
+ return None
+
+ # Run the test
+ if env.execute:
+ try:
+ print "Test: %(path)s" % locals()
+ result = self.run()
+ if 'result' not in result:
+ result['result'] = 'fail'
+ if not isinstance(result, TestResult):
+ result = TestResult({}, result)
+ result['result'] = 'warn'
+ result['note'] = 'Result not returned as an instance of TestResult'
+ except:
+ result = TestResult()
+ result['result'] = 'fail'
+ result['exception'] = str(sys.exc_info()[0]) + str(sys.exc_info()[1])
+ result['traceback'] = '@@@' + "".join(traceback.format_tb(sys.exc_info()[2]))
+
+ print " result: %(result)s" % { 'result': result['result'] }
+
+ varname = testPathToResultName(path)
+ print >>env.file, "%(varname)s = %(result)s" % locals()
+ else:
+ print "Dry-run: %(path)s" % locals()
+
+ # Default handling for stderr messages
+ def handleErr(self, results, err):
+ errors = filter(lambda s: len(s) > 0, map(lambda s: s.strip(), err.split('\n')))
+
+ ignored = []
+ for s in errors:
+ ignore = False
+ for pattern in Test.ignoreErrors:
+ if type(pattern) == str:
+ if s.find(pattern) >= 0:
+ ignore = True
+ break
+ else:
+ if pattern.search(s):
+ ignore = True
+ break
+ if ignore:
+ ignored.append(s)
+
+ errors = [s for s in errors if s not in ignored]
+
+ if len(errors) > 0:
+ results['errors'] = errors
+
+ if results['result'] == 'pass':
+ results['result'] = 'warn'
+
+ if len(ignored) > 0:
+ results['errors_ignored'] = ignored
+
+
+class Group(dict):
+ def doRun(self, env, path):
+ print >>env.file, "%s = GroupResult()" % (testPathToResultName(path))
+ for sub in self:
+ spath = sub
+ if len(path) > 0:
+ spath = path + '/' + spath
+ self[sub].doRun(env, spath)
+
+#############################################################################
+##### PlainExecTest: Simply run an executable
+##### Expect one line prefixed PIGLIT: in the output, which contains a
+##### result dictionary. The plain output is appended to this dictionary
+#############################################################################
+class PlainExecTest(Test):
+ def __init__(self, command):
+ self.command = command
+
+ def run(self):
+ proc = subprocess.Popen(
+ self.command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE
+ )
+ out,err = proc.communicate()
+
+ outlines = out.split('\n')
+ outpiglit = map(lambda s: s[7:], filter(lambda s: s.startswith('PIGLIT:'), outlines))
+
+ results = TestResult()
+
+ if len(outpiglit) > 0:
+ try:
+ results.update(eval(''.join(outpiglit), {}))
+ out = '\n'.join(filter(lambda s: not s.startswith('PIGLIT:'), outlines))
+ except:
+ results['result'] = 'fail'
+ results['note'] = 'Failed to parse result string'
+
+ if 'result' not in results:
+ results['result'] = 'fail'
+
+ if proc.returncode != 0:
+ results['result'] = 'fail'
+ results['note'] = 'Returncode was %d' % (proc.returncode)
+
+ self.handleErr(results, err)
+
+ results['info'] = "@@@Returncode: %d\n\nErrors:\n%s\n\nOutput:\n%s" % (proc.returncode, err, out)
+ results['returncode'] = proc.returncode
+
+ return results
+
+
+
+#############################################################################
+##### GleanTest: Execute a sub-test of Glean
+#############################################################################
+def gleanExecutable():
+ return "./tests/glean/glean"
+
+def gleanResultDir():
+ return "./results/glean/"
+
+class GleanTest(Test):
+ globalParams = []
+
+ def __init__(self, name):
+ self.name = name
+ self.env = {}
+
+ def run(self):
+ results = TestResult()
+
+ fullenv = os.environ.copy()
+ for e in self.env:
+ fullenv[e] = str(self.env[e])
+
+ checkDir(gleanResultDir()+self.name, False)
+
+ glean = subprocess.Popen(
+ [gleanExecutable(), "-o", "-r", gleanResultDir()+self.name,
+ "--ignore-prereqs",
+ "-v", "-v", "-v",
+ "-t", "+"+self.name] + GleanTest.globalParams,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=fullenv
+ )
+
+ out, err = glean.communicate()
+
+ results['result'] = 'pass'
+ if glean.returncode != 0 or out.find('FAIL') >= 0:
+ results['result'] = 'fail'
+
+ results['returncode'] = glean.returncode
+
+ self.handleErr(results, err)
+
+ results['info'] = "@@@Returncode: %d\n\nErrors:\n%s\n\nOutput:\n%s" % (glean.returncode, err, out)
+
+ return results
+
+
+#############################################################################
+##### Loaders
+#############################################################################
+
+def loadTestProfile(filename):
+ try:
+ ns = {
+ '__file__': filename,
+ '__dir__': os.path.dirname(filename),
+ 'Test': Test,
+ 'Group': Group,
+ 'GleanTest': GleanTest,
+ 'gleanExecutable': gleanExecutable,
+ 'PlainExecTest': PlainExecTest
+ }
+ execfile(filename, ns)
+ return ns['tests']
+ except:
+ traceback.print_exc()
+ raise FatalError('Could not read tests profile')
+
+def loadTestResults(filename):
+ try:
+ ns = {
+ '__file__': filename,
+ 'GroupResult': GroupResult,
+ 'TestResult': TestResult,
+ 'TestrunResult': TestrunResult
+ }
+ execfile(filename, ns)
+
+ # BACKWARDS COMPATIBILITY
+ if 'testrun' not in ns:
+ testrun = TestrunResult()
+ testrun.results.update(ns['results'])
+ if 'name' in ns:
+ testrun.name = ns['name']
+ ns['testrun'] = testrun
+ # END BACKWARDS COMPATIBILITY
+
+ testrun = ns['testrun']
+ if len(testrun.name) == 0:
+ testrun.name = filename
+
+ return testrun
+ except:
+ traceback.print_exc()
+ raise FatalError('Could not read tests results')
diff --git a/piglit-run.py b/piglit-run.py
new file mode 100755
index 00000000..c9a3e6d4
--- /dev/null
+++ b/piglit-run.py
@@ -0,0 +1,101 @@
+#!/usr/bin/python
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# This permission notice shall be included in all copies or
+# substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+
+from getopt import getopt, GetoptError
+import os
+import os.path
+import re
+import sys
+
+import framework.core as core
+
+
+
+#############################################################################
+##### Main program
+#############################################################################
+def usage():
+ USAGE = """\
+Usage: %(progName)s [options] [profile.tests] [profile.results]
+
+Options:
+ -h, --help Show this message
+ -d, --dry-run Do not execute the tests
+ -t regexp, --tests=regexp Run only matching tests (can be used more
+ than once)
+ -n name, --name=name Name of the testrun
+
+Example:
+ %(progName)s tests/all.tests results/all.results
+ Run all tests, store the results in results/all.results
+
+ %(progName)s -t basic tests/all.tests results/all.results
+ Run all tests whose path contains the word 'basic'
+
+ %(progName)s -t ^glean/ -t tex tests/all.tests results/all.results
+ Run all tests that are in the 'glean' group or whose path contains
+ the substring 'tex'
+"""
+ print USAGE % {'progName': sys.argv[0]}
+ exit(1)
+
+def main():
+ env = core.Environment()
+
+ try:
+ options, args = getopt(sys.argv[1:], "hdt:n:", [ "help", "dry-run", "tests=", "name=" ])
+ except GetoptError:
+ usage()
+
+ OptionName = ''
+
+ for name,value in options:
+ if name in ('-h', '--help'):
+ usage()
+ elif name in ('-d', '--dry-run'):
+ env.execute = False
+ elif name in ('-t', '--tests'):
+ env.filter[:0] = [re.compile(value)]
+ elif name in ('-n', '--name'):
+ OptionName = value
+
+ if len(args) != 2:
+ usage()
+
+ profileFilename = args[0]
+ resultsFilename = args[1]
+
+ core.checkDir(os.path.dirname(resultsFilename), False)
+
+ profile = core.loadTestProfile(profileFilename)
+ env.file = open(resultsFilename, "w")
+ print >>env.file, """
+testrun = TestrunResult()
+testrun.name = %(name)s
+""" % { 'name': repr(OptionName) }
+ profile.doRun(env, '')
+ env.file.close()
+
+if __name__ == "__main__":
+ main()
diff --git a/piglit-summary-html.py b/piglit-summary-html.py
new file mode 100755
index 00000000..edad4f67
--- /dev/null
+++ b/piglit-summary-html.py
@@ -0,0 +1,414 @@
+#!/usr/bin/python
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# This permission notice shall be included in all copies or
+# substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+from getopt import getopt, GetoptError
+import errno
+import os
+import sys
+
+import framework.core as core
+
+#############################################################################
+##### Auxiliary functions
+#############################################################################
+
+def testPathToHtmlFilename(path):
+ return filter(lambda s: s.isalnum() or s == '_', path.replace('/', '__')) + '.html'
+
+
+#############################################################################
+##### Annotation preprocessing
+#############################################################################
+
+class PassVector:
+ def __init__(self,p,w,f,s):
+ self.passnr = p
+ self.warnnr = w
+ self.failnr = f
+ self.skipnr = s
+
+ def add(self,o):
+ self.passnr += o.passnr
+ self.warnnr += o.warnnr
+ self.failnr += o.failnr
+ self.skipnr += o.skipnr
+
+def annotateOneTest(path, results):
+ """\
+Result is an array containing one test result.
+"""
+ result = ''
+ if 'result' in results:
+ result = results['result']
+
+ vectormap = {
+ 'pass': PassVector(1,0,0,0),
+ 'warn': PassVector(0,1,0,0),
+ 'fail': PassVector(0,0,1,0),
+ 'skip': PassVector(0,0,0,1)
+ }
+
+ if result not in vectormap:
+ result = 'warn'
+
+ results.status = result
+ results.passvector = vectormap[result]
+ results.path = path
+
+ return results
+
+
+def annotateTest(path, results):
+ """\
+Result is an array containing corresponding test results, one per test run
+"""
+ for j in range(len(results)):
+ results[j] = annotateOneTest(path, results[j])
+
+ stati = set([r.status for r in results])
+ changes = len(stati) > 1
+ problems = len(stati - set(['pass', 'skip'])) > 0
+ for r in results:
+ r.changes = changes
+ r.problems = problems
+
+
+def annotateGroup(path, results):
+ """\
+Result is an array containing corresponding GroupResults, one per test run
+"""
+ groupnames = set()
+ testnames = set()
+
+ changes = False
+ problems = False
+
+ for r in results:
+ r.passvector = PassVector(0,0,0,0)
+ r.path = path
+
+ for name in r:
+ if type(name) != str:
+ continue
+
+ if isinstance(r[name], core.GroupResult):
+ groupnames.add(name)
+ else:
+ testnames.add(name)
+
+ for name in groupnames:
+ children = []
+
+ for r in results:
+ if name not in r:
+ r[name] = core.GroupResult()
+
+ children.append(r[name])
+
+ spath = name
+ if len(path) > 0:
+ spath = path + '/' + spath
+
+ annotateGroup(spath, children)
+
+ changes = changes or results[0][name].changes
+ problems = problems or results[0][name].problems
+
+ for r in results:
+ r.passvector.add(r[name].passvector)
+
+
+ for name in testnames:
+ children = []
+
+ for r in results:
+ if name not in r:
+ r[name] = core.TestResult({}, { 'result': 'skip' })
+
+ # BACKWARDS COMPATIBILITY
+ if not isinstance(r[name], core.TestResult):
+ r[name] = core.TestResult({}, r[name])
+ # END BACKWARDS COMPATIBILITY
+
+ children.append(r[name])
+
+ spath = name
+ if len(path) > 0:
+ spath = path + '/' + spath
+
+ annotateTest(spath, children)
+
+ changes = changes or results[0][name].changes
+ problems = problems or results[0][name].problems
+
+ for r in results:
+ r.passvector.add(r[name].passvector)
+
+ for r in results:
+ r.changes = changes
+ r.problems = problems
+
+
+#############################################################################
+##### HTML output
+#############################################################################
+
+def readfile(filename):
+ f = open(filename, "r")
+ s = f.read()
+ f.close()
+ return s
+
+def writefile(filename, text):
+ f = open(filename, "w")
+ f.write(text)
+ f.close()
+
+Result = readfile('templates/result.html')
+ResultDetail = readfile('templates/result_detail.html')
+ResultList = readfile('templates/result_list.html')
+ResultListItem = readfile('templates/result_listitem.html')
+ResultMString = readfile('templates/result_mstring.html')
+
+Index = readfile('templates/index.html')
+IndexTestrun = readfile('templates/index_testrun.html')
+IndexTestrunB = readfile('templates/index_testrunb.html')
+IndexGroup = readfile('templates/index_group.html')
+IndexGroupTestrun = readfile('templates/index_group_testrun.html')
+IndexGroupGroup = readfile('templates/index_groupgroup.html')
+IndexTest = readfile('templates/index_test.html')
+IndexTestTestrun = readfile('templates/index_test_testrun.html')
+
+SummaryPages = {
+ 'all': 'index.html',
+ 'changes': 'changes.html',
+ 'problems': 'problems.html'
+}
+
+def buildDetailValue(detail):
+ if type(detail) == list:
+ items = ''
+
+ for d in detail:
+ items = items + ResultListItem % { 'detail': buildDetailValue(d) }
+
+ return ResultList % { 'items': items }
+ elif type(detail) == str and detail[0:3] == '@@@':
+ return ResultMString % { 'detail': detail[3:] }
+
+ return str(detail)
+
+
+def buildDetails(testResult):
+ details = []
+ for name in testResult:
+ if type(name) != str or name == 'result':
+ continue
+
+ value = buildDetailValue(testResult[name])
+ details += [(name,value)]
+
+ details.sort(lambda a,b: len(a[1])-len(b[1]))
+
+ text = ''
+ alternate = 'a'
+ for name,value in details:
+ text += ResultDetail % locals()
+
+ if alternate == 'a':
+ alternate = 'b'
+ else:
+ alternate = 'a'
+
+ return text
+
+
+def writeResultHtml(testResult, filename):
+ path = testResult.path
+ name = testResult.path.split('/')[-1]
+ status = testResult.status
+
+ if 'result' in testResult:
+ result = testResult['result']
+ else:
+ result = '?'
+
+ details = buildDetails(testResult)
+
+ writefile(filename, Result % locals())
+
+
+def recursiveWriteResultHtml(results, summaryDir):
+ for n in results:
+ if type(n) != str:
+ continue
+
+ if isinstance(results[n], core.GroupResult):
+ recursiveWriteResultHtml(results[n], summaryDir)
+ else:
+ writeResultHtml(results[n], summaryDir + '/' + testPathToHtmlFilename(results[n].path))
+
+
+def buildTestSummary(indent, alternate, name, test):
+ tenindent = 10 - indent
+ testruns = "".join([IndexTestTestrun % {
+ 'alternate': alternate,
+ 'status': t.status,
+ 'link': r.codename + '/' + testPathToHtmlFilename(t.path)
+ } for r,t in test])
+
+ return IndexTest % locals()
+
+
+def buildGroupSummaryTestrun(results, group):
+ passnr = group.passvector.passnr
+ warnnr = group.passvector.warnnr
+ failnr = group.passvector.failnr
+ skipnr = group.passvector.skipnr
+ totalnr = passnr + warnnr + failnr # do not count skips
+
+ if failnr > 0:
+ status = 'fail'
+ elif warnnr > 0:
+ status = 'warn'
+ elif passnr > 0:
+ status = 'pass'
+ else:
+ status = 'skip'
+
+ return IndexGroupTestrun % locals()
+
+
+def buildGroupSummary(indent, name, results, showcurrent):
+ """\
+testruns is an array of pairs (results,group), where results is the
+entire testrun record and group is the group we're currently printing.
+"""
+ tenindent = 10 - indent
+
+ items = ''
+ alternate = 'a'
+ names = filter(lambda k: type(k) == str, results[0][1])
+
+ if showcurrent == 'changes':
+ names = filter(lambda n: results[0][1][n].changes, names)
+ elif showcurrent == 'problems':
+ names = filter(lambda n: results[0][1][n].problems, names)
+
+ names.sort()
+ for n in names:
+ if isinstance(results[0][1][n], core.GroupResult):
+ items = items + IndexGroupGroup % {
+ 'group': buildGroupSummary(indent+1, n, [(r,g[n]) for r,g in results], showcurrent)
+ }
+ else:
+ items = items + buildTestSummary(indent+1, alternate, n, [(r,g[n]) for r,g in results])
+
+ if alternate == 'a':
+ alternate = 'b'
+ else:
+ alternate = 'a'
+
+ testruns = "".join([buildGroupSummaryTestrun(r,g) for r,g in results])
+
+ return IndexGroup % locals()
+
+
+def writeSummaryHtml(results, summaryDir, showcurrent):
+ """\
+results is an array containing the top-level results dictionarys.
+"""
+ def link(to):
+ if to == showcurrent:
+ return to
+ else:
+ page = SummaryPages[to]
+ return '<a href="%(page)s">%(to)s</a>' % locals()
+
+ group = buildGroupSummary(1, 'Total', [(r,r.results) for r in results], showcurrent)
+ testruns = "".join([IndexTestrun % r.__dict__ for r in results])
+ testrunsb = "".join([IndexTestrunB % r.__dict__ for r in results])
+
+ tolist = SummaryPages.keys()
+ tolist.sort()
+ showlinks = " | ".join([link(to) for to in tolist])
+
+ writefile(summaryDir + '/' + SummaryPages[showcurrent], Index % locals())
+
+
+#############################################################################
+##### Main program
+#############################################################################
+def usage():
+ USAGE = """\
+Usage: %(progName)s [options] [summary-dir] [test.results]...
+
+Options:
+ -h, --help Show this message
+ -o, --overwrite Overwrite existing directories
+
+Example:
+ %(progName)s summary/mysum results/all.results
+"""
+ print USAGE % {'progName': sys.argv[0]}
+ exit(1)
+
+
+def main():
+ try:
+ options, args = getopt(sys.argv[1:], "ho", [ "help", "overwrite" ])
+ except GetoptError:
+ usage()
+
+ OptionOverwrite = False
+ for name,value in options:
+ if name == "-h" or name == "--help":
+ usage()
+ elif name == "-o" or name == "--overwrite":
+ OptionOverwrite = True
+
+ if len(args) < 2:
+ usage()
+
+ summaryDir = args[0]
+ resultFilenames = args[1:]
+
+ core.checkDir(summaryDir, not OptionOverwrite)
+
+ results = [core.loadTestResults(name) for name in resultFilenames]
+
+ annotateGroup('', [r.results for r in results])
+ for r in results:
+ r.codename = filter(lambda s: s.isalnum(), r.name)
+ core.checkDir(summaryDir + '/' + r.codename, False)
+ recursiveWriteResultHtml(r.results, summaryDir + '/' + r.codename)
+
+ writefile(summaryDir + '/result.css', readfile('templates/result.css'))
+ writefile(summaryDir + '/index.css', readfile('templates/index.css'))
+ writeSummaryHtml(results, summaryDir, 'all')
+ writeSummaryHtml(results, summaryDir, 'problems')
+ writeSummaryHtml(results, summaryDir, 'changes')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/templates/index.css b/templates/index.css
new file mode 100644
index 00000000..3e10f8d2
--- /dev/null
+++ b/templates/index.css
@@ -0,0 +1,89 @@
+
+table {
+ border: 0pt;
+ border-collapse: collapse;
+}
+
+tr {
+ padding: 4pt;
+}
+
+td {
+ padding: 4pt;
+}
+
+.title {
+ background-color: #c8c838;
+}
+
+.head {
+ background-color: #c8c838
+}
+
+.a {
+ background-color: #ffff95
+}
+
+.b {
+ background-color: #e1e183
+}
+
+.skip {
+ text-align: right;
+ background-color: #b0b0b0;
+}
+
+.warn {
+ text-align: right;
+ background-color: #ff9020;
+}
+
+.fail {
+ text-align: right;
+ background-color: #ff2020;
+}
+
+.pass {
+ text-align: right;
+ background-color: #20ff20;
+}
+
+.skipa {
+ text-align: right;
+ background-color: #d0d0d0;
+}
+
+.warna {
+ text-align: right;
+ background-color: #ffc050;
+}
+
+.faila {
+ text-align: right;
+ background-color: #ff5050;
+}
+
+.passa {
+ text-align: right;
+ background-color: #50ff50;
+}
+
+.skipb {
+ text-align: right;
+ background-color: #c0c0c0;
+}
+
+.warnb {
+ text-align: right;
+ background-color: #ffa040;
+}
+
+.failb {
+ text-align: right;
+ background-color: #ff4040;
+}
+
+.passb {
+ text-align: right;
+ background-color: #40ff40;
+}
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 00000000..d6bf392d
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,40 @@
+<html>
+ <head>
+ <title>Result summary </title>
+ <link rel="stylesheet" href="index.css"/>
+ </head>
+ <body>
+ <h1>Result summary</h1>
+ <p>
+ Currently showing: %(showcurrent)s
+ </p>
+ <p>
+ Show: %(showlinks)s
+ </p>
+ <table width="95%%">
+ <colgroup>
+ <!-- 9 columns for indent -->
+ <col width="5pt" />
+ <col width="20pt" />
+ <col width="20pt" />
+ <col width="20pt" />
+ <col width="20pt" />
+ <col width="20pt" />
+ <col width="20pt" />
+ <col width="20pt" />
+ <col width="20pt" />
+
+ <!-- remaining name column -->
+ <col />
+
+ <!-- status column -->
+ %(testruns)s
+ </colgroup>
+ <tr>
+ <td colspan="10" />
+ %(testrunsb)s
+ </tr>
+ %(group)s
+ </table>
+ </body>
+</html>
diff --git a/templates/index_group.html b/templates/index_group.html
new file mode 100644
index 00000000..9c72bcff
--- /dev/null
+++ b/templates/index_group.html
@@ -0,0 +1,6 @@
+<tr>
+ <td colspan="%(indent)s">&#160;</td>
+ <td class="head" colspan="%(tenindent)s"><b>%(name)s</b></td>
+ %(testruns)s
+</tr>
+%(items)s
diff --git a/templates/index_group_testrun.html b/templates/index_group_testrun.html
new file mode 100644
index 00000000..07b53421
--- /dev/null
+++ b/templates/index_group_testrun.html
@@ -0,0 +1 @@
+<td class="%(status)s"><b>%(passnr)d/%(totalnr)d</b></td>
diff --git a/templates/index_groupgroup.html b/templates/index_groupgroup.html
new file mode 100644
index 00000000..53db6070
--- /dev/null
+++ b/templates/index_groupgroup.html
@@ -0,0 +1 @@
+%(group)s
diff --git a/templates/index_test.html b/templates/index_test.html
new file mode 100644
index 00000000..0c3bdde6
--- /dev/null
+++ b/templates/index_test.html
@@ -0,0 +1,5 @@
+<tr>
+ <td colspan="%(indent)s">&#160;</td>
+ <td class="%(alternate)s" colspan="%(tenindent)s">%(name)s</td>
+ %(testruns)s
+</tr>
diff --git a/templates/index_test_testrun.html b/templates/index_test_testrun.html
new file mode 100644
index 00000000..43de898b
--- /dev/null
+++ b/templates/index_test_testrun.html
@@ -0,0 +1 @@
+<td class="%(status)s%(alternate)s"><a href="%(link)s">%(status)s</a></td>
diff --git a/templates/index_testrun.html b/templates/index_testrun.html
new file mode 100644
index 00000000..1dc68ffe
--- /dev/null
+++ b/templates/index_testrun.html
@@ -0,0 +1 @@
+<col width="50pt" />
diff --git a/templates/index_testrunb.html b/templates/index_testrunb.html
new file mode 100644
index 00000000..b4ef7ecc
--- /dev/null
+++ b/templates/index_testrunb.html
@@ -0,0 +1 @@
+<td class="head"><b>%(name)s</b></td>
diff --git a/templates/result.css b/templates/result.css
new file mode 100644
index 00000000..7c6a557c
--- /dev/null
+++ b/templates/result.css
@@ -0,0 +1,35 @@
+
+td {
+ padding: 4pt;
+}
+
+th {
+ padding: 4pt;
+}
+
+table {
+ border: 0pt;
+ border-collapse: collapse;
+}
+
+.head {
+ background-color: #c8c838
+}
+
+.a {
+ background-color: #ffff95
+}
+
+.b {
+ background-color: #e1e183
+}
+
+.bara {
+ vertical-align: top;
+ background-color: #ffff85;
+}
+
+.barb {
+ vertical-align: top;
+ background-color: #d1d173;
+}
diff --git a/templates/result.html b/templates/result.html
new file mode 100644
index 00000000..d6167e7b
--- /dev/null
+++ b/templates/result.html
@@ -0,0 +1,28 @@
+<html>
+ <head>
+ <title>%(path)s - Details</title>
+ <link rel="stylesheet" href="../result.css"/>
+ </head>
+ <body>
+ <h1>Results for %(path)s</h1>
+ <h2>Overview</h2>
+ <p>
+ <b>Status:</b> %(status)s<br/>
+ <b>Result:</b> %(result)s<br/>
+ </p>
+ <p>
+ <a href="../index.html">Back to summary</a>
+ </p>
+ <h2>Details</h2>
+ <table>
+ <tr class="head">
+ <th>Detail</th>
+ <th>Value</th>
+ </tr>
+ %(details)s
+ </table>
+ <p>
+ <a href="../index.html">Back to summary</a>
+ </p>
+ </body>
+</html>
diff --git a/templates/result_detail.html b/templates/result_detail.html
new file mode 100644
index 00000000..d735d0da
--- /dev/null
+++ b/templates/result_detail.html
@@ -0,0 +1,4 @@
+<tr>
+ <td class="bar%(alternate)s">%(name)s</td>
+ <td class="%(alternate)s">%(value)s</td>
+</tr>
diff --git a/templates/result_list.html b/templates/result_list.html
new file mode 100644
index 00000000..af215d48
--- /dev/null
+++ b/templates/result_list.html
@@ -0,0 +1,3 @@
+<ul>
+%(items)s
+</ul>
diff --git a/templates/result_listitem.html b/templates/result_listitem.html
new file mode 100644
index 00000000..12ef6ebf
--- /dev/null
+++ b/templates/result_listitem.html
@@ -0,0 +1 @@
+<li>%(detail)s</li>
diff --git a/templates/result_mstring.html b/templates/result_mstring.html
new file mode 100644
index 00000000..b4c91d8a
--- /dev/null
+++ b/templates/result_mstring.html
@@ -0,0 +1 @@
+<pre>%(detail)s</pre>
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 00000000..8cbc961e
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,5 @@
+
+add_subdirectory (bugs)
+add_subdirectory (glean)
+add_subdirectory (mesa)
+add_subdirectory (shaders)
diff --git a/tests/all.tests b/tests/all.tests
new file mode 100644
index 00000000..931ec366
--- /dev/null
+++ b/tests/all.tests
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+# All tests that come with piglit, using default settings
+
+import re
+import subprocess
+
+######
+# Glean sub-tests
+glean_fragprog1 = Group()
+
+out,err = subprocess.Popen(
+ [gleanExecutable(), "-t", "+fragProg1", "--listdetails"],
+ stdout=subprocess.PIPE
+).communicate()
+
+st = 0
+for line in out.split('\n'):
+ if st == 0:
+ if line == "DETAILS for fragProg1":
+ st = 1
+ elif st == 1:
+ if line == "END DETAILS":
+ break
+
+ line = line.strip()
+ line = filter(lambda s: s.isalnum() or s in ' ()-_', line)
+
+ t = GleanTest('fragProg1')
+ t.env['GLEAN_FRAGPROG'] = line
+ glean_fragprog1[line] = t
+
+
+######
+# Collecting all tests
+glean = Group()
+glean['basic'] = GleanTest('basic')
+glean['makeCurrent'] = GleanTest('makeCurrent')
+glean['blendFunc'] = GleanTest('blendFunc')
+glean['depthStencil'] = GleanTest('depthStencil')
+glean['fpexceptions'] = GleanTest('fpexceptions')
+glean['fragProg1'] = GleanTest('fragProg1') # also add entire tests, because of interdependency bugs that only occur when several different FPs are used
+glean['getString'] = GleanTest('getString')
+glean['logicOp'] = GleanTest('logicOp')
+glean['maskedClear'] = GleanTest('maskedClear')
+glean['orthoPosRandTris'] = GleanTest('orthoPosRandTris')
+glean['orthoPosRandRects'] = GleanTest('orthoPosRandRects')
+glean['orthoPosTinyQuads'] = GleanTest('orthoPosTinyQuads')
+glean['orthoPosHLines'] = GleanTest('orthoPosHLines')
+glean['orthoPosVLines'] = GleanTest('orthoPosVLines')
+glean['orthoPosPoints'] = GleanTest('orthoPosPoints')
+glean['paths'] = GleanTest('paths')
+glean['polygonOffset'] = GleanTest('polygonOffset')
+glean['pixelFormats'] = GleanTest('pixelFormats')
+glean['pointAtten'] = GleanTest('pointAtten')
+glean['exactRGBA'] = GleanTest('exactRGBA')
+glean['readPixSanity'] = GleanTest('readPixSanity')
+glean['rgbTriStrip'] = GleanTest('rgbTriStrip')
+glean['scissor'] = GleanTest('scissor')
+glean['teapot'] = GleanTest('teapot')
+glean['texCombine'] = GleanTest('texCombine')
+glean['texCube'] = GleanTest('texCube')
+glean['texEnv'] = GleanTest('texEnv')
+glean['texgen'] = GleanTest('texgen')
+glean['texRect'] = GleanTest('texRect')
+glean['texture_srgb'] = GleanTest('texture_srgb')
+glean['vertattrib'] = GleanTest('vertattrib')
+glean['vertProg1'] = GleanTest('vertProg1')
+
+mesa = Group()
+mesa['crossbar'] = PlainExecTest([__dir__ + '/mesa/tests/crossbar', '-auto'])
+
+shaders = Group()
+shaders['trinity-fp1'] = PlainExecTest([__dir__ + '/shaders/trinity-fp1', '-auto'])
+shaders['fp-lit-mask'] = PlainExecTest([__dir__ + '/shaders/fp-lit-mask', '-auto'])
+shaders['fp-fragment-position'] = PlainExecTest([__dir__ + '/shaders/fp-fragment-position', '-auto'])
+shaders['fp-kil'] = PlainExecTest([__dir__ + '/shaders/fp-kil', '-auto'])
+shaders['fp-incomplete-tex'] = PlainExecTest([__dir__ + '/shaders/fp-incomplete-tex', '-auto'])
+shaders['glean-fragProg1'] = glean_fragprog1
+
+bugs = Group()
+bugs['fdo9833'] = PlainExecTest([__dir__ + '/bugs/fdo9833', '-auto'])
+bugs['fdo10370'] = PlainExecTest([__dir__ + '/bugs/fdo10370', '-auto'])
+
+tests = Group()
+tests['bugs'] = bugs
+tests['glean'] = glean
+tests['mesa'] = mesa
+tests['shaders'] = shaders
+
+#############
+# Some Mesa diagnostic messages that we should probably ignore
+Test.ignoreErrors.append("couldn't open libtxc_dxtn.so")
+Test.ignoreErrors.append(re.compile("Mesa: .*build"))
+Test.ignoreErrors.append(re.compile("Mesa: CPU.*"))
+Test.ignoreErrors.append(re.compile("Mesa: .*cpu detected."))
+Test.ignoreErrors.append(re.compile("Mesa: Test.*"))
+Test.ignoreErrors.append(re.compile("Mesa: Yes.*"))
diff --git a/tests/bugs/CMakeLists.txt b/tests/bugs/CMakeLists.txt
new file mode 100644
index 00000000..3f282581
--- /dev/null
+++ b/tests/bugs/CMakeLists.txt
@@ -0,0 +1,21 @@
+
+include_directories(
+ ${OPENGL_INCLUDE_PATH}
+ ${GLUT_INCLUDE_DIR}
+ ${piglit_SOURCE_DIR}/tests/mesa/util
+)
+
+link_directories (
+ ${piglit_SOURCE_DIR}/tests/mesa/util
+)
+
+link_libraries (
+ ${OPENGL_gl_LIBRARY}
+ ${OPENGL_glu_LIBRARY}
+ ${GLUT_glut_LIBRARY}
+ ${TIFF_LIBRARY}
+ mesautil
+)
+
+add_executable (fdo9833 fdo9833.c)
+add_executable (fdo10370 fdo10370.c)
diff --git a/tests/bugs/fdo10370.c b/tests/bugs/fdo10370.c
new file mode 100644
index 00000000..bfbfc4b2
--- /dev/null
+++ b/tests/bugs/fdo10370.c
@@ -0,0 +1,178 @@
+/*
+ * Test case from fdo bug #10370
+ * http://bugs.freedesktop.org/show_bug.cgi?id=10370
+ */
+
+#include "GL/glut.h"
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static int Automatic = 0;
+
+#define WIN_WIDTH 128
+#define WIN_HEIGHT 128
+#define BITMAP_WIDTH 1
+#define BITMAP_HEIGHT 1
+#define ALIGN 1
+GLfloat read_buf[4 * BITMAP_WIDTH * BITMAP_HEIGHT];
+static GLfloat r_map[] = { 0, 1 };
+static GLfloat g_map[] = { 0, 0 };
+static GLfloat b_map[] = { 1, 0 };
+static GLfloat a_map[] = { 1, 1 };
+static GLubyte data[] = { 0x8f, 0xff, 0x7f, 0x70 };
+
+static GLuint tex_name;
+
+void init()
+{
+ int i, j;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glTranslatef(-1.0, -1.0, 0.0);
+ glScalef(2.0/WIN_WIDTH, 2.0/WIN_HEIGHT, 1.0);
+
+ glDisable(GL_DITHER);
+ glClearColor(1, 1, 1, 1);
+ glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
+
+ glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 2, r_map);
+ glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 2, g_map);
+ glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 2, b_map);
+ glPixelMapfv(GL_PIXEL_MAP_I_TO_A, 2, a_map);
+
+ glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
+
+ glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, ALIGN);
+
+ glGenTextures(1, &tex_name);
+ glBindTexture(GL_TEXTURE_2D, tex_name);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+}
+
+
+
+void display()
+{
+ int i, j, k, col, pixel;
+ GLubyte zero_data = 0;
+ GLfloat expected[4];
+ float dmax = 0.0;
+
+ memset(read_buf, 0xff, sizeof(read_buf)); //reset
+
+ for (k = 0; k < (sizeof(data)/sizeof(GLubyte)); k ++) {
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ glNewList(1, GL_COMPILE_AND_EXECUTE);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, tex_name);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ BITMAP_WIDTH, BITMAP_HEIGHT, 0,
+ GL_COLOR_INDEX, GL_BITMAP, &data[k]);
+
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0,0); glVertex2f(0, 0);
+ glTexCoord2f(1,0); glVertex2f(BITMAP_WIDTH, 0);
+ glTexCoord2f(1,1); glVertex2f(BITMAP_WIDTH, BITMAP_HEIGHT);
+ glTexCoord2f(0,1); glVertex2f(0, BITMAP_HEIGHT);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+ glEndList();
+ glFlush();
+
+ glReadPixels(0, 0, BITMAP_WIDTH, BITMAP_HEIGHT,
+ GL_RGBA, GL_FLOAT, read_buf);
+
+ printf("data[0x%x], ", data[k]);
+ if (data[k] & 0x80) {
+ printf("foreground: expected RGBA (%1.1f, %1.1f %1.1f %1.1f)\n",
+ r_map[1], g_map[1], b_map[1], a_map[1]);
+ expected[0] = r_map[1];
+ expected[1] = g_map[1];
+ expected[2] = b_map[1];
+ expected[3] = a_map[1];
+ } else {
+ printf("background: expected RGBA (%1.1f, %1.1f %1.1f %1.1f)\n",
+ r_map[0], g_map[0], b_map[0], a_map[0]);
+ expected[0] = r_map[0];
+ expected[1] = g_map[0];
+ expected[2] = b_map[0];
+ expected[3] = a_map[0];
+ }
+
+ printf("First execution, Readback RGBA:\n");
+ for (i = 0; i < BITMAP_HEIGHT; i ++) {
+ for (j = 0; j < BITMAP_WIDTH; j ++) {
+ pixel = j + i*BITMAP_WIDTH;
+ printf("pixel[%d, %d]: %1.1f %1.1f %1.1f %1.1f\n", j, i,
+ read_buf[pixel*4], read_buf[pixel*4+1],
+ read_buf[pixel*4+2], read_buf[pixel*4+3]);
+
+ for(col = 0; col < 4; ++col) {
+ float delta = read_buf[pixel*4+col] - expected[col];
+ if (delta > dmax) dmax = delta;
+ else if (-delta > dmax) dmax = -delta;
+ }
+ }
+ }
+
+ /* 2nd time execution from call list */
+ glCallList(1);
+ glDeleteLists(1,1);
+
+ memset(read_buf, 0xff, sizeof(read_buf)); //reset
+ glReadPixels(0, 0, BITMAP_WIDTH, BITMAP_HEIGHT,
+ GL_RGBA, GL_FLOAT, read_buf);
+
+ printf("CallList execution, Readback RGBA:\n");
+ for (i = 0; i < BITMAP_HEIGHT; i ++) {
+ for (j = 0; j < BITMAP_WIDTH; j ++) {
+ pixel = j + i*BITMAP_WIDTH;
+ printf("pixel[%d, %d]: %1.1f %1.1f %1.1f %1.1f\n", j, i,
+ read_buf[pixel*4], read_buf[pixel*4+1],
+ read_buf[pixel*4+2], read_buf[pixel*4+3]);
+ for(col = 0; col < 4; ++col) {
+ float delta = read_buf[pixel*4+col] - expected[col];
+ if (delta > dmax) dmax = delta;
+ else if (-delta > dmax) dmax = -delta;
+ }
+ }
+ }
+ printf("------------------------------------\n");
+ } //end for(k)
+
+ printf("max delta: %f\n", dmax);
+
+ if (Automatic) {
+ if (dmax > 0.02)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ else
+ printf("PIGLIT: {'result': 'pass' }\n");
+
+ exit(0);
+ }
+}
+
+
+int main(int argc, char**argv)
+{
+ glutInit(&argc, argv);
+ if (argc == 2 && !strcmp(argv[1], "-auto"))
+ Automatic = 1;
+ glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
+ glutInitWindowSize (WIN_WIDTH, WIN_HEIGHT);
+ glutInitWindowPosition (100, 100);
+ glutCreateWindow ("fdo10370");
+ init();
+ glutDisplayFunc(display);
+ glutMainLoop();
+}
diff --git a/tests/bugs/fdo9833.c b/tests/bugs/fdo9833.c
new file mode 100644
index 00000000..c14c0a65
--- /dev/null
+++ b/tests/bugs/fdo9833.c
@@ -0,0 +1,51 @@
+/**
+ * Test case from fd.o bug #9833.
+ * https://bugs.freedesktop.org/show_bug.cgi?id=9833
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <GL/glut.h>
+
+static int Automatic = 0;
+
+static void display(void)
+{
+ static int goterrors = 0;
+ static int frame = 0;
+ GLuint error;
+
+ frame++;
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glPushAttrib(GL_TEXTURE_BIT);
+ while ( (error = glGetError()) != GL_NO_ERROR) {
+ fprintf(stderr, "OpenGL error 0x%0x occured after glPushAttrib!\n", error);
+ goterrors++;
+ }
+
+
+ glPopAttrib();
+ while ( (error = glGetError()) != GL_NO_ERROR) {
+ fprintf(stderr, "OpenGL error 0x%0x occured after glPopAttrib!\n", error);
+ goterrors++;
+ }
+
+ if (Automatic && frame > 2) {
+ printf("PIGLIT: {'result': '%s' }\n", goterrors ? "fail" : "pass");
+ exit(0);
+ }
+
+ glutPostRedisplay();
+}
+
+int main(int argc, char **argv)
+{
+ glutInit(&argc, argv);
+ if (argc == 2 && !strcmp(argv[1], "-auto"))
+ Automatic = 1;
+ glutCreateWindow("fdo9833");
+ glutDisplayFunc(display);
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/glean/CMakeLists.txt b/tests/glean/CMakeLists.txt
new file mode 100644
index 00000000..9156f1a8
--- /dev/null
+++ b/tests/glean/CMakeLists.txt
@@ -0,0 +1,69 @@
+
+add_definitions ( -D__X11__ -D__UNIX__ )
+
+include_directories( ${OPENGL_INCLUDE_PATH} )
+
+add_executable (glean
+ codedid.cpp
+ dsconfig.cpp
+ dsfilt.cpp
+ dsurf.cpp
+ environ.cpp
+ geomrend.cpp
+ geomutil.cpp
+ glutils.cpp
+ main.cpp
+ misc.cpp
+ options.cpp
+ rc.cpp
+ tbasic.cpp
+ tbasicperf.cpp
+ tbinding.cpp
+ tblend.cpp
+ tchgperf.cpp
+ tdepthstencil.cpp
+ test.cpp
+ tfpexceptions.cpp
+ tfragprog1.cpp
+ tgetstr.cpp
+ tlogicop.cpp
+ tmaskedclear.cpp
+ tmultitest.cpp
+ torthpos.cpp
+ tpaths.cpp
+ tpgos.cpp
+ tpixelformats.cpp
+ tpointatten.cpp
+ treadpix.cpp
+ treadpixperf.cpp
+ trgbtris.cpp
+ tscissor.cpp
+ tteapot.cpp
+ ttexcombine.cpp
+ ttexcube.cpp
+ ttexenv.cpp
+ ttexgen.cpp
+ ttexrect.cpp
+ ttexture_srgb.cpp
+ tvertattrib.cpp
+ tvertprog1.cpp
+ tvtxperf.cpp
+ winsys.cpp
+ gl.cpp
+ image_misc.cpp
+ pack.cpp
+ rdtiff.cpp
+ reg.cpp
+ unpack.cpp
+ wrtiff.cpp
+ basic.cpp
+ lex.cpp
+ timer.cpp
+)
+
+target_link_libraries (glean
+ ${OPENGL_gl_LIBRARY}
+ ${OPENGL_glu_LIBRARY}
+ ${TIFF_LIBRARY}
+)
+
diff --git a/tests/glean/basic.cpp b/tests/glean/basic.cpp
new file mode 100644
index 00000000..af317bd9
--- /dev/null
+++ b/tests/glean/basic.cpp
@@ -0,0 +1,64 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// basic.cpp: basic statistics utilities for glean
+
+#include <cfloat>
+#include <cmath>
+#include "stats.h"
+
+namespace GLEAN {
+
+void
+BasicStats::init() {
+ _min = DBL_MAX;
+ _max = -DBL_MAX;
+ _sum = _sum2 = 0.0;
+ _n = 0;
+}
+
+double
+BasicStats::mean() const {return _n? (_sum / _n): 0.0;}
+
+double
+BasicStats::variance() const {
+ if (_n < 2)
+ return 0.0;
+ return (_sum2 - _sum * _sum / _n) / (_n - 1);
+ // Not really numerically robust, but good enough for us.
+}
+double
+BasicStats::deviation() const {
+ const double v = variance();
+ return (v < 0.0)? 0.0: sqrt(v);
+}
+
+} // namespace GLEAN
diff --git a/tests/glean/codedid.cpp b/tests/glean/codedid.cpp
new file mode 100644
index 00000000..44fe56b8
--- /dev/null
+++ b/tests/glean/codedid.cpp
@@ -0,0 +1,146 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+// codedid.h: tool to map integer IDs into colors, and vice-versa
+
+using namespace std;
+
+#include <algorithm>
+#include <vector>
+#include "codedid.h"
+#include "image.h"
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// RGBCodedID: Create an object that maps integer identification numbers
+// to RGB triples, and vice-versa
+///////////////////////////////////////////////////////////////////////////////
+RGBCodedID::RGBCodedID(int r, int g, int b) {
+ rBits = min(8, r); // 8 because we use GLubyte color values
+ gBits = min(8, g);
+ bBits = min(8, b);
+ nsRBits = 8 - rBits;
+ nsGBits = 8 - gBits;
+ nsBBits = 8 - bBits;
+ rMask = (1 << rBits) - 1;
+ gMask = (1 << gBits) - 1;
+ bMask = (1 << bBits) - 1;
+} // RGBCodedID::RGBCodedID
+
+RGBCodedID::~RGBCodedID() {
+} // RGBCodedID::~RGBCodedID
+
+///////////////////////////////////////////////////////////////////////////////
+// maxID: Return the maximum allowable integer ID number
+///////////////////////////////////////////////////////////////////////////////
+int
+RGBCodedID::maxID() const {
+ return (1 << (rBits + gBits + bBits)) - 1;
+} // RGBCodedID::maxID
+
+///////////////////////////////////////////////////////////////////////////////
+// toRGB: Convert integer ID number to RGB triple
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBCodedID::toRGB(int id, GLubyte& r, GLubyte& g, GLubyte& b) const {
+ b = (id & bMask) << nsBBits;
+ id >>= bBits;
+ g = (id & gMask) << nsGBits;
+ id >>= gBits;
+ r = (id & rMask) << nsRBits;
+} // RGBCodedID::toRGB
+
+///////////////////////////////////////////////////////////////////////////////
+// toID: Convert RGB triple to integer ID number
+///////////////////////////////////////////////////////////////////////////////
+int
+RGBCodedID::toID(GLubyte r, GLubyte g, GLubyte b) const {
+ int id = 0;
+ id |= (r >> nsRBits) & rMask;
+ id <<= gBits;
+ id |= (g >> nsGBits) & gMask;
+ id <<= bBits;
+ id |= (b >> nsBBits) & bMask;
+ return id;
+} // RGBCodedID::toID
+
+///////////////////////////////////////////////////////////////////////////////
+// histogram: Compute histogram of coded IDs in an UNSIGNED_BYTE RGB image
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBCodedID::histogram(Image& img, vector<int>& hist) const {
+ if (img.format() != GL_RGB || img.type() != GL_UNSIGNED_BYTE) {
+ hist.resize(0);
+ return;
+ }
+
+ int max = maxID();
+ hist.resize(max + 1);
+ for (vector<int>::iterator p = hist.begin(); p != hist.end(); ++p)
+ *p = 0;
+
+ GLubyte* row = reinterpret_cast<GLubyte*>(img.pixels());
+ for (GLsizei r = 0; r < img.height(); ++r) {
+ GLubyte* pix = row;
+ for (GLsizei c = 0; c < img.width(); ++c) {
+ int id = toID(pix[0], pix[1], pix[2]);
+ if (id <= max)
+ ++hist[id];
+ pix += 3;
+ }
+ row += img.rowSizeInBytes();
+ }
+} // RGBCodedID::histogram
+
+///////////////////////////////////////////////////////////////////////////////
+// allPresent: See if all of a range of IDs are present in a given RGB image
+///////////////////////////////////////////////////////////////////////////////
+bool
+RGBCodedID::allPresent(Image& img, int first, int last) const {
+ vector<int> hist;
+ histogram(img, hist);
+ if (hist.size() == 0)
+ return false;
+ if (first >= static_cast<int>(hist.size()))
+ return false;
+ if (last >= static_cast<int>(hist.size()))
+ return false;
+ if (first > last)
+ return false;
+
+ for (vector<int>::const_iterator p = hist.begin() + first;
+ p != hist.begin() + last + 1; ++p)
+ if (*p == 0)
+ return false;
+ return true;
+} // RGBCodedID::allPresent
+
+} // namespace GLEAN
diff --git a/tests/glean/codedid.h b/tests/glean/codedid.h
new file mode 100644
index 00000000..b7bbc066
--- /dev/null
+++ b/tests/glean/codedid.h
@@ -0,0 +1,92 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+// codedid.h: tool to map integer IDs into colors, and vice-versa
+
+// A note on principles of operation: The OpenGL spec normally allows
+// a reasonable amount of slop when converting user-specified colors
+// to a hardware-dependent representation in the framebuffer. One
+// exception to this lenience is when lighting is disabled and the
+// color is specified as an unsigned byte, short, or int. In this
+// case the conversion from user-supplied color to hardware-determined
+// color must be exact, up to the number of bits in the framebuffer or
+// in the value supplied by the user (whichever is smaller). This is
+// intended to allow object identification numbers to be encoded as
+// colors, so that applications can implement object selection by
+// drawing objects and reading back the image to determine the object
+// ID of the closest visible object. glean uses this property in a
+// number of cases, for example, where it needs to draw a large number
+// of primitives and verify that all of them were actually drawn. See
+// the OpenGL spec, version 1.2.1, section 2.13.9 (page 55) for the
+// description of this convertibility requirement.
+
+#ifndef __codedid_h__
+#define __codedid_h__
+
+using namespace std;
+
+#include <vector>
+#include "glwrap.h"
+
+namespace GLEAN {
+
+class Image; // forward reference
+
+class RGBCodedID {
+ int rBits, gBits, bBits; // number of signif. bits in channels
+ int nsRBits, nsGBits, nsBBits; // non-significant bits in each
+ int rMask, gMask, bMask; // masks for significant bits in each
+ public:
+ RGBCodedID(int r, int g, int b);
+ ~RGBCodedID();
+
+ // Return the maximum ID number that the caller can use:
+ int maxID() const;
+
+ // Map an ID number to an RGB triple:
+ void toRGB(int id, GLubyte& r, GLubyte& g, GLubyte& b) const;
+
+ // Map an RGB triple to the equivalent ID number:
+ int toID(GLubyte r, GLubyte g, GLubyte b) const;
+
+ // Histogram an UNSIGNED_BYTE RGB image:
+ void histogram(Image& img, vector<int>& hist) const;
+
+ // Are all of a range of IDs present in an RGB image?
+ bool allPresent(Image& img, int first, int last) const;
+
+}; // RGBCodedID
+
+// XXX Might want an IndexCodedID class for use with color index drawing
+// surfaces, even though such a class would be trivial.
+
+} // namespace GLEAN
+
+#endif // __codedid_h__
diff --git a/tests/glean/dsconfig.cpp b/tests/glean/dsconfig.cpp
new file mode 100644
index 00000000..88f9a81b
--- /dev/null
+++ b/tests/glean/dsconfig.cpp
@@ -0,0 +1,881 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// dsconfig.cpp: Implementation of drawing surface configuration utilities
+#include "dsconfig.h"
+#include <iostream>
+#include <strstream>
+#include <cstring>
+#include <map>
+#include <climits>
+
+#ifdef __WIN__
+// disable the annoying warning : "forcing value to bool 'true' or 'false' (performance warning)"
+#pragma warning (disable : 4800)
+#endif
+
+
+#include "lex.h"
+
+
+
+namespace {
+
+#ifdef __X11__
+
+bool
+haveGLXExtension(::Display* dpy, const char* extName) {
+ const char* extString =
+ glXQueryExtensionsString(dpy, DefaultScreen(dpy));
+ // We don't cache the result, so that subsequent calls
+ // with different values of ``dpy'' will work correctly.
+ // Would be nice to improve this, though.
+
+ const char* start = extString;
+ for (;;) {
+ const char* where = strstr(start, extName);
+ if (!where)
+ return false;
+
+ // Make sure we're not fooled by extensions whose names
+ // have the desired extName as an initial substring:
+ const char* terminator = where + strlen(extName);
+ if ((where == start || where[-1] == ' ')
+ && (*terminator == ' ' || *terminator == 0))
+ return true;
+
+ start = terminator;
+ }
+
+ return false;
+} // haveGLXExtension
+
+#endif
+
+typedef enum { // These variable tags are used as array indices,
+ // so they should represent a small dense set of
+ // nonnegative integers. 0 is reserved.
+ VID = 1,
+ VFBCID,
+ VCANRGBA,
+ VR,
+ VG,
+ VB,
+ VA,
+ VCANCI,
+ VBUFSIZE,
+ VLEVEL,
+ VDB,
+ VSTEREO,
+ VAUX,
+ VZ,
+ VS,
+ VACCUMR,
+ VACCUMG,
+ VACCUMB,
+ VACCUMA,
+ VCANWINDOW,
+ VCANPIXMAP,
+ VCANPBUFFER,
+ VMAXPBUFFERWIDTH,
+ VMAXPBUFFERHEIGHT,
+ VMAXPBUFFERPIXELS,
+ VCANWINSYSRENDER,
+ VFAST,
+ VCONFORMANT,
+ VTRANSPARENT,
+ VTRANSR,
+ VTRANSG,
+ VTRANSB,
+ VTRANSA,
+ VTRANSI,
+ V_LAST
+} CanonVar;
+
+struct {CanonVar var; char* name;} varNames[] = {
+ {VID, "id"},
+ {VFBCID, "fbcID"},
+ {VCANRGBA, "canRGBA"},
+ {VR, "r"},
+ {VG, "g"},
+ {VB, "b"},
+ {VA, "a"},
+ {VCANCI, "canCI"},
+ {VBUFSIZE, "bufSize"},
+ {VLEVEL, "level"},
+ {VDB, "db"},
+ {VSTEREO, "stereo"},
+ {VAUX, "aux"},
+ {VZ, "z"},
+ {VS, "s"},
+ {VACCUMR, "accumR"},
+ {VACCUMG, "accumG"},
+ {VACCUMB, "accumB"},
+ {VACCUMA, "accumA"},
+ {VCANWINDOW, "window"},
+ {VCANPIXMAP, "pixmap"},
+ {VCANPBUFFER, "pBuffer"},
+ {VMAXPBUFFERWIDTH, "maxPBufferWidth"},
+ {VMAXPBUFFERHEIGHT, "maxPBufferHeight"},
+ {VMAXPBUFFERPIXELS, "maxPBufferPixels"},
+ {VCANWINSYSRENDER, "winsys"},
+ {VFAST, "fast"},
+ {VCONFORMANT, "conformant"},
+ {VTRANSPARENT, "transparent"},
+ {VTRANSR, "transR"},
+ {VTRANSG, "transG"},
+ {VTRANSB, "transB"},
+ {VTRANSA, "transA"},
+ {VTRANSI, "transI"}
+};
+
+char* mapVarToName[V_LAST];
+map<string, CanonVar> mapNameToVar;
+bool mapsInitialized = false;
+
+void
+initializeMaps() {
+ for (unsigned i = 0; i < sizeof(varNames)/sizeof(varNames[0]); ++i) {
+ mapVarToName[varNames[i].var] = varNames[i].name;
+ mapNameToVar[varNames[i].name] = varNames[i].var;
+ }
+ mapsInitialized = true;
+} // initializeMaps
+
+template<class T> inline T abs(T a) {return (a < 0)? -a: a;}
+
+} // anonymous namespace
+
+
+namespace GLEAN {
+
+
+#if defined(__X11__)
+
+DrawingSurfaceConfig::DrawingSurfaceConfig(::Display* dpy, ::XVisualInfo* pvi) {
+ if (!mapsInitialized)
+ initializeMaps();
+
+ int var;
+
+ vi = pvi;
+ visID = vi->visualid;
+# if defined(GLX_VERSION_1_3)
+ fbcID = 0;
+# endif
+
+ glXGetConfig(dpy, vi, GLX_RGBA, &var);
+ canRGBA = var;
+ canCI = !var;
+ // There is no dual-personality Visual support in early
+ // versions of GLX.
+
+ glXGetConfig(dpy, vi, GLX_BUFFER_SIZE, &bufSize);
+
+ glXGetConfig(dpy, vi, GLX_LEVEL, &level);
+
+ glXGetConfig(dpy, vi, GLX_DOUBLEBUFFER, &var);
+ db = var;
+
+ glXGetConfig(dpy, vi, GLX_STEREO, &var);
+ stereo = var;
+
+ glXGetConfig(dpy, vi, GLX_AUX_BUFFERS, &aux);
+
+ if (canRGBA) {
+ glXGetConfig(dpy, vi, GLX_RED_SIZE, &r);
+ glXGetConfig(dpy, vi, GLX_GREEN_SIZE, &g);
+ glXGetConfig(dpy, vi, GLX_BLUE_SIZE, &b);
+ glXGetConfig(dpy, vi, GLX_ALPHA_SIZE, &a);
+ } else
+ r = g = b = a = 0;
+
+ glXGetConfig(dpy, vi, GLX_DEPTH_SIZE, &z);
+
+ glXGetConfig(dpy, vi, GLX_STENCIL_SIZE, &s);
+
+ if (canRGBA) {
+ glXGetConfig(dpy, vi, GLX_ACCUM_RED_SIZE, &accR);
+ glXGetConfig(dpy, vi, GLX_ACCUM_GREEN_SIZE, &accG);
+ glXGetConfig(dpy, vi, GLX_ACCUM_BLUE_SIZE, &accB);
+ glXGetConfig(dpy, vi, GLX_ACCUM_ALPHA_SIZE, &accA);
+ } else
+ accR = accG = accB = accA = 0;
+
+ canWindow = canPixmap = true;
+ // Only guaranteed in early versions of GLX.
+
+# if defined(GLX_VERSION_1_3)
+ canPBuffer = 0;
+ maxPBufferWidth = 0;
+ maxPBufferHeight = 0;
+ maxPBufferPixels = 0;
+# endif
+
+ canWinSysRender = true;
+ // Only guaranteed in early versions of GLX.
+
+ fast = true;
+ conformant = true;
+# if defined(GLX_EXT_visual_rating)
+ if (haveGLXExtension(dpy, "GLX_EXT_visual_rating")) {
+ glXGetConfig(dpy, vi, GLX_VISUAL_CAVEAT_EXT, &var);
+ if (var == GLX_SLOW_VISUAL_EXT)
+ fast = false;
+ else if (var == GLX_NON_CONFORMANT_VISUAL_EXT)
+ conformant = false;
+ }
+# endif
+
+ transparent = false;
+ transR = transG = transB = transA = transI = 0;
+# if defined(GLX_EXT_visual_info)
+ if (haveGLXExtension(dpy, "GLX_EXT_visual_info")) {
+ glXGetConfig(dpy, vi, GLX_TRANSPARENT_TYPE_EXT, &var);
+ if (var == GLX_TRANSPARENT_RGB_EXT) {
+ glXGetConfig(dpy, vi,
+ GLX_TRANSPARENT_RED_VALUE_EXT, &transR);
+ glXGetConfig(dpy, vi,
+ GLX_TRANSPARENT_GREEN_VALUE_EXT, &transG);
+ glXGetConfig(dpy, vi,
+ GLX_TRANSPARENT_BLUE_VALUE_EXT, &transB);
+ glXGetConfig(dpy, vi,
+ GLX_TRANSPARENT_ALPHA_VALUE_EXT, &transA);
+ } else
+ glXGetConfig(dpy, vi,
+ GLX_TRANSPARENT_INDEX_VALUE_EXT, &transI);
+ }
+# endif
+} // DrawingSurfaceConfig::DrawingSurfaceConfig
+
+#if defined(GLX_VERSION_1_3)
+DrawingSurfaceConfig::DrawingSurfaceConfig(::Display* dpy, ::GLXFBConfig* pfbc)
+{
+ // silence warnings about unused parameters:
+ (void) dpy;
+ (void) pfbc;
+
+ if (!mapsInitialized)
+ initializeMaps();
+// XXX Need to write drawing surface config code for GLX 1.3
+ cerr << "GLX 1.3 version of DrawingSurfaceConfig constructor is not"
+ "implemented.\n";
+} // DrawingSurfaceConfig::DrawingSurfaceConfig
+#endif
+
+#elif defined(__WIN__)
+
+DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::PIXELFORMATDESCRIPTOR *ppfd)
+{
+ if (!mapsInitialized)
+ initializeMaps();
+
+ pfd = ppfd;
+ pfdID = id;
+
+ canRGBA = pfd->iPixelType == PFD_TYPE_RGBA;
+ canCI = pfd->iPixelType == PFD_TYPE_COLORINDEX;
+
+ bufSize = pfd->cColorBits + pfd->cAlphaBits;
+
+ level = 0;
+
+ db = pfd->dwFlags & PFD_DOUBLEBUFFER;
+
+ stereo = pfd->dwFlags & PFD_STEREO;
+
+ aux = pfd->cAuxBuffers;
+
+ if (canRGBA) {
+ r = pfd->cRedBits;
+ g = pfd->cGreenBits;
+ b = pfd->cBlueBits;
+ a = pfd->cAlphaBits;
+ }
+ else
+ r = g = b = a = 0;
+
+ z = pfd->cDepthBits;
+ s = pfd->cStencilBits;
+
+ accR = pfd->cAccumRedBits;
+ accG = pfd->cAccumGreenBits;
+ accB = pfd->cAccumBlueBits;
+ accA = pfd->cAccumAlphaBits;
+
+ canWindow = pfd->dwFlags & PFD_DRAW_TO_WINDOW;
+
+ canWinSysRender = pfd->dwFlags & PFD_SUPPORT_GDI;
+
+ if (pfd->dwFlags & PFD_GENERIC_FORMAT)
+ {
+ if (pfd->dwFlags & PFD_GENERIC_ACCELERATED)
+ {
+ // it's an MCD - at least it has some acceleration
+ fast = true;
+ }
+ else
+ {
+ // it's software
+ fast = false;
+ }
+ }
+ else
+ {
+ // it's an ICD
+ fast = true;
+ }
+
+ // we'll assume that the OpenGL implementation thinks it is conformant
+ conformant = true;
+
+ // chromakeying isn't supported
+ transparent = false;
+ transR = transG = transB = transA = transI = 0;
+}
+#elif defined(__BEWIN__)
+
+DrawingSurfaceConfig::DrawingSurfaceConfig() {
+
+ if (!mapsInitialized)
+ initializeMaps();
+
+ /* these values are estimates for the moment */
+ level = 0;
+ db = 1;
+ stereo =0;
+ r = g = b = a = 32;
+
+ z = 30;
+ accR = 32;
+ accG = 32;
+ accB = 32;
+ accA = 32;
+
+
+ canWindow = 1;
+ canWinSysRender = 1;
+
+ // This is a software-mode assumption
+ fast = false;
+
+ // we'll assume that the OpenGL implementation thinks it is conformant
+ conformant = true;
+
+ // chromakeying isn't supported
+ transparent = false;
+ transR = transG = transB = transA = transI = 0;
+}
+
+#elif defined(__AGL__)
+
+DrawingSurfaceConfig::DrawingSurfaceConfig(int id, ::AGLPixelFormat pfd)
+{
+ long i;
+
+ if (!mapsInitialized)
+ initializeMaps();
+
+ pf = pfd;
+
+ if (aglDescribePixelFormat( pf, AGL_RGBA, &i))
+ canRGBA = (i == GL_TRUE);
+ canCI = (i == GL_FALSE);
+
+ if (aglDescribePixelFormat( pf, AGL_BUFFER_SIZE, &i))
+ bufSize = i;
+
+ level = 0;
+
+ if (aglDescribePixelFormat( pf, AGL_DOUBLEBUFFER, &i))
+ db = (i == GL_TRUE);
+ if (aglDescribePixelFormat( pf, AGL_STEREO, &i))
+ stereo = (i == GL_TRUE);
+ if (aglDescribePixelFormat( pf, AGL_AUX_BUFFERS, &i))
+ aux = i;
+
+ if (canRGBA) {
+ aglDescribePixelFormat( pf, AGL_RED_SIZE, (long *)&r);
+ aglDescribePixelFormat( pf, AGL_GREEN_SIZE, (long *)&g);
+ aglDescribePixelFormat( pf, AGL_BLUE_SIZE, (long *)&b);
+ aglDescribePixelFormat( pf, AGL_ALPHA_SIZE, (long *)&a);
+
+ //this is a workaround for some versions of AGL
+ if (r == 10)
+ {
+ r=g=b=8;
+ bufSize = r + g + b + a;
+ }
+ }
+ else
+ r = g = b = a = 0;
+
+ aglDescribePixelFormat( pf, AGL_DEPTH_SIZE, (long *)& z);
+ aglDescribePixelFormat( pf, AGL_STENCIL_SIZE, (long *)& s);
+
+ aglDescribePixelFormat( pf, AGL_ACCUM_RED_SIZE, (long *)& accR);
+ aglDescribePixelFormat( pf, AGL_ACCUM_GREEN_SIZE, (long *)& accG);
+ aglDescribePixelFormat( pf, AGL_ACCUM_BLUE_SIZE, (long *)& accB);
+ aglDescribePixelFormat( pf, AGL_ACCUM_ALPHA_SIZE, (long *)& accA);
+
+ aglDescribePixelFormat( pf, AGL_WINDOW, &i);
+ canWindow = i;
+ aglDescribePixelFormat( pf, AGL_OFFSCREEN, &i);
+ canWinSysRender = i;
+ aglDescribePixelFormat( pf, AGL_ACCELERATED, & i);
+ fast = i;
+
+ // we'll assume that the OpenGL implementation thinks it is conformant
+ conformant = true;
+
+ // chromakeying isn't supported
+ transparent = false;
+ transR = transG = transB = transA = transI = 0;
+}
+
+#endif
+
+DrawingSurfaceConfig::DrawingSurfaceConfig(string& str) {
+ if (!mapsInitialized)
+ initializeMaps();
+
+ try {
+ Lex lex(str.c_str());
+
+ for (lex.next(); lex.token != Lex::END; lex.next()) {
+ if (lex.token != Lex::ID)
+ throw Syntax("expected variable name",
+ lex.position());
+ lex.next();
+ if (lex.token != Lex::ICONST)
+ throw Syntax("expected integer value",
+ lex.position());
+
+ // Yes, this is an unpleasantly verbose way to
+ // handle this problem. However, it will be
+ // necessary when we have to deal with attributes
+ // that aren't all of a simple integral type.
+
+ switch (mapNameToVar[lex.id]) {
+ case VID:
+# if defined(__X11__)
+ visID = lex.iValue;
+# endif
+ break;
+ case VFBCID:
+# if defined(GLX_VERSION_1_3)
+ fbcID = lex.iValue;
+# endif
+ break;
+ case VCANRGBA:
+ canRGBA = lex.iValue;
+ break;
+ case VR:
+ r = lex.iValue;
+ break;
+ case VG:
+ g = lex.iValue;
+ break;
+ case VB:
+ b = lex.iValue;
+ break;
+ case VA:
+ a = lex.iValue;
+ break;
+ case VCANCI:
+ canCI = lex.iValue;
+ break;
+ case VBUFSIZE:
+ bufSize = lex.iValue;
+ break;
+ case VLEVEL:
+ level = lex.iValue;
+ break;
+ case VDB:
+ db = lex.iValue;
+ break;
+ case VSTEREO:
+ stereo = lex.iValue;
+ break;
+ case VAUX:
+ aux = lex.iValue;
+ break;
+ case VZ:
+ z = lex.iValue;
+ break;
+ case VS:
+ s = lex.iValue;
+ break;
+ case VACCUMR:
+ accR = lex.iValue;
+ break;
+ case VACCUMG:
+ accG = lex.iValue;
+ break;
+ case VACCUMB:
+ accB = lex.iValue;
+ break;
+ case VACCUMA:
+ accA = lex.iValue;
+ break;
+ case VCANWINDOW:
+ canWindow = lex.iValue;
+ break;
+ case VCANPIXMAP:
+# if defined(__X11__)
+ canPixmap = lex.iValue;
+# endif
+ break;
+ case VCANPBUFFER:
+# if defined(GLX_VERSION_1_3)
+ canPBuffer = lex.iValue;
+# endif
+ break;
+ case VMAXPBUFFERWIDTH:
+# if defined(GLX_VERSION_1_3)
+ maxPBufferWidth = lex.iValue;
+# endif
+ break;
+ case VMAXPBUFFERHEIGHT:
+# if defined(GLX_VERSION_1_3)
+ maxPBufferHeight = lex.iValue;
+# endif
+ break;
+ case VMAXPBUFFERPIXELS:
+# if defined(GLX_VERSION_1_3)
+ maxPBufferPixels = lex.iValue;
+# endif
+ break;
+ case VCANWINSYSRENDER:
+ canWinSysRender = lex.iValue;
+ break;
+ case VFAST:
+ fast = lex.iValue;
+ break;
+ case VCONFORMANT:
+ conformant = lex.iValue;
+ break;
+ case VTRANSPARENT:
+ transparent = lex.iValue;
+ break;
+ case VTRANSR:
+ transR = lex.iValue;
+ break;
+ case VTRANSG:
+ transG = lex.iValue;
+ break;
+ case VTRANSB:
+ transB = lex.iValue;
+ break;
+ case VTRANSA:
+ transA = lex.iValue;
+ break;
+ case VTRANSI:
+ transI = lex.iValue;
+ break;
+ default:
+ throw Syntax("unrecognized variable",
+ lex.position());
+ }
+ }
+ }
+ catch (Lex::Lexical e) {
+ throw Syntax(e.err, e.position);
+ }
+} // DrawingSurfaceConfing::DrawingSurfaceConfig
+
+
+///////////////////////////////////////////////////////////////////////////////
+// canonicalDescription - return a description string that can be used
+// to reconstruct the essential attributes of a drawing surface
+// configuration. Note that visual ID numbers are included for
+// completeness, but they must be ignored when attempting to compare
+// two surface configurations; there's no guarantee that they'll be
+// valid (or even relevant, since they may have been created on another
+// OS).
+//
+// This is ugly code, but it keeps the names used here and in
+// the string-based constructor for DrawingSurfaceConfig in sync
+// automatically.
+///////////////////////////////////////////////////////////////////////////////
+string
+DrawingSurfaceConfig::canonicalDescription() {
+
+ // Would rather use ostringstream, but it's not available in
+ // egcs 1.1.2.
+ char buf[1024];
+ ostrstream s(buf, sizeof(buf));
+
+# if defined(__X11__)
+ s << mapVarToName[VID] << ' ' << visID;
+# if defined(GLX_VERSION_1_3)
+ s << ' ' << mapVarToName[VFBCID] << ' ' << fbcID;
+# endif
+# elif defined(__WIN__)
+ s << mapVarToName[VID] << ' ' << pfdID;
+# endif
+
+ s << ' ' << mapVarToName[VCANRGBA] << ' ' << canRGBA;
+ s << ' ' << mapVarToName[VR] << ' ' << r
+ << ' ' << mapVarToName[VG] << ' ' << g
+ << ' ' << mapVarToName[VB] << ' ' << b
+ << ' ' << mapVarToName[VA] << ' ' << a;
+
+ s << ' ' << mapVarToName[VCANCI] << ' ' << canCI;
+
+ s << ' ' << mapVarToName[VBUFSIZE] << ' ' << bufSize;
+
+ s << ' ' << mapVarToName[VLEVEL] << ' ' << level;
+
+ s << ' ' << mapVarToName[VDB] << ' ' << db;
+
+ s << ' ' << mapVarToName[VSTEREO] << ' '<< stereo;
+
+ s << ' ' << mapVarToName[VAUX] << ' ' << aux;
+
+ s << ' ' << mapVarToName[VZ] << ' ' << z;
+
+ s << ' ' << mapVarToName[VS] << ' ' << DrawingSurfaceConfig::s;
+
+ s << ' ' << mapVarToName[VACCUMR] << ' ' << accR
+ << ' ' << mapVarToName[VACCUMG] << ' ' << accG
+ << ' ' << mapVarToName[VACCUMB] << ' ' << accB
+ << ' ' << mapVarToName[VACCUMA] << ' ' << accA;
+
+ s << ' ' << mapVarToName[VCANWINDOW] << ' ' << canWindow;
+
+# if defined(__X11__)
+ s << ' ' << mapVarToName[VCANPIXMAP] << ' ' << canPixmap;
+
+# if defined(GLX_VERSION_1_3)
+ s << ' ' << mapVarToName[VCANPBUFFER] << ' ' << canPBuffer;
+ s << ' ' << mapVarToName[VMAXPBUFFERWIDTH] << ' ' << maxPBufferWidth;
+ s << ' ' << mapVarToName[VMAXPBUFFERHEIGHT] << ' ' << maxPBufferHeight;
+ s << ' ' << mapVarToName[VMAXPBUFFERPIXELS] << ' ' << maxPBufferPixels;
+# endif
+
+# endif
+
+ s << ' ' << mapVarToName[VCANWINSYSRENDER] << ' ' << canWinSysRender;
+
+ s << ' ' << mapVarToName[VFAST] << ' ' << fast;
+
+ s << ' ' << mapVarToName[VCONFORMANT] << ' ' << conformant;
+
+ s << ' ' << mapVarToName[VTRANSPARENT] << ' ' << transparent;
+ s << ' ' << mapVarToName[VTRANSR] << ' ' << transR
+ << ' ' << mapVarToName[VTRANSG] << ' ' << transG
+ << ' ' << mapVarToName[VTRANSB] << ' ' << transB
+ << ' ' << mapVarToName[VTRANSA] << ' ' << transA
+ << ' ' << mapVarToName[VTRANSI] << ' ' << transI;
+
+ s << '\0';
+ return s.str();
+} // DrawingSurfaceConfig::canonicalDescription
+
+///////////////////////////////////////////////////////////////////////////////
+// conciseDescription - return a description string that's appropriate for
+// reading by humans, rather than parsing by machine.
+///////////////////////////////////////////////////////////////////////////////
+string
+DrawingSurfaceConfig::conciseDescription() {
+ char buf[1024];
+ ostrstream s(buf, sizeof(buf));
+
+ if (canRGBA && canCI)
+ s << "dual ";
+
+ if (canRGBA) {
+ if (a) {
+ if (r == g && g == b && b == a)
+ s << "rgba" << r;
+ else
+ s << "r" << r << "g" << g << "b" << b
+ << "a" << a;
+ } else {
+ if (r == g && g == b)
+ s << "rgb" << r;
+ else
+ s << "r" << r << "g" << g << "b" << b;
+ }
+ }
+
+ if (canCI) {
+ if (canRGBA) s << "+";
+ s << "ci" << bufSize;
+ }
+
+ if (level < 0)
+ s << ", underlay";
+ else if (level > 0)
+ s << ", overlay";
+
+ if (db)
+ s << ", db";
+
+ if (stereo)
+ s << ", stereo";
+
+ if (aux)
+ s << ", aux" << aux;
+
+ if (z)
+ s << ", z" << z;
+
+ if (DrawingSurfaceConfig::s)
+ s << ", s" << DrawingSurfaceConfig::s;
+
+ if (accR) {
+ if (accA) {
+ if (accR == accG && accG == accB
+ && accB == accA)
+ s << ", accrgba" << accR;
+ else
+ s << ", accr" << accR << "g" << accG
+ << "b" << accB << "a" << accA;
+ } else {
+ if (accR == accG && accG == accB)
+ s << ", accrgb" << accR;
+ else
+ s << ", accr" << accR << "g" << accG
+ << "b" << accB;
+ }
+ }
+
+ {
+ s << ", ";
+ bool sep = false;
+ if (canWindow) {
+ s << "win";
+ sep = true;
+ }
+# if defined(__X11__)
+ if (canPixmap) {
+ if (sep)
+ s << "+";
+ s << "pmap";
+ sep = true;
+ }
+# endif
+# if defined(GLX_VERSION_1_3)
+ if (canPBuffer) {
+ if (sep)
+ s << "+";
+ s << "pbuf";
+ }
+# endif
+ }
+
+ if (!fast)
+ s << ", slow";
+
+ if (!conformant)
+ s << ", nonconformant";
+
+ if (transparent) {
+ if (canRGBA) {
+ s << ", transrgba (" << transR << "," << transG
+ << "," << transB << "," << transA << ")";
+ }
+ if (canCI) {
+ s << ", transci (" << transI << ")";
+ }
+ }
+
+# if defined(__X11__)
+ s << ", id " << visID;
+# if defined(GLX_VERSION_1_3)
+ if (fbcID)
+ s << ", fbcid " << fbcID;
+# endif
+# elif defined(__WIN__)
+ s << ", id " << pfdID;
+# endif
+
+ s << '\0';
+ return s.str();
+} // DrawingSurfaceConfig::conciseDescription
+
+///////////////////////////////////////////////////////////////////////////////
+// match - select a config that ``matches'' the current config.
+// To keep this problem manageable, we'll assume that both the config
+// to be matched (call it the ``A'' config) and the vector of configs to
+// choose from (call them the ``B'' configs) were selected by a test
+// using a single filter. Thus we can ignore any differences in buffer
+// availability (because we know those are irrelevant to the test), and
+// concentrate on picking configs for which the available buffers are
+// (in some sense) closest in size.
+//
+// This will not be an acceptable solution in all cases, but it should
+// suffice for many.
+///////////////////////////////////////////////////////////////////////////////
+int
+DrawingSurfaceConfig::match(vector<DrawingSurfaceConfig*>& choices) {
+ typedef vector<DrawingSurfaceConfig*>::iterator cptr;
+
+ int best = -1;
+ int bestError = INT_MAX;
+
+ for (cptr p = choices.begin(); p < choices.end(); ++p) {
+ DrawingSurfaceConfig& c = **p;
+ int error = 0;
+
+ if (bufSize && c.bufSize)
+ error += abs(bufSize - c.bufSize);
+ if (r && c.r)
+ error += abs(r - c.r);
+ if (g && c.g)
+ error += abs(g - c.g);
+ if (b && c.b)
+ error += abs(b - c.b);
+ if (a && c.a)
+ error += abs(a - c.a);
+ if (z && c.z)
+ error += abs(z - c.z);
+ if (s && c.s)
+ error += abs(s - c.s);
+ if (accR && c.accR)
+ error += abs(accR - c.accR);
+ if (accG && c.accG)
+ error += abs(accG - c.accG);
+ if (accB && c.accB)
+ error += abs(accB - c.accB);
+ if (accA && c.accA)
+ error += abs(accA - c.accA);
+
+ if (error < bestError) {
+ bestError = error;
+ best = static_cast<int>(p - choices.begin());
+ }
+ }
+
+ return best;
+} // DrawingSurfaceConfig::match
+
+} // namespace GLEAN
diff --git a/tests/glean/dsconfig.h b/tests/glean/dsconfig.h
new file mode 100644
index 00000000..a5f24f92
--- /dev/null
+++ b/tests/glean/dsconfig.h
@@ -0,0 +1,210 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// dsconfig.h: Drawing surface configuration utilities
+
+// This class abstracts the basic characteristics of drawing surfaces
+// (size, depth, ancillary buffers, etc.) and operations on them. It
+// serves as a wrapper for X11 Visual and FBConfig information on
+// X11-based systems, and PixelFormatDescriptor information on
+// Win32-based systems.
+
+
+#ifndef __dsconfig_h__
+#define __dsconfig_h__
+
+#include <string>
+#include <vector>
+#include "glwrap.h"
+
+using namespace std;
+
+namespace GLEAN {
+
+class DrawingSurfaceConfig {
+ public:
+
+ // Constructors/Destructor:
+
+# if defined(__X11__)
+ DrawingSurfaceConfig(::Display* dpy, ::XVisualInfo* pvi);
+# if defined(GLX_VERSION_1_3)
+ DrawingSurfaceConfig(::Display* dpy, ::GLXFBConfig* pfbc);
+# endif
+# elif defined(__WIN__)
+ DrawingSurfaceConfig(int id, ::PIXELFORMATDESCRIPTOR *ppfd);
+# elif defined(__BEWIN__)
+ DrawingSurfaceConfig();
+# elif defined(__AGL__)
+ DrawingSurfaceConfig(int id, ::AGLPixelFormat pfd);
+# endif
+
+ DrawingSurfaceConfig(string& s); // s is a canonical description
+
+ // Exceptions:
+
+ struct Error { }; // Base class for errors.
+ struct Syntax: public Error { // Syntax error in constructor string.
+ const char* err;
+ int position;
+ Syntax(const char* e, int p) {
+ err = e;
+ position = p;
+ }
+ };
+
+ // Attributes:
+
+# if defined(__X11__)
+ ::XVisualInfo* vi; // XVisualInfo pointer
+ ::XID visID; // Visual ID.
+# if defined(GLX_VERSION_1_3)
+ ::GLXFBConfig* fbc;
+ ::XID fbcID; // Framebuffer Config ID.
+# endif
+# elif defined(__WIN__)
+ ::PIXELFORMATDESCRIPTOR *pfd;
+ int pfdID;
+# elif defined(__AGL__)
+ AGLPixelFormat pf;
+ int pfID;
+# endif
+
+ bool canRGBA; // Can be used with RGBA contexts.
+
+ bool canCI; // Can be used with color index
+ // contexts.
+
+ int bufSize; // Total depth of color buffer.
+
+ int level; // Framebuffer level.
+ // (<0 for underlay, 0 for main,
+ // >0 for overlay)
+
+ bool db; // True if double buffered.
+
+ bool stereo; // True if stereo-capable.
+
+ int aux; // Number of aux color buffers.
+
+ int r; // Depth of red channel.
+
+ int g; // Depth of green channel.
+
+ int b; // Depth of blue channel.
+
+ int a; // Depth of alpha channel.
+
+ int z; // Depth of ``z'' (depth) buffer.
+
+ int s; // Depth of stencil buffer.
+
+ int accR; // Depth of accum buf red channel.
+
+ int accG; // Depth of accum buf green channel.
+
+ int accB; // Depth of accum buf blue channel.
+
+ int accA; // Depth of accum buf alpha channel.
+
+ bool canWindow; // True if can be used for windows.
+
+# if defined(__X11__)
+ bool canPixmap; // True if can be used for pixmaps.
+# if defined(GLX_VERSION_1_3)
+ bool canPBuffer; // True if can be used for pbuffers.
+
+ int maxPBufferWidth; // Maximum width of PBuffer that
+ // may be created with this config.
+
+ int maxPBufferHeight; // Maximum height of PBuffer that
+ // may be created with this config.
+
+ int maxPBufferPixels; // Maximum size (in pixels) of
+ // PBuffer that may be created with
+ // this config.
+# endif
+# endif
+
+ bool canWinSysRender; // True if the native window system
+ // can render to a drawable created
+ // with this config.
+
+ bool fast; // True if config is probably
+ // hardware accelerated. (On GLX,
+ // it must not be marked ``slow.'')
+
+ bool conformant; // True if config is advertised as
+ // conforming to the OpenGL spec.
+
+ bool transparent; // True if config has some pixel value
+ // that is transparent (e.g., for
+ // overlays).
+
+ int transR; // Transparent color red value.
+
+ int transG; // Transparent color green value.
+
+ int transB; // Transparent color blue value.
+
+ int transA; // Transparent color alpha value.
+
+ int transI; // Transparent color index value.
+
+ // Utilities:
+
+ string canonicalDescription();
+ // Return a string containing all the attributes in a
+ // drawing surface configuration. This allows the config
+ // to be stored and recreated (essentially for use by
+ // configuration-matching algorithms in test result
+ // comparisons).
+
+ string conciseDescription();
+ // Return a description string that elides default
+ // attribute values and expresses some attributes in
+ // compressed form. Intended to be more easily readable
+ // for humans than the canonical description, at the
+ // cost of some ambiguity.
+
+ int match(vector<DrawingSurfaceConfig*>& choices);
+ // Find the index of the config from ``choices'' that most
+ // closely matches the config specified by ``*this''.
+ // The matching scheme is heuristic, but intended to
+ // be good enough that test results for configs on one
+ // machine may be compared with test results for
+ // configs on another machine.
+
+}; // class DrawingSurfaceConfig
+
+} // namespace GLEAN
+
+#endif // __dsconfig_h__
diff --git a/tests/glean/dsfilt.cpp b/tests/glean/dsfilt.cpp
new file mode 100644
index 00000000..9227bc6f
--- /dev/null
+++ b/tests/glean/dsfilt.cpp
@@ -0,0 +1,690 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// dsfilt.cpp: Implementation of drawing surface configuration filtering
+
+#include <iostream>
+#include <strstream>
+#include <ctype.h>
+#include <stdlib.h>
+#include <algorithm>
+#include "dsfilt.h"
+#include "dsconfig.h"
+
+namespace GLEAN {
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor:
+///////////////////////////////////////////////////////////////////////////////
+DrawingSurfaceFilter::DrawingSurfaceFilter(const string& s):
+ lex(s.c_str(), true) {
+
+ if (!varTableInitialized)
+ InitVarTable();
+
+ try {
+ GetSymbol();
+ if (!ParseCriteria())
+ throw Syntax("no criteria found", lex.position());
+ }
+ catch (Lex::Lexical e) {
+ throw Syntax(e.err, e.position);
+ }
+
+ // Make the final sort in order of increasing ID number:
+ EmitKey(MIN);
+ EmitKey(VAR_ID);
+# if defined(GLX_VERSION_1_3)
+ EmitKey(MIN);
+ EmitKey(VAR_FBCID);
+# endif
+} // DrawingSurfaceFilter::DrawingSurfaceFilter
+
+///////////////////////////////////////////////////////////////////////////////
+// matches - determine if a drawing surface config matches the specified
+// criteria
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::matches(DrawingSurfaceConfig& c) {
+ // Process the RPN expression in ``condition'', using the supplied
+ // drawing surface configuration to determine values of variables.
+
+ vector<int> stack;
+
+ for (vector<int>::const_iterator p = condition.begin();
+ p < condition.end(); ++p) {
+ int right;
+
+ switch (*p) {
+ case ADD:
+ right = stack.back(); stack.pop_back();
+ stack.back() += right;
+ break;
+ case AND:
+ right = stack.back(); stack.pop_back();
+ stack.back() = stack.back() && right;
+ break;
+ case DIV:
+ right = stack.back(); stack.pop_back();
+ stack.back() = (right == 0)? 0: stack.back() / right;
+ break;
+ case EQ:
+ right = stack.back(); stack.pop_back();
+ stack.back() = stack.back() == right;
+ break;
+ case GE:
+ right = stack.back(); stack.pop_back();
+ stack.back() = stack.back() >= right;
+ break;
+ case GT:
+ right = stack.back(); stack.pop_back();
+ stack.back() = stack.back() > right;
+ break;
+ case LE:
+ right = stack.back(); stack.pop_back();
+ stack.back() = stack.back() <= right;
+ break;
+ case LT:
+ right = stack.back(); stack.pop_back();
+ stack.back() = stack.back() < right;
+ break;
+ case MOD:
+ right = stack.back(); stack.pop_back();
+ stack.back() = (right == 0)? 0: stack.back() % right;
+ break;
+ case MUL:
+ right = stack.back(); stack.pop_back();
+ stack.back() *= right;
+ break;
+ case NE:
+ right = stack.back(); stack.pop_back();
+ stack.back() = stack.back() != right;
+ break;
+ case NEGATE:
+ stack.back() = -stack.back();
+ break;
+ case NOT:
+ stack.back() = !stack.back();
+ break;
+ case OR:
+ right = stack.back(); stack.pop_back();
+ stack.back() = stack.back() || right;
+ break;
+ case SUB:
+ right = stack.back(); stack.pop_back();
+ stack.back() -= right;
+ break;
+ case CONSTANT:
+ stack.push_back(*++p);
+ break;
+ default:
+ // Must be a variable.
+ stack.push_back(FetchVariable(c,
+ static_cast<Token>(*p)));
+ break;
+ }
+ }
+
+ return stack.back();
+} // DrawingSurfaceFilter::matches
+
+///////////////////////////////////////////////////////////////////////////////
+// filter - find and sort all matching drawing surface configurations
+///////////////////////////////////////////////////////////////////////////////
+vector<DrawingSurfaceConfig*>
+DrawingSurfaceFilter::filter(vector<DrawingSurfaceConfig*>& v) {
+ vector<DrawingSurfaceConfig*> result;
+ for (vector<DrawingSurfaceConfig*>::const_iterator p = v.begin();
+ p < v.end(); ++p) {
+ if (matches(**p))
+ result.push_back(*p);
+ }
+
+ sort(result.begin(), result.end(), ConfigSort(sortKeys));
+ return result;
+} // DrawingSurfaceFilter::filter
+
+///////////////////////////////////////////////////////////////////////////////
+// ConfigSort operator() - sort comparison for final ordering of configurations
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ConfigSort::operator()
+ (const DrawingSurfaceConfig* c1, const DrawingSurfaceConfig* c2) {
+ for (vector<Token>::const_iterator p=keys.begin(); p<keys.end(); ++p) {
+ Token dir = *p++;
+ int d = FetchVariable(*c1, *p) - FetchVariable(*c2, *p);
+ if (dir == MAX) // sort largest first?
+ d = -d;
+ if (d < 0)
+ return true; // c1 goes before c2
+ if (d > 0)
+ return false; // c1 goes after c2
+ }
+ return false; // order doesn't matter
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// InitVarTable - initialize the table mapping variable names to token values
+///////////////////////////////////////////////////////////////////////////////
+
+map<string,DrawingSurfaceFilter::Token> DrawingSurfaceFilter::varTable;
+bool DrawingSurfaceFilter::varTableInitialized;
+
+void
+DrawingSurfaceFilter::InitVarTable() {
+ varTable["r"] = VAR_R;
+ varTable["g"] = VAR_G;
+ varTable["b"] = VAR_B;
+ varTable["a"] = VAR_A;
+ varTable["rgb"] = VAR_RGB;
+ varTable["rgba"] = VAR_RGBA;
+ varTable["ci"] = VAR_CI;
+ varTable["accumr"] = VAR_ACCUM_R;
+ varTable["accumg"] = VAR_ACCUM_G;
+ varTable["accumb"] = VAR_ACCUM_B;
+ varTable["accuma"] = VAR_ACCUM_A;
+ varTable["accumrgb"] = VAR_ACCUM_RGB;
+ varTable["accumrgba"] = VAR_ACCUM_RGBA;
+ varTable["aux"] = VAR_AUX;
+ varTable["db"] = VAR_DB;
+ varTable["sb"] = VAR_SB;
+ varTable["id"] = VAR_ID;
+ varTable["fbcid"] = VAR_FBCID;
+ varTable["level"] = VAR_LEVEL;
+ varTable["main"] = VAR_MAIN;
+ varTable["overlay"] = VAR_OVERLAY;
+ varTable["underlay"] = VAR_UNDERLAY;
+ varTable["mono"] = VAR_MONO;
+ varTable["stereo"] = VAR_STEREO;
+ varTable["ms"] = VAR_MS;
+ varTable["s"] = VAR_S;
+ varTable["z"] = VAR_Z;
+ varTable["fast"] = VAR_FAST;
+ varTable["conformant"] = VAR_CONFORMANT;
+ varTable["transparent"] = VAR_TRANSPARENT;
+ varTable["transr"] = VAR_TRANS_R;
+ varTable["transg"] = VAR_TRANS_G;
+ varTable["transb"] = VAR_TRANS_B;
+ varTable["transa"] = VAR_TRANS_A;
+ varTable["transci"] = VAR_TRANS_CI;
+ varTable["window"] = VAR_WINDOW;
+ varTable["pbuffer"] = VAR_PBUFFER;
+ varTable["pixmap"] = VAR_PIXMAP;
+ varTable["glonly"] = VAR_GL_ONLY;
+ varTable["max"] = MAX;
+ varTable["min"] = MIN;
+
+ varTableInitialized = true;
+} // DrawingSurfaceFilter::InitVarTable
+
+///////////////////////////////////////////////////////////////////////////////
+// FetchVariable - fetch the value of a variable from a
+// DrawingSurfaceConfig
+///////////////////////////////////////////////////////////////////////////////
+
+int
+DrawingSurfaceFilter::FetchVariable(const DrawingSurfaceConfig& c, Token v) {
+ switch (v) {
+ case VAR_R:
+ return c.r;
+ case VAR_G:
+ return c.g;
+ case VAR_B:
+ return c.b;
+ case VAR_A:
+ return c.a;
+ case VAR_RGB:
+ return min(c.r, min(c.g, c.b));
+ case VAR_RGBA:
+ return min(c.r, min(c.g, min(c.b, c.a)));
+
+ case VAR_CI:
+ return c.canCI? c.bufSize: 0;
+
+ case VAR_ACCUM_R:
+ return c.accR;
+ case VAR_ACCUM_G:
+ return c.accG;
+ case VAR_ACCUM_B:
+ return c.accB;
+ case VAR_ACCUM_A:
+ return c.accA;
+ case VAR_ACCUM_RGB:
+ return min(c.accR, min(c.accG, c.accB));
+ case VAR_ACCUM_RGBA:
+ return min(c.accR, min(c.accG, min(c.accB, c.accA)));
+
+ case VAR_AUX:
+ return c.aux;
+
+ case VAR_DB:
+ return c.db;
+ case VAR_SB:
+ return !c.db;
+
+ case VAR_ID:
+# if defined(__X11__)
+ return c.visID;
+# elif defined(__WIN__)
+ return c.pfdID;
+# endif
+ case VAR_FBCID:
+# if defined(GLX_VERSION_1_3)
+ return c.fbcID;
+# else
+ return 0;
+# endif
+
+ case VAR_LEVEL:
+ return c.level;
+ case VAR_MAIN:
+ return c.level == 0;
+ case VAR_OVERLAY:
+ return c.level > 0;
+ case VAR_UNDERLAY:
+ return c.level < 0;
+
+ case VAR_MONO:
+ return !c.stereo;
+ break;
+ case VAR_STEREO:
+ return c.stereo;
+
+ case VAR_MS:
+ // XXX Can't support this at the moment; have no way to
+ // compile or test.
+ return 0;
+
+ case VAR_S:
+ return c.s;
+
+ case VAR_Z:
+ return c.z;
+
+ case VAR_FAST:
+ return c.fast;
+ case VAR_CONFORMANT:
+ return c.conformant;
+
+ case VAR_TRANSPARENT:
+ return c.transparent;
+ case VAR_TRANS_R:
+ return c.transR;
+ case VAR_TRANS_G:
+ return c.transG;
+ case VAR_TRANS_B:
+ return c.transB;
+ case VAR_TRANS_A:
+ return c.transA;
+ case VAR_TRANS_CI:
+ return c.transI;
+
+ case VAR_WINDOW:
+ return c.canWindow;
+ case VAR_PBUFFER:
+# if defined(GLX_VERSION_1_3)
+ return c.canPBuffer;
+# else
+ return 0;
+# endif
+ case VAR_PIXMAP:
+# if defined(__X11__)
+ return c.canPixmap;
+# else
+ return 0;
+# endif
+
+ case VAR_GL_ONLY:
+ return !c.canWinSysRender;
+
+ default:
+ throw InternalError();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetSymbol - Fetch next symbol from the input string
+///////////////////////////////////////////////////////////////////////////////
+void
+DrawingSurfaceFilter::GetSymbol() {
+ lex.next();
+ switch(lex.token) {
+ case Lex::ID:
+ Symbol = varTable[lex.id];
+ // Note: Because ERROR has value zero in the
+ // Token enumeration, if the user provides a
+ // variable that is not in varTable, then Symbol
+ // will be set to ERROR.
+ if (Symbol == ERROR)
+ throw Syntax("unrecognized variable", lex.position());
+ break;
+ case Lex::ICONST:
+ Value = lex.iValue;
+ Symbol = CONSTANT;
+ break;
+ case Lex::OR_OR:
+ Symbol = OR;
+ break;
+ case Lex::AND_AND:
+ Symbol = AND;
+ break;
+ case Lex::LE:
+ Symbol = LE;
+ break;
+ case Lex::LT:
+ Symbol = LT;
+ break;
+ case Lex::GE:
+ Symbol = GE;
+ break;
+ case Lex::GT:
+ Symbol = GT;
+ break;
+ case Lex::EQ:
+ Symbol = EQ;
+ break;
+ case Lex::NE:
+ Symbol = NE;
+ break;
+ case Lex::BANG:
+ Symbol = NOT;
+ break;
+ case Lex::PLUS:
+ Symbol = ADD;
+ break;
+ case Lex::MINUS:
+ Symbol = SUB;
+ break;
+ case Lex::STAR:
+ Symbol = MUL;
+ break;
+ case Lex::SLASH:
+ Symbol = DIV;
+ break;
+ case Lex::PERCENT:
+ Symbol = MOD;
+ break;
+ case Lex::COMMA:
+ Symbol = SEPARATOR;
+ break;
+ case Lex::LPAREN:
+ Symbol = LPAREN;
+ break;
+ case Lex::RPAREN:
+ Symbol = RPAREN;
+ break;
+ case Lex::END:
+ Symbol = END;
+ break;
+ default:
+ throw Syntax("unrecognized symbol", lex.position());
+ }
+
+ return;
+} // DrawingSurfaceFilter::GetSymbol
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseArithExpr
+// Syntax: arithExpr -> arithTerm {('+'|'-') arithTerm}
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseArithExpr() {
+ if (!ParseArithTerm())
+ return false;
+
+ for (;;) {
+ if (Symbol == ADD || Symbol == SUB) {
+ Token op = Symbol;
+ GetSymbol();
+ if (!ParseArithTerm())
+ throw Syntax("missing operand of + or -",
+ lex.position());
+ Emit(op);
+ } else
+ return true;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseArithFactor
+// Syntax: arithFactor -> ['+'|'-'|'!'] arithPrimary
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseArithFactor() {
+ if (Symbol == ADD || Symbol == SUB || Symbol == NOT) {
+ Token op = Symbol;
+ GetSymbol();
+ if (!ParseArithPrimary())
+ throw Syntax("missing operand of unary +, -, or !",
+ lex.position());
+ if (op == SUB)
+ Emit(NEGATE);
+ else if (op == NOT)
+ Emit(NOT);
+ return true;
+ }
+
+ return ParseArithPrimary();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseArithPrimary
+// Syntax: arithPrimary -> variable | constant | '(' expression ')'
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseArithPrimary() {
+ if (FIRST_VAR < Symbol && Symbol < LAST_VAR) {
+ Emit(Symbol);
+ GetSymbol();
+ return true;
+ }
+
+ if (Symbol == CONSTANT) {
+ Emit(CONSTANT);
+ Emit(Value);
+ GetSymbol();
+ return true;
+ }
+
+ if (Symbol == LPAREN) {
+ GetSymbol();
+ if (!ParseExpression())
+ throw Syntax("missing expression after (",
+ lex.position());
+ if (Symbol == RPAREN) {
+ GetSymbol();
+ return true;
+ } else
+ throw Syntax("missing )", lex.position());
+ }
+
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseArithTerm
+// Syntax: arithTerm -> arithFactor {('*'|'/'|'%') arithFactor}
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseArithTerm() {
+ if (!ParseArithFactor())
+ return false;
+
+ for (;;) {
+ if (Symbol == MUL
+ || Symbol == DIV
+ || Symbol == MOD) {
+ Token op = Symbol;
+ GetSymbol();
+ if (!ParseArithFactor())
+ throw Syntax("missing operand of *, /, or %",
+ lex.position());
+ Emit(op);
+ } else
+ return true;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseBoolFactor
+// Syntax: boolFactor -> arithExpr [('<'|'>'|'<='|'>='|'=='|'!=') arithExpr]
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseBoolFactor() {
+ if (!ParseArithExpr())
+ return false;
+
+ if (Symbol == LT
+ || Symbol == GT
+ || Symbol == LE
+ || Symbol == GE
+ || Symbol == EQ
+ || Symbol == NE) {
+ Token op = Symbol;
+ GetSymbol();
+ if (!ParseArithExpr())
+ throw Syntax("missing operand of comparison",
+ lex.position());
+ Emit(op);
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseBoolTerm
+// Syntax: boolTerm -> boolFactor {'&&' boolFactor}
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseBoolTerm() {
+ if (!ParseBoolFactor())
+ return false;
+
+ for (;;) {
+ if (Symbol == AND) {
+ GetSymbol();
+ if (!ParseBoolFactor())
+ throw Syntax("missing operand of &&",
+ lex.position());
+ Emit(AND);
+ } else
+ return true;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseCriteria
+// Syntax: criteria -> criterion {',' criterion}
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseCriteria() {
+ /* Process all the user-specified conditions and sort keys: */
+ if (!ParseCriterion())
+ return false;
+
+ for (;;) {
+ if (Symbol == SEPARATOR) {
+ GetSymbol();
+ if (!ParseCriterion())
+ throw Syntax("missing criterion after comma",
+ lex.position());
+ Emit(AND);
+ } else if (Symbol == END)
+ return true;
+ else
+ throw Syntax("expected comma or end of criteria",
+ lex.position());
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseCriterion
+// Syntax: criterion -> sortKey | expression
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseCriterion() {
+ if (ParseSortKey())
+ return true;
+ return ParseExpression();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseExpression
+// Syntax: expression -> boolTerm {'||' boolTerm}
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseExpression() {
+ if (!ParseBoolTerm())
+ return false;
+
+ for (;;) {
+ if (Symbol == OR) {
+ GetSymbol();
+ if (!ParseBoolTerm())
+ throw Syntax("missing operand of ||",
+ lex.position());
+ Emit(OR);
+ } else
+ return true;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseSortKey
+// Syntax: sortKey -> ('max'|'min') variable
+///////////////////////////////////////////////////////////////////////////////
+bool
+DrawingSurfaceFilter::ParseSortKey() {
+ if (Symbol == MAX || Symbol == MIN) {
+ EmitKey(Symbol);
+ GetSymbol();
+ if (FIRST_VAR < Symbol && Symbol < LAST_VAR) {
+ EmitKey(Symbol);
+ //
+ // When sorting, eliminate visuals with a zero value
+ // for the key. This is hard to justify on grounds
+ // of orthogonality, but it seems to yield the right
+ // behavior (especially for ``min'').
+ //
+ Emit(Symbol);
+ GetSymbol();
+ return true;
+ } else
+ throw Syntax("missing variable name after sort key",
+ lex.position());
+ }
+
+ return false;
+} // DrawingSurfaceFilter::ParseSortKey
+
+
+} // namespace GLEAN
diff --git a/tests/glean/dsfilt.h b/tests/glean/dsfilt.h
new file mode 100644
index 00000000..89c6d583
--- /dev/null
+++ b/tests/glean/dsfilt.h
@@ -0,0 +1,268 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// dsfilt.h: Utilities for selecting (filtering) drawing surface configs
+
+// Given a string representing a Boolean expression involving
+// attributes of drawing surface configurations, construct an internal
+// representation of the expression which can be used to find matching
+// configurations. The string may also include sorting criteria that
+// will be used to select the order in which matching configurations
+// are returned.
+
+// This class accepts a superset of the criteria supported by the
+// visinfo package, originally released by SGI and used in the isfast
+// library (among other things). Apologies for inconsistent naming
+// conventions, capitalization, redundancy, etc.; they're due to an
+// incomplete translation of the old C code. Here's the original
+// copyright from visinfo, just in case the lawyers are interested:
+
+/*
+ * Copyright (c) 1994 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee,
+ * provided that (i) the above copyright notices and this permission
+ * notice appear in all copies of the software and related documentation,
+ * and (ii) the name of Silicon Graphics may not be used in any
+ * advertising or publicity relating to the software without the specific,
+ * prior written permission of Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
+ * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
+ * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+
+#ifndef __dsfilt_h__
+#define __dsfilt_h__
+
+#include <string>
+#include <vector>
+#include <map>
+#include "lex.h"
+
+using namespace std;
+
+namespace GLEAN {
+
+class DrawingSurfaceConfig; // forward reference
+
+class DrawingSurfaceFilter {
+ public:
+
+ // Constructors:
+
+ DrawingSurfaceFilter(const string& s);
+ // Creates a DrawingSurfaceFilter that implements the
+ // filtering and sorting criteria in the given string.
+
+ // Exceptions:
+
+ struct Error { }; // Base class for errors.
+ struct Syntax: public Error { // Syntax error in string.
+ const char* err;
+ int position;
+ Syntax(const char* e, int p) {
+ err = e;
+ position = p;
+ }
+ };
+ struct InternalError: public Error { // Shouldn't happen.
+ };
+
+ // Utilities:
+
+ bool matches(DrawingSurfaceConfig& c);
+ // Returns true if the given DrawingSurfaceConfig matches
+ // the filter criteria.
+
+ vector<DrawingSurfaceConfig*> filter(vector<DrawingSurfaceConfig*>& v);
+ // Returns a vector of DrawingSurfaceConfig pointers that
+ // match the filter criteria, sorted according to the sorting
+ // criteria.
+
+ protected:
+
+ typedef enum {
+ // These are items that may appear in the parsed
+ // representations of the filter or sort keys.
+
+ // First, some special cases:
+ ERROR = 0, // erroneous token; must appear first
+ END, // end of expression
+
+ // Next, arithmetic and Boolean operators:
+
+ ADD, // C integer +
+ AND, // C integer &&
+ DIV, // C integer /
+ EQ, // C integer ==
+ GE, // C integer >=
+ GT, // C integer >
+ LE, // C integer <=
+ LT, // C integer <
+ MOD, // C integer %
+ MUL, // C integer *
+ NE, // C integer !=
+ NEGATE, // C integer unary -
+ NOT, // C integer unary !
+ OR, // C integer ||
+ SUB, // C integer -
+ SEPARATOR, // comma, separating exprs and sort keys
+ LPAREN, // (
+ RPAREN, // )
+
+ // Sort keys:
+
+ MAX, // sort largest value first
+ MIN, // sort smallest value first
+
+ // Finally, operands:
+
+ CONSTANT, // integer constants
+
+ FIRST_VAR, // marker; starts list of variables
+
+ VAR_R, // red channel size
+ VAR_G, // green channel size
+ VAR_B, // blue channel size
+ VAR_A, // alpha channel size
+ VAR_RGB, // min(r, g, b)
+ VAR_RGBA, // min(r, g, b, a)
+
+ VAR_CI, // color index channel size
+
+ VAR_ACCUM_R, // accum buf red channel size
+ VAR_ACCUM_G, // accum buf green channel size
+ VAR_ACCUM_B, // accum buf blue channel size
+ VAR_ACCUM_A, // accum buf alpha channel size
+ VAR_ACCUM_RGB, // min(accum r, accum g, accum b)
+ VAR_ACCUM_RGBA, // min(accum r, accum g, accum b, accum a)
+
+ VAR_AUX, // number of aux color buffers
+
+ VAR_DB, // nonzero if double buffered
+ VAR_SB, // nonzero if single buffered
+
+ VAR_ID, // X11 Visual or Win32 PixelFormat ID
+ VAR_FBCID, // GLXFBConfig ID
+
+ VAR_LEVEL, // framebuffer level
+ VAR_MAIN, // nonzero for main buffers
+ VAR_OVERLAY, // nonzero for overlay buffers
+ VAR_UNDERLAY, // nonzero for underlay buffers
+
+ VAR_MONO, // nonzero for monoscopic buffers
+ VAR_STEREO, // nonzero for stereoscopic buffers
+
+ VAR_MS, // number of multisamples
+
+ VAR_S, // stencil buffer depth
+
+ VAR_Z, // depth (z) buffer depth
+
+ VAR_FAST, // nonzero if accelerated (or not marked
+ // ``slow'' in GLX)
+
+ VAR_CONFORMANT, // nonzero if conforms to OpenGL spec
+
+ VAR_TRANSPARENT, // nonzero if some pixel value is
+ // transparent
+ VAR_TRANS_R, // transparent value red component
+ VAR_TRANS_G, // transparent value green component
+ VAR_TRANS_B, // transparent value blue component
+ VAR_TRANS_A, // transparent value alpha component
+ VAR_TRANS_CI, // transparent value color index
+
+ VAR_WINDOW, // nonzero if can be used to create a window
+ VAR_PBUFFER, // nonzero if can be used to create a pbuffer
+ VAR_PIXMAP, // nonzero if can be used to create a pixmap
+ // XXXWIN need VAR_BITMAP, at least;
+ // possibly others
+
+ VAR_GL_ONLY, // nonzero if only OpenGL can render into
+ // surfaces created with this config (i.e.,
+ // the native window system *can't* render
+ // into them).
+
+ LAST_VAR // marker; ends list of variables
+ } Token;
+
+ vector<int> condition;
+ inline void Emit(Token op) {condition.push_back(static_cast<int>(op));}
+ inline void Emit(int v) {condition.push_back(v);}
+ vector<Token> sortKeys;
+ inline void EmitKey(Token key) {sortKeys.push_back(key);}
+
+ // Expression-parsing state and utilities:
+ Lex lex;
+ Token Symbol;
+ int Value;
+ static map<string,Token> varTable;
+ static bool varTableInitialized;
+
+ static int FetchVariable(const DrawingSurfaceConfig& c, Token v);
+ static void InitVarTable();
+ bool ParseArithExpr();
+ bool ParseArithFactor();
+ bool ParseArithPrimary();
+ bool ParseArithTerm();
+ bool ParseBoolFactor();
+ bool ParseBoolTerm();
+ bool ParseCriteria();
+ bool ParseCriterion();
+ bool ParseExpression();
+ bool ParseSortKey();
+ void GetSymbol();
+
+ class ConfigSort { // comparison function-object used for sorting
+ protected:
+ vector<Token>& keys;
+ public:
+ ConfigSort(vector<Token>& k): keys(k) { }
+ bool operator() (const DrawingSurfaceConfig* c1,
+ const DrawingSurfaceConfig* c2);
+ };
+ friend class ConfigSort;
+
+}; // class DrawingSurfaceFilter
+
+} // namespace GLEAN
+
+#endif // __dsfilt_h__
diff --git a/tests/glean/dsurf.cpp b/tests/glean/dsurf.cpp
new file mode 100644
index 00000000..f158921e
--- /dev/null
+++ b/tests/glean/dsurf.cpp
@@ -0,0 +1,263 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// dsurf.cpp: implementation of drawing surface utilities
+
+#include <iostream>
+#include <algorithm>
+#include "dsurf.h"
+#include "dsconfig.h"
+#include "winsys.h"
+
+namespace {
+
+#if defined(__X11__)
+
+Colormap
+ChooseColormap(Display* dpy, XVisualInfo* vi) {
+ // We could be polite here and search for a standard colormap,
+ // but the normal mode of operation should be that glean is
+ // running alone, so there doesn't seem to be much point in sharing.
+
+ return XCreateColormap(dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocNone);
+} // ChooseColormap
+
+#endif
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors
+///////////////////////////////////////////////////////////////////////////////
+DrawingSurface::DrawingSurface(WindowSystem& ws, DrawingSurfaceConfig& c) {
+ // Link back to enclosing window system, so as to simplify bookkeeping:
+ winSys = &ws;
+ ws.surfaces.push_back(this);
+
+ // Save pointer to configuration information:
+ config = &c;
+} // DrawingSurface::DrawingSurface
+
+Window::Window(WindowSystem& ws, DrawingSurfaceConfig& c, int w, int h,
+ int x, int y):
+ DrawingSurface(ws, c) {
+
+#if defined(__X11__)
+
+#if defined(GLX_VERSION_1_3)
+ if (ws.GLXVersMajor == 1 && ws.GLXVersMinor < 3)
+ goto legacyMethod;
+// XXX Need GLX 1.3 window-creation code. For now, just fall through.
+#endif
+
+legacyMethod:
+ // XXX There's basically no error-handling code here.
+ // See XErrorHandler().
+
+ // Create the window:
+ XSetWindowAttributes xswa;
+ xswa.background_pixmap = None;
+ xswa.border_pixel = 0;
+ xswa.colormap = ChooseColormap(winSys->dpy, config->vi);
+ xswa.event_mask = StructureNotifyMask;
+ xWindow = XCreateWindow(winSys->dpy,
+ RootWindow(winSys->dpy, config->vi->screen),
+ x, y, w, h,
+ 0,
+ config->vi->depth,
+ InputOutput,
+ config->vi->visual,
+ CWBackPixmap|CWBorderPixel|CWColormap|CWEventMask,
+ &xswa);
+
+ // Set attributes for the benefit of the window manager:
+ XSizeHints sizeHints;
+ sizeHints.width = w;
+ sizeHints.height = h;
+ sizeHints.x = x;
+ sizeHints.y = y;
+ sizeHints.flags = USSize | USPosition;
+ XSetStandardProperties(winSys->dpy, xWindow, "glean", "glean",
+ None, 0, 0, &sizeHints);
+
+ // Map the window and wait for it to appear:
+ XMapWindow(winSys->dpy, xWindow);
+ XEvent event;
+ for (;;) {
+ XNextEvent(winSys->dpy, &event);
+ if (event.type == MapNotify && event.xmap.window == xWindow)
+ break;
+ }
+
+
+#elif defined(__WIN__)
+ // XXX There's basically no error-handling code here.
+ // create the window
+ RECT r;
+ int style = WS_POPUP | WS_CAPTION | WS_BORDER;
+
+ r.left = x;
+ r.top = y;
+ r.right = r.left + w;
+ r.bottom = r.top + h;
+ AdjustWindowRect(&r,style,FALSE);
+
+ hWindow = CreateWindow("glean","glean",
+ style | WS_VISIBLE,
+ r.left,r.top,r.right - r.left,r.bottom - r.top,
+ NULL, NULL,
+ GetModuleHandle(NULL),
+ NULL);
+
+ if (!hWindow)
+ return;
+
+ hDC = GetDC(hWindow);
+
+ PIXELFORMATDESCRIPTOR pfd;
+ SetPixelFormat(hDC,config->pfdID,&pfd);
+
+#elif defined(__BEWIN__)
+
+ tWindow = new GLTestWindow (BRect(x,y, x+w, y+h), "GL Test Window");
+ tWindow->Show();
+
+#elif defined(__AGL__)
+ Rect r ;
+
+ //we need some extra room for the menu bar
+ r.left = x+16;
+ r.top = y+20;
+ if (h < 20)
+ r.bottom = r.top + 32;
+ else
+ r.bottom = r.top+w;
+
+ if (w < 20)
+ r.right = r.left + 32;
+ else
+ r.right = r.left + w;
+
+ macWindow = NewCWindow(nil, &r, (unsigned char*)"glean", true, documentProc,
+ (WindowPtr) -1, false, 0);
+
+ SetPortWindowPort(macWindow);
+
+#endif
+} // Window::Window
+
+///////////////////////////////////////////////////////////////////////////////
+// Destructors
+///////////////////////////////////////////////////////////////////////////////
+
+void
+DrawingSurface::commonDestructorCode() {
+ remove(winSys->surfaces.begin(), winSys->surfaces.end(), this);
+} // DrawingSurface::commonDestructorCode
+
+Window::~Window() {
+
+#if defined(__X11__)
+ XDestroyWindow(winSys->dpy, xWindow);
+#elif defined(__WIN__)
+ ReleaseDC(hWindow,hDC);
+ DestroyWindow(hWindow);
+
+#elif defined(__BEWIN__)
+
+ tWindow->Lock();
+ tWindow->Quit();
+
+#elif defined(__AGL__)
+// ::CloseWindow(macWindow);
+#endif
+
+} // Window::~Window
+
+///////////////////////////////////////////////////////////////////////////////
+// Utilities
+///////////////////////////////////////////////////////////////////////////////
+void
+Window::swap() {
+# if defined(__X11__)
+ glXSwapBuffers(winSys->dpy, xWindow);
+# elif defined(__WIN__)
+ SwapBuffers(hDC);
+# elif defined(__BEWIN__)
+ tWindow->SwapBuffers();
+# elif defined(__AGL__)
+ aglSwapBuffers(aglGetCurrentContext());
+# endif
+} // Window::swap
+
+#if defined(__WIN__)
+
+///////////////////////////////////////////////////////////////////////////////
+// Window procedure
+///////////////////////////////////////////////////////////////////////////////
+
+LRESULT CALLBACK
+Window::WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch (message)
+ {
+ default :
+ return DefWindowProc(hwnd, message, wParam, lParam);
+
+ }
+
+ return FALSE;
+}
+
+#endif
+
+
+#if defined(__BEWIN__)
+
+GLTestWindow::GLTestWindow(BRect frame, const char *title) :
+ BWindow(frame, title, B_TITLED_WINDOW, B_NOT_RESIZABLE)
+{
+ /* right now we just create all the buffers we can */
+ tView = new BGLView(Bounds(), "glean_view", B_FOLLOW_ALL, B_WILL_DRAW,
+ BGL_RGB | BGL_DOUBLE | BGL_DEPTH | BGL_ALPHA | BGL_STENCIL | BGL_ACCUM );
+ AddChild(tView);
+}
+
+void
+GLTestWindow::SwapBuffers()
+{
+ tView->SwapBuffers();
+}
+#endif
+} // namespace GLEAN
diff --git a/tests/glean/dsurf.h b/tests/glean/dsurf.h
new file mode 100644
index 00000000..9e81d965
--- /dev/null
+++ b/tests/glean/dsurf.h
@@ -0,0 +1,103 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// dsurf.h: utilities for manipulating drawing surfaces
+
+#ifndef __dsurf_h__
+#define __dsurf_h__
+
+#include "glwrap.h"
+
+namespace GLEAN {
+
+class WindowSystem; // Forward and mutually-recursive references
+class DrawingSurfaceConfig;
+
+class DrawingSurface {
+ public:
+ DrawingSurface(WindowSystem& ws, DrawingSurfaceConfig& c);
+ virtual ~DrawingSurface() { }
+
+ WindowSystem* winSys; // Window system that owns this surface.
+ DrawingSurfaceConfig* config; // Configuration of this surface.
+
+ protected:
+ void commonDestructorCode();
+
+}; // class DrawingSurface
+
+/* we have to create a utility test window for BeOS */
+# if defined(__BEWIN__)
+class GLTestWindow : public BWindow {
+public:
+ GLTestWindow(BRect frame, const char *title);
+ void SwapBuffers();
+// void SwapBuffers( bool vSync );
+
+private:
+ BGLView *tView;
+};
+# endif
+
+
+class Window: public DrawingSurface {
+ public:
+ Window(WindowSystem& ws, DrawingSurfaceConfig& c, int w, int h,
+ int x = 10, int y = 10);
+ ~Window();
+
+ // Utilities:
+
+ void swap();
+
+ // XXX Add constructors for more specialized window creation --
+ // for example, at a particular screen location, with a particular
+ // parent window, etc. -- as needed by new tests.
+
+# if defined(__X11__)
+ ::Window xWindow;
+# elif defined(__WIN__)
+ ::HWND hWindow;
+ ::HDC hDC;
+
+ ::HDC get_dc() const {return hDC;}
+ static LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
+
+# elif defined(__BEWIN__)
+ GLTestWindow *tWindow;
+# elif defined(__AGL__)
+ ::WindowRef macWindow;
+# endif
+}; // class Window
+
+} // namespace GLEAN
+
+#endif // __dsurf_h__
diff --git a/tests/glean/environ.cpp b/tests/glean/environ.cpp
new file mode 100644
index 00000000..d1447cd0
--- /dev/null
+++ b/tests/glean/environ.cpp
@@ -0,0 +1,161 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// environ.cpp: implementation of test environment class
+
+#include "environ.h"
+
+#if defined(__UNIX__)
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#elif defined(__MS__)
+
+#include <sys/stat.h>
+
+#endif
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor
+///////////////////////////////////////////////////////////////////////////////
+Environment::Environment(Options& opt):
+ options(opt),
+ log(cout),
+ winSys(opt)
+{
+# if defined(__UNIX__)
+
+ // If running tests, first create the results directory.
+ // Refuse to overwrite one that already exists.
+ if (opt.mode == Options::run) {
+ if (opt.overwrite) {
+ // remove existing db dir
+ // XXX using system() probably isn't ideal
+ char cmd[1000];
+ snprintf(cmd, 999, "rm -rf %s", opt.db1Name.c_str());
+ system(cmd);
+ }
+ if (mkdir(opt.db1Name.c_str(), 0755)) {
+ if (errno == EEXIST)
+ throw DBExists();
+ else
+ throw DBCantOpen(opt.db1Name);
+ }
+ // If comparing previous runs, make a token attempt to verify
+ // that the two databases exist.
+ } else if (opt.mode == Options::compare) {
+ struct stat s;
+ if (stat(opt.db1Name.c_str(), &s) || !S_ISDIR(s.st_mode))
+ throw DBCantOpen(opt.db1Name);
+ if (stat(opt.db2Name.c_str(), &s) || !S_ISDIR(s.st_mode))
+ throw DBCantOpen(opt.db2Name);
+ }
+
+# elif defined(__MS__)
+ // If running tests, first create the results directory.
+ // Refuse to overwrite one that already exists.
+ if (opt.mode == Options::run) {
+ if (opt.overwrite) {
+ // XXX a Windows programmer needs to complete this
+ abort();
+ }
+ if (!CreateDirectory(opt.db1Name.c_str(),0)) {
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ throw DBExists();
+ else
+ throw DBCantOpen(opt.db1Name);
+ }
+ // If comparing previous runs, make a token attempt to verify
+ // that the two databases exist.
+ } else if (opt.mode == Options::compare) {
+ struct _stat s;
+
+ if (_stat(opt.db1Name.c_str(), &s) || !(s.st_mode & _S_IFDIR))
+ throw DBCantOpen(opt.db1Name);
+ if (_stat(opt.db2Name.c_str(), &s) || !(s.st_mode & _S_IFDIR))
+ throw DBCantOpen(opt.db2Name);
+ }
+
+# endif
+} // Environment::Environment()
+
+///////////////////////////////////////////////////////////////////////////////
+// Results-file access utilities
+///////////////////////////////////////////////////////////////////////////////
+string
+Environment::resultFileName(string& dbName, string& testName) {
+# if defined(__UNIX__)
+ string dirName(dbName + '/' + testName);
+ if (mkdir(dirName.c_str(), 0755)) {
+ if (errno != EEXIST)
+ throw DBCantOpen(dirName);
+ }
+ string fileName(dirName + "/results");
+# elif defined(__MS__)
+ string dirName(dbName + '/' + testName);
+ if (!CreateDirectory(dirName.c_str(),0)) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ throw DBCantOpen(dirName);
+ }
+ string fileName(dirName + "/results");
+# endif
+ return fileName;
+} // Environment::resultFileName
+
+string
+Environment::imageFileName(string& dbName, string& testName, int n) {
+ char sn[4];
+ sn[3] = 0;
+ sn[2] = static_cast<char>('0' + n % 10);
+ sn[1] = static_cast<char>('0' + (n / 10) % 10);
+ sn[0] = static_cast<char>('0' + (n / 100) % 10);
+# if defined(__UNIX__)
+ string fileName(dbName + '/' + testName + "/i" + sn + ".tif");
+# elif defined(__MS__)
+ string fileName(dbName + '/' + testName + "/i" + sn + ".tif");
+# endif
+ return fileName;
+} // Environment::imageFileName
+
+void
+Environment::quiesce() {
+ winSys.quiesce();
+# if defined(__UNIX__)
+ sync();
+# elif defined(__MS__)
+# endif
+} // Environment::quiesce
+
+} // namespace GLEAN
diff --git a/tests/glean/environ.h b/tests/glean/environ.h
new file mode 100644
index 00000000..1bf08f0c
--- /dev/null
+++ b/tests/glean/environ.h
@@ -0,0 +1,111 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// environ.h: global test environment
+
+// This class provides a facade for all the operating-system and
+// window-system services that we need to run ``portable'' tests.
+// Examples include logging services, opening streams to read or write
+// database files, and gaining access to the window system.
+
+
+#ifndef __environ_h__
+#define __environ_h__
+
+#include <iostream>
+#include "options.h"
+#include "winsys.h"
+
+namespace GLEAN {
+
+class Image; // Forward and mutually-recursive references.
+
+class Environment {
+ public:
+ // Constructors:
+ Environment(Options& opt);
+
+ // Exceptions:
+ struct Error { }; // Base class for all errors.
+ struct DBExists: public Error { // Output DB already exists.
+ };
+ struct DBCantOpen: public Error { // Can't open a DB.
+ const string* db;
+ DBCantOpen(string& s) {db = &s;}
+ };
+
+ // Members:
+ Options options; // Global testing options.
+
+ ostream& log; // Output stream used for logging results.
+
+ WindowSystem winSys; // The window system providing the OpenGL
+ // implementation under test.
+
+ string resultFileName(string& dbName, string& testName);
+ // Return name of results file for given
+ // test. Suitable for opening a stream.
+ // XXX Creates results directory as a side
+ // effect. Should separate this.
+ inline string resultFileName(string& testName) {
+ return resultFileName(options.db1Name, testName);
+ }
+ inline string result1FileName(string& testName) {
+ return resultFileName(options.db1Name, testName);
+ }
+ inline string result2FileName(string& testName) {
+ return resultFileName(options.db2Name, testName);
+ }
+
+ string imageFileName(string& dbName, string& testName, int n);
+ // Return name of image file number ``n''
+ // associated with the given test. Suitable
+ // for use with Image::readTIFF(), etc.
+ // XXX Doesn't create results directory,
+ // so resultFileName() must be called before
+ // using this.
+ inline string imageFileName(string& testName, int n) {
+ return imageFileName(options.db1Name, testName, n);
+ }
+ inline string image1FileName(string& testName, int n) {
+ return imageFileName(options.db1Name, testName, n);
+ }
+ inline string image2FileName(string& testName, int n) {
+ return imageFileName(options.db2Name, testName, n);
+ }
+
+ void quiesce(); // Settle down before starting a benchmark.
+
+}; // class Environment
+
+} // namespace GLEAN
+
+#endif // __environ_h__
diff --git a/tests/glean/geomrend.cpp b/tests/glean/geomrend.cpp
new file mode 100644
index 00000000..e8142a50
--- /dev/null
+++ b/tests/glean/geomrend.cpp
@@ -0,0 +1,504 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999,2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+// geomrend.h: convenience object for rendering any geometry via
+// a host of OpenGL paths: immediate mode (glVertex), vertex
+// arrays with glDrawArrays, vertex arrays with glArrayElement,
+// vertex arrays with glDrawElements, and any of the preceding
+// methods stuffed in a display list.
+
+using namespace std;
+
+#include "geomrend.h"
+#include "rand.h"
+#include "glutils.h"
+#include <algorithm>
+#include <iostream>
+#include <cmath>
+#include <float.h>
+#include <cassert>
+
+namespace GLEAN {
+
+
+// geomrend.h: convenience object for rendering any geometry via
+// a host of OpenGL paths: immediate mode (glVertex), vertex
+// arrays with glDrawArrays, vertex arrays with glArrayElement,
+// vertex arrays with glDrawElements, and any of the preceding
+// methods stuffed in a display list.
+
+// Functions for the helper class ArrayData, which stores the info about each parameter's data.
+ArrayData::ArrayData()
+{
+ size = 0;
+ type = GL_UNSIGNED_INT;
+ stride = 0;
+ pointer = 0;
+}
+
+void ArrayData::setData(GLint sizeIn, GLenum typeIn, GLsizei strideIn, const GLvoid* pointerIn)
+{
+ size = sizeIn;
+ type = typeIn;
+ stride = strideIn;
+ pointer = pointerIn;
+ if (stride == 0)
+ {
+ stride = size;
+ switch(type)
+ {
+ case GL_BYTE: stride *= sizeof(GLbyte); break;
+ case GL_UNSIGNED_BYTE: stride *= sizeof(GLubyte); break;
+ case GL_SHORT: stride *= sizeof(GLshort); break;
+ case GL_UNSIGNED_SHORT: stride *= sizeof(GLushort); break;
+ case GL_INT: stride *= sizeof(GLint); break;
+ case GL_UNSIGNED_INT: stride *= sizeof(GLuint); break;
+ case GL_FLOAT: stride *= sizeof(GLfloat); break;
+ case GL_DOUBLE: stride *= sizeof(GLdouble); break;
+ default: assert(false);
+ }
+ }
+}
+
+// Only a default constructor.
+GeomRenderer::GeomRenderer() : vertexData(), colorData(), texCoordData(), normalData()
+{
+ drawMethod = GLVERTEX_MODE;
+ parameterBits = 0;
+ compileArrays = false;
+
+ indicesCount = 0;
+ indicesType = GL_UNSIGNED_INT;
+ indices = 0;
+
+ arrayLength = 0;
+}
+
+// Used to set the method by which this GeomRenderer will pass the primitive data to the GL.
+// Default is GLVERTEX_MODE.
+void GeomRenderer::setDrawMethod(GeomRenderer::DrawMethod method)
+{
+ drawMethod = method;
+}
+
+GeomRenderer::DrawMethod GeomRenderer::getDrawMethod() const
+{
+ return drawMethod;
+}
+
+// Used to set the various parameters that are either enabled or disabled. Example usage:
+// to tell the GeomRenderer to pass vertex, color, and texcoord data, but not normals,
+// call setParameterBits(COLOR_BIT | TEXTURE_COORD_BIT). (Vertex data is implicitly enabled
+// all the time.) The default is that only vertex data is enabled.
+void GeomRenderer::setParameterBits(GLuint bits)
+{
+ parameterBits = bits;
+}
+
+GLuint GeomRenderer::getParameterBits() const
+{
+ return parameterBits;
+}
+
+// Used to specify whether EXT_compiled_vertex_array should be used if present. Default is false.
+// If set to true, the arrays are kept unlocked and only locked just before rendering calls are issued.
+// If you call setArraysCompiled(true) and the extension is not present, the function returns false
+// and acts as though you had passed false in as the argument.
+bool GeomRenderer::setArraysCompiled(bool compile)
+{
+ // Make sure we have the extension.
+ if (!GLUtils::haveExtension("GL_EXT_compiled_vertex_array") && compile == true)
+ {
+ compileArrays = false;
+ return false;
+ }
+
+ compileArrays = compile;
+ return true;
+}
+
+bool GeomRenderer::getArraysCompiled() const
+{
+ return compileArrays;
+}
+
+// If you're using GLDRAWELEMENTS_MODE, GLARRAYELEMENT_MODE, or GLVERTEX_MODE, you need to give
+// it the indices to pass into the GL.
+void GeomRenderer::setVArrayIndices(GLuint count, GLenum type, const GLvoid* indicesIn)
+{
+ assert(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT);
+
+ indicesCount = count;
+ indicesType = type;
+ indices = indicesIn;
+}
+
+// This hands the actual primitive data to the GeomRenderer. It holds onto these as pointers,
+// rather than copying them, so don't delete the data until you're done with the GeomRenderer.
+// These are prototypically equivalent to their respective GL calls, except that there's an extra
+// argument on the front of the vertex function for how many elements are in the array (this is
+// atomic; if you pass in 5, it means there are 5 vertices, not 5 floats or bytes or whatever).
+// The lengths of all other arrays are assumed to be >= the size passed in for the vertex array.
+void GeomRenderer::setVertexPointer(GLuint length, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+{
+ arrayLength = length;
+ vertexData.setData(size, type, stride, pointer);
+}
+
+void GeomRenderer::setColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+{
+ colorData.setData(size, type, stride, pointer);
+}
+
+void GeomRenderer::setTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+{
+ texCoordData.setData(size, type, stride, pointer);
+}
+
+void GeomRenderer::setNormalPointer(GLenum type, GLsizei stride, const GLvoid* pointer)
+{
+ normalData.setData(3, type, stride, pointer);
+}
+
+// Finally, the actual calls to do something with all this data. You can either choose to render
+// it given the configuration, or generate a display list of rendering it with the given
+// configuration (uses GL_COMPILE mode to build the list). Fails if insufficient data has
+// been given (i.e. if you don't give it an array for an enabled parameter, if you don't
+// give it an array of indices when it needs them).
+// Note that rendering with GLVERTEX_MODE currently involves a lot of CPU overhead to
+// unpack the data and pass it to the GL; while the results will be correct, it would be
+// unwise to use this method for rendering that is to be benchmarked, because it will
+// underestimate performance significantly on some machines.
+bool GeomRenderer::renderPrimitives(GLenum mode)
+{
+ if (!isReadyToRender())
+ {
+ return false;
+ }
+
+ // Okay, different sections here depending on what we're doing.
+ if (drawMethod == GLVERTEX_MODE)
+ {
+ glBegin(mode);
+ for (unsigned int x=0; x<indicesCount; x++)
+ {
+ int directIndex = getIndex(x);
+ if (parameterBits & COLOR_BIT) sendColor(directIndex);
+ if (parameterBits & TEXTURE_COORD_BIT) sendTexCoord(directIndex);
+ if (parameterBits & NORMAL_BIT) sendNormal(directIndex);
+ sendVertex(directIndex);
+ }
+ glEnd();
+ }
+ // Otherwise it has something to do with arrays; set up the arrays.
+ else
+ {
+ if (parameterBits & COLOR_BIT)
+ {
+ glEnableClientState(GL_COLOR_ARRAY);
+ glColorPointer(colorData.size, colorData.type, colorData.stride, colorData.pointer);
+// std::cout << "Enabled color arrays, size [" << colorData.size << "], type [" << colorData.type
+// << "], stride [" << colorData.stride << "], pointer [" << colorData.pointer << "]" << std::endl;
+ }
+ if (parameterBits & TEXTURE_COORD_BIT)
+ {
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(texCoordData.size, texCoordData.type, texCoordData.stride, texCoordData.pointer);
+// std::cout << "Enabled texCoord arrays, size [" << texCoordData.size << "], type [" << texCoordData.type
+// << "], stride [" << texCoordData.stride << "], pointer [" << texCoordData.pointer << "]" << std::endl;
+ }
+ if (parameterBits & NORMAL_BIT)
+ {
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glNormalPointer(normalData.type, normalData.stride, normalData.pointer);
+// std::cout << "Enabled normal arrays, size [" << normalData.size << "], type [" << normalData.type
+// << "], stride [" << normalData.stride << "], pointer [" << normalData.pointer << "]" << std::endl;
+ }
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(vertexData.size, vertexData.type, vertexData.stride, vertexData.pointer);
+// std::cout << "Enabled vertex arrays, size [" << vertexData.size << "], type [" << vertexData.type
+// << "], stride [" << vertexData.stride << "], pointer [" << vertexData.pointer << "]" << std::endl;
+
+ // Should we lock?
+ if (compileArrays)
+ {
+ PFNGLLOCKARRAYSEXTPROC glLockArraysEXT = 0;
+ assert(GLUtils::haveExtension("GL_EXT_compiled_vertex_array"));
+ glLockArraysEXT = reinterpret_cast<PFNGLLOCKARRAYSEXTPROC>
+ (GLUtils::getProcAddress("glLockArraysEXT"));
+ glLockArraysEXT(0, arrayLength);
+ }
+
+ // Okay, arrays configured; what exactly are we doing?
+ if (drawMethod == GLARRAYELEMENT_MODE)
+ {
+ glBegin(mode);
+ for (unsigned int x=0; x<indicesCount; x++)
+ {
+ glArrayElement(getIndex(x));
+ }
+ glEnd();
+ }
+ else if (drawMethod == GLDRAWARRAYS_MODE)
+ {
+ glDrawArrays(mode, 0, arrayLength);
+ std::cout << "Called glDrawArrays, mode [" << mode << "], from 0 to " << arrayLength << std::endl;
+ }
+ else if (drawMethod == GLDRAWELEMENTS_MODE)
+ {
+ glDrawElements(mode, indicesCount, indicesType, indices);
+ }
+
+ // Done. If we locked, unlock.
+ if (compileArrays)
+ {
+ PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT = 0;
+ assert(GLUtils::haveExtension("GL_EXT_compiled_vertex_array"));
+ glUnlockArraysEXT = reinterpret_cast<PFNGLUNLOCKARRAYSEXTPROC>
+ (GLUtils::getProcAddress("glUnlockArraysEXT"));
+ glUnlockArraysEXT();
+ }
+ }
+
+ return true;
+}
+
+bool GeomRenderer::generateDisplayList(GLenum mode, GLint& listHandleOut)
+{
+ if (!isReadyToRender())
+ {
+ return false;
+ }
+
+ listHandleOut = glGenLists(1);
+ glNewList(listHandleOut, GL_COMPILE);
+ assert(renderPrimitives(mode));
+ glEndList();
+
+ return true;
+}
+
+bool GeomRenderer::isReadyToRender()
+{
+ // Make sure we have vertex data.
+ if (vertexData.pointer == 0) return false;
+
+ // For the enabled parameters, make sure we have them, too.
+ if ((parameterBits & COLOR_BIT ) && (colorData.pointer == 0)) return false;
+ if ((parameterBits & TEXTURE_COORD_BIT) && (texCoordData.pointer == 0)) return false;
+ if ((parameterBits & NORMAL_BIT ) && (normalData.pointer == 0)) return false;
+
+ // If we need indices, we'd better have them.
+ if ((drawMethod == GLVERTEX_MODE ||
+ drawMethod == GLARRAYELEMENT_MODE ||
+ drawMethod == GLDRAWELEMENTS_MODE) && indices == 0)
+ {
+ return false;
+ }
+
+ // Otherwise we're good to go!
+ return true;
+}
+
+// This unpacks the indices depending on their format and returns the specified one.
+GLuint GeomRenderer::getIndex(int indicesIndex)
+{
+ assert(indicesIndex >= 0 && indicesIndex < static_cast<int>(indicesCount));
+
+ switch (indicesType)
+ {
+ case GL_UNSIGNED_BYTE:
+ return ((GLubyte*)indices)[indicesIndex];
+ break;
+
+ case GL_UNSIGNED_SHORT:
+ return ((GLushort*)indices)[indicesIndex];
+ break;
+
+ case GL_UNSIGNED_INT:
+ return ((GLuint*)indices)[indicesIndex];
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ // It never gets here, but let's quell the compiler warning...
+ return 0;
+}
+
+// I thought about making a lookup table for this, but it would involve an STL map of STL vectors
+// and some weird function casts, so I'm doing it the naive way instead.
+void GeomRenderer::sendVertex(GLuint vertexIndex)
+{
+ assert(vertexData.size >= 2 && vertexData.size <= 4);
+
+ switch(vertexData.type)
+ {
+ case GL_SHORT:
+ if (vertexData.size == 2) glVertex2sv((const GLshort*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ if (vertexData.size == 3) glVertex3sv((const GLshort*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ if (vertexData.size == 4) glVertex4sv((const GLshort*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ break;
+
+ case GL_INT:
+ if (vertexData.size == 2) glVertex2iv((const GLint*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ if (vertexData.size == 3) glVertex3iv((const GLint*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ if (vertexData.size == 4) glVertex4iv((const GLint*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ break;
+
+ case GL_FLOAT:
+ if (vertexData.size == 2) glVertex2fv((const GLfloat*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ if (vertexData.size == 3) glVertex3fv((const GLfloat*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ if (vertexData.size == 4) glVertex4fv((const GLfloat*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ break;
+
+ case GL_DOUBLE:
+ if (vertexData.size == 2) glVertex2dv((const GLdouble*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ if (vertexData.size == 3) glVertex3dv((const GLdouble*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ if (vertexData.size == 4) glVertex4dv((const GLdouble*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
+ break;
+ }
+}
+
+void GeomRenderer::sendColor(GLuint colorIndex)
+{
+ assert(colorData.size == 3 || colorData.size == 4);
+
+ switch(colorData.type)
+ {
+ case GL_BYTE:
+ if (colorData.size == 3) glColor3bv((const GLbyte*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ if (colorData.size == 4) glColor4bv((const GLbyte*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ break;
+
+ case GL_UNSIGNED_BYTE:
+ if (colorData.size == 3) glColor3ubv((const GLubyte*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ if (colorData.size == 4) glColor4ubv((const GLubyte*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ break;
+
+ case GL_SHORT:
+ if (colorData.size == 3) glColor3sv((const GLshort*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ if (colorData.size == 4) glColor4sv((const GLshort*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ break;
+
+ case GL_UNSIGNED_SHORT:
+ if (colorData.size == 3) glColor3usv((const GLushort*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ if (colorData.size == 4) glColor4usv((const GLushort*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ break;
+
+ case GL_INT:
+ if (colorData.size == 3) glColor3iv((const GLint*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ if (colorData.size == 4) glColor4iv((const GLint*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ break;
+
+ case GL_UNSIGNED_INT:
+ if (colorData.size == 3) glColor3uiv((const GLuint*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ if (colorData.size == 4) glColor4uiv((const GLuint*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ break;
+
+ case GL_FLOAT:
+ if (colorData.size == 3) glColor3fv((const GLfloat*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ if (colorData.size == 4) glColor4fv((const GLfloat*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ break;
+
+ case GL_DOUBLE:
+ if (colorData.size == 3) glColor3dv((const GLdouble*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ if (colorData.size == 4) glColor4dv((const GLdouble*)((const char*)colorData.pointer + colorIndex*colorData.stride));
+ break;
+ }
+}
+
+void GeomRenderer::sendTexCoord(GLuint texCoordIndex)
+{
+ assert(texCoordData.size >= 1 && texCoordData.size <= 4);
+
+ switch(texCoordData.type)
+ {
+ case GL_SHORT:
+ if (texCoordData.size == 1) glTexCoord1sv((const GLshort*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 2) glTexCoord2sv((const GLshort*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 3) glTexCoord3sv((const GLshort*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 4) glTexCoord4sv((const GLshort*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ break;
+
+ case GL_INT:
+ if (texCoordData.size == 1) glTexCoord1iv((const GLint*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 2) glTexCoord2iv((const GLint*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 3) glTexCoord3iv((const GLint*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 4) glTexCoord4iv((const GLint*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ break;
+
+ case GL_FLOAT:
+ if (texCoordData.size == 1) glTexCoord1fv((const GLfloat*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 2) glTexCoord2fv((const GLfloat*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 3) glTexCoord3fv((const GLfloat*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 4) glTexCoord4fv((const GLfloat*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ break;
+
+ case GL_DOUBLE:
+ if (texCoordData.size == 1) glTexCoord1dv((const GLdouble*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 2) glTexCoord2dv((const GLdouble*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 3) glTexCoord3dv((const GLdouble*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ if (texCoordData.size == 4) glTexCoord4dv((const GLdouble*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
+ break;
+ }
+}
+
+void GeomRenderer::sendNormal(GLuint normalIndex)
+{
+ assert(normalData.size == 3);
+
+ switch(normalData.type)
+ {
+ case GL_BYTE:
+ glNormal3bv((const GLbyte*)((const char*)normalData.pointer + normalIndex*normalData.stride));
+ break;
+
+ case GL_SHORT:
+ glNormal3sv((const GLshort*)((const char*)normalData.pointer + normalIndex*normalData.stride));
+ break;
+
+ case GL_INT:
+ glNormal3iv((const GLint*)((const char*)normalData.pointer + normalIndex*normalData.stride));
+ break;
+
+ case GL_FLOAT:
+ glNormal3fv((const GLfloat*)((const char*)normalData.pointer + normalIndex*normalData.stride));
+ break;
+
+ case GL_DOUBLE:
+ glNormal3dv((const GLdouble*)((const char*)normalData.pointer + normalIndex*normalData.stride));
+ break;
+ }
+}
+
+} // namespace GLEAN
diff --git a/tests/glean/geomrend.h b/tests/glean/geomrend.h
new file mode 100644
index 00000000..31678b28
--- /dev/null
+++ b/tests/glean/geomrend.h
@@ -0,0 +1,146 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999,2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// geomrend.h: convenience object for rendering any geometry via
+// a host of OpenGL paths: immediate mode (glVertex), vertex
+// arrays with glDrawArrays, vertex arrays with glArrayElement,
+// vertex arrays with glDrawElements, and any of the preceding
+// methods stuffed in a display list.
+
+#ifndef __geomrend_h__
+#define __geomrend_h__
+
+#include "glwrap.h"
+#include <cassert>
+
+namespace GLEAN {
+
+// A helper class to store parameter array data.
+class ArrayData {
+public:
+ GLint size;
+ GLenum type;
+ GLsizei stride;
+ const GLvoid* pointer;
+
+ ArrayData();
+ void setData(GLint sizeIn, GLenum typeIn, GLsizei strideIn, const GLvoid* pointerIn);
+};
+
+class GeomRenderer {
+ public:
+ // These indicate the methods of passing the primitive data to OpenGL. Note that whether
+ // the arrays are locked or not is an independent variable, not part of the method. See
+ // setArraysLocked and getArraysLocked.
+ enum DrawMethod {GLVERTEX_MODE, GLARRAYELEMENT_MODE, GLDRAWARRAYS_MODE, GLDRAWELEMENTS_MODE};
+
+ // Sorry, no indices, and especially no silly edge flags. There's no vertex bit because
+ // vertex data always implicitly enabled (you can't draw anything without vertex data).
+ enum ParameterBits {COLOR_BIT = 1, TEXTURE_COORD_BIT = 2, NORMAL_BIT = 4};
+
+ // Only a default constructor.
+ GeomRenderer();
+
+ // Used to set the method by which this GeomRenderer will pass the primitive data to the GL.
+ // Default is GLVERTEX_MODE.
+ void setDrawMethod(DrawMethod);
+ DrawMethod getDrawMethod() const;
+
+ // Used to set the various parameters that are either enabled or disabled. Example usage:
+ // to tell the GeomRenderer to pass vertex, color, and texcoord data, but not normals,
+ // call setParameterBits(COLOR_BIT | TEXTURE_COORD_BIT). (Vertex data is implicitly enabled
+ // all the time.) The default is that only vertex data is enabled.
+ void setParameterBits(GLuint bits);
+ GLuint getParameterBits() const;
+
+ // Used to specify whether EXT_compiled_vertex_array should be used if present. Default is false.
+ // If set to true, the arrays are kept unlocked and only locked just before rendering calls are issued.
+ // If you call setArraysCompiled(true) and the extension is not present, the function returns false
+ // and acts as though you had passed false in as the argument.
+ bool setArraysCompiled(bool);
+ bool getArraysCompiled() const;
+
+ // If you're using GLDRAWELEMENTS_MODE, GLARRAYELEMENT_MODE, or GLVERTEX_MODE, you need to give
+ // it the indices to pass into the GL.
+ void setVArrayIndices(GLuint count, GLenum type, const GLvoid* indices);
+
+ // This hands the actual primitive data to the GeomRenderer. It holds onto these as pointers,
+ // rather than copying them, so don't delete the data until you're done with the GeomRenderer.
+ // These are prototypically equivalent to their respective GL calls, except that there's an extra
+ // argument on the front of the vertex function for how many elements are in the array (this is
+ // atomic; if you pass in 5, it means there are 5 vertices, not 5 floats or bytes or whatever).
+ // The lengths of all other arrays are assumed to be >= the size passed in for the vertex array.
+ void setVertexPointer(GLuint arrayLength, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);
+ void setColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);
+ void setTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);
+ void setNormalPointer(GLenum type, GLsizei stride, const GLvoid* pointer);
+
+ // Finally, the actual calls to do something with all this data. You can either choose to render
+ // it given the configuration, or generate a display list of rendering it with the given
+ // configuration (uses GL_COMPILE mode to build the list). Fails if insufficient data has
+ // been given (i.e. if you don't give it an array for an enabled parameter, if you don't
+ // give it an array of indices when it needs them).
+ bool renderPrimitives(GLenum mode);
+ bool generateDisplayList(GLenum mode, GLint& listHandleOut);
+
+ private:
+ bool isReadyToRender();
+
+ // Helper functions for unpacking and translating the data from the indices, vertices, colors,
+ // texcoords, and normals arrays.
+ GLuint getIndex(int);
+ void sendVertex(GLuint index);
+ void sendColor(GLuint index);
+ void sendTexCoord(GLuint index);
+ void sendNormal(GLuint index);
+
+ DrawMethod drawMethod;
+ GLuint parameterBits;
+ bool compileArrays;
+
+ GLuint indicesCount;
+ GLenum indicesType;
+ const GLvoid* indices;
+
+ GLuint arrayLength;
+
+ ArrayData vertexData;
+ ArrayData colorData;
+ ArrayData texCoordData;
+ ArrayData normalData;
+};
+
+} // namespace GLEAN
+
+#endif // __geomrend_h__
+
+
+
diff --git a/tests/glean/geomutil.cpp b/tests/glean/geomutil.cpp
new file mode 100644
index 00000000..ab8ab2dc
--- /dev/null
+++ b/tests/glean/geomutil.cpp
@@ -0,0 +1,360 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999,2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+// geomutil.cpp: frequently-used geometric operations
+
+using namespace std;
+
+#include "geomutil.h"
+#include "rand.h"
+#include <cassert>
+#include <algorithm>
+#include <cmath>
+#include <float.h>
+#include <stdio.h>
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// RandomMesh2D: Generate 2D array with fixed boundaries but interior points
+// that have been perturbed randomly.
+///////////////////////////////////////////////////////////////////////////////
+RandomMesh2D::RandomMesh2D(float minX, float maxX, int xPoints,
+ float minY, float maxY, int yPoints,
+ RandomDouble& rand) {
+ m = new float[xPoints * yPoints * 2];
+ rowLength = xPoints;
+
+ // Loop var; we declare it here and not in the for loop because
+ // different compilers scope variables differently when
+ // declared in a for loop.
+ int iy;
+
+ // Drop each point squarely into the center of its grid cell:
+ for (iy = 0; iy < yPoints; ++iy)
+ for (int ix = 0; ix < xPoints; ++ix) {
+ float* v = (*this)(iy, ix);
+ v[0] = minX + (ix * (maxX - minX)) / (xPoints - 1);
+ v[1] = minY + (iy * (maxY - minY)) / (yPoints - 1);
+ }
+ // Now perturb each interior point, but only within its cell:
+ double deltaX = 0.9 * (maxX - minX) / (xPoints - 1);
+ double deltaY = 0.9 * (maxY - minY) / (yPoints - 1);
+ for (iy = 1; iy < yPoints - 1; ++iy)
+ for (int ix = 1; ix < xPoints - 1; ++ix) {
+ float* v = (*this)(iy, ix);
+ v[0] += deltaX * (rand.next() - 0.5);
+ v[1] += deltaY * (rand.next() - 0.5);
+ }
+} // RandomMesh2D::RandomMesh2D
+
+RandomMesh2D::~RandomMesh2D() {
+ delete[] m;
+} // RandomMesh2D::~RandomMesh2D
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SpiralStrip2D: Generate (x,y) vertices for a triangle strip of arbitrary
+// length. The triangles are of approximately equal size, and arranged
+// in a spiral so that a reasonably large number of triangles can be
+// packed into a small screen area.
+///////////////////////////////////////////////////////////////////////////////
+SpiralStrip2D::SpiralStrip2D(int nPoints, float minX, float maxX,
+ float minY, float maxY) {
+
+ // Most of the complexity of this code results from attempting
+ // to keep the triangles approximately equal in area.
+ //
+ // Conceptually, we construct concentric rings whose inner and
+ // outer radii differ by a constant. We then split each ring
+ // (at theta == 0), and starting from the point of the split
+ // gradually increase both the inner and outer radii so that
+ // when we've wrapped all the way around the ring (to theta ==
+ // 2*pi), the inner radius now matches the original outer
+ // radius. We then repeat the process with the next ring
+ // (working from innermost to outermost) until we've
+ // accumulated enough vertices to satisfy the caller's
+ // requirements.
+ //
+ // Finally, we scale and offset all the points so that the
+ // resulting spiral fits comfortably within the rectangle
+ // provided by the caller.
+
+ // Set up the array of vertices:
+ v = new float[2 * nPoints];
+ float* lastV = v + 2 * nPoints;
+
+ // Initialize the ring parameters:
+ double innerRadius = 4.0;
+ double ringWidth = 1.0;
+ double segLength = 1.0;
+
+ float* pV = v;
+ while (pV < lastV) {
+ // Each ring consists of segments. We'll make the arc
+ // length of each segment that lies on the inner
+ // radius approximately equal to segLength, but we'll
+ // adjust it to ensure there are an integral number of
+ // equal-sized segments in the ring.
+ int nSegments = static_cast<int>
+ (6.2831853 * innerRadius / segLength + 0.5);
+
+ double dTheta = 6.2831853 / nSegments;
+ double dRadius = ringWidth / nSegments;
+
+ double theta = 0.0;
+ for (int i = 0; i < nSegments; ++i) {
+ double c = cos(theta);
+ double s = sin(theta);
+
+ *pV++ = innerRadius * c;
+ *pV++ = innerRadius * s;
+ if (pV >= lastV)
+ break;
+
+ *pV++ = (innerRadius + ringWidth) * c;
+ *pV++ = (innerRadius + ringWidth) * s;
+ if (pV >= lastV)
+ break;
+
+ theta += dTheta;
+ innerRadius += dRadius;
+ }
+ }
+
+ // Find the bounding box for the spiral:
+ float lowX = FLT_MAX;
+ float highX = - FLT_MAX;
+ float lowY = FLT_MAX;
+ float highY = -FLT_MAX;
+ for (pV = v; pV < lastV; pV += 2) {
+ lowX = min(lowX, pV[0]);
+ highX = max(highX, pV[0]);
+ lowY = min(lowY, pV[1]);
+ highY = max(highY, pV[1]);
+ }
+
+ // Find scale and offset to map the spiral into the bounds supplied
+ // by our caller, with a little bit of margin around the edges:
+ lowX -= ringWidth;
+ highX += ringWidth;
+ lowY -= ringWidth;
+ highY += ringWidth;
+ float scaleX = (maxX - minX) / (highX - lowX);
+ float offsetX = minX - scaleX * lowX;
+ float scaleY = (maxY - minY) / (highY - lowY);
+ float offsetY = minY - scaleY * lowY;
+
+ // Finally scale and offset the constructed vertices so that
+ // they fit in the caller-supplied rectangle:
+ for (pV = v; pV < lastV; pV += 2) {
+ pV[0] = scaleX * pV[0] + offsetX;
+ pV[1] = scaleY * pV[1] + offsetY;
+ }
+} // SpiralStrip2D::SpiralStrip2D
+
+SpiralStrip2D::~SpiralStrip2D() {
+ delete[] v;
+} // SpiralStrip2D::~SpiralStrip2D
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SpiralTri2D: Generate (x,y) vertices for a set of independent triangles,
+// arranged in spiral fashion exactly as in SpiralStrip2D.
+// One may rely on the fact that SpiralTri2D generates exactly the
+// same triangles as SpiralStrip2D, so that comparison of images
+// using the two primitives is meaningful.
+///////////////////////////////////////////////////////////////////////////////
+SpiralTri2D::SpiralTri2D(int nTris, float minX, float maxX,
+ float minY, float maxY) {
+ SpiralStrip2D ts(nTris + 2, minX, maxX, minY, maxY);
+ const int nVertices = 3 * nTris;
+ v = new float[2 * nVertices];
+
+ float* pTris = v;
+ float* pStrip = ts(0);
+ bool front = true; // winding order alternates in strip
+ for (int i = 0; i < nTris; ++i) {
+ if (front) {
+ pTris[0] = pStrip[0];
+ pTris[1] = pStrip[1];
+
+ pTris[2] = pStrip[2];
+ pTris[3] = pStrip[3];
+
+ pTris[4] = pStrip[4];
+ pTris[5] = pStrip[5];
+ } else {
+ pTris[0] = pStrip[0];
+ pTris[1] = pStrip[1];
+
+ pTris[2] = pStrip[4];
+ pTris[3] = pStrip[5];
+
+ pTris[4] = pStrip[2];
+ pTris[5] = pStrip[3];
+ }
+
+ front = !front;
+ pTris += 6;
+ pStrip += 2;
+ }
+} // SpiralTri2D::SpiralTri2D
+
+SpiralTri2D::~SpiralTri2D() {
+ delete[] v;
+} // SpiralTri2D::~SpiralTri2D
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sphere3D: Forms a stacks/slices sphere and can return the vertices and index list for drawing it.
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+Sphere3D::Sphere3D(float radius, int slices, int stacks)
+{
+ // Loop vars.
+ int curStack, curSlice;
+
+ // Can't have a sphere of less than 2 slices or stacks.
+ assert(slices >= 2 && stacks >= 2);
+
+ // We have 2 verts for the top and bottom point, and then slices*(stacks-1) more for the
+ // middle rings (it's stacks-1 since the top and bottom points each count in the stack count).
+ numVertices = 2 + (slices*(stacks-1));
+ vertices.reserve(numVertices*3);
+ normals.reserve(numVertices*3);
+
+ // The top and bottom slices have <slices> tris in them, and the ones in the middle (since they're
+ // made of quads) have 2*<slices> each.
+ numIndices = 3*(2*slices + 2*(stacks-2)*slices);
+ indices.reserve(numIndices);
+
+#define VX(i) vertices[3*(i)+0]
+#define VY(i) vertices[3*(i)+1]
+#define VZ(i) vertices[3*(i)+2]
+#define VINDEX(st,sl) (1 + (((st)-1)*slices) + (sl))
+#ifndef M_PI
+#define M_PI 3.14159
+#endif
+
+ // Generate the verts. The bottom and top verts are kind of special cases (they
+ // occupy the first and last vertex slots, respectively).
+ vertices.push_back(0);
+ vertices.push_back(0);
+ vertices.push_back(-radius);
+ normals.push_back(0);
+ normals.push_back(0);
+ normals.push_back(-1);
+
+ // Now the inner rings; I can't decide whether it spreads the tri area out better to do this by
+ // increments in the spherical coordinate phi or in the cartesian z, but I think phi is a better bet.
+ for (curStack=1; curStack<stacks; curStack++)
+ {
+ float phi = M_PI - ((curStack / (float)stacks) * M_PI);
+ float zVal = radius * cos(phi);
+ float sliceRadius = sqrt(radius*radius - zVal*zVal);
+ for (curSlice = 0; curSlice < slices; curSlice++)
+ {
+ float theta = 2*M_PI*((float)curSlice / slices);
+
+ float xVal = sliceRadius*cos(theta);
+ float yVal = sliceRadius*sin(theta);
+
+ vertices.push_back(xVal);
+ vertices.push_back(yVal);
+ vertices.push_back(zVal);
+ normals.push_back(xVal/radius);
+ normals.push_back(yVal/radius);
+ normals.push_back(zVal/radius);
+ }
+ }
+
+ vertices.push_back(0);
+ vertices.push_back(0);
+ vertices.push_back(radius);
+ normals.push_back(0);
+ normals.push_back(0);
+ normals.push_back(1);
+
+ // Now to assemble them into triangles. Do the top and bottom slices first.
+ for (curSlice=0; curSlice<slices; curSlice++)
+ {
+ indices.push_back(0);
+ indices.push_back((curSlice+1)%slices + 1);
+ indices.push_back(curSlice+1);
+
+ indices.push_back(numVertices - 1);
+ indices.push_back(numVertices - 2 - ((curSlice+1)%slices));
+ indices.push_back(numVertices - 2 - curSlice);
+ }
+
+ // Now for the inner rings. We're already done with 2*slices triangles, so start after that.
+ for (curStack=1; curStack<stacks-1; curStack++)
+ {
+ for (curSlice=0; curSlice<slices; curSlice++)
+ {
+ int nextStack = curStack+1;
+ int nextSlice = (curSlice+1)%slices;
+ indices.push_back(VINDEX(curStack, curSlice));
+ indices.push_back(VINDEX(curStack, nextSlice));
+ indices.push_back(VINDEX(nextStack, nextSlice));
+
+ indices.push_back(VINDEX(curStack, curSlice));
+ indices.push_back(VINDEX(nextStack, nextSlice));
+ indices.push_back(VINDEX(nextStack, curSlice));
+ }
+ }
+
+ assert(static_cast<int>(vertices.size()) == numVertices*3);
+ assert(static_cast<int>(indices.size()) == numIndices);
+
+#undef VX
+#undef VY
+#undef VZ
+#undef VINDEX
+}
+
+// This returns the vertices: 3 floats per vertex in a tightly packed array (no padding between vertices).
+const float* Sphere3D::getVertices() const { return &(vertices[0]); }
+int Sphere3D::getNumVertices() const { return numVertices; }
+
+// This returns the normals; same data format as the vertices. And of course the number of normals is
+// the same as the number of vertices.
+const float* Sphere3D::getNormals() const { return &(normals[0]); }
+
+// This returns a series of vertices that form triangles from the vertices (the indices specify loose
+// triangles, not tristrips or fans or whatnot. So each triplet of indices is an individual triangle.)
+const unsigned int* Sphere3D::getIndices() const { return &(indices[0]); }
+int Sphere3D::getNumIndices() const { return numIndices; }
+
+
+} // namespace GLEAN
diff --git a/tests/glean/geomutil.h b/tests/glean/geomutil.h
new file mode 100644
index 00000000..34e73566
--- /dev/null
+++ b/tests/glean/geomutil.h
@@ -0,0 +1,100 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999,2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// geomutil.h: frequently-used geometric operations
+
+#ifndef __geomutil_h__
+#define __geomutil_h__
+
+#include <vector>
+
+namespace GLEAN {
+
+class RandomDouble; // Forward reference.
+
+class RandomMesh2D {
+ float* m;
+ int rowLength;
+ public:
+ RandomMesh2D(float minX, float maxX, int xPoints,
+ float minY, float maxY, int yPoints,
+ RandomDouble& rand);
+ ~RandomMesh2D();
+ inline float* operator() (int y, int x)
+ { return m + 2 * (y * rowLength + x); }
+}; // RandomMesh2D
+
+class SpiralStrip2D {
+ float* v;
+ public:
+ SpiralStrip2D(int nPoints, float minX, float maxX,
+ float minY, float maxY);
+ ~SpiralStrip2D();
+ inline float* operator() (int i)
+ { return v + 2 * i; }
+}; // SpiralStrip2D
+
+class SpiralTri2D {
+ float* v;
+ public:
+ SpiralTri2D(int nTris, float minX, float maxX,
+ float minY, float maxY);
+ ~SpiralTri2D();
+ inline float* operator() (int i)
+ { return v + 6 * i; }
+}; // SpiralTri2D
+
+class Sphere3D {
+ std::vector<float> vertices;
+ std::vector<float> normals;
+ int numVertices;
+ std::vector<unsigned int> indices;
+ int numIndices;
+ public:
+ Sphere3D(float radius, int slices, int stacks);
+
+ // This returns the vertices: 3 floats per vertex in a tightly packed array (no padding between vertices).
+ const float* getVertices() const;
+ int getNumVertices() const;
+
+ // This returns the normals; same data format as the vertices. And of course the number of normals is
+ // the same as the number of vertices.
+ const float* getNormals() const;
+
+ // This returns a series of vertices that form triangles from the vertices (the indices specify loose
+ // triangles, not tristrips or fans or whatnot. So each triplet of indices is an individual triangle.)
+ const unsigned int* getIndices() const;
+ int getNumIndices() const;
+};
+
+} // namespace GLEAN
+
+#endif // __geomutil_h__
diff --git a/tests/glean/gl.cpp b/tests/glean/gl.cpp
new file mode 100644
index 00000000..89ca4ae9
--- /dev/null
+++ b/tests/glean/gl.cpp
@@ -0,0 +1,82 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// OpenGL utility routines for images
+
+#include "image.h"
+
+namespace GLEAN {
+
+
+///////////////////////////////////////////////////////////////////////////////
+// draw - draw image using glDrawPixels
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::draw() {
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment());
+ glDrawPixels(width(), height(), format(), type(), pixels());
+} // Image::draw
+
+///////////////////////////////////////////////////////////////////////////////
+// read - read image using glReadPixels
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::read(GLint x, GLint y) {
+ glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, alignment());
+ glReadPixels(x, y, width(), height(), format(), type(), pixels());
+} // Image::read
+
+///////////////////////////////////////////////////////////////////////////////
+// makeMipmaps - generate and load mipmaps for texturing
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::makeMipmaps(GLenum internalFormat) {
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment());
+ gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, width(), height(),
+ format(), type(), pixels());
+} // Image::makeMipmaps
+
+}; // namespace GLEAN
diff --git a/tests/glean/glutils.cpp b/tests/glean/glutils.cpp
new file mode 100644
index 00000000..342bd476
--- /dev/null
+++ b/tests/glean/glutils.cpp
@@ -0,0 +1,325 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999, 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// glutils.cpp: frequently-used OpenGL operations
+
+#define GLX_GLXEXT_PROTOTYPES
+#include "glwrap.h"
+#include "environ.h"
+#include "lex.h"
+#include "glutils.h"
+#if defined(__X11__)
+# include <dlfcn.h>
+#endif
+#if defined(__AGL__)
+# include <cstring>
+#endif
+
+namespace GLEAN {
+
+namespace GLUtils {
+
+///////////////////////////////////////////////////////////////////////////////
+// useScreenCoords: Map object coords directly to screen coords.
+///////////////////////////////////////////////////////////////////////////////
+void
+useScreenCoords(int windowW, int windowH) {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, windowW, 0, windowH, -1, 1);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glViewport(0, 0, windowW, windowH);
+ glTranslatef(0.375, 0.375, 0.0);
+} // useScreenCoords
+
+///////////////////////////////////////////////////////////////////////////////
+// haveExtensions: See if the current rendering context supports a given
+// set of extensions.
+///////////////////////////////////////////////////////////////////////////////
+bool
+haveExtensions(const char* required) {
+ const char* available = reinterpret_cast<const char*>
+ (glGetString(GL_EXTENSIONS));
+
+ if (!required)
+ return true;
+ if (!available)
+ return false;
+
+ bool haveAll = true;
+ Lex lRequired(required);
+ for (lRequired.next(); lRequired.token != Lex::END; lRequired.next()) {
+ if (lRequired.token != Lex::ID)
+ continue;
+ bool haveOne = false;
+ Lex lAvailable(available);
+ for (lAvailable.next(); lAvailable.token != Lex::END;
+ lAvailable.next())
+ if (lAvailable.token == Lex::ID
+ && lAvailable.id == lRequired.id) {
+ haveOne = true;
+ break;
+ }
+ haveAll &= haveOne;
+ if (!haveAll)
+ break;
+ }
+
+ return haveAll;
+} // haveExtensions
+
+///////////////////////////////////////////////////////////////////////////////
+// getProcAddress: Get address of an OpenGL or window-system-binding function.
+// This belongs here, rather than as a member of RenderingContext, because
+// on Windows it must only be applied to the *current* context. (The
+// return value on Windows is context-dependent, and wglGetProcAddress
+// doesn't take a rendering context as an argument.)
+///////////////////////////////////////////////////////////////////////////////
+void
+(*getProcAddress(const char* name))() {
+#if defined(__X11__)
+# if defined(GLX_ARB_get_proc_address)
+ return glXGetProcAddressARB(reinterpret_cast<const GLubyte*>(name));
+# else
+ // XXX This isn't guaranteed to work, but it may be the best option
+ // we have at the moment.
+ void* libHandle = dlopen("libGL.so", RTLD_LAZY);
+ if (libHandle) {
+ void* funcPointer = dlsym(libHandle, name);
+ dlclose(libHandle);
+ return funcPointer;
+ } else
+ return 0;
+# endif
+#elif defined(__WIN__)
+ // Gotta be a little more explicit about the cast to please MSVC.
+ typedef void (__cdecl* VOID_FUNC_VOID) ();
+ return reinterpret_cast<VOID_FUNC_VOID>(wglGetProcAddress(name));
+#elif defined(__BEWIN__)
+# error "Need GetProcAddress (or equivalent) for BeOS"
+ return 0;
+#elif defined(__AGL__)
+ // Very quick hack to keep things running for a few hours until
+ // a better solution is in place:
+ if (!strcmp(name, "glLockArraysEXT"))
+ return reinterpret_cast<void (*)()> (glLockArraysEXT);
+ else if (!strcmp(name, "glUnlockArraysEXT"))
+ return reinterpret_cast<void (*)()> (glUnlockArraysEXT);
+ else if (!strcmp(name, "glActiveTextureARB"))
+ return reinterpret_cast<void (*)()> (glActiveTextureARB);
+ else if (!strcmp(name, "glMultiTexCoord2fARB"))
+ return reinterpret_cast<void (*)()> (glMultiTexCoord2fARB);
+ else if (!strcmp(name, "glLockArraysEXT"))
+ return reinterpret_cast<void (*)()> (glLockArraysEXT);
+ else if (!strcmp(name, "glUnlockArraysEXT"))
+ return reinterpret_cast<void (*)()> (glUnlockArraysEXT);
+ else if (!strcmp(name, "glLockArraysEXT"))
+ return reinterpret_cast<void (*)()> (glLockArraysEXT);
+ else if (!strcmp(name, "glUnlockArraysEXT"))
+ return reinterpret_cast<void (*)()> (glUnlockArraysEXT);
+ else
+ return 0;
+#endif
+} // getProcAddress
+
+///////////////////////////////////////////////////////////////////////////////
+// logGLErrors: Check for OpenGL errors and log any that have occurred.
+///////////////////////////////////////////////////////////////////////////////
+void
+logGLErrors(Environment& env) {
+ GLenum err;
+ while ((err = glGetError()))
+ env.log << "\tOpenGL error: " << gluErrorString(err) << '\n';
+} // logGLErrors
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Syntactic sugar for light sources
+///////////////////////////////////////////////////////////////////////////////
+
+Light::Light(int l) {
+ lightNumber = static_cast<GLenum>(GL_LIGHT0 + l);
+} // Light::Light
+
+void
+Light::ambient(float r, float g, float b, float a){
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glLightfv(lightNumber, GL_AMBIENT, v);
+} // Light::ambient
+
+void
+Light::diffuse(float r, float g, float b, float a){
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glLightfv(lightNumber, GL_DIFFUSE, v);
+} // Light::diffuse
+
+void
+Light::specular(float r, float g, float b, float a){
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glLightfv(lightNumber, GL_SPECULAR, v);
+} // Light::specular
+
+void
+Light::position(float x, float y, float z, float w){
+ GLfloat v[4];
+ v[0] = x; v[1] = y; v[2] = z; v[3] = w;
+ glLightfv(lightNumber, GL_POSITION, v);
+} // Light::position
+
+void
+Light::spotDirection(float x, float y, float z){
+ GLfloat v[3];
+ v[0] = x; v[1] = y; v[2] = z;
+ glLightfv(lightNumber, GL_SPOT_DIRECTION, v);
+} // Light::spotDirection
+
+void
+Light::spotExponent(float e){
+ glLightf(lightNumber, GL_SPOT_EXPONENT, e);
+} // Light::spotExponent
+
+void
+Light::spotCutoff(float c){
+ glLightf(lightNumber, GL_SPOT_CUTOFF, c);
+} // Light::spotCutoff
+
+void
+Light::constantAttenuation(float a){
+ glLightf(lightNumber, GL_CONSTANT_ATTENUATION, a);
+} // Light::constantAttenuation
+
+void
+Light::linearAttenuation(float a){
+ glLightf(lightNumber, GL_LINEAR_ATTENUATION, a);
+} // Light::linearAttenuation
+
+void
+Light::quadraticAttenuation(float a){
+ glLightf(lightNumber, GL_QUADRATIC_ATTENUATION, a);
+} // Light::quadraticAttenuation
+
+void
+Light::enable() {
+ glEnable(lightNumber);
+} // Light::enable
+
+void
+Light::disable() {
+ glDisable(lightNumber);
+} // Light::disable
+
+///////////////////////////////////////////////////////////////////////////////
+// Syntactic sugar for light model
+///////////////////////////////////////////////////////////////////////////////
+
+LightModel::LightModel() {
+} // LightModel::LightModel
+
+void
+LightModel::ambient(float r, float g, float b, float a) {
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, v);
+} // LightModel::ambient
+
+void
+LightModel::localViewer(bool v) {
+ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, static_cast<GLint>(v));
+} // LightModel::localViewer
+
+void
+LightModel::twoSide(bool v) {
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, static_cast<GLint>(v));
+} // LightModel::twoSide
+
+void
+LightModel::colorControl(GLenum e) {
+ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, e);
+} // LightModel::colorControl
+
+///////////////////////////////////////////////////////////////////////////////
+// Syntactic sugar for material properties
+///////////////////////////////////////////////////////////////////////////////
+
+Material::Material(GLenum f) {
+ face = f;
+} // Material::Material
+
+void
+Material::ambient(float r, float g, float b, float a) {
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glMaterialfv(face, GL_AMBIENT, v);
+} // Material::ambient
+
+void
+Material::diffuse(float r, float g, float b, float a) {
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glMaterialfv(face, GL_DIFFUSE, v);
+} // Material::diffuse
+
+void
+Material::ambientAndDiffuse(float r, float g, float b, float a) {
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glMaterialfv(face, GL_AMBIENT_AND_DIFFUSE, v);
+} // Material::ambientAndDiffuse
+
+void
+Material::specular(float r, float g, float b, float a) {
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glMaterialfv(face, GL_SPECULAR, v);
+} // Material::specular
+
+void
+Material::emission(float r, float g, float b, float a) {
+ GLfloat v[4];
+ v[0] = r; v[1] = g; v[2] = b; v[3] = a;
+ glMaterialfv(face, GL_EMISSION, v);
+} // Material::emission
+
+void
+Material::shininess(float s) {
+ glMaterialf(face, GL_SHININESS, static_cast<GLfloat>(s));
+} // Material::shininess
+
+
+} // namespace GLUtils
+
+} // namespace GLEAN
diff --git a/tests/glean/glutils.h b/tests/glean/glutils.h
new file mode 100644
index 00000000..94db42c5
--- /dev/null
+++ b/tests/glean/glutils.h
@@ -0,0 +1,111 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999, 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// glutils.h: frequently-used OpenGL operations
+
+#ifndef __glutils_h__
+#define __glutils_h__
+
+namespace GLEAN {
+
+class Environment; // Forward reference.
+
+namespace GLUtils {
+
+// Set up projection and modelview matrices so that first-quadrant
+// object coordinates map directly to screen coordinates (using the
+// normal Cartesian convention, with (0,0) at lower left).
+void useScreenCoords(int windowW, int windowH);
+
+// Check to see if the current rendering context supports a given
+// extension or set of extensions. (This is here, rather than in
+// RenderingContext, because it can only be applied to the ``current''
+// context rather than to any arbitrary context.)
+bool haveExtensions(const char* required);
+inline bool haveExtension(const char* name) {
+ return haveExtensions(name);
+}
+
+// Get a pointer to a function (usually, an extension function).
+// Like haveExtension, we have to do this here rather than in
+// RenderingContext.
+void (*getProcAddress(const char* name))();
+
+// Check for OpenGL errors and log any that have occurred:
+void logGLErrors(Environment& env);
+
+// Syntactic sugar for dealing with light source parameters:
+class Light {
+ GLenum lightNumber;
+ public:
+ Light(int l);
+ void ambient(float r, float g, float b, float a);
+ void diffuse(float r, float g, float b, float a);
+ void specular(float r, float g, float b, float a);
+ void position(float x, float y, float z, float w);
+ void spotDirection(float x, float y, float z);
+ void spotExponent(float e);
+ void spotCutoff(float c);
+ void constantAttenuation(float a);
+ void linearAttenuation(float a);
+ void quadraticAttenuation(float a);
+ void enable();
+ void disable();
+}; // Light
+
+// Syntactic sugar for dealing with light model:
+class LightModel {
+ public:
+ LightModel();
+ void ambient(float r, float g, float b, float a);
+ void localViewer(bool v);
+ void twoSide(bool v);
+ void colorControl(GLenum e);
+}; // LightModel
+
+// Syntactic sugar for dealing with material properties:
+class Material {
+ GLenum face;
+ public:
+ Material(GLenum f = GL_FRONT_AND_BACK);
+ void ambient(float r, float g, float b, float a);
+ void diffuse(float r, float g, float b, float a);
+ void ambientAndDiffuse(float r, float g, float b, float a);
+ void specular(float r, float g, float b, float a);
+ void emission(float r, float g, float b, float a);
+ void shininess(float s);
+}; // Material
+
+} // namespace GLUtils
+
+} // namespace GLEAN
+
+#endif // __glutils_h__
diff --git a/tests/glean/glwrap.h b/tests/glean/glwrap.h
new file mode 100644
index 00000000..18136ca8
--- /dev/null
+++ b/tests/glean/glwrap.h
@@ -0,0 +1,784 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// Microsoft's version of gl.h invokes macros that are defined in
+// windows.h. To avoid a conditional #include <windows.h> in
+// every file, we wrap gl.h with the proper conditions here, and
+// have our source files #include "glwrap.h" instead.
+
+// As a bonus we ensure that all declarations for GLU are included,
+// and on X11-based systems, we cover X11 and GLX as well. This
+// should cover nearly everything needed by a typical glean test.
+
+// It's unfortunate that both Windows and Xlib are so casual about
+// polluting the global namespace. The problem isn't easily resolved,
+// even with the use of C++ namespace directives, because (a) macros
+// in the include files refer to unqualified global variables, and (b)
+// preprocessor macros themselves aren't affected by namespaces.
+
+
+#ifndef __glwrap_h__
+#define __glwrap_h__
+
+#if defined(__WIN__)
+# include <windows.h>
+# include <GL/gl.h>
+# include <GL/glu.h>
+# if !defined(GLAPIENTRY)
+# define GLAPIENTRY __stdcall
+# endif
+# if !defined(GLCALLBACK)
+# define GLCALLBACK __stdcall
+# endif
+# include <GL/glext.h>
+#elif defined(__X11__)
+# include <GL/glx.h>
+ // glx.h covers Xlib.h and gl.h, among others
+# include <GL/glu.h>
+# if !defined(GLAPIENTRY)
+# define GLAPIENTRY
+# endif
+# if !defined(GLCALLBACK)
+# define GLCALLBACK
+# endif
+# include <GL/glext.h>
+#elif defined(__AGL__)
+# include <Carbon/Carbon.h>
+# include <OpenGL/glu.h>
+# include <OpenGL/glext.h>
+# include <AGL/agl.h>
+# include <AGL/aglRenderers.h>
+# if !defined(GLAPIENTRY)
+# define GLAPIENTRY
+# endif
+# if !defined(GLCALLBACK)
+# define GLCALLBACK
+# endif
+# if !defined(sinf)
+# define sinf sin
+# define cosf cos
+# define sqrtf sqrt
+# endif
+#else
+# error "Improper window system configuration; must be __WIN__ or __X11__."
+#endif
+
+#ifndef GL_COMBINE_EXT
+ #ifdef GL_COMBINE_ARB
+ #define GL_COMBINE_EXT GL_COMBINE_ARB
+ #define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB
+ #define GL_COMBINE_ALPHA_EXT GL_COMBINE_ALPHA_ARB
+ #define GL_RGB_SCALE_EXT GL_RGB_SCALE_ARB
+ #define GL_ADD_SIGNED_EXT GL_ADD_SIGNED_ARB
+ #define GL_INTERPOLATE_EXT GL_INTERPOLATE_ARB
+ #define GL_CONSTANT_EXT GL_CONSTANT_ARB
+ #define GL_PRIMARY_COLOR_EXT GL_PRIMARY_COLOR_ARB
+ #define GL_PREVIOUS_EXT GL_PREVIOUS_ARB
+ #define GL_SUBTRACT_EXT GL_SUBTRACT_ARB
+ #define GL_SOURCE0_RGB_EXT GL_SOURCE0_RGB_ARB
+ #define GL_SOURCE1_RGB_EXT GL_SOURCE1_RGB_ARB
+ #define GL_SOURCE2_RGB_EXT GL_SOURCE2_RGB_ARB
+ #define GL_SOURCE0_ALPHA_EXT GL_SOURCE0_ALPHA_ARB
+ #define GL_SOURCE1_ALPHA_EXT GL_SOURCE1_ALPHA_ARB
+ #define GL_SOURCE2_ALPHA_EXT GL_SOURCE2_ALPHA_ARB
+ #define GL_OPERAND0_RGB_EXT GL_OPERAND0_RGB_ARB
+ #define GL_OPERAND1_RGB_EXT GL_OPERAND1_RGB_ARB
+ #define GL_OPERAND2_RGB_EXT GL_OPERAND2_RGB_ARB
+ #define GL_OPERAND0_ALPHA_EXT GL_OPERAND0_ALPHA_ARB
+ #define GL_OPERAND1_ALPHA_EXT GL_OPERAND1_ALPHA_ARB
+ #define GL_OPERAND2_ALPHA_EXT GL_OPERAND2_ALPHA_ARB
+ #endif
+#endif
+// Windows has a convention for typedef'ing pointers to OpenGL functions
+// which encapsulates some of the oddities of Win32 calling conventions.
+// Identical conventions are being established for Linux, but they are
+// not yet in place, and are not necessarily supported in other UNIX
+// variants. Therefore we need a similar mechanism that accomplishes
+// the same goal. We'll use the standard typedef names, but put them
+// in the GLEAN namespace; that should preserve as much source-code
+// compatibility as possible elsewhere in glean.
+
+namespace GLEAN {
+typedef void (GLAPIENTRY * PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);
+typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);
+typedef void (GLAPIENTRY * PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum types, GLvoid *values);
+typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (GLAPIENTRY * PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (GLAPIENTRY * PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);
+typedef void (GLAPIENTRY * PFNGLRESETMINMAXEXTPROC) (GLenum target);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);
+typedef void (GLAPIENTRY * PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum target, GLfloat value);
+typedef void (GLAPIENTRY * PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum target, const GLfloat *value);
+typedef void (GLAPIENTRY * PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum target, GLint value);
+typedef void (GLAPIENTRY * PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum target, const GLint *value);
+typedef void (GLAPIENTRY * PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum target, GLfloat *value);
+typedef void (GLAPIENTRY * PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum target, GLint *value);
+typedef void (GLAPIENTRY * PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);
+typedef void (GLAPIENTRY * PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);
+typedef void (GLAPIENTRY * PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);
+typedef void (GLAPIENTRY * PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+typedef GLboolean (GLAPIENTRY * PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);
+typedef GLboolean (GLAPIENTRY * PFNGLISTEXTUREEXTPROC) (GLuint texture);
+typedef void (GLAPIENTRY * PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (GLAPIENTRY * PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+typedef void (GLAPIENTRY * PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+typedef void (GLAPIENTRY * PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (GLAPIENTRY * PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);
+typedef void (GLAPIENTRY * PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);
+typedef void (GLAPIENTRY * PFNGLARRAYELEMENTEXTPROC) (GLint i);
+typedef void (GLAPIENTRY * PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (GLAPIENTRY * PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);
+typedef void (GLAPIENTRY * PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params);
+typedef void (GLAPIENTRY * PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);
+typedef void (GLAPIENTRY * PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (GLAPIENTRY * PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *param);
+typedef void (GLAPIENTRY * PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);
+typedef void (GLAPIENTRY * PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *param);
+typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);
+typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);
+typedef GLint (GLAPIENTRY * PFNGLGETINSTRUMENTSSGIXPROC) (void);
+typedef void (GLAPIENTRY * PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buf);
+typedef GLint (GLAPIENTRY * PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *markerp);
+typedef void (GLAPIENTRY * PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);
+typedef void (GLAPIENTRY * PFNGLSTARTINSTRUMENTSSGIXPROC) (void);
+typedef void (GLAPIENTRY * PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);
+typedef void (GLAPIENTRY * PFNGLFRAMEZOOMSGIXPROC) (GLint factor);
+typedef void (GLAPIENTRY * PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);
+typedef void (GLAPIENTRY * PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *plane);
+typedef void (GLAPIENTRY * PFNGLFLUSHRASTERSGIXPROC) (void);
+typedef void (GLAPIENTRY * PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLHINTPGIPROC) (GLenum target, GLint mode);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum name, GLfloat *param);
+typedef void (GLAPIENTRY * PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum name, GLint *param);
+typedef void (GLAPIENTRY * PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum name, GLfloat param);
+typedef void (GLAPIENTRY * PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum name, const GLfloat *param);
+typedef void (GLAPIENTRY * PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum name, GLint param);
+typedef void (GLAPIENTRY * PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum name, const GLint *param);
+typedef void (GLAPIENTRY * PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);
+typedef void (GLAPIENTRY * PFNGLINDEXFUNCEXTPROC) (GLenum func, GLfloat ref);
+typedef void (GLAPIENTRY * PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
+typedef void (GLAPIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
+typedef void (GLAPIENTRY * PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble* params);
+typedef void (GLAPIENTRY * PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat* params);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint * params);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint * params);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);
+typedef void (GLAPIENTRY * PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint * params);
+typedef void (GLAPIENTRY * PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint * params);
+typedef void (GLAPIENTRY * PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint * params);
+typedef void (GLAPIENTRY * PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);
+typedef void (GLAPIENTRY * PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
+typedef void (GLAPIENTRY * PFNGLFOGCOORDFVEXTPROC) (const GLfloat * coord);
+typedef void (GLAPIENTRY * PFNGLFOGCOORDDEXTPROC) (GLdouble coord);
+typedef void (GLAPIENTRY * PFNGLFOGCOORDDVEXTPROC) (const GLdouble * coord);
+typedef void (GLAPIENTRY * PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid * pointer);
+typedef void (GLAPIENTRY * PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (GLAPIENTRY * PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (GLAPIENTRY * PFNGLADDSWAPHINTRECTWINPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);
+typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);
+typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGENVPROC) (GLsizei size, const GLvoid * pointer);
+typedef void (GLAPIENTRY * PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);
+typedef void (GLAPIENTRY * PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint * params);
+typedef void (GLAPIENTRY * PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (GLAPIENTRY * PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (GLAPIENTRY * PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+typedef void (GLAPIENTRY * PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (GLAPIENTRY * PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint * params);
+typedef void (GLAPIENTRY * PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint * params);
+typedef void (GLAPIENTRY * PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat * params);
+typedef void (GLAPIENTRY * PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint * params);
+typedef void (GLAPIENTRY * PFNGLRESIZEBUFFERSMESAPROC) (void);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS2IVMESAPROC) (const GLint *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS3IVMESAPROC) (const GLint *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS4IVMESAPROC) (const GLint *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *p);
+typedef void (GLAPIENTRY * PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *p);
+typedef void (GLAPIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (GLAPIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (GLAPIENTRY * PFNGLLOADTRANSPOSEMATRIXDARBPROC) ( const GLdouble m[16] );
+typedef void (GLAPIENTRY * PFNGLLOADTRANSPOSEMATRIXFARBPROC) ( const GLfloat m[16] );
+typedef void (GLAPIENTRY * PFNGLMULTTRANSPOSEMATRIXDARBPROC) ( const GLdouble m[16] );
+typedef void (GLAPIENTRY * PFNGLMULTTRANSPOSEMATRIXFARBPROC) ( const GLfloat m[16] );
+typedef void (GLAPIENTRY * PFNGLSAMPLEPASSARBPROC) (GLenum pass);
+typedef void (GLAPIENTRY * PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert);
+
+// OpenGL 1.2 enumerants, to allow glean to be compiled on OpenGL 1.1 systems.
+// (This odd workaround is needed to handle problems with some copies of
+// glext.h that are floating around the net.)
+
+#ifndef GL_PACK_SKIP_IMAGES
+#define GL_PACK_SKIP_IMAGES 0x806B
+#endif
+#ifndef GL_PACK_IMAGE_HEIGHT
+#define GL_PACK_IMAGE_HEIGHT 0x806C
+#endif
+#ifndef GL_UNPACK_SKIP_IMAGES
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#endif
+#ifndef GL_UNPACK_IMAGE_HEIGHT
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#endif
+#ifndef GL_TEXTURE_3D
+#define GL_TEXTURE_3D 0x806F
+#endif
+#ifndef GL_PROXY_TEXTURE_3D
+#define GL_PROXY_TEXTURE_3D 0x8070
+#endif
+#ifndef GL_TEXTURE_DEPTH
+#define GL_TEXTURE_DEPTH 0x8071
+#endif
+#ifndef GL_TEXTURE_WRAP_R
+#define GL_TEXTURE_WRAP_R 0x8072
+#endif
+#ifndef GL_MAX_3D_TEXTURE_SIZE
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#endif
+#ifndef GL_TEXTURE_BINDING_3D
+#define GL_TEXTURE_BINDING_3D 0x806A
+#endif
+#ifndef GL_RESCALE_NORMAL
+#define GL_RESCALE_NORMAL 0x803A
+#endif
+#ifndef GL_CLAMP_TO_EDGE
+#define GL_CLAMP_TO_EDGE 0x812F
+#endif
+#ifndef GL_MAX_ELEMENTS_VERTICES
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#endif
+#ifndef GL_MAX_ELEMENTS_INDICES
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#endif
+#ifndef GL_BGR
+#define GL_BGR 0x80E0
+#endif
+#ifndef GL_BGRA
+#define GL_BGRA 0x80E1
+#endif
+#ifndef GL_UNSIGNED_BYTE_3_3_2
+#define GL_UNSIGNED_BYTE_3_3_2 0x8032
+#endif
+#ifndef GL_UNSIGNED_BYTE_2_3_3_REV
+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#endif
+#ifndef GL_UNSIGNED_SHORT_5_6_5
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#endif
+#ifndef GL_UNSIGNED_SHORT_5_6_5_REV
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#endif
+#ifndef GL_UNSIGNED_SHORT_4_4_4_4
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#endif
+#ifndef GL_UNSIGNED_SHORT_4_4_4_4_REV
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#endif
+#ifndef GL_UNSIGNED_SHORT_5_5_5_1
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#endif
+#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#endif
+#ifndef GL_UNSIGNED_INT_8_8_8_8
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#endif
+#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#endif
+#ifndef GL_UNSIGNED_INT_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#endif
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#endif
+#ifndef GL_LIGHT_MODEL_COLOR_CONTROL
+#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8
+#endif
+#ifndef GL_SINGLE_COLOR
+#define GL_SINGLE_COLOR 0x81F9
+#endif
+#ifndef GL_SEPARATE_SPECULAR_COLOR
+#define GL_SEPARATE_SPECULAR_COLOR 0x81FA
+#endif
+#ifndef GL_TEXTURE_MIN_LOD
+#define GL_TEXTURE_MIN_LOD 0x813A
+#endif
+#ifndef GL_TEXTURE_MAX_LOD
+#define GL_TEXTURE_MAX_LOD 0x813B
+#endif
+#ifndef GL_TEXTURE_BASE_LEVEL
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#endif
+#ifndef GL_TEXTURE_MAX_LEVEL
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#endif
+#ifndef GL_SMOOTH_POINT_SIZE_RANGE
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#endif
+#ifndef GL_SMOOTH_POINT_SIZE_GRANULARITY
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
+#endif
+#ifndef GL_SMOOTH_LINE_WIDTH_RANGE
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#endif
+#ifndef GL_SMOOTH_LINE_WIDTH_GRANULARITY
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
+#endif
+#ifndef GL_ALIASED_POINT_SIZE_RANGE
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#endif
+#ifndef GL_ALIASED_LINE_WIDTH_RANGE
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#endif
+#ifndef GL_COLOR_TABLE
+#define GL_COLOR_TABLE 0x80D0
+#endif
+#ifndef GL_POST_CONVOLUTION_COLOR_TABLE
+#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1
+#endif
+#ifndef GL_POST_COLOR_MATRIX_COLOR_TABLE
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2
+#endif
+#ifndef GL_PROXY_COLOR_TABLE
+#define GL_PROXY_COLOR_TABLE 0x80D3
+#endif
+#ifndef GL_PROXY_POST_CONVOLUTION_COLOR_TABLE
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
+#endif
+#ifndef GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#endif
+#ifndef GL_COLOR_TABLE_SCALE
+#define GL_COLOR_TABLE_SCALE 0x80D6
+#endif
+#ifndef GL_COLOR_TABLE_BIAS
+#define GL_COLOR_TABLE_BIAS 0x80D7
+#endif
+#ifndef GL_COLOR_TABLE_FORMAT
+#define GL_COLOR_TABLE_FORMAT 0x80D8
+#endif
+#ifndef GL_COLOR_TABLE_WIDTH
+#define GL_COLOR_TABLE_WIDTH 0x80D9
+#endif
+#ifndef GL_COLOR_TABLE_RED_SIZE
+#define GL_COLOR_TABLE_RED_SIZE 0x80DA
+#endif
+#ifndef GL_COLOR_TABLE_GREEN_SIZE
+#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB
+#endif
+#ifndef GL_COLOR_TABLE_BLUE_SIZE
+#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC
+#endif
+#ifndef GL_COLOR_TABLE_ALPHA_SIZE
+#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD
+#endif
+#ifndef GL_COLOR_TABLE_LUMINANCE_SIZE
+#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE
+#endif
+#ifndef GL_COLOR_TABLE_INTENSITY_SIZE
+#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF
+#endif
+#ifndef GL_CONVOLUTION_1D
+#define GL_CONVOLUTION_1D 0x8010
+#endif
+#ifndef GL_CONVOLUTION_2D
+#define GL_CONVOLUTION_2D 0x8011
+#endif
+#ifndef GL_SEPARABLE_2D
+#define GL_SEPARABLE_2D 0x8012
+#endif
+#ifndef GL_CONVOLUTION_BORDER_MODE
+#define GL_CONVOLUTION_BORDER_MODE 0x8013
+#endif
+#ifndef GL_CONVOLUTION_FILTER_SCALE
+#define GL_CONVOLUTION_FILTER_SCALE 0x8014
+#endif
+#ifndef GL_CONVOLUTION_FILTER_BIAS
+#define GL_CONVOLUTION_FILTER_BIAS 0x8015
+#endif
+#ifndef GL_REDUCE
+#define GL_REDUCE 0x8016
+#endif
+#ifndef GL_CONVOLUTION_FORMAT
+#define GL_CONVOLUTION_FORMAT 0x8017
+#endif
+#ifndef GL_CONVOLUTION_WIDTH
+#define GL_CONVOLUTION_WIDTH 0x8018
+#endif
+#ifndef GL_CONVOLUTION_HEIGHT
+#define GL_CONVOLUTION_HEIGHT 0x8019
+#endif
+#ifndef GL_MAX_CONVOLUTION_WIDTH
+#define GL_MAX_CONVOLUTION_WIDTH 0x801A
+#endif
+#ifndef GL_MAX_CONVOLUTION_HEIGHT
+#define GL_MAX_CONVOLUTION_HEIGHT 0x801B
+#endif
+#ifndef GL_POST_CONVOLUTION_RED_SCALE
+#define GL_POST_CONVOLUTION_RED_SCALE 0x801C
+#endif
+#ifndef GL_POST_CONVOLUTION_GREEN_SCALE
+#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D
+#endif
+#ifndef GL_POST_CONVOLUTION_BLUE_SCALE
+#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E
+#endif
+#ifndef GL_POST_CONVOLUTION_ALPHA_SCALE
+#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F
+#endif
+#ifndef GL_POST_CONVOLUTION_RED_BIAS
+#define GL_POST_CONVOLUTION_RED_BIAS 0x8020
+#endif
+#ifndef GL_POST_CONVOLUTION_GREEN_BIAS
+#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021
+#endif
+#ifndef GL_POST_CONVOLUTION_BLUE_BIAS
+#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022
+#endif
+#ifndef GL_POST_CONVOLUTION_ALPHA_BIAS
+#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023
+#endif
+#ifndef GL_CONSTANT_BORDER
+#define GL_CONSTANT_BORDER 0x8151
+#endif
+#ifndef GL_REPLICATE_BORDER
+#define GL_REPLICATE_BORDER 0x8153
+#endif
+#ifndef GL_CONVOLUTION_BORDER_COLOR
+#define GL_CONVOLUTION_BORDER_COLOR 0x8154
+#endif
+#ifndef GL_COLOR_MATRIX
+#define GL_COLOR_MATRIX 0x80B1
+#endif
+#ifndef GL_COLOR_MATRIX_STACK_DEPTH
+#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2
+#endif
+#ifndef GL_MAX_COLOR_MATRIX_STACK_DEPTH
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3
+#endif
+#ifndef GL_POST_COLOR_MATRIX_RED_SCALE
+#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4
+#endif
+#ifndef GL_POST_COLOR_MATRIX_GREEN_SCALE
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5
+#endif
+#ifndef GL_POST_COLOR_MATRIX_BLUE_SCALE
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6
+#endif
+#ifndef GL_POST_COLOR_MATRIX_ALPHA_SCALE
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7
+#endif
+#ifndef GL_POST_COLOR_MATRIX_RED_BIAS
+#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8
+#endif
+#ifndef GL_POST_COLOR_MATRIX_GREEN_BIAS
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9
+#endif
+#ifndef GL_POST_COLOR_MATRIX_BLUE_BIAS
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA
+#endif
+#ifndef GL_POST_COLOR_MATRIX_ALPHA_BIAS
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB
+#endif
+#ifndef GL_HISTOGRAM
+#define GL_HISTOGRAM 0x8024
+#endif
+#ifndef GL_PROXY_HISTOGRAM
+#define GL_PROXY_HISTOGRAM 0x8025
+#endif
+#ifndef GL_HISTOGRAM_WIDTH
+#define GL_HISTOGRAM_WIDTH 0x8026
+#endif
+#ifndef GL_HISTOGRAM_FORMAT
+#define GL_HISTOGRAM_FORMAT 0x8027
+#endif
+#ifndef GL_HISTOGRAM_RED_SIZE
+#define GL_HISTOGRAM_RED_SIZE 0x8028
+#endif
+#ifndef GL_HISTOGRAM_GREEN_SIZE
+#define GL_HISTOGRAM_GREEN_SIZE 0x8029
+#endif
+#ifndef GL_HISTOGRAM_BLUE_SIZE
+#define GL_HISTOGRAM_BLUE_SIZE 0x802A
+#endif
+#ifndef GL_HISTOGRAM_ALPHA_SIZE
+#define GL_HISTOGRAM_ALPHA_SIZE 0x802B
+#endif
+#ifndef GL_HISTOGRAM_LUMINANCE_SIZE
+#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C
+#endif
+#ifndef GL_HISTOGRAM_SINK
+#define GL_HISTOGRAM_SINK 0x802D
+#endif
+#ifndef GL_MINMAX
+#define GL_MINMAX 0x802E
+#endif
+#ifndef GL_MINMAX_FORMAT
+#define GL_MINMAX_FORMAT 0x802F
+#endif
+#ifndef GL_MINMAX_SINK
+#define GL_MINMAX_SINK 0x8030
+#endif
+#ifndef GL_TABLE_TOO_LARGE
+#define GL_TABLE_TOO_LARGE 0x8031
+#endif
+#ifndef GL_BLEND_EQUATION
+#define GL_BLEND_EQUATION 0x8009
+#endif
+#ifndef GL_MIN
+#define GL_MIN 0x8007
+#endif
+#ifndef GL_MAX
+#define GL_MAX 0x8008
+#endif
+#ifndef GL_FUNC_ADD
+#define GL_FUNC_ADD 0x8006
+#endif
+#ifndef GL_FUNC_SUBTRACT
+#define GL_FUNC_SUBTRACT 0x800A
+#endif
+#ifndef GL_FUNC_REVERSE_SUBTRACT
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#endif
+#ifndef GL_BLEND_COLOR
+#define GL_BLEND_COLOR 0x8005
+#endif
+
+// Extension enumerants, in case they're not defined in glext.h.
+
+#ifndef GL_DOT3_RGB_EXT
+#define GL_DOT3_RGB_EXT 0x8740
+#endif
+#ifndef GL_DOT3_RGBA_EXT
+#define GL_DOT3_RGBA_EXT 0x8741
+#endif
+#ifndef GL_DOT3_RGB_ARB
+#define GL_DOT3_RGB_ARB 0x86AE
+#endif
+#ifndef GL_DOT3_RGBA_ARB
+#define GL_DOT3_RGBA_ARB 0x86AF
+#endif
+
+
+#ifndef GL_VERSION_1_2
+// OpenGL 1.2 function pointer types, to allow glean to
+// be compiled on OpenGL 1.1 systems.
+typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode);
+typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void (GLAPIENTRY * PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (GLAPIENTRY * PFNGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (GLAPIENTRY * PFNGLRESETMINMAXPROC) (GLenum target);
+typedef void (GLAPIENTRY * PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum types, GLvoid *values);
+typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (GLAPIENTRY * PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (GLAPIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (GLAPIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+#endif
+} // namespace GLEAN
+
+
+#endif // __glwrap_h__
diff --git a/tests/glean/image.h b/tests/glean/image.h
new file mode 100644
index 00000000..83942f4f
--- /dev/null
+++ b/tests/glean/image.h
@@ -0,0 +1,250 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// image.h: image data and attributes, image I/O
+
+// This class encapsulates OpenGL information related to images (size,
+// format, etc.) and provides utilities for transferring images to and
+// from files.
+
+
+#ifndef __image_h__
+#define __image_h__
+
+#include <string>
+#include "glwrap.h"
+#include "stats.h"
+
+namespace GLEAN {
+
+class Image {
+
+ private:
+
+ GLsizei _width;
+ GLsizei _height;
+ GLenum _format;
+ GLenum _type;
+ char* _pixels;
+ GLsizei _alignment;
+ GLsizei _rowSizeInBytes;
+ GLsizei _pixelSizeInBytes;
+
+ enum { // validation bits, for lazy validation
+ vbRowSizeInBytes = 1,
+ vbPixelSizeInBytes = 2,
+ vbPacker = 4,
+ vbUnpacker = 8,
+ vbAll = ~0
+ };
+ int _invalid;
+ inline bool invalid(int bit) const { return _invalid & bit; }
+ inline bool valid(int bit) const { return !invalid(bit); }
+ inline void invalidate(int bits) { _invalid |= bits; }
+ inline void validate(int bits) { _invalid &= ~bits; }
+
+ GLsizei validateRowSizeInBytes();
+ GLsizei validatePixelSizeInBytes();
+
+ typedef void Unpacker(GLsizei n, double* rgba, char* nextPixel);
+ Unpacker* _unpacker;
+ Unpacker* validateUnpacker();
+ typedef void Packer(GLsizei n, char* nextPixel, double* rgba);
+ Packer* _packer;
+ Packer* validatePacker();
+
+ // For now, we will require that:
+ // 1. All images are in native byte order (so that byte swapping
+ // at the OpenGL level is unnecessary).
+ // 2. The image width and height above describe the entire image
+ // (so that there is no need to specify row length
+ // independently).
+ // 3. We have no need to specify subimages at this level (so
+ // there is no need for SKIP_ROWS and SKIP_PIXELS attributes).
+
+ // Should construction fix the format and type for all time?
+ // That would eliminate synchronization problems between data and
+ // descriptive information that might arise when an Image is reused,
+ // and might permit use of template functions instead of lots of
+ // switches. Probably not; it would make dynamic type assignment
+ // (such as reading a TIFF file) quite awkward.
+
+ public:
+
+ // Exceptions:
+
+ struct Error { }; // Base class for all image errors.
+ struct BadFormat: public Error { // Bad image format.
+ GLenum format;
+ BadFormat(GLenum f) {format = f;}
+ };
+ struct BadType: public Error { // Bad image type.
+ GLenum type;
+ BadType(GLenum t) {type = t;}
+ };
+ struct CantOpen: public Error { // Can't open file.
+ const char* filename;
+ CantOpen(const char* p) {filename = p;}
+ };
+ struct UnsupportedTIFF: public Error { // TIFF we can't handle.
+ };
+ struct RefImageTooLarge: public Error { // Can't register ref image.
+ };
+
+ // Constructors/Destructor:
+
+ Image();
+ Image(int aWidth, int aHeight, GLenum aFormat, GLenum aType);
+ Image(int aWidth, int aHeight, GLenum aFormat, GLenum aType,
+ double r, double g, double b, double a);
+ Image(Image& i);
+ Image& operator= (Image& i);
+ ~Image();
+
+ // Reserve space for the pixel array:
+
+ void reserve();
+
+ // Get/Set attributes. These attributes are useful for calls
+ // to glDrawPixels, glTexImage2D, etc. Note the alignment
+ // value; passing it to glPixelStore is essential before using
+ // one of the other OpenGL commands.
+
+ inline GLsizei width() const // Image width, in pixels
+ { return _width; }
+ inline void width(GLsizei w)
+ { _width = w; invalidate(vbRowSizeInBytes); }
+
+ inline GLsizei height() const // Image height, in pixels.
+ { return _height; }
+ inline void height(GLsizei h)
+ { _height = h; }
+
+ inline GLenum format() const // Image format. Currently
+ { return _format; } // these formats are supported:
+ // GL_LUMINANCE,
+ // GL_LUMINANCE_ALPHA,
+ // GL_RGB, GL_RGBA.
+ // It may be easiest to treat
+ // stencil, depth, etc. images
+ // as luminance images.
+ inline void format(GLenum f) {
+ _format = f;
+ invalidate(
+ vbRowSizeInBytes
+ | vbPixelSizeInBytes
+ | vbPacker
+ | vbUnpacker);
+ }
+
+ inline GLenum type() const // Pixel data type. Currently
+ { return _type; } // these types are supported:
+ // GL_BYTE, GL_UNSIGNED_BYTE,
+ // GL_SHORT, GL_UNSIGNED_SHORT,
+ // GL_INT, GL_UNSIGNED_INT, GL_FLOAT.
+ inline void type(GLenum t) {
+ _type = t;
+ invalidate(
+ vbRowSizeInBytes
+ | vbPixelSizeInBytes
+ | vbPacker
+ | vbUnpacker);
+ }
+
+ inline char* pixels() // The pixels.
+ { return _pixels; }
+ inline const char* pixels() const
+ { return const_cast<const char*>(_pixels); }
+ void pixels(char* p);
+
+ inline GLsizei alignment() const // Alignment. See glPixelStore.
+ { return _alignment; }
+ inline void alignment(GLsizei a)
+ { _alignment = a; invalidate(vbRowSizeInBytes); }
+
+ inline GLsizei rowSizeInBytes() { // Size of scanline, in bytes
+ return valid(vbRowSizeInBytes)?
+ _rowSizeInBytes: validateRowSizeInBytes();
+ }
+
+ inline GLsizei pixelSizeInBytes() { // Size of pixel, in bytes
+ return valid(vbPixelSizeInBytes)?
+ _pixelSizeInBytes: validatePixelSizeInBytes();
+ }
+
+ // XXX Utilities to determine component size in bits/bytes?
+ // XXX Component range (min neg, max neg, min pos, max pos, eps?)
+
+ // Pixel packing/unpacking utilities:
+
+ void unpack(GLsizei n, double* rgba, char* nextPixel);
+ void pack(GLsizei n, char* nextPixel, double* rgba);
+ // XXX get(x, y, double* rgba);
+ // XXX put(x, y, double* rgba);
+
+ // Image registration. The utility compares a reference image
+ // to the current image (which must be at least as large as the
+ // reference image in both dimensions), determines the offset at
+ // which the reference image minus the current image has minimum
+ // mean absolute error (summed over R, G, B, and A), and returns
+ // an object specifying the offset and corresponding statistics.
+
+ struct Registration {
+ int wOffset; // offset in width (x)
+ int hOffset; // offset in height (y)
+ BasicStats stats[4]; // stats for absolute error in
+ // R, G, B, and A
+ };
+ Registration reg(Image& ref);
+
+ // Image arithmetic
+ // XXX type and format conversions, with appropriate scaling.
+ // XXX image difference
+ // XXX minmax, histogram, contrast stretch?
+
+ // TIFF I/O utilities:
+
+ void readTIFF(const char* filename);
+ inline void readTIFF(const std::string& s) { readTIFF(s.c_str()); }
+ void writeTIFF(const char* filename);
+ inline void writeTIFF(const std::string& s) { writeTIFF(s.c_str()); }
+
+ // GL operation utilities:
+
+ void draw(); // Invoke glDrawPixels.
+ void read(GLint x, GLint y); // Invoke glReadPixels.
+ void makeMipmaps(GLenum intFormat); // Load texture mipmaps.
+
+}; // class Image
+
+} // namespace GLEAN
+
+#endif // __image_h__
diff --git a/tests/glean/image_misc.cpp b/tests/glean/image_misc.cpp
new file mode 100644
index 00000000..adfdc224
--- /dev/null
+++ b/tests/glean/image_misc.cpp
@@ -0,0 +1,210 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// Implementation of image data, attribute, and I/O
+
+#include "image.h"
+#include <string.h>
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/Destructor
+///////////////////////////////////////////////////////////////////////////////
+// An empty image:
+Image::Image() {
+ _width = _height = 0;
+ _format = GL_RGB;
+ _type = GL_UNSIGNED_BYTE;
+ _pixels = 0;
+ _alignment = 4;
+ _packer = 0;
+ _unpacker = 0;
+ _invalid = vbAll;
+} // Image::Image
+
+// An unitialized image of the given type and size:
+Image::Image(int aWidth, int aHeight, GLenum aFormat, GLenum aType) {
+ _width = aWidth;
+ _height = aHeight;
+ _format = aFormat;
+ _type = aType;
+ _pixels = 0;
+ _alignment = 4;
+ _packer = 0;
+ _unpacker = 0;
+ _invalid = vbAll;
+ reserve();
+} // Image::Image(aWidth, aHeight, aFormat, aType)
+
+// An image of the given type and size, initialized to a solid color:
+Image::Image(int aWidth, int aHeight, GLenum aFormat, GLenum aType,
+ double r, double g, double b, double a) {
+ _width = aWidth;
+ _height = aHeight;
+ _format = aFormat;
+ _type = aType;
+ _pixels = 0;
+ _alignment = 4;
+ _packer = 0;
+ _unpacker = 0;
+ _invalid = vbAll;
+ reserve();
+ int i; // VC++ 6 doesn't handle the definition of variables in a
+ // for-statement properly
+
+ double* solidColor = new double[4 * width()];
+ for (/*int */i = 0; i < 4 * width(); i += 4) {
+ solidColor[i + 0] = r;
+ solidColor[i + 1] = g;
+ solidColor[i + 2] = b;
+ solidColor[i + 3] = a;
+ }
+
+ char* row = pixels();
+ for (/*int */i = 0; i < height(); ++i) {
+ pack(width(), row, solidColor);
+ row += rowSizeInBytes();
+ }
+} // Image::Image(aWidth, aHeight, aFormat, aType)
+
+// Copy constructor:
+Image::Image(Image& i) {
+ _width = i.width();
+ _height = i.height();
+ _format = i.format();
+ _type = i.type();
+ _alignment = i.alignment();
+ _pixels = 0;
+ _packer = 0;
+ _unpacker = 0;
+ _invalid = vbAll;
+ reserve();
+ memcpy(pixels(), i.pixels(), height() * rowSizeInBytes());
+} // Image::Image(Image&)
+
+/*Image::*/Image&
+Image::operator= (Image& i) {
+ if (this == &i)
+ return *this;
+ width(i.width());
+ height(i.height());
+ format(i.format());
+ type(i.type());
+ alignment(i.alignment());
+ _invalid = vbAll;
+ reserve();
+ memcpy(pixels(), i.pixels(), height() * rowSizeInBytes());
+ return *this;
+} // Image::operator=
+
+Image::~Image() {
+ if (_pixels)
+ delete[] _pixels;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// pixels - set pointer to pixel array
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::pixels(char* p) {
+ // We always own our pixels, so delete the old ones (if any) before
+ // installing new ones:
+ if (_pixels)
+ delete[] _pixels;
+ _pixels = p;
+} // Image::pixels
+
+///////////////////////////////////////////////////////////////////////////////
+// reserve - reserve memory for image (assuming current type, format, and size)
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::reserve() {
+ pixels(0); // deallocate old pixel array
+ pixels(new char[height() * rowSizeInBytes()]);
+} // Image::reserve
+
+///////////////////////////////////////////////////////////////////////////////
+// validateRowSizeInBytes - compute image row size, measured in bytes
+///////////////////////////////////////////////////////////////////////////////
+GLsizei
+Image::validateRowSizeInBytes() {
+ _rowSizeInBytes =
+ (width() * pixelSizeInBytes() + alignment() - 1)
+ & ~(alignment() - 1);
+ validate(vbRowSizeInBytes);
+ return _rowSizeInBytes;
+} // Image::calcRowSizeInBytes
+
+///////////////////////////////////////////////////////////////////////////////
+// validatePixelSizeInBytes - compute pixel size, measured in bytes
+///////////////////////////////////////////////////////////////////////////////
+GLsizei
+Image::validatePixelSizeInBytes() {
+ switch (format()) {
+ case GL_LUMINANCE:
+ _pixelSizeInBytes = 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ _pixelSizeInBytes = 2;
+ break;
+ case GL_RGB:
+ _pixelSizeInBytes = 3;
+ break;
+ case GL_RGBA:
+ _pixelSizeInBytes = 4;
+ break;
+ default:
+ throw BadFormat(format());
+ }
+
+ switch (type()) {
+ case GL_BYTE:
+ case GL_UNSIGNED_BYTE:
+ break;
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT:
+ _pixelSizeInBytes <<= 1;
+ break;
+ case GL_INT:
+ case GL_UNSIGNED_INT:
+ case GL_FLOAT:
+ _pixelSizeInBytes <<= 2;
+ break;
+ default:
+ throw BadType(type());
+ }
+
+ validate(vbPixelSizeInBytes);
+ return _pixelSizeInBytes;
+}
+
+}; // namespace GLEAN
diff --git a/tests/glean/lex.cpp b/tests/glean/lex.cpp
new file mode 100644
index 00000000..84891f14
--- /dev/null
+++ b/tests/glean/lex.cpp
@@ -0,0 +1,167 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// lex.cpp: Implementation of simple lexical analyzer
+
+#include <ctype.h>
+#include <stdlib.h>
+#include "lex.h"
+
+namespace GLEAN {
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor:
+///////////////////////////////////////////////////////////////////////////////
+Lex::Lex(const char* s, bool ignoreCase/* = false */) {
+ input = s;
+ p = input;
+ ignoringCase = ignoreCase;
+} // Lex::Lex
+
+///////////////////////////////////////////////////////////////////////////////
+// next - Fetch next token from the input string
+///////////////////////////////////////////////////////////////////////////////
+void
+Lex::next() {
+ while (isspace(*p))
+ ++p;
+
+ if (isalpha(*p) || *p == '_') {
+ id = "";
+ if (ignoringCase)
+ while (isalnum(*p) || *p == '_')
+ id += tolower(*p++);
+ else
+ while (isalnum(*p) || *p == '_')
+ id += *p++;
+ token = ID;
+ return;
+ }
+
+ if (isdigit(*p)) {
+ iValue = strtol(p, const_cast<char**>(&p), 0);
+ token = ICONST;
+ return;
+ }
+
+ char nextC = 0;
+ char c = *p++;
+ if (c)
+ nextC = *p;
+ switch (c) {
+ case '|':
+ if (nextC == '|') {
+ ++p;
+ token = OR_OR;
+ }
+ else
+ token = OR;
+ break;
+ case '&':
+ if (nextC == '&') {
+ ++p;
+ token = AND_AND;
+ }
+ else
+ token = AND;
+ break;
+ case '<':
+ if (nextC == '=') {
+ ++p;
+ token = LE;
+ }
+ else
+ token = LT;
+ break;
+ case '>':
+ if (nextC == '=') {
+ ++p;
+ token = GE;
+ }
+ else
+ token = GT;
+ break;
+ case '=':
+ if (nextC == '=') {
+ ++p;
+ token = EQ;
+ }
+ else
+ token = ASSIGN;
+ break;
+ case '!':
+ if (nextC == '=') {
+ ++p;
+ token = NE;
+ }
+ else
+ token = BANG;
+ break;
+ case '+':
+ token = PLUS;
+ break;
+ case '-':
+ token = MINUS;
+ break;
+ case '*':
+ token = STAR;
+ break;
+ case '/':
+ token = SLASH;
+ break;
+ case '%':
+ token = PERCENT;
+ break;
+ case ',':
+ token = COMMA;
+ break;
+ case '(':
+ token = LPAREN;
+ break;
+ case ')':
+ token = RPAREN;
+ break;
+ case '.':
+ token = DOT;
+ break;
+ case '\0':
+ token = END;
+ --p; // push back '\0' so that token will always be END
+ break;
+ default:
+ throw Lexical("unrecognized symbol", p - input);
+ }
+
+ return;
+} // Lex::next
+
+} // namespace GLEAN
diff --git a/tests/glean/lex.h b/tests/glean/lex.h
new file mode 100644
index 00000000..87e24dfc
--- /dev/null
+++ b/tests/glean/lex.h
@@ -0,0 +1,128 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// lex.h: Simple lexical analysis utilities
+
+// Given a string containing C-style tokens, returns information about
+// successive tokens. Doesn't support all C tokens; just the few that
+// GLEAN needs.
+
+
+#ifndef __lex_h__
+#define __lex_h__
+
+#include <string>
+
+#ifdef __WIN__
+// ERROR is already defined in some windows header file
+#undef ERROR
+#endif
+
+namespace GLEAN {
+
+class Lex {
+ protected:
+
+ // State information:
+ const char* input;
+ const char* p;
+ bool ignoringCase;
+
+ public:
+
+ // Constructors:
+
+ Lex(const char* s, bool ignoreCase = false);
+ // Creates a lexer which will draw input from the given string.
+
+ // Exceptions:
+
+ struct Error { }; // Base class for errors.
+ struct Lexical: public Error { // Lexical error in string.
+ const char* err;
+ int position;
+ Lexical(const char* e, int p) {
+ err = e;
+ position = p;
+ }
+ };
+ struct InternalError: public Error { // Shouldn't happen.
+ };
+
+ // Tokens:
+
+ typedef enum {
+ ERROR = 0, // erroneous token; must be zero
+ END, // end of input
+
+ AND, // &
+ AND_AND, // &&
+ ASSIGN, // =
+ BANG, // !
+ COMMA, // ,
+ DOT, // .
+ EQ, // ==
+ GE, // >=
+ GT, // >
+ LE, // <=
+ LPAREN, // (
+ LT, // <
+ MINUS, // -
+ NE, // !=
+ OR, // |
+ OR_OR, // ||
+ PERCENT, // %
+ PLUS, // +
+ RPAREN, // )
+ SLASH, // /
+ STAR, // *
+
+ ICONST, // signed integer constant
+
+ ID // identifier
+ } Token;
+
+ // Utilities:
+
+ void next(); // fetch next token
+
+ Token token; // current token
+ std::string id; // most recent identifier
+ int iValue; // most recent signed integer value
+
+ inline int position() { // current position in input string
+ return p - input;
+ }
+}; // class Lex
+
+} // namespace GLEAN
+
+#endif // __lex_h__
diff --git a/tests/glean/main.cpp b/tests/glean/main.cpp
new file mode 100644
index 00000000..c40b5db5
--- /dev/null
+++ b/tests/glean/main.cpp
@@ -0,0 +1,347 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// main.cpp: main program for Glean
+
+using namespace std;
+
+#include <cassert>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include "options.h"
+#include "environ.h"
+#include "test.h"
+#include "version.h"
+#include "lex.h"
+#include "dsfilt.h"
+
+using namespace GLEAN;
+
+char* mandatoryArg(int argc, char* argv[], int i);
+void selectTests(Options& o, vector<string>& allTestNames, int argc,
+ char* argv[], int i);
+void usage(char* command);
+void listTests(const Test *tests, bool verbose);
+
+int
+main(int argc, char* argv[]) {
+
+ // Until someone gets around to writing a fancy GUI front-end,
+ // we'll set options the old-fashioned way.
+ Options o;
+
+ vector<string> allTestNames;
+ for (Test* t = Test::testList; t; t = t->nextTest)
+ allTestNames.push_back(t->name);
+ sort(allTestNames.begin(), allTestNames.end());
+ o.selectedTests = allTestNames;
+
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "--help")) {
+ usage(argv[0]);
+ } else if (!strcmp(argv[i], "-v")
+ || !strcmp(argv[i], "--verbose")) {
+ ++o.verbosity;
+ } else if (!strcmp(argv[i], "-r")
+ || !strcmp(argv[i], "--run")) {
+ o.mode = Options::run;
+ ++i;
+ o.db1Name = mandatoryArg(argc, argv, i);
+ } else if (!strcmp(argv[i], "-o")
+ || !strcmp(argv[i], "--overwrite")) {
+ o.overwrite = true;
+ } else if (!strcmp(argv[i], "--ignore-prereqs")) {
+ o.ignorePrereqs = true;
+ } else if (!strcmp(argv[i], "-c")
+ || !strcmp(argv[i], "--compare")) {
+ o.mode = Options::compare;
+ ++i;
+ o.db1Name = mandatoryArg(argc, argv, i);
+ ++i;
+ o.db2Name = mandatoryArg(argc, argv, i);
+ } else if (!strcmp(argv[i], "--visuals")) {
+ ++i;
+ o.visFilter = mandatoryArg(argc, argv, i);
+ } else if (!strcmp(argv[i], "-t")
+ || !strcmp(argv[i], "--tests")) {
+ ++i;
+ selectTests(o, allTestNames, argc, argv, i);
+ } else if (!strcmp(argv[i], "--listtests")) {
+ o.mode = Options::listtests;
+ } else if (!strcmp(argv[i], "--listdetails")) {
+ o.mode = Options::listdetails;
+# if defined(__X11__)
+ } else if (!strcmp(argv[i], "-display")
+ || !strcmp(argv[i], "--display")) {
+ ++i;
+ o.dpyName = mandatoryArg(argc, argv, i);
+# endif
+ } else {
+ usage(argv[0]);
+ }
+ }
+
+ if (o.mode == Options::notSet)
+ usage(argv[0]);
+
+ if (o.mode == Options::listtests) {
+ listTests(Test::testList, o.verbosity);
+ exit(0);
+ }
+
+ // Create the test environment, then invoke each test to generate
+ // results or compare two previous runs.
+ try {
+ Environment e(o);
+ switch (o.mode) {
+ case Options::run:
+ {
+ for (Test* t = Test::testList; t; t = t->nextTest)
+ if (binary_search(o.selectedTests.begin(),
+ o.selectedTests.end(), t->name))
+ t->run(e);
+ break;
+ }
+ case Options::compare:
+ {
+ for (Test* t = Test::testList; t; t = t->nextTest)
+ if (binary_search(o.selectedTests.begin(),
+ o.selectedTests.end(), t->name))
+ try {
+ t->compare(e);
+ }
+ catch (Test::CantOpenResultsFile e) {
+ // For comparisons, we want to
+ // continue running even if a
+ // test result file can't be
+ // opened. We report the
+ // problem here, but don't exit
+ // as we would in the catch{}
+ // below.
+ cerr << "Can't open results file for test "
+ << e.testName
+ << " in database "
+ << e.dbName
+ << '\n';
+ }
+ break;
+ }
+ case Options::listdetails:
+ {
+ for (Test* t = Test::testList; t; t = t->nextTest)
+ if (binary_search(o.selectedTests.begin(),
+ o.selectedTests.end(), t->name))
+ t->details(e);
+ break;
+ }
+ default:
+ cerr << "Bad run mode in main()\n";
+ break;
+ }
+ }
+#if defined(__X11__)
+ catch (WindowSystem::CantOpenDisplay) {
+ cerr << "can't open display " << o.dpyName << "\n";
+ exit(1);
+ }
+#endif
+ catch (WindowSystem::NoOpenGL) {
+ cerr << "display doesn't support OpenGL\n";
+ exit(1);
+ }
+ catch (DrawingSurfaceFilter::Syntax e) {
+ cerr << "Syntax error in visual selection criteria:\n"
+ "'" << o.visFilter << "'\n";
+ for (int i = 0; i < e.position; ++i)
+ cerr << ' ';
+ cerr << "^ " << e.err << '\n';
+ exit(1);
+ }
+ catch (Environment::DBExists) {
+ cerr << "Won't overwrite existing database " << o.db1Name
+ << "\n";
+ exit(1);
+ }
+ catch (Environment::DBCantOpen e) {
+ cerr << "Can't open database directory " << *e.db << "\n";
+ exit(1);
+ }
+ catch (Test::CantOpenResultsFile e) {
+ cerr << "Can't open results file for test " << e.testName
+ << " in database " << e.dbName << '\n';
+ exit(1);
+ }
+ catch (...) {
+ cerr << "caught an unexpected error in main()\n";
+ exit(1);
+ }
+
+ return 0;
+} // main
+
+
+char*
+mandatoryArg(int argc, char* argv[], int i) {
+ if (i < argc && argv[i][0] != '-')
+ return argv[i];
+ usage(argv[0]);
+ /*NOTREACHED*/
+ return 0;
+} // mandatoryArg
+
+
+void
+selectTests(Options& o, vector<string>& allTestNames, int argc, char* argv[],
+ int i) {
+ if (i >= argc)
+ usage(argv[0]);
+
+ // At present, we deal with the following syntax:
+ // [+] testname {(+|-) testname}
+ // Assume we're running none of the tests, then include
+ // those preceded by "+" and exclude those preceded by
+ // "-".
+ // - testname {(+|-) testname}
+ // Assume we're running all of the tests, then exclude
+ // those preceded by "-" and include those preceded by
+ // "+".
+ // XXX It would be nice to support the syntax "@filename" to mean
+ // "the list of tests given in the named file." This could be
+ // preceded by "+" or "-" just like an ordinary test name, or maybe
+ // the +/- should be required in the file itself.
+
+ struct SyntaxError {
+ int position;
+ SyntaxError(int pos): position(pos) { }
+ };
+
+ Lex lex(argv[i]);
+ try {
+ lex.next();
+ if (lex.token == Lex::MINUS)
+ o.selectedTests = allTestNames;
+ else
+ o.selectedTests.resize(0);
+
+ while (lex.token != Lex::END) {
+ bool inserting = true;
+ if (lex.token == Lex::MINUS) {
+ inserting = false;
+ lex.next();
+ } else if (lex.token == Lex::PLUS)
+ lex.next();
+
+ if (lex.token != Lex::ID)
+ throw SyntaxError(lex.position());
+
+ if (!binary_search(allTestNames.begin(),
+ allTestNames.end(), lex.id))
+ cerr << "Warning: " << lex.id << " ignored;"
+ " not a valid test name.\n";
+ else {
+ vector<string>::iterator p =
+ lower_bound(o.selectedTests.begin(),
+ o.selectedTests.end(), lex.id);
+ if (inserting) {
+ if (p == o.selectedTests.end()
+ || *p != lex.id)
+ o.selectedTests.insert(p,
+ lex.id);
+ } else {
+ // removing
+ if (p != o.selectedTests.end()
+ && *p == lex.id)
+ o.selectedTests.erase(p);
+ }
+ }
+ lex.next();
+ }
+ }
+ catch (Lex::Lexical e) {
+ cerr << "Lexical error in test inclusion/exclusion list:\n"
+ "'" << argv[i] << "'\n";
+ for (int i = 0; i < e.position; ++i)
+ cerr << ' ';
+ cerr << "^ " << e.err << "\n\n";
+ usage(argv[0]);
+ }
+ catch (SyntaxError e) {
+ cerr << "'" << argv[i] << "'\n";
+ for (int i = 0; i < e.position; ++i)
+ cerr << ' ';
+ cerr << "^ Syntax error in test inclusion/exclusion list\n\n";
+ usage(argv[0]);
+ }
+} // selectTests
+
+
+void
+listTests(const Test *tests, bool verbose) {
+ for (const Test *t = tests; t; t = t->nextTest) {
+ cout << t->name << (verbose? ":" : "") << "\n";
+ if (verbose) {
+ cout << t->description;
+ cout << '\n';
+ }
+ }
+}
+
+
+void
+usage(char* command) {
+ cerr << GLEAN::versionString << '\n';
+ cerr << "Usage: " << command << " mode [options]\n"
+"\n"
+"mode:\n"
+" (-r|--run) results-directory\n"
+" or (-c|--compare) old-results-dir new-results-dir\n"
+"\n"
+"options:\n"
+" (-v|--verbose) # each occurrence increases\n"
+" # verbosity of output\n"
+" (-o|--overwrite) # overwrite existing results database\n"
+" --visuals 'filter-string' # select subset of visuals (FBConfigs,\n"
+" # pixel formats) to test\n"
+" --ignore-prereqs # do not force prerequisite tests\n"
+" (-t|--tests) {(+|-)test} # choose tests to include (+) or exclude (-)\n"
+" --listtests # list test names and exit\n"
+" --listdetails # list details of the selected tests and exit\n"
+" --help # display usage information\n"
+#if defined(__X11__)
+" -display X11-display-name # select X11 display to use\n"
+" (or --display)\n"
+#elif defined(__WIN__)
+#endif
+ ;
+ exit(1);
+} // usage
diff --git a/tests/glean/misc.cpp b/tests/glean/misc.cpp
new file mode 100644
index 00000000..6d8aee4b
--- /dev/null
+++ b/tests/glean/misc.cpp
@@ -0,0 +1,82 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// misc.cpp: implementation of miscellaneous functions
+
+#include <cctype>
+#include <cmath>
+#include "misc.h"
+
+namespace GLEAN {
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Utility routine to skip whitespace in streams
+// This is helpful when interleaving invocations of getline() and
+// operator>>. In particular, after operator>> at the end of a line,
+// there may be whitespace (especially a newline) remaining; this may
+// confuse a subsequent invocation of getline().
+///////////////////////////////////////////////////////////////////////////////
+void
+SkipWhitespace(istream& s) {
+ char c;
+ while (s.get(c)) {
+ if (!isspace(c)) {
+ s.putback(c);
+ break;
+ }
+ }
+} // SkipWhitespace
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Utility routine to compute logarithm, base two
+///////////////////////////////////////////////////////////////////////////////
+double
+log2(double x) {
+ return 1.4426950408889634 * log(x);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Utility routine to compute error, expressed in bits
+// Typically used to convert a floating-point error (in the range [0,1])
+// to the number of bits in the representation of a color.
+///////////////////////////////////////////////////////////////////////////////
+double
+ErrorBits(double absError, int repBits) {
+ if (absError <= 0.0)
+ return 0.0;
+ double log2Error = log2(absError) + repBits;
+ return (log2Error <= 0.0)? 0.0: log2Error;
+} // ErrorBits
+
+
+} // namespace GLEAN
diff --git a/tests/glean/misc.h b/tests/glean/misc.h
new file mode 100644
index 00000000..0590a5fd
--- /dev/null
+++ b/tests/glean/misc.h
@@ -0,0 +1,50 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// misc.h: Miscellaneous functions
+
+
+#ifndef __misc_h__
+#define __misc_h__
+
+using namespace std;
+
+#include <iostream>
+
+namespace GLEAN {
+
+void SkipWhitespace(istream& s);
+double ErrorBits(double absError, int repBits);
+double log2(double x);
+
+} // namespace GLEAN
+
+#endif // __misc_h__
diff --git a/tests/glean/options.cpp b/tests/glean/options.cpp
new file mode 100644
index 00000000..9bda4e48
--- /dev/null
+++ b/tests/glean/options.cpp
@@ -0,0 +1,66 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// options.cpp: implementation of global options class
+
+#include "options.h"
+#if defined(__X11__)
+# include <stdlib.h>
+#endif
+
+namespace GLEAN {
+
+
+
+Options::Options() {
+ mode = notSet;
+ verbosity = 0;
+ db1Name = "results";
+ db2Name = "previous";
+ visFilter = "1";
+ selectedTests.resize(0);
+ overwrite = false;
+ ignorePrereqs = false;
+# if defined(__X11__)
+ {
+ char* display = getenv("DISPLAY");
+ if (display)
+ dpyName = display;
+ else
+ dpyName = ":0";
+ }
+# elif defined(__WIN__)
+# endif
+} // Options::Options()
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/options.h b/tests/glean/options.h
new file mode 100644
index 00000000..ad476d37
--- /dev/null
+++ b/tests/glean/options.h
@@ -0,0 +1,97 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// options.h: global test options
+
+// This class encapsulates global options that apply to the entire
+// testing process -- things like the display name (for X11),
+// constraints on the drawing surface configurations to be tested,
+// locations of test results files, etc.
+
+// We collect this information for two reasons. First, it allows the
+// (relatively) large number of parameters needed for creating an
+// Environment to be passed cleanly to Environment's constructor.
+// Second, it allows the process of gathering parameters (by parsing a
+// command line, running a set of GUI dialogs, etc.) to be separated
+// from the creation of the Environment.
+
+
+
+#ifndef __options_h__
+#define __options_h__
+
+using namespace std;
+
+#include <string>
+#include <vector>
+
+namespace GLEAN {
+
+class Options {
+ public:
+ typedef enum {notSet, run, compare, listtests, listdetails} RunMode;
+ RunMode mode; // Indicates whether we're generating
+ // results, or comparing two previous runs.
+
+ int verbosity; // Verbosity level. 0 == concise; larger
+ // values imply more verbose output.
+
+ string db1Name; // Name of output database, or one of
+ // the two databases being compared.
+ // Typically the pathname of a directory,
+ // provided on the command line.
+
+ string db2Name; // Name of the second database being
+ // compared.
+
+ string visFilter; // Filter constraining the set of visuals
+ // (FBConfigs, pixel formats) that will be
+ // available for test. See
+ // DrawingSurfaceFilter for description of
+ // contents.
+
+ vector<string> selectedTests;
+ // Sorted list of tests to be executed.
+
+ bool overwrite; // overwrite old results database if exists
+ bool ignorePrereqs; // ignore prerequisite tests
+#if defined(__X11__)
+ string dpyName; // Name of the X11 display providing the
+ // OpenGL implementation to be tested.
+#elif defined(__WIN__)
+#endif
+
+ Options();
+}; // class Options
+
+} // namespace GLEAN
+
+#endif // __options_h__
diff --git a/tests/glean/pack.cpp b/tests/glean/pack.cpp
new file mode 100644
index 00000000..11617ef4
--- /dev/null
+++ b/tests/glean/pack.cpp
@@ -0,0 +1,262 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// Data packing utilities. Note that these map component values per
+// the usual OpenGL conversions. Also, see comments in unpack.cpp.
+
+#include "image.h"
+
+namespace {
+
+#define SCALE (static_cast<double>(num) / static_cast<double>(denom))
+#define BIAS (static_cast<double>(bias) / static_cast<double>(denom))
+
+// The original implementation of packing functions (using function
+// templates) wouldn't compile under VC6, but this slight variant
+// using static member functions in a class template will compile.
+
+template<class component, int num, unsigned int denom, int bias>
+class Pack
+{
+public :
+ // pack_l
+ static void pack_l(GLsizei n, char* dst, double* rgba)
+ {
+ component* out = reinterpret_cast<component*>(dst);
+ double* end = rgba + 4 * n;
+ for (; rgba != end; rgba += 4) {
+ if (bias)
+ out[0] = static_cast<component>(SCALE * rgba[0] - BIAS);
+ else
+ out[0] = static_cast<component>(SCALE * rgba[0]);
+ out += 1;
+ }
+ }
+
+ // pack_la
+ static void pack_la(GLsizei n, char* dst, double* rgba)
+ {
+ component* out = reinterpret_cast<component*>(dst);
+ double* end = rgba + 4 * n;
+ for (; rgba != end; rgba += 4) {
+ if (bias) {
+ out[0] = static_cast<component>(SCALE * rgba[0] - BIAS);
+ out[1] = static_cast<component>(SCALE * rgba[3] - BIAS);
+ } else {
+ out[0] = static_cast<component>(SCALE * rgba[0]);
+ out[1] = static_cast<component>(SCALE * rgba[3]);
+ }
+ out += 2;
+ }
+ }
+
+ // pack_rga
+ static void pack_rgb(GLsizei n, char* dst, double* rgba)
+ {
+ component* out = reinterpret_cast<component*>(dst);
+ double* end = rgba + 4 * n;
+ for (; rgba != end; rgba += 4) {
+ if (bias) {
+ out[0] = static_cast<component>(SCALE * rgba[0] - BIAS);
+ out[1] = static_cast<component>(SCALE * rgba[1] - BIAS);
+ out[2] = static_cast<component>(SCALE * rgba[2] - BIAS);
+ } else {
+ out[0] = static_cast<component>(SCALE * rgba[0]);
+ out[1] = static_cast<component>(SCALE * rgba[1]);
+ out[2] = static_cast<component>(SCALE * rgba[2]);
+ }
+ out += 3;
+ }
+ }
+
+ // pack_rgba
+ static void pack_rgba(GLsizei n, char* dst, double* rgba)
+ {
+ component* out = reinterpret_cast<component*>(dst);
+ double* end = rgba + 4 * n;
+ for (; rgba != end; rgba += 4) {
+ if (bias) {
+ out[0] = static_cast<component>(SCALE * rgba[0] - BIAS);
+ out[1] = static_cast<component>(SCALE * rgba[1] - BIAS);
+ out[2] = static_cast<component>(SCALE * rgba[2] - BIAS);
+ out[3] = static_cast<component>(SCALE * rgba[3] - BIAS);
+ } else {
+ out[0] = static_cast<component>(SCALE * rgba[0]);
+ out[1] = static_cast<component>(SCALE * rgba[1]);
+ out[2] = static_cast<component>(SCALE * rgba[2]);
+ out[3] = static_cast<component>(SCALE * rgba[3]);
+ }
+ out += 4;
+ }
+ }
+
+}; // class Pack
+
+#undef SCALE
+#undef BIAS
+
+}; // anonymous namespace
+
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Public interface
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::pack(GLsizei n, char* nextPixel, double* rgba) {
+ (*(valid(vbPacker)? _packer: validatePacker())) (n, nextPixel, rgba);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// validatePacker - select appropriate pixel-packing utility
+///////////////////////////////////////////////////////////////////////////////
+
+Image::Packer*
+Image::validatePacker() {
+ switch (format()) {
+ case GL_LUMINANCE:
+ switch (type()) {
+ case GL_BYTE:
+ _packer = Pack<GLbyte, 255, 2, 1>::pack_l;
+ break;
+ case GL_UNSIGNED_BYTE:
+ _packer = Pack<GLubyte, 255, 1, 0>::pack_l;
+ break;
+ case GL_SHORT:
+ _packer = Pack<GLshort, 65535, 2, 1>::pack_l;
+ break;
+ case GL_UNSIGNED_SHORT:
+ _packer = Pack<GLushort, 65535, 1, 0>::pack_l;
+ break;
+ case GL_INT:
+ _packer = Pack<GLint, 4294967295U, 2, 1>::pack_l;
+ break;
+ case GL_UNSIGNED_INT:
+ _packer = Pack<GLuint, 4294967295U, 1, 0>::pack_l;
+ break;
+ case GL_FLOAT:
+ _packer = Pack<GLfloat, 1, 1, 0>::pack_l;
+ break;
+ default:
+ throw BadType(type());
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ switch (type()) {
+ case GL_BYTE:
+ _packer = Pack<GLbyte, 255, 2, 1>::pack_la;
+ break;
+ case GL_UNSIGNED_BYTE:
+ _packer = Pack<GLubyte, 255, 1, 0>::pack_la;
+ break;
+ case GL_SHORT:
+ _packer = Pack<GLshort, 65535, 2, 1>::pack_la;
+ break;
+ case GL_UNSIGNED_SHORT:
+ _packer = Pack<GLushort, 65535, 1, 0>::pack_la;
+ break;
+ case GL_INT:
+ _packer = Pack<GLint, 4294967295U, 2, 1>::pack_la;
+ break;
+ case GL_UNSIGNED_INT:
+ _packer = Pack<GLuint, 4294967295U, 1, 0>::pack_la;
+ break;
+ case GL_FLOAT:
+ _packer = Pack<GLfloat, 1, 1, 0>::pack_la;
+ break;
+ default:
+ throw BadType(type());
+ }
+ break;
+ case GL_RGB:
+ switch (type()) {
+ case GL_BYTE:
+ _packer = Pack<GLbyte, 255, 2, 1>::pack_rgb;
+ break;
+ case GL_UNSIGNED_BYTE:
+ _packer = Pack<GLubyte, 255, 1, 0>::pack_rgb;
+ break;
+ case GL_SHORT:
+ _packer = Pack<GLshort, 65535, 2, 1>::pack_rgb;
+ break;
+ case GL_UNSIGNED_SHORT:
+ _packer = Pack<GLushort, 65535, 1, 0>::pack_rgb;
+ break;
+ case GL_INT:
+ _packer = Pack<GLint, 4294967295U, 2, 1>::pack_rgb;
+ break;
+ case GL_UNSIGNED_INT:
+ _packer = Pack<GLuint, 4294967295U, 1, 0>::pack_rgb;
+ break;
+ case GL_FLOAT:
+ _packer = Pack<GLfloat, 1, 1, 0>::pack_rgb;
+ break;
+ default:
+ throw BadType(type());
+ }
+ break;
+ case GL_RGBA:
+ switch (type()) {
+ case GL_BYTE:
+ _packer = Pack<GLbyte, 255, 2, 1>::pack_rgba;
+ break;
+ case GL_UNSIGNED_BYTE:
+ _packer = Pack<GLubyte, 255, 1, 0>::pack_rgba;
+ break;
+ case GL_SHORT:
+ _packer = Pack<GLshort, 65535, 2, 1>::pack_rgba;
+ break;
+ case GL_UNSIGNED_SHORT:
+ _packer = Pack<GLushort, 65535, 1, 0>::pack_rgba;
+ break;
+ case GL_INT:
+ _packer = Pack<GLint, 4294967295U, 2, 1>::pack_rgba;
+ break;
+ case GL_UNSIGNED_INT:
+ _packer = Pack<GLuint, 4294967295U, 1, 0>::pack_rgba;
+ break;
+ case GL_FLOAT:
+ _packer = Pack<GLfloat, 1, 1, 0>::pack_rgba;
+ break;
+ default:
+ throw BadType(type());
+ }
+ break;
+ default:
+ throw BadFormat(format());
+ }
+
+ validate(vbPacker);
+ return _packer;
+}
+
+}; // namespace GLEAN
diff --git a/tests/glean/rand.h b/tests/glean/rand.h
new file mode 100644
index 00000000..b47684d7
--- /dev/null
+++ b/tests/glean/rand.h
@@ -0,0 +1,125 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// rand.h: Simple random sequence generation utilities.
+
+// We provide these to eliminate dependencies on the operating
+// system's random number generator. This makes it possible to
+// compare results for a given graphics device running under different
+// operating systems.
+
+// Based on Numerical Recipes, 2d ed., p. 284.
+
+
+#ifndef __rand_h__
+#define __rand_h__
+
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// RandomBase: Quick-and-dirty linear congruential generator that serves as
+// a base for other random-sequence classes.
+///////////////////////////////////////////////////////////////////////////////
+class RandomBase {
+ unsigned int i;
+ public:
+ inline RandomBase(unsigned int seed): i(seed) { }
+ inline RandomBase(): i(1) { }
+ inline unsigned int next() {
+ i = 1664525 * i + 1013904223;
+ return i;
+ }
+}; // class RandomBase
+
+///////////////////////////////////////////////////////////////////////////////
+// RandomBits: Returns a given number of random bits (expressed as an unsigned
+// int, so the maximum portable number of bits is 32).
+///////////////////////////////////////////////////////////////////////////////
+class RandomBits: public RandomBase {
+ unsigned int shift;
+ public:
+ inline RandomBits(unsigned int bits, unsigned int seed):
+ RandomBase(seed), shift(32 - bits) { }
+ inline RandomBits(unsigned int bits):
+ RandomBase(), shift(32 - bits) { }
+ inline unsigned int next() { return RandomBase::next() >> shift; }
+}; // class RandomBits
+
+///////////////////////////////////////////////////////////////////////////////
+// RandomSignedBits: Returns a given number of random bits (expressed as a
+// signed int, so the maximum portable number of bits is 32 including sign).
+///////////////////////////////////////////////////////////////////////////////
+class RandomSignedBits: public RandomBase {
+ unsigned int shift;
+ public:
+ inline RandomSignedBits(unsigned int bits, unsigned int seed):
+ RandomBase(seed), shift(32 - bits) { }
+ inline RandomSignedBits(unsigned int bits):
+ RandomBase(), shift(32 - bits) { }
+ inline int next() {
+ return static_cast<int>(RandomBase::next()) >> shift;
+ }
+}; // class RandomSignedBits
+
+///////////////////////////////////////////////////////////////////////////////
+// RandomDouble: Returns a random floating-point value in the closed
+// interval [0.0, 1.0].
+///////////////////////////////////////////////////////////////////////////////
+class RandomDouble: public RandomBase {
+ public:
+ inline RandomDouble(unsigned int seed): RandomBase(seed) { }
+ inline RandomDouble(): RandomBase() { }
+ inline double next() {
+ return static_cast<double>(RandomBase::next()) / 4294967295.0;
+ }
+}; // class RandomDouble
+
+///////////////////////////////////////////////////////////////////////////////
+// RandomBitsDouble: Returns a random floating-point value in the closed
+// interval [0.0, 1.0], but with possible values limited by a generator
+// returning a specific number of bits.
+///////////////////////////////////////////////////////////////////////////////
+class RandomBitsDouble: public RandomBits {
+ double scale;
+ public:
+ inline RandomBitsDouble(unsigned int bits, unsigned int seed):
+ RandomBits(bits, seed) { scale = (1 << bits) - 1.0; }
+ inline RandomBitsDouble(unsigned int bits):
+ RandomBits(bits) { scale = (1 << bits) - 1.0; }
+ inline double next() {
+ return static_cast<double>(RandomBits::next()) / scale;
+ }
+}; // class RandomBitsDouble
+
+} // namespace GLEAN
+
+#endif // __rand_h__
diff --git a/tests/glean/rc.cpp b/tests/glean/rc.cpp
new file mode 100644
index 00000000..8cc95b3d
--- /dev/null
+++ b/tests/glean/rc.cpp
@@ -0,0 +1,159 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// rc.cpp: implementation of rendering context utilities
+
+#include <iostream>
+#include <algorithm>
+#include "rc.h"
+#include "dsconfig.h"
+#include "winsys.h"
+
+namespace {
+
+#if defined (__WIN__)
+
+// XXX
+// wglCreateContext requires a handle to a device context.
+// The ctor of RenderingContext doesn't know which window
+// it is creating a surface for, only what the pixelformat
+// of that window is. The hDC passed to wglCreateContext
+// doesn't have to be the same as the one use in SwapBuffers
+// or wglMakeCurrent, their pixelformats have to be the
+// same though. A limitation is that the pixelformat of
+// a window can only be set once. That is why a
+// temporary window is created.
+
+
+HGLRC create_context(GLEAN::DrawingSurfaceConfig &c)
+{
+ HWND hwnd = CreateWindow("STATIC","temp",WS_POPUP,
+ CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
+ 0,0,GetModuleHandle(NULL),0);
+
+ if (!hwnd)
+ return 0;
+
+ HDC hDC = GetDC(hwnd);
+ if (!hDC)
+ return 0;
+
+ PIXELFORMATDESCRIPTOR pfd;
+
+ if (!SetPixelFormat(hDC,c.pfdID,&pfd))
+ {
+ ReleaseDC(hwnd,hDC);
+ DestroyWindow(hwnd);
+ return 0;
+ }
+
+ HGLRC rc = wglCreateContext(hDC);
+ if (!rc)
+ return 0;
+
+ ReleaseDC(hwnd,hDC);
+ DestroyWindow(hwnd);
+
+ return rc;
+}
+
+#endif
+
+} // anonymous namespace
+
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors
+///////////////////////////////////////////////////////////////////////////////
+RenderingContext::RenderingContext(WindowSystem& ws, DrawingSurfaceConfig& c,
+ RenderingContext* share, bool direct) {
+
+ // Link back to enclosing window system, so as to simplify bookkeeping:
+ winSys = &ws;
+ ws.contexts.push_back(this);
+
+# if defined(__X11__)
+
+# if defined(GLX_VERSION_1_3)
+
+ if (ws.GLXVersMajor == 1 && ws.GLXVersMinor < 3)
+ goto legacyMethod;
+ // XXX Need GLX 1.3 rc constructor code
+ // For now, just fall through.
+
+# endif
+
+legacyMethod:
+ // Create the rendering context:
+ rc = glXCreateContext(winSys->dpy, c.vi, (share? share->rc: 0),
+ direct? True: False);
+ if (!rc)
+ throw Error();
+ // XXX Ideally, we would deal with X11 and GLX errors here, too
+ // (Badmatch, BadValue, GLXBadContext, BadAlloc)
+
+# elif defined(__WIN__)
+
+ rc = create_context(c);
+ if (!rc)
+ throw Error();
+# elif defined(__AGL__)
+ rc = aglCreateContext(c.pf, NULL);
+ if(rc == NULL)
+ throw Error();
+# endif
+
+} // RenderingContext::RenderingContext
+
+///////////////////////////////////////////////////////////////////////////////
+// Destructors
+///////////////////////////////////////////////////////////////////////////////
+
+RenderingContext::~RenderingContext() {
+ remove(winSys->contexts.begin(), winSys->contexts.end(), this);
+# if defined(__X11__)
+# if defined(GLX_VERSION_1_3)
+ if (winSys->GLXVersMajor == 1 && winSys->GLXVersMinor < 3)
+ goto legacyMethod;
+ // XXX Need to write GLX 1.3 rc destructor
+ // For now, just fall through.
+# endif
+legacyMethod:
+ glXDestroyContext(winSys->dpy, rc);
+# elif defined(__WIN__)
+ wglDeleteContext(rc);
+# endif
+} // RenderingContext::~RenderingContext
+
+
+} // namespace GLEAN
diff --git a/tests/glean/rc.h b/tests/glean/rc.h
new file mode 100644
index 00000000..eaea5150
--- /dev/null
+++ b/tests/glean/rc.h
@@ -0,0 +1,68 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// rc.h: utilities for manipulating rendering contexts
+
+#ifndef __rc_h__
+#define __rc_h__
+
+#include "glwrap.h"
+
+namespace GLEAN {
+
+class WindowSystem; // Forward and mutually-recursive references
+class DrawingSurfaceConfig;
+
+class RenderingContext {
+ public:
+ RenderingContext(WindowSystem& ws, DrawingSurfaceConfig& c,
+ RenderingContext* share = 0, bool direct = true);
+ ~RenderingContext();
+
+ // Exceptions:
+ struct Error { }; // Base class for all errors.
+
+ // Members:
+ WindowSystem* winSys; // Window system that owns this context.
+
+# if defined(__X11__)
+ GLXContext rc;
+# elif defined(__WIN__)
+ ::HGLRC rc;
+# elif defined(__AGL__)
+ ::AGLContext rc;
+# endif
+
+}; // class RenderingContext
+
+} // namespace GLEAN
+
+#endif // __rc_h__
diff --git a/tests/glean/rdtiff.cpp b/tests/glean/rdtiff.cpp
new file mode 100644
index 00000000..5e5068f2
--- /dev/null
+++ b/tests/glean/rdtiff.cpp
@@ -0,0 +1,156 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+#include "image.h"
+#include "tiffio.h"
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// readTIFF - read image from TIFF file, set attributes to match the file
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::readTIFF(const char* filename) {
+ // XXX Things we explicitly don't handle:
+ // Varying number of bits per sample. Sam's library doesn't
+ // handle that.
+ // Bits per sample other than 8, 16, or 32.
+ // Tile-oriented TIFF files. We only do strip-oriented files.
+ // Planar configurations other than contiguous (R,G,B,R,G,B,...).
+ // Premultiplied alpha. If there's a fourth color channel,
+ // we just assume it's non-premultiplied alpha.
+ // Eventually would be good to add a ``validation'' function which
+ // checks a file before attempting to read the image it contains.
+ // Also: need error-reporting code.
+
+ TIFF* tf = TIFFOpen(filename, "r");
+ if (!tf)
+ throw CantOpen(filename);
+
+ uint32 u32;
+
+ TIFFGetFieldDefaulted(tf, TIFFTAG_IMAGELENGTH, &u32);
+ height(u32);
+
+ TIFFGetFieldDefaulted(tf, TIFFTAG_IMAGEWIDTH, &u32);
+ width(u32);
+
+ uint16 samplesPerPixel;
+ TIFFGetFieldDefaulted(tf, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel);
+ switch (samplesPerPixel) {
+ case 1:
+ format(GL_LUMINANCE);
+ break;
+ case 2:
+ format(GL_LUMINANCE_ALPHA);
+ break;
+ case 3:
+ format(GL_RGB);
+ break;
+ case 4:
+ format(GL_RGBA);
+ break;
+ default:
+ TIFFClose(tf);
+ throw UnsupportedTIFF();
+ }
+
+ uint16 bitsPerSample;
+ TIFFGetFieldDefaulted(tf, TIFFTAG_BITSPERSAMPLE, &bitsPerSample);
+ uint16 sampleFormat;
+ if (TIFFGetField(tf, TIFFTAG_SAMPLEFORMAT, &sampleFormat) != 1)
+ sampleFormat = SAMPLEFORMAT_UINT;
+ switch ((sampleFormat << 8) | bitsPerSample) {
+ case (SAMPLEFORMAT_UINT << 8) | 8:
+ type(GL_UNSIGNED_BYTE);
+ break;
+ case (SAMPLEFORMAT_UINT << 8) | 16:
+ type(GL_UNSIGNED_SHORT);
+ break;
+ case (SAMPLEFORMAT_UINT << 8) | 32:
+ type(GL_UNSIGNED_INT);
+ break;
+ case (SAMPLEFORMAT_INT << 8) | 8:
+ type(GL_BYTE);
+ break;
+ case (SAMPLEFORMAT_INT << 8) | 16:
+ type(GL_SHORT);
+ break;
+ case (SAMPLEFORMAT_INT << 8) | 32:
+ type(GL_INT);
+ break;
+ case (SAMPLEFORMAT_IEEEFP << 8) | 32:
+ type(GL_FLOAT);
+ break;
+ default:
+ TIFFClose(tf);
+ throw UnsupportedTIFF();
+ }
+
+ // At the moment it's not obvious whether we should pad
+ // scanlines to achieve a preferred alignment, so we'll just
+ // return an alignment that matches the data.
+ alignment(1);
+ switch (rowSizeInBytes() & 0x7) {
+ case 0:
+ alignment(8);
+ break;
+ case 4:
+ alignment(4);
+ break;
+ case 2:
+ case 6:
+ alignment(2);
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ alignment(1);
+ break;
+ }
+
+ reserve();
+
+ {
+ // Store rows in reverse order, so that the default TIFF
+ // orientation won't result in an upside-down image for
+ // OpenGL:
+ GLsizei rowStep = rowSizeInBytes();
+ char* row = pixels() + (height() - 1) * rowStep;
+ for (GLsizei r = 0; r < height(); ++r, row -= rowStep)
+ TIFFReadScanline(tf, row, r);
+ }
+
+ TIFFClose(tf);
+} // Image::readTIFF
+
+}; // namespace GLEAN
diff --git a/tests/glean/reg.cpp b/tests/glean/reg.cpp
new file mode 100644
index 00000000..87c8c41a
--- /dev/null
+++ b/tests/glean/reg.cpp
@@ -0,0 +1,176 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// Image registration.
+
+#include <cfloat>
+#include "image.h"
+
+#include <cmath> // for fabs
+
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// register: compare a reference image to the current (``test'') image.
+//
+// The reference image must be no larger than the current image, in
+// both dimensions. Type doesn't matter, as both images will be
+// converted to RGBA.
+//
+// The reference image will be slid into all possible positions over
+// the current image, and the sum of the mean absolute errors for all
+// four color channels computed at each position.
+//
+// Returns an Image::Registration struct that specifies the position at
+// which the sum of mean absolute errors was minimal, plus the statistics
+// at that position.
+///////////////////////////////////////////////////////////////////////////////
+Image::Registration
+Image::reg(Image& ref) {
+ int wt = width(); // Width of test image, in pixels.
+ int ht = height(); // Height of test image, in pixels.
+ int wr = ref.width(); // Width of reference image, in pixels.
+ int hr = ref.height(); // Height of test image, in pixels.
+ int dh = ht - hr; // Difference in heights, in pixels.
+ int dw = wt - wr; // Difference in widths, in pixels.
+ int i;
+
+ if (dh < 0 || dw < 0)
+ throw RefImageTooLarge();
+
+ int wt4 = 4 * wt; // Width of test image, in RGBA samples.
+ int wr4 = 4 * wr; // Width of ref image, in RGBA samples.
+ int dw4 = 4 * dw; // Difference in widths, in samples.
+
+ double** testPix; // Buffers containing all the rows of
+ // the test image that need to be
+ // accessed concurrently.
+ // XXX sure would be nice to use auto_ptr to allocate this stuff,
+ // but it isn't supported in the STL that came with egcs 1.1.2.
+
+ // XXX testPix = new (double*) [dh + 1];
+ // VC 6 seems to misinterpret this as a c-style cast
+ testPix = new double* [dh + 1];
+
+
+ for (/*int */i = 0; i <= dh; ++i)
+ testPix[i] = new double [wt4];
+
+ double* refPix = new double [wr4];
+ // Buffer containing the one row of
+ // the reference image that's accessed
+ // at any given time.
+
+ BasicStats** stats; // Buffers containing a statistics-
+ // gathering structure for each of
+ // the possible reference image
+ // positions.
+ // XXX stats = new (BasicStats*) [dh + 1];
+ // VC 6 seems to misinterpret this as a c-style cast
+ stats = new BasicStats * [dh + 1];
+
+ for (/*int*/ i = 0; i <= dh; ++i)
+ stats[i] = new BasicStats [dw4 + 4];
+
+ // Prime the pump by unpacking the first few rows of the test image:
+ char* testRow = pixels();
+ for (/*int*/ i = 0; i < dh; ++i) {
+ unpack(wt, testPix[i], testRow);
+ testRow += rowSizeInBytes();
+ }
+
+ // Now accumulate statistics for one row of the reference image
+ // at a time, in all possible positions:
+ char* refRow = ref.pixels();
+ for (/*int*/ i = 0; i < hr; ++i) {
+ // Get the next row of the reference image:
+ ref.unpack(wr, refPix, refRow);
+ refRow += ref.rowSizeInBytes();
+
+ // Get the next row of the test image:
+ unpack(wt, testPix[dh], testRow);
+ testRow += rowSizeInBytes();
+
+ // Accumulate absolute error for R,G,B,A in all positions:
+ for (int j = 0; j <= dh; ++j)
+ for (int k = 0; k <= dw4; k += 4)
+ for (int m = 0; m < wr4; m += 4) {
+ stats[j][k+0].sample( fabs(
+ refPix[m+0]-testPix[j][m+k+0]));
+ stats[j][k+1].sample( fabs(
+ refPix[m+1]-testPix[j][m+k+1]));
+ stats[j][k+2].sample( fabs(
+ refPix[m+2]-testPix[j][m+k+2]));
+ stats[j][k+3].sample( fabs(
+ refPix[m+3]-testPix[j][m+k+3]));
+ }
+ }
+
+ // Now find the position for which the sum of the mean absolute errors
+ // is minimal:
+ double minErrorSum = DBL_MAX;
+ int minI = 0;
+ int minJ = 0;
+ for (/*int*/ i = 0; i <= dh; ++i)
+ for (int j = 0; j <= dw4; j += 4) {
+ double errorSum = stats[i][j+0].mean()
+ + stats[i][j+1].mean()
+ + stats[i][j+2].mean()
+ + stats[i][j+3].mean();
+ if (errorSum < minErrorSum) {
+ minErrorSum = errorSum;
+ minI = i;
+ minJ = j;
+ }
+ }
+
+ Registration r;
+ r.wOffset = minJ / 4;
+ r.hOffset = minI;
+ r.stats[0] = stats[minI][minJ+0];
+ r.stats[1] = stats[minI][minJ+1];
+ r.stats[2] = stats[minI][minJ+2];
+ r.stats[3] = stats[minI][minJ+3];
+
+ // Clean up:
+ for (/*int*/ i = 0; i <= dh; ++i)
+ delete[] testPix[i];
+ delete[] testPix;
+ delete[] refPix;
+ for (/*int*/ i = 0; i <= dh; ++i)
+ delete[] stats[i];
+ delete[] stats;
+
+ return r;
+} // Image::register
+
+}; // namespace GLEAN
diff --git a/tests/glean/stats.h b/tests/glean/stats.h
new file mode 100644
index 00000000..d9eb019f
--- /dev/null
+++ b/tests/glean/stats.h
@@ -0,0 +1,91 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// stats.h: simple statistics-gathering utilities for glean
+
+// These are rather simplistic. For more robust implementations, consider
+// using Numerical Recipes.
+
+#ifndef __stats_h__
+#define __stats_h__
+
+#include <vector>
+
+#ifdef __WIN__
+using namespace std;
+#endif
+
+#if defined( __WIN__ )
+
+#undef min
+#undef max
+
+#endif
+
+namespace GLEAN {
+
+class BasicStats {
+ int _n;
+ double _min;
+ double _max;
+ double _sum;
+ double _sum2;
+ public:
+ void init();
+ inline int n() const {return _n;}
+ inline double min() const {return _min;}
+ inline double max() const {return _max;}
+ inline double sum() const {return _sum;}
+ inline double sum2() const {return _sum2;}
+ double mean() const;
+ double variance() const;
+ double deviation() const;
+ inline void sample(double d) {
+ ++_n;
+ if (d < _min)
+ _min = d;
+ if (d > _max)
+ _max = d;
+ _sum += d;
+ _sum2 += d*d;
+ }
+
+ BasicStats() {init();}
+ template<class T> BasicStats(std::vector<T>& v) {
+ init();
+ for (typename std::vector<T>::const_iterator p = v.begin(); p < v.end(); ++p)
+ sample(*p);
+ }
+}; // class BasicStats
+
+} // namespace GLEAN
+
+#endif // __stats_h__
diff --git a/tests/glean/tbase.h b/tests/glean/tbase.h
new file mode 100644
index 00000000..47675427
--- /dev/null
+++ b/tests/glean/tbase.h
@@ -0,0 +1,414 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999-2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+/*
+tbase.h: Base template class for (most) tests
+
+In general, a glean test is an instance of a class derived from the
+class Test. It produces a vector of results, which are instances of a
+class derived from the class Result. Most glean tests are "portable"
+in the sense that they don't contain OS- or window-system-specific
+code; those things are abstracted by the Environment and WindowSystem
+classes.
+
+This file contains a template class and result class that serve as
+bases for portable tests, and several macros that simplify test class
+declarations.
+
+The result class, BaseResult, includes utility functions that read and
+write test results. To use it, derive a new class from it, add
+whatever variables you need to store your test results, and override
+the getresults() and putresults() member functions to read and write
+those variables from and to a stream.
+
+The template class, BaseTest, is parameterized by the result class and
+declares member functions and variables that are common to all
+portable tests. These include the member functions run() and
+compare() which are invoked for each test by main(). BaseTest also
+provides several variables which you might want to use when
+constructing a test:
+
+ A drawing surface filter string. The test can be run on all
+ the drawing surface configurations that are selected by the
+ filter, and one result structure will be generated for each
+ such configuration.
+
+ A flag indicating whether the test is to be run on *all*
+ drawing surface configurations, or just one. For tests that
+ take a long time to run, it is often sufficient to check just
+ one drawing surface configuration rather than all of them.
+
+ An extension filter string. The test will only be run on
+ contexts that support all the listed extensions. Extension
+ names in the string may be separated with non alphanumerics;
+ whitespace and commas are used by convention.
+
+ A description string. This will be printed in the test log to
+ describe the test.
+
+ Default width and height for any windows to be created by the
+ test.
+
+ A pointer to an array of other tests that must be run before
+ running the current test. This makes the results of
+ "prerequisite" tests available.
+
+To use BaseTest, declare a new class derived from BaseTest,
+parameterized by your result class. Then override the runOne(),
+compareOne(), and logOne() member functions. runOne() runs a test and
+generates a result. compareOne() compares one result from a test run
+with the same result from another test run. logOne() generates a log
+message summarizing the result of the test.
+
+Your new test will need a few common declarations (such as
+constructors). To simplify writing them, this file provides a few
+helper macros. GLEAN_CLASS(TEST,RESULT) handles the declarations for
+a test class named TEST and a result class named RESULT, using the
+default values for window width and height and the run-once flag.
+GLEAN_CLASS_WH() and GLEAN_CLASS_WHO() allow you to specify the width,
+height, and run-once flag if you choose.
+
+Finally, declare an object using your new test class. This object
+must be global, so that its constructor will automatically add it to
+the list of all tests.
+
+You can find an example of this whole process in the files tbasic.h
+and tbasic.cpp.
+
+*/
+
+
+#ifndef __tbase_h__
+#define __tbase_h__
+
+#ifdef __UNIX__
+#include <unistd.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+#include "dsconfig.h"
+#include "dsfilt.h"
+#include "dsurf.h"
+#include "winsys.h"
+#include "environ.h"
+#include "rc.h"
+#include "glutils.h"
+#include "misc.h"
+
+#include "test.h"
+
+class GLEAN::DrawingSurfaceConfig; // Forward reference.
+
+#define GLEAN_CLASS_WHO(TEST, RESULT, WIDTH, HEIGHT, ONE) \
+ TEST(const char* aName, const char* aFilter, \
+ const char* aDescription): \
+ BaseTest<RESULT>(aName, aFilter, aDescription) { \
+ fWidth = WIDTH; \
+ fHeight = HEIGHT; \
+ testOne = ONE; \
+ } \
+ TEST(const char* aName, const char* aFilter, Test** thePrereqs, \
+ const char* aDescription): \
+ BaseTest<RESULT>(aName, aFilter, thePrereqs, aDescription) { \
+ fWidth = WIDTH; \
+ fHeight = HEIGHT; \
+ testOne = ONE; \
+ } \
+ TEST(const char* aName, const char* aFilter, \
+ const char* anExtensionList, \
+ const char* aDescription): \
+ BaseTest<RESULT>(aName, aFilter, anExtensionList, aDescription) { \
+ fWidth = WIDTH; \
+ fHeight = HEIGHT; \
+ } \
+ virtual ~TEST() {} \
+ \
+ virtual void runOne(RESULT& r, Window& w); \
+ virtual void compareOne(RESULT& oldR, RESULT& newR); \
+ virtual void logOne(RESULT& r)
+
+#define GLEAN_CLASS_WH(TEST, RESULT, WIDTH, HEIGHT) \
+ GLEAN_CLASS_WHO(TEST, RESULT, WIDTH, HEIGHT, false)
+
+#define GLEAN_CLASS(TEST, RESULT) \
+ GLEAN_CLASS_WHO(TEST, RESULT, 258, 258, false)
+
+namespace GLEAN {
+
+class BaseResult : public Result {
+ // Class for a single test result. All basic tests have a
+ // drawing surface configuration, plus other information
+ // that's specific to the test.
+public:
+ DrawingSurfaceConfig* config;
+
+ virtual void putresults(ostream& s) const = 0;
+ virtual bool getresults(istream& s) = 0;
+
+ virtual void put(ostream& s) const {
+ s << config->canonicalDescription() << '\n';
+ putresults(s);
+ }
+
+ virtual bool get(istream& s) {
+ SkipWhitespace(s);
+ string configDesc;
+ if (!getline(s, configDesc)) return false;
+ config = new DrawingSurfaceConfig(configDesc);
+ return getresults(s);
+ }
+};
+
+template <class ResultType> class BaseTest: public Test {
+public:
+ BaseTest(const char* aName, const char* aFilter,
+ const char* aDescription): Test(aName, aDescription) {
+ filter = aFilter;
+ extensions = 0;
+ description = aDescription;
+ fWidth = 258;
+ fHeight = 258;
+ testOne = false;
+ }
+ BaseTest(const char* aName, const char* aFilter, Test** thePrereqs,
+ const char* aDescription):
+ Test(aName, aDescription, thePrereqs) {
+ filter = aFilter;
+ extensions = 0;
+ description = aDescription;
+ fWidth = 258;
+ fHeight = 258;
+ testOne = false;
+ }
+ BaseTest(const char* aName, const char* aFilter,
+ const char* anExtensionList,
+ const char* aDescription): Test(aName, aDescription) {
+ filter = aFilter;
+ extensions = anExtensionList;
+ description = aDescription;
+ fWidth = 258;
+ fHeight = 258;
+ testOne = false;
+ }
+
+ virtual ~BaseTest() {}
+
+ const char* filter; // Drawing surface config filter.
+ const char* extensions; // Required extensions.
+ int fWidth; // Drawing surface width.
+ int fHeight; // Drawing surface height.
+ bool testOne; // Test only one config?
+ vector<ResultType*> results; // Test results.
+
+ virtual void runOne(ResultType& r, Window& w) = 0;
+ virtual void compareOne(ResultType& oldR, ResultType& newR) = 0;
+ virtual void logOne(ResultType& r) = 0;
+
+ virtual vector<ResultType*> getResults(istream& s) {
+ vector<ResultType*> v;
+ while (s.good()) {
+ ResultType* r = new ResultType();
+ if (r->get(s))
+ v.push_back(r);
+ else {
+ delete r;
+ break;
+ }
+ }
+ return v;
+ }
+
+ virtual void logDescription() {
+ if (env->options.verbosity)
+ env->log <<
+"----------------------------------------------------------------------\n"
+ << description
+ << '\n';
+ }
+
+ virtual void run(Environment& environment) {
+ if (hasRun) return; // no multiple invocations
+ // Invoke the prerequisite tests, if any:
+ if (!environment.options.ignorePrereqs) {
+ for (Test** t = prereqs; t != 0 && *t != 0; ++t)
+ (*t)->run(environment);
+ }
+ env = &environment; // make environment available
+ logDescription(); // log invocation
+ WindowSystem& ws = env->winSys;
+ try {
+ OutputStream os(*this); // open results file
+
+ // Select the drawing configurations for testing
+ DrawingSurfaceFilter f(filter);
+ vector<DrawingSurfaceConfig*>
+ configs(f.filter(ws.surfConfigs));
+
+ // Test each config
+ for (vector<DrawingSurfaceConfig*>::const_iterator
+ p = configs.begin();
+ p < configs.end();
+ ++p) {
+ Window w(ws, **p, fWidth, fHeight);
+ RenderingContext rc(ws, **p);
+ if (!ws.makeCurrent(rc, w))
+ ; // XXX need to throw exception here
+
+ // Check for all prerequisite extensions. Note
+ // that this must be done after the rendering
+ // context has been created and made current!
+ if (!GLUtils::haveExtensions(extensions))
+ continue;
+
+ // Create a result object and run the test:
+ ResultType* r = new ResultType();
+ r->config = *p;
+ runOne(*r, w);
+ logOne(*r);
+
+ // Save the result
+ results.push_back(r);
+ r->put(os);
+ if (testOne) break;
+ }
+ }
+ catch (DrawingSurfaceFilter::Syntax e) {
+ env->log << "Syntax error in test's drawing-surface"
+ << " selection criteria:\n'"
+ << filter
+ << "'\n";
+ for (int i = 0; i < e.position; ++i)
+ env->log << ' ';
+ env->log << "^ " << e.err << '\n';
+ }
+ catch (RenderingContext::Error) {
+ env->log << "Could not create a rendering context\n";
+ }
+ env->log << '\n';
+
+ hasRun = true; // Note that we've completed the run
+ }
+
+ virtual void compare(Environment& environment) {
+ env = &environment; // Save the environment
+ logDescription();
+ // Read results from previous runs:
+ Input1Stream is1(*this);
+ vector<ResultType*> oldR(getResults(is1));
+ Input2Stream is2(*this);
+ vector<ResultType*> newR(getResults(is2));
+
+ // Construct a vector of surface configurations from the
+ // old run. (Later we'll find the best match in this
+ // vector for each config in the new run.)
+ vector<DrawingSurfaceConfig*> oldConfigs;
+ for (typename vector<ResultType*>::const_iterator p = oldR.begin();
+ p < oldR.end();
+ ++p)
+ oldConfigs.push_back((*p)->config);
+
+ // Compare results:
+ for (typename vector<ResultType*>::const_iterator newP = newR.begin();
+ newP < newR.end();
+ ++newP) {
+
+ // Find the drawing surface config that most
+ // closely matches the config for this result:
+ int c = (*newP)->config->match(oldConfigs);
+
+ // If there was a match, compare the results:
+ if (c < 0)
+ env->log << name
+ << ": NOTE no matching config for "
+ << (*newP)
+ ->config->conciseDescription()
+ << '\n';
+ else
+ compareOne(*(oldR[c]), **newP);
+ }
+
+ // Get rid of the results; we don't need them for future
+ // comparisons.
+ for (typename vector<ResultType*>::iterator np = newR.begin();
+ np < newR.end();
+ ++np)
+ delete *np;
+ for (typename vector<ResultType*>::iterator op = oldR.begin();
+ op < oldR.end();
+ ++op)
+ delete *op;
+ }
+
+ // comparePassFail is a helper function for tests that have a
+ // boolean result as all or part of their ResultType
+ virtual void comparePassFail(ResultType& oldR, ResultType& newR) {
+ if (oldR.pass == newR.pass) {
+ if (env->options.verbosity)
+ env->log << name
+ << ": SAME "
+ << newR.config->conciseDescription()
+ << '\n'
+ << (oldR.pass
+ ? "\tBoth PASS\n"
+ : "\tBoth FAIL\n");
+ } else {
+ env->log << name
+ << ": DIFF "
+ << newR.config->conciseDescription()
+ << '\n'
+ << '\t'
+ << env->options.db1Name
+ << (oldR.pass? " PASS, ": " FAIL, ")
+ << env->options.db2Name
+ << (newR.pass? " PASS\n": " FAIL\n");
+ }
+ }
+
+ virtual void logPassFail(ResultType& r) {
+ env->log << name << (r.pass ? ": PASS ": ": FAIL ");
+ }
+
+ virtual void logConcise(ResultType& r) {
+ env->log << r.config->conciseDescription() << '\n';
+ }
+
+ virtual void printDetails() {
+ }
+
+ virtual void details(Environment& environment) {
+ env = &environment;
+ env->log << "DETAILS for " << name << '\n';
+ printDetails();
+ env->log << "END DETAILS\n";
+ }
+}; // class BaseTest
+
+} // namespace GLEAN
+
+#endif // __tbasic_h__
diff --git a/tests/glean/tbasic.cpp b/tests/glean/tbasic.cpp
new file mode 100644
index 00000000..b4fab023
--- /dev/null
+++ b/tests/glean/tbasic.cpp
@@ -0,0 +1,68 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999-2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tbasic.cpp: implementation of example class for basic tests
+
+#include "tbasic.h"
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicTest::runOne(BasicResult& r, Window&) {
+ r.pass = true;
+} // BasicTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicTest::logOne(BasicResult& r) {
+ logPassFail(r);
+ logConcise(r);
+} // BasicTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicTest::compareOne(BasicResult& oldR, BasicResult& newR) {
+ comparePassFail(oldR, newR);
+} // BasicTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+BasicTest basicTest("basic", "window",
+ "This trivial test simply verifies the internal support for basic\n"
+ "tests. It is run on every OpenGL-capable drawing surface\n"
+ "configuration that supports creation of a window.\n");
+
+} // namespace GLEAN
diff --git a/tests/glean/tbasic.h b/tests/glean/tbasic.h
new file mode 100644
index 00000000..2d3af683
--- /dev/null
+++ b/tests/glean/tbasic.h
@@ -0,0 +1,69 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999-2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+// tbasic.h: Example class for basic tests
+
+// This class illustrates the use of the BaseResult class and BaseTest
+// template class for constructing straightforward portable tests.
+// See the file tbase.h for a discussion of this process.
+
+// BasicTest simply runs on all drawing surface configurations that
+// permit the creation of a window, and always passes.
+
+
+#ifndef __tbasic_h__
+#define __tbasic_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+class BasicResult: public BaseResult {
+public:
+ bool pass;
+
+ void putresults(ostream& s) const {
+ s << pass << '\n';
+ }
+
+ bool getresults(istream& s) {
+ s >> pass;
+ return s.good();
+ }
+};
+
+class BasicTest: public BaseTest<BasicResult> {
+public:
+ GLEAN_CLASS(BasicTest, BasicResult);
+};
+
+} // namespace GLEAN
+
+#endif // __tbasic_h__
diff --git a/tests/glean/tbasicperf.cpp b/tests/glean/tbasicperf.cpp
new file mode 100644
index 00000000..94e91796
--- /dev/null
+++ b/tests/glean/tbasicperf.cpp
@@ -0,0 +1,189 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tbasicperf.cpp: implementation of example class for basic
+// performance tests
+
+// To customize this for benchmarking a particular function,
+// create a new performance test object of type GLEAN::Perf,
+// overriding the preop(), op(), and postop() methods as needed.
+// (For OpenGL timing tests preop() and postop() will both call
+// glFinish(), but other pre- and post-ops may be used for
+// timing things other than OpenGL.) Then invoke the object's
+// calibrate() and time() methods as shown in runOne().
+
+#include "tbasicperf.h"
+#include "timer.h"
+#include <algorithm>
+
+namespace {
+class MyPerf : public GLEAN::Timer {
+public:
+ int msec;
+
+ void preop() { glFinish(); }
+ void op() {
+#ifdef __WIN__
+ Sleep(msec); /* milliseconds */
+#else
+ usleep(msec*1000); /* microseconds */
+#endif
+ }
+ void postop() { glFinish(); }
+
+ MyPerf() { msec = 100; }
+};
+
+
+// Complex results helper functions
+
+void
+diffHeader(bool& same, const string& name,
+ GLEAN::DrawingSurfaceConfig* config, GLEAN::Environment* env) {
+ if (same) {
+ same = false;
+ env->log << name << ": DIFF "
+ << config->conciseDescription() << '\n';
+ }
+} // diffHeader
+
+}
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicPerfTest::runOne(BasicPerfResult& r, Window &w) {
+ MyPerf perf;
+
+ perf.calibrate();
+ vector<float> m;
+ for (int i = 0; i < 5; i++) {
+ env->quiesce();
+ double t = perf.time();
+ w.swap(); // So user can see something
+ m.push_back(t);
+ }
+ sort(m.begin(), m.end());
+ r.timeAvg = (m[1] + m[2] + m[3]) / 3.0;
+ r.timeLow = m[1];
+ r.timeHigh = m[3];
+ r.pass = true;
+} // BasicPerfTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicPerfTest::logOne(BasicPerfResult& r) {
+ logPassFail(r);
+ logConcise(r);
+ logStats(r);
+} // BasicPerfTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicPerfTest::compareOne(BasicPerfResult& oldR, BasicPerfResult& newR) {
+ bool same = true;
+ const char *title = "100mS sleep";
+
+ if (newR.timeLow < oldR.timeLow) {
+ double percent = (100.0
+ * (oldR.timeLow - newR.timeLow)
+ / newR.timeLow + 0.5);
+ if (percent >= 5.0) {
+ diffHeader(same, name, oldR.config, env);
+ env->log << '\t'
+ << env->options.db1Name
+ << " may be "
+ << percent
+ << "% faster on "
+ << title
+ << '\n';
+ }
+ }
+ if (newR.timeHigh > oldR.timeHigh) {
+ double percent = (100.0
+ * (newR.timeHigh - oldR.timeHigh)
+ / oldR.timeHigh + 0.5);
+ if (percent >= 5.0) {
+ diffHeader(same, name, oldR.config, env);
+ env->log << '\t'
+ << env->options.db2Name
+ << " may be "
+ << percent
+ << "% faster on "
+ << title
+ << '\n';
+ }
+ }
+
+ if (same && env->options.verbosity) {
+ env->log << name
+ << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n\t"
+ << env->options.db2Name
+ << " test time falls within the"
+ << " valid measurement range of\n\t"
+ << env->options.db1Name
+ << " test time.\n";
+ }
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR);
+ env->log << env->options.db2Name << ':';
+ logStats(newR);
+ }
+} // BasicPerfTest::compareOne
+
+void
+BasicPerfTest::logStats(BasicPerfResult& r) {
+ env->log << "\tAverage = "
+ << r.timeAvg
+ << "\tRange = ["
+ << r.timeLow
+ << ", "
+ << r.timeHigh
+ << "]\n";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+BasicPerfTest basicPerfTest("basicPerf", "window",
+ "This trivial test simply verifies the internal support for basic\n"
+ "performance tests. It is run on every OpenGL-capable drawing surface\n"
+ "configuration that supports creation of a window. If everything is\n"
+ "working correctly, each result should be close to 0.1 second.\n");
+
+} // namespace GLEAN
diff --git a/tests/glean/tbasicperf.h b/tests/glean/tbasicperf.h
new file mode 100644
index 00000000..f53a6416
--- /dev/null
+++ b/tests/glean/tbasicperf.h
@@ -0,0 +1,85 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+// tbasicperf.h: Example class for basic performance tests
+
+// This class provides a framework for performance tests. Like most
+// glean tests, it's derived from the BaseResult class and BaseTest
+// template class; see tbase.h for further information. However, it
+// is specialized to include member variables and functions that show
+// how to perform timing operations, save results, and compare
+// results.
+
+// To produce a customized benchmark, one can derive a new class from
+// this one and override the runOne() function to perform the timing
+// measurements. For more information, see tbasicperf.cpp.
+
+
+#ifndef __tbasicperf_h__
+#define __tbasicperf_h__
+
+#include "tbase.h"
+
+class DrawingSurfaceConfig; // Forward reference.
+
+namespace GLEAN {
+
+class BasicPerfResult: public BaseResult {
+public:
+ bool pass;
+ double timeAvg, timeLow, timeHigh;
+
+ BasicPerfResult() {
+ timeAvg = timeLow = timeHigh = 0.0;
+ }
+
+ void putresults(ostream& s) const {
+ s << pass
+ << ' ' << timeAvg
+ << ' ' << timeLow
+ << ' ' << timeHigh
+ << '\n';
+ }
+
+ bool getresults(istream& s) {
+ s >> pass >> timeAvg >> timeLow >> timeHigh;
+ return s.good();
+ }
+};
+
+class BasicPerfTest: public BaseTest<BasicPerfResult> {
+public:
+ GLEAN_CLASS(BasicPerfTest, BasicPerfResult);
+ void logStats(BasicPerfResult& r);
+}; // class BasicPerfTest
+
+} // namespace GLEAN
+
+#endif // __tbasicperf_h__
diff --git a/tests/glean/tbinding.cpp b/tests/glean/tbinding.cpp
new file mode 100644
index 00000000..6aedd025
--- /dev/null
+++ b/tests/glean/tbinding.cpp
@@ -0,0 +1,199 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tbinding.cpp: Test functions in the window-system binding
+
+#include "tbinding.h"
+#include "image.h"
+#include "rand.h"
+#include <cmath>
+
+#if 0
+#ifdef __UNIX__
+#include <unistd.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <cmath>
+#include "dsconfig.h"
+#include "dsfilt.h"
+#include "dsurf.h"
+#include "winsys.h"
+#include "environ.h"
+#include "rc.h"
+#include "glutils.h"
+#include "stats.h"
+#include "tbinding.h"
+#include "misc.h"
+#endif
+
+namespace {
+
+bool
+makeCurrentOK(GLEAN::DrawingSurfaceConfig& config) {
+ using namespace GLEAN;
+ float expected[4];
+ glClear(GL_COLOR_BUFFER_BIT);
+ glGetFloatv(GL_COLOR_CLEAR_VALUE, expected);
+ Image probe(1, 1, GL_RGBA, GL_FLOAT);
+ probe.read(drawingSize/2, drawingSize/2);
+ const float* actual = reinterpret_cast<float*>(probe.pixels());
+ double maxError = ErrorBits(fabs(expected[0] - actual[0]), config.r);
+ maxError = max(maxError,
+ ErrorBits(fabs(expected[1] - actual[1]), config.g));
+ maxError = max(maxError,
+ ErrorBits(fabs(expected[2] - actual[2]), config.b));
+ return maxError <= 1.0;
+} // makeCurrentOK
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+MakeCurrentTest::runOne(MakeCurrentResult& r, Window& w) {
+
+ DrawingSurfaceConfig& config = *(r.config);
+ WindowSystem& ws = env->winSys;
+
+ // The rendering contexts to be used:
+ vector<RenderingContext*> rcs;
+ // Short descriptions of the rendering contexts:
+
+ RandomBitsDouble rRand(config.r, 712105);
+ RandomBitsDouble gRand(config.g, 63230);
+ RandomBitsDouble bRand(config.b, 912167);
+
+ // Create rendering contexts to be used with the test window.
+ // Note that the first context (at index 0) is always the
+ // null context.
+
+ rcs.push_back(0);
+ r.descriptions.push_back("Null context");
+ ws.makeCurrent();
+ r.testSequence.push_back(static_cast<int>(rcs.size()) - 1);
+
+ rcs.push_back(new RenderingContext(env->winSys, config, 0, true));
+ r.descriptions.push_back("Direct-rendering context");
+ ws.makeCurrent(*rcs.back(), w);
+ r.testSequence.push_back(static_cast<int>(rcs.size()) - 1);
+ glDisable(GL_DITHER);
+ glClearColor(rRand.next(), gRand.next(), bRand.next(), 1.0);
+ if (!makeCurrentOK(config))
+ goto failed;
+
+ rcs.push_back(new RenderingContext(env->winSys, config, 0, false));
+ r.descriptions.push_back("Indirect-rendering context");
+ ws.makeCurrent(*rcs.back(), w);
+ r.testSequence.push_back(static_cast<int>(rcs.size()) - 1);
+ glDisable(GL_DITHER);
+ glClearColor(rRand.next(), gRand.next(), bRand.next(), 1.0);
+ if (!makeCurrentOK(config))
+ goto failed;
+
+ // Now run through all the pairs of rendering contexts, making
+ // them current in sequence and checking that rendering looks
+ // correct. Don't worry about the redundant sequences; we want
+ // to check those, too!
+
+ int i;
+ for (i = 0; i < static_cast<int>(rcs.size()); ++i)
+ for (int j = 0; j < static_cast<int>(rcs.size()); ++j) {
+ r.testSequence.push_back(i);
+ if (rcs[i] == 0)
+ ws.makeCurrent();
+ else {
+ ws.makeCurrent(*rcs[i], w);
+ if (!makeCurrentOK(config))
+ goto failed;
+ }
+ r.testSequence.push_back(j);
+ if (rcs[j] == 0)
+ ws.makeCurrent();
+ else {
+ ws.makeCurrent(*rcs[j], w);
+ if (!makeCurrentOK(config))
+ goto failed;
+ }
+ }
+ r.pass = true;
+ goto cleanup;
+
+failed:
+ r.pass = false;
+cleanup:
+ for (i = 0; i < static_cast<int>(rcs.size()); ++i)
+ if (rcs[i])
+ delete rcs[i];
+} // MakeCurrentTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+MakeCurrentTest::logOne(MakeCurrentResult& r) {
+ logPassFail(r);
+ logConcise(r);
+ if (!r.pass) {
+ env->log << "\tSequence of MakeCurrent operations was:\n";
+ for (int k = 0; k < static_cast<int>(r.testSequence.size()); ++k)
+ env->log << "\t\t"
+ << r.descriptions[r.testSequence[k]]
+ << '\n';
+ }
+} // MakeCurrentTestTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+MakeCurrentTest::compareOne(MakeCurrentResult& oldR, MakeCurrentResult& newR) {
+ comparePassFail(oldR, newR);
+} // MakeCurrentTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+MakeCurrentTest makeCurrentTest("makeCurrent", "window, rgb",
+
+ "This test sanity-checks the ability to use multiple rendering\n"
+ "contexts. It creates several contexts with differing\n"
+ "characteristics (e.g., some are direct-rendering and some\n"
+ "are indirect-rendering, if the window system binding supports\n"
+ "that distinction). Then it runs through all pairs of contexts,\n"
+ "making each one \"current\" in turn and verifying that simple\n"
+ "rendering succeeds.\n"
+
+ );
+
+} // namespace GLEAN
diff --git a/tests/glean/tbinding.h b/tests/glean/tbinding.h
new file mode 100644
index 00000000..835bf7a3
--- /dev/null
+++ b/tests/glean/tbinding.h
@@ -0,0 +1,73 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// tbinding.h: Test functions in the window-system binding
+
+#ifndef __tbinding_h__
+#define __tbinding_h__
+
+#include "tbasic.h"
+
+class DrawingSurfaceConfig; // Forward reference.
+class GLEAN::Window;
+
+namespace GLEAN {
+
+#define drawingSize 64
+
+class MakeCurrentResult: public BaseResult {
+public:
+ bool pass;
+ // Short descriptions of the rendering contexts:
+ vector<const char*> descriptions;
+ // Complete record of rendering contexts made "current" during
+ // the test:
+ vector<int> testSequence;
+
+ void putresults(ostream& s) const {
+ s << pass << '\n';
+ }
+
+ bool getresults(istream& s) {
+ s >> pass;
+ return s.good();
+ }
+};
+
+class MakeCurrentTest: public BaseTest<MakeCurrentResult> {
+public:
+ GLEAN_CLASS_WH(MakeCurrentTest, MakeCurrentResult,
+ drawingSize, drawingSize);
+}; // class MakeCurrentTest
+
+} // namespace GLEAN
+
+#endif // __tbinding_h__
diff --git a/tests/glean/tblend.cpp b/tests/glean/tblend.cpp
new file mode 100644
index 00000000..87d0934d
--- /dev/null
+++ b/tests/glean/tblend.cpp
@@ -0,0 +1,621 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tblend.cpp: Test blending functions.
+
+#include "tblend.h"
+#include "rand.h"
+#include "image.h"
+#include <cmath>
+
+namespace {
+
+struct factorNameMapping {GLenum factor; char* name;};
+factorNameMapping factorNames[] = {
+ {GL_DST_ALPHA, "GL_DST_ALPHA"},
+ {GL_DST_COLOR, "GL_DST_COLOR"},
+ {GL_ONE, "GL_ONE"},
+ {GL_ONE_MINUS_DST_ALPHA, "GL_ONE_MINUS_DST_ALPHA"},
+ {GL_ONE_MINUS_DST_COLOR, "GL_ONE_MINUS_DST_COLOR"},
+ {GL_ONE_MINUS_SRC_ALPHA, "GL_ONE_MINUS_SRC_ALPHA"},
+ {GL_ONE_MINUS_SRC_COLOR, "GL_ONE_MINUS_SRC_COLOR"},
+ {GL_SRC_ALPHA, "GL_SRC_ALPHA"},
+ {GL_SRC_ALPHA_SATURATE, "GL_SRC_ALPHA_SATURATE"},
+ {GL_SRC_COLOR, "GL_SRC_COLOR"},
+ {GL_ZERO, "GL_ZERO"}
+};
+
+char*
+factorToName(GLenum factor) {
+ for (unsigned int i = 0;
+ i < sizeof(factorNames) / sizeof(factorNames[0]);
+ ++i)
+ if (factorNames[i].factor == factor)
+ return factorNames[i].name;
+ return 0;
+} // factorToName
+
+GLenum
+nameToFactor(string& name) {
+ for (unsigned int i = 0;
+ i < sizeof(factorNames) / sizeof(factorNames[0]);
+ ++i)
+ if (factorNames[i].name == name)
+ return factorNames[i].factor;
+ return GL_ZERO;
+} // nameToFactor
+
+bool
+needsDstAlpha(const GLenum func) {
+ return func == GL_DST_ALPHA || func == GL_ONE_MINUS_DST_ALPHA
+ || func == GL_SRC_ALPHA_SATURATE;
+}
+
+void
+makeRGBA(GLEAN::RandomBitsDouble& rRand,
+ GLEAN::RandomBitsDouble& gRand,
+ GLEAN::RandomBitsDouble& bRand,
+ GLEAN::RandomBitsDouble& aRand,
+ float* rgba) {
+ rgba[0] = rRand.next();
+ rgba[1] = gRand.next();
+ rgba[2] = bRand.next();
+ rgba[3] = aRand.next();
+} // makeRGBA
+
+void
+drawQuad(const int x, const int y, const float* color) {
+ glColor4fv(color);
+ glBegin(GL_QUADS);
+ glVertex2i(x, y);
+ glVertex2i(x + 1, y);
+ glVertex2i(x + 1, y + 1);
+ glVertex2i(x, y + 1);
+ glEnd();
+} // drawQuad
+
+inline float
+clamp(float f) {
+ if (f < 0.0)
+ return 0.0;
+ else if (f > 1.0)
+ return 1.0;
+ else
+ return f;
+} // clamp
+
+void
+applyBlend(GLenum srcFactor, GLenum dstFactor, float* dst, float* src) {
+ // XXX Currently we don't test any of the const-color blend factors.
+ // It would be a good idea to do so as soon as we have access to an
+ // implementation that supports the OpenGL 1.2 imaging extensions.
+
+ float sf[4];
+ switch (srcFactor) {
+ case GL_ZERO:
+ sf[0] = sf[1] = sf[2] = sf[3] = 0.0;
+ break;
+ case GL_ONE:
+ sf[0] = sf[1] = sf[2] = sf[3] = 1.0;
+ break;
+ case GL_DST_COLOR:
+ sf[0] = dst[0]; sf[1] = dst[1]; sf[2] = dst[2]; sf[3] = dst[3];
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ sf[0] = 1.0 - dst[0]; sf[1] = 1.0 - dst[1];
+ sf[2] = 1.0 - dst[2]; sf[3] = 1.0 - dst[3];
+ break;
+ case GL_SRC_ALPHA:
+ sf[0] = sf[1] = sf[2] = sf[3] = src[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ sf[0] = sf[1] = sf[2] = sf[3] = 1.0 - src[3];
+ break;
+ case GL_DST_ALPHA:
+ sf[0] = sf[1] = sf[2] = sf[3] = dst[3];
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ sf[0] = sf[1] = sf[2] = sf[3] = 1.0 - dst[3];
+ break;
+ case GL_SRC_ALPHA_SATURATE: {
+ float f = 1.0 - dst[3];
+ if (src[3] < f)
+ f = src[3];
+ sf[0] = sf[1] = sf[2] = f; sf[3] = 1.0;
+ }
+ break;
+ default:
+ sf[0] = sf[1] = sf[2] = sf[3] = 0.0;
+ break;
+ }
+
+ float df[4];
+ switch (dstFactor) {
+ case GL_ZERO:
+ df[0] = df[1] = df[2] = df[3] = 0.0;
+ break;
+ case GL_ONE:
+ df[0] = df[1] = df[2] = df[3] = 1.0;
+ break;
+ case GL_SRC_COLOR:
+ df[0] = src[0]; df[1] = src[1]; df[2] = src[2]; df[3] = src[3];
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ df[0] = 1.0 - src[0]; df[1] = 1.0 - src[1];
+ df[2] = 1.0 - src[2]; df[3] = 1.0 - src[3];
+ break;
+ case GL_SRC_ALPHA:
+ df[0] = df[1] = df[2] = df[3] = src[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ df[0] = df[1] = df[2] = df[3] = 1.0 - src[3];
+ break;
+ case GL_DST_ALPHA:
+ df[0] = df[1] = df[2] = df[3] = dst[3];
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ df[0] = df[1] = df[2] = df[3] = 1.0 - dst[3];
+ break;
+ default:
+ df[0] = df[1] = df[2] = df[3] = 0.0;
+ break;
+ }
+
+ dst[0] = clamp(src[0] * sf[0] + dst[0] * df[0]);
+ dst[1] = clamp(src[1] * sf[1] + dst[1] * df[1]);
+ dst[2] = clamp(src[2] * sf[2] + dst[2] * df[2]);
+ dst[3] = clamp(src[3] * sf[3] + dst[3] * df[3]);
+} // applyBlend
+
+struct runFactorsResult {
+ float readbackErrorBits;
+ float blendRGBErrorBits;
+ float blendAlphaErrorBits;
+};
+
+runFactorsResult
+runFactors(GLenum srcFactor, GLenum dstFactor,
+ GLEAN::DrawingSurfaceConfig& config, GLEAN::Environment& env,
+ float rgbTolerance, float alphaTolerance) {
+ using namespace GLEAN;
+
+ runFactorsResult result;
+ int y;
+
+ glDisable(GL_DITHER);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ Image dst(drawingSize, drawingSize, GL_RGBA, GL_FLOAT);
+ RandomBitsDouble rRand(config.r, 6021023);
+ RandomBitsDouble gRand(config.g, 1137);
+ RandomBitsDouble bRand(config.b, 1138);
+ RandomBitsDouble dstARand(config.a? config.a: 1, 6);
+
+ // Fill the framebuffer with random RGBA values, and place a copy
+ // in ``dst'':
+ glDisable(GL_BLEND);
+ char* dRow = dst.pixels();
+ for (/*int */y = 0; y < drawingSize; ++y) {
+ float* pix = reinterpret_cast<float*>(dRow);
+ for (int x = 0; x < drawingSize; ++x) {
+ float rgba[4];
+ makeRGBA(rRand, gRand, bRand, dstARand, rgba);
+ if (!config.a)
+ rgba[3] = 1.0;
+ drawQuad(x + 1, y + 1, rgba);
+ pix[0] = rgba[0];
+ pix[1] = rgba[1];
+ pix[2] = rgba[2];
+ pix[3] = rgba[3];
+ pix += 4;
+ }
+ dRow += dst.rowSizeInBytes();
+ }
+
+ // Read back the contents of the framebuffer, and measure any
+ // difference from what was actually written. We can't tell
+ // whether errors occurred when writing or when reading back,
+ // but at least we can report anything unusual.
+ Image fbDst(drawingSize, drawingSize, GL_RGBA, GL_FLOAT);
+ fbDst.read(1, 1);
+ Image::Registration reg1(fbDst.reg(dst));
+ result.readbackErrorBits =
+ max(ErrorBits(reg1.stats[0].max(), config.r),
+ max(ErrorBits(reg1.stats[1].max(), config.g),
+ max(ErrorBits(reg1.stats[2].max(), config.b),
+ ErrorBits(reg1.stats[3].max(), config.a))));
+
+ // Now generate random source pixels and apply the blending
+ // operation to both the framebuffer and a copy in the image
+ // ``expected''. Note that a fresh source alpha must be
+ // generated here, because the range of source alpha values is
+ // not limited by the range of alpha values that can be
+ // represented in the framebuffer. Save the source pixels in
+ // the image ``src'' so we can diagnose any problems we find
+ // later.
+ Image expected(dst);
+ Image src(drawingSize, drawingSize, GL_RGBA, GL_FLOAT);
+ RandomBitsDouble srcARand(16, 42);
+
+ glBlendFunc(srcFactor, dstFactor);
+ glEnable(GL_BLEND);
+
+ dRow = expected.pixels();
+ char* sRow = src.pixels();
+ for (/*int */y = 0; y < drawingSize; ++y) {
+ float* pix = reinterpret_cast<float*>(dRow);
+ float* sPix = reinterpret_cast<float*>(sRow);
+ for (int x = 0; x < drawingSize; ++x) {
+ float rgba[4];
+ makeRGBA(rRand, gRand, bRand, srcARand, rgba);
+ sPix[0] = rgba[0];
+ sPix[1] = rgba[1];
+ sPix[2] = rgba[2];
+ sPix[3] = rgba[3];
+ drawQuad(x + 1, y + 1, rgba);
+ applyBlend(srcFactor, dstFactor, pix, rgba);
+ pix += 4;
+ sPix += 4;
+ }
+ dRow += expected.rowSizeInBytes();
+ sRow += src.rowSizeInBytes();
+ }
+
+ // Read the generated image (``actual'') and compare it to the
+ // computed image (``expected'') to see if any pixels are
+ // outside the expected tolerance range (one LSB). If so,
+ // report the first such pixel, along with the source and
+ // destination values that generated it. Keep track of the
+ // maximum error encountered.
+ Image actual(drawingSize, drawingSize, GL_RGBA, GL_FLOAT);
+ actual.read(1, 1);
+ result.blendRGBErrorBits = 0.0;
+ result.blendAlphaErrorBits = 0.0;
+ sRow = actual.pixels();
+ dRow = expected.pixels();
+ for (/*int */y = 0; y < drawingSize; ++y) {
+ float* aPix = reinterpret_cast<float*>(sRow);
+ float* ePix = reinterpret_cast<float*>(dRow);
+ for (int x = 0; x < drawingSize; ++x) {
+ float rError = fabs(aPix[0] - ePix[0]);
+ float gError = fabs(aPix[1] - ePix[1]);
+ float bError = fabs(aPix[2] - ePix[2]);
+ float aError = fabs(aPix[3] - ePix[3]);
+ result.blendRGBErrorBits =
+ max(static_cast<double>(result.blendRGBErrorBits),
+ max(ErrorBits(rError, config.r),
+ max(ErrorBits(gError, config.g),
+ ErrorBits(bError, config.b))));
+ result.blendAlphaErrorBits =
+ max(static_cast<double>(result.blendAlphaErrorBits),
+ ErrorBits(aError, config.a));
+ if (result.blendRGBErrorBits > rgbTolerance || result.blendAlphaErrorBits > alphaTolerance) {
+ if (env.options.verbosity) {
+float* sPix = reinterpret_cast<float*>(src.pixels()
+ + y * src.rowSizeInBytes() + x * 4 * sizeof(float));
+float* dPix = reinterpret_cast<float*>(dst.pixels()
+ + y * dst.rowSizeInBytes() + x * 4 * sizeof(float));
+env.log << '\n'
+<< "First failing pixel is at row " << y << " column " << x << "\n"
+<< "Actual values are (" << aPix[0] << ", " << aPix[1] << ", " << aPix[2]
+ << ", " << aPix[3] << ")\n"
+<< "Expected values are (" << ePix[0] << ", " << ePix[1] << ", " << ePix[2]
+ << ", " << ePix[3] << ")\n"
+<< "Errors are (" << rError << ", " << gError << ", " << bError << ", "
+ << aError << ")\n"
+<< "Source values are (" << sPix[0] << ", " << sPix[1] << ", " << sPix[2]
+ << ", " << sPix[3] << ")\n"
+<< "Destination values are (" << dPix[0] << ", " << dPix[1] << ", " << dPix[2]
+ << ", " << dPix[3] << ")\n";
+ }
+ return result;
+ }
+ aPix += 4;
+ ePix += 4;
+ }
+ sRow += actual.rowSizeInBytes();
+ dRow += expected.rowSizeInBytes();
+ }
+
+ return result;
+} // runOneSet
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncTest::runOne(BlendFuncResult& r, Window& w) {
+ GLUtils::useScreenCoords(drawingSize + 2, drawingSize + 2);
+
+ static GLenum srcFactors[] = {
+ GL_ZERO,
+ GL_ONE,
+ GL_DST_COLOR,
+ GL_ONE_MINUS_DST_COLOR,
+ GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA,
+ GL_DST_ALPHA,
+ GL_ONE_MINUS_DST_ALPHA,
+ GL_SRC_ALPHA_SATURATE
+ };
+ static GLenum dstFactors[] = {
+ GL_ZERO,
+ GL_ONE,
+ GL_SRC_COLOR,
+ GL_ONE_MINUS_SRC_COLOR,
+ GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA,
+ GL_DST_ALPHA,
+ GL_ONE_MINUS_DST_ALPHA
+ };
+
+ // Hack: Make driver tests on incorrect hardware feasible
+ // by adjusting the error tolerance to whatever the hardware can do
+ float rgbTolerance = 1.0;
+ float alphaTolerance = 1.0;
+ const char* s;
+
+ s = getenv("GLEAN_BLEND_RGB_TOLERANCE");
+ if (s) {
+ rgbTolerance = atof(s);
+ env->log << "Note: RGB tolerance adjusted to " << rgbTolerance << "\n";
+ }
+ s = getenv("GLEAN_BLEND_ALPHA_TOLERANCE");
+ if (s) {
+ alphaTolerance = atof(s);
+ env->log << "Note: Alpha tolerance adjusted to " << alphaTolerance << "\n";
+ }
+
+ bool allPassed = true;
+ for (unsigned int sf = 0; sf < sizeof(srcFactors)/sizeof(srcFactors[0]);
+ ++sf)
+
+ for (unsigned int df = 0;
+ df < sizeof(dstFactors)/sizeof(dstFactors[0]); ++df) {
+
+ BlendFuncResult::PartialResult p;
+ p.src = srcFactors[sf];
+ p.dst = dstFactors[df];
+
+ if ((needsDstAlpha(p.src) || needsDstAlpha(p.dst))
+ && (r.config->a == 0))
+ continue;
+
+ runFactorsResult res(runFactors(p.src, p.dst,
+ *(r.config), *env, rgbTolerance, alphaTolerance));
+ w.swap();
+
+ p.rbErr = res.readbackErrorBits;
+ p.blRGBErr = res.blendRGBErrorBits;
+ p.blAErr = res.blendAlphaErrorBits;
+ r.results.push_back(p);
+
+ if (p.rbErr > 1.0 || p.blRGBErr > rgbTolerance || p.blAErr > alphaTolerance) {
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription()<< '\n'
+ << "\tsource factor = "
+ << factorToName(p.src)
+ << ", dest factor = "
+ << factorToName(p.dst)
+ << "\n\tReadback had " << p.rbErr
+ << " bits in error; RGB blending had "
+ << p.blRGBErr << " bits in error, Alpha blending had "
+ << p.blAErr << " bits in error.\n";
+ allPassed = false;
+ }
+ }
+
+ r.pass = allPassed;
+} // BlendFuncTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncTest::logOne(BlendFuncResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncTest::compareOne(BlendFuncResult& oldR, BlendFuncResult& newR) {
+ BasicStats readbackStats;
+ BasicStats blendStats;
+
+ vector<BlendFuncResult::PartialResult>::const_iterator np;
+ vector<BlendFuncResult::PartialResult>::const_iterator op;
+
+ for (np = newR.results.begin(); np != newR.results.end(); ++np)
+ // Find the matching case, if any, in the old results:
+ for (op = oldR.results.begin(); op != oldR.results.end(); ++op)
+ if (np->src == op->src && np->dst == op->dst) {
+ readbackStats.sample(np->rbErr - op->rbErr);
+ blendStats.sample(np->blRGBErr - op->blRGBErr);
+ blendStats.sample(np->blAErr - op->blAErr);
+ }
+
+ if (readbackStats.n() == static_cast<int>(newR.results.size())
+ && newR.results.size() == oldR.results.size()
+ && readbackStats.mean() == 0.0 && blendStats.mean() == 0.0) {
+ if (env->options.verbosity)
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription() << '\n';
+ } else {
+ env->log << name << ": DIFF "
+ << newR.config->conciseDescription() << '\n';
+
+ if (readbackStats.mean() < 0.0)
+ env->log << '\t' << env->options.db2Name
+ << " appears to have more accurate readback.\n";
+ else if (readbackStats.mean() > 0.0)
+ env->log << '\t' << env->options.db1Name
+ << " appears to have more accurate readback.\n";
+ if (blendStats.mean() < 0.0)
+ env->log << '\t' << env->options.db2Name
+ << " appears to have more accurate blending.\n";
+ else if (blendStats.mean() > 0.0)
+ env->log << '\t' << env->options.db1Name
+ << " appears to have more accurate blending.\n";
+ if (readbackStats.n() != static_cast<int>(newR.results.size())){
+ env->log << "\tThe following cases in "
+ << env->options.db2Name
+ << " have no matching test in "
+ << env->options.db1Name
+ << ":\n";
+ for (np = newR.results.begin();
+ np != newR.results.end(); ++np) {
+ for (op = oldR.results.begin();
+ op != oldR.results.end(); ++op)
+ if (np->src == op->src
+ && np->dst == op->dst)
+ break;
+ if (op == oldR.results.end())
+ env->log << "\t\t"
+ << factorToName(np->src)
+ << ' '
+ << factorToName(np->dst)
+ << '\n';
+ }
+ }
+ if (readbackStats.n() != static_cast<int>(oldR.results.size())){
+ env->log << "\tThe following cases in "
+ << env->options.db1Name
+ << " have no matching test in "
+ << env->options.db2Name
+ << ":\n";
+ for (op = oldR.results.begin();
+ op != oldR.results.end(); ++op) {
+ for (np = newR.results.begin();
+ np != newR.results.end(); ++np)
+ if (op->src == np->src
+ && op->dst == np->dst)
+ break;
+ if (np == newR.results.end())
+ env->log << "\t\t"
+ << factorToName(op->src)
+ << ' '
+ << factorToName(op->dst)
+ << '\n';
+ }
+ }
+ if (env->options.verbosity) {
+ env->log << "\tThe following cases appear in both "
+ << env->options.db1Name
+ << " and "
+ << env->options.db2Name
+ << ":\n";
+ for (np = newR.results.begin();
+ np != newR.results.end(); ++np){
+ for (op = oldR.results.begin();
+ op != oldR.results.end(); ++op)
+ if (np->src == op->src
+ && np->dst == op->dst)
+ break;
+ if (op != oldR.results.end())
+ env->log << "\t\t"
+ << factorToName(np->src)
+ << ' '
+ << factorToName(np->dst)
+ << '\n';
+ }
+ }
+ }
+} // BlendFuncTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// Result I/O functions:
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncResult::putresults(ostream& s) const {
+ s << results.size() << '\n';
+ for (vector<PartialResult>::const_iterator p = results.begin();
+ p != results.end(); ++p)
+ s << factorToName(p->src) << ' '
+ << factorToName(p->dst) << ' '
+ << p->rbErr << ' ' << p->blRGBErr << ' ' << p->blAErr << '\n';
+} // BlendFuncResult::put
+
+bool
+BlendFuncResult::getresults(istream& s) {
+ int n;
+ s >> n;
+ for (int i = 0; i < n; ++i) {
+ PartialResult p;
+ string src;
+ string dst;
+ s >> src >> dst >> p.rbErr >> p.blRGBErr >> p.blAErr;
+ p.src = nameToFactor(src);
+ p.dst = nameToFactor(dst);
+ results.push_back(p);
+ }
+
+ return s.good();
+} // BlendFuncResult::get
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+BlendFuncTest blendFuncTest("blendFunc", "window, rgb",
+
+ "This test checks all combinations of source and destination\n"
+ "blend factors for the GL_FUNC_ADD blend equation. It operates\n"
+ "on all RGB or RGBA drawing surface configurations that support\n"
+ "the creation of windows.\n"
+ "\n"
+ "Note that a common cause of failures for this test is small errors\n"
+ "introduced when an implementation scales color values incorrectly;\n"
+ "for example, converting an 8-bit color value to float by\n"
+ "dividing by 256 rather than 255, or computing a blending result\n"
+ "by shifting a double-width intermediate value rather than scaling\n"
+ "it. Also, please note that the OpenGL spec requires that when\n"
+ "converting from floating-point colors to integer form, the result\n"
+ "must be rounded to the nearest integer, not truncated.\n"
+ "[1.2.1, 2.13.9]\n"
+ "\n"
+ "The test reports two error measurements. The first (readback) is\n"
+ "the error detected when reading back raw values that were written\n"
+ "to the framebuffer. The error in this case should be very close\n"
+ "to zero, since the values are carefully constructed so that they\n"
+ "can be represented accurately in the framebuffer. The second\n"
+ "(blending) is the error detected in the result of the blending\n"
+ "computation. For the test to pass, these errors must both be\n"
+ "no greater than one least-significant bit in the framebuffer\n"
+ "representation of a color.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tblend.h b/tests/glean/tblend.h
new file mode 100644
index 00000000..5a83902c
--- /dev/null
+++ b/tests/glean/tblend.h
@@ -0,0 +1,69 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tblend.h: Test blending functions.
+
+#ifndef __tblend_h__
+#define __tblend_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define drawingSize 64 // We will check each pair of blend factors
+ // for each pixel in a square image of this
+ // dimension, so if you make it too large,
+ // the tests may take quite a while to run.
+#define windowSize (drawingSize + 2)
+
+class BlendFuncResult: public BaseResult {
+public:
+ bool pass; // not written to log file
+
+ struct PartialResult {
+ GLenum src; // Source blend factor.
+ GLenum dst; // Destination blend factor.
+ float rbErr; // Max readback error, in bits.
+ float blRGBErr; // Max RGB blend error, in bits.
+ float blAErr; // Max Alpha blend error, in bits.
+ };
+ vector<PartialResult> results;
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+class BlendFuncTest: public BaseTest<BlendFuncResult> {
+public:
+ GLEAN_CLASS_WH(BlendFuncTest, BlendFuncResult,
+ windowSize, windowSize);
+}; // class BlendFuncTest
+
+} // namespace GLEAN
+
+#endif // __tblend_h__
diff --git a/tests/glean/tchgperf.cpp b/tests/glean/tchgperf.cpp
new file mode 100644
index 00000000..b943f53d
--- /dev/null
+++ b/tests/glean/tchgperf.cpp
@@ -0,0 +1,317 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tchgperf.cpp: Some basic tests of attribute-change performance.
+
+#include "tchgperf.h"
+#include <algorithm>
+#include "rand.h"
+#include "image.h"
+#include "timer.h"
+#include "geomutil.h"
+
+#if 0
+#ifdef __UNIX__
+#include <unistd.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+#include "dsconfig.h"
+#include "dsfilt.h"
+#include "dsurf.h"
+#include "winsys.h"
+#include "environ.h"
+#include "rc.h"
+#include "glutils.h"
+#include "timer.h"
+#include "tchgperf.h"
+#include "misc.h"
+#endif
+
+namespace {
+
+GLEAN::Image redImage(64, 64, GL_RGB, GL_UNSIGNED_BYTE, 1.0, 0.0, 0.0, 0.0);
+GLuint redTex;
+GLEAN::Image greenImage(64, 64, GL_RGB, GL_UNSIGNED_BYTE, 0.0, 1.0, 0.0, 0.0);
+GLuint greenTex;
+
+int nPoints;
+float* vertices;
+float* texCoords;
+
+void
+noBindDraw() {
+ int rowSize = 2 * nPoints;
+ for (int y = 0; y < nPoints - 1; ++y) {
+ float* t0 = texCoords + y * rowSize;
+ float* v0 = vertices + y * rowSize;
+ for (int x = 0; x < nPoints - 1; ++x) {
+ float* t1 = t0 + rowSize;
+ float* t2 = t1 + 2;
+ float* t3 = t0 + 2;
+ float* v1 = v0 + rowSize;
+ float* v2 = v1 + 2;
+ float* v3 = v0 + 2;
+
+ glBegin(GL_TRIANGLES);
+ glTexCoord2fv(t0);
+ glVertex2fv(v0);
+ glTexCoord2fv(t1);
+ glVertex2fv(v1);
+ glTexCoord2fv(t2);
+ glVertex2fv(v2);
+ glEnd();
+ glBegin(GL_TRIANGLES);
+ glTexCoord2fv(t2);
+ glVertex2fv(v2);
+ glTexCoord2fv(t3);
+ glVertex2fv(v3);
+ glTexCoord2fv(t0);
+ glVertex2fv(v0);
+ glEnd();
+
+ t0 += 2;
+ v0 += 2;
+ }
+ }
+} // noBindDraw
+
+void
+bindDraw() {
+ int rowSize = 2 * nPoints;
+ for (int y = 0; y < nPoints - 1; ++y) {
+ float* v0 = vertices + y * rowSize;
+ float* t0 = texCoords + y * rowSize;
+ for (int x = 0; x < nPoints - 1; ++x) {
+ float* t1 = t0 + rowSize;
+ float* t2 = t1 + 2;
+ float* t3 = t0 + 2;
+ float* v1 = v0 + rowSize;
+ float* v2 = v1 + 2;
+ float* v3 = v0 + 2;
+
+ glBindTexture(GL_TEXTURE_2D, redTex);
+ glBegin(GL_TRIANGLES);
+ glTexCoord2fv(t0);
+ glVertex2fv(v0);
+ glTexCoord2fv(t1);
+ glVertex2fv(v1);
+ glTexCoord2fv(t2);
+ glVertex2fv(v2);
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, greenTex);
+ glBegin(GL_TRIANGLES);
+ glTexCoord2fv(t2);
+ glVertex2fv(v2);
+ glTexCoord2fv(t3);
+ glVertex2fv(v3);
+ glTexCoord2fv(t0);
+ glVertex2fv(v0);
+ glEnd();
+
+ t0 += 2;
+ v0 += 2;
+ }
+ }
+} // BindDraw
+
+class BindDrawTimer: public GLEAN::Timer {
+ virtual void op() { bindDraw(); }
+ virtual void preop() { glFinish(); }
+ virtual void postop() { glFinish(); }
+};
+
+class NoBindDrawTimer: public GLEAN::Timer {
+ virtual void op() { noBindDraw(); }
+ virtual void preop() { glFinish(); }
+ virtual void postop() { glFinish(); }
+};
+
+void
+logStats(GLEAN::TexBindPerfResult& r, GLEAN::Environment* env) {
+ env->log << "\tApproximate texture binding time = " << r.bindTime
+ << " microseconds.\n\tRange of valid measurements = ["
+ << r.lowerBound << ", " << r.upperBound << "]\n";
+} // logStats
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+void
+TexBindPerf::runOne(TexBindPerfResult& r, Window& w) {
+ glGenTextures(1, &redTex);
+ glBindTexture(GL_TEXTURE_2D, redTex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ redImage.makeMipmaps(GL_RGB);
+
+ glGenTextures(1, &greenTex);
+ glBindTexture(GL_TEXTURE_2D, greenTex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ greenImage.makeMipmaps(GL_RGB);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+
+ GLUtils::useScreenCoords(drawingSize + 2, drawingSize + 2);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+
+ nPoints = drawingSize / 2; // Yields 1-pixel triangles.
+
+ RandomDouble vRand(142857);
+ RandomMesh2D v(1.0, drawingSize, nPoints, 1.0, drawingSize, nPoints,
+ vRand);
+ vertices = v(0, 0);
+
+ RandomDouble tRand(314159);
+ RandomMesh2D t(0.0, 1.0, nPoints, 0.0, 1.0, nPoints, tRand);
+ texCoords = t(0, 0);
+
+ int nTris = (nPoints - 1) * (nPoints - 1) / 2;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ BindDrawTimer bindDrawTimer;
+ NoBindDrawTimer noBindDrawTimer;
+
+ bindDrawTimer.calibrate();
+ noBindDrawTimer.calibrate();
+
+ vector<float> measurements;
+ for (int i = 0; i < 5; ++i) {
+ env->quiesce();
+ double tBind = bindDrawTimer.time();
+ w.swap(); // So the user can see something happening.
+
+ env->quiesce();
+ double tNoBind = noBindDrawTimer.time();
+ w.swap();
+
+ double bindTime = 1E6 * (tBind - tNoBind) / nTris;
+ if (bindTime < 0.0) {
+ // This can happen if the system isn't quiescent;
+ // some process sneaks in and takes wall-clock time
+ // when ``noBindDraw'' is running. Just flush it
+ // and try again. (Note: You really shouldn't be
+ // running timing tests on a system where other
+ // processes are active!)
+ --i;
+ continue;
+ }
+
+ measurements.push_back(bindTime);
+ }
+
+ sort(measurements.begin(), measurements.end());
+ r.bindTime = (measurements[1]+measurements[2]+measurements[3]) / 3.0;
+ r.lowerBound = measurements[1];
+ r.upperBound = measurements[3];
+ r.pass = true;
+} // TexBindPerf::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+TexBindPerf::logOne(TexBindPerfResult& r) {
+ logPassFail(r);
+ logConcise(r);
+ logStats(r, env);
+} // TexBindPerf::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+TexBindPerf::compareOne(TexBindPerfResult& oldR, TexBindPerfResult& newR) {
+ if (newR.bindTime < oldR.lowerBound) {
+ int percent = static_cast<int>(
+ 100.0 * (oldR.bindTime - newR.bindTime) / newR.bindTime
+ + 0.5);
+ env->log << name << ": DIFF "
+ << newR.config->conciseDescription() << '\n'
+ << '\t' << env->options.db2Name << " may be "
+ << percent << "% faster.\n";
+ } else if (newR.bindTime > oldR.upperBound) {
+ int percent = static_cast<int>(
+ 100.0 * (newR.bindTime - oldR.bindTime) / oldR.bindTime
+ + 0.5);
+ env->log << name << ": DIFF "
+ << oldR.config->conciseDescription() << '\n'
+ << '\t' << env->options.db1Name << " may be "
+ << percent << "% faster.\n";
+ } else {
+ if (env->options.verbosity)
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n\t"
+ << env->options.db2Name
+ << " test time falls within the "
+ << "valid measurement range of "
+ << env->options.db1Name
+ << " test time.\n";
+ }
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR, env);
+ env->log << env->options.db2Name << ':';
+ logStats(newR, env);
+ }
+} // TexBindPerf::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+TexBindPerf texBindPerfTest("texBindPerf", "window, rgb, z",
+
+ "This test makes a rough estimate of the cost of a glBindTexture()\n"
+ "operation, expressed in microseconds.\n"
+ "\n"
+ "Since the apparent cost of a texture bind is dependent on many\n"
+ "factors (including the fraction of the texture map that's actually\n"
+ "used for drawing, on machines that cache textures; texture map\n"
+ "size; texel format; etc.), a general-purpose test can only estimate\n"
+ "it. In this test we do so by drawing random triangles of very\n"
+ "small size, and reporting simple statistics concerning the cost.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tchgperf.h b/tests/glean/tchgperf.h
new file mode 100644
index 00000000..11f3bd7e
--- /dev/null
+++ b/tests/glean/tchgperf.h
@@ -0,0 +1,72 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// tchgperf.h: Some basic tests of attribute-change performance.
+
+#ifndef __tchgperf_h__
+#define __tchgperf_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define drawingSize 128 // must be power-of-2, 128 or greater
+
+class TexBindPerfResult: public BaseResult {
+public:
+ bool pass;
+ double bindTime;
+ double lowerBound;
+ double upperBound;
+
+ TexBindPerfResult() { bindTime = lowerBound = upperBound = 0.0; }
+
+ void putresults(ostream& s) const {
+ s << bindTime
+ << ' ' << lowerBound
+ << ' ' << upperBound
+ << '\n';
+ }
+
+ bool getresults(istream& s) {
+ s >> bindTime >> lowerBound >> upperBound;
+ return s.good();
+ }
+
+};
+
+class TexBindPerf: public BaseTest<TexBindPerfResult> {
+public:
+ GLEAN_CLASS_WH(TexBindPerf, TexBindPerfResult,
+ drawingSize, drawingSize);
+}; // class TexBindPerf
+
+} // namespace GLEAN
+
+#endif // __tchgperf_h__
diff --git a/tests/glean/tdepthstencil.cpp b/tests/glean/tdepthstencil.cpp
new file mode 100644
index 00000000..f691d2cf
--- /dev/null
+++ b/tests/glean/tdepthstencil.cpp
@@ -0,0 +1,422 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tdepthstencil.h: Test GL_EXT_packed_depth_stencil extension.
+// Brian Paul 1 October 2005
+
+
+#include "tdepthstencil.h"
+#include "rand.h"
+#include "timer.h"
+#include "image.h"
+#include <cassert>
+#include <cmath>
+
+#ifdef GL_EXT_packed_depth_stencil
+
+namespace GLEAN {
+
+static PFNGLWINDOWPOS2IARBPROC WindowPos2i = NULL;
+
+
+bool
+DepthStencilTest::checkError(const char *where)
+{
+ GLenum err = glGetError();
+ if (err) {
+ errorCode = err;
+ errorPos = where;
+ return true;
+ }
+ return false;
+}
+
+void
+DepthStencilTest::setup(void)
+{
+ glGetIntegerv(GL_DEPTH_BITS, &depthBits);
+ glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
+
+ WindowPos2i = (PFNGLWINDOWPOS2IARBPROC)
+ GLUtils::getProcAddress("glWindowPos2iARB");
+ assert(WindowPos2i);
+}
+
+
+// If we're lacking a depth and/or stencil buffer we'll just run this test.
+// Return true if pass, false if fail.
+bool
+DepthStencilTest::testInsufficientVisual(void)
+{
+ GLuint p[1];
+
+ glDrawPixels(1, 1, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, p);
+ if (glGetError() != GL_INVALID_OPERATION) {
+ sprintf(errorMsg,
+ "glDrawPixels failed to raise GL_INVALID_OPERATION"
+ " when there's no depth or stencil buffer.");
+ return false;
+ }
+
+ glCopyPixels(0, 0, 5, 5, GL_DEPTH_STENCIL_EXT);
+ if (glGetError() != GL_INVALID_OPERATION) {
+ sprintf(errorMsg,
+ "glCopyPixels failed to raise GL_INVALID_OPERATION"
+ " when there's no depth or stencil buffer.");
+ return false;
+ }
+
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT,
+ 0, 0, 1, 1, 0);
+ if (glGetError() != GL_INVALID_OPERATION) {
+ sprintf(errorMsg,
+ "glCopyTexImage2D failed to raise GL_INVALID_OPERATION"
+ " when there's no depth or stencil buffer.");
+ return false;
+ }
+
+ return true;
+}
+
+
+// Each of these OpenGL calls in this function should generate an error!
+// Note to GL implementors: if you find any errors here, you better check
+// your glTexImage functions too!
+bool
+DepthStencilTest::testErrorDetection(void)
+{
+ GLuint p[1];
+
+ glDrawPixels(1, 1, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT, p);
+ if (glGetError() != GL_INVALID_ENUM) {
+ sprintf(errorMsg,
+ "glDrawPixels(GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT)"
+ " failed to generate GL_INVALID_ENUM.");
+ return false;
+ }
+
+ glDrawPixels(1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_EXT, p);
+ if (glGetError() != GL_INVALID_OPERATION) {
+ sprintf(errorMsg,
+ "glDrawPixels(GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_EXT)"
+ " failed to generate GL_INVALID_OPERATION.");
+ return false;
+ }
+
+ glReadPixels(0, 0, 1, 1, GL_DEPTH_STENCIL_EXT, GL_FLOAT, p);
+ if (glGetError() != GL_INVALID_ENUM) {
+ sprintf(errorMsg,
+ "glReadPixels(GL_DEPTH_STENCIL_EXT, GL_FLOAT)"
+ " failed to generate GL_INVALID_ENUM.");
+ return false;
+ }
+
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_INT_24_8_EXT, p);
+ if (glGetError() != GL_INVALID_OPERATION) {
+ sprintf(errorMsg,
+ "glReadPixels(GL_STENCIL_INDEX, GL_UNSIGNED_INT_24_8_EXT)"
+ " failed to generate GL_INVALID_OPERATION.");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
+DepthStencilTest::testDrawAndRead(void)
+{
+ // the reference image
+ static const GLuint image[4] = {
+ 0x00000000,
+ 0x000000ff,
+ 0xffffff00,
+ 0xffffffff
+ };
+ GLuint readback[4];
+
+ WindowPos2i(0, 0);
+ glDrawPixels(2, 2, GL_DEPTH_STENCIL_EXT,
+ GL_UNSIGNED_INT_24_8_EXT, image);
+ if (checkError("glDrawPixels in testDrawAndRead"))
+ return false;
+
+ glReadPixels(0, 0, 2, 2, GL_DEPTH_STENCIL_EXT,
+ GL_UNSIGNED_INT_24_8_EXT, readback);
+ if (checkError("glReadPixels in testDrawAndRead"))
+ return false;
+
+ for (int i = 0; i < 4; i++) {
+ if (image[i] != readback[i]) {
+ sprintf(errorMsg,
+ "Image returned by glReadPixels didn't match"
+ " the expected result (0x%x != 0x%x)",
+ readback[i], image[i]);
+ return false;
+ }
+ }
+
+ // test depth scale/bias and stencil mapping (in a trivial way)
+ glPixelTransferf(GL_DEPTH_SCALE, 0.0); // map all depths to 1.0
+ glPixelTransferf(GL_DEPTH_BIAS, 1.0);
+ GLuint stencilMap[2] = { 2, 2 }; // map all stencil values to 2
+ glPixelMapuiv(GL_PIXEL_MAP_S_TO_S, 2, stencilMap);
+ glPixelTransferi(GL_MAP_STENCIL, 1);
+ glReadPixels(0, 0, 2, 2, GL_DEPTH_STENCIL_EXT,
+ GL_UNSIGNED_INT_24_8_EXT, readback);
+ if (checkError("glReadPixels in testDrawAndRead"))
+ return false;
+ for (int i = 0; i < 4; i++) {
+ if (readback[i] != 0xffffff02) {
+ sprintf(errorMsg,
+ "Image returned by glReadPixels didn't match"
+ " the expected result (0x%x != 0xffffff02)",
+ readback[i]);
+ return false;
+ }
+ }
+ glPixelTransferf(GL_DEPTH_SCALE, 1.0);
+ glPixelTransferf(GL_DEPTH_BIAS, 0.0);
+ glPixelTransferi(GL_MAP_STENCIL, 0);
+
+ return true;
+}
+
+
+bool
+DepthStencilTest::testTextureOperations(void)
+{
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT,
+ 0, 0, 1, 1, 0);
+ if (checkError("glCopyTexImage2D in testTextureOperations."))
+ return false;
+
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
+ if (checkError("glCopyTexSubImage2D in testTextureOperations."))
+ return false;
+
+ return true;
+}
+
+
+double
+DepthStencilTest::readPixelsRate(GLenum format, GLenum type)
+{
+ const int width = drawingSize, height = drawingSize;
+ GLuint *img = new GLuint [width * height];
+
+ WindowPos2i(0, 0);
+ glDrawPixels(width, height, GL_DEPTH_STENCIL_EXT,
+ GL_UNSIGNED_INT_24_8_EXT, img);
+
+ const double minInterval = 2.0; // two seconds
+ Timer tTimer;
+ double start = tTimer.getClock();
+ double elapsedTime = 0.0;
+ int iterations = 0;
+ do {
+ for (int i = 0; i < 50; i++) {
+ glReadPixels(0, 0, width, height, format, type, img);
+ iterations++;
+ }
+
+ double finish = tTimer.getClock();
+ elapsedTime = finish - start;
+ } while (elapsedTime < minInterval);
+
+ delete [] img;
+
+ double rate = width * height * iterations / elapsedTime;
+ return rate; // pixels/second
+}
+
+
+void
+DepthStencilTest::testPerformance(DepthStencilResult &r)
+{
+ r.readDepthStencilRate = readPixelsRate(GL_DEPTH_STENCIL_EXT,
+ GL_UNSIGNED_INT_24_8_EXT);
+ r.readDepthUintRate = readPixelsRate(GL_DEPTH_COMPONENT,
+ GL_UNSIGNED_INT);
+ r.readDepthUshortRate = readPixelsRate(GL_DEPTH_COMPONENT,
+ GL_UNSIGNED_SHORT);
+
+ // XXX maybe also test glCopyTexImage, etc.
+}
+
+
+void
+DepthStencilTest::runOne(DepthStencilResult &r, Window &w)
+{
+ (void) w; // silence warning
+ r.pass = true;
+ errorCode = 0;
+ errorPos = NULL;
+ errorMsg[0] = 0;
+
+ setup();
+
+ if (depthBits == 0 || stencilBits == 0) {
+ r.pass = testInsufficientVisual();
+ return;
+ }
+
+ if (r.pass)
+ r.pass = testErrorDetection();
+ if (r.pass)
+ r.pass = testDrawAndRead();
+ if (r.pass)
+ r.pass = testTextureOperations();
+ if (r.pass)
+ testPerformance(r);
+}
+
+
+void
+DepthStencilTest::logOne(DepthStencilResult &r)
+{
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+
+ char str[1000];
+ double mbps;
+
+ env->log << "\tglReadPixels GL_DEPTH_STENCIL rate: ";
+ mbps = r.readDepthStencilRate * sizeof(GLuint) / (1024*1024);
+ sprintf(str, "%.2f", mbps);
+ env->log << str << " MBytes per second.\n";
+
+ env->log << "\tglReadPixels GL_DEPTH/GLuint rate: ";
+ mbps = r.readDepthUintRate * sizeof(GLuint) / (1024*1024);
+ sprintf(str, "%.2f", mbps);
+ env->log << str << " MBytes per second.\n";
+
+ env->log << "\tglReadPixels GL_DEPTH/GLushort rate: ";
+ mbps = r.readDepthUshortRate * sizeof(GLshort) / (1024*1024);
+ sprintf(str, "%.2f", mbps);
+ env->log << str << " MBytes per second.\n";
+ }
+ else {
+ env->log << name << "FAIL\n";
+ if (errorCode) {
+ env->log << "\tOpenGL Error " << gluErrorString(errorCode)
+ << " at " << errorPos << "\n";
+ }
+ else if (errorMsg[0]) {
+ env->log << "\t" << errorMsg << "\n";
+ }
+ }
+}
+
+
+void
+DepthStencilTest::compareOne(DepthStencilResult &oldR,
+ DepthStencilResult &newR)
+{
+ comparePassFail(oldR, newR);
+
+ if (newR.pass && oldR.pass == newR.pass) {
+ if (env->options.verbosity) {
+ env->log << "\tReadPixels rate:\n";
+ env->log << "\t\tGL_DEPTH_STENCIL:\n";
+ env->log << "\t\t\told: " << oldR.readDepthStencilRate;
+ env->log << "\t\t\tnew: " << newR.readDepthStencilRate;
+ env->log << "\t\tGL_DEPTH/GL_UNSIGNED_INT:\n";
+ env->log << "\t\t\told: " << oldR.readDepthUintRate;
+ env->log << "\t\t\tnew: " << newR.readDepthUintRate;
+ env->log << "\t\tGL_DEPTH/GL_UNSIGNED_SHORT:\n";
+ env->log << "\t\t\told: " << oldR.readDepthUshortRate;
+ env->log << "\t\t\tnew: " << newR.readDepthUshortRate;
+ }
+ }
+ else {
+ env->log << "\tNew: ";
+ env->log << (newR.pass ? "PASS" : "FAIL");
+ env->log << "\tOld: ";
+ env->log << (oldR.pass ? "PASS" : "FAIL");
+ }
+}
+
+
+void
+DepthStencilResult::putresults(ostream &s) const
+{
+ if (pass) {
+ s << "PASS\n";
+
+ char str[1000];
+ double mbps;
+
+ mbps = readDepthStencilRate * sizeof(GLuint) / (1024*1024);
+ sprintf(str, "%.2f", mbps);
+ s << str << "\n";
+
+ mbps = readDepthUintRate * sizeof(GLuint) / (1024*1024);
+ sprintf(str, "%.2f", mbps);
+ s << str << "\n";
+
+ mbps = readDepthUshortRate * sizeof(GLushort) / (1024*1024);
+ sprintf(str, "%.2f", mbps);
+ s << str << "\n";
+ }
+ else {
+ s << "FAIL\n";
+ }
+}
+
+
+bool
+DepthStencilResult::getresults(istream &s)
+{
+ char result[1000];
+ s >> result;
+
+ if (strcmp(result, "FAIL") == 0) {
+ pass = false;
+ }
+ else {
+ pass = true;
+ s >> readDepthStencilRate;
+ s >> readDepthUintRate;
+ s >> readDepthUshortRate;
+ }
+ return s.good();
+}
+
+
+// The test object itself:
+DepthStencilTest depthstencilTest("depthStencil", "window, rgb",
+ "GL_EXT_packed_depth_stencil GL_ARB_window_pos",
+ "Test the GL_EXT_packed_depth_stencil extension.\n");
+
+
+
+} // namespace GLEAN
+
+#endif // GL_EXT_packed_depth_stencil
diff --git a/tests/glean/tdepthstencil.h b/tests/glean/tdepthstencil.h
new file mode 100644
index 00000000..9c915ecc
--- /dev/null
+++ b/tests/glean/tdepthstencil.h
@@ -0,0 +1,80 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tdepthstencil.h: Test GL_EXT_packed_depth_stencil extension.
+// Brian Paul 1 October 2005
+
+#ifndef __tdepthstencil_h__
+#define __tdepthstencil_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define drawingSize 1000
+#define windowSize (drawingSize + 2)
+
+class DepthStencilResult: public BaseResult
+{
+public:
+ bool pass;
+ double readDepthStencilRate; // pixels/second
+ double readDepthUintRate; // pixels/second
+ double readDepthUshortRate; // pixels/second
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+
+class DepthStencilTest: public BaseTest<DepthStencilResult>
+{
+public:
+ GLEAN_CLASS_WH(DepthStencilTest, DepthStencilResult,
+ windowSize, windowSize);
+
+private:
+ int depthBits, stencilBits;
+ GLenum errorCode;
+ const char *errorPos;
+ char errorMsg[1000];
+
+ bool checkError(const char *where);
+ void setup(void);
+ bool testInsufficientVisual(void);
+ bool testErrorDetection(void);
+ bool testDrawAndRead(void);
+ bool testTextureOperations(void);
+ void testPerformance(DepthStencilResult &r);
+ double readPixelsRate(GLenum format, GLenum type);
+};
+
+} // namespace GLEAN
+
+#endif // __tdepthstencil_h__
+
diff --git a/tests/glean/test.cpp b/tests/glean/test.cpp
new file mode 100644
index 00000000..02bd16c5
--- /dev/null
+++ b/tests/glean/test.cpp
@@ -0,0 +1,134 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// test.cpp: implementation of base class for tests
+#ifdef __UNIX__
+#include <unistd.h>
+#endif
+
+#include <iostream>
+#include "dsconfig.h"
+#include "dsfilt.h"
+#include "dsurf.h"
+#include "winsys.h"
+#include "environ.h"
+#include "rc.h"
+#include "test.h"
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Class variables for automatic construction of list of all tests
+///////////////////////////////////////////////////////////////////////////////
+Test* Test::testList; // Guaranteed initialized to zero at startup,
+ // before any constructors are invoked.
+ // (See discussion in section 10.4.9,
+ // page 252, of ``C++ Programming Language''
+ // (third edition).)
+
+int Test::testCount; // Also initialized to zero.
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor/Destructor:
+///////////////////////////////////////////////////////////////////////////////
+Test::Test(const char* testName, const char *descrip):
+ name(testName), description(descrip) {
+ prereqs = 0;
+ hasRun = false;
+ nextTest = testList;
+ testList = this;
+ ++testCount;
+} // Test::Test()
+
+Test::Test(const char* testName, const char *descrip, Test** thePrereqs):
+ name(testName), description(descrip) {
+ prereqs = thePrereqs;
+ hasRun = false;
+ nextTest = testList;
+ testList = this;
+ ++testCount;
+} // Test::Test()
+
+Test::~Test() {
+} // Test::~Test
+
+///////////////////////////////////////////////////////////////////////////////
+// Stream opening utilities for results databases
+///////////////////////////////////////////////////////////////////////////////
+
+Test::OutputStream::OutputStream(Test& t) {
+ s = new ofstream(t.env->resultFileName(t.name).c_str());
+ if (!*s)
+ throw Test::CantOpenResultsFile(t.name, t.env->options.db1Name);
+} // Test::OutputStream::OutputStream
+
+Test::OutputStream::~OutputStream() {
+ s->close();
+ delete s;
+} // Test::OutputStream::~OutputStream
+
+Test::OutputStream::operator ofstream& () {
+ return *s;
+} // Test::OutputStream::operator ::ofstream&
+
+Test::Input1Stream::Input1Stream(Test& t) {
+ s = new ifstream(t.env->resultFileName(
+ t.env->options.db1Name, t.name).c_str());
+ if (!*s)
+ throw Test::CantOpenResultsFile(t.name, t.env->options.db1Name);
+} // Test::Input1Stream::Input1Stream
+
+Test::Input1Stream::~Input1Stream() {
+ s->close();
+ delete s;
+} // Test::Input1Stream::~Input1Stream
+
+Test::Input1Stream::operator ifstream& () {
+ return *s;
+} // Test::Input1Stream::operator ::ifstream&
+
+Test::Input2Stream::Input2Stream(Test& t) {
+ s = new ifstream(t.env->resultFileName(
+ t.env->options.db2Name, t.name).c_str());
+ if (!*s)
+ throw Test::CantOpenResultsFile(t.name, t.env->options.db2Name);
+} // Test::Input2Stream::Input2Stream
+
+Test::Input2Stream::~Input2Stream() {
+ s->close();
+ delete s;
+} // Test::Input2Stream::~Input2Stream
+
+Test::Input2Stream::operator ifstream& () {
+ return *s;
+} // Test::Input2Stream::operator ::ifstream&
+
+} // namespace GLEAN
diff --git a/tests/glean/test.h b/tests/glean/test.h
new file mode 100644
index 00000000..1d6e78c4
--- /dev/null
+++ b/tests/glean/test.h
@@ -0,0 +1,152 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// test.h: Base class for all tests
+
+// This class encapsulates base functionality used by all tests. Some
+// of this is fairly trivial (the test name, for example). One of the
+// most important nontrivial functions is the use of the constructor
+// to build a linked list of test objects; this eliminates the need to
+// maintain a separate table of tests. This class also provides a
+// flag for determining if a test has been run, which allows tests to
+// invoke one another and make use of previous results without forcing
+// tests to run multiple times. Finally, it provides a basic
+// framework for recording a vector of results (which typically will
+// vary depending on the drawing surface configuration or the
+// particular type of drawing surface used).
+
+// It is possible to derive test classes directly from this class.
+// Most people will find it more convenient to use the BaseTest
+// template class. See tbase.h for more information.
+
+
+
+#ifndef __test_h__
+#define __test_h__
+
+using namespace std;
+
+#include <string>
+#include <vector>
+#include <fstream>
+
+namespace GLEAN {
+
+class Environment; // Mutually-recursive and forward references.
+class DrawingSurfaceConfig;
+
+// Base class for a single test result. A test may have many results
+// (for example, one per drawing surface configuration), so in general
+// individual tests will have a vector of these objects.
+class Result {
+public:
+ virtual void put(ostream& s) const = 0;
+ virtual bool get(istream& s) = 0;
+ Result() { }
+ virtual ~Result() { }
+};
+
+class Test {
+ public:
+ Test(const char* testName, const char *descrip);
+ Test(const char* testName, const char *descrip, Test** prereqs);
+ virtual ~Test();
+
+ string name; // Test name. Should avoid characters
+ // that aren't universally available in
+ // filenames, since it might be used to
+ // construct such names.
+
+ string description; // Verbose description of test.
+
+ Test** prereqs; // Pointer to array of prerequisite tests.
+ // These will always be run before the
+ // current test.
+
+ bool hasRun; // True if test has been run.
+
+ Environment* env; // Environment in which runs or comparisons
+ // will be performed.
+
+ virtual void run(Environment& env) = 0; // Run test, save results.
+
+ virtual void compare(Environment& env) = 0;
+
+ virtual void details(Environment& env) = 0;
+ // Compare two previous runs.
+
+ // Exceptions:
+ struct Error { }; // Base class for all exceptions.
+ struct CantOpenResultsFile: public Error {
+ const string& testName;
+ const string& dbName;
+ CantOpenResultsFile(const string& test, const string& db):
+ testName(test), dbName(db) { }
+ };
+
+
+ // OutputStream and Input*Stream objects provide convenient access
+ // to the results database, and close the file streams automatically
+ // when their destructors are executed.
+ class OutputStream { // Open an output stream for storing results.
+ public:
+ ofstream* s;
+ OutputStream(Test& t);
+ ~OutputStream();
+ operator ofstream& ();
+ };
+ class Input1Stream { // Open db #1 input stream for reading results.
+ public:
+ ifstream* s;
+ Input1Stream(Test& t);
+ ~Input1Stream();
+ operator ifstream& ();
+ };
+ class Input2Stream { // Open db #2 input stream for reading results.
+ public:
+ ifstream* s;
+ Input2Stream(Test& t);
+ ~Input2Stream();
+ operator ifstream& ();
+ };
+
+
+ static Test* testList; // List of all test objects. Built by
+ // constructor Test::Test(...).
+
+ Test* nextTest; // Link to next test object.
+
+ static int testCount; // Count of elements in testList.
+}; // class Test
+
+} // namespace GLEAN
+
+#endif // __test_h__
diff --git a/tests/glean/tfpexceptions.cpp b/tests/glean/tfpexceptions.cpp
new file mode 100644
index 00000000..7a93eda1
--- /dev/null
+++ b/tests/glean/tfpexceptions.cpp
@@ -0,0 +1,602 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// Authors: Brian Paul, Keith Whitwell
+
+#include "tfpexceptions.h"
+#include <cassert>
+#include <cmath>
+
+#define INCLUDE_FPU_CONTROL 0
+#if INCLUDE_FPU_CONTROL
+#include <fpu_control.h>
+#endif
+
+
+namespace GLEAN {
+
+
+// This might be useful at some point
+void
+FPExceptionsTest::enableExceptions(bool enable)
+{
+#if INCLUDE_FPU_CONTROL
+ const fpu_control_t bits =
+ _FPU_MASK_IM |
+ _FPU_MASK_DM |
+ _FPU_MASK_ZM |
+ _FPU_MASK_OM |
+ _FPU_MASK_UM;
+
+ if (enable) {
+ /* generate FP exceptions */
+ fpu_control_t mask;
+ _FPU_GETCW(mask);
+ mask &= ~bits;
+ _FPU_SETCW(mask);
+ }
+ else {
+ fpu_control_t mask;
+ _FPU_GETCW(mask);
+ mask |= bits;
+ _FPU_SETCW(mask);
+ }
+#else
+ (void) enable;
+#endif
+}
+
+
+
+// XXX any endian issues with this???
+// Works on x86 / little endian
+union fi {
+ float f;
+ struct {
+ unsigned mantissa:23;
+ unsigned exponent:8;
+ unsigned sign:1;
+ } bits;
+ unsigned ui;
+};
+
+
+static void
+make_float(float *dest, unsigned sign, unsigned exponent, unsigned mantissa)
+{
+ union fi *destfi = (union fi *) dest;
+ destfi->bits.sign = sign;
+ destfi->bits.exponent = exponent;
+ destfi->bits.mantissa = mantissa;
+}
+
+static void
+make_denorm_float(float *dest, int sign, int mantissa)
+{
+ make_float(dest, sign, 0, mantissa);
+}
+
+static void
+make_pos_inf_float(float *dest)
+{
+ make_float(dest, 0, 255, 0); // or HUGE_VALF?
+}
+
+static void
+make_neg_inf_float(float *dest)
+{
+ make_float(dest, 1, 255, 0); // or -HUGE_VALF?
+}
+
+static void
+make_signaling_nan_float(float *dest)
+{
+ make_float(dest, 0, 255, 1);
+}
+
+static void
+make_quiet_nan_float(float *dest)
+{
+ make_float(dest, 0, 255, 1 << 22);
+}
+
+static void
+make_denorm_double(double * /*dest*/, int /*sign*/, int /*mantissa*/)
+{
+ // XXX to do
+}
+
+static void
+make_pos_inf_double(double *dest)
+{
+ *dest = HUGE_VAL;
+}
+
+static void
+make_neg_inf_double(double *dest)
+{
+ *dest = -HUGE_VAL;
+}
+
+static void
+make_signaling_nan_double(double * /*dest*/)
+{
+ // XXX to do
+}
+
+static void
+make_quiet_nan_double(double * /*dest*/)
+{
+ // XXX to do
+}
+
+
+static void
+print_float(float f)
+{
+ union fi fi, fi2;
+ int iexp, imnt, isgn;
+
+ fi.f = f;
+ printf("float %f (%e)\n\tuint 0x%x\n\tsign %d exponent %d mantissa 0x%x\n",
+ fi.f, fi.f, fi.ui, fi.bits.sign, fi.bits.exponent, fi.bits.mantissa);
+
+ switch (fi.bits.exponent) {
+ case 0:
+ if (fi.bits.mantissa == 0)
+ printf("\t%szero\n", fi.bits.sign ? "-" : "+");
+ else {
+ printf("\tdenormalized float\n");
+
+ iexp = -126 - 23; /* -149 */
+ imnt = (int)fi.bits.mantissa;
+ isgn = fi.bits.sign ? -1 : 1;
+ fi2.f = isgn * imnt * ldexp(1.0, iexp);
+
+ printf("\trecombining: %d * 0x%x * 2.0^%d == %f (%e)\n",
+ isgn, imnt, iexp, fi2.f, fi2.f);
+ printf("\trecombined: sign %d exponent %d mantissa 0x%x\n",
+ fi2.bits.sign, fi2.bits.exponent, fi2.bits.mantissa);
+ }
+ break;
+
+ case 255:
+ if (fi.bits.mantissa & (1<<22))
+ printf("\tQNaN (Quiet NaN/indeterminate value)\n");
+ else if (fi.bits.mantissa)
+ printf("\tSNaN (Signalling NaN/invalid value)\n");
+ else
+ printf("\t%sinf\n", fi.bits.sign ? "-" : "+");
+ break;
+
+ default:
+ iexp = fi.bits.exponent - (127 + 23);
+ imnt = (1<<23) + (int)fi.bits.mantissa;
+ isgn = fi.bits.sign ? -1 : 1;
+ fi2.f = isgn * imnt * ldexp(1.0, iexp);
+
+ printf("\trecombining: %d * 0x%x * 2.0^%d == %f\n",
+ isgn, imnt, iexp, fi2.f);
+
+ printf("\trecombined: sign %d exponent %d mantissa 0x%x\n",
+ fi2.bits.sign, fi2.bits.exponent, fi2.bits.mantissa);
+ break;
+ }
+
+ /* Let's look and see what would happen if we interpret all these
+ * cases as normal floats:
+ */
+ iexp = fi.bits.exponent - (127 + 23);
+ imnt = (1<<23) + (int)fi.bits.mantissa;
+ isgn = fi.bits.sign ? -1 : 1;
+ fi2.f = isgn * imnt * ldexp(1.0, iexp);
+
+ printf("\tvalue if treated as normalized: %f (%e)\n",
+ fi2.f, fi2.f);
+}
+
+
+/* Examine some interesting floats
+ */
+#if 0
+int main()
+{
+ float f;
+ int i;
+
+ for (i = -3; i < 10; i++) {
+ printf("%d:\n ", i);
+ print_float(ldexp(1.0, i));
+ }
+
+ for (f = -4 ; f < 4; f += 1)
+ print_float(f);
+
+ for (f = -.01 ; f < .01; f += .002)
+ print_float(f);
+
+ f = 1.0/0;
+ print_float(f);
+
+ f += 1.0;
+ print_float(f);
+
+ /* Explicitly make a denormal - I've no idea how to create these
+ * with regular calculations:
+ */
+ make_float(&f, 0, 0, 0x1000);
+ print_float(f);
+
+ /* It seems you can just specify them!
+ */
+ f = 5.739719e-42;
+ print_float(f);
+
+ /* A little, non-denormalized float
+ */
+ make_float(&f, 0, 1, 0x1);
+ print_float(f);
+
+ /* A negative little, non-denormalized float
+ */
+ make_float(&f, 1, 1, 0x1);
+ print_float(f);
+
+ /* A big float
+ */
+ make_float(&f, 0, 254, ~0);
+ print_float(f);
+
+ make_float(&f, 1, 254, ~0);
+ print_float(f);
+
+ /* Littlest and biggest denormals:
+ */
+ make_float(&f, 0, 0, 1);
+ print_float(f);
+ make_float(&f, 0, 0, ~0);
+ print_float(f);
+
+
+ make_float(&f, 1, 0, 1);
+ print_float(f);
+ make_float(&f, 1, 0, ~0);
+ print_float(f);
+
+}
+#endif
+
+
+bool
+FPExceptionsTest::testVertices(Mode m)
+{
+ float v[3][4];
+ // nice coords
+ for (int i = 0; i < 3; i++) {
+ v[i][0] = 0.0;
+ v[i][1] = 0.0;
+ v[i][2] = 0.0;
+ v[i][3] = 1.0;
+ }
+
+ // set problematic values
+ switch (m) {
+ case MODE_INFINITY:
+ make_pos_inf_float(&v[1][0]);
+ make_neg_inf_float(&v[2][1]);
+ break;
+ case MODE_NAN:
+ make_signaling_nan_float(&v[1][0]);
+ make_quiet_nan_float(&v[2][1]);
+ break;
+ case MODE_DIVZERO:
+ v[0][3] = 0.0;
+ v[1][3] = 0.0;
+ v[2][3] = 0.0;
+ break;
+ case MODE_DENORM:
+ make_denorm_float(&v[0][0], 0, 1);
+ make_denorm_float(&v[1][1], 1, 1);
+ break;
+ default:
+ ; // nothing
+ }
+
+ // vertex positions
+ glBegin(GL_POLYGON);
+ glVertex4fv(v[0]);
+ glVertex4fv(v[1]);
+ glVertex4fv(v[2]);
+ glEnd();
+
+ // colors
+ glBegin(GL_POLYGON);
+ glColor4fv(v[0]); glVertex2f(-1, -1);
+ glColor4fv(v[1]); glVertex2f( 1, -1);
+ glColor4fv(v[2]); glVertex2f( 0, 1);
+ glEnd();
+
+ // normals
+ glEnable(GL_LIGHTING);
+ glBegin(GL_POLYGON);
+ glNormal3fv(v[0]); glVertex2f(-1, -1);
+ glNormal3fv(v[1]); glVertex2f( 1, -1);
+ glNormal3fv(v[2]); glVertex2f( 0, 1);
+ glEnd();
+ glDisable(GL_LIGHTING);
+
+ // texcoords
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_POLYGON);
+ glTexCoord4fv(v[0]); glVertex2f(-1, -1);
+ glTexCoord4fv(v[1]); glVertex2f( 1, -1);
+ glTexCoord4fv(v[2]); glVertex2f( 0, 1);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+
+ return true;
+}
+
+
+bool
+FPExceptionsTest::testTransformation(Mode m)
+{
+ float mat[16];
+
+ // identity
+ for (int i = 0; i < 15; i++)
+ mat[i] = 0.0;
+ mat[0] = mat[5] = mat[10] = mat[15] = 1.0;
+
+ // set problematic values
+ switch (m) {
+ case MODE_INFINITY:
+ make_pos_inf_float(&mat[0]); // X scale
+ make_neg_inf_float(&mat[13]); // Y translate
+ break;
+ case MODE_NAN:
+ make_signaling_nan_float(&mat[0]); // X scale
+ make_quiet_nan_float(&mat[13]); // Y translate
+ break;
+ case MODE_DIVZERO:
+ // all zero matrix
+ mat[0] = mat[5] = mat[10] = mat[15] = 0.0;
+ break;
+ case MODE_DENORM:
+ make_denorm_float(&mat[0], 0, 1);
+ make_denorm_float(&mat[13], 1, 1);
+ break;
+ default:
+ ; // nothing
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(mat);
+
+ // vertex positions
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 0, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ return true;
+}
+
+
+bool
+FPExceptionsTest::testClipping(Mode m)
+{
+ double plane[4];
+
+ // start w/ nice values
+ plane[0] = plane[1] = plane[2] = plane[3] = 0.0;
+
+ // set problematic values
+ switch (m) {
+ case MODE_INFINITY:
+ make_pos_inf_double(&plane[0]);
+ make_neg_inf_double(&plane[3]);
+ break;
+ case MODE_NAN:
+ make_signaling_nan_double(&plane[0]);
+ make_quiet_nan_double(&plane[3]);
+ break;
+ case MODE_DIVZERO:
+ // nothing
+ break;
+ case MODE_DENORM:
+ make_denorm_double(&plane[0], 0, 1);
+ make_denorm_double(&plane[3], 1, 1);
+ break;
+ case MODE_OVERFLOW:
+ plane[0] = 1.0e300;
+ plane[3] = 1.0e-300;
+ break;
+ default:
+ ; // nothing
+ }
+
+ glClipPlane(GL_CLIP_PLANE0, plane);
+ glEnable(GL_CLIP_PLANE0);
+
+ // vertex positions
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 0, 1);
+ glEnd();
+
+ glDisable(GL_CLIP_PLANE0);
+
+ return true;
+}
+
+
+// pass large doubles to OpenGL and see what happens when converted to float.
+bool
+FPExceptionsTest::testOverflow(void)
+{
+ GLdouble v[3][4];
+ for (int i = 0; i < 3; i++) {
+ v[i][0] = 0.0;
+ v[i][1] = 0.0;
+ v[i][2] = 0.0;
+ v[i][3] = 1.0;
+ }
+ v[0][0] = 1.0e300;
+ v[0][1] = -1.0e300;
+ v[1][0] = 1.0e-300;
+ v[1][1] = 1.0e-300;
+
+ GLdouble mat[16];
+ for (int i = 0; i < 15; i++)
+ mat[i] = 0.0;
+ mat[0] = mat[5] = mat[10] = mat[15] = 1.0e500;
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixd(mat);
+
+ glBegin(GL_POLYGON);
+ glVertex4dv(v[0]);
+ glVertex4dv(v[1]);
+ glVertex4dv(v[2]);
+ glEnd();
+
+ glPopMatrix();
+
+ return true;
+}
+
+
+
+void
+FPExceptionsTest::setup(void)
+{
+ // Simple texture map
+ static const GLfloat texImage[2][2][3] = {
+ { {1, 1, 1}, {0, 0, 0} },
+ { {0, 0, 0}, {1, 1, 1} }
+ };
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
+ GL_RGB, GL_FLOAT, texImage);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ // simple lighting
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHT1);
+ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
+}
+
+
+void
+FPExceptionsTest::reportPassFail(MultiTestResult &r,
+ bool pass, const char *msg) const
+{
+ if (pass) {
+ if (env->options.verbosity)
+ env->log << name << " PASS: " << msg << " test\n";
+ r.numPassed++;
+ }
+ else {
+ if (env->options.verbosity)
+ env->log << name << " FAILURE: " << msg << " test\n";
+ r.numFailed++;
+ }
+}
+
+void
+FPExceptionsTest::runOne(MultiTestResult &r, Window &w)
+{
+ bool p;
+
+ (void) w;
+
+ p = testVertices(MODE_INFINITY);
+ reportPassFail(r, p, "Infinite value vertex");
+
+ p = testVertices(MODE_NAN);
+ reportPassFail(r, p, "NaN value vertex");
+
+ p = testVertices(MODE_DIVZERO);
+ reportPassFail(r, p, "Divide by zero vertex");
+
+ p = testVertices(MODE_DENORM);
+ reportPassFail(r, p, "Denorm vertex");
+
+
+ p = testTransformation(MODE_INFINITY);
+ reportPassFail(r, p, "Infinite matrix transform");
+
+ p = testTransformation(MODE_NAN);
+ reportPassFail(r, p, "NaN matrix transform");
+
+ p = testTransformation(MODE_DIVZERO);
+ reportPassFail(r, p, "Zero matrix transform");
+
+ p = testTransformation(MODE_DENORM);
+ reportPassFail(r, p, "Denorm matrix transform");
+
+
+ p = testClipping(MODE_INFINITY);
+ reportPassFail(r, p, "Infinite clip plane");
+
+ p = testClipping(MODE_NAN);
+ reportPassFail(r, p, "NaN clip plane");
+
+ p = testClipping(MODE_DIVZERO);
+ reportPassFail(r, p, "Zero clip plane");
+
+ p = testClipping(MODE_DENORM);
+ reportPassFail(r, p, "Denorm clip plane");
+
+ p = testClipping(MODE_OVERFLOW);
+ reportPassFail(r, p, "Overflow clip plane");
+
+
+ p = testOverflow();
+ reportPassFail(r, p, "Overflow");
+
+ r.pass = (r.numFailed == 0);
+}
+
+
+// The test object itself:
+FPExceptionsTest FPExceptionsTest("fpexceptions", // test name
+ "window, rgb", // surface/pixel format
+ "", // no extensions required
+ "Test for floating point exceptions caused by +/-infinity, Nan, divide by zero, etc in a number of circumstances.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tfpexceptions.h b/tests/glean/tfpexceptions.h
new file mode 100644
index 00000000..fee9a0c6
--- /dev/null
+++ b/tests/glean/tfpexceptions.h
@@ -0,0 +1,78 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tfpexceptions.h: Test for floating point exceptions caused by
+// infinity, Nan, denormalized numbers, divide by zero, etc.
+// Brian Paul 9 November 2005
+
+#ifndef __tfpexceptions_h__
+#define __tfpexceptions_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+
+#define windowSize 100
+
+
+class FPExceptionsTest: public MultiTest
+{
+public:
+ FPExceptionsTest(const char* testName, const char* filter,
+ const char *extensions, const char* description)
+ : MultiTest(testName, filter, extensions, description)
+ {
+ }
+
+ virtual void runOne(MultiTestResult &r, Window &w);
+
+private:
+ enum Mode {
+ MODE_INFINITY,
+ MODE_NAN,
+ MODE_DIVZERO,
+ MODE_DENORM,
+ MODE_OVERFLOW
+ };
+
+ void enableExceptions(bool enable);
+
+ bool testVertices(Mode m);
+ bool testTransformation(Mode m);
+ bool testClipping(Mode m);
+ bool testOverflow(void);
+
+ void reportPassFail(MultiTestResult &r, bool pass, const char *msg) const;
+ void setup(void);
+};
+
+
+} // namespace GLEAN
+
+#endif // __tfpexceptions_h__
diff --git a/tests/glean/tfragprog1.cpp b/tests/glean/tfragprog1.cpp
new file mode 100644
index 00000000..632a5af2
--- /dev/null
+++ b/tests/glean/tfragprog1.cpp
@@ -0,0 +1,1056 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tfragprog.cpp: Test GL_ARB_fragment_program extension.
+// Brian Paul 22 October 2005
+//
+// This is pretty simple. Specific fragment programs are run, we read back
+// the framebuffer color and compare the color to the expected result.
+// Pretty much any fragment program can be tested in the manner.
+// Ideally, an additional fragment program test should be developed which
+// exhaustively tests instruction combinations with all the various swizzle
+// and masking options, etc.
+// But this test is good for regression testing to be sure that particular or
+// unique programs work correctly.
+
+
+#include "tfragprog1.h"
+#include <cassert>
+#include <cmath>
+#include <math.h>
+
+
+namespace GLEAN {
+
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB_func;
+static PFNGLGENPROGRAMSARBPROC glGenProgramsARB_func;
+static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB_func;
+static PFNGLBINDPROGRAMARBPROC glBindProgramARB_func;
+static PFNGLISPROGRAMARBPROC glIsProgramARB_func;
+static PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB_func;
+static PFNGLGETPROGRAMIVARBPROC glGetProgramivARB_func;
+static PFNGLFOGCOORDFPROC glFogCoordf_func;
+
+
+// Clamp X to [0, 1]
+#define CLAMP01( X ) ( (X)<(0.0) ? (0.0) : ((X)>(1.0) ? (1.0) : (X)) )
+// Absolute value
+#define ABS(X) ( (X) < 0.0 ? -(X) : (X) )
+// Max
+#define MAX( A, B ) ( (A) > (B) ? (A) : (B) )
+// Min
+#define MIN( A, B ) ( (A) < (B) ? (A) : (B) )
+// Duplicate value four times
+#define SMEAR(X) (X), (X), (X), (X)
+
+#define DONT_CARE_Z -1.0
+#define DONT_CARE_COLOR -1.0
+
+#define FRAGCOLOR { 0.25, 0.75, 0.5, 0.25 }
+#define PARAM0 { 0.0, 0.0, 0.0, 0.0 }
+#define PARAM1 { 0.5, 0.25, 1.0, 0.5 }
+#define PARAM2 { -1.0, 0.0, 0.25, -0.5 }
+static const GLfloat FragColor[4] = FRAGCOLOR;
+static const GLfloat Param0[4] = PARAM0;
+static const GLfloat Param1[4] = PARAM1;
+static const GLfloat Param2[4] = PARAM2;
+static GLfloat InfNan[4];
+static GLfloat FogColor[4] = {1.0, 1.0, 0.0, 0.0};
+static GLfloat FogStart = 10.0;
+static GLfloat FogEnd = 100.0;
+static GLfloat FogDensity = 0.03;
+static GLfloat FogCoord = 50.0; /* Between FogStart and FogEnd */
+
+
+// These are the specific fragment programs which we'll test
+// Alphabetical order, please
+static const FragmentProgram Programs[] = {
+ {
+ "ABS test",
+ "!!ARBfp1.0\n"
+ "PARAM p = program.local[2]; \n"
+ "ABS result.color, p; \n"
+ "END \n",
+ { ABS(Param2[0]),
+ ABS(Param2[1]),
+ ABS(Param2[2]),
+ ABS(Param2[3])
+ },
+ DONT_CARE_Z,
+ false,
+ },
+ {
+ "ADD test",
+ "!!ARBfp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "ADD result.color, fragment.color, p; \n"
+ "END \n",
+ { CLAMP01(FragColor[0] + Param1[0]),
+ CLAMP01(FragColor[1] + Param1[1]),
+ CLAMP01(FragColor[2] + Param1[2]),
+ CLAMP01(FragColor[3] + Param1[3])
+ },
+ DONT_CARE_Z,
+ false,
+ },
+ {
+ "CMP test",
+ "!!ARBfp1.0\n"
+ "PARAM zero = program.local[0]; \n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "CMP result.color, p2, zero, p1; \n"
+ "END \n",
+ { Param0[0], Param1[1], Param1[2], Param0[3] },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "COS test",
+ "!!ARBfp1.0\n"
+ "PARAM values = { 0.0, 3.14159, 0.5, 1.0 }; \n"
+ "COS result.color.x, values.x; \n"
+ "COS result.color.y, values.y; \n"
+ "COS result.color.z, values.z; \n"
+ "COS result.color.w, values.w; \n"
+ "END \n",
+ { CLAMP01(1.0),
+ CLAMP01(-1.0),
+ CLAMP01(0.8775),
+ CLAMP01(0.5403)
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "DP3 test",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "DP3 result.color, p1, fragment.color; \n"
+ "END \n",
+ { SMEAR(CLAMP01(Param1[0] * FragColor[0] +
+ Param1[1] * FragColor[1] +
+ Param1[2] * FragColor[2]))
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "DP4 test",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "DP4 result.color, p1, fragment.color; \n"
+ "END \n",
+ { SMEAR(CLAMP01(Param1[0] * FragColor[0] +
+ Param1[1] * FragColor[1] +
+ Param1[2] * FragColor[2] +
+ Param1[3] * FragColor[3]))
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "DPH test",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
+ "TEMP t; \n"
+ "DPH t, p1, fragment.color; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { SMEAR(CLAMP01((Param1[0] * FragColor[0] +
+ Param1[1] * FragColor[1] +
+ Param1[2] * FragColor[2] +
+ FragColor[3]) * 0.1))
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "DST test",
+ "!!ARBfp1.0\n"
+ "# let d = 0.4 \n"
+ "PARAM v1 = {9.9, 0.16, 0.16, 9.9}; \n"
+ "PARAM v2 = {9.9, 2.5, 9.9, 2.5}; \n"
+ "DST result.color, v1, v2; \n"
+ "END \n",
+ { 1.0,
+ 0.4, // v1.y * v2.y
+ 0.16, // v1.z
+ CLAMP01(2.5) // v2.w
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "EX2 test",
+ "!!ARBfp1.0\n"
+ "PARAM scale = {0.01, 0.01, 0.01, 0.01}; \n"
+ "PARAM values = {0.0, 1.0, 4.0, -2.0 }; \n"
+ "TEMP t; \n"
+ "EX2 t.x, values.x; \n"
+ "EX2 t.y, values.y; \n"
+ "EX2 t.z, values.z; \n"
+ "EX2 t.w, values.w; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { 1.0 * 0.01,
+ 2.0 * 0.01,
+ 16.0 * 0.01,
+ 0.25 * 0.01 },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "FLR test",
+ "!!ARBfp1.0\n"
+ "PARAM values = {4.8, 0.3, -0.2, 1.2}; \n"
+ "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
+ "TEMP t; \n"
+ "FLR t, values; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { 0.4,
+ 0.0,
+ CLAMP01(-0.1),
+ 0.1
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "FRC test",
+ "!!ARBfp1.0\n"
+ "PARAM values = {-1.1, 0.1, -2.2, 2.4 }; \n"
+ "FRC result.color, values; \n"
+ "END \n",
+ { 0.9, 0.1, 0.8, 0.4 },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "LG2 test",
+ "!!ARBfp1.0\n"
+ "PARAM values = {64.0, 1, 30, 4}; \n"
+ "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
+ "TEMP t; \n"
+ "LG2 t.x, values.x; \n"
+ "LG2 t.y, values.y; \n"
+ "LG2 t.z, values.z; \n"
+ "LG2 t.w, values.w; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { 0.6,
+ 0.0,
+ 0.49,
+ 0.2
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "LIT test 1",
+ "!!ARBfp1.0\n"
+ "PARAM values = {0.65, 0.9, 0.0, 8.0}; \n"
+ "LIT result.color, values; \n"
+ "END \n",
+ { 1.0,
+ 0.65, // values.x
+ 0.433, // roughly Pow(values.y, values.w)
+ 1.0
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "LIT test 2 (degenerate case: 0 ^ 0 -> 1)",
+ "!!ARBfp1.0\n"
+ "PARAM values = {0.65, 0.0, 0.0, 0.0}; \n"
+ "LIT result.color, values; \n"
+ "END \n",
+ { 1.0,
+ 0.65, // values.x
+ 1.0, // 0^0
+ 1.0
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "LIT test 3 (case x < 0)",
+ "!!ARBfp1.0\n"
+ "PARAM values = {-0.5, 0.0, 0.0, 0.0}; \n"
+ "LIT result.color, values; \n"
+ "END \n",
+ { 1.0,
+ CLAMP01(-0.5), // values.x
+ 0.0,
+ 1.0
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "LRP test",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM t = {0.2, 0.5, 1.0, 0.0}; \n"
+ "LRP result.color, t, fragment.color, p1; \n"
+ "END \n",
+ { 0.2 * FragColor[0] + (1.0 - 0.2) * Param1[0],
+ 0.5 * FragColor[1] + (1.0 - 0.5) * Param1[1],
+ 1.0 * FragColor[2] + (1.0 - 1.0) * Param1[2],
+ 0.0 * FragColor[3] + (1.0 - 0.0) * Param1[3]
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "MAD test",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "MAD result.color, fragment.color, p1, p2; \n"
+ "END \n",
+ { CLAMP01(FragColor[0] * Param1[0] + Param2[0]),
+ CLAMP01(FragColor[1] * Param1[1] + Param2[1]),
+ CLAMP01(FragColor[2] * Param1[2] + Param2[2]),
+ CLAMP01(FragColor[3] * Param1[3] + Param2[3])
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "MAX test",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "MAX result.color, p1, p2; \n"
+ "END \n",
+ { MAX(Param1[0], Param2[0]),
+ MAX(Param1[1], Param2[1]),
+ MAX(Param1[2], Param2[2]),
+ MAX(Param1[3], Param2[3]),
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "MIN test",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "MIN result.color, p1, fragment.color; \n"
+ "END \n",
+ { MIN(Param1[0], FragColor[0]),
+ MIN(Param1[1], FragColor[1]),
+ MIN(Param1[2], FragColor[2]),
+ MIN(Param1[3], FragColor[3]),
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "MOV test",
+ "!!ARBfp1.0\n"
+ "MOV result.color, fragment.color; \n"
+ "END \n",
+ FRAGCOLOR,
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "MUL test",
+ "!!ARBfp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "MUL result.color, fragment.color, p; \n"
+ "END \n",
+ { CLAMP01(FragColor[0] * Param1[0]),
+ CLAMP01(FragColor[1] * Param1[1]),
+ CLAMP01(FragColor[2] * Param1[2]),
+ CLAMP01(FragColor[3] * Param1[3])
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "masked MUL test",
+ "!!ARBfp1.0\n"
+ "PARAM zero = program.local[0]; \n"
+ "PARAM p = program.local[1]; \n"
+ "MOV result.color, zero; \n"
+ "MUL result.color.xy, fragment.color, p; \n"
+ "END \n",
+ { CLAMP01(FragColor[0] * Param1[0]),
+ CLAMP01(FragColor[1] * Param1[1]),
+ 0.0,
+ 0.0
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "POW test (exponentiation)",
+ "!!ARBfp1.0\n"
+ "PARAM values = {0.5, 2, 3, 4}; \n"
+ "POW result.color.x, values.x, values.y; \n"
+ "POW result.color.y, values.x, values.z; \n"
+ "POW result.color.z, values.x, values.w; \n"
+ "POW result.color.w, values.w, values.x; \n"
+ "END \n",
+ { 0.5 * 0.5,
+ 0.5 * 0.5 * 0.5,
+ 0.5 * 0.5 * 0.5 * 0.5,
+ CLAMP01(2.0) },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "RCP test (reciprocal)",
+ "!!ARBfp1.0\n"
+ "PARAM values = {8, -10, 1, 12 }; \n"
+ "RCP result.color.x, values.x; \n"
+ "RCP result.color.y, values.y; \n"
+ "RCP result.color.z, values.z; \n"
+ "RCP result.color.w, values.w; \n"
+ "END \n",
+ { 1.0 / 8.0, CLAMP01(1.0 / -10.0), 1, 1.0 / 12.0 },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "RSQ test 1 (reciprocal square root)",
+ "!!ARBfp1.0\n"
+ "PARAM values = {1, 4, 9, 100 }; \n"
+ "RSQ result.color.x, values.x; \n"
+ "RSQ result.color.y, values.y; \n"
+ "RSQ result.color.z, values.z; \n"
+ "RSQ result.color.w, values.w; \n"
+ "END \n",
+ { 1.0, 0.5, 0.3333, 0.1 },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "RSQ test 2 (reciprocal square root of negative value)",
+ "!!ARBfp1.0\n"
+ "PARAM values = {0, -100, -5, -1}; \n"
+ "RSQ result.color.x, values.x; \n"
+ "RSQ result.color.y, values.y; \n"
+ "RSQ result.color.z, values.z; \n"
+ "RSQ result.color.w, values.w; \n"
+ "END \n",
+ { DONT_CARE_COLOR,
+ 0.1,
+ 0.447,
+ 1.0,
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "SCS test",
+ "!!ARBfp1.0\n"
+ "PARAM values = { 0.5, 0.5, 0.0, 0.0 }; \n"
+ "SCS result.color.x, values.x; \n"
+ "SCS result.color.y, values.y; \n"
+ "END \n",
+ { CLAMP01(0.8775),
+ CLAMP01(0.4794),
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "SGE test",
+ "!!ARBfp1.0\n"
+ "PARAM p0 = program.local[0]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "SGE result.color, p2, p0; \n"
+ "END \n",
+ { Param2[0] >= Param0[0] ? 1.0 : 0.0,
+ Param2[1] >= Param0[1] ? 1.0 : 0.0,
+ Param2[2] >= Param0[2] ? 1.0 : 0.0,
+ Param2[3] >= Param0[3] ? 1.0 : 0.0,
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "SIN test",
+ "!!ARBfp1.0\n"
+ "PARAM values = { 1.57079, -1.57079, 0.5, 1.0 }; \n"
+ "SIN result.color.x, values.x; \n"
+ "SIN result.color.y, values.y; \n"
+ "SIN result.color.z, values.z; \n"
+ "SIN result.color.w, values.w; \n"
+ "END \n",
+ { CLAMP01(1.0),
+ CLAMP01(-1.0),
+ CLAMP01(0.4794),
+ CLAMP01(0.8414)
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "SLT test",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "SLT result.color, fragment.color, p1; \n"
+ "END \n",
+ { FragColor[0] < Param1[0] ? 1.0 : 0.0,
+ FragColor[1] < Param1[1] ? 1.0 : 0.0,
+ FragColor[2] < Param1[2] ? 1.0 : 0.0,
+ FragColor[3] < Param1[3] ? 1.0 : 0.0,
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "SUB test (with swizzle)",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "SUB result.color, p1.yxwz, fragment.color.yxwz; \n"
+ "END \n",
+ { CLAMP01(Param1[1] - FragColor[1]),
+ CLAMP01(Param1[0] - FragColor[0]),
+ CLAMP01(Param1[3] - FragColor[3]),
+ CLAMP01(Param1[2] - FragColor[2])
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "SWZ test",
+ "!!ARBfp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "SWZ result.color, p, -1,-y,z,0; \n"
+ "END \n",
+ { CLAMP01(-1.0),
+ CLAMP01(-Param1[1]),
+ CLAMP01(Param1[2]),
+ CLAMP01(0.0)
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "XPD test 1",
+ "!!ARBfp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "XPD result.color, p1, p2; \n"
+ "END \n",
+ { CLAMP01(Param1[1] * Param2[2] - Param1[2] * Param2[1]),
+ CLAMP01(Param1[2] * Param2[0] - Param1[0] * Param2[2]),
+ CLAMP01(Param1[0] * Param2[1] - Param1[1] * Param2[0]),
+ DONT_CARE_COLOR
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "Z-write test",
+ "!!ARBfp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "MOV result.color, p; \n"
+ "MOV result.depth.z, p.y; \n"
+ "END \n",
+ { Param1[0],
+ Param1[1],
+ Param1[2],
+ Param1[3]
+ },
+ Param1[1],
+ false
+ },
+
+ // ============= Numeric stress tests =================================
+ // Basically just check that we don't crash when we do divides by
+ // zero, etc.
+ {
+ "Divide by zero test",
+ "!!ARBfp1.0\n"
+ "PARAM zero = program.local[0]; \n"
+ "RCP result.color.x, zero.x; \n"
+ "RCP result.color.y, zero.y; \n"
+ "RCP result.color.z, zero.z; \n"
+ "RCP result.color.w, zero.w; \n"
+ "END \n",
+ { DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR
+ },
+ DONT_CARE_Z,
+ false
+ },
+ {
+ "Infinity / nan test",
+ "!!ARBfp1.0\n"
+ "PARAM zero = program.local[0]; \n"
+ "PARAM infNan = program.local[9]; \n"
+ "ADD result.color, infNan, zero; \n"
+ "END \n",
+ { DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR
+ },
+ DONT_CARE_Z,
+ false
+ },
+
+ // ============= Fog tests ============================================
+ // Linear fog
+#define FOG_FACT ((FogEnd - FogCoord) / (FogEnd - FogStart))
+ {
+ "ARB_fog_linear test",
+ "!!ARBfp1.0\n"
+ "OPTION ARB_fog_linear; \n"
+ "MOV result.color, fragment.color; \n"
+ "END \n",
+ { FragColor[0] * FOG_FACT + FogColor[0] * (1.0 - FOG_FACT),
+ FragColor[1] * FOG_FACT + FogColor[1] * (1.0 - FOG_FACT),
+ FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
+ FragColor[3]
+ },
+ DONT_CARE_Z,
+ true
+ },
+ {
+ "Computed fog linear test",
+ "!!ARBfp1.0\n"
+ "# fogParams.x = density \n"
+ "# fogParams.y = start \n"
+ "# fogParams.z = end \n"
+ "# fogParams.w = 1/(end-start) \n"
+ "PARAM fogParams = state.fog.params; \n"
+ "ATTRIB fogCoord = fragment.fogcoord; \n"
+ "PARAM fogColor = state.fog.color; \n"
+ "TEMP numerator, f; \n"
+ "# f = (end - coord) / (end - start) \n"
+ "SUB numerator, fogParams.z, fogCoord.x; \n"
+ "MUL_SAT f, numerator, fogParams.w; \n"
+ "LRP result.color.rgb, f, fragment.color, fogColor; \n"
+ "MOV result.color.a, fragment.color.a; \n"
+ "END \n",
+ { FragColor[0] * FOG_FACT + FogColor[0] * (1.0 - FOG_FACT),
+ FragColor[1] * FOG_FACT + FogColor[1] * (1.0 - FOG_FACT),
+ FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
+ FragColor[3]
+ },
+ DONT_CARE_Z,
+ true
+ },
+#undef FOG_FACT
+
+ // Exp fog
+#define FOG_FACT 0.2231 // = exp(-Density * Coord)
+ {
+ "ARB_fog_exp test",
+ "!!ARBfp1.0\n"
+ "OPTION ARB_fog_exp; \n"
+ "MOV result.color, fragment.color; \n"
+ "END \n",
+ { FragColor[0] * FOG_FACT + FogColor[0] * (1.0 - FOG_FACT),
+ FragColor[1] * FOG_FACT + FogColor[1] * (1.0 - FOG_FACT),
+ FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
+ FragColor[3]
+ },
+ DONT_CARE_Z,
+ true
+ },
+#undef FOG_FACT
+#define FOG_FACT 0.3535 // = ex2(-Density * Coord)
+ {
+ // NOTE: we could also do this with the POW instruction
+ "Computed fog exp test",
+ "!!ARBfp1.0\n"
+ "# fogParams.x = density \n"
+ "# fogParams.y = start \n"
+ "# fogParams.z = end \n"
+ "# fogParams.w = 1/(end-start) \n"
+ "PARAM fogParams = state.fog.params; \n"
+ "ATTRIB fogCoord = fragment.fogcoord; \n"
+ "PARAM fogColor = state.fog.color; \n"
+ "TEMP f, dc; \n"
+ "# f = exp(-density * coord) \n"
+ "MUL dc.x, fogParams.x, fogCoord.x; \n"
+ "EX2_SAT f, -dc.x; \n"
+ "LRP result.color.rgb, f, fragment.color, fogColor; \n"
+ "MOV result.color.a, fragment.color.a; \n"
+ "END \n",
+ { FragColor[0] * FOG_FACT + FogColor[0] * (1.0 - FOG_FACT),
+ FragColor[1] * FOG_FACT + FogColor[1] * (1.0 - FOG_FACT),
+ FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
+ FragColor[3]
+ },
+ DONT_CARE_Z,
+ true
+ },
+#undef FOG_FACT
+
+ // Exp2 fog
+#define FOG_FACT 0.1054 // = exp(-(Density * Coord)^2)
+ {
+ "ARB_fog_exp2 test",
+ "!!ARBfp1.0\n"
+ "OPTION ARB_fog_exp2; \n"
+ "MOV result.color, fragment.color; \n"
+ "END \n",
+ { FragColor[0] * FOG_FACT + FogColor[0] * (1.0 - FOG_FACT),
+ FragColor[1] * FOG_FACT + FogColor[1] * (1.0 - FOG_FACT),
+ FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
+ FragColor[3]
+ },
+ DONT_CARE_Z,
+ true
+ },
+#undef FOG_FACT
+#define FOG_FACT 0.2102 // = ex2(-(Density * Coord)^2)
+ {
+ // NOTE: we could also do this with the POW instruction
+ "Computed fog exp2 test",
+ "!!ARBfp1.0\n"
+ "# fogParams.x = density \n"
+ "# fogParams.y = start \n"
+ "# fogParams.z = end \n"
+ "# fogParams.w = 1/(end-start) \n"
+ "PARAM fogParams = state.fog.params; \n"
+ "ATTRIB fogCoord = fragment.fogcoord; \n"
+ "PARAM fogColor = state.fog.color; \n"
+ "TEMP f, dc; \n"
+ "# f = exp(-(density * coord)^2) \n"
+ "MUL dc.x, fogParams.x, fogCoord.x; \n"
+ "MUL dc.x, dc.x, dc.x; \n"
+ "EX2_SAT f, -dc.x; \n"
+ "LRP result.color.rgb, f, fragment.color, fogColor; \n"
+ "MOV result.color.a, fragment.color.a; \n"
+ "END \n",
+ { FragColor[0] * FOG_FACT + FogColor[0] * (1.0 - FOG_FACT),
+ FragColor[1] * FOG_FACT + FogColor[1] * (1.0 - FOG_FACT),
+ FragColor[2] * FOG_FACT + FogColor[2] * (1.0 - FOG_FACT),
+ FragColor[3]
+ },
+ DONT_CARE_Z,
+ true
+ },
+#undef FOG_FACT
+
+ // XXX add lots more tests here!
+ { NULL, NULL, {0,0,0,0}, 0, false } // end of list sentinal
+};
+
+
+
+void
+FragmentProgramTest::setup(void)
+{
+ haveFogCoord = false;
+
+ if (GLUtils::haveExtensions("EXT_fog_coord"))
+ haveFogCoord = true;
+
+ // setup Infinity, Nan values
+ int nan;
+ float *nanPtr;
+
+ nan = (0xff << 23) | (1 << 0);
+ nanPtr = (float *) &nan;
+ InfNan[0] = HUGE_VAL;
+ InfNan[1] = -HUGE_VAL;
+ InfNan[2] = (float) (*nanPtr);
+ InfNan[3] = 1.0 / HUGE_VAL;
+
+ // get function pointers
+ glProgramLocalParameter4fvARB_func = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLUtils::getProcAddress("glProgramLocalParameter4fvARB");
+ assert(glProgramLocalParameter4fvARB_func);
+
+ glGenProgramsARB_func = (PFNGLGENPROGRAMSARBPROC) GLUtils::getProcAddress("glGenProgramsARB");
+ assert(glGenProgramsARB_func);
+
+ glProgramStringARB_func = (PFNGLPROGRAMSTRINGARBPROC) GLUtils::getProcAddress("glProgramStringARB");
+ assert(glProgramStringARB_func);
+
+ glBindProgramARB_func = (PFNGLBINDPROGRAMARBPROC) GLUtils::getProcAddress("glBindProgramARB");
+ assert(glBindProgramARB_func);
+
+ glIsProgramARB_func = (PFNGLISPROGRAMARBPROC) GLUtils::getProcAddress("glIsProgramARB");
+ assert(glIsProgramARB_func);
+
+ glDeleteProgramsARB_func = (PFNGLDELETEPROGRAMSARBPROC) GLUtils::getProcAddress("glDeleteProgramsARB");
+ assert(glDeleteProgramsARB_func);
+
+ glGetProgramivARB_func = (PFNGLGETPROGRAMIVARBPROC) GLUtils::getProcAddress("glGetProgramivARB");
+ assert(glGetProgramivARB_func);
+
+ if (haveFogCoord) {
+ glFogCoordf_func = (PFNGLFOGCOORDFPROC) GLUtils::getProcAddress("glFogCoordf");
+ assert(glFogCoordf_func);
+ }
+
+ GLuint progID;
+ glGenProgramsARB_func(1, &progID);
+ glBindProgramARB_func(GL_FRAGMENT_PROGRAM_ARB, progID);
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ // load program inputs
+ glColor4fv(FragColor);
+ glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB, 0, Param0);
+ glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB, 1, Param1);
+ glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB, 2, Param2);
+ glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB, 9, InfNan);
+
+ GLenum err = glGetError();
+ assert(!err); // should be OK
+
+ // setup vertex transform (we'll draw a quad in middle of window)
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+#if DEVEL_MODE
+ glOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 1.0);
+#else
+ glOrtho(-4.0, 4.0, -4.0, 4.0, 0.0, 1.0);
+#endif
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ // other GL state
+ if (haveFogCoord) {
+ glFogf(GL_FOG_START, FogStart);
+ glFogf(GL_FOG_END, FogEnd);
+ glFogf(GL_FOG_DENSITY, FogDensity);
+ glFogfv(GL_FOG_COLOR, FogColor);
+ glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
+ glFogCoordf_func(FogCoord);
+ }
+
+ // compute error tolerances (may need fine-tuning)
+ int bufferBits[5];
+ glGetIntegerv(GL_RED_BITS, &bufferBits[0]);
+ glGetIntegerv(GL_GREEN_BITS, &bufferBits[1]);
+ glGetIntegerv(GL_BLUE_BITS, &bufferBits[2]);
+ glGetIntegerv(GL_ALPHA_BITS, &bufferBits[3]);
+ glGetIntegerv(GL_DEPTH_BITS, &bufferBits[4]);
+
+ tolerance[0] = 2.0 / (1 << bufferBits[0]);
+ tolerance[1] = 2.0 / (1 << bufferBits[1]);
+ tolerance[2] = 2.0 / (1 << bufferBits[2]);
+ if (bufferBits[3])
+ tolerance[3] = 2.0 / (1 << bufferBits[3]);
+ else
+ tolerance[3] = 1.0;
+ if (bufferBits[4])
+ tolerance[4] = 16.0 / (1 << bufferBits[4]);
+ else
+ tolerance[4] = 1.0;
+}
+
+
+void
+FragmentProgramTest::reportFailure(const char *programName,
+ const GLfloat expectedColor[4],
+ const GLfloat actualColor[4] ) const
+{
+ env->log << "FAILURE:\n";
+ env->log << " Program: " << programName << "\n";
+ env->log << " Expected color: ";
+ env->log << expectedColor[0] << ", ";
+ env->log << expectedColor[1] << ", ";
+ env->log << expectedColor[2] << ", ";
+ env->log << expectedColor[3] << "\n";
+ env->log << " Observed color: ";
+ env->log << actualColor[0] << ", ";
+ env->log << actualColor[1] << ", ";
+ env->log << actualColor[2] << ", ";
+ env->log << actualColor[3] << "\n";
+}
+
+
+void
+FragmentProgramTest::reportZFailure(const char *programName,
+ GLfloat expectedZ, GLfloat actualZ) const
+{
+ env->log << "FAILURE:\n";
+ env->log << " Program: " << programName << "\n";
+ env->log << " Expected Z: " << expectedZ << "\n";
+ env->log << " Observed Z: " << actualZ << "\n";
+}
+
+
+// Compare actual and expected colors
+bool
+FragmentProgramTest::equalColors(const GLfloat act[4], const GLfloat exp[4]) const
+{
+ if (fabsf(act[0] - exp[0]) > tolerance[0] && exp[0] != DONT_CARE_COLOR)
+ return false;
+ if (fabsf(act[1] - exp[1]) > tolerance[1] && exp[1] != DONT_CARE_COLOR)
+ return false;
+ if (fabsf(act[2] - exp[2]) > tolerance[2] && exp[2] != DONT_CARE_COLOR)
+ return false;
+ if (fabsf(act[3] - exp[3]) > tolerance[3] && exp[3] != DONT_CARE_COLOR)
+ return false;
+ return true;
+}
+
+
+bool
+FragmentProgramTest::equalDepth(GLfloat z0, GLfloat z1) const
+{
+ if (fabsf(z0 - z1) > tolerance[4])
+ return false;
+ else
+ return true;
+}
+
+
+bool
+FragmentProgramTest::testProgram(const FragmentProgram &p)
+{
+ glProgramStringARB_func(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(p.progString),
+ (const GLubyte *) p.progString);
+
+ GLenum err = glGetError();
+ if (err) {
+ env->log << "OpenGL error " << (int) err << "\n";
+ env->log << "Invalid Fragment Program:\n";
+ env->log << p.progString;
+ env->log << glGetString(GL_PROGRAM_ERROR_STRING_ARB) << "\n";
+ return false;
+ }
+
+ // to avoid potential issue with undefined result.depth.z
+ if (p.expectedZ == DONT_CARE_Z)
+ glDisable(GL_DEPTH_TEST);
+ else
+ glEnable(GL_DEPTH_TEST);
+
+#if !DEVEL_MODE
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+#endif
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+#if !DEVEL_MODE
+ GLfloat pixel[4];
+ glReadPixels(windowWidth / 2, windowHeight / 2, 1, 1,
+ GL_RGBA, GL_FLOAT, pixel);
+
+ if (0) // debug
+ printf("%s: Expect: %.3f %.3f %.3f %.3f found: %.3f %.3f %.3f %.3f\n",
+ p.name,
+ p.expectedColor[0], p.expectedColor[1],
+ p.expectedColor[2], p.expectedColor[3],
+ pixel[0], pixel[1], pixel[2], pixel[3]);
+
+ if (!equalColors(pixel, p.expectedColor)) {
+ reportFailure(p.name, p.expectedColor, pixel);
+ return false;
+ }
+
+ if (p.expectedZ != DONT_CARE_Z) {
+ GLfloat z;
+ glReadPixels(windowWidth / 2, windowHeight / 2, 1, 1,
+ GL_DEPTH_COMPONENT, GL_FLOAT, &z);
+ if (!equalDepth(z, p.expectedZ)) {
+ reportZFailure(p.name, p.expectedZ, z);
+ return false;
+ }
+ }
+#endif
+ return true;
+}
+
+void
+FragmentProgramTest::runOne(MultiTestResult &r, Window &w)
+{
+ (void) w;
+ setup();
+
+ const char* filter;
+
+ filter = getenv("GLEAN_FRAGPROG");
+ if (filter && !strlen(filter))
+ filter = 0;
+
+#if DEVEL_MODE
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+#endif
+ for (int i = 0; Programs[i].name; i++) {
+ if (filter && strcmp(filter, Programs[i].name))
+ continue;
+
+ if (Programs[i].needFogCoord && !haveFogCoord)
+ continue;
+
+#if DEVEL_MODE
+ glViewport(0, i * 20, windowWidth, 20);
+#endif
+ if (!testProgram(Programs[i])) {
+ r.numFailed++;
+ }
+ else {
+ r.numPassed++;
+ }
+ }
+
+#if DEVEL_MODE
+ glFinish();
+ sleep(100);
+#endif
+ r.pass = (r.numFailed == 0);
+}
+
+void
+FragmentProgramTest::printDetails()
+{
+ for (int i = 0; Programs[i].name; i++)
+ env->log << Programs[i].name << '\n';
+}
+
+
+// The test object itself:
+FragmentProgramTest fragmentProgramTest("fragProg1", "window, rgb, z",
+ "GL_ARB_fragment_program",
+ "Fragment Program test 1: test a specific set of fragment programs.\n");
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tfragprog1.h b/tests/glean/tfragprog1.h
new file mode 100644
index 00000000..b36e7a6f
--- /dev/null
+++ b/tests/glean/tfragprog1.h
@@ -0,0 +1,94 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tfragprog.h: Test GL_ARB_fragment_program extension.
+// Brian Paul 22 October 2005
+
+#ifndef __tfragprog_h__
+#define __tfragprog_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+// If DEVEL_MODE==1 we generate a tall window of color swatches, one per
+// fragment program, which can be eyeballed against a reference image.
+// Use this if glReadPixels functionality is not working yet.
+#undef windowWidth
+#undef windowHeight
+#define DEVEL_MODE 0
+#if DEVEL_MODE
+#define windowWidth 200
+#define windowHeight 850
+#else
+#define windowWidth 100
+#define windowHeight 100
+#endif
+
+
+class FragmentProgram
+{
+public:
+ const char *name;
+ const char *progString;
+ const GLfloat expectedColor[4];
+ const GLfloat expectedZ;
+ const bool needFogCoord;
+};
+
+
+class FragmentProgramTest: public MultiTest
+{
+public:
+ FragmentProgramTest(const char* testName, const char* filter,
+ const char *extensions, const char* description)
+ : MultiTest(testName, filter, extensions, description)
+ {
+ }
+
+ virtual void runOne(MultiTestResult &r, Window &w);
+
+private:
+ GLfloat tolerance[5];
+ bool haveFogCoord;
+
+ void setup(void);
+ bool equalColors(const GLfloat a[4], const GLfloat b[4]) const;
+ bool equalDepth(GLfloat z0, GLfloat z1) const;
+ bool testProgram(const FragmentProgram &p);
+ void reportFailure(const char *programName,
+ const GLfloat expectedColor[4],
+ const GLfloat actualColor[4] ) const;
+ void reportZFailure(const char *programName,
+ GLfloat expectedZ, GLfloat actualZ) const;
+ void printDetails();
+};
+
+} // namespace GLEAN
+
+#endif // __tfragprog_h__
diff --git a/tests/glean/tgetstr.cpp b/tests/glean/tgetstr.cpp
new file mode 100644
index 00000000..22c3347d
--- /dev/null
+++ b/tests/glean/tgetstr.cpp
@@ -0,0 +1,167 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tgetstr.cpp: implementation of OpenGL glGetString() tests
+
+using namespace std;
+
+#include "tgetstr.h"
+#include <algorithm>
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+GetStringTest::runOne(GetStringResult& r, Window&) {
+ r.vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ r.renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
+ r.version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ r.extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
+ r.pass = true;
+} // GetStringTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+GetStringTest::logOne(GetStringResult& r) {
+ logPassFail(r);
+ logConcise(r);
+ if (env->options.verbosity) {
+ env->log << "\tvendor: " << r.vendor << '\n';
+ env->log << "\trenderer: " << r.renderer << '\n';
+ env->log << "\tversion: " << r.version << '\n';
+ env->log << "\textensions: " << r.extensions << '\n';
+ }
+} // GetStringTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+GetStringTest::compareOne(GetStringResult& oldR, GetStringResult& newR) {
+ if (oldR.vendor == newR.vendor && oldR.renderer == newR.renderer
+ && oldR.version == newR.version && oldR.extensions == newR.extensions){
+ if (env->options.verbosity)
+ env->log << name << ": SAME " <<
+ newR.config->conciseDescription() << '\n';
+ } else {
+ env->log << name << ": DIFF "
+ << newR.config->conciseDescription() << '\n';
+ if (oldR.vendor != newR.vendor) {
+ env->log << '\t' << env->options.db1Name
+ << " vendor: " << oldR.vendor;
+ env->log << '\t' << env->options.db2Name
+ << " vendor: " << newR.vendor;
+ }
+ if (oldR.renderer != newR.renderer) {
+ env->log << '\t' << env->options.db1Name
+ << " renderer: " << oldR.renderer;
+ env->log << '\t' << env->options.db2Name
+ << " renderer: " << newR.renderer;
+ }
+ if (oldR.version != newR.version) {
+ env->log << '\t' << env->options.db1Name
+ << " version: " << oldR.version;
+ env->log << '\t' << env->options.db2Name
+ << " version: " << newR.version;
+ }
+ if (oldR.extensions != newR.extensions) {
+ vector<string> oldExts;
+ Lex oldLex(oldR.extensions.c_str());
+ for (;;) {
+ oldLex.next();
+ if (oldLex.token == Lex::ID)
+ oldExts.push_back(oldLex.id);
+ else
+ break;
+ }
+ sort(oldExts.begin(), oldExts.end());
+
+ vector<string> newExts;
+ Lex newLex(newR.extensions.c_str());
+ for (;;) {
+ newLex.next();
+ if (newLex.token == Lex::ID)
+ newExts.push_back(newLex.id);
+ else
+ break;
+ }
+ sort(newExts.begin(), newExts.end());
+
+ vector<string> d(max(oldExts.size(), newExts.size()));
+ vector<string>::iterator dEnd;
+
+ dEnd = set_difference(oldExts.begin(), oldExts.end(),
+ newExts.begin(), newExts.end(), d.begin());
+ if (dEnd != d.begin()) {
+ env->log << "\tExtensions in " <<
+ env->options.db1Name << " but not in "
+ << env->options.db2Name << ":\n";
+ for (vector<string>::iterator p = d.begin();
+ p != dEnd; ++p)
+ env->log << "\t\t" << *p << '\n';
+ }
+
+ dEnd = set_difference(newExts.begin(), newExts.end(),
+ oldExts.begin(), oldExts.end(), d.begin());
+ if (dEnd != d.begin()) {
+ env->log << "\tExtensions in " <<
+ env->options.db2Name << " but not in "
+ << env->options.db1Name << ":\n";
+ for (vector<string>::iterator p = d.begin();
+ p != dEnd; ++p)
+ env->log << "\t\t" << *p << '\n';
+ }
+
+ dEnd = set_intersection(newExts.begin(), newExts.end(),
+ oldExts.begin(), oldExts.end(), d.begin());
+ if (dEnd != d.begin()) {
+ env->log << "\tExtensions in both " <<
+ env->options.db2Name << " and in "
+ << env->options.db1Name << ":\n";
+ for (vector<string>::iterator p = d.begin();
+ p != dEnd; ++p)
+ env->log << "\t\t" << *p << '\n';
+ }
+ }
+ }
+} // GetStringTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+GetStringTest getStringTest("getString", "window",
+ "This test checks the contents of the strings returned by\n"
+ "glGetString(): the vendor name, renderer name, version, and\n"
+ "extensions. It is run on every OpenGL-capable drawing surface\n"
+ "configuration that supports creation of a window.\n");
+
+} // namespace GLEAN
diff --git a/tests/glean/tgetstr.h b/tests/glean/tgetstr.h
new file mode 100644
index 00000000..d0465b5d
--- /dev/null
+++ b/tests/glean/tgetstr.h
@@ -0,0 +1,75 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// tgetstr.h: Check OpenGL vendor, renderer, version, and extension strings
+
+// See tbasic.cpp for the basic test structure.
+
+
+#ifndef __tgetstr_h__
+#define __tgetstr_h__
+
+#include "tbase.h"
+
+class DrawingSurfaceConfig; // Forward reference.
+
+namespace GLEAN {
+
+class GetStringResult: public BaseResult {
+public:
+ bool pass;
+ string vendor;
+ string renderer;
+ string version;
+ string extensions;
+
+ void putresults(ostream& s) const {
+ s << vendor << '\n';
+ s << renderer << '\n';
+ s << version << '\n';
+ s << extensions << '\n';
+ }
+
+ bool getresults(istream& s) {
+ getline(s, vendor);
+ getline(s, renderer);
+ getline(s, version);
+ getline(s, extensions);
+ return s.good();
+ }
+};
+
+class GetStringTest: public BaseTest<GetStringResult> {
+public:
+ GLEAN_CLASS(GetStringTest, GetStringResult);
+}; // class GetStringTest
+
+} // namespace GLEAN
+
+#endif // __tgetstr_h__
diff --git a/tests/glean/timer.cpp b/tests/glean/timer.cpp
new file mode 100644
index 00000000..54994603
--- /dev/null
+++ b/tests/glean/timer.cpp
@@ -0,0 +1,232 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999-2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// timer.cpp: Implementation of simple benchmark timer utilities.
+
+// This particular implementation is derived from the one in libpdb,
+// part of the isfast library for OpenGL.
+
+// XXXWIN as of 5/8/99: The code for Windows timing is taken from
+// Michael Gold's implementation of libpdb. I've probably introduced
+// some bugs in the translation, unfortunately. [Allen]
+
+// Modified from original timer.cpp by Rickard E. (Rik) Faith
+// <faith@valinux.com>, December 2000
+
+#include "timer.h"
+#include <vector>
+#include <algorithm>
+using namespace std;
+
+#if defined(__UNIX__)
+# include <sys/time.h> // for gettimeofday, used by getClock
+#elif defined(__MS__)
+# include <windows.h>
+# include <sys/types.h>
+# include <sys/timeb.h> // for _ftime(), used by getClock
+#endif
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// calibrate: Determine overhead of measurement, initialization routine,
+// and finalization routine
+///////////////////////////////////////////////////////////////////////////////
+void
+Timer::calibrate() {
+ double runTime = chooseRunTime();
+
+ preop();
+
+ long reps = 0;
+ double current;
+ double start = waitForTick();
+ do {
+ postop();
+ ++reps;
+ } while ((current = getClock()) < start + runTime);
+
+ overhead = (current - start) / (double) reps;
+ calibrated = true;
+} // Timer::calibrate
+
+///////////////////////////////////////////////////////////////////////////////
+// chooseRunTime: Select an appropriate runtime for benchmarks.
+// By running for at least 10000 ticks, and attempting to keep timing
+// accurate to one tick, we hope to make our results repeatable.
+// (ignoring all the other stuff that might be going on in the system,
+// of course). Long runs reduce the effect of measurement error, but
+// short runs reduce the chance that some other process on the system
+// will steal time.
+///////////////////////////////////////////////////////////////////////////////
+double
+Timer::chooseRunTime() {
+ double start = getClock();
+ double finish;
+
+ // Wait for next tick:
+ while ((finish = getClock()) == start)
+ ;
+
+ // Run for 10000 ticks, clamped to [0.1 sec, 5.0 sec]:
+ double runTime = 10000.0 * (finish - start);
+ if (runTime < 0.1)
+ runTime = 0.1;
+ else if (runTime > 5.0)
+ runTime = 5.0;
+
+ return runTime;
+} // Timer::chooseRunTime
+
+///////////////////////////////////////////////////////////////////////////////
+// getClock - get current wall-clock time (expressed in seconds)
+///////////////////////////////////////////////////////////////////////////////
+double
+Timer::getClock() {
+#if defined(__MS__)
+ static int once = 1;
+ static double freq;
+
+ if (once) {
+ LARGE_INTEGER fr;
+ freq = (double) (QueryPerformanceFrequency(&fr) ?
+ 1.0 / fr.QuadPart : 0);
+ once = 0;
+ }
+
+ // Use high-resolution counter, if available
+ if (freq) {
+ LARGE_INTEGER pc;
+ QueryPerformanceCounter(&pc);
+ return freq * (double) pc.QuadPart;
+ } else {
+ struct _timeb t;
+
+ _ftime(&t);
+
+ return (double) t.time + (double) t.millitm * 1E-3;
+ }
+#elif defined(__UNIX__)
+ struct timeval t;
+
+ // XXX gettimeofday is different on SysV, if I remember correctly
+ gettimeofday(&t, 0);
+
+ return (double) t.tv_sec + (double) t.tv_usec * 1E-6;
+#endif
+} // Timer::getClock
+
+///////////////////////////////////////////////////////////////////////////////
+// waitForTick: wait for beginning of next system clock tick; return the time.
+///////////////////////////////////////////////////////////////////////////////
+double
+Timer::waitForTick() {
+ double start;
+ double current;
+
+ start = getClock();
+
+ // Wait for next tick:
+ while ((current = getClock()) == start)
+ ;
+
+ // Start timing:
+ return current;
+} // Timer::waitForTick
+
+///////////////////////////////////////////////////////////////////////////////
+// time: measure time (in seconds) to perform caller's operation
+///////////////////////////////////////////////////////////////////////////////
+double
+Timer::time() {
+ // Select a run time that's appropriate for our timer resolution:
+ double runTime = chooseRunTime();
+
+ // Measure successively larger batches of operations until we find
+ // one that's long enough to meet our runtime target:
+ long reps = 1;
+ double start;
+ double current;
+ for (;;) {
+ preop();
+
+ start = waitForTick();
+
+ for (long i = reps; i > 0; --i) op();
+
+
+ postop();
+
+ current = getClock();
+ if (current >= start + runTime + overhead)
+ break;
+
+ // Try to reach runtime target in one fell swoop:
+ long newReps;
+ if (current > start + overhead)
+ newReps = static_cast<long> (reps *
+ (0.5 + runTime / (current - start - overhead)));
+ else
+ newReps = reps * 2;
+ if (newReps == reps)
+ reps += 1;
+ else
+ reps = newReps;
+ }
+
+ // Subtract overhead to determine the final operation rate:
+ return (current - start - overhead) / reps;
+} // Timer::time
+
+///////////////////////////////////////////////////////////////////////////////
+// measure: measure several results for performing caller's operation
+///////////////////////////////////////////////////////////////////////////////
+void
+Timer::measure(int count, double* low, double* avg, double* high)
+{
+ vector<double> m;
+ double sum = 0.0;
+
+ if (!calibrated) calibrate();
+ if (count < 3) count = 3;
+ premeasure();
+ for (int i = 0; i < count; i++) {
+ preop();
+ double t = time();
+ postop();
+ m.push_back(compute(t));
+ }
+ postmeasure();
+ sort(m.begin(), m.end());
+ for (int j = 1; j < count - 1; j++) sum += m[j];
+ *avg = sum / (count - 2);
+ *low = m[1];
+ *high = m[count - 2];
+} // Timer::measure
+
+} // namespace GLEAN
diff --git a/tests/glean/timer.h b/tests/glean/timer.h
new file mode 100644
index 00000000..41a80c5a
--- /dev/null
+++ b/tests/glean/timer.h
@@ -0,0 +1,74 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999-2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// timer.h: Simple benchmark timing utilities based on the previous timer.h
+// Modified from timer.h by Rickard E. (Rik) Faith <faith@valinux.com>
+
+// Timer objects provide a framework for measuring the rate at which an
+// operation can be performed.
+
+#ifndef __timer_h__
+#define __timer_h__
+
+namespace GLEAN {
+
+class Timer {
+ double overhead; // Overhead (in seconds) of initial op,
+ // final op, and timer access.
+
+ int calibrated; // Has calibrate been called?
+
+ double chooseRunTime(); // Select a runtime that will reduce random
+ // timing error to an acceptable level.
+
+public:
+ virtual void premeasure() {}; // called in measure(), before time()
+ virtual void postmeasure() {}; // called in measure(), after time()
+ virtual void preop() {}; // before op, in each loop in time()
+ virtual void op() {}; // in each loop in time()
+ virtual void postop() {}; // after op, in each loop in time()
+ virtual double compute(double t) {
+ // modify measure()'s result -- e.g., by computing a rate
+ return t;
+ }
+
+ void calibrate();
+ double time();
+ double getClock(); // Get wall-clock time, in seconds
+ double waitForTick(); // Wait for next clock tick; return time
+ void measure(int count,
+ double* low, double* avg, double* high);
+
+ Timer() { overhead = 0.0; calibrated = false; }
+ virtual ~Timer() { /* just silence warning */ }
+
+}; // class Timer
+
+} // namespace GLEAN
+
+#endif // __timer_h__
diff --git a/tests/glean/tlogicop.cpp b/tests/glean/tlogicop.cpp
new file mode 100644
index 00000000..06a80cfc
--- /dev/null
+++ b/tests/glean/tlogicop.cpp
@@ -0,0 +1,573 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tlogicop.cpp: Test RGBA logic op functions.
+// Based on Allen's blendFunc test.
+// Brian Paul 10 May 2001
+
+#include "tlogicop.h"
+#include "rand.h"
+#include "image.h"
+#include <cmath>
+
+namespace {
+
+struct logicopNameMapping {GLenum op; char* name;};
+logicopNameMapping logicopNames[] = {
+ {GL_CLEAR, "GL_CLEAR"},
+ {GL_SET, "GL_SET"},
+ {GL_COPY, "GL_COPY"},
+ {GL_COPY_INVERTED, "GL_COPY_INVERTED"},
+ {GL_NOOP, "GL_NOOP"},
+ {GL_INVERT, "GL_INVERT"},
+ {GL_AND, "GL_AND"},
+ {GL_NAND, "GL_NAND"},
+ {GL_OR, "GL_OR"},
+ {GL_NOR, "GL_NOR"},
+ {GL_XOR, "GL_XOR"},
+ {GL_EQUIV, "GL_EQUIV"},
+ {GL_AND_REVERSE, "GL_AND_REVERSE"},
+ {GL_AND_INVERTED, "GL_AND_INVERTED"},
+ {GL_OR_REVERSE, "GL_OR_REVERSE"},
+ {GL_OR_INVERTED, "GL_OR_INVERTED"}
+};
+
+char*
+logicopToName(GLenum op) {
+ for (unsigned int i = 0;
+ i < sizeof(logicopNames) / sizeof(logicopNames[0]); ++i) {
+ if (logicopNames[i].op == op)
+ return logicopNames[i].name;
+ }
+ return 0;
+} // logicopToName
+
+GLenum
+nameToLogicop(string& name) {
+ for (unsigned int i = 0;
+ i < sizeof(logicopNames) / sizeof(logicopNames[0]); ++i) {
+ if (logicopNames[i].name == name)
+ return logicopNames[i].op;
+ }
+ return GL_ZERO;
+} // nameToLogicop
+
+void
+makeRGBA(GLEAN::RandomBits& rRand,
+ GLEAN::RandomBits& gRand,
+ GLEAN::RandomBits& bRand,
+ GLEAN::RandomBits& aRand,
+ GLubyte* rgba) {
+ rgba[0] = rRand.next() & 0xff;
+ rgba[1] = gRand.next() & 0xff;
+ rgba[2] = bRand.next() & 0xff;
+ rgba[3] = aRand.next() & 0xff;
+} // makeRGBA
+
+void
+drawQuad(const int x, const int y, const GLubyte* color) {
+ glColor4ubv(color);
+ glBegin(GL_QUADS);
+ glVertex2i(x, y);
+ glVertex2i(x + 1, y);
+ glVertex2i(x + 1, y + 1);
+ glVertex2i(x, y + 1);
+ glEnd();
+} // drawQuad
+
+void
+applyLogicop(GLenum logicop, GLubyte dst[4], const GLubyte src[4]) {
+
+ switch (logicop) {
+ case GL_CLEAR:
+ dst[0] = dst[1] = dst[2] = dst[3] = 0;
+ break;
+ case GL_SET:
+ dst[0] = dst[1] = dst[2] = dst[3] = ~0;
+ break;
+ case GL_COPY:
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ break;
+ case GL_COPY_INVERTED:
+ dst[0] = ~src[0];
+ dst[1] = ~src[1];
+ dst[2] = ~src[2];
+ dst[3] = ~src[3];
+ break;
+ case GL_NOOP:
+ break;
+ case GL_INVERT:
+ dst[0] = ~dst[0];
+ dst[1] = ~dst[1];
+ dst[2] = ~dst[2];
+ dst[3] = ~dst[3];
+ break;
+ case GL_AND:
+ dst[0] = src[0] & dst[0];
+ dst[1] = src[1] & dst[1];
+ dst[2] = src[2] & dst[2];
+ dst[3] = src[3] & dst[3];
+ break;
+ case GL_NAND:
+ dst[0] = ~(src[0] & dst[0]);
+ dst[1] = ~(src[1] & dst[1]);
+ dst[2] = ~(src[2] & dst[2]);
+ dst[3] = ~(src[3] & dst[3]);
+ break;
+ case GL_OR:
+ dst[0] = src[0] | dst[0];
+ dst[1] = src[1] | dst[1];
+ dst[2] = src[2] | dst[2];
+ dst[3] = src[3] | dst[3];
+ break;
+ case GL_NOR:
+ dst[0] = ~(src[0] | dst[0]);
+ dst[1] = ~(src[1] | dst[1]);
+ dst[2] = ~(src[2] | dst[2]);
+ dst[3] = ~(src[3] | dst[3]);
+ break;
+ case GL_XOR:
+ dst[0] = src[0] ^ dst[0];
+ dst[1] = src[1] ^ dst[1];
+ dst[2] = src[2] ^ dst[2];
+ dst[3] = src[3] ^ dst[3];
+ break;
+ case GL_EQUIV:
+ dst[0] = ~(src[0] ^ dst[0]);
+ dst[1] = ~(src[1] ^ dst[1]);
+ dst[2] = ~(src[2] ^ dst[2]);
+ dst[3] = ~(src[3] ^ dst[3]);
+ break;
+ case GL_AND_REVERSE:
+ dst[0] = src[0] & ~dst[0];
+ dst[1] = src[1] & ~dst[1];
+ dst[2] = src[2] & ~dst[2];
+ dst[3] = src[3] & ~dst[3];
+ break;
+ case GL_AND_INVERTED:
+ dst[0] = ~src[0] & dst[0];
+ dst[1] = ~src[1] & dst[1];
+ dst[2] = ~src[2] & dst[2];
+ dst[3] = ~src[3] & dst[3];
+ break;
+ case GL_OR_REVERSE:
+ dst[0] = src[0] | ~dst[0];
+ dst[1] = src[1] | ~dst[1];
+ dst[2] = src[2] | ~dst[2];
+ dst[3] = src[3] | ~dst[3];
+ break;
+ case GL_OR_INVERTED:
+ dst[0] = ~src[0] | dst[0];
+ dst[1] = ~src[1] | dst[1];
+ dst[2] = ~src[2] | dst[2];
+ dst[3] = ~src[3] | dst[3];
+ break;
+ default:
+ abort(); // implementation error
+ }
+} // applyLogicop
+
+// return number of bits set differenty in a and b.
+static int bitDifference(GLbyte a, GLubyte b) {
+ int count = 0;
+ for (int i = 0; i < 8; i++) {
+ GLubyte mask = 1 << i;
+ if ((a & mask) != (b & mask))
+ count++;
+ }
+ return count;
+}
+
+static GLubyte redMask, greenMask, blueMask, alphaMask;
+
+static void
+computeError(const GLubyte aPix[4], const GLubyte ePix[4],
+ int &er, int &eg, int &eb, int &ea) {
+ if ((aPix[0] & redMask ) == (ePix[0] & redMask ) &&
+ (aPix[1] & greenMask) == (ePix[1] & greenMask) &&
+ (aPix[2] & blueMask ) == (ePix[2] & blueMask ) &&
+ (aPix[3] & alphaMask) == (ePix[3] & alphaMask)) {
+ er = eg = eb = ea = 0; // no error at all
+ }
+ else {
+ // count up total bit difference
+ er = bitDifference(aPix[0] & redMask, ePix[0] & redMask);
+ eg = bitDifference(aPix[1] & greenMask, ePix[1] & greenMask);
+ eb = bitDifference(aPix[2] & blueMask, ePix[2] & blueMask);
+ ea = bitDifference(aPix[3] & alphaMask, ePix[3] & alphaMask);
+ }
+}
+
+struct runResult {float readbackErrorBits; float logicopErrorBits;};
+
+static runResult
+runTest(GLenum logicop,
+ GLEAN::DrawingSurfaceConfig& config, GLEAN::Environment& env) {
+ using namespace GLEAN;
+
+ runResult result;
+ int y;
+
+ // Compute error bitmasks depending on color channel sizes
+ redMask = ((1 << config.r) - 1) << (8 - config.r);
+ greenMask = ((1 << config.g) - 1) << (8 - config.g);
+ blueMask = ((1 << config.b) - 1) << (8 - config.b);
+ alphaMask = ((1 << config.a) - 1) << (8 - config.a);
+
+ glDisable(GL_DITHER);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ Image dst(drawingSize, drawingSize, GL_RGBA, GL_UNSIGNED_BYTE);
+ RandomBits rRand(config.r, 6021023);
+ RandomBits gRand(config.g, 1137);
+ RandomBits bRand(config.b, 1138);
+ RandomBits aRand(config.a, 6);
+
+ // Fill the framebuffer with random RGBA values, and place a copy
+ // in ``dst'':
+ glDisable(GL_COLOR_LOGIC_OP);
+ char* dRow = dst.pixels();
+ for (y = 0; y < drawingSize; ++y) {
+ GLubyte* pix = reinterpret_cast<GLubyte*>(dRow);
+ for (int x = 0; x < drawingSize; ++x) {
+ GLubyte rgba[4];
+ makeRGBA(rRand, gRand, bRand, aRand, rgba);
+ drawQuad(x + 1, y + 1, rgba);
+ pix[0] = rgba[0];
+ pix[1] = rgba[1];
+ pix[2] = rgba[2];
+ pix[3] = rgba[3];
+ pix += 4;
+ }
+ dRow += dst.rowSizeInBytes();
+ }
+
+ // Read back the contents of the framebuffer, and measure any
+ // difference from what was actually written. We can't tell
+ // whether errors occurred when writing or when reading back,
+ // but at least we can report anything unusual.
+ Image fbDst(drawingSize, drawingSize, GL_RGBA, GL_UNSIGNED_BYTE);
+ fbDst.read(1, 1);
+ Image::Registration reg1(fbDst.reg(dst));
+ result.readbackErrorBits =
+ max(ErrorBits(reg1.stats[0].max(), config.r),
+ max(ErrorBits(reg1.stats[1].max(), config.g),
+ max(ErrorBits(reg1.stats[2].max(), config.b),
+ ErrorBits(reg1.stats[3].max(), config.a))));
+
+ // Now generate random source pixels and apply the logicop
+ // operation to both the framebuffer and a copy in the image
+ // ``expected''. Save the source pixels in the image ``src''
+ // so we can diagnose any problems we find later.
+ Image expected(fbDst);
+ Image src(drawingSize, drawingSize, GL_RGBA, GL_UNSIGNED_BYTE);
+
+ glLogicOp(logicop);
+ glEnable(GL_COLOR_LOGIC_OP);
+
+ dRow = expected.pixels();
+ char* sRow = src.pixels();
+ for (y = 0; y < drawingSize; ++y) {
+ GLubyte* pix = reinterpret_cast<GLubyte*>(dRow);
+ GLubyte* sPix = reinterpret_cast<GLubyte*>(sRow);
+ for (int x = 0; x < drawingSize; ++x) {
+ GLubyte rgba[4];
+ makeRGBA(rRand, gRand, bRand, aRand, rgba);
+ sPix[0] = rgba[0];
+ sPix[1] = rgba[1];
+ sPix[2] = rgba[2];
+ sPix[3] = rgba[3];
+ drawQuad(x + 1, y + 1, rgba);
+ applyLogicop(logicop, pix, rgba);
+ pix += 4;
+ sPix += 4;
+ }
+ dRow += expected.rowSizeInBytes();
+ sRow += src.rowSizeInBytes();
+ }
+
+ // Read the generated image (``actual'') and compare it to the
+ // computed image (``expected'') to see if any pixels are
+ // outside the expected tolerance range (one LSB). If so,
+ // report the first such pixel, along with the source and
+ // destination values that generated it. Keep track of the
+ // maximum error encountered.
+ Image actual(drawingSize, drawingSize, GL_RGBA, GL_UNSIGNED_BYTE);
+ actual.read(1, 1);
+ result.logicopErrorBits = 0.0;
+ sRow = actual.pixels();
+ dRow = expected.pixels();
+ for (y = 0; y < drawingSize; ++y) {
+ GLubyte* aPix = reinterpret_cast<GLubyte*>(sRow);
+ GLubyte* ePix = reinterpret_cast<GLubyte*>(dRow);
+ for (int x = 0; x < drawingSize; ++x) {
+ int rErr, gErr, bErr, aErr;
+ computeError(aPix, ePix, rErr, gErr, bErr, aErr);
+ result.logicopErrorBits = rErr + gErr + bErr + aErr;
+
+ if (result.logicopErrorBits > 1.0) {
+ if (env.options.verbosity) {
+GLubyte* sPix = reinterpret_cast<GLubyte*>(src.pixels()
+ + y * src.rowSizeInBytes() + x * 4 * sizeof(GLubyte));
+GLubyte* dPix = reinterpret_cast<GLubyte*>(dst.pixels()
+ + y * dst.rowSizeInBytes() + x * 4 * sizeof(GLubyte));
+env.log << '\n'
+<< "First failing pixel is at row " << y << " column " << x << "\n"
+<< "Actual values are (" << (int) aPix[0] << ", " << (int) aPix[1] << ", "
+ << (int) aPix[2] << ", " << (int) aPix[3] << ")\n"
+<< "Expected values are (" << (int) ePix[0] << ", " << (int) ePix[1] << ", "
+ << (int) ePix[2] << ", " << (int) ePix[3] << ")\n"
+<< "Errors (number of bad bits) are (" << rErr << ", " << gErr << ", "
+ << bErr << ", " << aErr << ")\n"
+<< "Source values are (" << (int) sPix[0] << ", " << (int) sPix[1] << ", "
+ << (int) sPix[2] << ", " << (int) sPix[3] << ")\n"
+<< "Destination values are (" << (int) dPix[0] << ", " << (int) dPix[1] << ", "
+ << (int) dPix[2] << ", " << (int) dPix[3] << ")\n";
+ }
+ return result;
+ }
+ aPix += 4;
+ ePix += 4;
+ }
+ sRow += actual.rowSizeInBytes();
+ dRow += expected.rowSizeInBytes();
+ }
+
+ return result;
+} // runOneSet
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+LogicopFuncTest::runOne(LogicopFuncResult& r, Window& w) {
+ GLUtils::useScreenCoords(drawingSize + 2, drawingSize + 2);
+
+ static GLenum logicopModes[] = {
+ GL_CLEAR,
+ GL_SET,
+ GL_COPY,
+ GL_COPY_INVERTED,
+ GL_NOOP,
+ GL_INVERT,
+ GL_AND,
+ GL_NAND,
+ GL_OR,
+ GL_NOR,
+ GL_XOR,
+ GL_EQUIV,
+ GL_AND_REVERSE,
+ GL_AND_INVERTED,
+ GL_OR_REVERSE,
+ GL_OR_INVERTED
+ };
+
+ bool allPassed = true;
+ for (unsigned int op = 0;
+ op < sizeof(logicopModes)/sizeof(logicopModes[0]); ++op) {
+
+ LogicopFuncResult::PartialResult p;
+ p.logicop = logicopModes[op];
+
+ runResult res = runTest(p.logicop, *(r.config), *env);
+ w.swap();
+
+ p.rbErr = res.readbackErrorBits;
+ p.opErr = res.logicopErrorBits;
+ r.results.push_back(p);
+
+ if (p.rbErr > 1.0 || p.opErr > 1.0) {
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription()<< '\n'
+ << "\tlogicop mode = "
+ << logicopToName(p.logicop)
+ << "\n\tReadback had " << p.rbErr
+ << " bits in error; logicop had "
+ << p.opErr << " bits in error.\n";
+ allPassed = false;
+ }
+ }
+
+ r.pass = allPassed;
+} // LogicopFuncTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+LogicopFuncTest::logOne(LogicopFuncResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+LogicopFuncTest::compareOne(LogicopFuncResult& oldR, LogicopFuncResult& newR) {
+ BasicStats readbackStats;
+ BasicStats logicopStats;
+
+ vector<LogicopFuncResult::PartialResult>::const_iterator np;
+ vector<LogicopFuncResult::PartialResult>::const_iterator op;
+
+ for (np = newR.results.begin(); np != newR.results.end(); ++np) {
+ // Find the matching case, if any, in the old results:
+ for (op = oldR.results.begin(); op != oldR.results.end(); ++op)
+ if (np->logicop == op->logicop) {
+ readbackStats.sample(np->rbErr - op->rbErr);
+ logicopStats.sample(np->opErr - op->opErr);
+ }
+ }
+
+ if (readbackStats.n() == static_cast<int>(newR.results.size())
+ && newR.results.size() == oldR.results.size()
+ && readbackStats.mean() == 0.0 && logicopStats.mean() == 0.0) {
+ if (env->options.verbosity)
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription() << '\n';
+ } else {
+ env->log << name << ": DIFF "
+ << newR.config->conciseDescription() << '\n';
+
+ if (readbackStats.mean() < 0.0)
+ env->log << '\t' << env->options.db2Name
+ << " appears to have more accurate readback.\n";
+ else if (readbackStats.mean() > 0.0)
+ env->log << '\t' << env->options.db1Name
+ << " appears to have more accurate readback.\n";
+ if (logicopStats.mean() < 0.0)
+ env->log << '\t' << env->options.db2Name
+ << " appears to have more accurate logicoping.\n";
+ else if (logicopStats.mean() > 0.0)
+ env->log << '\t' << env->options.db1Name
+ << " appears to have more accurate logicoping.\n";
+ if (readbackStats.n() != static_cast<int>(newR.results.size())){
+ env->log << "\tThe following cases in "
+ << env->options.db2Name
+ << " have no matching test in "
+ << env->options.db1Name
+ << ":\n";
+ for (np = newR.results.begin();
+ np != newR.results.end(); ++np) {
+ for (op = oldR.results.begin();
+ op != oldR.results.end(); ++op)
+ if (np->logicop == op->logicop)
+ break;
+ if (op == oldR.results.end())
+ env->log << "\t\t"
+ << logicopToName(np->logicop)
+ << '\n';
+ }
+ }
+ if (readbackStats.n() != static_cast<int>(oldR.results.size())){
+ env->log << "\tThe following cases in "
+ << env->options.db1Name
+ << " have no matching test in "
+ << env->options.db2Name
+ << ":\n";
+ for (op = oldR.results.begin();
+ op != oldR.results.end(); ++op) {
+ for (np = newR.results.begin();
+ np != newR.results.end(); ++np)
+ if (op->logicop == np->logicop)
+ break;
+ if (np == newR.results.end())
+ env->log << "\t\t"
+ << logicopToName(op->logicop)
+ << '\n';
+ }
+ }
+ if (env->options.verbosity) {
+ env->log << "\tThe following cases appear in both "
+ << env->options.db1Name
+ << " and "
+ << env->options.db2Name
+ << ":\n";
+ for (np = newR.results.begin();
+ np != newR.results.end(); ++np){
+ for (op = oldR.results.begin();
+ op != oldR.results.end(); ++op)
+ if (np->logicop == op->logicop)
+ break;
+ if (op != oldR.results.end())
+ env->log << "\t\t"
+ << logicopToName(np->logicop)
+ << '\n';
+ }
+ }
+ }
+} // LogicopFuncTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// Result I/O functions:
+///////////////////////////////////////////////////////////////////////////////
+void
+LogicopFuncResult::putresults(ostream& s) const {
+ s << results.size() << '\n';
+ for (vector<PartialResult>::const_iterator p = results.begin();
+ p != results.end(); ++p) {
+ s << logicopToName(p->logicop) << ' '
+ << p->rbErr << ' ' << p->opErr << '\n';
+ }
+} // LogicopFuncResult::put
+
+bool
+LogicopFuncResult::getresults(istream& s) {
+ int n;
+ s >> n;
+ for (int i = 0; i < n; ++i) {
+ PartialResult p;
+ string src;
+ s >> src >> p.rbErr >> p.opErr;
+ p.logicop = nameToLogicop(src);
+ results.push_back(p);
+ }
+
+ return s.good();
+} // LogicopFuncResult::get
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+LogicopFuncTest logicopFuncTest("logicOp", "window, rgb",
+
+ "This test checks the logicop functions in RGBA mode.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tlogicop.h b/tests/glean/tlogicop.h
new file mode 100644
index 00000000..0e670b0a
--- /dev/null
+++ b/tests/glean/tlogicop.h
@@ -0,0 +1,66 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tlogicop.h: Test RGBA logic op functions.
+// Based on Allen's blendFunc test.
+// Brian Paul 10 May 2001
+
+#ifndef __tlogicop_h__
+#define __tlogicop_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define drawingSize 64
+#define windowSize (drawingSize + 2)
+
+class LogicopFuncResult: public BaseResult {
+public:
+ bool pass; // not written to log file
+
+ struct PartialResult {
+ GLenum logicop; // The logic op
+ float rbErr; // Max readback error, in bits.
+ float opErr; // Max logicop error, in bits.
+ };
+ vector<PartialResult> results;
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+class LogicopFuncTest: public BaseTest<LogicopFuncResult> {
+public:
+ GLEAN_CLASS_WH(LogicopFuncTest, LogicopFuncResult,
+ windowSize, windowSize);
+}; // class LogicopFuncTest
+
+} // namespace GLEAN
+
+#endif // __tlogicop_h__
diff --git a/tests/glean/tmaskedclear.cpp b/tests/glean/tmaskedclear.cpp
new file mode 100644
index 00000000..b8fd6f9e
--- /dev/null
+++ b/tests/glean/tmaskedclear.cpp
@@ -0,0 +1,266 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tmaskedclear.cpp: Test color/index masking with glClear.
+
+#include "tmaskedclear.h"
+#include "rand.h"
+#include "image.h"
+
+namespace GLEAN {
+
+void
+MaskedClearTest::failRGB(BasicResult &r, GLint chan, GLfloat expected,
+ GLfloat actual, GLint buffer)
+{
+ static const char *chanNames[] = { "Red", "Green", "Blue", "Alpha" };
+ static const char *bufferNames[] = { "GL_FRONT", "GL_BACK" };
+ GLboolean mask[4];
+ glGetBooleanv(GL_COLOR_WRITEMASK, mask);
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n'
+ << "\t" << chanNames[chan] << " is " << actual
+ << ", expected " << expected
+ << " in " << bufferNames[buffer] << " buffer\n";
+ env->log << "\tGL_COLOR_WRITEMASK = ("
+ << (mask[0] ? "GL_TRUE" : "GL_FALSE") << ", "
+ << (mask[1] ? "GL_TRUE" : "GL_FALSE") << ", "
+ << (mask[2] ? "GL_TRUE" : "GL_FALSE") << ", "
+ << (mask[3] ? "GL_TRUE" : "GL_FALSE") << ")\n";
+}
+
+void
+MaskedClearTest::failCI(BasicResult& r, GLuint expected, GLuint actual,
+ GLint buffer)
+{
+ static const char *bufferNames[] = { "GL_FRONT", "GL_BACK" };
+ GLint mask;
+ glGetIntegerv(GL_INDEX_WRITEMASK, &mask);
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n'
+ << "\tcolor index is " << actual
+ << ", expected " << expected
+ << " in " << bufferNames[buffer] << " buffer\n";
+ env->log << "\tGL_INDEX_WRITEMASK = " << mask << "\n";
+}
+
+void
+MaskedClearTest::failZ(BasicResult& r, GLfloat expected, GLfloat actual)
+{
+ GLboolean mask;
+ glGetBooleanv(GL_DEPTH_WRITEMASK, &mask);
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n'
+ << "\tdepth buffer value is " << actual
+ << ", expected " << expected << "\n";
+ env->log << "\tGL_DEPTH_WRITEMASK = "
+ << (mask ? "GL_TRUE" : "GL_FALSE") << "\n";
+}
+
+void
+MaskedClearTest::failStencil(BasicResult& r, GLuint expected, GLuint actual)
+{
+ GLint mask;
+ glGetIntegerv(GL_STENCIL_WRITEMASK, &mask);
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n'
+ << "\tstencil buffer value is " << actual
+ << ", expected " << expected << "\n";
+ env->log << "\tGL_STENCIL_WRITEMASK = " << mask << "\n";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+MaskedClearTest::runOne(BasicResult& r, Window&) {
+
+ bool passed = true;
+
+ // GL init, just to be safe
+ glDisable(GL_SCISSOR_TEST);
+
+ // only test front/back-left buffers, quad-buffer stereo in the future
+ const GLint numBuffers = r.config->db ? 2 : 1;
+ for (GLint buffer = 0; buffer < numBuffers && passed; buffer++) {
+
+ if (buffer == 0) {
+ glReadBuffer(GL_FRONT);
+ glDrawBuffer(GL_FRONT);
+ } else {
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
+ }
+
+ if (r.config->canRGBA) {
+ const GLint numChannels = (r.config->a > 0) ? 4 : 3;
+ for (GLint chan = 0;
+ chan < numChannels && passed; chan++) {
+ // clear to black
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // select one channel to "clear" to 1.0
+ glColorMask(chan == 0, chan == 1,
+ chan == 2, chan == 3);
+
+ // try to clear surface to white
+ glClearColor(1.0, 1.0, 1.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // read 1x1 image at (x,y)=(4,4)
+ GLfloat pixel[4];
+ glReadPixels(4, 4, 1, 1,
+ GL_RGBA, GL_FLOAT, pixel);
+
+ // test results
+ for (GLint comp = 0;
+ comp < numChannels && passed; comp++) {
+ if (comp == chan) {
+ // component should be 1.0
+ if (pixel[comp] < 0.5) {
+ passed = false;
+ failRGB(r, comp, 1.0,
+ pixel[comp], buffer);
+ }
+ } else {
+ // component should be 0.0
+ if (pixel[comp] > 0.5) {
+ passed = false;
+ failRGB(r, comp, 0.0,
+ pixel[comp], buffer);
+ }
+ }
+ }
+ }
+ }
+ else {
+ const GLint indexBits = r.config->bufSize;
+ // We just run <indexBits> tests rather than 2^indexBits
+ for (GLint bit = 0; bit < indexBits && passed; bit++) {
+ // clear to 0
+ glIndexMask(~0);
+ glClearIndex(0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // select one bit to "clear" to 1
+ glIndexMask(1 << bit);
+
+ // try to clear surface to ~0
+ glClearIndex(~0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // read 1x1 image at (x,y)=(4,4)
+ GLuint pixel;
+ glReadPixels(4, 4, 1, 1,
+ GL_COLOR_INDEX, GL_UNSIGNED_INT, &pixel);
+
+ // test results
+ if (pixel != (1U << bit)) {
+ passed = false;
+ failCI(r, 1 << bit, pixel, buffer);
+ }
+ }
+ }
+ }
+
+ if (passed && r.config->z > 0) {
+ // clear depth buffer to zero
+ glDepthMask(GL_TRUE);
+ glClearDepth(0.0);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // disable Z writes, try to clear to one
+ glDepthMask(GL_FALSE);
+ glClearDepth(1.0);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // read 1x1 image at (x,y)=(4,4);
+ GLfloat depth;
+ glReadPixels(4, 4, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
+
+ // test result
+ if (depth != 0.0) {
+ passed = false;
+ failZ(r, 0.0, depth);
+ }
+ }
+
+ if (passed && r.config->s > 0) {
+ const GLint stencilBits = r.config->s;
+ // We just run <stencilBits> tests rather than 2^stencilBits
+ for (GLint bit = 0; bit < stencilBits && passed; bit++) {
+ // clear to 0
+ glStencilMask(~0);
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ // select one bit to "clear" to 1
+ glStencilMask(1 << bit);
+
+ // try to clear stencil buffer to ~0
+ glClearStencil(~0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ // read 1x1 image at (x,y)=(4,4)
+ GLuint stencil;
+ glReadPixels(4, 4, 1, 1,
+ GL_STENCIL_INDEX, GL_UNSIGNED_INT, &stencil);
+
+ // test results
+ if (stencil != (1U << bit)) {
+ passed = false;
+ failStencil(r, 1 << bit, stencil);
+ }
+ }
+ }
+ r.pass = passed;
+} // MaskedClearTest::runOne
+
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+MaskedClearTest::logOne(BasicResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+} // MaskedClearTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+MaskedClearTest maskedClearTest("maskedClear", "window",
+ "This test checks that glClear works correctly with glColorMask,\n"
+ "glIndexMask, glDepthMask and glStencilMask.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tmaskedclear.h b/tests/glean/tmaskedclear.h
new file mode 100644
index 00000000..d03fd155
--- /dev/null
+++ b/tests/glean/tmaskedclear.h
@@ -0,0 +1,62 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tmaskedclear.h: Test clearing of colorbuffers with glColorMask or
+// glIndexMask.
+// Author: Brian Paul (brianp@valinux.com) September 2000
+
+
+#ifndef __tmaskedclear_h__
+#define __tmaskedclear_h__
+
+#include "tbasic.h"
+
+namespace GLEAN {
+
+class MaskedClearTest: public BasicTest {
+ public:
+ MaskedClearTest(const char* testName, const char* filter,
+ const char* description):
+ BasicTest(testName, filter, description) {
+ }
+
+ virtual void runOne(BasicResult& r, Window& w);
+ virtual void logOne(BasicResult& r);
+
+ private:
+ void failRGB(BasicResult& r, GLint chan, GLfloat expected,
+ GLfloat actual, GLint buffer);
+ void failCI(BasicResult& r, GLuint expected, GLuint actual,
+ GLint buffer);
+ void failZ(BasicResult& r, GLfloat expected, GLfloat actual);
+ void failStencil(BasicResult& r, GLuint expected, GLuint actual);
+}; // class MaskedClearTest
+
+} // namespace GLEAN
+
+#endif // __tmaskedclear_h__
diff --git a/tests/glean/tmultitest.cpp b/tests/glean/tmultitest.cpp
new file mode 100644
index 00000000..42cac038
--- /dev/null
+++ b/tests/glean/tmultitest.cpp
@@ -0,0 +1,109 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+
+MultiTestResult::MultiTestResult()
+{
+ numPassed = numFailed = 0;
+ pass = true;
+}
+
+
+void
+MultiTestResult::putresults(ostream &s) const
+{
+ s << pass;
+ s << numPassed;
+ s << numFailed;
+}
+
+
+bool
+MultiTestResult::getresults(istream &s)
+{
+ s >> pass;
+ s >> numPassed;
+ s >> numFailed;
+ return s.good();
+}
+
+
+// VERY IMPORTANT: this function _must_ be defined here, even though
+// it's never used. Otherwise, you'll get linker errors like this:
+// tmultitest.h:83: undefined reference to `vtable for GLEAN::MultiTest'
+void
+MultiTest::runOne(MultiTestResult &r, Window &)
+{
+ r.numPassed = r.numFailed = 0;
+ r.pass = true;
+}
+
+
+void
+MultiTest::logOne(MultiTestResult &r)
+{
+ logPassFail(r);
+ logConcise(r);
+ env->log << "\t"
+ << r.numPassed << " tests passed, "
+ << r.numFailed << " tests failed.\n";
+}
+
+
+void
+MultiTest::compareOne(MultiTestResult &oldR,
+ MultiTestResult &newR)
+{
+ if (oldR.numPassed != newR.numPassed ||
+ oldR.numFailed != newR.numFailed) {
+ env->log << "Different results: passed: "
+ << oldR.numPassed
+ << " vs. "
+ << newR.numPassed
+ << " failed: "
+ << oldR.numFailed
+ << " vs. "
+ << newR.numFailed
+ << "\n";
+ }
+}
+
+
+#if 0
+MultiTest multiTest("multi", "window",
+ "",
+ "Base class for multi pass/fail tests\n"
+ );
+#endif
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tmultitest.h b/tests/glean/tmultitest.h
new file mode 100644
index 00000000..4ecad043
--- /dev/null
+++ b/tests/glean/tmultitest.h
@@ -0,0 +1,77 @@
+// begin_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tmultitest.h - base class for Glean tests that produce a number of
+// sub-pass/fail results.
+// Brian Paul September 2006
+
+
+#ifndef __tmultitest_h__
+#define __tmultitest_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#ifndef windowSize
+#define windowSize 100
+#endif
+
+#ifndef windowWidth
+#define windowWidth windowSize
+#endif
+
+#ifndef windowHeight
+#define windowHeight windowSize
+#endif
+
+
+class MultiTestResult: public BaseResult
+{
+public:
+ MultiTestResult();
+
+ bool pass;
+ int numPassed, numFailed;
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+
+class MultiTest: public BaseTest<MultiTestResult>
+{
+public:
+ GLEAN_CLASS_WH(MultiTest, MultiTestResult,
+ windowWidth, windowHeight);
+};
+
+
+} // namespace GLEAN
+
+#endif // __tmultitest_h__
diff --git a/tests/glean/torthpos.cpp b/tests/glean/torthpos.cpp
new file mode 100644
index 00000000..a50cfeab
--- /dev/null
+++ b/tests/glean/torthpos.cpp
@@ -0,0 +1,1159 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// torthopos.cpp: Test positioning of primitives in orthographic projection.
+// Some applications use OpenGL extensively for 2D rendering: portable
+// GUI toolkits, heads-up display generators, etc. These apps require
+// primitives to be drawn with reliable position and size in orthographic
+// projections. There are some potential pitfalls; for a good discussion,
+// see the OpenGL Programming Guide (the Red Book). In the second edition,
+// see the OpenGL Correctness Tips on page 601.
+
+#include "torthpos.h"
+#include "image.h"
+#include "rand.h"
+#include "geomutil.h"
+
+#if 0
+#ifdef __UNIX__
+#include <unistd.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include "dsconfig.h"
+#include "dsfilt.h"
+#include "dsurf.h"
+#include "winsys.h"
+#include "environ.h"
+#include "rc.h"
+#include "glutils.h"
+#include "torthpos.h"
+#include "misc.h"
+#endif
+
+
+namespace {
+
+void
+logStats1(const char* title, GLEAN::OPResult& r,
+ GLEAN::Environment* env) {
+ env->log << '\t' << title << ": ";
+ if (r.hasGaps || r.hasOverlaps || r.hasBadEdges) {
+ env->log << (r.hasGaps? " Gaps.": "")
+ << (r.hasOverlaps? " Overlaps.": "")
+ << (r.hasBadEdges? " Incorrect edges.": "")
+ << '\n';
+ } else {
+ env->log << " No gaps, overlaps, or incorrect edges.\n";
+ }
+} // logStats1
+
+void
+diffHeader(bool& same, const string& name,
+ GLEAN::DrawingSurfaceConfig* config, GLEAN::Environment* env) {
+ if (same) {
+ same = false;
+ env->log << name << ": DIFF "
+ << config->conciseDescription() << '\n';
+ }
+} // diffHeader
+
+void
+failHeader(bool& pass, const string& name,
+ GLEAN::DrawingSurfaceConfig* config, GLEAN::Environment* env) {
+ if (pass) {
+ pass = false;
+ env->log << name << ": FAIL "
+ << config->conciseDescription() << '\n';
+ }
+} // failHeader
+
+void
+doComparison(const GLEAN::OPResult& oldR,
+ const GLEAN::OPResult& newR,
+ GLEAN::DrawingSurfaceConfig* config,
+ bool& same,
+ const string& name,
+ GLEAN::Environment* env,
+ const char* title) {
+ if (newR.hasGaps != oldR.hasGaps) {
+ diffHeader(same, name, config, env);
+ env->log << '\t' << env->options.db1Name
+ << ' ' << title << ' '
+ << (oldR.hasGaps? " has": " does not have")
+ << " gaps\n";
+ env->log << '\t' << env->options.db2Name
+ << ' ' << title << ' '
+ << (newR.hasGaps? " has": " does not have")
+ << " gaps\n";
+ }
+ if (newR.hasOverlaps != oldR.hasOverlaps) {
+ diffHeader(same, name, config, env);
+ env->log << '\t' << env->options.db1Name
+ << ' ' << title << ' '
+ << (oldR.hasOverlaps? " has": " does not have")
+ << " overlaps\n";
+ env->log << '\t' << env->options.db2Name
+ << ' ' << title << ' '
+ << (newR.hasOverlaps? " has": " does not have")
+ << " overlaps\n";
+ }
+ if (newR.hasBadEdges != oldR.hasBadEdges) {
+ diffHeader(same, name, config, env);
+ env->log << '\t' << env->options.db1Name
+ << ' ' << title << ' '
+ << (oldR.hasBadEdges? " has": " does not have")
+ << " incorrect edges\n";
+ env->log << '\t' << env->options.db2Name
+ << ' ' << title << ' '
+ << (newR.hasBadEdges? " has": " does not have")
+ << " incorrect edges\n";
+ }
+} // doComparison
+
+GLubyte
+logicalSum(GLubyte* start, int stride, int count) {
+ GLubyte* p = start;
+ GLubyte sum = 0;
+ for (int i = 0; i < count; ++i) {
+ sum |= p[0];
+ sum |= p[1];
+ sum |= p[2];
+ p += stride;
+ }
+ return sum;
+}
+
+void
+verifyOrthPos(GLEAN::Window& w, bool& passed, string& name,
+ GLEAN::DrawingSurfaceConfig* config, GLEAN::OPResult& res,
+ GLEAN::Environment* env, const char* title) {
+
+ GLEAN::Image img(windowSize, windowSize, GL_RGB, GL_UNSIGNED_BYTE);
+ img.read(0, 0);
+ w.swap(); // give the user something to watch
+
+ // All of the tests in this group are constructed so that the
+ // "correct" image covers a square of exactly drawingSize by
+ // drawingSize pixels, embedded in a window that's two pixels
+ // larger in both dimensions. The border consists of pixels
+ // with all components set to zero. Within the image, all
+ // pixels should be either red (only the red component is
+ // nonzero) or green (only the green component is nonzero). If
+ // any pixels with all zero components are found, that indicates
+ // the presence of gaps. If any pixels with both red and green
+ // nonzero components are found, that indicates the presence of
+ // overlaps.
+
+ res.hasGaps = false;
+ res.hasOverlaps = false;
+ res.hasBadEdges = false;
+
+ GLubyte* row0 = reinterpret_cast<GLubyte*>(img.pixels());
+ GLubyte* row1 = row0 + img.rowSizeInBytes();
+ GLubyte* rowLast = row0 + (windowSize - 1) * img.rowSizeInBytes();
+ GLubyte* rowNextLast = rowLast - img.rowSizeInBytes();
+
+ // Check the bottom horizontal edge; it must be all zero.
+ if (logicalSum(row0, 3, windowSize)) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": bottom border (at Y==0) was touched\n";
+ res.hasBadEdges = true;
+ }
+ // Repeat the process for the top horizontal edge.
+ if (logicalSum(rowLast, 3, windowSize)) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": top border (at Y==" << windowSize - 1
+ << ") was touched\n";
+ res.hasBadEdges = true;
+ }
+ // Check the second row; there must be at least one nonzero
+ // pixel in the "drawn" region (excluding the first and last
+ // column).
+ if (!logicalSum(row1 + 3/*skip first pixel's RGB*/, 3, drawingSize)) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": first row (at Y==1) was not drawn\n";
+ res.hasBadEdges = true;
+ }
+ // Repeat the process for the last row.
+ if (!logicalSum(rowNextLast + 3, 3, drawingSize)) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": last row (at Y==" << windowSize - 2
+ << ") was not drawn\n";
+ res.hasBadEdges = true;
+ }
+
+ // Check the left-hand vertical edge; it must be all zero.
+ if (logicalSum(row0, img.rowSizeInBytes(), windowSize)) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": left border (at X==0) was touched\n";
+ res.hasBadEdges = true;
+ }
+ // Repeat for the right-hand vertical edge.
+ if (logicalSum(row0 + 3 * (windowSize - 1), img.rowSizeInBytes(),
+ windowSize)) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": right border (at X==" << windowSize - 1
+ << ") was touched\n";
+ res.hasBadEdges = true;
+ }
+ // Check the left-hand column; something must be nonzero.
+ if (!logicalSum(row1 + 3, img.rowSizeInBytes(), drawingSize)) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": first column (at X==1) was not drawn\n";
+ res.hasBadEdges = true;
+ }
+ // And repeat for the right-hand column:
+ if (!logicalSum(row1 + 3 * (drawingSize - 1), img.rowSizeInBytes(),
+ drawingSize)) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": last column (at X==" << windowSize - 2
+ << ") was not drawn\n";
+ res.hasBadEdges = true;
+ }
+
+ // Scan the drawing area. Anytime we find a pixel with all zero
+ // components, that's a gap. Anytime we find a pixel with both
+ // red and green components nonzero, that's an overlap.
+ GLubyte* row = row1 + 3; // lower-left pixel in drawing area
+ for (int i = 0; i < drawingSize; ++i) {
+ GLubyte* p = row;
+ for (int j = 0; j < drawingSize; ++j) {
+ if (!p[0] && !p[1] && !p[2]) {
+ if (!res.hasGaps) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": found first gap at X=="
+ << j + 1 << ", Y==" << i + 1
+ << '\n';
+ res.hasGaps = true;
+ }
+ }
+ if (p[0] && p[1]) {
+ if (!res.hasOverlaps) {
+ failHeader(passed, name, config, env);
+ env->log << '\t' << title
+ << ": found first overlap at "
+ << "X==" << j + 1 << ", Y=="
+ << i + 1 << '\n';
+ res.hasOverlaps = true;
+ }
+ }
+ p += 3;
+ }
+ row += img.rowSizeInBytes();
+ }
+
+} // verifyOrthPos
+
+void
+subdivideRects(int minX, int maxX, int minY, int maxY,
+ GLEAN::RandomDouble& rand, bool splitHoriz, bool drawInRed) {
+ // Basically we're just splitting the input rectangle
+ // recursively. At each step we alternate between splitting
+ // horizontally (dividing along Y) or vertically (along X). We
+ // also toggle colors (between red and green) at various times,
+ // in order to give us some adjacent edges of different colors
+ // that we can check for overlaps. Recursion bottoms out when
+ // the axis of interest drops below 30 pixels in length.
+ //
+ int min = splitHoriz? minY: minX;
+ int max = splitHoriz? maxY: maxX;
+ if (min + 30 > max) {
+ glColor4f(drawInRed? 1.0: 0.0, drawInRed? 0.0: 1.0,
+ 0.0, 0.5);
+ glBegin(GL_QUADS);
+ glVertex2i(minX, minY);
+ glVertex2i(maxX, minY);
+ glVertex2i(maxX, maxY);
+ glVertex2i(minX, maxY);
+ glEnd();
+ return;
+ }
+
+ int split = min + static_cast<int>((max - min) * rand.next());
+ if (splitHoriz) {
+ subdivideRects(minX, maxX, minY, split,
+ rand, !splitHoriz, drawInRed);
+ subdivideRects(minX, maxX, split, maxY,
+ rand, !splitHoriz, !drawInRed);
+ } else {
+ subdivideRects(minX, split, minY, maxY,
+ rand, !splitHoriz, drawInRed);
+ subdivideRects(split, maxX, minY, maxY,
+ rand, !splitHoriz, !drawInRed);
+ }
+}
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosPoints::runOne(OPResult& r, Window& w) {
+ bool passed = true;
+
+ GLUtils::useScreenCoords(windowSize, windowSize);
+
+ glFrontFace(GL_CCW);
+
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_FOG);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glClearColor(0, 0, 0, 0);
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode points
+ ////////////////////////////////////////////////////////////
+
+ // Clear both front and back buffers and swap, to avoid confusing
+ // this test with results of the previous test:
+ glClear(GL_COLOR_BUFFER_BIT);
+ w.swap();
+ glClear(GL_COLOR_BUFFER_BIT);
+ {
+ glBegin(GL_POINTS);
+ for (int x = 1; x <= drawingSize; ++x)
+ for (int y = 1; y <= drawingSize; ++y) {
+ if ((x ^ y) & 1)
+ glColor4f(0.0, 1.0, 0.0, 0.5);
+ else
+ glColor4f(1.0, 0.0, 0.0, 0.5);
+ glVertex2i(x, y);
+ }
+ glEnd();
+ }
+ verifyOrthPos(w, passed, name, r.config, r, env, "Immediate-mode points");
+ r.pass = passed;
+} // OrthoPosPoints::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosPoints::logOne(OPResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ } else {
+ env->log << '\n';
+ }
+ logStats(r);
+} // OrthoPosPoints::logOne
+
+void
+OrthoPosPoints::logStats(OPResult& r) {
+ logStats1("Immediate-mode points", r, env);
+} // OrthoPosPoints::logStats
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosPoints::compareOne(OPResult& oldR, OPResult& newR) {
+ bool same = true;
+
+ doComparison(oldR, newR, newR.config, same, name,
+ env, "immediate-mode points");
+
+ if (same && env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n";
+ }
+
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR);
+ env->log << env->options.db2Name << ':';
+ logStats(newR);
+ }
+} // OrthoPosPoints::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+OrthoPosPoints orthoPosPointsTest("orthoPosPoints",
+ "window, rgb > 1, z, fast",
+
+ "This test checks the positioning of unit-sized points under\n"
+ "orthographic projection. (This is important for apps that\n"
+ "want to use OpenGL for precise 2D drawing.) It fills in an\n"
+ "entire rectangle one pixel at a time, drawing adjacent pixels\n"
+ "with different colors and with blending enabled. If there are\n"
+ "gaps (pixels that are the background color, and thus haven't\n"
+ "been filled), overlaps (pixels that show a blend of more than\n"
+ "one color), or improper edges (pixels around the edge of the\n"
+ "rectangle that haven't been filled, or pixels just outside the\n"
+ "edge that have), then the test fails.\n"
+ "\n"
+ "This test generally fails for one of several reasons. First,\n"
+ "the coordinate transformation process may have an incorrect bias;\n"
+ "this usually will cause a bad edge. Second, the coordinate\n"
+ "transformation process may round pixel coordinates incorrectly;\n"
+ "this will usually cause gaps and/or overlaps. Third, the point\n"
+ "rasterization process may not be filling the correct pixels;\n"
+ "this can cause gaps, overlaps, or bad edges.\n"
+
+ );
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+void
+OrthoPosVLines::runOne(OPResult& r, Window& w) {
+ bool passed = true;
+
+ GLUtils::useScreenCoords(windowSize, windowSize);
+
+ glFrontFace(GL_CCW);
+
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_FOG);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glClearColor(0, 0, 0, 0);
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode vertical lines
+ // Note that these are a little tricky, because of
+ // OpenGL's "diamond-exit rule" line semantics. In
+ // this case, we can safely treat them as half-open
+ // lines, where the terminal point isn't drawn. Thus
+ // we need to specify a terminal coordinate one pixel
+ // beyond the last pixel we wish to be drawn.
+ ////////////////////////////////////////////////////////////
+
+ // Clear both front and back buffers and swap, to avoid confusing
+ // this test with results of the previous test:
+ glClear(GL_COLOR_BUFFER_BIT);
+ w.swap();
+ glClear(GL_COLOR_BUFFER_BIT);
+ {
+ glBegin(GL_LINES);
+ for (int x = 1; x <= drawingSize; ++x) {
+ if (x & 1)
+ glColor4f(0.0, 1.0, 0.0, 0.5);
+ else
+ glColor4f(1.0, 0.0, 0.0, 0.5);
+ glVertex2i(x, 1);
+ glVertex2i(x, drawingSize + 1);
+ }
+ glEnd();
+ }
+ verifyOrthPos(w, passed, name, r.config, r, env,
+ "Immediate-mode vertical lines");
+ r.pass = passed;
+} // OrthoPosVLines::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosVLines::logOne(OPResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ } else {
+ env->log << '\n';
+ }
+ logStats(r);
+} // OrthoPosVLines::logOne
+
+void
+OrthoPosVLines::logStats(OPResult& r) {
+ logStats1("Immediate-mode vertical lines", r, env);
+} // OrthoPosVLines::logStats
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosVLines::compareOne(OPResult& oldR, OPResult& newR) {
+ bool same = true;
+
+ doComparison(oldR, newR, newR.config, same, name,
+ env, "immediate-mode vertical lines");
+
+ if (same && env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n";
+ }
+
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR);
+ env->log << env->options.db2Name << ':';
+ logStats(newR);
+ }
+} // OrthoPosVLines::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+OrthoPosVLines orthoPosVLinesTest("orthoPosVLines",
+ "window, rgb > 1, z, fast",
+
+ "This test checks the positioning of unit-width vertical lines\n"
+ "under orthographic projection. (This is important for apps\n"
+ "that want to use OpenGL for precise 2D drawing.) It fills in\n"
+ "an entire rectangle with a collection of vertical lines, drawing\n"
+ "adjacent lines with different colors and with blending enabled.\n"
+ "If there are gaps (pixels that are the background color, and\n"
+ "thus haven't been filled), overlaps (pixels that show a blend\n"
+ "of more than one color), or improper edges (pixels around the\n"
+ "edge of the rectangle that haven't been filled, or pixels just\n"
+ "outside the edge that have), then the test fails.\n"
+ "\n"
+ "This test generally fails for one of several reasons. First,\n"
+ "the coordinate transformation process may have an incorrect bias;\n"
+ "this usually will cause a bad edge. Second, the coordinate\n"
+ "transformation process may round pixel coordinates incorrectly;\n"
+ "this will usually cause gaps and/or overlaps. Third, the\n"
+ "line rasterization process may not be filling the correct\n"
+ "pixels; this can cause gaps, overlaps, or bad edges. Fourth,\n"
+ "the OpenGL implementation may not handle the diamond-exit rule\n"
+ "(section 3.4.1 in version 1.2.1 of the OpenGL spec) correctly;\n"
+ "this should cause a bad border or bad top edge.\n"
+ "\n"
+ "It can be argued that this test is more strict that the OpenGL\n"
+ "specification requires. However, it is necessary to be this\n"
+ "strict in order for the results to be useful to app developers\n"
+ "using OpenGL for 2D drawing.\n"
+
+ );
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+void
+OrthoPosHLines::runOne(OPResult& r, Window& w) {
+ bool passed = true;
+
+ GLUtils::useScreenCoords(windowSize, windowSize);
+
+ glFrontFace(GL_CCW);
+
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_FOG);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glClearColor(0, 0, 0, 0);
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode horizontal lines
+ // See the comments in the vertical line case above.
+ ////////////////////////////////////////////////////////////
+
+ // Clear both front and back buffers and swap, to avoid confusing
+ // this test with results of the previous test:
+ glClear(GL_COLOR_BUFFER_BIT);
+ w.swap();
+ glClear(GL_COLOR_BUFFER_BIT);
+ {
+ glBegin(GL_LINES);
+ for (int y = 1; y <= drawingSize; ++y) {
+ if (y & 1)
+ glColor4f(0.0, 1.0, 0.0, 0.5);
+ else
+ glColor4f(1.0, 0.0, 0.0, 0.5);
+ glVertex2i(1, y);
+ glVertex2i(drawingSize + 1, y);
+ }
+ glEnd();
+ }
+ verifyOrthPos(w, passed, name, r.config, r, env,
+ "Immediate-mode horizontal lines");
+ r.pass = passed;
+} // OrthoPosHLines::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosHLines::logOne(OPResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ } else {
+ env->log << '\n';
+ }
+ logStats(r);
+} // OrthoPosHLines::logOne
+
+void
+OrthoPosHLines::logStats(OPResult& r) {
+ logStats1("Immediate-mode horizontal lines", r, env);
+} // OrthoPosHLines::logStats
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosHLines::compareOne(OPResult& oldR, OPResult& newR) {
+ bool same = true;
+
+ doComparison(oldR, newR, newR.config, same, name,
+ env, "immediate-mode horizontal lines");
+
+ if (same && env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n";
+ }
+
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR);
+ env->log << env->options.db2Name << ':';
+ logStats(newR);
+ }
+} // OrthoPosHLines::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+OrthoPosHLines orthoPosHLinesTest("orthoPosHLines",
+ "window, rgb > 1, z, fast",
+
+ "This test checks the positioning of unit-width horizontal lines\n"
+ "under orthographic projection. (This is important for apps\n"
+ "that want to use OpenGL for precise 2D drawing.) It fills in\n"
+ "an entire rectangle with a stack of horizontal lines, drawing\n"
+ "adjacent lines with different colors and with blending enabled.\n"
+ "If there are gaps (pixels that are the background color, and\n"
+ "thus haven't been filled), overlaps (pixels that show a blend\n"
+ "of more than one color), or improper edges (pixels around the\n"
+ "edge of the rectangle that haven't been filled, or pixels just\n"
+ "outside the edge that have), then the test fails.\n"
+ "\n"
+ "This test generally fails for one of several reasons. First,\n"
+ "the coordinate transformation process may have an incorrect bias;\n"
+ "this usually will cause a bad edge. Second, the coordinate\n"
+ "transformation process may round pixel coordinates incorrectly;\n"
+ "this will usually cause gaps and/or overlaps. Third, the\n"
+ "line rasterization process may not be filling the correct\n"
+ "pixels; this can cause gaps, overlaps, or bad edges. Fourth,\n"
+ "the OpenGL implementation may not handle the diamond-exit rule\n"
+ "(section 3.4.1 in version 1.2.1 of the OpenGL spec) correctly;\n"
+ "this should cause a bad border or bad right edge.\n"
+ "\n"
+ "It can be argued that this test is more strict that the OpenGL\n"
+ "specification requires. However, it is necessary to be this\n"
+ "strict in order for the results to be useful to app developers\n"
+ "using OpenGL for 2D drawing.\n"
+
+ );
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+void
+OrthoPosTinyQuads::runOne(OPResult& r, Window& w) {
+ bool passed = true;
+
+ GLUtils::useScreenCoords(windowSize, windowSize);
+
+ glFrontFace(GL_CCW);
+
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_FOG);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glClearColor(0, 0, 0, 0);
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode 1x1-pixel quads
+ ////////////////////////////////////////////////////////////
+
+ // Clear both front and back buffers and swap, to avoid confusing
+ // this test with results of the previous test:
+ glClear(GL_COLOR_BUFFER_BIT);
+ w.swap();
+ glClear(GL_COLOR_BUFFER_BIT);
+ {
+ glBegin(GL_QUADS);
+ for (int x = 1; x <= drawingSize; ++x)
+ for (int y = 1; y <= drawingSize; ++y) {
+ if ((x ^ y) & 1)
+ glColor4f(0.0, 1.0, 0.0, 0.5);
+ else
+ glColor4f(1.0, 0.0, 0.0, 0.5);
+ glVertex2i(x, y);
+ glVertex2i(x + 1, y);
+ glVertex2i(x + 1, y + 1);
+ glVertex2i(x, y + 1);
+ }
+ glEnd();
+ }
+ verifyOrthPos(w, passed, name, r.config, r, env,
+ "Immediate-mode 1x1 quads");
+ r.pass = passed;
+} // OrthoPosTinyQuads::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosTinyQuads::logOne(OPResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ } else {
+ env->log << '\n';
+ }
+ logStats(r);
+} // OrthoPosTinyQuads::logOne
+
+void
+OrthoPosTinyQuads::logStats(OPResult& r) {
+ logStats1("Immediate-mode 1x1 quads", r, env);
+} // OrthoPosTinyQuads::logStats
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosTinyQuads::compareOne(OPResult& oldR, OPResult& newR) {
+ bool same = true;
+
+ doComparison(oldR, newR, newR.config, same, name,
+ env, "immediate-mode 1x1 quads");
+
+ if (same && env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n";
+ }
+
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR);
+ env->log << env->options.db2Name << ':';
+ logStats(newR);
+ }
+} // OrthoPosTinyQuads::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+OrthoPosTinyQuads orthoPosTinyQuadsTest("orthoPosTinyQuads",
+ "window, rgb > 1, z, fast",
+
+ "This test checks the positioning of 1x1-pixel quadrilaterals\n"
+ "under orthographic projection. (This is important for apps\n"
+ "that want to use OpenGL for precise 2D drawing.) It fills in\n"
+ "an entire rectangle with an array of quadrilaterals, drawing\n"
+ "adjacent quads with different colors and with blending enabled.\n"
+ "If there are gaps (pixels that are the background color, and\n"
+ "thus haven't been filled), overlaps (pixels that show a blend\n"
+ "of more than one color), or improper edges (pixels around the\n"
+ "edge of the rectangle that haven't been filled, or pixels just\n"
+ "outside the edge that have), then the test fails.\n"
+ "\n"
+ "This test generally fails for one of several reasons. First,\n"
+ "the coordinate transformation process may have an incorrect bias;\n"
+ "this usually will cause a bad edge. Second, the coordinate\n"
+ "transformation process may round pixel coordinates incorrectly;\n"
+ "this will usually cause gaps and/or overlaps. Third, the\n"
+ "quad rasterization process may not be filling the correct\n"
+ "pixels; this can cause gaps, overlaps, or bad edges.\n"
+
+ );
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+void
+OrthoPosRandRects::runOne(OPResult& r, Window& w) {
+ bool passed = true;
+
+ GLUtils::useScreenCoords(windowSize, windowSize);
+
+ glFrontFace(GL_CCW);
+
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_FOG);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glClearColor(0, 0, 0, 0);
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode random axis-aligned rectangles
+ ////////////////////////////////////////////////////////////
+
+ // Clear both front and back buffers and swap, to avoid confusing
+ // this test with results of the previous test:
+ glClear(GL_COLOR_BUFFER_BIT);
+ w.swap();
+ glClear(GL_COLOR_BUFFER_BIT);
+ RandomDouble rand(1618);
+ subdivideRects(1, drawingSize + 1, 1, drawingSize + 1,
+ rand, true, true);
+ verifyOrthPos(w, passed, name, r.config, r, env,
+ "Immediate-mode axis-aligned rectangles");
+ r.pass = passed;
+} // OrthoPosRandRects::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosRandRects::logOne(OPResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ } else {
+ env->log << '\n';
+ }
+ logStats(r);
+} // OrthoPosRandRects::logOne
+
+void
+OrthoPosRandRects::logStats(OPResult& r) {
+ logStats1("Immediate-mode axis-aligned rectangles", r, env);
+} // OrthoPosRandRects::logStats
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosRandRects::compareOne(OPResult& oldR, OPResult& newR) {
+ bool same = true;
+
+ doComparison(oldR, newR, newR.config, same, name,
+ env, "immediate-mode axis-aligned rectangles");
+
+ if (same && env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n";
+ }
+
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR);
+ env->log << env->options.db2Name << ':';
+ logStats(newR);
+ }
+} // OrthoPosRandRects::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+OrthoPosRandRects orthoPosRandRectsTest("orthoPosRandRects",
+ "window, rgb > 1, z, fast",
+
+ "This test checks the positioning of axis-aligned rectangles\n"
+ "under orthographic projection. (This is important for apps\n"
+ "that want to use OpenGL for precise 2D drawing.) It fills in\n"
+ "an entire rectangle with an array of smaller rects, drawing\n"
+ "adjacent rects with different colors and with blending enabled.\n"
+ "If there are gaps (pixels that are the background color, and\n"
+ "thus haven't been filled), overlaps (pixels that show a blend\n"
+ "of more than one color), or improper edges (pixels around the\n"
+ "edge of the rectangle that haven't been filled, or pixels just\n"
+ "outside the edge that have), then the test fails.\n"
+ "\n"
+ "This test generally fails for one of several reasons. First,\n"
+ "the coordinate transformation process may have an incorrect bias;\n"
+ "this usually will cause a bad edge. Second, the coordinate\n"
+ "transformation process may round pixel coordinates incorrectly;\n"
+ "this will usually cause gaps and/or overlaps. Third, the\n"
+ "rectangle rasterization process may not be filling the correct\n"
+ "pixels; this can cause gaps, overlaps, or bad edges.\n"
+
+ );
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+void
+OrthoPosRandTris::runOne(OPResult& r, Window& w) {
+ bool passed = true;
+
+ GLUtils::useScreenCoords(windowSize, windowSize);
+
+ glFrontFace(GL_CCW);
+
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_FOG);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glClearColor(0, 0, 0, 0);
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode random axis-aligned rectangles
+ ////////////////////////////////////////////////////////////
+
+ // Clear both front and back buffers and swap, to avoid confusing
+ // this test with results of the previous test:
+ glClear(GL_COLOR_BUFFER_BIT);
+ w.swap();
+ glClear(GL_COLOR_BUFFER_BIT);
+ const int nPoints = 10;
+ RandomDouble vRand(141421356);
+ RandomMesh2D v(1, drawingSize + 1, nPoints,
+ 1, drawingSize + 1, nPoints,
+ vRand);
+ for (int i = nPoints - 1; i > 0; --i) {
+ glBegin(GL_TRIANGLE_STRIP);
+ for (int j = 0; j < nPoints; ++j) {
+ glColor4f(1.0, 0.0, 0.0, 0.5);
+ glVertex2fv(v(i, j));
+ glColor4f(0.0, 1.0, 0.0, 0.5);
+ glVertex2fv(v(i - 1, j));
+ }
+ glEnd();
+ }
+ verifyOrthPos(w, passed, name, r.config, r, env,
+ "Immediate-mode triangles");
+ r.pass = passed;
+} // OrthoPosRandTris::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosRandTris::logOne(OPResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ } else {
+ env->log << '\n';
+ }
+ logStats(r);
+} // OrthoPosRandTris::logOne
+
+void
+OrthoPosRandTris::logStats(OPResult& r) {
+ logStats1("Immediate-mode triangles", r, env);
+} // OrthoPosRandTris::logStats
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+OrthoPosRandTris::compareOne(OPResult& oldR, OPResult& newR) {
+ bool same = true;
+
+ doComparison(oldR, newR, newR.config, same, name,
+ env, "immediate-mode triangles");
+
+ if (same && env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n";
+ }
+
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR);
+ env->log << env->options.db2Name << ':';
+ logStats(newR);
+ }
+} // OrthoPosRandTris::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+OrthoPosRandTris orthoPosRandTrisTest("orthoPosRandTris",
+ "window, rgb > 1, z, fast",
+
+ "This test checks the positioning of random triangles under\n"
+ "orthographic projection. (This is important for apps that\n"
+ "want to use OpenGL for precise 2D drawing.) It fills in an\n"
+ "entire rectangle with an array of randomly-generated triangles,\n"
+ "drawing adjacent triangles with different colors and with blending\n"
+ "enabled. If there are gaps (pixels that are the background color,\n"
+ "and thus haven't been filled), overlaps (pixels that show a blend\n"
+ "of more than one color), or improper edges (pixels around the\n"
+ "edge of the rectangle that haven't been filled, or pixels just\n"
+ "outside the edge that have), then the test fails.\n"
+ "\n"
+ "This test generally fails for one of several reasons. First,\n"
+ "the coordinate transformation process may have an incorrect bias;\n"
+ "this usually will cause a bad edge. Second, the coordinate\n"
+ "transformation process may round pixel coordinates incorrectly;\n"
+ "this will usually cause gaps and/or overlaps. Third, the\n"
+ "triangle rasterization process may not be filling the correct\n"
+ "pixels; this can cause gaps, overlaps, or bad edges.\n"
+
+ );
+
+
+} // namespace GLEAN
diff --git a/tests/glean/torthpos.h b/tests/glean/torthpos.h
new file mode 100644
index 00000000..f12f3137
--- /dev/null
+++ b/tests/glean/torthpos.h
@@ -0,0 +1,103 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// torthpos.h: Test positioning of primitives in orthographic projection.
+// Apps that require precise 2D rasterization depend on these semantics.
+
+#ifndef __torthpos_h__
+#define __torthpos_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define drawingSize 256
+#define windowSize (drawingSize + 2)
+
+// Auxiliary struct for holding a test result:
+class OPResult: public BaseResult {
+public:
+ bool pass; // not saved in results file
+ bool hasGaps; // true if gaps between prims were detected
+ bool hasOverlaps; // true if overlaps were detected
+ bool hasBadEdges; // true if edge-conditions were incorrect
+
+ OPResult() {
+ hasGaps = hasOverlaps = hasBadEdges = false;
+ }
+ void putresults(ostream& s) const {
+ s << hasGaps
+ << ' ' << hasOverlaps
+ << ' ' << hasBadEdges
+ << '\n';
+ }
+ bool getresults(istream& s) {
+ s >> hasGaps >> hasOverlaps >> hasBadEdges;
+ return s.good();
+ }
+};
+
+class OrthoPosPoints: public BaseTest<OPResult> {
+public:
+ GLEAN_CLASS_WH(OrthoPosPoints, OPResult, windowSize, windowSize);
+ void logStats(OPResult& r);
+}; // class OrthoPosPoints
+
+class OrthoPosVLines: public BaseTest<OPResult> {
+public:
+ GLEAN_CLASS_WH(OrthoPosVLines, OPResult, windowSize, windowSize);
+ void logStats(OPResult& r);
+}; // class OrthoPosVLines
+
+class OrthoPosHLines: public BaseTest<OPResult> {
+public:
+ GLEAN_CLASS_WH(OrthoPosHLines, OPResult, windowSize, windowSize);
+ void logStats(OPResult& r);
+}; // class OrthoPosHLines
+
+class OrthoPosTinyQuads: public BaseTest<OPResult> {
+public:
+ GLEAN_CLASS_WH(OrthoPosTinyQuads, OPResult, windowSize, windowSize);
+ void logStats(OPResult& r);
+}; // class OrthoPosTinyQuads
+
+class OrthoPosRandRects: public BaseTest<OPResult> {
+public:
+ GLEAN_CLASS_WH(OrthoPosRandRects, OPResult, windowSize, windowSize);
+ void logStats(OPResult& r);
+}; // class OrthoPosRandRects
+
+class OrthoPosRandTris: public BaseTest<OPResult> {
+public:
+ GLEAN_CLASS_WH(OrthoPosRandTris, OPResult, windowSize, windowSize);
+ void logStats(OPResult& r);
+}; // class OrthoPosRandTris
+
+} // namespace GLEAN
+
+#endif // __torthpos_h__
diff --git a/tests/glean/tpaths.cpp b/tests/glean/tpaths.cpp
new file mode 100644
index 00000000..00926ea1
--- /dev/null
+++ b/tests/glean/tpaths.cpp
@@ -0,0 +1,373 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// tpaths.h: Basic test of GL rendering paths.
+// This test verifies that basic, trival OpenGL paths work as expected.
+// For example, glAlphaFunc(GL_GEQUAL, 0.0) should always pass and
+// glAlphaFunc(GL_LESS, 0.0) should always fail. We setup trivial
+// pass and fail conditions for each of alpha test, blending, color mask,
+// depth test, logic ops, scissor, stencil, stipple, and texture and
+// make sure they work as expected. We also setup trival-pass for all
+// these paths simultaneously and test that as well.
+//
+// To test for pass/fail we examine the color buffer for white or black,
+// respectively.
+//
+// Author: Brian Paul (brianp@valinux.com) November 2000
+
+#include "tpaths.h"
+
+namespace GLEAN {
+
+void
+PathsTest::SetPathState(Path path, State state) const {
+
+ switch (path) {
+ case ALPHA:
+ if (state == ALWAYS_PASS) {
+ glAlphaFunc(GL_GEQUAL, 0.0);
+ glEnable(GL_ALPHA_TEST);
+ }
+ else if (state == ALWAYS_FAIL) {
+ glAlphaFunc(GL_GREATER, 1.0);
+ glEnable(GL_ALPHA_TEST);
+ }
+ else {
+ glDisable(GL_ALPHA_TEST);
+ }
+ break;
+ case BLEND:
+ if (state == ALWAYS_PASS) {
+ glBlendFunc(GL_ONE, GL_ZERO);
+ glEnable(GL_BLEND);
+ }
+ else if (state == ALWAYS_FAIL) {
+ glBlendFunc(GL_ZERO, GL_ONE);
+ glEnable(GL_BLEND);
+ }
+ else {
+ glDisable(GL_BLEND);
+ }
+ break;
+ case COLOR_MASK:
+ if (state == ALWAYS_PASS) {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+ else if (state == ALWAYS_FAIL) {
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ }
+ else {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+ break;
+ case DEPTH:
+ if (state == ALWAYS_PASS) {
+ glDepthFunc(GL_ALWAYS);
+ glEnable(GL_DEPTH_TEST);
+ }
+ else if (state == ALWAYS_FAIL) {
+ glDepthFunc(GL_NEVER);
+ glEnable(GL_DEPTH_TEST);
+ }
+ else {
+ glDisable(GL_DEPTH_TEST);
+ }
+ break;
+ case LOGIC:
+ if (state == ALWAYS_PASS) {
+ glLogicOp(GL_OR);
+ glEnable(GL_COLOR_LOGIC_OP);
+ }
+ else if (state == ALWAYS_FAIL) {
+ glLogicOp(GL_AND);
+ glEnable(GL_COLOR_LOGIC_OP);
+ }
+ else {
+ glDisable(GL_COLOR_LOGIC_OP);
+ }
+ break;
+ case SCISSOR:
+ if (state == ALWAYS_PASS) {
+ glScissor(0, 0, 10, 10);
+ glEnable(GL_SCISSOR_TEST);
+ }
+ else if (state == ALWAYS_FAIL) {
+ glScissor(0, 0, 0, 0);
+ glEnable(GL_SCISSOR_TEST);
+ }
+ else {
+ glDisable(GL_SCISSOR_TEST);
+ }
+ break;
+ case STENCIL:
+ if (state == ALWAYS_PASS) {
+ // pass if reference <= stencil value (ref = 0)
+ glStencilFunc(GL_LEQUAL, 0, ~0);
+ glEnable(GL_STENCIL_TEST);
+ }
+ else if (state == ALWAYS_FAIL) {
+ // pass if reference > stencil value (ref = 0)
+ glStencilFunc(GL_GREATER, 0, ~0);
+ glEnable(GL_STENCIL_TEST);
+ }
+ else {
+ glDisable(GL_STENCIL_TEST);
+ }
+ break;
+ case STIPPLE:
+ if (state == ALWAYS_PASS) {
+ GLubyte stipple[4*32];
+ for (int i = 0; i < 4*32; i++)
+ stipple[i] = 0xff;
+ glPolygonStipple(stipple);
+ glEnable(GL_POLYGON_STIPPLE);
+ }
+ else if (state == ALWAYS_FAIL) {
+ GLubyte stipple[4*32];
+ for (int i = 0; i < 4*32; i++)
+ stipple[i] = 0x0;
+ glPolygonStipple(stipple);
+ glEnable(GL_POLYGON_STIPPLE);
+ }
+ else {
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ break;
+ case TEXTURE:
+ if (state == DISABLE) {
+ glDisable(GL_TEXTURE_2D);
+ }
+ else {
+ GLubyte val = (state == ALWAYS_PASS) ? 0xff : 0x00;
+ int i;
+ GLubyte texImage[4*4*4];
+ for (i = 0; i < 4*4*4; i++)
+ texImage[i] = val;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texImage);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
+ GL_MODULATE);
+ glEnable(GL_TEXTURE_2D);
+ }
+ break;
+ default:
+ abort(); // error
+ }
+}
+
+
+const char *
+PathsTest::PathName(Path path) const {
+
+ switch (path) {
+ case ALPHA:
+ return "Alpha Test";
+ case BLEND:
+ return "Blending";
+ case COLOR_MASK:
+ return "Color Mask";
+ case DEPTH:
+ return "Depth Test";
+ case LOGIC:
+ return "LogicOp";
+ case SCISSOR:
+ return "Scissor Test";
+ case STENCIL:
+ return "Stencil Test";
+ case STIPPLE:
+ return "Polygon Stipple";
+ case TEXTURE:
+ return "Modulated Texture";
+ case ZZZ:
+ return "paths";
+ default:
+ return "???";
+ }
+}
+
+
+void
+PathsTest::FailMessage(BasicResult &r, Path path, State state, GLfloat pixel[3])
+ const {
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n';
+ if (state == ALWAYS_PASS) {
+ env->log << "\t" << PathName(path)
+ << " should have had no effect (1, 1, 1)"
+ << " but actually modified the fragment: "
+ << "(" << pixel[0] << "," << pixel[1] << ","
+ << pixel[2] << ")\n";
+ }
+ else {
+ env->log << "\t" << PathName(path)
+ << " should have culled the fragment (0, 0, 0)"
+ << " but actually didn't: (" << pixel[0] << ","
+ << pixel[1] << "," << pixel[2] << ")\n";
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+PathsTest::runOne(BasicResult& r, Window&) {
+
+ Path p, paths[1000];
+ int i, numPaths = 0;
+
+ // draw 10x10 pixel quads
+ glViewport(0, 0, 10, 10);
+
+ glDisable(GL_DITHER);
+
+ // Build the list of paths to exercise. Skip depth test if we have no
+ // depth buffer. Skip stencil test if we have no stencil buffer.
+ for (p = ALPHA; p != ZZZ; p = (Path) (p + 1)) {
+ if (!((p == DEPTH && r.config->z == 0) ||
+ (p == STENCIL && r.config->s == 0))) {
+ paths[numPaths++] = p;
+ }
+ }
+
+ // test always-pass paths
+ for (i = 0; i < numPaths; i++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ SetPathState(paths[i], ALWAYS_PASS);
+
+ // draw polygon
+ glColor4f(1, 1, 1, 1);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ SetPathState(paths[i], DISABLE);
+
+ // test buffer
+ GLfloat pixel[3];
+ glReadPixels(4, 4, 1, 1, GL_RGB, GL_FLOAT, pixel);
+ if (pixel[0] != 1.0 || pixel[1] != 1.0 || pixel[2] != 1.0) {
+ FailMessage(r, paths[i], ALWAYS_PASS, pixel);
+ r.pass = false;
+ return;
+ }
+ }
+
+ // enable all always-pass paths
+ {
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ for (i = 0; i < numPaths; i++) {
+ SetPathState(paths[i], ALWAYS_PASS);
+ }
+
+ // draw polygon
+ glColor4f(1, 1, 1, 1);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ for (i = 0; i < numPaths; i++) {
+ SetPathState(paths[i], DISABLE);
+ }
+
+ // test buffer
+ GLfloat pixel[3];
+ glReadPixels(4, 4, 1, 1, GL_RGB, GL_FLOAT, pixel);
+ if (pixel[0] != 1.0 || pixel[1] != 1.0 || pixel[2] != 1.0) {
+ FailMessage(r, paths[i], ALWAYS_PASS, pixel);
+ r.pass = false;
+ return;
+ }
+ }
+
+ // test never-pass paths
+ for (i = 0; i < numPaths; i++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ SetPathState(paths[i], ALWAYS_FAIL);
+
+ // draw polygon
+ glColor4f(1, 1, 1, 1);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ SetPathState(paths[i], DISABLE);
+
+ // test buffer
+ GLfloat pixel[3];
+ glReadPixels(4, 4, 1, 1, GL_RGB, GL_FLOAT, pixel);
+ if (pixel[0] != 0.0 || pixel[1] != 0.0 || pixel[2] != 0.0) {
+ FailMessage(r, paths[i], ALWAYS_FAIL, pixel);
+ r.pass = false;
+ return;
+ }
+ }
+
+ // success
+ r.pass = true;
+} // PathsTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+PathsTest::logOne(BasicResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+} // PathsTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+PathsTest pathsTest("paths", "window, rgb",
+
+ "This test verifies that basic OpenGL operations such as the alpha\n"
+ "test, depth test, blending, stippling, and texturing work for\n"
+ "trivial cases.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tpaths.h b/tests/glean/tpaths.h
new file mode 100644
index 00000000..3b1704b9
--- /dev/null
+++ b/tests/glean/tpaths.h
@@ -0,0 +1,79 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// tpaths.h: Basic test of GL rendering paths.
+// Author: Brian Paul (brianp@valinux.com) November 2000
+
+
+#ifndef __tpaths_h__
+#define __tpaths_h__
+
+#include "tbasic.h"
+
+namespace GLEAN {
+
+class PathsTest: public BasicTest {
+ public:
+ PathsTest(const char* testName, const char* filter,
+ const char* description):
+ BasicTest(testName, filter, description) {
+ }
+
+ virtual void runOne(BasicResult& r, Window& w);
+ virtual void logOne(BasicResult& r);
+
+ private:
+ enum Path {
+ ALPHA,
+ BLEND,
+ COLOR_MASK,
+ DEPTH,
+ LOGIC,
+ SCISSOR,
+ STENCIL,
+ STIPPLE,
+ TEXTURE,
+ ZZZ // end-of-list token
+ };
+ enum State {
+ DISABLE,
+ ALWAYS_PASS,
+ ALWAYS_FAIL
+ };
+
+ const char *PathName(Path path) const;
+ void FailMessage(BasicResult &r, Path path, State state,
+ GLfloat pixel[3]) const;
+ void SetPathState(Path path, State state) const;
+
+}; // class PathsTest
+
+} // namespace GLEAN
+
+#endif // __tpaths_h__
diff --git a/tests/glean/tpgos.cpp b/tests/glean/tpgos.cpp
new file mode 100644
index 00000000..71e982c4
--- /dev/null
+++ b/tests/glean/tpgos.cpp
@@ -0,0 +1,735 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2001 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tpgos.cpp: implementation of polygon offset tests
+// Derived in part from tests written by Angus Dorbie <dorbie@sgi.com>
+// in September 2000 and Rickard E. (Rik) Faith <faith@valinux.com> in
+// October 2000.
+
+#include "tpgos.h"
+#include "image.h"
+#include "misc.h"
+#include <cmath>
+
+
+namespace {
+
+typedef struct {
+ GLfloat angle;
+ GLfloat axis[3];
+} AngleAxis;
+
+void
+red() {
+ glColor3f(1.0, 0.0, 0.0);
+}
+
+void
+black() {
+ glColor3f(0.0, 0.0, 0.0);
+}
+
+void
+drawQuadAtDistance(GLdouble dist) {
+ glBegin(GL_QUADS);
+ glVertex3d(-dist, -dist, -dist);
+ glVertex3d( dist, -dist, -dist);
+ glVertex3d( dist, dist, -dist);
+ glVertex3d(-dist, dist, -dist);
+ glEnd();
+}
+
+GLdouble
+windowCoordDepth(GLdouble dist) {
+ // Assumes we're using the "far at infinity" projection matrix
+ // and simple viewport transformation.
+ return 0.5 * (dist - 2.0) / dist + 0.5;
+}
+
+bool
+redQuadWasDrawn() {
+ GLEAN::Image
+ img(PGOS_WIN_SIZE, PGOS_WIN_SIZE, GL_RGB, GL_UNSIGNED_BYTE);
+ img.read(0, 0);
+
+ GLubyte* row = reinterpret_cast<GLubyte*>(img.pixels());
+ for (GLsizei r = 0; r < img.height(); ++r) {
+ GLubyte* pix = row;
+ for (GLsizei c = 0; c < img.width(); ++c) {
+ if (pix[0] == 0 // bad red component?
+ || pix[1] != 0 // bad green component?
+ || pix[2] != 0) // bad blue component?
+ return false; // ...then quad wasn't drawn
+ pix += 3;
+ }
+ row += img.rowSizeInBytes();
+ }
+
+ return true;
+}
+
+void
+findIdealMRD(GLEAN::POResult& r, GLEAN::Window& w) {
+
+ // MRD stands for Minimum Resolvable Difference, the smallest
+ // distance in depth that suffices to separate any two
+ // polygons (or a polygon and the near or far clipping
+ // planes).
+ //
+ // This function tries to determine the "ideal" MRD for the
+ // current rendering context. It's expressed in window
+ // coordinates, because the value in model or clipping
+ // coordinates depends on the scale factors in the modelview
+ // and projection matrices and on the distances to the near
+ // and far clipping planes.
+ //
+ // For simple unsigned-integer depth buffers that aren't too
+ // deep (so that precision isn't an issue during coordinate
+ // transformations), it should be about one least-significant
+ // bit. For deep or floating-point or compressed depth
+ // buffers the situation may be more complicated, so we don't
+ // pass or fail an implementation solely on the basis of its
+ // ideal MRD.
+ //
+ // There are two subtle parts of this function. The first is
+ // the projection matrix we use for rendering. This matrix
+ // places the far clip plane at infinity (so that we don't run
+ // into arbitrary limits during our search process). The
+ // second is the method used for drawing the polygon. We
+ // scale the x and y coords of the polygon vertices by the
+ // polygon's depth, so that it always occupies the full view
+ // frustum. This makes it easier to verify that the polygon
+ // was resolved completely -- we just read back the entire
+ // window and see if any background pixels appear.
+ //
+ // To insure that we get reasonable results on machines with
+ // unusual depth buffers (floating-point, or compressed), we
+ // determine the MRD twice, once close to the near clipping
+ // plane and once as far away from the eye as possible. On a
+ // simple integer depth buffer these two values should be
+ // essentially the same. For other depth-buffer formats, the
+ // ideal MRD is simply the largest of the two.
+
+ GLdouble nearDist, farDist;
+ int i;
+
+ // First, find a distance that is as far away as possible, yet
+ // a quad at that distance can be distinguished from the
+ // background. Start by pushing quads away from the eye until
+ // we find an interval where the closer quad can be resolved,
+ // but the farther quad cannot. Then binary-search to find
+ // the threshold.
+
+ glDepthFunc(GL_LESS);
+ glClearDepth(1.0);
+ red();
+ nearDist = 1.0;
+ farDist = 2.0;
+ for (;;) {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ drawQuadAtDistance(farDist);
+ w.swap();
+ if (!redQuadWasDrawn())
+ break;
+ nearDist = farDist;
+ farDist *= 2.0;
+ }
+ for (i = 0; i < 64; ++i) {
+ GLdouble halfDist = 0.5 * (nearDist + farDist);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ drawQuadAtDistance(halfDist);
+ w.swap();
+ if (redQuadWasDrawn())
+ nearDist = halfDist;
+ else
+ farDist = halfDist;
+ }
+ r.nextToFar = nearDist;
+
+ // We can derive a resolvable difference from the value
+ // nextToFar, but it's not necessarily the one we want.
+ // Consider mapping the object coordinate range [0,1] onto the
+ // integer window coordinate range [0,2]. A natural way to do
+ // this is with a linear function, windowCoord =
+ // 2*objectCoord. With rounding, this maps [0,0.25) to 0,
+ // [0.25,0.75) to 1, and [0.75,1] to 2. Note that the
+ // intervals at either end are 0.25 wide, but the one in the
+ // middle is 0.5 wide. The difference we can derive from
+ // nextToFar is related to the width of the final interval.
+ // We want to back up just a bit so that we can get a
+ // (possibly much larger) difference that will work for the
+ // larger interval. To do this we need to find a difference
+ // that allows us to distinguish two quads when the more
+ // distant one is at distance nextToFar.
+
+ nearDist = 1.0;
+ farDist = r.nextToFar;
+ for (i = 0; i < 64; ++i) {
+ GLdouble halfDist = 0.5 * (nearDist + farDist);
+
+ black();
+ glDepthFunc(GL_ALWAYS);
+ drawQuadAtDistance(r.nextToFar);
+
+ red();
+ glDepthFunc(GL_LESS);
+ drawQuadAtDistance(halfDist);
+
+ w.swap();
+ if (redQuadWasDrawn())
+ nearDist = halfDist;
+ else
+ farDist = halfDist;
+ }
+
+ r.idealMRDFar = windowCoordDepth(r.nextToFar)
+ - windowCoordDepth(nearDist);
+
+
+ // Now we apply a similar strategy at the near end of the
+ // depth range, but swapping the senses of various comparisons
+ // so that we approach the near clipping plane rather than the
+ // far.
+
+ glClearDepth(0.0);
+ glDepthFunc(GL_GREATER);
+ red();
+ nearDist = 1.0;
+ farDist = r.nextToFar;
+ for (i = 0; i < 64; ++i) {
+ GLdouble halfDist = 0.5 * (nearDist + farDist);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ drawQuadAtDistance(halfDist);
+ w.swap();
+ if (redQuadWasDrawn())
+ farDist = halfDist;
+ else
+ nearDist = halfDist;
+ }
+ r.nextToNear = farDist;
+
+ nearDist = r.nextToNear;
+ farDist = r.nextToFar;
+ for (i = 0; i < 64; ++i) {
+ GLdouble halfDist = 0.5 * (nearDist + farDist);
+
+ black();
+ glDepthFunc(GL_ALWAYS);
+ drawQuadAtDistance(r.nextToNear);
+
+ red();
+ glDepthFunc(GL_GREATER);
+ drawQuadAtDistance(halfDist);
+
+ w.swap();
+ if (redQuadWasDrawn())
+ farDist = halfDist;
+ else
+ nearDist = halfDist;
+ }
+
+ r.idealMRDNear = windowCoordDepth(farDist)
+ - windowCoordDepth(r.nextToNear);
+} // findIdealMRD
+
+double
+readDepth(int x, int y) {
+ GLuint depth;
+ glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &depth);
+
+ // This normalization of "depth" is correct even on 64-bit
+ // machines because GL types have machine-independent ranges.
+ return static_cast<double>(depth) / 4294967295.0;
+}
+
+double
+readDepth(double x, double y) {
+ return readDepth(static_cast<int>(x), static_cast<int>(y));
+}
+
+void
+findActualMRD(GLEAN::POResult& r, GLEAN::Window& w) {
+
+ // Here we use polygon offset to determine the
+ // implementation's actual MRD.
+
+ double baseDepth;
+
+ glDepthFunc(GL_ALWAYS);
+
+ // Draw a quad far away from the eye and read the depth at its center:
+ glDisable(GL_POLYGON_OFFSET_FILL);
+ drawQuadAtDistance(r.nextToFar);
+ baseDepth = readDepth(PGOS_WIN_SIZE/2, PGOS_WIN_SIZE/2);
+
+ // Now draw a quad that's one MRD closer to the eye:
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(0.0, -1.0);
+ drawQuadAtDistance(r.nextToFar);
+
+ // The difference between the depths of the two quads is the
+ // value the implementation is actually using for one MRD:
+ r.actualMRDFar = baseDepth
+ - readDepth(PGOS_WIN_SIZE/2, PGOS_WIN_SIZE/2);
+
+ // Repeat the process for a quad close to the eye:
+ glDisable(GL_POLYGON_OFFSET_FILL);
+ drawQuadAtDistance(r.nextToNear);
+ baseDepth = readDepth(PGOS_WIN_SIZE/2, PGOS_WIN_SIZE/2);
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(0.0, 1.0); // 1 MRD further away
+ drawQuadAtDistance(r.nextToNear);
+ r.actualMRDNear = readDepth(PGOS_WIN_SIZE/2, PGOS_WIN_SIZE/2)
+ - baseDepth;
+ w.swap();
+} // findActualMRD
+
+void
+logMRD(ostream& log, double mrd, GLEAN::DrawingSurfaceConfig* config) {
+ int bits = static_cast<int>(0.5 + (pow(2.0, config->z) - 1.0) * mrd);
+ log << mrd << " (nominally " << bits
+ << ((bits == 1)? " bit)": " bits)");
+} // logMRD
+
+void
+draw2x2Quad() {
+ glBegin(GL_QUADS);
+ glVertex2f(-1.0, -1.0);
+ glVertex2f( 1.0, -1.0);
+ glVertex2f( 1.0, 1.0);
+ glVertex2f(-1.0, 1.0);
+ glEnd();
+}
+
+void
+checkSlopeOffset(GLEAN::POResult& r, GLEAN::Window& w, AngleAxis* aa) {
+ // This function checks for correct slope-based offsets for
+ // a quad rotated to a given angle around a given axis.
+ //
+ // The basic strategy is to:
+ // Draw the quad. (Note: the quad's size and position
+ // are chosen so that it won't ever be clipped.)
+ // Sample three points in the quad's interior.
+ // Compute dz/dx and dz/dy based on those samples.
+ // Compute the range of allowable offsets; must be between
+ // max(abs(dz/dx), abs(dz/dy)) and
+ // sqrt((dz/dx)**2, (dz/dy)**2)
+ // Sample the depth of the quad at its center.
+ // Use PolygonOffset to produce an offset equal to one
+ // times the depth slope of the base quad.
+ // Draw another quad with the same orientation as the first.
+ // Sample the second quad at its center.
+ // Compute the difference in depths between the first quad
+ // and the second.
+ // Verify that the difference is within the allowable range.
+ // Repeat for a third quad at twice the offset from the first.
+ // (This verifies that the implementation is scaling
+ // the depth offset correctly.)
+
+ if (!r.slopeOffsetsPassed)
+ return;
+
+ const GLfloat quadDist = 2.5; // must be > 1+sqrt(2) to avoid
+ // clipping by the near plane
+
+ glClearDepth(1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ red();
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -quadDist);
+ glRotatef(aa->angle, aa->axis[0], aa->axis[1], aa->axis[2]);
+
+ GLdouble modelViewMat[16];
+ glGetDoublev(GL_MODELVIEW_MATRIX, modelViewMat);
+ GLdouble projectionMat[16];
+ glGetDoublev(GL_PROJECTION_MATRIX, projectionMat);
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ draw2x2Quad();
+ w.swap();
+
+ GLdouble centerW[3];
+ gluProject(0.0, 0.0, 0.0, modelViewMat, projectionMat, viewport,
+ centerW + 0, centerW + 1, centerW + 2);
+ GLdouble baseDepth = readDepth(centerW[0], centerW[1]);
+
+ GLdouble p0[3];
+ gluProject(-0.9, -0.9, 0.0, modelViewMat, projectionMat, viewport,
+ p0 + 0, p0 + 1, p0 + 2);
+ p0[2] = readDepth(p0[0], p0[1]);
+ GLdouble p1[3];
+ gluProject( 0.9, -0.9, 0.0, modelViewMat, projectionMat, viewport,
+ p1 + 0, p1 + 1, p1 + 2);
+ p1[2] = readDepth(p1[0], p1[1]);
+ GLdouble p2[3];
+ gluProject( 0.9, 0.9, 0.0, modelViewMat, projectionMat, viewport,
+ p2 + 0, p2 + 1, p2 + 2);
+ p2[2] = readDepth(p2[0], p2[1]);
+
+ double det = (p0[0] - p1[0]) * (p0[1] - p2[1])
+ - (p0[0] - p2[0]) * (p0[1] - p1[1]);
+ if (fabs(det) < 0.001)
+ return; // too close to colinear to evaluate
+
+ double dzdx = ((p0[2] - p1[2]) * (p0[1] - p2[1])
+ - (p0[2] - p2[2]) * (p0[1] - p1[1])) / det;
+ double dzdy = ((p0[0] - p1[0]) * (p0[2] - p2[2])
+ - (p0[0] - p2[0]) * (p0[2] - p1[2])) / det;
+
+ double mMax = 1.1 * sqrt(dzdx * dzdx + dzdy * dzdy) + r.idealMRDNear;
+ // (adding idealMRDNear is a fudge for roundoff error when
+ // the slope is extremely close to zero)
+ double mMin = 0.9 * max(fabs(dzdx), fabs(dzdy));
+
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-1.0, 0.0);
+ draw2x2Quad();
+ GLdouble offsetDepth = readDepth(centerW[0], centerW[1]);
+ GLdouble offset = max(baseDepth - offsetDepth, 0.0);
+ if (offset < mMin || offset > mMax) {
+ r.slopeOffsetsPassed = false;
+ r.failingAngle = aa->angle;
+ r.failingAxis[0] = aa->axis[0];
+ r.failingAxis[1] = aa->axis[1];
+ r.failingAxis[2] = aa->axis[2];
+ r.failingOffset = offset;
+ r.minGoodOffset = mMin;
+ r.maxGoodOffset = mMax;
+ return;
+ }
+
+ glPolygonOffset(-2.0, 0.0);
+ draw2x2Quad();
+ offsetDepth = readDepth(centerW[0], centerW[1]);
+ offset = max(baseDepth - offsetDepth, 0.0);
+ if (offset < 2.0 * mMin || offset > 2.0 * mMax) {
+ r.slopeOffsetsPassed = false;
+ r.failingAngle = aa->angle;
+ r.failingAxis[0] = aa->axis[0];
+ r.failingAxis[1] = aa->axis[1];
+ r.failingAxis[2] = aa->axis[2];
+ r.failingOffset = offset;
+ r.minGoodOffset = 2.0 * mMin;
+ r.maxGoodOffset = 2.0 * mMax;
+ return;
+ }
+}
+
+void
+checkSlopeOffsets(GLEAN::POResult& r, GLEAN::Window& w) {
+ // This function checks that the implementation is offsetting
+ // primitives correctly according to their depth slopes.
+ // (Note that it uses some values computed by findIdealMRD, so
+ // that function must be run first.)
+
+ // Rotation angles (degrees) and axes for which offset will be checked:
+ AngleAxis aa[] = {
+ { 0, {1, 0, 0}},
+ {30, {1, 0, 0}},
+ {45, {1, 0, 0}},
+ {60, {1, 0, 0}},
+ {80, {1, 0, 0}},
+ { 0, {0, 1, 0}},
+ {30, {0, 1, 0}},
+ {45, {0, 1, 0}},
+ {60, {0, 1, 0}},
+ {80, {0, 1, 0}},
+ { 0, {1, 1, 0}},
+ {30, {1, 1, 0}},
+ {45, {1, 1, 0}},
+ {60, {1, 1, 0}},
+ {80, {1, 1, 0}},
+ { 0, {2, 1, 0}},
+ {30, {2, 1, 0}},
+ {45, {2, 1, 0}},
+ {60, {2, 1, 0}},
+ {80, {2, 1, 0}}
+ };
+
+ r.slopeOffsetsPassed = true;
+ for (unsigned int i = 0;
+ r.slopeOffsetsPassed && i < sizeof(aa)/sizeof(aa[0]);
+ ++i)
+ checkSlopeOffset(r, w, aa + i);
+} // checkSlopeOffsets
+
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+PgosTest::runOne(POResult& r, GLEAN::Window& w) {
+
+ glViewport(0, 0, PGOS_WIN_SIZE, PGOS_WIN_SIZE);
+ glDepthRange(0.0, 1.0);
+ {
+ glMatrixMode(GL_PROJECTION);
+
+ // The following projection matrix places the near clipping
+ // plane at distance 1.0, and the far clipping plane at
+ // infinity. This allows us to stress depth-buffer resolution
+ // as far away from the eye as possible, without introducing
+ // code that depends on the size or format of the depth
+ // buffer.
+ //
+ // (To derive this matrix, start with the matrix generated by
+ // glFrustum with near-plane distance equal to 1.0, and take
+ // the limit of the matrix elements as the far-plane distance
+ // goes to infinity.)
+
+ static GLfloat near1_farInfinity[] = {
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, -1.0, -1.0,
+ 0.0, 0.0, -2.0, 0.0
+ };
+ glLoadMatrixf(near1_farInfinity);
+ }
+
+ glDisable(GL_LIGHTING);
+
+ glFrontFace(GL_CCW);
+ glDisable(GL_NORMALIZE);
+ glDisable(GL_COLOR_MATERIAL);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glDisable(GL_TEXTURE_2D);
+
+ glDisable(GL_FOG);
+
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+ glReadBuffer(GL_FRONT);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClearDepth(1.0);
+
+ // Clear both front and back buffers and swap, to avoid confusing
+ // this test with results of the previous test:
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ w.swap();
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ findIdealMRD(r, w);
+ findActualMRD(r, w);
+ double idealMRD = max(r.idealMRDNear, r.idealMRDFar);
+ double actualMRD = max(r.actualMRDNear, r.actualMRDFar);
+ r.bigEnoughMRD = (actualMRD >= 0.99 * idealMRD);
+ r.smallEnoughMRD = (actualMRD <= 2.0 * idealMRD);
+
+ checkSlopeOffsets(r, w);
+
+ r.pass = r.bigEnoughMRD && r.smallEnoughMRD && r.slopeOffsetsPassed;
+} // PgosTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+PgosTest::compareOne(POResult& oldR, POResult& newR) {
+ comparePassFail(oldR, newR);
+ if (oldR.bigEnoughMRD != newR.bigEnoughMRD) {
+ env->log << "\tMin size MRD criterion: "
+ << env->options.db1Name
+ << (oldR.bigEnoughMRD? " PASS, ": " FAIL, ")
+ << env->options.db2Name
+ << (newR.bigEnoughMRD? " PASS\n": " FAIL\n");
+ }
+ if (oldR.smallEnoughMRD != newR.smallEnoughMRD) {
+ env->log << "\tMax size MRD criterion: "
+ << env->options.db1Name
+ << (oldR.smallEnoughMRD? " PASS, ": " FAIL, ")
+ << env->options.db2Name
+ << (newR.smallEnoughMRD? " PASS\n": " FAIL\n");
+ }
+ if (oldR.slopeOffsetsPassed != newR.slopeOffsetsPassed) {
+ env->log << "\tSlope-relative offsets criterion: "
+ << env->options.db1Name
+ << (oldR.slopeOffsetsPassed? " PASS, ": " FAIL, ")
+ << env->options.db2Name
+ << (newR.slopeOffsetsPassed? " PASS\n": " FAIL\n");
+ }
+ if (!oldR.slopeOffsetsPassed && !newR.slopeOffsetsPassed) {
+ if (oldR.failingAngle != newR.failingAngle) {
+ env->log << '\t'
+ << env->options.db1Name
+ << " failed at angle "
+ << oldR.failingAngle
+ << ", "
+ << env->options.db2Name
+ << " failed at angle "
+ << newR.failingAngle
+ << '\n';
+ }
+ if (oldR.failingAxis[0] != newR.failingAxis[0]
+ || oldR.failingAxis[1] != newR.failingAxis[1]
+ || oldR.failingAxis[2] != newR.failingAxis[2]) {
+ env->log << '\t'
+ << env->options.db1Name
+ << " failed at axis ("
+ << oldR.failingAxis[0]
+ << ", "
+ << oldR.failingAxis[1]
+ << ", "
+ << oldR.failingAxis[2]
+ << "), "
+ << env->options.db2Name
+ << " failed at axis ("
+ << newR.failingAxis[0]
+ << ", "
+ << newR.failingAxis[1]
+ << ", "
+ << newR.failingAxis[2]
+ << ")\n";
+ }
+ }
+} // PgosTest::compareOne
+
+void
+PgosTest::logOne(POResult& r) {
+ logPassFail(r);
+ logConcise(r);
+
+ if (!r.bigEnoughMRD)
+ env->log << "\tActual MRD is too small "
+ "(may cause incorrect results)\n";
+ if (!r.smallEnoughMRD)
+ env->log << "\tActual MRD is too large "
+ "(may waste depth-buffer range)\n";
+ if (!r.slopeOffsetsPassed) {
+ env->log << "\tDepth-slope related offset was too "
+ << ((r.failingOffset < r.minGoodOffset)?
+ "small": "large")
+ << "; first failure at:\n";
+ env->log << "\t\tAngle = " << r.failingAngle << " degrees, "
+ << "axis = (" << r.failingAxis[0] << ", "
+ << r.failingAxis[1] << ", "
+ << r.failingAxis[2] << ")\n";
+ env->log << "\t\tFailing offset was "
+ << setprecision(16) << r.failingOffset << "\n";
+ env->log << "\t\tAllowable range is ("
+ << r.minGoodOffset << ", " << r.maxGoodOffset << ")\n";
+ }
+
+ if (!r.pass)
+ env->log << '\n';
+
+ env->log << "\tIdeal MRD at near plane is ";
+ logMRD(env->log, r.idealMRDNear, r.config);
+ env->log << '\n';
+
+ env->log << "\tActual MRD at near plane is ";
+ logMRD(env->log, r.actualMRDNear, r.config);
+ env->log << '\n';
+
+ env->log << "\tIdeal MRD at infinity is ";
+ logMRD(env->log, r.idealMRDFar, r.config);
+ env->log << '\n';
+
+ env->log << "\tActual MRD at infinity is ";
+ logMRD(env->log, r.actualMRDFar, r.config);
+ env->log << '\n';
+
+} // PgosTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+PgosTest
+pgosTest("polygonOffset", "window, rgb, z",
+
+ "This test verifies glPolygonOffset. It is run on every\n"
+ "OpenGL-capable drawing surface configuration that supports\n"
+ "creation of a window, has a depth buffer, and is RGB.\n"
+ "\n"
+ "The first subtest verifies that the OpenGL implementation is\n"
+ "using a plausible value for the \"minimum resolvable\n"
+ "difference\" (MRD). This is the offset in window coordinates\n"
+ "that is sufficient to provide separation in depth (Z) for any\n"
+ "two parallel surfaces. The subtest searches for the MRD by\n"
+ "drawing two surfaces at a distance from each other and\n"
+ "checking the resulting image to see if they were cleanly\n"
+ "separated. The distance is then modified (using a binary\n"
+ "search) until a minimum value is found. This is the so-called\n"
+ "\"ideal\" MRD. Then two surfaces are drawn using\n"
+ "glPolygonOffset to produce a separation that should equal one\n"
+ "MRD. The depth values at corresponding points on each surface\n"
+ "are subtracted to form the \"actual\" MRD. The subtest performs\n"
+ "these checks twice, once close to the viewpoint and once far\n"
+ "away from it, and passes if the largest of the ideal MRDs and\n"
+ "the largest of the actual MRDs are nearly the same.\n"
+ "\n"
+ "The second subtest verifies that the OpenGL implementation is\n"
+ "producing plausible values for slope-dependent offsets. The\n"
+ "OpenGL spec requires that the depth slope of a surface be\n"
+ "computed by an approximation that is at least as large as\n"
+ "max(abs(dz/dx),abs(dz/dy)) and no larger than\n"
+ "sqrt((dz/dx)**2+(dz/dy)**2). The subtest draws a quad rotated\n"
+ "by various angles along various axes, samples three points on\n"
+ "the quad's surface, and computes dz/dx and dz/dy. Then it\n"
+ "draws two additional quads offset by one and two times the\n"
+ "depth slope, respectively. The base quad and the two new\n"
+ "quads are sampled and their actual depths read from the depth\n"
+ "buffer. The subtest passes if the quads are offset by amounts\n"
+ "that are within one and two times the allowable range,\n"
+ "respectively.\n"
+
+ );
+
+} // namespace GLEAN
diff --git a/tests/glean/tpgos.h b/tests/glean/tpgos.h
new file mode 100644
index 00000000..8919756e
--- /dev/null
+++ b/tests/glean/tpgos.h
@@ -0,0 +1,124 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// tpgos.h: Polygon offset tests.
+// Derived in part from tests written by Angus Dorbie <dorbie@sgi.com>
+// in September 2000 and Rickard E. (Rik) Faith <faith@valinux.com> in
+// October 2000.
+
+#ifndef __tpgos_h__
+#define __tpgos_h__
+
+#include "tbase.h"
+#include <iomanip>
+
+namespace GLEAN {
+
+// Auxiliary struct for holding a glPolygonOffset result
+class POResult: public BaseResult {
+public:
+ bool pass;
+ double nextToNear;
+ double nextToFar;
+ double idealMRDNear;
+ double idealMRDFar;
+ double actualMRDNear;
+ double actualMRDFar;
+ bool bigEnoughMRD;
+ bool smallEnoughMRD;
+ bool slopeOffsetsPassed;
+ float failingAngle;
+ float failingAxis[3];
+ double failingOffset;
+ double minGoodOffset;
+ double maxGoodOffset;
+
+ POResult() {
+ pass = true;
+ nextToNear = 1.0;
+ nextToFar = 2.0;
+ idealMRDNear = 0.1;
+ idealMRDFar = 0.1;
+ actualMRDNear = 0.1;
+ actualMRDFar = 0.1;
+ bigEnoughMRD = true;
+ smallEnoughMRD = true;
+ slopeOffsetsPassed = true;
+ failingAngle = 0.0;
+ failingAxis[0] = failingAxis[1] = failingAxis[2] = 0.0;
+ failingOffset = 1.0;
+ minGoodOffset = 0.1;
+ maxGoodOffset = 0.1;
+ }
+
+ void putresults(ostream& s) const {
+ s << setprecision(16)
+ << pass << '\n'
+ << nextToNear << ' ' << nextToFar << '\n'
+ << idealMRDNear << ' ' << idealMRDFar << '\n'
+ << actualMRDNear << ' ' << actualMRDFar << '\n'
+ << bigEnoughMRD << ' ' << smallEnoughMRD << '\n'
+ << slopeOffsetsPassed << '\n'
+ << failingAngle << '\n'
+ << failingAxis[0] << ' ' << failingAxis[1] << ' '
+ << failingAxis[2] << '\n'
+ << failingOffset << ' ' << minGoodOffset << ' '
+ << maxGoodOffset << '\n'
+ ;
+ }
+
+ bool getresults(istream& s) {
+ s >> pass
+ >> nextToNear
+ >> nextToFar
+ >> idealMRDNear
+ >> idealMRDFar
+ >> actualMRDNear
+ >> actualMRDFar
+ >> bigEnoughMRD
+ >> smallEnoughMRD
+ >> slopeOffsetsPassed
+ >> failingAngle
+ >> failingAxis[0] >> failingAxis[1] >> failingAxis[2]
+ >> failingOffset >> minGoodOffset >> maxGoodOffset
+ ;
+ return s.good();
+ }
+};
+
+#define PGOS_WIN_SIZE 128
+
+class PgosTest: public BaseTest<POResult> {
+public:
+ GLEAN_CLASS_WH(PgosTest, POResult, PGOS_WIN_SIZE, PGOS_WIN_SIZE);
+}; // class PgosTest
+
+} // namespace GLEAN
+
+#endif // __tpgos_h__
diff --git a/tests/glean/tpixelformats.cpp b/tests/glean/tpixelformats.cpp
new file mode 100644
index 00000000..867ba08f
--- /dev/null
+++ b/tests/glean/tpixelformats.cpp
@@ -0,0 +1,1405 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+#include "tpixelformats.h"
+#include <cassert>
+#include <cmath>
+
+
+// Set to 1 to help debug test failures:
+// Also, when a test failure is found, rearrange the order of the
+// formats, types, internformats below so the failure case comes first.
+#define DEBUG 0
+
+
+// just for extra debugging
+// Maybe add fragment program path as a 3rd envMode (below) someday.
+#define USE_FRAG_PROG 0
+
+
+namespace GLEAN {
+
+
+struct NameTokenComps {
+ const char *Name;
+ GLenum Token;
+ GLuint Components;
+};
+
+
+static const NameTokenComps Types[] =
+{
+ { "GL_UNSIGNED_BYTE", GL_UNSIGNED_BYTE, 0 },
+ { "GL_BYTE", GL_BYTE, 0 },
+ { "GL_UNSIGNED_INT", GL_UNSIGNED_INT, 0 },
+ { "GL_SHORT", GL_SHORT, 0 },
+ { "GL_UNSIGNED_SHORT", GL_UNSIGNED_SHORT, 0 },
+ { "GL_INT", GL_INT, 0 },
+ { "GL_FLOAT", GL_FLOAT, 0 },
+#ifdef GL_ARB_half_float_pixel
+ { "GL_HALF_FLOAT_ARB", GL_HALF_FLOAT_ARB, 0 },
+#endif
+
+ { "GL_UNSIGNED_INT_8_8_8_8", GL_UNSIGNED_INT_8_8_8_8, 4 },
+ { "GL_UNSIGNED_INT_8_8_8_8_REV", GL_UNSIGNED_INT_8_8_8_8_REV, 4 },
+ { "GL_UNSIGNED_INT_10_10_10_2", GL_UNSIGNED_INT_10_10_10_2, 4 },
+ { "GL_UNSIGNED_INT_2_10_10_10_REV", GL_UNSIGNED_INT_2_10_10_10_REV, 4 },
+ { "GL_UNSIGNED_SHORT_5_5_5_1", GL_UNSIGNED_SHORT_5_5_5_1, 4 },
+ { "GL_UNSIGNED_SHORT_1_5_5_5_REV", GL_UNSIGNED_SHORT_1_5_5_5_REV, 4 },
+ { "GL_UNSIGNED_SHORT_4_4_4_4", GL_UNSIGNED_SHORT_4_4_4_4, 4 },
+ { "GL_UNSIGNED_SHORT_4_4_4_4_REV", GL_UNSIGNED_SHORT_4_4_4_4_REV, 4 },
+ { "GL_UNSIGNED_SHORT_5_6_5", GL_UNSIGNED_SHORT_5_6_5, 3 },
+ { "GL_UNSIGNED_SHORT_5_6_5_REV", GL_UNSIGNED_SHORT_5_6_5_REV, 3 },
+ { "GL_UNSIGNED_BYTE_3_3_2", GL_UNSIGNED_BYTE_3_3_2, 3 },
+ { "GL_UNSIGNED_BYTE_2_3_3_REV", GL_UNSIGNED_BYTE_2_3_3_REV, 3 }
+};
+
+#define NUM_TYPES (sizeof(Types) / sizeof(Types[0]))
+
+
+static const NameTokenComps Formats[] =
+{
+ { "GL_RGBA", GL_RGBA, 4 },
+ { "GL_BGRA", GL_BGRA, 4 },
+ { "GL_RGB", GL_RGB, 3 },
+ { "GL_BGR", GL_BGR, 3 },
+ { "GL_RED", GL_RED, 1 },
+ { "GL_GREEN", GL_GREEN, 1 },
+ { "GL_BLUE", GL_BLUE, 1 },
+ { "GL_ALPHA", GL_ALPHA, 1 },
+ { "GL_LUMINANCE", GL_LUMINANCE, 1 },
+ { "GL_LUMINANCE_ALPHA", GL_LUMINANCE_ALPHA, 2 },
+#ifdef GL_EXT_abgr
+ { "GL_ABGR_EXT", GL_ABGR_EXT, 4 }
+#endif
+};
+
+#define NUM_FORMATS (sizeof(Formats) / sizeof(Formats[0]))
+
+
+static const NameTokenComps InternalFormats[] =
+{
+ { "glDrawPixels", 0, 4 }, // special case for glDrawPixels
+
+ { "4", 4, 4 },
+ { "GL_RGBA", GL_RGBA, 4 },
+ { "GL_RGBA2", GL_RGBA2, 4 },
+ { "GL_RGBA4", GL_RGBA4, 4 },
+ { "GL_RGB5_A1", GL_RGB5_A1, 4 },
+ { "GL_RGBA8", GL_RGBA8, 4 },
+ { "GL_RGB10_A2", GL_RGB10_A2, 4 },
+ { "GL_RGBA12", GL_RGBA12, 4 },
+ { "GL_RGBA16", GL_RGBA16, 4 },
+#ifdef GL_EXT_texture_sRGB
+ { "GL_SRGB_ALPHA_EXT", GL_SRGB_ALPHA_EXT, 4 },
+ { "GL_SRGB8_ALPHA8_EXT", GL_SRGB8_ALPHA8_EXT, 4 },
+#endif
+
+ { "3", 3, 3 },
+ { "GL_RGB", GL_RGB, 3 },
+ { "GL_R3_G3_B2", GL_R3_G3_B2, 3 },
+ { "GL_RGB4", GL_RGB4, 3 },
+ { "GL_RGB5", GL_RGB5, 3 },
+ { "GL_RGB8", GL_RGB8, 3 },
+ { "GL_RGB10", GL_RGB10, 3 },
+ { "GL_RGB12", GL_RGB12, 3 },
+ { "GL_RGB16", GL_RGB16, 3 },
+#ifdef GL_EXT_texture_sRGB
+ { "GL_SRGB_EXT", GL_SRGB_EXT, 3 },
+ { "GL_SRGB8_EXT", GL_SRGB8_EXT, 3 },
+#endif
+
+ { "2", 2, 1 },
+ { "GL_LUMINANCE_ALPHA", GL_LUMINANCE_ALPHA, 1 },
+ { "GL_LUMINANCE4_ALPHA4", GL_LUMINANCE4_ALPHA4, 1 },
+ { "GL_LUMINANCE6_ALPHA2", GL_LUMINANCE6_ALPHA2, 1 },
+ { "GL_LUMINANCE8_ALPHA8", GL_LUMINANCE8_ALPHA8, 1 },
+ { "GL_LUMINANCE12_ALPHA4", GL_LUMINANCE12_ALPHA4, 1 },
+ { "GL_LUMINANCE12_ALPHA12", GL_LUMINANCE12_ALPHA12, 1 },
+ { "GL_LUMINANCE16_ALPHA16", GL_LUMINANCE16_ALPHA16, 1 },
+#ifdef GL_EXT_texture_sRGB
+ { "GL_SLUMINANCE_ALPHA_EXT", GL_SLUMINANCE_ALPHA_EXT, 3 },
+ { "GL_SLUMINANCE8_ALPHA8_EXT", GL_SLUMINANCE8_ALPHA8_EXT, 3 },
+#endif
+
+ { "1", 1, 1 },
+ { "GL_LUMINANCE", GL_LUMINANCE, 1 },
+ { "GL_LUMINANCE4", GL_LUMINANCE4, 1 },
+ { "GL_LUMINANCE8", GL_LUMINANCE8, 1 },
+ { "GL_LUMINANCE12", GL_LUMINANCE12, 1 },
+ { "GL_LUMINANCE16", GL_LUMINANCE16, 1 },
+#ifdef GL_EXT_texture_sRGB
+ { "GL_SLUMINANCE_EXT", GL_SLUMINANCE_EXT, 3 },
+ { "GL_SLUMINANCE8_EXT", GL_SLUMINANCE8_EXT, 3 },
+#endif
+
+ { "GL_ALPHA", GL_ALPHA, 1 },
+ { "GL_ALPHA4", GL_ALPHA4, 1 },
+ { "GL_ALPHA8", GL_ALPHA8, 1 },
+ { "GL_ALPHA12", GL_ALPHA12, 1 },
+ { "GL_ALPHA16", GL_ALPHA16, 1 },
+
+ { "GL_INTENSITY", GL_INTENSITY, 1 },
+ { "GL_INTENSITY4", GL_INTENSITY4, 1 },
+ { "GL_INTENSITY8", GL_INTENSITY8, 1 },
+ { "GL_INTENSITY12", GL_INTENSITY12, 1 },
+ { "GL_INTENSITY16", GL_INTENSITY16, 1 },
+
+ // XXX maybe add compressed formats too...
+};
+
+#define NUM_INT_FORMATS (sizeof(InternalFormats) / sizeof(InternalFormats[0]))
+
+
+static const char *EnvModes[] = {
+ "GL_REPLACE",
+ "GL_COMBINE_ARB"
+};
+
+
+// Return four bitmasks indicating which bits correspond to the
+// 1st, 2nd, 3rd and 4th components in a packed datatype.
+// Set all masks to zero for non-packed types.
+static void
+ComponentMasks(GLenum datatype, GLuint masks[4])
+{
+ switch (datatype) {
+ case GL_UNSIGNED_BYTE:
+ case GL_BYTE:
+ case GL_UNSIGNED_SHORT:
+ case GL_SHORT:
+ case GL_UNSIGNED_INT:
+ case GL_INT:
+ case GL_FLOAT:
+#ifdef GL_ARB_half_float_pixel
+ case GL_HALF_FLOAT_ARB:
+#endif
+ masks[0] =
+ masks[1] =
+ masks[2] =
+ masks[3] = 0x0;
+ break;
+ case GL_UNSIGNED_INT_8_8_8_8:
+ masks[0] = 0xff000000;
+ masks[1] = 0x00ff0000;
+ masks[2] = 0x0000ff00;
+ masks[3] = 0x000000ff;
+ break;
+ case GL_UNSIGNED_INT_8_8_8_8_REV:
+ masks[0] = 0x000000ff;
+ masks[1] = 0x0000ff00;
+ masks[2] = 0x00ff0000;
+ masks[3] = 0xff000000;
+ break;
+ case GL_UNSIGNED_INT_10_10_10_2:
+ masks[0] = 0xffc00000;
+ masks[1] = 0x003ff000;
+ masks[2] = 0x00000ffc;
+ masks[3] = 0x00000003;
+ break;
+ case GL_UNSIGNED_INT_2_10_10_10_REV:
+ masks[0] = 0x000003ff;
+ masks[1] = 0x000ffc00;
+ masks[2] = 0x3ff00000;
+ masks[3] = 0xc0000000;
+ break;
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ masks[0] = 0xf800;
+ masks[1] = 0x07c0;
+ masks[2] = 0x003e;
+ masks[3] = 0x0001;
+ break;
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+ masks[0] = 0x001f;
+ masks[1] = 0x03e0;
+ masks[2] = 0x7c00;
+ masks[3] = 0x8000;
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ masks[0] = 0xf000;
+ masks[1] = 0x0f00;
+ masks[2] = 0x00f0;
+ masks[3] = 0x000f;
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+ masks[0] = 0x000f;
+ masks[1] = 0x00f0;
+ masks[2] = 0x0f00;
+ masks[3] = 0xf000;
+ break;
+ case GL_UNSIGNED_SHORT_5_6_5:
+ masks[0] = 0xf800;
+ masks[1] = 0x07e0;
+ masks[2] = 0x001f;
+ masks[3] = 0;
+ break;
+ case GL_UNSIGNED_SHORT_5_6_5_REV:
+ masks[0] = 0x001f;
+ masks[1] = 0x07e0;
+ masks[2] = 0xf800;
+ masks[3] = 0;
+ break;
+ case GL_UNSIGNED_BYTE_3_3_2:
+ masks[0] = 0xe0;
+ masks[1] = 0x1c;
+ masks[2] = 0x03;
+ masks[3] = 0;
+ break;
+ case GL_UNSIGNED_BYTE_2_3_3_REV:
+ masks[0] = 0x07;
+ masks[1] = 0x38;
+ masks[2] = 0xc0;
+ masks[3] = 0;
+ break;
+ default:
+ abort();
+ }
+}
+
+
+// Return four values indicating the ordering of the Red, Green, Blue and
+// Alpha components for the given image format.
+// For example: GL_BGRA = {2, 1, 0, 3}.
+static void
+ComponentPositions(GLenum format, GLint pos[4])
+{
+ switch (format) {
+ case GL_RGBA:
+ pos[0] = 0;
+ pos[1] = 1;
+ pos[2] = 2;
+ pos[3] = 3;
+ break;
+ case GL_BGRA:
+ pos[0] = 2;
+ pos[1] = 1;
+ pos[2] = 0;
+ pos[3] = 3;
+ break;
+ case GL_RGB:
+ pos[0] = 0;
+ pos[1] = 1;
+ pos[2] = 2;
+ pos[3] = -1;
+ break;
+ case GL_BGR:
+ pos[0] = 2;
+ pos[1] = 1;
+ pos[2] = 0;
+ pos[3] = -1;
+ break;
+ case GL_LUMINANCE:
+ pos[0] = 0;
+ pos[1] = -1;
+ pos[2] = -1;
+ pos[3] = -1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ pos[0] = 0;
+ pos[1] = -1;
+ pos[2] = -1;
+ pos[3] = 1;
+ break;
+ case GL_RED:
+ pos[0] = 0;
+ pos[1] = -1;
+ pos[2] = -1;
+ pos[3] = -1;
+ break;
+ case GL_GREEN:
+ pos[0] = -1;
+ pos[1] = 0;
+ pos[2] = -1;
+ pos[3] = -1;
+ break;
+ case GL_BLUE:
+ pos[0] = -1;
+ pos[1] = -1;
+ pos[2] = 0;
+ pos[3] = -1;
+ break;
+ case GL_ALPHA:
+ pos[0] = -1;
+ pos[1] = -1;
+ pos[2] = -1;
+ pos[3] = 0;
+ break;
+#ifdef GL_EXT_abgr
+ case GL_ABGR_EXT:
+ pos[0] = 3;
+ pos[1] = 2;
+ pos[2] = 1;
+ pos[3] = 0;
+ break;
+#endif
+ default:
+ abort();
+ }
+}
+
+
+// Given a texture internal format, return the corresponding base format.
+static GLenum
+BaseTextureFormat(GLint intFormat)
+{
+ switch (intFormat) {
+ case 0:
+ return 0; // for glDrawPixels
+ case GL_ALPHA:
+ case GL_ALPHA4:
+ case GL_ALPHA8:
+ case GL_ALPHA12:
+ case GL_ALPHA16:
+ return GL_ALPHA;
+ case 1:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE4:
+ case GL_LUMINANCE8:
+ case GL_LUMINANCE12:
+ case GL_LUMINANCE16:
+ return GL_LUMINANCE;
+ case 2:
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE4_ALPHA4:
+ case GL_LUMINANCE6_ALPHA2:
+ case GL_LUMINANCE8_ALPHA8:
+ case GL_LUMINANCE12_ALPHA4:
+ case GL_LUMINANCE12_ALPHA12:
+ case GL_LUMINANCE16_ALPHA16:
+ return GL_LUMINANCE_ALPHA;
+ case GL_INTENSITY:
+ case GL_INTENSITY4:
+ case GL_INTENSITY8:
+ case GL_INTENSITY12:
+ case GL_INTENSITY16:
+ return GL_INTENSITY;
+ case 3:
+ case GL_RGB:
+ case GL_R3_G3_B2:
+ case GL_RGB4:
+ case GL_RGB5:
+ case GL_RGB8:
+ case GL_RGB10:
+ case GL_RGB12:
+ case GL_RGB16:
+ return GL_RGB;
+ case 4:
+ case GL_RGBA:
+ case GL_RGBA2:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGBA8:
+ case GL_RGB10_A2:
+ case GL_RGBA12:
+ case GL_RGBA16:
+ return GL_RGBA;
+
+#ifdef GL_EXT_texture_sRGB
+ case GL_SRGB_EXT:
+ case GL_SRGB8_EXT:
+ case GL_COMPRESSED_SRGB_EXT:
+ case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ return GL_RGB;
+ case GL_SRGB_ALPHA_EXT:
+ case GL_SRGB8_ALPHA8_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ return GL_RGBA;
+ case GL_SLUMINANCE_ALPHA_EXT:
+ case GL_SLUMINANCE8_ALPHA8_EXT:
+ case GL_COMPRESSED_SLUMINANCE_EXT:
+ case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
+ return GL_LUMINANCE_ALPHA;
+ case GL_SLUMINANCE_EXT:
+ case GL_SLUMINANCE8_EXT:
+ return GL_LUMINANCE;
+#endif
+ default:
+ abort();
+ }
+}
+
+
+
+
+// Return number components in the given datatype. This is 3 or 4 for
+// packed types and zero for non-packed types
+// Ex: GL_UNSIGNED_SHORT_5_5_5_1 = 4
+// Ex: GL_INT = 0
+static int
+NumberOfComponentsInPackedType(GLenum datatype)
+{
+ for (unsigned i = 0; i < NUM_TYPES; i++) {
+ if (Types[i].Token == datatype)
+ return Types[i].Components;
+ }
+ abort();
+}
+
+
+static int
+IsPackedType(GLenum datatype)
+{
+ return NumberOfComponentsInPackedType(datatype) > 0;
+}
+
+
+// Return number components in the given image format.
+// Ex: GL_BGR = 3
+static int
+NumberOfComponentsInFormat(GLenum format)
+{
+ for (unsigned i = 0; i < NUM_FORMATS; i++) {
+ if (Formats[i].Token == format)
+ return Formats[i].Components;
+ }
+ abort();
+}
+
+
+// Return size, in bytes, of given datatype.
+static int
+SizeofType(GLenum datatype)
+{
+ switch (datatype) {
+ case GL_UNSIGNED_INT_10_10_10_2:
+ case GL_UNSIGNED_INT_2_10_10_10_REV:
+ case GL_UNSIGNED_INT_8_8_8_8:
+ case GL_UNSIGNED_INT_8_8_8_8_REV:
+ case GL_UNSIGNED_INT:
+ case GL_INT:
+ case GL_FLOAT:
+#ifdef GL_ARB_half_float_pixel
+ case GL_HALF_FLOAT_ARB:
+#endif
+ return 4;
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_UNSIGNED_SHORT_5_6_5_REV:
+ case GL_UNSIGNED_SHORT:
+ case GL_SHORT:
+ return 2;
+ case GL_UNSIGNED_BYTE_3_3_2:
+ case GL_UNSIGNED_BYTE_2_3_3_REV:
+ case GL_UNSIGNED_BYTE:
+ case GL_BYTE:
+ return 1;
+ default:
+ abort();
+ }
+}
+
+
+// Check if the given image format and datatype are compatible.
+// Also check for types/formats defined by GL extensions here.
+bool
+PixelFormatsTest::CompatibleFormatAndType(GLenum format, GLenum datatype) const
+{
+ // Special case: GL_BGR can't be used with packed types!
+ // This has to do with putting the most color bits in red and green,
+ // not blue.
+ if (format == GL_BGR && IsPackedType(datatype))
+ return false;
+
+#ifdef GL_ARB_half_float_pixel
+ if (datatype == GL_HALF_FLOAT_ARB && !haveHalfFloat)
+ return false;
+#endif
+
+#ifdef GL_EXT_abgr
+ if (format == GL_ABGR_EXT && !haveABGR)
+ return false;
+#endif
+
+ const int formatComps = NumberOfComponentsInFormat(format);
+ const int typeComps = NumberOfComponentsInPackedType(datatype);
+ return formatComps == typeComps || typeComps == 0;
+}
+
+
+bool
+PixelFormatsTest::SupportedIntFormat(GLint intFormat) const
+{
+ switch (intFormat) {
+#ifdef GL_EXT_texture_sRGB
+ case GL_SRGB_ALPHA_EXT:
+ case GL_SRGB8_ALPHA8_EXT:
+ case GL_SRGB_EXT:
+ case GL_SRGB8_EXT:
+ case GL_SLUMINANCE_ALPHA_EXT:
+ case GL_SLUMINANCE8_ALPHA8_EXT:
+ case GL_SLUMINANCE_EXT:
+ case GL_SLUMINANCE8_EXT:
+ return haveSRGB;
+#endif
+ default:
+ return true;
+ }
+}
+
+
+// Determine if the ith pixel is in the upper-right quadrant of the
+// rectangle of size 'width' x 'height'.
+static bool
+IsUpperRight(int i, int width, int height)
+{
+ const int y = i / width, x = i % width;
+ return (x >= width / 2 && y >= height / 2);
+}
+
+
+
+// Create an image buffer and fill it so that a single image channel is
+// the max value (1.0) while the other channels are zero. For example,
+// if fillComponent==2 and we're filling a four-component image, the
+// pixels will be (0, 0, max, 0).
+//
+// We always leave the upper-right quadrant black/zero. This is to help
+// detect any image conversion issues related to stride, packing, etc.
+static GLubyte *
+MakeImage(int width, int height, GLenum format, GLenum type,
+ int fillComponent)
+{
+ assert(fillComponent < 4);
+
+ if (IsPackedType(type)) {
+ const int bpp = SizeofType(type);
+ GLubyte *image = new GLubyte [width * height * bpp];
+ GLuint masks[4];
+ int pos[4];
+ int i;
+
+ ComponentMasks(type, masks);
+ ComponentPositions(format, pos);
+
+ const GLuint value = masks[fillComponent];
+
+ switch (bpp) {
+ case 1:
+ for (i = 0; i < width * height; i++) {
+ if (IsUpperRight(i, width, height))
+ image[i] = 0;
+ else
+ image[i] = (GLubyte) value;
+ }
+ break;
+ case 2:
+ {
+ GLushort *image16 = (GLushort *) image;
+ for (i = 0; i < width * height; i++) {
+ if (IsUpperRight(i, width, height))
+ image16[i] = 0;
+ else
+ image16[i] = (GLushort) value;
+ }
+ }
+ break;
+ case 4:
+ {
+ GLuint *image32 = (GLuint *) image;
+ for (i = 0; i < width * height; i++) {
+ if (IsUpperRight(i, width, height))
+ image32[i] = 0;
+ else
+ image32[i] = (GLuint) value;
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+
+ return image;
+ }
+ else {
+ const int comps = NumberOfComponentsInFormat(format);
+ const int bpp = comps * SizeofType(type);
+ assert(bpp > 0);
+ GLubyte *image = new GLubyte [width * height * bpp];
+ int i;
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ for (i = 0; i < width * height * comps; i++) {
+ if (i % comps == fillComponent && !IsUpperRight(i/comps, width, height))
+ image[i] = 0xff;
+ else
+ image[i] = 0x0;
+ }
+ break;
+ case GL_BYTE:
+ {
+ GLbyte *b = (GLbyte *) image;
+ for (i = 0; i < width * height * comps; i++) {
+ if (i % comps == fillComponent && !IsUpperRight(i/comps, width, height))
+ b[i] = 0x7f;
+ else
+ b[i] = 0x0;
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ {
+ GLushort *us = (GLushort *) image;
+ for (i = 0; i < width * height * comps; i++) {
+ if (i % comps == fillComponent && !IsUpperRight(i/comps, width, height))
+ us[i] = 0xffff;
+ else
+ us[i] = 0x0;
+ }
+ }
+ break;
+ case GL_SHORT:
+ {
+ GLshort *s = (GLshort *) image;
+ for (i = 0; i < width * height * comps; i++) {
+ if (i % comps == fillComponent && !IsUpperRight(i/comps, width, height))
+ s[i] = 0x7fff;
+ else
+ s[i] = 0x0;
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ {
+ GLuint *ui = (GLuint *) image;
+ for (i = 0; i < width * height * comps; i++) {
+ if (i % comps == fillComponent && !IsUpperRight(i/comps, width, height))
+ ui[i] = 0xffffffff;
+ else
+ ui[i] = 0x0;
+ }
+ }
+ break;
+ case GL_INT:
+ {
+ GLint *in = (GLint *) image;
+ for (i = 0; i < width * height * comps; i++) {
+ if (i % comps == fillComponent && !IsUpperRight(i/comps, width, height))
+ in[i] = 0x7fffffff;
+ else
+ in[i] = 0x0;
+ }
+ }
+ break;
+ case GL_FLOAT:
+ {
+ GLfloat *f = (GLfloat *) image;
+ for (i = 0; i < width * height * comps; i++) {
+ if (i % comps == fillComponent && !IsUpperRight(i/comps, width, height))
+ f[i] = 1.0;
+ else
+ f[i] = 0.0;
+ }
+ }
+ break;
+#ifdef GL_ARB_half_float_pixel
+ case GL_HALF_FLOAT_ARB:
+ {
+ GLhalfARB *f = (GLhalfARB *) image;
+ for (i = 0; i < width * height * comps; i++) {
+ if (i % comps == fillComponent && !IsUpperRight(i/comps, width, height))
+ f[i] = 0x3c00; /* == 1.0 */
+ else
+ f[i] = 0;
+ }
+ }
+ break;
+#endif
+ default:
+ abort();
+ }
+ return image;
+ }
+}
+
+
+bool
+PixelFormatsTest::CheckError(const char *where) const
+{
+ GLint err = glGetError();
+ if (err) {
+ char msg[1000];
+ sprintf(msg, "GL Error: %s (0x%x) in %s\n",
+ gluErrorString(err), err, where);
+ env->log << msg;
+ return true;
+ }
+ return false;
+}
+
+
+// Draw the given image, either as a texture quad or glDrawPixels.
+// Return true for success, false if GL error detected.
+bool
+PixelFormatsTest::DrawImage(int width, int height,
+ GLenum format, GLenum type, GLint intFormat,
+ const GLubyte *image) const
+{
+ if (intFormat) {
+ glEnable(GL_TEXTURE_2D);
+ glViewport(0, 0, width, height);
+ glTexImage2D(GL_TEXTURE_2D, 0, intFormat, width, height, 0,
+ format, type, image);
+ if (CheckError("glTexImage2D"))
+ return false;
+#if USE_FRAG_PROG
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+#endif
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-1, -1);
+ glTexCoord2f(1, 0); glVertex2f(1, -1);
+ glTexCoord2f(1, 1); glVertex2f(1, 1);
+ glTexCoord2f(0, 1); glVertex2f(-1, 1);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+#if USE_FRAG_PROG
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+#endif
+ }
+ else {
+ // glDrawPixels
+ glDrawPixels(width, height, format, type, image);
+ if (CheckError("glDrawPixels"))
+ return false;
+ }
+ return true;
+}
+
+
+static bool
+ColorsEqual(const GLubyte img[4], const GLubyte expected[4])
+{
+ const int tolerance = 1;
+ if ((abs(img[0] - expected[0]) > tolerance) ||
+ (abs(img[1] - expected[1]) > tolerance) ||
+ (abs(img[2] - expected[2]) > tolerance) ||
+ (abs(img[3] - expected[3]) > tolerance)) {
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+
+// Compute the expected RGBA color we're expecting to find with glReadPixels
+// if the texture was defined with the given image format and texture
+// internal format. 'testChan' indicates which of the srcFormat's image
+// channels was set (to 1.0) when the image was filled.
+void
+PixelFormatsTest::ComputeExpected(GLenum srcFormat, int testChan,
+ GLint intFormat, GLubyte exp[4]) const
+{
+ const GLenum baseIntFormat = BaseTextureFormat(intFormat);
+
+ switch (srcFormat) {
+
+ case GL_RGBA:
+ case GL_BGRA:
+#ifdef GL_EXT_abgr
+ case GL_ABGR_EXT:
+#endif
+ assert(testChan < 4);
+ switch (baseIntFormat) {
+ case 0: // == glReadPixels
+ // fallthrough
+ case GL_RGBA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = 0;
+ exp[testChan] = 255;
+ break;
+ case GL_RGB:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[testChan] = 255;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_ALPHA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = testChan == 3 ? 255 : 0;
+ break;
+ case GL_LUMINANCE:
+ exp[0] =
+ exp[1] =
+ exp[2] = testChan == 0 ? 255 : 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_LUMINANCE_ALPHA:
+ exp[0] =
+ exp[1] =
+ exp[2] = testChan == 0 ? 255 : 0;
+ exp[3] = testChan == 3 ? 255 : 0;
+ break;
+ case GL_INTENSITY:
+ exp[0] =
+ exp[1] =
+ exp[2] =
+ exp[3] = testChan == 0 ? 255 : 0;
+ break;
+ default:
+ abort();
+ }
+ break;
+
+ case GL_RGB:
+ case GL_BGR:
+ assert(testChan < 3);
+ switch (baseIntFormat) {
+ case 0:
+ case GL_RGBA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[testChan] = 255;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_RGB:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[testChan] = 255;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_ALPHA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_LUMINANCE:
+ exp[0] =
+ exp[1] =
+ exp[2] = testChan == 0 ? 255 : 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_LUMINANCE_ALPHA:
+ exp[0] =
+ exp[1] =
+ exp[2] = testChan == 0 ? 255 : 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_INTENSITY:
+ exp[0] =
+ exp[1] =
+ exp[2] =
+ exp[3] = testChan == 0 ? 255 : 0;
+ break;
+ default:
+ abort();
+ }
+ break;
+
+ case GL_RED:
+ assert(testChan == 0);
+ switch (baseIntFormat) {
+ case 0:
+ case GL_RGBA:
+ exp[0] = 255;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_RGB:
+ exp[0] = 255;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_ALPHA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_LUMINANCE:
+ exp[0] =
+ exp[1] =
+ exp[2] = 255;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_LUMINANCE_ALPHA:
+ exp[0] =
+ exp[1] =
+ exp[2] = 255;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_INTENSITY:
+ exp[0] =
+ exp[1] =
+ exp[2] = 255;
+ exp[3] = 255; // texture's alpha
+ break;
+ default:
+ abort();
+ }
+ break;
+
+ case GL_GREEN:
+ case GL_BLUE:
+ assert(testChan == 0);
+ switch (baseIntFormat) {
+ case 0:
+ case GL_RGBA:
+ exp[0] = 0;
+ exp[1] = 255;
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_RGB:
+ exp[0] = 0;
+ exp[1] = 255;
+ exp[2] = 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_ALPHA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_LUMINANCE:
+ exp[0] =
+ exp[1] =
+ exp[2] = 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_LUMINANCE_ALPHA:
+ exp[0] =
+ exp[1] =
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_INTENSITY:
+ exp[0] =
+ exp[1] =
+ exp[2] = 0;
+ exp[3] = 0; // texture's alpha
+ break;
+ default:
+ abort();
+ }
+ break;
+
+ case GL_ALPHA:
+ assert(testChan == 0);
+ switch (baseIntFormat) {
+ case 0:
+ case GL_RGBA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_RGB:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_ALPHA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_LUMINANCE:
+ exp[0] =
+ exp[1] =
+ exp[2] = 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_LUMINANCE_ALPHA:
+ exp[0] =
+ exp[1] =
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_INTENSITY:
+ exp[0] =
+ exp[1] =
+ exp[2] = 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ default:
+ abort();
+ }
+ break;
+
+ case GL_LUMINANCE:
+ assert(testChan == 0);
+ switch (baseIntFormat) {
+ case 0:
+ case GL_RGBA:
+ exp[0] = 255;
+ exp[1] = 255;
+ exp[2] = 255;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_RGB:
+ exp[0] = 255;
+ exp[1] = 255;
+ exp[2] = 255;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_ALPHA:
+ exp[0] = 0;
+ exp[1] = 0;
+ exp[2] = 0;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_LUMINANCE:
+ exp[0] = 255;
+ exp[1] = 255;
+ exp[2] = 255;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_LUMINANCE_ALPHA:
+ exp[0] = 255;
+ exp[1] = 255;
+ exp[2] = 255;
+ exp[3] = 255; // texture's alpha
+ break;
+ case GL_INTENSITY:
+ exp[0] = 255;
+ exp[1] = 255;
+ exp[2] = 255;
+ exp[3] = 255; // texture's alpha
+ break;
+ default:
+ abort();
+ }
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ assert(testChan < 2);
+ switch (baseIntFormat) {
+ case 0:
+ case GL_RGBA:
+ exp[0] =
+ exp[1] =
+ exp[2] = testChan == 0 ? 255 : 0;
+ exp[3] = testChan == 1 ? 255 : 0;
+ break;
+ case GL_RGB:
+ exp[0] =
+ exp[1] =
+ exp[2] = testChan == 0 ? 255 : 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_ALPHA:
+ exp[0] =
+ exp[1] =
+ exp[2] = 0; // fragment color
+ exp[3] = testChan == 1 ? 255 : 0;
+ break;
+ case GL_LUMINANCE:
+ exp[0] =
+ exp[1] =
+ exp[2] = testChan == 0 ? 255 : 0;
+ exp[3] = defaultAlpha; // fragment alpha or texture alpha
+ break;
+ case GL_LUMINANCE_ALPHA:
+ exp[0] = testChan == 0 ? 255 : 0;
+ exp[1] = testChan == 0 ? 255 : 0;
+ exp[2] = testChan == 0 ? 255 : 0;
+ exp[3] = testChan == 1 ? 255 : 0;
+ break;
+ case GL_INTENSITY:
+ exp[0] =
+ exp[1] =
+ exp[2] =
+ exp[3] = testChan == 0 ? 255 : 0;
+ break;
+ default:
+ abort();
+ }
+ break;
+
+ default:
+ abort();
+ }
+}
+
+
+// Read framebuffer and check that region [width x height] is the expected
+// solid color, except the upper-right quadrant will always be black/zero.
+// comp: which color channel in src image was set (0 = red, 1 = green,
+// 2 = blue, 3 = alpha), other channels are zero.
+// format is the color format we're testing.
+bool
+PixelFormatsTest::CheckRendering(int width, int height, int comp,
+ GLenum format, GLint intFormat) const
+{
+ const int checkAlpha = alphaBits > 0;
+ GLubyte *image = new GLubyte [width * height * 4];
+ GLboolean ok = 1;
+ GLubyte expected[4];
+ int i;
+
+ assert(comp >= 0 && comp < 4);
+
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
+ for (i = 0; i < width * height; i += 4) {
+
+ ComputeExpected(format, comp, intFormat, expected);
+ if (IsUpperRight(i/4, width, height)) {
+ expected[0] =
+ expected[1] =
+ expected[2] =
+ expected[3] = 0;
+ }
+
+ if (!checkAlpha) {
+ expected[3] = 0xff;
+ }
+
+ // do the color check
+ if (!ColorsEqual(image+i, expected)) {
+ // report failure info
+ char msg[1000];
+ env->log << name;
+ sprintf(msg, " failed at pixel (%d,%d), color channel %d:\n",
+ i/width, i%width, comp);
+ env->log << msg;
+ sprintf(msg, " Expected: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ expected[0], expected[1], expected[2], expected[3]);
+ env->log << msg;
+ sprintf(msg, " Found: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ image[i + 0], image[i + 1], image[i + 2], image[i + 3]);
+ env->log << msg;
+ ok = false;
+ break;
+ }
+ }
+ delete [] image;
+ return ok;
+}
+
+
+
+// Exercise a particular combination of image format, type and internal
+// texture format.
+// Return true for success, false for failure.
+bool
+PixelFormatsTest::TestCombination(GLenum format, GLenum type, GLint intFormat)
+{
+ const int numComps = NumberOfComponentsInFormat(format);
+ const int width = 16;
+ const int height = 16;
+ int colorPos[4];
+ ComponentPositions(format, colorPos);
+
+ for (int comp = 0; comp < numComps; comp++) {
+ if (colorPos[comp] >= 0) {
+ // make original/incoming image
+ const int comp2 = colorPos[comp];
+ GLubyte *image = MakeImage(width, height, format, type, comp2);
+
+ // render with image (texture / glDrawPixels)
+ bool ok = DrawImage(width, height, format, type, intFormat, image);
+
+ if (ok) {
+ // check rendering
+ ok = CheckRendering(width, height, comp, format, intFormat);
+ }
+
+ delete [] image;
+
+ if (!ok) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+// Per visual setup.
+void
+PixelFormatsTest::setup(void)
+{
+ haveHalfFloat = GLUtils::haveExtensions("GL_ARB_half_float_pixel");
+ haveABGR = GLUtils::haveExtensions("GL_EXT_abgr");
+ haveSRGB = GLUtils::haveExtensions("GL_EXT_texture_sRGB");
+#if GL_ARB_texture_env_combine
+ haveCombine = GLUtils::haveExtensions("GL_ARB_texture_env_combine");
+#else
+ haveCombine = false;
+#endif
+
+ glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ glColor4f(0, 0, 0, 0);
+
+#if USE_FRAG_PROG
+ {
+ PFNGLPROGRAMSTRINGARBPROC glProgramStringARB_func;
+ PFNGLBINDPROGRAMARBPROC glBindProgramARB_func;
+ static const char *progText =
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.texcoord[0], texture[0], 2D; \n"
+ "END \n"
+ ;
+ glProgramStringARB_func = (PFNGLPROGRAMSTRINGARBPROC)
+ GLUtils::getProcAddress("glProgramStringARB");
+ assert(glProgramStringARB_func);
+ glBindProgramARB_func = (PFNGLBINDPROGRAMARBPROC)
+ GLUtils::getProcAddress("glBindProgramARB");
+ assert(glBindProgramARB_func);
+ glBindProgramARB_func(GL_FRAGMENT_PROGRAM_ARB, 1);
+ glProgramStringARB_func(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(progText), (const GLubyte *) progText);
+ if (glGetError()) {
+ fprintf(stderr, "Bad fragment program, error: %s\n",
+ (const char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ exit(0);
+ }
+ }
+#endif
+}
+
+
+
+// Test all possible image formats, types and internal texture formats.
+// Result will indicate number of passes and failures.
+void
+PixelFormatsTest::runOne(MultiTestResult &r, Window &w)
+{
+ int testNum = 0;
+ (void) w; // silence warning
+
+ setup();
+
+ const unsigned numEnvModes = haveCombine ? 2 : 1;
+
+ for (unsigned envMode = 0; envMode < numEnvModes; envMode++) {
+ if (envMode == 0) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ // When the texture internal format is GL_LUMINANCE or GL_RGB,
+ // GL_REPLACE takes alpha from the fragment, which we set to zero
+ // with glColor4f(0,0,0,0).
+#if USE_FRAG_PROG
+ defaultAlpha = 255;
+#else
+ defaultAlpha = 0;
+#endif
+ }
+ else {
+ assert(haveCombine);
+#if GL_ARB_texture_env_combine
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+#endif
+ // For this GL_COMBINE mode, when sampling a texture that does
+ // not have an alpha channel, alpha is effectively 1.0.
+ defaultAlpha = 255;
+ }
+
+ for (unsigned formatIndex = 0; formatIndex < NUM_FORMATS; formatIndex++) {
+ for (unsigned typeIndex = 0; typeIndex < NUM_TYPES; typeIndex++) {
+
+ if (CompatibleFormatAndType(Formats[formatIndex].Token,
+ Types[typeIndex].Token)) {
+
+ for (unsigned intFormat = 0; intFormat < NUM_INT_FORMATS; intFormat++) {
+
+ if (!SupportedIntFormat(InternalFormats[intFormat].Token))
+ continue;
+
+#if DEBUG
+ env->log << "testing "
+ << testNum
+ << ":\n";
+ env->log << " Format: " << Formats[formatIndex].Name << "\n";
+ env->log << " Type: " << Types[typeIndex].Name << "\n";
+ env->log << " IntFormat: " << InternalFormats[intFormat].Name << "\n";
+
+#endif
+ bool ok = TestCombination(Formats[formatIndex].Token,
+ Types[typeIndex].Token,
+ InternalFormats[intFormat].Token);
+
+ if (!ok) {
+ // error was reported to log, add format info here:
+ env->log << " Format: " << Formats[formatIndex].Name << "\n";
+ env->log << " Type: " << Types[typeIndex].Name << "\n";
+ env->log << " Internal Format: " << InternalFormats[intFormat].Name << "\n";
+ env->log << " EnvMode: " << EnvModes[envMode] << "\n";
+ r.numFailed++;
+ }
+ else {
+ r.numPassed++;
+ }
+ testNum++;
+ }
+ }
+ }
+ }
+ }
+
+ r.pass = (r.numFailed == 0);
+}
+
+
+// The test object itself:
+PixelFormatsTest pixelFormatsTest("pixelFormats", "window, rgb",
+ "",
+ "Test that all the various pixel formats/types (like\n"
+ "GL_BGRA/GL_UNSIGNED_SHORT_4_4_4_4_REV) operate correctly.\n"
+ "Test both glTexImage and glDrawPixels.\n"
+ "For textures, also test all the various internal texture formats.\n"
+ "Thousands of combinations are possible!\n"
+ );
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tpixelformats.h b/tests/glean/tpixelformats.h
new file mode 100644
index 00000000..faffc327
--- /dev/null
+++ b/tests/glean/tpixelformats.h
@@ -0,0 +1,85 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// Brian Paul September 2006
+
+#ifndef __tpixelformats_h__
+#define __tpixelformats_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+#define windowSize 100
+
+
+class PixelFormatsTest: public MultiTest
+{
+public:
+ PixelFormatsTest(const char* testName, const char* filter,
+ const char *extensions, const char* description)
+ : MultiTest(testName, filter, extensions, description)
+ {
+ }
+
+ virtual void runOne(MultiTestResult &r, Window &w);
+
+private:
+ int alphaBits;
+ int defaultAlpha; // depends on texture env mode
+ // extensions
+ bool haveHalfFloat;
+ bool haveABGR;
+ bool haveSRGB;
+ bool haveCombine;
+
+ bool CheckError(const char *where) const;
+
+ bool CompatibleFormatAndType(GLenum format, GLenum datatype) const;
+
+ bool SupportedIntFormat(GLint intFormat) const;
+
+ bool DrawImage(int width, int height,
+ GLenum format, GLenum type, GLint intFormat,
+ const GLubyte *image) const;
+
+ void ComputeExpected(GLenum srcFormat, int testChan,
+ GLint intFormat, GLubyte exp[4]) const;
+
+ bool CheckRendering(int width, int height, int color,
+ GLenum format, GLint intFormat) const;
+
+ bool TestCombination(GLenum format, GLenum type, GLint intFormat);
+
+ void setup(void);
+};
+
+} // namespace GLEAN
+
+#endif // __tpixelformats_h__
+
diff --git a/tests/glean/tpointatten.cpp b/tests/glean/tpointatten.cpp
new file mode 100644
index 00000000..87919780
--- /dev/null
+++ b/tests/glean/tpointatten.cpp
@@ -0,0 +1,259 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tpointatten.h: Test GL_ARB_point_parameters extension.
+// Brian Paul 6 October 2005
+
+
+#include "tpointatten.h"
+#include <cassert>
+#include <cmath>
+
+
+namespace GLEAN {
+
+// Max tested point size
+#define MAX_SIZE 25.0
+
+
+/* Clamp X to [MIN,MAX] */
+#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
+
+
+static PFNGLPOINTPARAMETERFVARBPROC PointParameterfvARB = NULL;
+static PFNGLPOINTPARAMETERFARBPROC PointParameterfARB = NULL;
+
+
+void
+PointAttenuationTest::setup(void)
+{
+ PointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)
+ GLUtils::getProcAddress("glPointParameterfvARB");
+ assert(PointParameterfvARB);
+ PointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC)
+ GLUtils::getProcAddress("glPointParameterfARB");
+ assert(PointParameterfARB);
+
+ glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, aliasedLimits);
+ glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, smoothLimits);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, -10.0, 10.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+void
+PointAttenuationTest::reportFailure(GLfloat initSize,
+ const GLfloat attenuation[3],
+ GLfloat min, GLfloat max,
+ GLfloat eyeZ, GLboolean smooth,
+ GLfloat expected, GLfloat actual) const
+{
+ env->log << "\tFAILURE:\n";
+ env->log << "\tExpected size: " << expected << " Actual size: " << actual << "\n";
+ env->log << "\tSize: " << initSize << "\n";
+ env->log << "\tMin: " << min << " Max: " << max << "\n";
+ env->log << "\tAttenuation: " << attenuation[0] << " " << attenuation[1] << " " << attenuation[2] << "\n";
+ env->log << "\tEye Z: " << eyeZ << "\n";
+ if (smooth)
+ env->log << "\tSmooth/antialiased\n";
+ else
+ env->log << "\tAliased\n";
+}
+
+
+void
+PointAttenuationTest::reportSuccess(int count, GLboolean smooth) const
+{
+ env->log << "PASS: " << count;
+ if (smooth)
+ env->log << " aliased combinations tested.\n";
+ else
+ env->log << " antialiased combinations tested.\n";
+}
+
+
+// Compute the expected point size given various point state
+GLfloat
+PointAttenuationTest::expectedSize(GLfloat initSize,
+ const GLfloat attenuation[3],
+ GLfloat min, GLfloat max,
+ GLfloat eyeZ, GLboolean smooth) const
+{
+ const GLfloat dist = fabs(eyeZ);
+ const GLfloat atten = sqrt(1.0 / (attenuation[0] +
+ attenuation[1] * dist +
+ attenuation[2] * dist * dist));
+
+ float size = initSize * atten;
+
+ size = CLAMP(size, min, max);
+
+ if (smooth)
+ size = CLAMP(size, smoothLimits[0], smoothLimits[1]);
+ else
+ size = CLAMP(size, aliasedLimits[0], aliasedLimits[1]);
+
+ return size;
+}
+
+
+// measure size of rendered point
+GLfloat
+PointAttenuationTest::measureSize() const
+{
+ int x = 0;
+ int y = windowSize / 2;
+ int w = windowSize;
+ int h = 1;
+ GLfloat image[windowSize * 3];
+ // Read row of pixels and add up colors, which should be white
+ // or shades of gray if smoothing is enabled.
+ glReadPixels(x, y, w, h, GL_RGB, GL_FLOAT, image);
+ float sum = 0.0;
+ for (int i = 0; i < w; i++) {
+ sum += (image[i*3+0] + image[i*3+1] + image[i*3+2]) / 3.0;
+ }
+ return sum;
+}
+
+
+bool
+PointAttenuationTest::testPointRendering(GLboolean smooth)
+{
+ // epsilon is the allowed size difference in pixels between the
+ // expected and actual rendering. We should use something tighter
+ // than 1.2 but 1.2 allows NVIDIA's driver to pass.
+ const GLfloat epsilon = 1.2;
+ GLfloat atten[3];
+ int count = 0;
+
+ // Enable front buffer if you want to see the rendering
+ //glDrawBuffer(GL_FRONT);
+ //glReadBuffer(GL_FRONT);
+
+ if (smooth) {
+ glEnable(GL_POINT_SMOOTH);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glDisable(GL_POINT_SMOOTH);
+ glDisable(GL_BLEND);
+ }
+
+ for (int a = 0; a < 3; a++) {
+ atten[0] = pow(10.0, -a);
+ for (int b = -2; b < 3; b++) {
+ atten[1] = (b == -1) ? 0.0 : pow(10.0, -b);
+ for (int c = -2; c < 3; c++) {
+ atten[2] = (c == -1) ? 0.0 : pow(10.0, -c);
+ PointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, atten);
+ for (float min = 1.0; min < MAX_SIZE; min += 5) {
+ PointParameterfARB(GL_POINT_SIZE_MIN_ARB, min);
+ for (float max = min; max < MAX_SIZE; max += 5) {
+ PointParameterfARB(GL_POINT_SIZE_MAX_ARB, max);
+ for (float size = 1.0; size < MAX_SIZE; size += 4) {
+ glPointSize(size);
+ for (float z = -8.0; z <= 8.0; z += 1.0) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBegin(GL_POINTS);
+ glVertex3f(0, 0, z);
+ glEnd();
+ count++;
+ float expected
+ = expectedSize(size, atten, min, max,
+ z, smooth);
+ float actual = measureSize();
+ if (fabs(expected - actual) > epsilon) {
+ reportFailure(size, atten, min, max,
+ z, smooth,
+ expected, actual);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ reportSuccess(count, smooth);
+ return true;
+}
+
+void
+PointAttenuationTest::runOne(BasicResult &r, Window &w)
+{
+ (void) w; // silence warning
+ r.pass = true;
+ errorCode = 0;
+ errorPos = NULL;
+
+ setup();
+
+ if (r.pass)
+ r.pass = testPointRendering(GL_FALSE);
+ if (r.pass)
+ r.pass = testPointRendering(GL_TRUE);
+}
+
+
+void
+PointAttenuationTest::logOne(BasicResult &r)
+{
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+}
+
+
+// constructor
+PointAttenuationTest::PointAttenuationTest(const char *testName,
+ const char *filter,
+ const char *extensions,
+ const char *description)
+ : BasicTest(testName, filter, extensions, description)
+{
+ fWidth = windowSize;
+ fHeight = windowSize;
+}
+
+
+
+// The test object itself:
+PointAttenuationTest pointAttenuationTest("pointAtten", "window, rgb",
+ "GL_ARB_point_parameters",
+ "Test point size attenuation with the GL_ARB_point_parameters extension.\n");
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tpointatten.h b/tests/glean/tpointatten.h
new file mode 100644
index 00000000..4ee032d5
--- /dev/null
+++ b/tests/glean/tpointatten.h
@@ -0,0 +1,78 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tpointatten.h: Test GL_ARB_point_parameters extension.
+// Brian Paul 6 October 2005
+
+#ifndef __tpointatten_h__
+#define __tpointatten_h__
+
+#include "tbasic.h"
+
+namespace GLEAN {
+
+#define drawingSize 101 // yes, odd
+#define windowSize (drawingSize + 2)
+
+
+class PointAttenuationTest: public BasicTest
+{
+public:
+ PointAttenuationTest(const char *testName,
+ const char *filter,
+ const char *extensions,
+ const char *description);
+
+ virtual void runOne(BasicResult& r, Window& w);
+ virtual void logOne(BasicResult& r);
+
+private:
+ GLenum errorCode;
+ const char *errorPos;
+ GLfloat aliasedLimits[2]; // min/max
+ GLfloat smoothLimits[2]; // min/max
+
+ void setup(void);
+ bool testPointRendering(GLboolean smooth);
+ void reportFailure(GLfloat initSize,
+ const GLfloat attenuation[3],
+ GLfloat min, GLfloat max,
+ GLfloat eyeZ, GLboolean smooth,
+ GLfloat expected, GLfloat actual) const;
+ void reportSuccess(int count, GLboolean smooth) const;
+ GLfloat expectedSize(GLfloat initSize,
+ const GLfloat attenuation[3],
+ GLfloat min, GLfloat max,
+ GLfloat eyeZ, GLboolean smooth) const;
+ GLfloat measureSize() const;
+};
+
+} // namespace GLEAN
+
+#endif // __tpointatten_h__
+
diff --git a/tests/glean/treadpix.cpp b/tests/glean/treadpix.cpp
new file mode 100644
index 00000000..bc1b3d07
--- /dev/null
+++ b/tests/glean/treadpix.cpp
@@ -0,0 +1,970 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2001 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// treadpix.cpp: implementation of ReadPixels tests
+
+#include <cmath>
+#include <iomanip>
+#include "misc.h"
+#include "rand.h"
+#include "treadpix.h"
+
+
+namespace GLEAN {
+
+void
+ReadPixSanityTest::checkRGBA(ReadPixSanityResult& r, Window& w) {
+ DrawingSurfaceConfig& config = *r.config;
+ RandomBitsDouble rRand(config.r, 1066);
+ RandomBitsDouble gRand(config.g, 1492);
+ RandomBitsDouble bRand(config.b, 1776);
+ RandomBitsDouble aRand((config.a? config.a: 1), 1789);
+ int thresh = 1;
+
+ r.passRGBA = true;
+ r.errRGBA = 0.0;
+ for (int i = 0; i < 100 && r.passRGBA; ++i) {
+ // Generate a random color and use it to clear the color buffer:
+ float expected[4];
+ expected[0] = rRand.next();
+ expected[1] = gRand.next();
+ expected[2] = bRand.next();
+ expected[3] = aRand.next();
+ glClearColor(expected[0],expected[1],expected[2],expected[3]);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // If the color buffer doesn't have an alpha channel, then
+ // the spec requires the readback value to be 1.0:
+ if (!config.a)
+ expected[3] = 1.0;
+
+ // Read the buffer:
+ GLfloat buf[READPIX_SANITY_WIN_SIZE][READPIX_SANITY_WIN_SIZE][4];
+ glReadPixels(0, 0, READPIX_SANITY_WIN_SIZE,
+ READPIX_SANITY_WIN_SIZE, GL_RGBA, GL_FLOAT, buf);
+
+ // Now compute the error for each pixel, and record the
+ // worst one we find:
+ for (int y = 0; y < READPIX_SANITY_WIN_SIZE; ++y)
+ for (int x = 0; x < READPIX_SANITY_WIN_SIZE; ++x) {
+ GLfloat dr = abs(buf[y][x][0] - expected[0]);
+ GLfloat dg = abs(buf[y][x][1] - expected[1]);
+ GLfloat db = abs(buf[y][x][2] - expected[2]);
+ GLfloat da = abs(buf[y][x][3] - expected[3]);
+ double err =
+ max(ErrorBits(dr, config.r),
+ max(ErrorBits(dg, config.g),
+ max(ErrorBits(db, config.b),
+ ErrorBits(da,
+ config.a? config.a: thresh+1))));
+ // The "thresh+1" fudge above is
+ // needed to force the error to
+ // be greater than the threshold
+ // in the case where there is no
+ // alpha channel. Without it the
+ // error would be just equal to
+ // the threshold, and the test
+ // would spuriously pass.
+ if (err > r.errRGBA) {
+ r.xRGBA = x;
+ r.yRGBA = y;
+ r.errRGBA = err;
+ for (int j = 0; j < 4; ++j) {
+ r.expectedRGBA[j] = expected[j];
+ r.actualRGBA[j] = buf[y][x][j];
+ }
+ }
+ }
+
+ if (r.errRGBA > thresh)
+ r.passRGBA = false;
+ w.swap();
+ }
+} // ReadPixSanityTest::checkRGBA
+
+void
+ReadPixSanityTest::checkDepth(ReadPixSanityResult& r, Window& w) {
+ DrawingSurfaceConfig& config = *r.config;
+ RandomDouble dRand(35798);
+ int thresh = 1;
+
+ r.passDepth = true;
+ r.errDepth = 0.0;
+ for (int i = 0; i < 100 && r.passDepth; ++i) {
+ // Generate a random depth and use it to clear the depth buffer:
+ GLdouble expected = dRand.next();
+ glClearDepth(expected);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // Because glReadPixels won't return data of type GLdouble,
+ // there's no straightforward portable way to deal with
+ // integer depth buffers that are deeper than 32 bits or
+ // floating-point depth buffers that have higher precision
+ // than a GLfloat. Since this is just a sanity check, we'll
+ // use integer readback and settle for 32 bits at best.
+ GLuint buf[READPIX_SANITY_WIN_SIZE][READPIX_SANITY_WIN_SIZE];
+ glReadPixels(0, 0, READPIX_SANITY_WIN_SIZE,
+ READPIX_SANITY_WIN_SIZE, GL_DEPTH_COMPONENT,
+ GL_UNSIGNED_INT, buf);
+
+ // Now compute the error for each pixel, and record the
+ // worst one we find:
+ for (int y = 0; y < READPIX_SANITY_WIN_SIZE; ++y)
+ for (int x = 0; x < READPIX_SANITY_WIN_SIZE; ++x) {
+ GLfloat dd = abs(buf[y][x]/4294967295.0
+ - expected);
+ double err = ErrorBits(dd, config.z);
+ if (err > r.errDepth) {
+ r.xDepth = x;
+ r.yDepth = y;
+ r.errDepth = err;
+ r.expectedDepth = expected;
+ r.actualDepth = buf[y][x]/4294967295.0;
+ }
+ }
+
+ if (r.errDepth > thresh)
+ r.passDepth = false;
+ w.swap();
+ }
+} // ReadPixSanityTest::checkDepth
+
+void
+ReadPixSanityTest::checkStencil(ReadPixSanityResult& r, Window& w) {
+ DrawingSurfaceConfig& config = *r.config;
+ RandomBits sRand(config.s, 10101);
+
+ r.passStencil = true;
+ for (int i = 0; i < 100 && r.passStencil; ++i) {
+ GLuint expected = sRand.next();
+ glClearStencil(expected);
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ GLuint buf[READPIX_SANITY_WIN_SIZE][READPIX_SANITY_WIN_SIZE];
+ glReadPixels(0, 0, READPIX_SANITY_WIN_SIZE,
+ READPIX_SANITY_WIN_SIZE, GL_STENCIL_INDEX,
+ GL_UNSIGNED_INT, buf);
+
+ for (int y = 0; y < READPIX_SANITY_WIN_SIZE && r.passStencil;
+ ++y)
+ for (int x = 0; x < READPIX_SANITY_WIN_SIZE; ++x)
+ if (buf[y][x] != expected) {
+ r.passStencil = false;
+ r.xStencil = x;
+ r.yStencil = y;
+ r.expectedStencil = expected;
+ r.actualStencil = buf[y][x];
+ break;
+ }
+
+ w.swap();
+ }
+} // ReadPixSanityTest::checkStencil
+
+void
+ReadPixSanityTest::checkIndex(ReadPixSanityResult& r, Window& w) {
+ DrawingSurfaceConfig& config = *r.config;
+ RandomBits iRand(config.bufSize, 2);
+
+ r.passIndex = true;
+ for (int i = 0; i < 100 && r.passIndex; ++i) {
+ GLuint expected = iRand.next();
+ glClearIndex(expected);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ GLuint buf[READPIX_SANITY_WIN_SIZE][READPIX_SANITY_WIN_SIZE];
+ glReadPixels(0, 0, READPIX_SANITY_WIN_SIZE,
+ READPIX_SANITY_WIN_SIZE, GL_COLOR_INDEX,
+ GL_UNSIGNED_INT, buf);
+
+ for (int y = 0; y < READPIX_SANITY_WIN_SIZE && r.passIndex; ++y)
+ for (int x = 0; x < READPIX_SANITY_WIN_SIZE; ++x)
+ if (buf[y][x] != expected) {
+ r.passIndex = false;
+ r.xIndex = x;
+ r.yIndex = y;
+ r.expectedIndex = expected;
+ r.actualIndex = buf[y][x];
+ break;
+ }
+
+ w.swap();
+ }
+} // ReadPixSanityTest::checkIndex
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ReadPixSanityTest::runOne(ReadPixSanityResult& r, GLEAN::Window& w) {
+
+ // Many (if not most) other tests need to read the contents of
+ // the framebuffer to determine if the correct image has been
+ // drawn. Obviously this is a waste of time if the basic
+ // functionality of glReadPixels isn't working.
+ //
+ // This test does a "sanity" check of glReadPixels. Using as
+ // little of the GL as practicable, it writes a random value
+ // in the framebuffer, reads it, and compares the value read
+ // with the value written.
+
+ glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
+ glPixelTransferi(GL_MAP_STENCIL, GL_FALSE);
+ glPixelTransferi(GL_INDEX_SHIFT, 0);
+ glPixelTransferi(GL_INDEX_OFFSET, 0);
+ glPixelTransferf(GL_RED_SCALE, 1.0);
+ glPixelTransferf(GL_GREEN_SCALE, 1.0);
+ glPixelTransferf(GL_BLUE_SCALE, 1.0);
+ glPixelTransferf(GL_ALPHA_SCALE, 1.0);
+ glPixelTransferf(GL_DEPTH_SCALE, 1.0);
+ glPixelTransferf(GL_RED_BIAS, 0.0);
+ glPixelTransferf(GL_GREEN_BIAS, 0.0);
+ glPixelTransferf(GL_BLUE_BIAS, 0.0);
+ glPixelTransferf(GL_ALPHA_BIAS, 0.0);
+ glPixelTransferf(GL_DEPTH_BIAS, 0.0);
+
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_DITHER);
+
+ glIndexMask(~0);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+ glStencilMask(~0);
+
+ if (r.config->canRGBA)
+ checkRGBA(r, w);
+ if (r.config->z)
+ checkDepth(r, w);
+ if (r.config->s)
+ checkStencil(r, w);
+
+ r.pass = r.passRGBA & r.passDepth & r.passStencil & r.passIndex;
+} // ReadPixSanityTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ReadPixSanityTest::compareOne(ReadPixSanityResult& oldR, ReadPixSanityResult& newR) {
+ comparePassFail(oldR, newR);
+ summarize("RGBA: ", oldR.passRGBA, newR.passRGBA);
+ summarize("Depth: ", oldR.passDepth, newR.passDepth);
+ summarize("Stencil: ", oldR.passStencil, newR.passStencil);
+ summarize("Index: ", oldR.passIndex, newR.passIndex);
+ if (env->options.verbosity) {
+ if (!oldR.passRGBA && !newR.passRGBA) {
+ if (oldR.xRGBA != newR.xRGBA
+ || oldR.yRGBA != newR.yRGBA)
+ env->log << "\tRGBA: "
+ << env->options.db1Name
+ << " failed at ("
+ << oldR.xRGBA
+ << ", "
+ << oldR.yRGBA
+ << "); "
+ << env->options.db2Name
+ << " failed at ("
+ << newR.xRGBA
+ << ", "
+ << newR.yRGBA
+ << ").\n"
+ ;
+ if (oldR.errRGBA != newR.errRGBA)
+ env->log << "\tRGBA: "
+ << env->options.db1Name
+ << " had "
+ << oldR.errRGBA
+ << " bits in error; "
+ << env->options.db2Name
+ << " had "
+ << newR.errRGBA
+ << " bits in error.\n"
+ ;
+ }
+ if (!oldR.passDepth && !newR.passDepth) {
+ if (oldR.xDepth != newR.xDepth
+ || oldR.yDepth != newR.yDepth)
+ env->log << "\tDepth: "
+ << env->options.db1Name
+ << " failed at ("
+ << oldR.xDepth
+ << ", "
+ << oldR.yDepth
+ << "); "
+ << env->options.db2Name
+ << " failed at ("
+ << newR.xDepth
+ << ", "
+ << newR.yDepth
+ << ").\n"
+ ;
+ if (oldR.errDepth != newR.errDepth)
+ env->log << "\tDepth: "
+ << env->options.db1Name
+ << " had "
+ << oldR.errDepth
+ << " bits in error; "
+ << env->options.db2Name
+ << " had "
+ << newR.errDepth
+ << " bits in error.\n"
+ ;
+ }
+ if (!oldR.passStencil && !newR.passStencil) {
+ if (oldR.xStencil != newR.xStencil
+ || oldR.yStencil != newR.yStencil)
+ env->log << "\tStencil: "
+ << env->options.db1Name
+ << " failed at ("
+ << oldR.xStencil
+ << ", "
+ << oldR.yStencil
+ << "); "
+ << env->options.db2Name
+ << " failed at ("
+ << newR.xStencil
+ << ", "
+ << newR.yStencil
+ << ").\n"
+ ;
+ }
+ if (!oldR.passIndex && !newR.passIndex) {
+ if (oldR.xIndex != newR.xIndex
+ || oldR.yIndex != newR.yIndex)
+ env->log << "\tIndex: "
+ << env->options.db1Name
+ << " failed at ("
+ << oldR.xIndex
+ << ", "
+ << oldR.yIndex
+ << "); "
+ << env->options.db2Name
+ << " failed at ("
+ << newR.xIndex
+ << ", "
+ << newR.yIndex
+ << ").\n"
+ ;
+ }
+ }
+} // ReadPixSanityTest::compareOne
+
+void
+ReadPixSanityTest::summarize(char* label, bool oldPass, bool newPass) {
+ if (oldPass == newPass) {
+ if (env->options.verbosity)
+ env->log << "\t"
+ << label
+ << "both "
+ << (oldPass? "passed": "failed")
+ << ".\n";
+ } else {
+ env->log << "\t"
+ << label
+ << env->options.db1Name
+ << " "
+ << (oldPass? "passed": "failed")
+ << "; "
+ << env->options.db2Name
+ << " "
+ << (newPass? "passed": "failed")
+ << ".\n"
+ ;
+ }
+} // ReadPixSanityTest::summarize
+
+void
+ReadPixSanityTest::logOne(ReadPixSanityResult& r) {
+ logPassFail(r);
+ logConcise(r);
+
+ if (!r.passRGBA) {
+ env->log << "\tRGB(A) worst-case error was "
+ << r.errRGBA << " bits at ("
+ << r.xRGBA << ", " << r.yRGBA << ")\n";
+ env->log << "\t\texpected ("
+ << r.expectedRGBA[0] << ", "
+ << r.expectedRGBA[1] << ", "
+ << r.expectedRGBA[2] << ", "
+ << r.expectedRGBA[3] << ")\n\t\tgot ("
+ << r.actualRGBA[0] << ", "
+ << r.actualRGBA[1] << ", "
+ << r.actualRGBA[2] << ", "
+ << r.actualRGBA[3] << ")\n"
+ ;
+ }
+ if (!r.passDepth) {
+ env->log << "\tDepth worst-case error was "
+ << r.errDepth << " bits at ("
+ << r.xDepth << ", " << r.yDepth << ")\n";
+ env->log << "\t\texpected "
+ << r.expectedDepth
+ << "; got "
+ << r.actualDepth
+ << ".\n"
+ ;
+ }
+ if (!r.passStencil) {
+ env->log << "\tStencil expected "
+ << r.expectedStencil
+ << "; got "
+ << r.actualStencil
+ << ".\n"
+ ;
+ }
+ if (!r.passIndex) {
+ env->log << "\tIndex expected "
+ << r.expectedIndex
+ << "; got "
+ << r.actualIndex
+ << ".\n"
+ ;
+ }
+ if (env->options.verbosity) {
+ if (r.config->canRGBA)
+ env->log << "\tRGBA largest readback error was "
+ << r.errRGBA
+ << " bits\n";
+ if (r.config->z)
+ env->log << "\tDepth largest readback error was "
+ << r.errDepth
+ << " bits\n";
+ }
+} // ReadPixSanityTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+ReadPixSanityTest
+readPixSanityTest("readPixSanity", "1",
+
+ "This test performs a sanity check of glReadPixels, using as\n"
+ "few other portions of the GL as possible. If this test fails,\n"
+ "it may be pointless to run other tests, since so many of them\n"
+ "depend on reading the contents of the framebuffer to determine\n"
+ "if they pass.\n"
+ "\n"
+ "The test works by using glClear to fill the framebuffer with a\n"
+ "randomly-chosen value, reading the contents of the\n"
+ "framebuffer, and comparing the actual contents with the\n"
+ "expected contents. RGB, RGBA, color index, stencil, and depth\n"
+ "buffers (whichever are applicable to the current rendering\n"
+ "context) are checked. The test passes if the actual contents\n"
+ "are within 1 LSB of the expected contents.\n"
+
+ );
+}; // namespace GLEAN
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// ExactRGBATest
+// Verifies that unsigned RGBA values written to a framebuffer with
+// sufficient depth are not altered by the OpenGL implementation.
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+template<class T>
+void
+check(GLEAN::ExactRGBAResult::Flavor& r, GLEAN::DrawingSurfaceConfig& config,
+ GLenum type, int roundingMode) {
+ unsigned size = EXACT_RGBA_WIN_SIZE - 2;
+ unsigned nPixels = size * size;
+ unsigned nComponents = 4 * nPixels;
+ T* expected = new T[nComponents];
+ T* actual = new T[nComponents];
+ GLEAN::RandomBits rand(32, 1929);
+ unsigned x;
+ unsigned y;
+ T* p;
+ T* q;
+
+ // Draw random colors into the window, recording the raw
+ // color data in the array "expected":
+ p = expected;
+ for (y = 0; y < size; ++y)
+ for (x = 0; x < size; ++x) {
+ p[0] = rand.next(); // r
+ p[1] = rand.next(); // g
+ p[2] = rand.next(); // b
+ p[3] = rand.next(); // a
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ glColor4ubv(reinterpret_cast<GLubyte*>
+ (p));
+ break;
+ case GL_UNSIGNED_SHORT:
+ glColor4usv(reinterpret_cast<GLushort*>
+ (p));
+ break;
+ case GL_UNSIGNED_INT:
+ glColor4uiv(reinterpret_cast<GLuint*>
+ (p));
+ break;
+ }
+ glBegin(GL_QUADS);
+ glVertex2i(x + 1, y + 1);
+ glVertex2i(x + 2, y + 1);
+ glVertex2i(x + 2, y + 2);
+ glVertex2i(x + 1, y + 2);
+ glEnd();
+ p += 4;
+ }
+
+ // Read the relevant contents of the window into the array
+ // "actual":
+ glReadPixels(1, 1, size, size, GL_RGBA, type, actual);
+
+ // Find masks that select only the high-order bits that should
+ // be common to both the host representation and the framebuffer
+ // representation:
+ int hostBits;
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ hostBits = 8;
+ break;
+ case GL_UNSIGNED_SHORT:
+ hostBits = 16;
+ break;
+ case GL_UNSIGNED_INT:
+ hostBits = 32;
+ break;
+ }
+ T Mask[4];
+
+ Mask[0] = static_cast<T>(-1) << (hostBits - min(hostBits, config.r));
+ Mask[1] = static_cast<T>(-1) << (hostBits - min(hostBits, config.g));
+ Mask[2] = static_cast<T>(-1) << (hostBits - min(hostBits, config.b));
+ Mask[3] = static_cast<T>(-1) << (hostBits - min(hostBits, config.a));
+
+ // Patch up arithmetic for RGB drawing surfaces. All other nasty cases
+ // are eliminated by the drawing surface filter, which requires
+ // nonzero R, G, and B.
+ if (config.a == 0)
+ Mask[3] = 0;
+
+ // Compare masked actual and expected values, and record the
+ // worst-case error location and magnitude.
+ r.err = 0;
+ p = expected;
+ q = actual;
+ for (y = 0; y < size; ++y)
+ for (x = 0; x < size; ++x) {
+ T e[4];
+ T a[4];
+ if (roundingMode == 1) {
+ e[0] = p[0];
+ e[1] = p[1];
+ e[2] = p[2];
+ e[3] = p[3];
+ a[0] = q[0];
+ a[1] = q[1];
+ a[2] = q[2];
+ a[3] = q[3];
+ if (config.a == 0) {
+ e[3] = a[3] = 0;
+ }
+ } else {
+ e[0] = p[0] & Mask[0];
+ e[1] = p[1] & Mask[1];
+ e[2] = p[2] & Mask[2];
+ e[3] = p[3] & Mask[3];
+ a[0] = q[0] & Mask[0];
+ a[1] = q[1] & Mask[1];
+ a[2] = q[2] & Mask[2];
+ a[3] = q[3] & Mask[3];
+ }
+ for (unsigned i = 0; i < 4; ++i) {
+ GLuint err = max(e[i], a[i]) - min(e[i], a[i]);
+ if (roundingMode == 1) {
+ if (err < ~Mask[i] / 2)
+ err = 0;
+ }
+ if (err > r.err) {
+ r.x = x;
+ r.y = y;
+ r.err = err;
+ for (unsigned j = 0; j < 4; ++j) {
+ r.expected[j] = e[j];
+ r.actual[j] = a[j];
+ r.written[j] = p[j];
+ r.read[j] = q[j];
+ }
+ }
+ }
+ p += 4;
+ q += 4;
+ }
+
+ // We only pass if the maximum error was zero.
+ r.pass = (r.err == 0);
+
+ delete[] expected;
+ delete[] actual;
+}
+
+};
+
+
+namespace GLEAN {
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ExactRGBATest::runOne(ExactRGBAResult& r, GLEAN::Window& w) {
+
+ // Many other tests depend on the ability of the OpenGL
+ // implementation to store fixed-point RGBA values in the
+ // framebuffer, and to read back exactly the value that
+ // was stored. The OpenGL spec guarantees that this will work
+ // under certain conditions, which are spelled out in section
+ // 2.13.9 in the 1.2.1 version of the spec:
+ //
+ // Suppose that lighting is disabled, the color associated
+ // with a vertex has not been clipped, and one of
+ // [gl]Colorub, [gl]Colorus, or [gl]Colorui was used to
+ // specify that color. When these conditions are
+ // satisfied, an RGBA component must convert to a value
+ // that matches the component as specified in the Color
+ // command: if m [the number of bits in the framebuffer
+ // color channel] is less than the number of bits b with
+ // which the component was specified, then the converted
+ // value must equal the most significant m bits of the
+ // specified value; otherwise, the most significant b bits
+ // of the converted value must equal the specified value.
+ //
+ // This test attempts to verify that behavior.
+
+
+ // Don't bother running if the ReadPixels sanity test for this
+ // display surface configuration failed:
+ if (!env->options.ignorePrereqs) {
+ vector<ReadPixSanityResult*>::const_iterator rpsRes;
+ for (rpsRes = readPixSanityTest.results.begin();
+ rpsRes != readPixSanityTest.results.end();
+ ++rpsRes)
+ if ((*rpsRes)->config == r.config)
+ break;
+ if (rpsRes == readPixSanityTest.results.end() || !(*rpsRes)->pass) {
+ r.skipped = true;
+ r.pass = false;
+ return;
+ }
+ }
+
+ // Much of this state should already be set, if the defaults are
+ // implemented correctly. We repeat the setting here in order
+ // to insure reasonable results when there are bugs.
+
+ GLUtils::useScreenCoords(EXACT_RGBA_WIN_SIZE, EXACT_RGBA_WIN_SIZE);
+
+ glDisable(GL_LIGHTING);
+
+ glFrontFace(GL_CCW);
+
+ glDisable(GL_COLOR_MATERIAL);
+
+ glDisable(GL_TEXTURE_1D);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_3D);
+
+ glDisable(GL_CLIP_PLANE0);
+ glDisable(GL_CLIP_PLANE1);
+ glDisable(GL_CLIP_PLANE2);
+ glDisable(GL_CLIP_PLANE3);
+ glDisable(GL_CLIP_PLANE4);
+ glDisable(GL_CLIP_PLANE5);
+
+ glDisable(GL_FOG);
+
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
+ glPixelTransferi(GL_MAP_STENCIL, GL_FALSE);
+ glPixelTransferi(GL_INDEX_SHIFT, 0);
+ glPixelTransferi(GL_INDEX_OFFSET, 0);
+ glPixelTransferf(GL_RED_SCALE, 1.0);
+ glPixelTransferf(GL_GREEN_SCALE, 1.0);
+ glPixelTransferf(GL_BLUE_SCALE, 1.0);
+ glPixelTransferf(GL_ALPHA_SCALE, 1.0);
+ glPixelTransferf(GL_DEPTH_SCALE, 1.0);
+ glPixelTransferf(GL_RED_BIAS, 0.0);
+ glPixelTransferf(GL_GREEN_BIAS, 0.0);
+ glPixelTransferf(GL_BLUE_BIAS, 0.0);
+ glPixelTransferf(GL_ALPHA_BIAS, 0.0);
+ glPixelTransferf(GL_DEPTH_BIAS, 0.0);
+
+ // Hack: Make hardware driver tests feasible
+ // The OpenGL spec apparently requires insane behaviour on the part
+ // of the implementation: On the one hand, implementations should round
+ // color values to the nearest representable color value, while on the
+ // other hand it has to truncate. Silly...
+ int roundingMode = 0;
+ const char* s;
+
+ s = getenv("GLEAN_EXACTRGBA_ROUNDING");
+ if (s) {
+ roundingMode = atoi(s);
+ env->log << "Note: Rounding mode changed to " << roundingMode << "\n";
+ }
+
+ check<GLubyte>(r.ub, *(r.config), GL_UNSIGNED_BYTE, roundingMode);
+ w.swap();
+ check<GLushort>(r.us, *(r.config), GL_UNSIGNED_SHORT, roundingMode);
+ w.swap();
+ check<GLuint>(r.ui, *(r.config), GL_UNSIGNED_INT, roundingMode);
+ w.swap();
+ r.pass = r.ub.pass && r.us.pass && r.ui.pass;
+ r.skipped = false;
+} // ExactRGBATest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ExactRGBATest::compareOne(ExactRGBAResult& oldR, ExactRGBAResult& newR) {
+ if (oldR.skipped || newR.skipped) {
+ env->log << name
+ << ((oldR.skipped && newR.skipped)? ": SAME "
+ : ": DIFF ")
+ << newR.config->conciseDescription()
+ << '\n';
+ if (oldR.skipped)
+ env->log << "\t"
+ << env->options.db1Name
+ << " skipped\n";
+ if (newR.skipped)
+ env->log << "\t"
+ << env->options.db2Name
+ << " skipped\n";
+ env->log << "\tNo comparison is possible.\n";
+ return;
+ }
+
+ if (oldR.ub == newR.ub && oldR.us == newR.us && oldR.ui == newR.ui) {
+ if (env->options.verbosity)
+ env->log << name
+ << ": SAME "
+ << newR.config->conciseDescription()
+ << '\n'
+ << (oldR.pass
+ ? "\tBoth PASS\n"
+ : "\tBoth FAIL\n");
+ } else {
+ env->log << name
+ << ": DIFF "
+ << newR.config->conciseDescription()
+ << '\n'
+#if 1
+ << '\t'
+ << env->options.db1Name
+ << (oldR.pass? " PASS, ": " FAIL, ")
+ << env->options.db2Name
+ << (newR.pass? " PASS\n": " FAIL\n");
+#endif
+ ;
+ }
+
+ summarize("Unsigned byte: ", oldR.ub, newR.ub);
+ summarize("Unsigned short: ", oldR.us, newR.us);
+ summarize("Unsigned int: ", oldR.ui, newR.ui);
+} // ExactRGBATest::compareOne
+
+void
+ExactRGBATest::summarize(const char* label, const ExactRGBAResult::Flavor& o,
+ const ExactRGBAResult::Flavor& n) {
+ if (o == n) {
+ if (env->options.verbosity)
+ env->log << "\t"
+ << label
+ << "both "
+ << (o.pass? "passed": "failed")
+ << ".\n";
+ } else {
+ if (o.pass != n.pass)
+ env->log << "\t"
+ << label
+ << env->options.db1Name
+ << " "
+ << (o.pass? "passed": "failed")
+ << "; "
+ << env->options.db2Name
+ << " "
+ << (n.pass? "passed": "failed")
+ << ".\n"
+ ;
+ if (o.x != n.x || o.y != n.y)
+ env->log << "\t"
+ << env->options.db1Name
+ << " failed at ("
+ << o.x
+ << ", "
+ << o.y
+ << "); "
+ << env->options.db2Name
+ << " failed at ("
+ << n.x
+ << ", "
+ << n.y
+ << ")\n"
+ ;
+ if (o.err != n.err)
+ env->log << "\t"
+ << env->options.db1Name
+ << " had max error "
+ << o.err
+ << "; "
+ << env->options.db2Name
+ << " had max error "
+ << n.err
+ << "\n"
+ ;
+ if (o.expected[0] != n.expected[0]
+ || o.expected[1] != n.expected[1]
+ || o.expected[2] != n.expected[2]
+ || o.expected[3] != n.expected[3])
+ env->log << "\tExpected values differ.\n";
+ if (o.actual[0] != n.actual[0]
+ || o.actual[1] != n.actual[1]
+ || o.actual[2] != n.actual[2]
+ || o.actual[3] != n.actual[3])
+ env->log << "\tActual values differ.\n";
+ }
+} // ExactRGBATest::summarize
+
+void
+ExactRGBATest::logFlavor(const char* label, const ExactRGBAResult::Flavor& r) {
+ if (!r.pass) {
+ env->log << "\t"
+ << label
+ << " worst-case error was 0x"
+ << hex
+ << r.err << " at ("
+ << dec
+ << r.x << ", " << r.y << ")\n";
+ env->log << "\t\texpected (0x"
+ << hex
+ << r.expected[0] << ", 0x"
+ << r.expected[1] << ", 0x"
+ << r.expected[2] << ", 0x"
+ << r.expected[3] << ")\n\t\tgot (0x"
+ << r.actual[0] << ", 0x"
+ << r.actual[1] << ", 0x"
+ << r.actual[2] << ", 0x"
+ << r.actual[3] << ")\n\t\twrote (0x"
+ << r.written[0] << ", 0x"
+ << r.written[1] << ", 0x"
+ << r.written[2] << ", 0x"
+ << r.written[3] << ")\n\t\tread (0x"
+ << r.read[0] << ", 0x"
+ << r.read[1] << ", 0x"
+ << r.read[2] << ", 0x"
+ << r.read[3] << ")\n"
+ << dec
+ ;
+ }
+} // ExactRGBATest::logFlavor
+
+void
+ExactRGBATest::logOne(ExactRGBAResult& r) {
+ if (r.skipped) {
+ env->log << name << ": NOTE ";
+ logConcise(r);
+ env->log << "\tTest skipped; prerequisite test "
+ << readPixSanityTest.name
+ << " failed or was not run\n";
+ return;
+ }
+
+ logPassFail(r);
+ logConcise(r);
+
+ logFlavor("Unsigned byte ", r.ub);
+ logFlavor("Unsigned short", r.us);
+ logFlavor("Unsigned int ", r.ui);
+} // ExactRGBATest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+Test* exactRGBATestPrereqs[] = {&readPixSanityTest, 0};
+ExactRGBATest
+exactRGBATest("exactRGBA", "rgb", exactRGBATestPrereqs,
+
+ "The OpenGL specification requires that under certain conditions\n"
+ "(e.g. lighting disabled, no clipping, no dithering, etc.) colors\n"
+ "specified as unsigned integers are represented *exactly* in the\n"
+ "framebuffer (up to the number of bits common to both the\n"
+ "original color and the framebuffer color channel). Several glean\n"
+ "tests depend on this behavior, so this test is a prerequisite for\n"
+ "them.\n"
+ "\n"
+ "This test works by drawing many small quadrilaterals whose\n"
+ "colors are specified by glColorub, glColorus, and glColorui;\n"
+ "reading back the resulting image; and comparing the colors read\n"
+ "back to the colors written. The high-order bits shared by the\n"
+ "source representation of the colors and the framebuffer\n"
+ "representation of the colors must agree exactly for the test to\n"
+ "pass.\n"
+
+ );
+
+
+} // namespace GLEAN
diff --git a/tests/glean/treadpix.h b/tests/glean/treadpix.h
new file mode 100644
index 00000000..07106883
--- /dev/null
+++ b/tests/glean/treadpix.h
@@ -0,0 +1,322 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2001 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// treadpix.h: ReadPixels tests.
+
+#ifndef __treadpix_h__
+#define __treadpix_h__
+
+#include <iomanip>
+#include "tbase.h"
+
+namespace GLEAN {
+
+class ReadPixSanityResult: public BaseResult {
+public:
+ bool pass;
+
+ bool passRGBA;
+ int xRGBA;
+ int yRGBA;
+ float errRGBA;
+ GLfloat expectedRGBA[4];
+ GLfloat actualRGBA[4];
+
+ bool passDepth;
+ int xDepth;
+ int yDepth;
+ float errDepth;
+ GLdouble expectedDepth;
+ GLdouble actualDepth;
+
+ bool passStencil;
+ int xStencil;
+ int yStencil;
+ GLuint expectedStencil;
+ GLuint actualStencil;
+
+ bool passIndex;
+ int xIndex;
+ int yIndex;
+ GLuint expectedIndex;
+ GLuint actualIndex;
+
+ ReadPixSanityResult() {
+ pass = true;
+
+ passRGBA = true;
+ xRGBA = yRGBA = 0;
+ errRGBA = 0.0;
+ expectedRGBA[0] = expectedRGBA[1] = expectedRGBA[2]
+ = expectedRGBA[3] = 0.0;
+ actualRGBA[0] = actualRGBA[1] = actualRGBA[2]
+ = actualRGBA[3] = 0.0;
+
+ passDepth = true;
+ xDepth = yDepth = 0;
+ errDepth = 0.0;
+ expectedDepth = 0.0;
+ actualDepth = 0.0;
+
+ passStencil = true;
+ xStencil = yStencil = 0;
+ expectedStencil = 0;
+ actualStencil = 0;
+
+ passIndex = true;
+ xIndex = yIndex = 0;
+ expectedIndex = 0;
+ actualIndex = 0;
+ }
+
+ void putresults(ostream& s) const {
+ s
+ << pass << '\n'
+
+ << passRGBA << '\n'
+ << xRGBA << ' ' << yRGBA << '\n'
+ << errRGBA << '\n'
+ << expectedRGBA[0] << ' ' << expectedRGBA[1] << ' '
+ << expectedRGBA[2] << ' ' << expectedRGBA[3] << '\n'
+ << actualRGBA[0] << ' ' << actualRGBA[1] << ' '
+ << actualRGBA[2] << ' ' << actualRGBA[3] << '\n'
+
+ << passDepth << '\n'
+ << xDepth << ' ' << yDepth << '\n'
+ << errDepth << '\n'
+ << setprecision(16)
+ << expectedDepth << '\n'
+ << actualDepth << '\n'
+
+ << passStencil << '\n'
+ << xStencil << ' ' << yStencil << '\n'
+ << expectedStencil << '\n'
+ << actualStencil << '\n'
+
+ << passIndex << '\n'
+ << xIndex << ' ' << yIndex << '\n'
+ << expectedIndex << '\n'
+ << actualIndex << '\n'
+ ;
+ }
+
+ bool getresults(istream& s) {
+ s >> pass
+
+ >> passRGBA
+ >> xRGBA >> yRGBA
+ >> errRGBA
+ >> expectedRGBA[0] >> expectedRGBA[1] >> expectedRGBA[2]
+ >> expectedRGBA[3]
+ >> actualRGBA[0] >> actualRGBA[1] >> actualRGBA[2]
+ >> actualRGBA[3]
+
+ >> passDepth
+ >> xDepth >> yDepth
+ >> errDepth
+ >> expectedDepth
+ >> actualDepth
+
+ >> passStencil
+ >> xStencil >> yStencil
+ >> expectedStencil
+ >> actualStencil
+
+ >> passIndex
+ >> xIndex >> yIndex
+ >> expectedIndex
+ >> actualIndex
+ ;
+ return s.good();
+ }
+};
+
+#define READPIX_SANITY_WIN_SIZE 32
+
+class ReadPixSanityTest: public BaseTest<ReadPixSanityResult> {
+public:
+ GLEAN_CLASS_WH(ReadPixSanityTest, ReadPixSanityResult,
+ READPIX_SANITY_WIN_SIZE, READPIX_SANITY_WIN_SIZE);
+
+ void checkRGBA(ReadPixSanityResult& r, Window& w);
+ void checkDepth(ReadPixSanityResult& r, Window& w);
+ void checkStencil(ReadPixSanityResult& r, Window& w);
+ void checkIndex(ReadPixSanityResult& r, Window& w);
+ void summarize(char* label, bool oldPass, bool newPass);
+}; // class ReadPixSanityTest
+extern ReadPixSanityTest readPixSanityTest;
+
+
+
+
+class ExactRGBAResult: public BaseResult {
+public:
+ struct Flavor {
+ bool pass;
+ int x;
+ int y;
+ GLuint err;
+ GLuint expected[4];
+ GLuint actual[4];
+ GLuint written[4];
+ GLuint read[4];
+
+ bool operator== (const Flavor& f) const {
+ return pass == f.pass
+ && x == f.x
+ && y == f.y
+ && err == f.err
+ && expected[0] == f.expected[0]
+ && expected[1] == f.expected[1]
+ && expected[2] == f.expected[2]
+ && expected[3] == f.expected[3]
+ && actual[0] == f.actual[0]
+ && actual[1] == f.actual[1]
+ && actual[2] == f.actual[2]
+ && actual[3] == f.actual[3]
+ && written[0] == f.written[0]
+ && written[1] == f.written[1]
+ && written[2] == f.written[2]
+ && written[3] == f.written[3]
+ && read[0] == f.read[0]
+ && read[1] == f.read[1]
+ && read[2] == f.read[2]
+ && read[3] == f.read[3]
+ ;
+ }
+
+ Flavor() {
+ pass = true;
+ x = y = 0;
+ err = 0;
+ expected[0] = expected[1] = expected[2]
+ = expected[3] = 0;
+ actual[0] = actual[1] = actual[2] = actual[3] = 0;
+ written[0] = written[1] = written[2] = written[3] = 0;
+ read[0] = read[1] = read[2] = read[3] = 0;
+ }
+
+ void put(ostream& s) const {
+ s
+ << pass << '\n'
+ << x << ' ' << y << '\n'
+ << err << '\n'
+ << expected[0] << ' '
+ << expected[1] << ' '
+ << expected[2] << ' '
+ << expected[3] << '\n'
+ << actual[0] << ' '
+ << actual[1] << ' '
+ << actual[2] << ' '
+ << actual[3] << '\n'
+ << written[0] << ' '
+ << written[1] << ' '
+ << written[2] << ' '
+ << written[3] << '\n'
+ << read[0] << ' '
+ << read[1] << ' '
+ << read[2] << ' '
+ << read[3] << '\n'
+ ;
+ }
+ void get(istream& s) {
+ s
+ >> pass
+ >> x >> y
+ >> err
+ >> expected[0]
+ >> expected[1]
+ >> expected[2]
+ >> expected[3]
+ >> actual[0]
+ >> actual[1]
+ >> actual[2]
+ >> actual[3]
+ >> written[0]
+ >> written[1]
+ >> written[2]
+ >> written[3]
+ >> read[0]
+ >> read[1]
+ >> read[2]
+ >> read[3]
+ ;
+ }
+ };
+
+ bool skipped;
+ bool pass;
+
+ Flavor ub;
+ Flavor us;
+ Flavor ui;
+
+ ExactRGBAResult(): ub(), us(), ui() {
+ skipped = false;
+ pass = true;
+ }
+
+ void putresults(ostream& s) const {
+ s
+ << skipped << '\n'
+ << pass << '\n'
+ ;
+ ub.put(s);
+ us.put(s);
+ ui.put(s);
+ }
+
+ bool getresults(istream& s) {
+ s
+ >> skipped
+ >> pass
+ ;
+ ub.get(s);
+ us.get(s);
+ ui.get(s);
+ return s.good();
+ }
+};
+
+#define EXACT_RGBA_WIN_SIZE (512+2)
+
+class ExactRGBATest: public BaseTest<ExactRGBAResult> {
+public:
+ GLEAN_CLASS_WH(ExactRGBATest, ExactRGBAResult,
+ EXACT_RGBA_WIN_SIZE, EXACT_RGBA_WIN_SIZE);
+
+ void summarize(const char* label, const ExactRGBAResult::Flavor& o,
+ const ExactRGBAResult::Flavor& n);
+ void logFlavor(const char* label, const ExactRGBAResult::Flavor& r);
+}; // class ExactRGBATest
+extern ExactRGBATest exactRGBATest;
+
+} // namespace GLEAN
+
+#endif // __treadpix_h__
diff --git a/tests/glean/treadpixperf.cpp b/tests/glean/treadpixperf.cpp
new file mode 100644
index 00000000..058e67a0
--- /dev/null
+++ b/tests/glean/treadpixperf.cpp
@@ -0,0 +1,548 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+#include "treadpixperf.h"
+#include "rand.h"
+#include "timer.h"
+#include "image.h"
+#include <cassert>
+#include <cmath>
+
+namespace GLEAN {
+
+
+static PFNGLBINDBUFFERARBPROC BindBuffer = NULL;
+static PFNGLBUFFERDATAARBPROC BufferData = NULL;
+static PFNGLMAPBUFFERARBPROC MapBuffer = NULL;
+static PFNGLUNMAPBUFFERARBPROC UnmapBuffer = NULL;
+static PFNGLGETBUFFERSUBDATAARBPROC GetBufferSubData = NULL;
+
+const GLuint PBO1 = 42, PBO2 = 43;
+
+const double minInterval = 1.0; // seconds
+
+
+struct ImageFormat
+{
+ const char *Name;
+ GLuint Bytes; // per pixel
+ GLenum Format;
+ GLenum Type;
+};
+
+
+static ImageFormat Formats[] =
+{
+ { "GL_RGB, GL_UNSIGNED_BYTE", 3, GL_RGB, GL_UNSIGNED_BYTE },
+ { "GL_BGR, GL_UNSIGNED_BYTE", 3, GL_BGR, GL_UNSIGNED_BYTE },
+ { "GL_RGBA, GL_UNSIGNED_BYTE", 4, GL_RGBA, GL_UNSIGNED_BYTE },
+ { "GL_BGRA, GL_UNSIGNED_BYTE", 4, GL_BGRA, GL_UNSIGNED_BYTE },
+ { "GL_ABGR, GL_UNSIGNED_BYTE", 4, GL_ABGR_EXT, GL_UNSIGNED_BYTE },
+ { "GL_RGBA, GL_UNSIGNED_INT_8_8_8_8", 4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8 },
+ { "GL_BGRA, GL_UNSIGNED_INT_8_8_8_8", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8 },
+ { "GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV },
+#ifdef GL_EXT_packed_depth_stencil
+ { "GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8", 4, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT },
+#endif
+ { "GL_DEPTH_COMPONENT, GL_FLOAT", 4, GL_DEPTH_COMPONENT, GL_FLOAT },
+ { "GL_DEPTH_COMPONENT, GL_UNSIGNED_INT", 4, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
+ { "GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT", 2, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
+ { NULL, 0, 0, 0 } // end of list marker
+};
+
+
+static GLenum PBOmodes[4] =
+{
+ GL_NONE,
+#ifdef GL_ARB_pixel_buffer_object
+ GL_STREAM_READ_ARB,
+ GL_STATIC_READ_ARB,
+ GL_DYNAMIC_READ_ARB
+#endif
+};
+
+static const char *PBOmodeStrings[4] =
+{
+ "No PBO",
+ "GL_STREAM_READ PBO",
+ "GL_STATIC_READ PBO",
+ "GL_DYNAMIC_READ PBO"
+};
+
+
+static bool
+isDepthFormat(GLenum format)
+{
+ switch (format) {
+ case GL_DEPTH_COMPONENT:
+#ifdef GL_EXT_packed_depth_stencil
+ case GL_DEPTH_STENCIL_EXT:
+#endif
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+static bool
+isStencilFormat(GLenum format)
+{
+ switch (format) {
+ case GL_STENCIL_INDEX:
+#ifdef GL_EXT_packed_depth_stencil
+ case GL_DEPTH_STENCIL_EXT:
+#endif
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+static bool
+isDepthStencilFormat(GLenum format)
+{
+#ifdef GL_EXT_packed_depth_stencil
+ if (format == GL_DEPTH_STENCIL_EXT)
+ return true;
+#endif
+ return false;
+}
+
+
+
+// print a SubResult test description in human-readable form
+void
+ReadpixPerfResult::SubResult::sprint(char *s) const
+{
+ sprintf(s, "glReadPixels(%d x %d, %s), %s, %s, GL_READ_BUFFER=%s",
+ width, height, Formats[formatNum].Name,
+ PBOmodeStrings[pboMode],
+ work ? "pixel sum" : "no pixel sum",
+ readBuf);
+}
+
+
+void
+ReadpixPerfResult::SubResult::print(Environment *env) const
+{
+ char descrip[1000], str[1000];
+ sprint(descrip);
+ sprintf(str, "\t%.3f Mpixels/second: %s\n", rate, descrip);
+ env->log << str;
+}
+
+
+static void
+SimpleRender()
+{
+ glBegin(GL_POINTS);
+ glVertex2f(0, 0);
+ glEnd();
+}
+
+
+// Exercise glReadPixels for a particular image size, format and type.
+// Return read rate in megapixels / second
+double
+ReadpixPerfTest::runNonPBOtest(int formatNum, GLsizei width, GLsizei height,
+ GLuint *sumOut)
+{
+ const GLint bufferSize = width * height * Formats[formatNum].Bytes;
+ GLubyte *buffer = new GLubyte [bufferSize];
+
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ Timer t;
+ double start = t.getClock();
+ double elapsedTime = 0.0;
+ int iter = 0;
+
+ do {
+ iter++;
+ if (sumOut) {
+ SimpleRender();
+ }
+ glReadPixels(0, 0, width, height,
+ Formats[formatNum].Format,
+ Formats[formatNum].Type, buffer);
+ if (sumOut) {
+ GLuint sum = 0;
+ for (int i = 0; i < bufferSize; i++) {
+ sum += buffer[i];
+ }
+ *sumOut = sum;
+ }
+ double finish = t.getClock();
+ elapsedTime = finish - start;
+ } while (elapsedTime < minInterval);
+
+ delete buffer;
+
+ double rate = width * height * iter / elapsedTime / 1000000.0;
+ return rate;
+}
+
+// use glMapBufferARB or glGetBufferSubDataARB:
+#define MAP_BUFFER 1
+
+double
+ReadpixPerfTest::runPBOtest(int formatNum, GLsizei width, GLsizei height,
+ GLenum bufferUsage, GLuint *sumOut)
+{
+#ifdef GL_ARB_pixel_buffer_object
+ const GLint bufferSize = width * height * Formats[formatNum].Bytes / 2;
+
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ // setup PBOs
+ BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO1);
+ BufferData(GL_PIXEL_PACK_BUFFER_ARB, bufferSize, NULL, bufferUsage);
+ BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO2);
+ BufferData(GL_PIXEL_PACK_BUFFER_ARB, bufferSize, NULL, bufferUsage);
+
+#if !MAP_BUFFER
+ GLubyte *b = new GLubyte [bufferSize];
+#endif
+
+ Timer t;
+ double start = t.getClock();
+ double elapsedTime = 0.0;
+ int iter = 0;
+
+ do {
+ iter++;
+ if (sumOut) {
+ SimpleRender();
+ }
+ // read lower half
+ BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO1);
+ glReadPixels(0, 0, width, height / 2,
+ Formats[formatNum].Format,
+ Formats[formatNum].Type, NULL);
+ // read upper half
+ BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO2);
+ glReadPixels(0, height / 2, width, height / 2,
+ Formats[formatNum].Format,
+ Formats[formatNum].Type, NULL);
+ if (sumOut) {
+ GLuint sum = 0;
+ // sum lower half
+ BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO1);
+#if MAP_BUFFER
+ GLubyte *b = (GLubyte *)
+ MapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
+ GL_READ_ONLY);
+#else
+ GetBufferSubData(GL_PIXEL_PACK_BUFFER_ARB,
+ 0, bufferSize, b);
+#endif
+ for (int i = 0; i < bufferSize; i++) {
+ sum += b[i];
+ }
+#if MAP_BUFFER
+ UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
+#endif
+
+ // sum upper half
+ BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO2);
+#if MAP_BUFFER
+ b = (GLubyte *) MapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
+ GL_READ_ONLY);
+#else
+ GetBufferSubData(GL_PIXEL_PACK_BUFFER_ARB,
+ 0, bufferSize, b);
+#endif
+ for (int i = 0; i < bufferSize; i++) {
+ sum += b[i];
+ }
+#if MAP_BUFFER
+ UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
+#endif
+ *sumOut = sum;
+ }
+ double finish = t.getClock();
+ elapsedTime = finish - start;
+ } while (elapsedTime < minInterval);
+
+ BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+
+#if !MAP_BUFFER
+ delete b;
+#endif
+
+ double rate = width * height * iter / elapsedTime / 1000000.0;
+ return rate;
+#else
+ return 0.0;
+#endif /* GL_ARB_pixel_buffer_object */
+}
+
+
+
+// Per visual setup.
+void
+ReadpixPerfTest::setup(void)
+{
+ env->log << name << ":\n";
+
+ glGetIntegerv(GL_DEPTH_BITS, &depthBits);
+ glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
+
+ if (GLUtils::haveExtensions("GL_ARB_pixel_buffer_object")) {
+ BindBuffer = (PFNGLBINDBUFFERARBPROC)
+ GLUtils::getProcAddress("glBindBufferARB");
+ assert(BindBuffer);
+ BufferData = (PFNGLBUFFERDATAARBPROC)
+ GLUtils::getProcAddress("glBufferDataARB");
+ assert(BufferData);
+ MapBuffer = (PFNGLMAPBUFFERARBPROC)
+ GLUtils::getProcAddress("glMapBufferARB");
+ assert(MapBuffer);
+ UnmapBuffer = (PFNGLUNMAPBUFFERARBPROC)
+ GLUtils::getProcAddress("glUnmapBufferARB");
+ assert(UnmapBuffer);
+ GetBufferSubData = (PFNGLGETBUFFERSUBDATAARBPROC)
+ GLUtils::getProcAddress("glGetBufferSubDataARB");
+ assert(GetBufferSubData);
+ numPBOmodes = 4;
+ }
+ else {
+ numPBOmodes = 1;
+ }
+
+ // Fill colorbuffer with random data
+ GLubyte *buffer = new GLubyte [windowSize * windowSize * 4];
+ for (int i = 0; i < windowSize * windowSize * 4; i++)
+ buffer[i] = 5;
+ glDrawPixels(windowSize, windowSize, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+ if (depthBits > 0) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+ glDrawPixels(windowSize, windowSize,
+ GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer);
+ }
+ if (stencilBits > 0) {
+ glDrawPixels(windowSize, windowSize,
+ GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer);
+ }
+ delete buffer;
+}
+
+
+
+void
+ReadpixPerfTest::runOne(ReadpixPerfResult &r, Window &w)
+{
+ ReadpixPerfResult::SubResult res;
+ (void) w; // silence warning
+
+ setup();
+ assert(numPBOmodes > 0);
+
+ r.pass = true;
+ res.width = windowSize;
+ res.height = windowSize;
+
+ {
+ GLint readBuf;
+ glGetIntegerv(GL_READ_BUFFER, &readBuf);
+ if (readBuf == GL_FRONT)
+ res.readBuf = "GL_FRONT";
+ else
+ res.readBuf = "GL_BACK";
+ }
+
+ for (res.formatNum = 0; Formats[res.formatNum].Name; res.formatNum++) {
+
+ if (isDepthFormat(Formats[res.formatNum].Format) && depthBits == 0)
+ continue;
+ if (isStencilFormat(Formats[res.formatNum].Format) && stencilBits == 0)
+ continue;
+
+ if (isDepthStencilFormat(Formats[res.formatNum].Format) &&
+ !GLUtils::haveExtensions("GL_EXT_packed_depth_stencil"))
+ continue;
+
+ for (res.work = 0; res.work < 2; res.work++) {
+ GLuint firstSum = 0;
+
+ for (res.pboMode = 0; res.pboMode < numPBOmodes; res.pboMode++) {
+ GLuint sum = 0;
+
+ if (res.pboMode) {
+ GLenum usage = PBOmodes[res.pboMode];
+ res.rate = runPBOtest(res.formatNum, res.width, res.height, usage,
+ res.work ? &sum : NULL);
+ }
+ else {
+ res.rate = runNonPBOtest(res.formatNum, res.width, res.height,
+ res.work ? &sum : NULL);
+ }
+
+ res.print(env);
+ r.results.push_back(res);
+
+ // sanity check
+ if (res.pboMode == 0) {
+ firstSum = sum;
+ }
+ else if (firstSum != sum) {
+ // this should never happen, probably an OpenGL bug
+ char s0[1000];
+ res.sprint(s0);
+ env->log << name
+ << " Error: glReadPixels returned inconsistant data:\n"
+ << s0
+ << " returned "
+ << firstSum
+ << " but expected sum is "
+ << sum << "\n";
+ r.pass = false;
+ }
+ }
+ }
+ }
+}
+
+
+void
+ReadpixPerfTest::logOne(ReadpixPerfResult &r)
+{
+ logPassFail(r);
+ logConcise(r);
+}
+
+
+void
+ReadpixPerfTest::compareOne(ReadpixPerfResult &oldR,
+ ReadpixPerfResult &newR)
+{
+ const double threshold = 2.0; // percent
+
+ comparePassFail(oldR, newR);
+
+ if (newR.pass && oldR.pass) {
+ // if both tests failed, compare/report rates
+ ReadpixPerfResult::sub_iterator it_old = oldR.results.begin();
+ ReadpixPerfResult::sub_iterator it_new = newR.results.begin();
+ assert(oldR.results.size() == newR.results.size());
+ for ( ; it_old != oldR.results.end(); ++it_old, ++it_new) {
+ const ReadpixPerfResult::SubResult &oldres = *it_old;
+ const ReadpixPerfResult::SubResult &newres = *it_new;
+
+ double diff = (newres.rate - oldres.rate) / newres.rate;
+ diff *= 100.0;
+ if (fabs(diff) >= threshold) {
+ char descrip[1000];
+ newres.sprint(descrip);
+ env->log << name << ": Warning: rate for '"
+ << descrip
+ << "' changed by "
+ << diff
+ << " percent (old: "
+ << newres.rate
+ << " new: "
+ << oldres.rate
+ << " MPixels/sec)\n";
+ }
+ }
+ }
+ else {
+ // one test or the other failed
+ env->log << "\tNew: ";
+ env->log << (newR.pass ? "PASS" : "FAIL");
+ env->log << "\tOld: ";
+ env->log << (oldR.pass ? "PASS" : "FAIL");
+ }
+}
+
+
+// Write vector of sub results
+void
+ReadpixPerfResult::putresults(ostream &s) const
+{
+ s << pass << '\n';
+ s << results.size() << '\n';
+ for (ReadpixPerfResult::sub_iterator it = results.begin();
+ it != results.end();
+ ++it) {
+ const ReadpixPerfResult::SubResult &res = *it;
+ s << res.rate << '\n';
+ s << res.width << '\n';
+ s << res.height << '\n';
+ s << res.formatNum << '\n';
+ s << res.pboMode << '\n';
+ s << res.work << '\n';
+ }
+}
+
+
+// Read vector of sub results
+bool
+ReadpixPerfResult::getresults(istream &s)
+{
+ int count;
+
+ s >> pass
+ >> count;
+
+ results.reserve(count);
+ for (int i = 0; i < count; i++) {
+ ReadpixPerfResult::SubResult res;
+ s >> res.rate
+ >> res.width
+ >> res.height
+ >> res.formatNum
+ >> res.pboMode
+ >> res.work;
+ results.push_back(res);
+ }
+ return s.good();
+}
+
+
+// The test object itself:
+ReadpixPerfTest readpixperfTest("readpixPerf", "window, rgb",
+ "",
+ "Test the performance of glReadPixels for a variety of pixel\n"
+ "formats and datatypes.\n"
+ "When GL_ARB_pixel_buffer_object is supported, we also test reading\n"
+ "pixels into a PBO using the three types of buffer usage modes:\n"
+ "GL_STREAM_READ_ARB, GL_STATIC_READ_ARB and GL_DYNAMIC_READ_ARB.\n"
+ "Furthermore, test effect of summing the value of all image bytes\n"
+ "to simulate host-based image processing.\n"
+ );
+
+
+
+
+} // namespace GLEAN
+
diff --git a/tests/glean/treadpixperf.h b/tests/glean/treadpixperf.h
new file mode 100644
index 00000000..8e710f91
--- /dev/null
+++ b/tests/glean/treadpixperf.h
@@ -0,0 +1,88 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// Brian Paul September 2006
+
+#ifndef __treadpixperf_h__
+#define __treadpixperf_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define windowSize 1000
+
+
+class ReadpixPerfResult: public BaseResult
+{
+public:
+ struct SubResult
+ {
+ double rate;
+ GLsizei width, height;
+ int formatNum;
+ int pboMode;
+ int work; // really bool
+ void sprint(char *s) const;
+ void print(Environment *env) const;
+ const char *readBuf; // "GL_FRONT" or "GL_BACK"
+ };
+
+ bool pass;
+
+ vector<SubResult> results;
+
+ typedef vector<ReadpixPerfResult::SubResult>::const_iterator sub_iterator;
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+
+class ReadpixPerfTest: public BaseTest<ReadpixPerfResult>
+{
+public:
+ GLEAN_CLASS_WH(ReadpixPerfTest, ReadpixPerfResult,
+ windowSize, windowSize);
+
+private:
+ int depthBits, stencilBits;
+ int numPBOmodes;
+
+ double runPBOtest(int formatNum, GLsizei width, GLsizei height,
+ GLenum bufferUsage, GLuint *sumOut);
+ double runNonPBOtest(int formatNum, GLsizei width, GLsizei height,
+ GLuint *sumOut);
+
+ void setup(void);
+};
+
+} // namespace GLEAN
+
+#endif // __treadpixperf_h__
+
diff --git a/tests/glean/trgbtris.cpp b/tests/glean/trgbtris.cpp
new file mode 100644
index 00000000..565a85fb
--- /dev/null
+++ b/tests/glean/trgbtris.cpp
@@ -0,0 +1,196 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// trgbtris.cpp: example image-based test to show use of TIFF images
+
+#include "trgbtris.h"
+#include "stats.h"
+#include "rand.h"
+#include "geomutil.h"
+#include "image.h"
+
+#if 0
+#if defined __UNIX__
+#include <unistd.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include "dsconfig.h"
+#include "dsfilt.h"
+#include "dsurf.h"
+#include "winsys.h"
+#include "environ.h"
+#include "rc.h"
+#include "glutils.h"
+#include "trgbtris.h"
+#include "misc.h"
+#endif
+
+namespace {
+
+void
+logStats(GLEAN::BasicStats& stats, GLEAN::Environment* env) {
+ env->log << "\t\tmin = " << stats.min() << ", max = " << stats.max()
+ << "\n\t\tmean = " << stats.mean() << ", standard deviation = "
+ << stats.deviation() << '\n';
+}
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBTriStripTest::runOne(RGBTriStripResult& r, Window& w) {
+ static int this_config = 0;
+ r.imageNumber = ++this_config;
+
+ GLUtils::useScreenCoords(drawingSize + 2, drawingSize + 2);
+
+ int nPoints = 20; // Exact value doesn't really matter.
+ RandomDouble vRand(142857);
+ RandomMesh2D v(1.0, drawingSize, nPoints, 1.0, drawingSize, nPoints,
+ vRand);
+
+ RandomDouble cRand(271828);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ glShadeModel(GL_SMOOTH);
+
+ for (int row = 0; row < nPoints - 1; ++row) {
+ glBegin(GL_TRIANGLE_STRIP);
+ for (int col = 0; col < nPoints; ++col) {
+ float r = cRand.next();
+ float g = cRand.next();
+ float b = cRand.next();
+ glColor3f(r, g, b);
+ glVertex2fv(v(row, col));
+ r = cRand.next();
+ g = cRand.next();
+ b = cRand.next();
+ glColor3f(r, g, b);
+ glVertex2fv(v(row + 1, col));
+ }
+ glEnd();
+ }
+ w.swap();
+
+ Image image(drawingSize + 2, drawingSize + 2, GL_RGB, GL_FLOAT);
+ image.read(0, 0); // Invoke glReadPixels to read the image.
+ image.writeTIFF(env->imageFileName(name, r.imageNumber));
+
+ r.pass = true;
+} // RGBTriStripTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBTriStripTest::logOne(RGBTriStripResult& r) {
+ env->log << name << ": NOTE "
+ << r.config->conciseDescription() << '\n'
+ << "\tImage number " << r.imageNumber << '\n';
+ if (env->options.verbosity)
+ env->log <<
+ "\tThis test does not check its result. Please view\n"
+ "\tthe image to verify that the result is correct, or\n"
+ "\tcompare it to a known-good result from a different\n"
+ "\trun of glean.\n";
+} // RGBTriStripTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBTriStripTest::compareOne(RGBTriStripResult& oldR, RGBTriStripResult& newR) {
+ // Fetch the old and new images:
+ Image oldI;
+ oldI.readTIFF(env->image1FileName(name, oldR.imageNumber));
+ Image newI;
+ newI.readTIFF(env->image2FileName(name, newR.imageNumber));
+
+ // Register the images, and gather statistics about the differences
+ // for each color channel:
+ Image::Registration reg(oldI.reg(newI));
+
+ // Compute worst-case tolerance (1 LSB in the shallowest drawing
+ // surface configuration) for each color channel:
+ double rTol = 1.0 / (1 << min(oldR.config->r, newR.config->r));
+ double gTol = 1.0 / (1 << min(oldR.config->g, newR.config->g));
+ double bTol = 1.0 / (1 << min(oldR.config->b, newR.config->b));
+
+ // We'll conclude that the images are the ``same'' if the maximum
+ // absolute error is no more than 1 LSB (in the shallowest config):
+ if (reg.stats[0].max() <= rTol && reg.stats[1].max() <= gTol
+ && reg.stats[2].max() <= bTol) {
+ if (env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription() << '\n';
+ if (reg.stats[0].max() == 0 && reg.stats[1].max() == 0
+ && reg.stats[1].max() == 0)
+ env->log << "\tImages are exactly equal\n";
+ else
+ env->log << "\tImages are approximately equal\n";
+ }
+ } else {
+ env->log << name << ": DIFF "
+ << newR.config->conciseDescription() << '\n'
+ << "\tDifference exceeds 1 LSB in at least one "
+ "color channel\n";
+ }
+ if (env->options.verbosity) {
+ env->log << "\tred:\n";
+ logStats(reg.stats[0], env);
+ env->log << "\tgreen:\n";
+ logStats(reg.stats[1], env);
+ env->log << "\tblue:\n";
+ logStats(reg.stats[2], env);
+ }
+} // RGBTriStripTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+RGBTriStripTest rgbTriStripTest("rgbTriStrip", "window, rgb",
+
+ "The best approach when designing a test is to make it\n"
+ "self-checking; that is, the test itself should determine\n"
+ "whether the image or other data structure that it produces is\n"
+ "correct. However, some tests are difficult to design in this\n"
+ "way, and for some other tests (like stress tests or regression\n"
+ "tests concerning previously-reported bugs) it may be\n"
+ "unnecessary. For such tests, glean provides mechanisms to\n"
+ "save images and compare them to images generated from other\n"
+ "runs. This test simply exercises those mechanisms.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/trgbtris.h b/tests/glean/trgbtris.h
new file mode 100644
index 00000000..b41a10bd
--- /dev/null
+++ b/tests/glean/trgbtris.h
@@ -0,0 +1,63 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// trgbtris.h: example image-based test to show use of TIFF images
+
+#ifndef __trgbtris_h__
+#define __trgbtris_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define drawingSize 64
+
+class RGBTriStripResult: public BaseResult {
+public:
+ bool pass;
+ int imageNumber;
+
+ void putresults(ostream& s) const {
+ s << imageNumber << '\n';
+ }
+
+ bool getresults(istream& s) {
+ s >> imageNumber;
+ return s.good();
+ }
+};
+
+class RGBTriStripTest: public BaseTest<RGBTriStripResult> {
+public:
+ GLEAN_CLASS_WH(RGBTriStripTest, RGBTriStripResult,
+ drawingSize, drawingSize);
+}; // class RGBTriStripTest
+
+} // namespace GLEAN
+
+#endif // __trgbtris_h__
diff --git a/tests/glean/tscissor.cpp b/tests/glean/tscissor.cpp
new file mode 100644
index 00000000..f72bfb4a
--- /dev/null
+++ b/tests/glean/tscissor.cpp
@@ -0,0 +1,188 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tscissor.cpp: Basic test of OpenGL scissor.
+//
+// This test verifies that the four corner pixels, and the four pixels
+// diagonally inside the corners, of a scissored region are filled
+// correctly. It then tests up to two pixels in both the horizontal and
+// vertical directions of the scissor region to verify that they are
+// unfilled.
+//
+// To test for pass/fail, we examine the color buffer for white or black,
+// respectively.
+//
+// Author: Gareth Hughes <gareth@valinux.com> December 2000
+
+#include "tscissor.h"
+
+namespace GLEAN {
+
+/* Verification helper macros:
+ */
+#define BAD_PIXEL( X, Y, R, G, B ) ( image[X][Y][0] != (R) || \
+ image[X][Y][1] != (G) || \
+ image[X][Y][2] != (B) )
+
+#define TEST_PIXEL( X, Y, R, G, B, E ) \
+do { \
+ if ( BAD_PIXEL( X, Y, R, G, B ) ) { \
+ FailMessage( r, E, X, Y, \
+ i, i, 10-2*i, 10-2*i ); \
+ passed = false; \
+ } \
+} while (0)
+
+#define TEST_CORNER( X, Y, SX, SY ) \
+do { \
+ TEST_PIXEL( X, Y, 1.0, 1.0, 1.0, 1 ); \
+ TEST_PIXEL( X SX 1, Y SY 1, 1.0, 1.0, 1.0, 2 ); \
+ for ( j = 1 ; j <= i ; j++ ) { \
+ TEST_PIXEL( X - SX j, Y, 0.0, 0.0, 0.0, j ); \
+ TEST_PIXEL( X, Y - SY j, 0.0, 0.0, 0.0, j ); \
+ } \
+} while (0)
+
+
+void
+ScissorTest::FailMessage( BasicResult &r, int error, int x, int y,
+ int sx, int sy, int sw, int sh ) const
+{
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << "\n";
+ env->log << "\tOff by " << error << " error at"
+ << " row " << x << " column " << y;
+ env->log << "\n\tglScissor( "
+ << sx << ", " << sy << ", "
+ << sw << ", " << sh << " )\n\n";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ScissorTest::runOne( BasicResult& r, Window& w ) {
+ bool passed = true;
+ int i, j, k;
+
+ // Draw 10x10 quads, as they fit nicely into a terminal window
+ // when dumped as RGB triplets...
+ glViewport( 0, 0, 10, 10 );
+
+ glDisable( GL_DITHER );
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, 1.0, 0.0, 1.0, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glClearColor( 0.0, 0.0, 0.0, 0.0 );
+ glColor3f( 1.0, 1.0, 1.0 );
+
+ if ( env->options.verbosity ) env->log << "\n";
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ float image[10][10][3];
+
+ glDisable( GL_SCISSOR_TEST );
+ glClear( GL_COLOR_BUFFER_BIT );
+ glEnable( GL_SCISSOR_TEST );
+
+ glScissor( i, i, 10-2*i, 10-2*i );
+
+ glBegin( GL_QUADS );
+ glVertex3f( 0.0, 0.0, 0.0 );
+ glVertex3f( 1.0, 0.0, 0.0 );
+ glVertex3f( 1.0, 1.0, 0.0 );
+ glVertex3f( 0.0, 1.0, 0.0 );
+ glEnd();
+
+ w.swap();
+
+ glReadPixels( 0, 0, 10, 10, GL_RGB, GL_FLOAT, image );
+
+ // Dump the entire 10x10 image so the exact results can
+ // be inspected. Should make any failures pretty clear.
+ if ( env->options.verbosity ) {
+ env->log << "glScissor( "
+ << i << ", " << i << ", "
+ << 10-2*i << ", " << 10-2*i << " ):\n\n";
+ for ( j = 0 ; j < 10 ; j++ ) {
+ for ( k = 0 ; k < 10 ; k++ ) {
+ env->log << " " << image[j][k][0]
+ << " " << image[j][k][1]
+ << " " << image[j][k][2];
+ }
+ env->log << "\n";
+ }
+ env->log << "\n";
+ }
+
+ // Test the four corners. Macro magic, I know...
+ TEST_CORNER( i, i, +, + );
+ TEST_CORNER( 9 - i, i, -, + );
+ TEST_CORNER( 9 - i, 9 - i, -, - );
+ TEST_CORNER( i, 9 - i, +, - );
+ }
+
+ r.pass = passed;
+} // ScissorTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ScissorTest::logOne( BasicResult& r ) {
+ if ( r.pass ) {
+ logPassFail( r );
+ logConcise( r );
+ }
+} // ScissorTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ScissorTest::compareOne( BasicResult&, BasicResult& ) {
+ // FIXME: Implement this...
+} // ScissorTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+ScissorTest scissorTest( "scissor", "window, rgb",
+
+ "This test performs a basic test of the OpenGL scissor. It\n"
+ "checks for off-by-one errors around all four corners of the\n"
+ "scissored region, perhaps the most common cause of scissor\n"
+ "test failures.\n"
+
+ );
+
+} // namespace GLEAN
diff --git a/tests/glean/tscissor.h b/tests/glean/tscissor.h
new file mode 100644
index 00000000..75b13d9b
--- /dev/null
+++ b/tests/glean/tscissor.h
@@ -0,0 +1,52 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// tscissor.h: Basic test of OpenGL scissor.
+//
+// Author: Gareth Hughes <gareth@valinux.com> December 2000
+
+
+#ifndef __tscissor_h__
+#define __tscissor_h__
+
+#include "tbasic.h"
+
+namespace GLEAN {
+
+class ScissorTest: public BaseTest<BasicResult> {
+public:
+ GLEAN_CLASS_WH( ScissorTest, BasicResult, 10, 10 );
+
+ void FailMessage( BasicResult &r, int err, int x, int y,
+ int sx, int sy, int sw, int sh ) const;
+}; // class ScissorTest
+
+} // namespace GLEAN
+
+#endif // __tscissor_h__
diff --git a/tests/glean/tteapot.cpp b/tests/glean/tteapot.cpp
new file mode 100644
index 00000000..44bff139
--- /dev/null
+++ b/tests/glean/tteapot.cpp
@@ -0,0 +1,3215 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Adam Haberlach All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+#include "tteapot.h"
+#include "timer.h"
+
+namespace {
+
+float depthOfView = 30.0;
+float zRatio = 10.0;
+
+float position[] = {0.0, 3.0, 3.0, 0.0};
+float position1[] = {-3.0, -3.0, 3.0, 0.0};
+float position2[] = {3.0, 0.0, 0.0, 0.0};
+float local_view[] = {0.0,0.0};
+float ambient[] = {0.1745, 0.03175, 0.03175};
+float diffuse[] = {0.61424, 0.10136, 0.10136};
+float specular[] = {0.727811, 0.626959, 0.626959};
+// rgb_color bg_black = {0,0,0,255};
+
+enum lights {
+ lightNone = 0,
+ lightWhite,
+ lightYellow,
+ lightRed,
+ lightBlue,
+ lightGreen
+};
+
+
+float white[3] = {1.0,1.0,1.0};
+float dimWhite[3] = {0.25,0.25,0.25};
+float black[3] = {0.0,0.0,0.0};
+float foggy[3] = {0.4,0.4,0.4};
+float blue[3] = {0.0,0.0,1.0};
+float dimBlue[3] = {0.0,0.0,0.5};
+float yellow[3] = {1.0,1.0,0.0};
+float dimYellow[3] = {0.5,0.5,0.0};
+float green[3] = {0.0,1.0,0.0};
+float dimGreen[3] = {0.0,0.5,0.0};
+float red[3] = {1.0,0.0,0.0};
+
+float *bgColor = black;
+
+struct light {
+ float *ambient;
+ float *diffuse;
+ float *specular;
+};
+
+light lights[] = {
+ {NULL,NULL,NULL},
+ {dimWhite,white,white},
+ {dimWhite,yellow,yellow},
+ {dimWhite,red,red},
+ {dimWhite,blue,blue},
+ {dimWhite,green,green}
+};
+
+struct material {
+ float ambient[3],diffuse[3],specular[3];
+};
+
+float *colors[] =
+{
+ NULL,white,yellow,blue,red,green
+};
+
+
+material materials[] = {
+ // Null
+ {
+ {0.1745, 0.03175, 0.03175},
+ {0.61424, 0.10136, 0.10136},
+ {0.727811, 0.626959, 0.626959}
+ },
+ // White
+ {
+ {0.1745, 0.1745, 0.1745},
+ {0.61424, 0.61424, 0.61424},
+ {0.727811, 0.727811, 0.727811}
+ },
+ // Yellow
+ {
+ {0.1745, 0.1745, 0.03175},
+ {0.61424, 0.61424, 0.10136},
+ {0.727811, 0.727811, 0.626959}
+ },
+ // Blue
+ {
+ {0.03175, 0.03175, 0.1745},
+ {0.10136, 0.10136, 0.61424},
+ {0.626959, 0.626959, 0.727811}
+ },
+ // Red
+ {
+ {0.1745, 0.03175, 0.03175},
+ {0.61424, 0.10136, 0.10136},
+ {0.727811, 0.626959, 0.626959}
+ },
+ // Green
+ {
+ {0.03175, 0.1745, 0.03175},
+ {0.10136, 0.61424, 0.10136},
+ {0.626959, 0.727811, 0.626959}
+ },
+};
+
+GLfloat vertexArrayData[] = {
+ 0.749768, 0.000000, 0.661700, 0.425044, 0.000000, 0.717239,
+ 0.902857, 0.000000, 0.429932, 0.436808, 0.000000, 0.698893,
+ 0.857866, -0.280456, 0.430593, 0.414863, -0.139359, 0.698893,
+ 0.712062, -0.232790, 0.662397, 0.403689, -0.135606, 0.717239,
+ 0.398032, 0.000000, 0.917368, 0.413454, 0.000000, 0.726412,
+ 0.377729, -0.123488, 0.917640, 0.392682, -0.131908, 0.726412,
+ -0.594549, 0.000000, 0.804060, 0.404834, 0.000000, 0.726412,
+ -0.564429, 0.184525, 0.804593, 0.384495, -0.129158, 0.726412,
+ -0.997566, 0.000000, -0.069671, 0.401980, 0.000000, 0.717239,
+ -0.948177, 0.309981, -0.069801, 0.381785, -0.128248, 0.717239,
+ -0.902860, 0.000000, -0.429934, 0.407688, 0.000000, 0.698893,
+ -0.857865, 0.280456, -0.430592, 0.387205, -0.130069, 0.698893,
+ 0.729170, -0.531333, 0.431273, 0.353500, -0.259429, 0.698893,
+ 0.604942, -0.440810, 0.663117, 0.343979, -0.252442, 0.717239,
+ 0.320655, -0.233655, 0.917921, 0.334600, -0.245558, 0.726412,
+ -0.479323, 0.349274, 0.805140, 0.327624, -0.240439, 0.726412,
+ -0.806215, 0.587474, -0.069936, 0.325314, -0.238744, 0.717239,
+ -0.729168, 0.531331, -0.431271, 0.329934, -0.242134, 0.698893,
+ 0.531333, -0.729170, 0.431273, 0.259429, -0.353500, 0.698893,
+ 0.440810, -0.604942, 0.663117, 0.252442, -0.343979, 0.717239,
+ 0.233655, -0.320655, 0.917921, 0.245558, -0.334600, 0.726412,
+ -0.349274, 0.479323, 0.805140, 0.240439, -0.327624, 0.726412,
+ -0.587474, 0.806215, -0.069936, 0.238744, -0.325314, 0.717239,
+ -0.531331, 0.729168, -0.431271, 0.242134, -0.329934, 0.698893,
+ 0.280456, -0.857866, 0.430593, 0.139359, -0.414863, 0.698893,
+ 0.232790, -0.712062, 0.662397, 0.135606, -0.403689, 0.717239,
+ 0.123488, -0.377729, 0.917640, 0.131908, -0.392682, 0.726412,
+ -0.184525, 0.564429, 0.804593, 0.129158, -0.384495, 0.726412,
+ -0.309981, 0.948177, -0.069801, 0.128248, -0.381785, 0.717239,
+ -0.280456, 0.857865, -0.430592, 0.130069, -0.387205, 0.698893,
+ 0.000000, -0.902857, 0.429932, 0.000000, -0.436808, 0.698893,
+ 0.000000, -0.749768, 0.661700, 0.000000, -0.425044, 0.717239,
+ 0.000000, -0.398032, 0.917368, 0.000000, -0.413454, 0.726412,
+ 0.000000, 0.594549, 0.804060, 0.000000, -0.404834, 0.726412,
+ 0.000000, 0.997566, -0.069671, 0.000000, -0.401980, 0.717239,
+ 0.000000, 0.902860, -0.429934, 0.000000, -0.407688, 0.698893,
+ 0.000000, 0.749768, 0.661700, 0.000000, 0.425044, 0.717239,
+ 0.000000, 0.902857, 0.429932, 0.000000, 0.436808, 0.698893,
+ 0.280456, 0.857866, 0.430593, 0.139359, 0.414863, 0.698893,
+ 0.232790, 0.712062, 0.662397, 0.135606, 0.403689, 0.717239,
+ 0.000000, 0.398032, 0.917368, 0.000000, 0.413454, 0.726412,
+ 0.123488, 0.377729, 0.917640, 0.131908, 0.392682, 0.726412,
+ 0.000000, -0.594549, 0.804060, 0.000000, 0.404834, 0.726412,
+ -0.184525, -0.564429, 0.804593, 0.129158, 0.384495, 0.726412,
+ 0.000000, -0.997566, -0.069671, 0.000000, 0.401980, 0.717239,
+ -0.309981, -0.948177, -0.069801, 0.128248, 0.381785, 0.717239,
+ 0.000000, -0.902860, -0.429934, 0.000000, 0.407688, 0.698893,
+ -0.280456, -0.857865, -0.430592, 0.130069, 0.387205, 0.698893,
+ 0.531333, 0.729170, 0.431273, 0.259429, 0.353500, 0.698893,
+ 0.440810, 0.604942, 0.663117, 0.252442, 0.343979, 0.717239,
+ 0.233655, 0.320655, 0.917921, 0.245558, 0.334600, 0.726412,
+ -0.349274, -0.479323, 0.805140, 0.240439, 0.327624, 0.726412,
+ -0.587474, -0.806215, -0.069936, 0.238744, 0.325314, 0.717239,
+ -0.531331, -0.729168, -0.431271, 0.242134, 0.329934, 0.698893,
+ 0.729170, 0.531333, 0.431273, 0.353500, 0.259429, 0.698893,
+ 0.604942, 0.440810, 0.663117, 0.343979, 0.252442, 0.717239,
+ 0.320655, 0.233655, 0.917921, 0.334600, 0.245558, 0.726412,
+ -0.479323, -0.349274, 0.805140, 0.327624, 0.240439, 0.726412,
+ -0.806215, -0.587474, -0.069936, 0.325314, 0.238744, 0.717239,
+ -0.729168, -0.531331, -0.431271, 0.329934, 0.242134, 0.698893,
+ 0.857866, 0.280456, 0.430593, 0.414863, 0.139359, 0.698893,
+ 0.712062, 0.232790, 0.662397, 0.403689, 0.135606, 0.717239,
+ 0.377729, 0.123488, 0.917640, 0.392682, 0.131908, 0.726412,
+ -0.564429, -0.184525, 0.804593, 0.384495, 0.129158, 0.726412,
+ -0.948177, -0.309981, -0.069801, 0.381785, 0.128248, 0.717239,
+ -0.857865, -0.280456, -0.430592, 0.387205, 0.130069, 0.698893,
+ -0.280456, -0.857866, 0.430593, -0.139359, -0.414863, 0.698893,
+ -0.232790, -0.712062, 0.662397, -0.135606, -0.403689, 0.717239,
+ -0.123488, -0.377729, 0.917640, -0.131908, -0.392682, 0.726412,
+ 0.184525, 0.564429, 0.804593, -0.129158, -0.384495, 0.726412,
+ 0.309981, 0.948177, -0.069801, -0.128248, -0.381785, 0.717239,
+ 0.280456, 0.857865, -0.430592, -0.130069, -0.387205, 0.698893,
+ -0.531333, -0.729170, 0.431273, -0.259429, -0.353500, 0.698893,
+ -0.440810, -0.604942, 0.663117, -0.252442, -0.343979, 0.717239,
+ -0.233655, -0.320655, 0.917921, -0.245558, -0.334600, 0.726412,
+ 0.349274, 0.479323, 0.805140, -0.240439, -0.327624, 0.726412,
+ 0.587474, 0.806215, -0.069936, -0.238744, -0.325314, 0.717239,
+ 0.531331, 0.729168, -0.431271, -0.242134, -0.329934, 0.698893,
+ -0.729170, -0.531333, 0.431273, -0.353500, -0.259429, 0.698893,
+ -0.604942, -0.440810, 0.663117, -0.343979, -0.252442, 0.717239,
+ -0.320655, -0.233655, 0.917921, -0.334600, -0.245558, 0.726412,
+ 0.479323, 0.349274, 0.805140, -0.327624, -0.240439, 0.726412,
+ 0.806215, 0.587474, -0.069936, -0.325314, -0.238744, 0.717239,
+ 0.729168, 0.531331, -0.431271, -0.329934, -0.242134, 0.698893,
+ -0.857866, -0.280456, 0.430593, -0.414863, -0.139359, 0.698893,
+ -0.712062, -0.232790, 0.662397, -0.403689, -0.135606, 0.717239,
+ -0.377729, -0.123488, 0.917640, -0.392682, -0.131908, 0.726412,
+ 0.564429, 0.184525, 0.804593, -0.384495, -0.129158, 0.726412,
+ 0.948177, 0.309981, -0.069801, -0.381785, -0.128248, 0.717239,
+ 0.857865, 0.280456, -0.430592, -0.387205, -0.130069, 0.698893,
+ -0.902857, 0.000000, 0.429932, -0.436808, 0.000000, 0.698893,
+ -0.749768, 0.000000, 0.661700, -0.425044, 0.000000, 0.717239,
+ -0.398032, 0.000000, 0.917368, -0.413454, 0.000000, 0.726412,
+ 0.594549, 0.000000, 0.804060, -0.404834, 0.000000, 0.726412,
+ 0.997566, 0.000000, -0.069671, -0.401980, 0.000000, 0.717239,
+ 0.902860, 0.000000, -0.429934, -0.407688, 0.000000, 0.698893,
+ -0.857866, 0.280456, 0.430593, -0.414863, 0.139359, 0.698893,
+ -0.712062, 0.232790, 0.662397, -0.403689, 0.135606, 0.717239,
+ -0.377729, 0.123488, 0.917640, -0.392682, 0.131908, 0.726412,
+ 0.564429, -0.184525, 0.804593, -0.384495, 0.129158, 0.726412,
+ 0.948177, -0.309981, -0.069801, -0.381785, 0.128248, 0.717239,
+ 0.857865, -0.280456, -0.430592, -0.387205, 0.130069, 0.698893,
+ -0.729170, 0.531333, 0.431273, -0.353500, 0.259429, 0.698893,
+ -0.604942, 0.440810, 0.663117, -0.343979, 0.252442, 0.717239,
+ -0.320655, 0.233655, 0.917921, -0.334600, 0.245558, 0.726412,
+ 0.479323, -0.349274, 0.805140, -0.327624, 0.240439, 0.726412,
+ 0.806215, -0.587474, -0.069936, -0.325314, 0.238744, 0.717239,
+ 0.729168, -0.531331, -0.431271, -0.329934, 0.242134, 0.698893,
+ -0.531333, 0.729170, 0.431273, -0.259429, 0.353500, 0.698893,
+ -0.440810, 0.604942, 0.663117, -0.252442, 0.343979, 0.717239,
+ -0.233655, 0.320655, 0.917921, -0.245558, 0.334600, 0.726412,
+ 0.349274, -0.479323, 0.805140, -0.240439, 0.327624, 0.726412,
+ 0.587474, -0.806215, -0.069936, -0.238744, 0.325314, 0.717239,
+ 0.531331, -0.729168, -0.431271, -0.242134, 0.329934, 0.698893,
+ -0.280456, 0.857866, 0.430593, -0.139359, 0.414863, 0.698893,
+ -0.232790, 0.712062, 0.662397, -0.135606, 0.403689, 0.717239,
+ -0.123488, 0.377729, 0.917640, -0.131908, 0.392682, 0.726412,
+ 0.184525, -0.564429, 0.804593, -0.129158, 0.384495, 0.726412,
+ 0.309981, -0.948177, -0.069801, -0.128248, 0.381785, 0.717239,
+ 0.280456, -0.857865, -0.430592, -0.130069, 0.387205, 0.698893,
+ 0.982662, 0.000000, 0.185408, 0.574257, 0.000000, 0.343157,
+ 0.999997, 0.000000, 0.000000, 0.582411, 0.000000, 0.262085,
+ 0.950495, -0.310739, 0.000000, 0.553151, -0.185812, 0.262085,
+ 0.933952, -0.305330, 0.185744, 0.545407, -0.183211, 0.343157,
+ 0.952068, 0.000000, 0.305886, 0.552126, 0.000000, 0.428422,
+ 0.904777, -0.295792, 0.306407, 0.524387, -0.176150, 0.428422,
+ 0.925461, 0.000000, 0.378844, 0.519511, 0.000000, 0.516832,
+ 0.879408, -0.287499, 0.379453, 0.493410, -0.165745, 0.516832,
+ 0.908570, 0.000000, 0.417733, 0.479907, 0.000000, 0.607338,
+ 0.863304, -0.282234, 0.418380, 0.455796, -0.153109, 0.607338,
+ 0.808194, -0.588917, 0.000000, 0.471334, -0.345906, 0.262085,
+ 0.794073, -0.578627, 0.186092, 0.464735, -0.341063, 0.343157,
+ 0.769179, -0.560487, 0.306945, 0.446824, -0.327918, 0.428422,
+ 0.747539, -0.544718, 0.380083, 0.420430, -0.308548, 0.516832,
+ 0.733807, -0.534712, 0.419049, 0.388379, -0.285026, 0.607338,
+ 0.588917, -0.808194, 0.000000, 0.345906, -0.471334, 0.262085,
+ 0.578627, -0.794073, 0.186092, 0.341063, -0.464735, 0.343157,
+ 0.560487, -0.769179, 0.306945, 0.327918, -0.446824, 0.428422,
+ 0.544718, -0.747539, 0.380083, 0.308548, -0.420430, 0.516832,
+ 0.534712, -0.733807, 0.419049, 0.285026, -0.388379, 0.607338,
+ 0.310739, -0.950495, 0.000000, 0.185812, -0.553151, 0.262085,
+ 0.305331, -0.933952, 0.185744, 0.183211, -0.545407, 0.343157,
+ 0.295792, -0.904777, 0.306407, 0.176150, -0.524387, 0.428422,
+ 0.287499, -0.879408, 0.379453, 0.165745, -0.493410, 0.516832,
+ 0.282234, -0.863304, 0.418380, 0.153109, -0.455796, 0.607338,
+ 0.000000, -0.999997, 0.000000, 0.000000, -0.582411, 0.262085,
+ 0.000000, -0.982662, 0.185408, 0.000000, -0.574257, 0.343157,
+ 0.000000, -0.952068, 0.305886, 0.000000, -0.552126, 0.428422,
+ 0.000000, -0.925461, 0.378844, 0.000000, -0.519511, 0.516832,
+ 0.000000, -0.908570, 0.417733, 0.000000, -0.479907, 0.607338,
+ 0.000000, 0.982662, 0.185408, 0.000000, 0.574257, 0.343157,
+ 0.000000, 0.999997, 0.000000, 0.000000, 0.582411, 0.262085,
+ 0.310739, 0.950495, 0.000000, 0.185812, 0.553151, 0.262085,
+ 0.305330, 0.933952, 0.185744, 0.183211, 0.545407, 0.343157,
+ 0.000000, 0.952068, 0.305886, 0.000000, 0.552126, 0.428422,
+ 0.295792, 0.904777, 0.306407, 0.176150, 0.524387, 0.428422,
+ 0.000000, 0.925461, 0.378844, 0.000000, 0.519511, 0.516832,
+ 0.287499, 0.879408, 0.379453, 0.165745, 0.493410, 0.516832,
+ 0.000000, 0.908570, 0.417733, 0.000000, 0.479907, 0.607338,
+ 0.282234, 0.863304, 0.418380, 0.153109, 0.455796, 0.607338,
+ 0.588917, 0.808194, 0.000000, 0.345906, 0.471334, 0.262085,
+ 0.578627, 0.794073, 0.186092, 0.341063, 0.464735, 0.343157,
+ 0.560487, 0.769179, 0.306945, 0.327918, 0.446824, 0.428422,
+ 0.544718, 0.747539, 0.380083, 0.308548, 0.420430, 0.516832,
+ 0.534712, 0.733807, 0.419049, 0.285026, 0.388379, 0.607338,
+ 0.808194, 0.588917, 0.000000, 0.471334, 0.345906, 0.262085,
+ 0.794073, 0.578627, 0.186092, 0.464735, 0.341063, 0.343157,
+ 0.769179, 0.560487, 0.306945, 0.446824, 0.327918, 0.428422,
+ 0.747539, 0.544718, 0.380083, 0.420430, 0.308548, 0.516832,
+ 0.733807, 0.534712, 0.419049, 0.388379, 0.285026, 0.607338,
+ 0.950495, 0.310739, 0.000000, 0.553151, 0.185812, 0.262085,
+ 0.933952, 0.305330, 0.185744, 0.545407, 0.183211, 0.343157,
+ 0.904777, 0.295792, 0.306407, 0.524387, 0.176150, 0.428422,
+ 0.879408, 0.287499, 0.379453, 0.493410, 0.165745, 0.516832,
+ 0.863304, 0.282234, 0.418380, 0.455796, 0.153109, 0.607338,
+ -0.310739, -0.950495, 0.000000, -0.185812, -0.553151, 0.262085,
+ -0.305330, -0.933952, 0.185744, -0.183211, -0.545407, 0.343157,
+ -0.295792, -0.904777, 0.306407, -0.176150, -0.524387, 0.428422,
+ -0.287499, -0.879408, 0.379453, -0.165745, -0.493410, 0.516832,
+ -0.282234, -0.863304, 0.418380, -0.153109, -0.455796, 0.607338,
+ -0.588917, -0.808194, 0.000000, -0.345906, -0.471334, 0.262085,
+ -0.578627, -0.794073, 0.186092, -0.341063, -0.464735, 0.343157,
+ -0.560487, -0.769179, 0.306945, -0.327918, -0.446824, 0.428422,
+ -0.544718, -0.747539, 0.380083, -0.308548, -0.420430, 0.516832,
+ -0.534712, -0.733807, 0.419049, -0.285026, -0.388379, 0.607338,
+ -0.808194, -0.588917, 0.000000, -0.471334, -0.345906, 0.262085,
+ -0.794073, -0.578627, 0.186092, -0.464735, -0.341063, 0.343157,
+ -0.769179, -0.560487, 0.306945, -0.446824, -0.327918, 0.428422,
+ -0.747539, -0.544718, 0.380083, -0.420430, -0.308548, 0.516832,
+ -0.733807, -0.534712, 0.419049, -0.388379, -0.285026, 0.607338,
+ -0.950495, -0.310739, 0.000000, -0.553151, -0.185812, 0.262085,
+ -0.933952, -0.305330, 0.185744, -0.545407, -0.183211, 0.343157,
+ -0.904777, -0.295792, 0.306407, -0.524387, -0.176150, 0.428422,
+ -0.879408, -0.287499, 0.379453, -0.493410, -0.165745, 0.516832,
+ -0.863304, -0.282234, 0.418380, -0.455796, -0.153109, 0.607338,
+ -0.999997, 0.000000, 0.000000, -0.582411, 0.000000, 0.262085,
+ -0.982662, 0.000000, 0.185408, -0.574257, 0.000000, 0.343157,
+ -0.952068, 0.000000, 0.305886, -0.552126, 0.000000, 0.428422,
+ -0.925461, 0.000000, 0.378844, -0.519511, 0.000000, 0.516832,
+ -0.908570, 0.000000, 0.417733, -0.479907, 0.000000, 0.607338,
+ -0.950495, 0.310739, 0.000000, -0.553151, 0.185812, 0.262085,
+ -0.933952, 0.305330, 0.185744, -0.545407, 0.183211, 0.343157,
+ -0.904777, 0.295792, 0.306407, -0.524387, 0.176150, 0.428422,
+ -0.879408, 0.287499, 0.379453, -0.493410, 0.165745, 0.516832,
+ -0.863304, 0.282234, 0.418380, -0.455796, 0.153109, 0.607338,
+ -0.808194, 0.588917, 0.000000, -0.471334, 0.345906, 0.262085,
+ -0.794073, 0.578627, 0.186092, -0.464735, 0.341063, 0.343157,
+ -0.769179, 0.560487, 0.306945, -0.446824, 0.327918, 0.428422,
+ -0.747539, 0.544718, 0.380083, -0.420430, 0.308548, 0.516832,
+ -0.733807, 0.534712, 0.419049, -0.388379, 0.285026, 0.607338,
+ -0.588917, 0.808194, 0.000000, -0.345906, 0.471334, 0.262085,
+ -0.578627, 0.794073, 0.186092, -0.341063, 0.464735, 0.343157,
+ -0.560487, 0.769179, 0.306945, -0.327918, 0.446824, 0.428422,
+ -0.544718, 0.747539, 0.380083, -0.308548, 0.420430, 0.516832,
+ -0.534712, 0.733807, 0.419049, -0.285026, 0.388379, 0.607338,
+ -0.310739, 0.950495, 0.000000, -0.185812, 0.553151, 0.262085,
+ -0.305331, 0.933952, 0.185744, -0.183211, 0.545407, 0.343157,
+ -0.295792, 0.904777, 0.306407, -0.176150, 0.524387, 0.428422,
+ -0.287499, 0.879408, 0.379453, -0.165745, 0.493410, 0.516832,
+ -0.282234, 0.863304, 0.418380, -0.153109, 0.455796, 0.607338,
+ 0.653126, 0.000000, -0.757248, 0.451951, 0.000000, 0.062201,
+ 0.999997, 0.000000, 0.000000, 0.436808, 0.000000, 0.043681,
+ 0.950495, -0.310739, 0.000000, 0.414863, -0.139359, 0.043681,
+ 0.620124, -0.202733, -0.757855, 0.429245, -0.144190, 0.062201,
+ 0.653126, 0.000000, -0.757247, 0.488060, 0.000000, 0.092254,
+ 0.620125, -0.202733, -0.757855, 0.463540, -0.155711, 0.092254,
+ 0.761538, 0.000000, -0.648117, 0.531159, 0.000000, 0.134886,
+ 0.723268, -0.236453, -0.648825, 0.504473, -0.169461, 0.134886,
+ 0.915054, 0.000000, -0.403329, 0.567268, 0.000000, 0.191147,
+ 0.869485, -0.284255, -0.403963, 0.538769, -0.180981, 0.191147,
+ 0.808194, -0.588917, 0.000000, 0.353500, -0.259429, 0.043681,
+ 0.526696, -0.383794, -0.758479, 0.365755, -0.268423, 0.062201,
+ 0.526697, -0.383795, -0.758480, 0.394977, -0.289869, 0.092254,
+ 0.614483, -0.447763, -0.649552, 0.429856, -0.315466, 0.134886,
+ 0.739078, -0.538553, -0.404618, 0.459079, -0.336912, 0.191147,
+ 0.588917, -0.808194, 0.000000, 0.259429, -0.353500, 0.043681,
+ 0.383794, -0.526696, -0.758479, 0.268423, -0.365755, 0.062201,
+ 0.383795, -0.526697, -0.758480, 0.289869, -0.394977, 0.092254,
+ 0.447763, -0.614483, -0.649552, 0.315466, -0.429856, 0.134886,
+ 0.538553, -0.739078, -0.404619, 0.336912, -0.459079, 0.191147,
+ 0.310739, -0.950495, 0.000000, 0.139359, -0.414863, 0.043681,
+ 0.202733, -0.620124, -0.757855, 0.144190, -0.429245, 0.062201,
+ 0.202733, -0.620125, -0.757855, 0.155711, -0.463540, 0.092254,
+ 0.236453, -0.723268, -0.648825, 0.169461, -0.504473, 0.134886,
+ 0.284255, -0.869485, -0.403963, 0.180981, -0.538769, 0.191147,
+ 0.000000, -0.999997, 0.000000, 0.000000, -0.436808, 0.043681,
+ 0.000000, -0.653126, -0.757248, 0.000000, -0.451951, 0.062201,
+ 0.000000, -0.653126, -0.757247, 0.000000, -0.488060, 0.092254,
+ 0.000000, -0.761538, -0.648117, 0.000000, -0.531159, 0.134886,
+ 0.000000, -0.915054, -0.403329, 0.000000, -0.567268, 0.191147,
+ 0.000000, 0.653126, -0.757248, 0.000000, 0.451951, 0.062201,
+ 0.000000, 0.999997, 0.000000, 0.000000, 0.436808, 0.043681,
+ 0.310739, 0.950495, 0.000000, 0.139359, 0.414863, 0.043681,
+ 0.202733, 0.620124, -0.757855, 0.144190, 0.429245, 0.062201,
+ 0.000000, 0.653126, -0.757247, 0.000000, 0.488060, 0.092254,
+ 0.202733, 0.620125, -0.757855, 0.155711, 0.463540, 0.092254,
+ 0.000000, 0.761538, -0.648117, 0.000000, 0.531159, 0.134886,
+ 0.236453, 0.723268, -0.648825, 0.169461, 0.504473, 0.134886,
+ 0.000000, 0.915054, -0.403329, 0.000000, 0.567268, 0.191147,
+ 0.284255, 0.869485, -0.403963, 0.180981, 0.538769, 0.191147,
+ 0.588917, 0.808194, 0.000000, 0.259429, 0.353500, 0.043681,
+ 0.383794, 0.526696, -0.758479, 0.268423, 0.365755, 0.062201,
+ 0.383795, 0.526697, -0.758480, 0.289869, 0.394977, 0.092254,
+ 0.447763, 0.614483, -0.649552, 0.315466, 0.429856, 0.134886,
+ 0.538553, 0.739078, -0.404618, 0.336912, 0.459079, 0.191147,
+ 0.808194, 0.588917, 0.000000, 0.353500, 0.259429, 0.043681,
+ 0.526696, 0.383794, -0.758479, 0.365755, 0.268423, 0.062201,
+ 0.526697, 0.383795, -0.758480, 0.394977, 0.289869, 0.092254,
+ 0.614483, 0.447763, -0.649552, 0.429856, 0.315466, 0.134886,
+ 0.739078, 0.538553, -0.404619, 0.459079, 0.336912, 0.191147,
+ 0.950495, 0.310739, 0.000000, 0.414863, 0.139359, 0.043681,
+ 0.620124, 0.202733, -0.757855, 0.429245, 0.144190, 0.062201,
+ 0.620125, 0.202733, -0.757855, 0.463540, 0.155711, 0.092254,
+ 0.723268, 0.236453, -0.648825, 0.504473, 0.169461, 0.134886,
+ 0.869485, 0.284255, -0.403963, 0.538769, 0.180981, 0.191147,
+ -0.310739, -0.950495, 0.000000, -0.139359, -0.414863, 0.043681,
+ -0.202733, -0.620124, -0.757855, -0.144190, -0.429245, 0.062201,
+ -0.202733, -0.620125, -0.757855, -0.155711, -0.463540, 0.092254,
+ -0.236453, -0.723268, -0.648825, -0.169461, -0.504473, 0.134886,
+ -0.284255, -0.869485, -0.403963, -0.180981, -0.538769, 0.191147,
+ -0.588917, -0.808194, 0.000000, -0.259429, -0.353500, 0.043681,
+ -0.383794, -0.526696, -0.758479, -0.268423, -0.365755, 0.062201,
+ -0.383795, -0.526697, -0.758480, -0.289869, -0.394977, 0.092254,
+ -0.447763, -0.614483, -0.649552, -0.315466, -0.429856, 0.134886,
+ -0.538553, -0.739078, -0.404618, -0.336912, -0.459079, 0.191147,
+ -0.808194, -0.588917, 0.000000, -0.353500, -0.259429, 0.043681,
+ -0.526696, -0.383794, -0.758479, -0.365755, -0.268423, 0.062201,
+ -0.526697, -0.383795, -0.758480, -0.394977, -0.289869, 0.092254,
+ -0.614483, -0.447763, -0.649552, -0.429856, -0.315466, 0.134886,
+ -0.739078, -0.538553, -0.404619, -0.459079, -0.336912, 0.191147,
+ -0.950495, -0.310739, 0.000000, -0.414863, -0.139359, 0.043681,
+ -0.620124, -0.202733, -0.757855, -0.429245, -0.144190, 0.062201,
+ -0.620125, -0.202733, -0.757855, -0.463540, -0.155711, 0.092254,
+ -0.723268, -0.236453, -0.648825, -0.504473, -0.169461, 0.134886,
+ -0.869485, -0.284255, -0.403963, -0.538769, -0.180981, 0.191147,
+ -0.999997, 0.000000, 0.000000, -0.436808, 0.000000, 0.043681,
+ -0.653126, 0.000000, -0.757248, -0.451951, 0.000000, 0.062201,
+ -0.653126, 0.000000, -0.757247, -0.488060, 0.000000, 0.092254,
+ -0.761538, 0.000000, -0.648117, -0.531159, 0.000000, 0.134886,
+ -0.915054, 0.000000, -0.403329, -0.567268, 0.000000, 0.191147,
+ -0.950495, 0.310739, 0.000000, -0.414863, 0.139359, 0.043681,
+ -0.620124, 0.202733, -0.757855, -0.429245, 0.144190, 0.062201,
+ -0.620125, 0.202733, -0.757855, -0.463540, 0.155711, 0.092254,
+ -0.723268, 0.236453, -0.648825, -0.504473, 0.169461, 0.134886,
+ -0.869485, 0.284255, -0.403963, -0.538769, 0.180981, 0.191147,
+ -0.808194, 0.588917, 0.000000, -0.353500, 0.259429, 0.043681,
+ -0.526696, 0.383794, -0.758479, -0.365755, 0.268423, 0.062201,
+ -0.526697, 0.383795, -0.758480, -0.394977, 0.289869, 0.092254,
+ -0.614483, 0.447763, -0.649552, -0.429856, 0.315466, 0.134886,
+ -0.739078, 0.538553, -0.404618, -0.459079, 0.336912, 0.191147,
+ -0.588917, 0.808194, 0.000000, -0.259429, 0.353500, 0.043681,
+ -0.383794, 0.526696, -0.758479, -0.268423, 0.365755, 0.062201,
+ -0.383795, 0.526697, -0.758480, -0.289869, 0.394977, 0.092254,
+ -0.447763, 0.614483, -0.649552, -0.315466, 0.429856, 0.134886,
+ -0.538553, 0.739078, -0.404619, -0.336912, 0.459079, 0.191147,
+ -0.310739, 0.950495, 0.000000, -0.139359, 0.414863, 0.043681,
+ -0.202733, 0.620124, -0.757855, -0.144190, 0.429245, 0.062201,
+ -0.202733, 0.620125, -0.757855, -0.155711, 0.463540, 0.092254,
+ -0.236453, 0.723268, -0.648825, -0.169461, 0.504473, 0.134886,
+ -0.284255, 0.869485, -0.403963, -0.180981, 0.538769, 0.191147,
+ 0.894427, 0.000000, -0.447213, 0.052184, 0.000000, 0.816657,
+ 0.600000, 0.000000, 0.800000, 0.058241, 0.000000, 0.786255,
+ 0.569610, -0.186218, 0.800539, 0.055315, -0.018581, 0.786255,
+ 0.849825, -0.277126, -0.448321, 0.049568, -0.016670, 0.816657,
+ 0.732528, 0.000000, -0.680733, 0.079674, 0.000000, 0.851252,
+ 0.695758, -0.226333, -0.681680, 0.075687, -0.025484, 0.851252,
+ 0.934487, 0.000000, -0.355995, 0.104368, 0.000000, 0.883750,
+ 0.888413, -0.288795, -0.356820, 0.099149, -0.033394, 0.883751,
+ 0.360398, 0.000000, 0.932794, 0.089924, 0.000000, 0.907862,
+ 0.342044, -0.111168, 0.933084, 0.085428, -0.028775, 0.907863,
+ 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.917297,
+ 0.483729, -0.352485, 0.801094, 0.047133, -0.034591, 0.786255,
+ 0.722111, -0.525753, -0.449592, 0.042248, -0.031017, 0.816657,
+ 0.590847, -0.429839, -0.682740, 0.064527, -0.047392, 0.851252,
+ 0.755194, -0.549270, -0.357749, 0.084536, -0.062095, 0.883751,
+ 0.290204, -0.211059, 0.933400, 0.072838, -0.053504, 0.907863,
+ 0.352485, -0.483729, 0.801094, 0.034591, -0.047133, 0.786255,
+ 0.525753, -0.722111, -0.449592, 0.031017, -0.042248, 0.816657,
+ 0.429838, -0.590847, -0.682740, 0.047392, -0.064527, 0.851252,
+ 0.549270, -0.755194, -0.357749, 0.062095, -0.084536, 0.883750,
+ 0.211060, -0.290203, 0.933400, 0.053504, -0.072838, 0.907862,
+ 0.186218, -0.569610, 0.800539, 0.018581, -0.055315, 0.786255,
+ 0.277127, -0.849825, -0.448321, 0.016670, -0.049568, 0.816657,
+ 0.226332, -0.695758, -0.681680, 0.025484, -0.075687, 0.851252,
+ 0.288795, -0.888413, -0.356820, 0.033394, -0.099149, 0.883750,
+ 0.111168, -0.342044, 0.933084, 0.028775, -0.085428, 0.907862,
+ 0.000000, -0.600000, 0.800000, 0.000000, -0.058241, 0.786255,
+ 0.000000, -0.894427, -0.447213, 0.000000, -0.052184, 0.816657,
+ 0.000000, -0.732528, -0.680733, 0.000000, -0.079674, 0.851252,
+ 0.000000, -0.934487, -0.355995, 0.000000, -0.104368, 0.883750,
+ 0.000000, -0.360398, 0.932794, 0.000000, -0.089924, 0.907862,
+ 0.000000, 0.894427, -0.447213, 0.000000, 0.052184, 0.816657,
+ 0.000000, 0.600000, 0.800000, 0.000000, 0.058241, 0.786255,
+ 0.186218, 0.569610, 0.800539, 0.018581, 0.055315, 0.786255,
+ 0.277126, 0.849825, -0.448321, 0.016670, 0.049568, 0.816657,
+ 0.000000, 0.732528, -0.680733, 0.000000, 0.079674, 0.851252,
+ 0.226333, 0.695758, -0.681680, 0.025484, 0.075687, 0.851252,
+ 0.000000, 0.934487, -0.355995, 0.000000, 0.104368, 0.883750,
+ 0.288795, 0.888413, -0.356820, 0.033394, 0.099149, 0.883751,
+ 0.000000, 0.360398, 0.932794, 0.000000, 0.089924, 0.907862,
+ 0.111168, 0.342044, 0.933084, 0.028775, 0.085428, 0.907863,
+ 0.352485, 0.483729, 0.801094, 0.034591, 0.047133, 0.786255,
+ 0.525753, 0.722111, -0.449592, 0.031017, 0.042248, 0.816657,
+ 0.429839, 0.590847, -0.682740, 0.047392, 0.064527, 0.851252,
+ 0.549270, 0.755194, -0.357749, 0.062095, 0.084536, 0.883751,
+ 0.211059, 0.290204, 0.933400, 0.053504, 0.072838, 0.907863,
+ 0.483729, 0.352485, 0.801094, 0.047133, 0.034591, 0.786255,
+ 0.722111, 0.525753, -0.449592, 0.042248, 0.031017, 0.816657,
+ 0.590847, 0.429838, -0.682740, 0.064527, 0.047392, 0.851252,
+ 0.755194, 0.549270, -0.357749, 0.084536, 0.062095, 0.883750,
+ 0.290203, 0.211060, 0.933400, 0.072838, 0.053504, 0.907862,
+ 0.569610, 0.186218, 0.800539, 0.055315, 0.018581, 0.786255,
+ 0.849825, 0.277126, -0.448321, 0.049568, 0.016670, 0.816657,
+ 0.695758, 0.226332, -0.681680, 0.075687, 0.025484, 0.851252,
+ 0.888413, 0.288795, -0.356820, 0.099149, 0.033394, 0.883750,
+ 0.342044, 0.111168, 0.933084, 0.085428, 0.028775, 0.907862,
+ -0.186218, -0.569610, 0.800539, -0.018581, -0.055315, 0.786255,
+ -0.277126, -0.849825, -0.448321, -0.016670, -0.049568, 0.816657,
+ -0.226333, -0.695758, -0.681680, -0.025484, -0.075687, 0.851252,
+ -0.288795, -0.888413, -0.356820, -0.033394, -0.099149, 0.883751,
+ -0.111168, -0.342044, 0.933084, -0.028775, -0.085428, 0.907863,
+ -0.352485, -0.483729, 0.801094, -0.034591, -0.047133, 0.786255,
+ -0.525753, -0.722111, -0.449592, -0.031017, -0.042248, 0.816657,
+ -0.429839, -0.590847, -0.682740, -0.047392, -0.064527, 0.851252,
+ -0.549270, -0.755194, -0.357749, -0.062095, -0.084536, 0.883751,
+ -0.211059, -0.290204, 0.933400, -0.053504, -0.072838, 0.907863,
+ -0.483729, -0.352485, 0.801094, -0.047133, -0.034591, 0.786255,
+ -0.722111, -0.525753, -0.449592, -0.042248, -0.031017, 0.816657,
+ -0.590847, -0.429838, -0.682740, -0.064527, -0.047392, 0.851252,
+ -0.755194, -0.549270, -0.357749, -0.084536, -0.062095, 0.883750,
+ -0.290203, -0.211060, 0.933400, -0.072838, -0.053504, 0.907862,
+ -0.569610, -0.186218, 0.800539, -0.055315, -0.018581, 0.786255,
+ -0.849825, -0.277126, -0.448321, -0.049568, -0.016670, 0.816657,
+ -0.695758, -0.226332, -0.681680, -0.075687, -0.025484, 0.851252,
+ -0.888413, -0.288795, -0.356820, -0.099149, -0.033394, 0.883750,
+ -0.342044, -0.111168, 0.933084, -0.085428, -0.028775, 0.907862,
+ -0.600000, 0.000000, 0.800000, -0.058241, 0.000000, 0.786255,
+ -0.894427, 0.000000, -0.447213, -0.052184, 0.000000, 0.816657,
+ -0.732528, 0.000000, -0.680733, -0.079674, 0.000000, 0.851252,
+ -0.934487, 0.000000, -0.355995, -0.104368, 0.000000, 0.883750,
+ -0.360398, 0.000000, 0.932794, -0.089924, 0.000000, 0.907862,
+ -0.569610, 0.186218, 0.800539, -0.055315, 0.018581, 0.786255,
+ -0.849825, 0.277126, -0.448321, -0.049568, 0.016670, 0.816657,
+ -0.695758, 0.226333, -0.681680, -0.075687, 0.025484, 0.851252,
+ -0.888413, 0.288795, -0.356820, -0.099149, 0.033394, 0.883751,
+ -0.342044, 0.111168, 0.933084, -0.085428, 0.028775, 0.907863,
+ -0.483729, 0.352485, 0.801094, -0.047133, 0.034591, 0.786255,
+ -0.722111, 0.525753, -0.449592, -0.042248, 0.031017, 0.816657,
+ -0.590847, 0.429839, -0.682740, -0.064527, 0.047392, 0.851252,
+ -0.755194, 0.549270, -0.357749, -0.084536, 0.062095, 0.883751,
+ -0.290204, 0.211059, 0.933400, -0.072838, 0.053504, 0.907863,
+ -0.352485, 0.483729, 0.801094, -0.034591, 0.047133, 0.786255,
+ -0.525753, 0.722111, -0.449592, -0.031017, 0.042248, 0.816657,
+ -0.429838, 0.590847, -0.682740, -0.047392, 0.064527, 0.851252,
+ -0.549270, 0.755194, -0.357749, -0.062095, 0.084536, 0.883750,
+ -0.211060, 0.290203, 0.933400, -0.053504, 0.072838, 0.907862,
+ -0.186218, 0.569610, 0.800539, -0.018581, 0.055315, 0.786255,
+ -0.277127, 0.849825, -0.448321, -0.016670, 0.049568, 0.816657,
+ -0.226332, 0.695758, -0.681680, -0.025484, 0.075687, 0.851252,
+ -0.288795, 0.888413, -0.356820, -0.033394, 0.099149, 0.883750,
+ -0.111168, 0.342044, 0.933084, -0.028775, 0.085428, 0.907862,
+ 0.325793, 0.000000, 0.945439, 0.350844, 0.000000, 0.720559,
+ 0.999999, 0.000000, 0.000000, 0.378567, 0.000000, 0.698893,
+ 0.950491, -0.310738, 0.000000, 0.359548, -0.120778, 0.698893,
+ 0.309144, -0.101066, 0.945625, 0.333218, -0.111934, 0.720559,
+ 0.165777, 0.000000, 0.986162, 0.282586, 0.000000, 0.735935,
+ 0.157282, -0.051419, 0.986211, 0.268389, -0.090156, 0.735935,
+ 0.152941, 0.000000, 0.988232, 0.196156, 0.000000, 0.749214,
+ 0.145104, -0.047438, 0.988278, 0.186301, -0.062582, 0.749214,
+ 0.238138, 0.000000, 0.971229, 0.113920, 0.000000, 0.764589,
+ 0.225949, -0.073868, 0.971335, 0.108196, -0.036345, 0.764589,
+ 0.808190, -0.588914, 0.000000, 0.306367, -0.224839, 0.698893,
+ 0.262406, -0.191211, 0.945819, 0.283931, -0.208374, 0.720559,
+ 0.133484, -0.097267, 0.986266, 0.228691, -0.167833, 0.735935,
+ 0.123146, -0.089735, 0.988323, 0.158745, -0.116501, 0.749214,
+ 0.191770, -0.139740, 0.971440, 0.092193, -0.067659, 0.764589,
+ 0.588914, -0.808190, 0.000000, 0.224839, -0.306367, 0.698893,
+ 0.191211, -0.262406, 0.945819, 0.208374, -0.283931, 0.720559,
+ 0.097267, -0.133484, 0.986266, 0.167833, -0.228691, 0.735935,
+ 0.089735, -0.123146, 0.988323, 0.116501, -0.158745, 0.749214,
+ 0.139740, -0.191770, 0.971440, 0.067659, -0.092193, 0.764589,
+ 0.310738, -0.950491, 0.000000, 0.120778, -0.359548, 0.698893,
+ 0.101066, -0.309144, 0.945625, 0.111933, -0.333218, 0.720559,
+ 0.051419, -0.157282, 0.986211, 0.090156, -0.268389, 0.735935,
+ 0.047438, -0.145104, 0.988278, 0.062582, -0.186301, 0.749214,
+ 0.073868, -0.225949, 0.971335, 0.036345, -0.108196, 0.764589,
+ 0.000000, -0.999999, 0.000000, 0.000000, -0.378567, 0.698893,
+ 0.000000, -0.325793, 0.945439, 0.000000, -0.350844, 0.720559,
+ 0.000000, -0.165777, 0.986162, 0.000000, -0.282586, 0.735935,
+ 0.000000, -0.152941, 0.988232, 0.000000, -0.196156, 0.749214,
+ 0.000000, -0.238138, 0.971229, 0.000000, -0.113920, 0.764589,
+ 0.000000, 0.325793, 0.945439, 0.000000, 0.350844, 0.720559,
+ 0.000000, 0.999999, 0.000000, 0.000000, 0.378567, 0.698893,
+ 0.310738, 0.950491, 0.000000, 0.120778, 0.359548, 0.698893,
+ 0.101066, 0.309144, 0.945625, 0.111934, 0.333218, 0.720559,
+ 0.000000, 0.165777, 0.986162, 0.000000, 0.282586, 0.735935,
+ 0.051419, 0.157282, 0.986211, 0.090156, 0.268389, 0.735935,
+ 0.000000, 0.152941, 0.988232, 0.000000, 0.196156, 0.749214,
+ 0.047438, 0.145104, 0.988278, 0.062582, 0.186301, 0.749214,
+ 0.000000, 0.238138, 0.971229, 0.000000, 0.113920, 0.764589,
+ 0.073868, 0.225949, 0.971335, 0.036345, 0.108196, 0.764589,
+ 0.588914, 0.808190, 0.000000, 0.224839, 0.306367, 0.698893,
+ 0.191211, 0.262406, 0.945819, 0.208374, 0.283931, 0.720559,
+ 0.097267, 0.133484, 0.986266, 0.167833, 0.228691, 0.735935,
+ 0.089735, 0.123146, 0.988323, 0.116501, 0.158745, 0.749214,
+ 0.139740, 0.191770, 0.971440, 0.067659, 0.092193, 0.764589,
+ 0.808190, 0.588914, 0.000000, 0.306367, 0.224839, 0.698893,
+ 0.262406, 0.191211, 0.945819, 0.283931, 0.208374, 0.720559,
+ 0.133484, 0.097267, 0.986266, 0.228691, 0.167833, 0.735935,
+ 0.123146, 0.089735, 0.988323, 0.158745, 0.116501, 0.749214,
+ 0.191770, 0.139740, 0.971440, 0.092193, 0.067659, 0.764589,
+ 0.950491, 0.310738, 0.000000, 0.359548, 0.120778, 0.698893,
+ 0.309144, 0.101066, 0.945625, 0.333218, 0.111933, 0.720559,
+ 0.157282, 0.051419, 0.986211, 0.268389, 0.090156, 0.735935,
+ 0.145104, 0.047438, 0.988278, 0.186301, 0.062582, 0.749214,
+ 0.225949, 0.073868, 0.971335, 0.108196, 0.036345, 0.764589,
+ -0.310738, -0.950491, 0.000000, -0.120778, -0.359548, 0.698893,
+ -0.101066, -0.309144, 0.945625, -0.111934, -0.333218, 0.720559,
+ -0.051419, -0.157282, 0.986211, -0.090156, -0.268389, 0.735935,
+ -0.047438, -0.145104, 0.988278, -0.062582, -0.186301, 0.749214,
+ -0.073868, -0.225949, 0.971335, -0.036345, -0.108196, 0.764589,
+ -0.588914, -0.808190, 0.000000, -0.224839, -0.306367, 0.698893,
+ -0.191211, -0.262406, 0.945819, -0.208374, -0.283931, 0.720559,
+ -0.097267, -0.133484, 0.986266, -0.167833, -0.228691, 0.735935,
+ -0.089735, -0.123146, 0.988323, -0.116501, -0.158745, 0.749214,
+ -0.139740, -0.191770, 0.971440, -0.067659, -0.092193, 0.764589,
+ -0.808190, -0.588914, 0.000000, -0.306367, -0.224839, 0.698893,
+ -0.262406, -0.191211, 0.945819, -0.283931, -0.208374, 0.720559,
+ -0.133484, -0.097267, 0.986266, -0.228691, -0.167833, 0.735935,
+ -0.123146, -0.089735, 0.988323, -0.158745, -0.116501, 0.749214,
+ -0.191770, -0.139740, 0.971440, -0.092193, -0.067659, 0.764589,
+ -0.950491, -0.310738, 0.000000, -0.359548, -0.120778, 0.698893,
+ -0.309144, -0.101066, 0.945625, -0.333218, -0.111933, 0.720559,
+ -0.157282, -0.051419, 0.986211, -0.268389, -0.090156, 0.735935,
+ -0.145104, -0.047438, 0.988278, -0.186301, -0.062582, 0.749214,
+ -0.225949, -0.073868, 0.971335, -0.108196, -0.036345, 0.764589,
+ -0.999999, 0.000000, 0.000000, -0.378567, 0.000000, 0.698893,
+ -0.325793, 0.000000, 0.945439, -0.350844, 0.000000, 0.720559,
+ -0.165777, 0.000000, 0.986162, -0.282586, 0.000000, 0.735935,
+ -0.152941, 0.000000, 0.988232, -0.196156, 0.000000, 0.749214,
+ -0.238138, 0.000000, 0.971229, -0.113920, 0.000000, 0.764589,
+ -0.950491, 0.310738, 0.000000, -0.359548, 0.120778, 0.698893,
+ -0.309144, 0.101066, 0.945625, -0.333218, 0.111934, 0.720559,
+ -0.157282, 0.051419, 0.986211, -0.268389, 0.090156, 0.735935,
+ -0.145104, 0.047438, 0.988278, -0.186301, 0.062582, 0.749214,
+ -0.225949, 0.073868, 0.971335, -0.108196, 0.036345, 0.764589,
+ -0.808190, 0.588914, 0.000000, -0.306367, 0.224839, 0.698893,
+ -0.262406, 0.191211, 0.945819, -0.283931, 0.208374, 0.720559,
+ -0.133484, 0.097267, 0.986266, -0.228691, 0.167833, 0.735935,
+ -0.123146, 0.089735, 0.988323, -0.158745, 0.116501, 0.749214,
+ -0.191770, 0.139740, 0.971440, -0.092193, 0.067659, 0.764589,
+ -0.588914, 0.808190, 0.000000, -0.224839, 0.306367, 0.698893,
+ -0.191211, 0.262406, 0.945819, -0.208374, 0.283931, 0.720559,
+ -0.097267, 0.133484, 0.986266, -0.167833, 0.228691, 0.735935,
+ -0.089735, 0.123146, 0.988323, -0.116501, 0.158745, 0.749214,
+ -0.139740, 0.191770, 0.971440, -0.067659, 0.092193, 0.764589,
+ -0.310738, 0.950491, 0.000000, -0.120778, 0.359548, 0.698893,
+ -0.101066, 0.309144, 0.945625, -0.111933, 0.333218, 0.720559,
+ -0.051419, 0.157282, 0.986211, -0.090156, 0.268389, 0.735935,
+ -0.047438, 0.145104, 0.988278, -0.062582, 0.186301, 0.749214,
+ -0.073868, 0.225949, 0.971335, -0.036345, 0.108196, 0.764589,
+ 0.000000, -0.664364, -0.747409, 0.000000, -0.431217, 0.030751,
+ 0.206227, -0.630811, -0.748027, 0.137576, -0.409553, 0.030751,
+ 0.000000, -0.232118, -0.972685, 0.000000, -0.402562, 0.018870,
+ 0.072000, -0.220235, -0.972782, 0.128434, -0.382338, 0.018870,
+ 0.000000, -0.087099, -0.996200, 0.000000, -0.333023, 0.009086,
+ 0.027015, -0.082633, -0.996211, 0.106247, -0.316292, 0.009086,
+ 0.000000, -0.028834, -0.999583, 0.000000, -0.204776, 0.002446,
+ 0.008943, -0.027355, -0.999585, 0.065332, -0.194488, 0.002446,
+ 0.000000, 0.000000, -1.000000, 0.000000, 0.000000, 0.000000,
+ 0.390419, -0.535788, -0.748665, 0.256109, -0.348975, 0.030751,
+ 0.136205, -0.186920, -0.972884, 0.239090, -0.325786, 0.018870,
+ 0.051100, -0.070127, -0.996225, 0.197789, -0.269509, 0.009086,
+ 0.016916, -0.023215, -0.999586, 0.121621, -0.165721, 0.002446,
+ 0.535788, -0.390419, -0.748665, 0.348975, -0.256109, 0.030751,
+ 0.186920, -0.136205, -0.972884, 0.325786, -0.239090, 0.018870,
+ 0.070127, -0.051100, -0.996225, 0.269509, -0.197789, 0.009086,
+ 0.023215, -0.016916, -0.999586, 0.165721, -0.121621, 0.002446,
+ 0.630811, -0.206227, -0.748027, 0.409553, -0.137575, 0.030751,
+ 0.220235, -0.072000, -0.972782, 0.382338, -0.128434, 0.018870,
+ 0.082633, -0.027015, -0.996211, 0.316292, -0.106247, 0.009086,
+ 0.027355, -0.008943, -0.999585, 0.194488, -0.065332, 0.002446,
+ 0.664364, 0.000000, -0.747409, 0.431217, 0.000000, 0.030751,
+ 0.232118, 0.000000, -0.972685, 0.402562, 0.000000, 0.018870,
+ 0.087099, 0.000000, -0.996200, 0.333023, 0.000000, 0.009086,
+ 0.028834, 0.000000, -0.999583, 0.204776, 0.000000, 0.002446,
+ 0.630811, 0.206227, -0.748027, 0.409553, 0.137576, 0.030751,
+ 0.220235, 0.072000, -0.972782, 0.382338, 0.128434, 0.018870,
+ 0.082633, 0.027015, -0.996211, 0.316292, 0.106247, 0.009086,
+ 0.027355, 0.008943, -0.999585, 0.194488, 0.065332, 0.002446,
+ 0.535788, 0.390419, -0.748665, 0.348975, 0.256109, 0.030751,
+ 0.186920, 0.136205, -0.972884, 0.325786, 0.239090, 0.018870,
+ 0.070127, 0.051100, -0.996225, 0.269509, 0.197789, 0.009086,
+ 0.023215, 0.016916, -0.999586, 0.165721, 0.121621, 0.002446,
+ 0.390419, 0.535788, -0.748665, 0.256109, 0.348975, 0.030751,
+ 0.136205, 0.186920, -0.972884, 0.239090, 0.325786, 0.018870,
+ 0.051100, 0.070127, -0.996225, 0.197789, 0.269509, 0.009086,
+ 0.016916, 0.023215, -0.999586, 0.121621, 0.165721, 0.002446,
+ 0.206227, 0.630811, -0.748027, 0.137575, 0.409553, 0.030751,
+ 0.072000, 0.220235, -0.972782, 0.128434, 0.382338, 0.018870,
+ 0.027015, 0.082633, -0.996211, 0.106247, 0.316292, 0.009086,
+ 0.008943, 0.027355, -0.999585, 0.065332, 0.194488, 0.002446,
+ 0.000000, 0.664364, -0.747409, 0.000000, 0.431217, 0.030751,
+ 0.000000, 0.232118, -0.972685, 0.000000, 0.402562, 0.018870,
+ 0.000000, 0.087099, -0.996200, 0.000000, 0.333023, 0.009086,
+ 0.000000, 0.028834, -0.999583, 0.000000, 0.204776, 0.002446,
+ -0.664364, 0.000000, -0.747409, -0.431217, 0.000000, 0.030751,
+ -0.630811, -0.206227, -0.748027, -0.409553, -0.137576, 0.030751,
+ -0.232118, 0.000000, -0.972685, -0.402562, 0.000000, 0.018870,
+ -0.220235, -0.072000, -0.972782, -0.382338, -0.128434, 0.018870,
+ -0.087099, 0.000000, -0.996200, -0.333023, 0.000000, 0.009086,
+ -0.082633, -0.027015, -0.996211, -0.316292, -0.106247, 0.009086,
+ -0.028834, 0.000000, -0.999583, -0.204776, 0.000000, 0.002446,
+ -0.027355, -0.008943, -0.999585, -0.194488, -0.065332, 0.002446,
+ -0.535788, -0.390419, -0.748665, -0.348975, -0.256109, 0.030751,
+ -0.186920, -0.136205, -0.972884, -0.325786, -0.239090, 0.018870,
+ -0.070127, -0.051100, -0.996225, -0.269509, -0.197789, 0.009086,
+ -0.023215, -0.016916, -0.999586, -0.165721, -0.121621, 0.002446,
+ -0.390419, -0.535788, -0.748665, -0.256109, -0.348975, 0.030751,
+ -0.136205, -0.186920, -0.972884, -0.239090, -0.325786, 0.018870,
+ -0.051100, -0.070127, -0.996225, -0.197789, -0.269509, 0.009086,
+ -0.016916, -0.023215, -0.999586, -0.121621, -0.165721, 0.002446,
+ -0.206227, -0.630811, -0.748027, -0.137575, -0.409553, 0.030751,
+ -0.072000, -0.220235, -0.972782, -0.128434, -0.382338, 0.018870,
+ -0.027015, -0.082633, -0.996211, -0.106247, -0.316292, 0.009086,
+ -0.008943, -0.027355, -0.999585, -0.065332, -0.194488, 0.002446,
+ -0.206227, 0.630811, -0.748027, -0.137576, 0.409553, 0.030751,
+ -0.072000, 0.220235, -0.972782, -0.128434, 0.382338, 0.018870,
+ -0.027015, 0.082633, -0.996211, -0.106247, 0.316292, 0.009086,
+ -0.008943, 0.027355, -0.999585, -0.065332, 0.194488, 0.002446,
+ -0.390419, 0.535788, -0.748665, -0.256109, 0.348975, 0.030751,
+ -0.136205, 0.186920, -0.972884, -0.239090, 0.325786, 0.018870,
+ -0.051100, 0.070127, -0.996225, -0.197789, 0.269509, 0.009086,
+ -0.016916, 0.023215, -0.999586, -0.121621, 0.165721, 0.002446,
+ -0.535788, 0.390419, -0.748665, -0.348975, 0.256109, 0.030751,
+ -0.186920, 0.136205, -0.972884, -0.325786, 0.239090, 0.018870,
+ -0.070127, 0.051100, -0.996225, -0.269509, 0.197789, 0.009086,
+ -0.023215, 0.016916, -0.999586, -0.165721, 0.121621, 0.002446,
+ -0.630811, 0.206227, -0.748027, -0.409553, 0.137575, 0.030751,
+ -0.220235, 0.072000, -0.972782, -0.382338, 0.128434, 0.018870,
+ -0.082633, 0.027015, -0.996211, -0.316292, 0.106247, 0.009086,
+ -0.027355, 0.008943, -0.999585, -0.194488, 0.065332, 0.002446,
+ 0.678279, 0.000000, -0.734802, -0.772510, 0.000000, 0.556144,
+ 1.000000, 0.000000, 0.000000, -0.786255, 0.000000, 0.524170,
+ 0.882349, -0.470586, 0.000000, -0.795340, -0.041934, 0.524170,
+ 0.629799, -0.445736, -0.636138, -0.781208, -0.041934, 0.559470,
+ 0.257464, 0.000000, -0.966285, -0.732207, 0.000000, 0.575539,
+ 0.252433, -0.388174, -0.886339, -0.739645, -0.041934, 0.580881,
+ 0.080816, 0.000000, -0.996729, -0.666744, 0.000000, 0.585498,
+ 0.079910, -0.370650, -0.925328, -0.671905, -0.041934, 0.591876,
+ 0.015623, 0.000000, -0.999877, -0.577519, 0.000000, 0.589167,
+ 0.015400, -0.370124, -0.928855, -0.579239, -0.041934, 0.595927,
+ 0.000000, 0.000000, -0.999997, -0.465929, 0.000000, 0.589691,
+ 0.000000, -0.371391, -0.928477, -0.462900, -0.041934, 0.596505,
+ 0.384615, -0.923074, 0.000000, -0.817006, -0.062900, 0.524170,
+ 0.298688, -0.917366, -0.263094, -0.801949, -0.062900, 0.567399,
+ 0.140821, -0.889659, -0.434364, -0.757382, -0.062900, 0.593620,
+ 0.046970, -0.875201, -0.481465, -0.684211, -0.062900, 0.607085,
+ 0.009046, -0.873433, -0.486852, -0.583341, -0.062900, 0.612046,
+ 0.000000, -0.874153, -0.485641, -0.455678, -0.062900, 0.612755,
+ -0.384616, -0.923077, 0.000000, -0.842865, -0.062900, 0.524170,
+ -0.308779, -0.920335, 0.240078, -0.826705, -0.062900, 0.576864,
+ -0.153234, -0.894313, 0.420379, -0.778552, -0.062900, 0.608825,
+ -0.052052, -0.876688, 0.478236, -0.698899, -0.062900, 0.625238,
+ -0.010009, -0.873532, 0.486663, -0.588237, -0.062900, 0.631285,
+ 0.000000, -0.874157, 0.485643, -0.447059, -0.062900, 0.632149,
+ -0.882353, -0.470588, 0.000000, -0.864531, -0.041934, 0.524170,
+ -0.718844, -0.467462, 0.514531, -0.847446, -0.041934, 0.584793,
+ -0.333894, -0.411701, 0.847945, -0.796289, -0.041934, 0.621565,
+ -0.107561, -0.377010, 0.919942, -0.711205, -0.041934, 0.640448,
+ -0.020401, -0.370527, 0.928596, -0.592339, -0.041934, 0.647405,
+ 0.000000, -0.371390, 0.928475, -0.439837, -0.041934, 0.648398,
+ -1.000000, 0.000000, 0.000000, -0.873617, 0.000000, 0.524170,
+ -0.821368, 0.000000, 0.570394, -0.856144, 0.000000, 0.588119,
+ -0.375382, 0.000000, 0.926870, -0.803727, 0.000000, 0.626907,
+ -0.119145, 0.000000, 0.992876, -0.716366, 0.000000, 0.646826,
+ -0.022494, 0.000000, 0.999744, -0.594059, 0.000000, 0.654164,
+ 0.000000, 0.000000, 0.999998, -0.436808, 0.000000, 0.655212,
+ -0.882353, 0.470588, 0.000000, -0.864531, 0.041934, 0.524170,
+ -0.718844, 0.467462, 0.514531, -0.847446, 0.041934, 0.584793,
+ -0.333894, 0.411701, 0.847945, -0.796289, 0.041934, 0.621565,
+ -0.107561, 0.377010, 0.919942, -0.711205, 0.041934, 0.640448,
+ -0.020401, 0.370527, 0.928596, -0.592339, 0.041934, 0.647404,
+ 0.000000, 0.371390, 0.928475, -0.439837, 0.041934, 0.648398,
+ -0.384615, 0.923077, 0.000000, -0.842865, 0.062900, 0.524170,
+ -0.308779, 0.920335, 0.240078, -0.826705, 0.062900, 0.576864,
+ -0.153234, 0.894313, 0.420378, -0.778552, 0.062900, 0.608826,
+ -0.052052, 0.876688, 0.478235, -0.698899, 0.062900, 0.625238,
+ -0.010009, 0.873533, 0.486663, -0.588237, 0.062900, 0.631285,
+ 0.000000, 0.874157, 0.485643, -0.447059, 0.062900, 0.632149,
+ 0.384614, 0.923074, 0.000000, -0.817006, 0.062900, 0.524170,
+ 0.298687, 0.917366, -0.263094, -0.801949, 0.062900, 0.567399,
+ 0.140821, 0.889659, -0.434364, -0.757382, 0.062900, 0.593620,
+ 0.046970, 0.875201, -0.481465, -0.684211, 0.062900, 0.607085,
+ 0.009046, 0.873433, -0.486852, -0.583341, 0.062900, 0.612046,
+ 0.000000, 0.874153, -0.485641, -0.455678, 0.062900, 0.612755,
+ 0.882349, 0.470586, 0.000000, -0.795340, 0.041934, 0.524170,
+ 0.629799, 0.445736, -0.636138, -0.781208, 0.041934, 0.559470,
+ 0.252433, 0.388174, -0.886339, -0.739645, 0.041934, 0.580881,
+ 0.079910, 0.370650, -0.925328, -0.671905, 0.041934, 0.591876,
+ 0.015400, 0.370124, -0.928855, -0.579239, 0.041934, 0.595927,
+ 0.000000, 0.371391, -0.928477, -0.462900, 0.041934, 0.596505,
+ 0.611799, 0.000000, 0.791013, -0.659522, 0.000000, 0.308212,
+ 0.379236, -0.382045, 0.842747, -0.579382, -0.041934, 0.252999,
+ 0.558613, -0.364714, 0.744934, -0.660661, -0.041934, 0.300725,
+ 0.769924, 0.000000, 0.638135, -0.717064, 0.000000, 0.363774,
+ 0.691468, -0.406502, 0.597183, -0.721571, -0.041934, 0.357396,
+ 0.884111, 0.000000, 0.467278, -0.756435, 0.000000, 0.422481,
+ 0.781918, -0.451570, 0.429746, -0.763438, -0.041934, 0.417320,
+ 0.962253, 0.000000, 0.272152, -0.779033, 0.000000, 0.478043,
+ 0.846995, -0.471755, 0.245044, -0.787586, -0.041934, 0.474809,
+ 0.194296, -0.880806, 0.431768, -0.572161, -0.062900, 0.231334,
+ 0.280289, -0.873120, 0.398872, -0.663376, -0.062900, 0.282873,
+ 0.322750, -0.896343, 0.303976, -0.732317, -0.062900, 0.342187,
+ 0.344194, -0.916219, 0.205104, -0.780135, -0.062900, 0.405014,
+ 0.366848, -0.923633, 0.111013, -0.807980, -0.062900, 0.467096,
+ -0.194296, -0.880808, -0.431769, -0.563541, -0.062900, 0.205475,
+ -0.265223, -0.876079, -0.402660, -0.666617, -0.062900, 0.261565,
+ -0.307337, -0.897713, -0.315680, -0.745143, -0.062900, 0.324033,
+ -0.335932, -0.916638, -0.216621, -0.800063, -0.062900, 0.390326,
+ -0.365298, -0.923730, -0.115227, -0.832322, -0.062900, 0.457890,
+ -0.379235, -0.382044, -0.842744, -0.556319, -0.041934, 0.183809,
+ -0.493114, -0.377428, -0.783828, -0.669333, -0.041934, 0.243713,
+ -0.614546, -0.413988, -0.671527, -0.755889, -0.041934, 0.308824,
+ -0.736106, -0.454498, -0.501569, -0.816760, -0.041934, 0.378020,
+ -0.838352, -0.472505, -0.271853, -0.852717, -0.041934, 0.450177,
+ -0.410363, 0.000000, -0.911918, -0.553290, 0.000000, 0.174723,
+ -0.525858, 0.000000, -0.850568, -0.670472, 0.000000, 0.236226,
+ -0.666422, 0.000000, -0.745575, -0.760396, 0.000000, 0.302446,
+ -0.820903, 0.000000, -0.571063, -0.823762, 0.000000, 0.372860,
+ -0.950315, 0.000000, -0.311291, -0.861269, 0.000000, 0.446942,
+ -0.379235, 0.382044, -0.842744, -0.556319, 0.041934, 0.183809,
+ -0.493114, 0.377428, -0.783828, -0.669333, 0.041934, 0.243713,
+ -0.614546, 0.413988, -0.671527, -0.755889, 0.041934, 0.308824,
+ -0.736106, 0.454498, -0.501569, -0.816760, 0.041934, 0.378020,
+ -0.838352, 0.472506, -0.271853, -0.852717, 0.041934, 0.450177,
+ -0.194296, 0.880808, -0.431769, -0.563541, 0.062900, 0.205475,
+ -0.265223, 0.876079, -0.402660, -0.666617, 0.062900, 0.261565,
+ -0.307337, 0.897713, -0.315680, -0.745143, 0.062900, 0.324033,
+ -0.335932, 0.916638, -0.216621, -0.800063, 0.062900, 0.390326,
+ -0.365297, 0.923730, -0.115227, -0.832322, 0.062900, 0.457890,
+ 0.194296, 0.880806, 0.431768, -0.572161, 0.062900, 0.231334,
+ 0.280289, 0.873120, 0.398872, -0.663376, 0.062900, 0.282873,
+ 0.322750, 0.896343, 0.303976, -0.732317, 0.062900, 0.342187,
+ 0.344194, 0.916219, 0.205104, -0.780135, 0.062900, 0.405014,
+ 0.366849, 0.923633, 0.111013, -0.807980, 0.062900, 0.467096,
+ 0.379236, 0.382045, 0.842747, -0.579382, 0.041934, 0.252999,
+ 0.558613, 0.364714, 0.744935, -0.660661, 0.041934, 0.300725,
+ 0.691468, 0.406502, 0.597183, -0.721571, 0.041934, 0.357396,
+ 0.781918, 0.451570, 0.429746, -0.763437, 0.041934, 0.417320,
+ 0.846995, 0.471755, 0.245044, -0.787586, 0.041934, 0.474809,
+ -0.901385, 0.000000, 0.433018, 0.736400, 0.000000, 0.635818,
+ -0.599998, 0.000000, 0.799997, 0.786255, 0.000000, 0.698893,
+ -0.456679, -0.584548, 0.670626, 0.804426, -0.034945, 0.698893,
+ -0.695153, -0.572370, 0.434915, 0.748321, -0.040905, 0.633002,
+ -0.948683, 0.000000, 0.316228, 0.708911, 0.000000, 0.561211,
+ -0.806605, -0.470480, 0.357817, 0.718505, -0.055118, 0.553398,
+ -0.836177, 0.000000, 0.548460, 0.677227, 0.000000, 0.489749,
+ -0.703305, -0.462338, 0.539998, 0.685804, -0.072081, 0.475848,
+ -0.417663, 0.000000, 0.908600, 0.614793, 0.000000, 0.436109,
+ -0.336099, -0.511011, 0.791137, 0.621044, -0.086294, 0.416121,
+ 0.000000, 0.000000, 0.999999, 0.495049, 0.000000, 0.414968,
+ -0.020447, -0.554584, 0.831876, 0.495049, -0.092254, 0.389982,
+ -0.163754, -0.943222, 0.288977, 0.847758, -0.052417, 0.698893,
+ -0.216744, -0.928832, 0.300487, 0.776746, -0.061357, 0.626285,
+ -0.225716, -0.923283, 0.310808, 0.741384, -0.082676, 0.534765,
+ -0.144680, -0.927429, 0.344881, 0.706257, -0.108122, 0.442700,
+ -0.052027, -0.935870, 0.348483, 0.635950, -0.129441, 0.368457,
+ -0.023270, -0.948426, 0.316142, 0.495049, -0.138381, 0.330402,
+ 0.161183, -0.928415, -0.334758, 0.899476, -0.052417, 0.698893,
+ 0.293016, -0.956011, -0.013319, 0.810673, -0.061357, 0.618269,
+ 0.490797, -0.869914, 0.048673, 0.768691, -0.082676, 0.512526,
+ 0.538925, -0.840157, -0.060780, 0.730668, -0.108122, 0.403136,
+ 0.312657, -0.914026, -0.258463, 0.653741, -0.129441, 0.311567,
+ 0.037642, -0.948010, -0.316003, 0.495049, -0.138381, 0.259289,
+ 0.354182, -0.453353, -0.817936, 0.942807, -0.034945, 0.698893,
+ 0.714527, -0.579088, -0.392560, 0.839099, -0.040905, 0.611553,
+ 0.875791, -0.442525, -0.192752, 0.791570, -0.055118, 0.493894,
+ 0.854131, -0.405027, -0.326210, 0.751120, -0.072081, 0.369987,
+ 0.550028, -0.485514, -0.679517, 0.668647, -0.086294, 0.263902,
+ 0.123484, -0.550453, -0.825679, 0.495049, -0.092254, 0.199709,
+ 0.384614, 0.000000, -0.923073, 0.960978, 0.000000, 0.698893,
+ 0.840531, 0.000000, -0.541764, 0.851019, 0.000000, 0.608736,
+ 0.962006, 0.000000, -0.273019, 0.801165, 0.000000, 0.486080,
+ 0.916944, 0.000000, -0.399005, 0.759697, 0.000000, 0.356086,
+ 0.608573, 0.000000, -0.793498, 0.674898, 0.000000, 0.243914,
+ 0.158678, 0.000000, -0.987330, 0.495049, 0.000000, 0.174723,
+ 0.354182, 0.453353, -0.817936, 0.942807, 0.034945, 0.698893,
+ 0.714527, 0.579088, -0.392560, 0.839099, 0.040905, 0.611553,
+ 0.875791, 0.442525, -0.192752, 0.791570, 0.055118, 0.493894,
+ 0.854131, 0.405027, -0.326210, 0.751120, 0.072081, 0.369987,
+ 0.550028, 0.485514, -0.679517, 0.668647, 0.086294, 0.263902,
+ 0.123484, 0.550453, -0.825679, 0.495049, 0.092254, 0.199709,
+ 0.161183, 0.928415, -0.334758, 0.899476, 0.052417, 0.698893,
+ 0.293015, 0.956010, -0.013319, 0.810673, 0.061357, 0.618269,
+ 0.490797, 0.869914, 0.048673, 0.768691, 0.082676, 0.512526,
+ 0.538925, 0.840157, -0.060780, 0.730668, 0.108122, 0.403136,
+ 0.312657, 0.914026, -0.258463, 0.653741, 0.129441, 0.311567,
+ 0.037642, 0.948010, -0.316003, 0.495049, 0.138381, 0.259289,
+ -0.163754, 0.943222, 0.288977, 0.847758, 0.052417, 0.698893,
+ -0.216744, 0.928832, 0.300487, 0.776746, 0.061357, 0.626285,
+ -0.225716, 0.923282, 0.310808, 0.741384, 0.082676, 0.534765,
+ -0.144680, 0.927429, 0.344881, 0.706257, 0.108122, 0.442700,
+ -0.052027, 0.935870, 0.348483, 0.635950, 0.129441, 0.368457,
+ -0.023270, 0.948426, 0.316142, 0.495049, 0.138381, 0.330402,
+ -0.456678, 0.584549, 0.670626, 0.804426, 0.034945, 0.698893,
+ -0.695153, 0.572369, 0.434915, 0.748321, 0.040905, 0.633002,
+ -0.806605, 0.470480, 0.357817, 0.718505, 0.055118, 0.553398,
+ -0.703305, 0.462338, 0.539998, 0.685804, 0.072081, 0.475848,
+ -0.336099, 0.511011, 0.791137, 0.621044, 0.086294, 0.416121,
+ -0.020447, 0.554584, 0.831877, 0.495049, 0.092254, 0.389982,
+ 0.849056, 0.000000, -0.528304, 0.826325, 0.000000, 0.709377,
+ 0.599997, 0.000000, -0.800000, 0.815375, 0.000000, 0.698893,
+ 0.439826, 0.625530, -0.644411, 0.827490, -0.020967, 0.698893,
+ 0.516600, 0.831320, -0.205017, 0.841177, -0.022420, 0.709867,
+ 0.472217, 0.000000, 0.881480, 0.826092, 0.000000, 0.714618,
+ 0.224528, 0.423910, 0.877431, 0.843391, -0.025887, 0.715272,
+ -0.215408, 0.000000, 0.976522, 0.817472, 0.000000, 0.714618,
+ -0.168884, -0.217723, 0.961285, 0.836455, -0.030024, 0.715191,
+ -0.439383, 0.000000, 0.898295, 0.803261, 0.000000, 0.709377,
+ -0.334755, -0.458291, 0.823348, 0.822692, -0.033491, 0.709704,
+ 0.149135, 0.954466, -0.258366, 0.856377, -0.031450, 0.698893,
+ 0.123177, 0.962458, 0.241862, 0.876593, -0.033631, 0.711037,
+ 0.021956, 0.416878, 0.908693, 0.884642, -0.038831, 0.716832,
+ -0.082283, -0.381857, 0.920550, 0.881722, -0.045037, 0.716556,
+ -0.131880, -0.781597, 0.609678, 0.869028, -0.050236, 0.710484,
+ -0.147596, 0.944613, 0.293111, 0.890856, -0.031450, 0.698893,
+ -0.127286, 0.787953, 0.602428, 0.918864, -0.033631, 0.712434,
+ -0.079448, 0.324229, 0.942633, 0.933878, -0.038831, 0.718694,
+ 0.054175, -0.554736, 0.830261, 0.935750, -0.045037, 0.718185,
+ 0.150468, -0.980604, 0.125601, 0.924332, -0.050236, 0.711415,
+ -0.360813, 0.513155, 0.778771, 0.919743, -0.020967, 0.698893,
+ -0.285775, 0.419575, 0.861559, 0.954280, -0.022420, 0.713604,
+ -0.149331, 0.185220, 0.971282, 0.975129, -0.025887, 0.720254,
+ 0.459685, -0.738552, 0.493175, 0.981017, -0.030024, 0.719550,
+ 0.445183, -0.620266, -0.645815, 0.970668, -0.033491, 0.712195,
+ -0.410363, 0.000000, 0.911919, 0.931858, 0.000000, 0.698893,
+ -0.335142, 0.000000, 0.942166, 0.969132, 0.000000, 0.714094,
+ -0.180328, 0.000000, 0.983607, 0.992428, 0.000000, 0.720908,
+ 0.980198, 0.000000, -0.198018, 1.000000, 0.000000, 0.720122,
+ 0.487997, 0.000000, -0.872840, 0.990099, 0.000000, 0.712522,
+ -0.360812, -0.513156, 0.778771, 0.919743, 0.020967, 0.698893,
+ -0.285775, -0.419575, 0.861559, 0.954280, 0.022420, 0.713604,
+ -0.149330, -0.185221, 0.971282, 0.975129, 0.025887, 0.720254,
+ 0.459685, 0.738552, 0.493175, 0.981017, 0.030024, 0.719550,
+ 0.445183, 0.620266, -0.645815, 0.970668, 0.033491, 0.712195,
+ -0.147596, -0.944613, 0.293111, 0.890856, 0.031450, 0.698893,
+ -0.127286, -0.787953, 0.602428, 0.918864, 0.033631, 0.712434,
+ -0.079448, -0.324229, 0.942633, 0.933878, 0.038831, 0.718694,
+ 0.054174, 0.554736, 0.830261, 0.935750, 0.045037, 0.718185,
+ 0.150468, 0.980604, 0.125601, 0.924332, 0.050236, 0.711415,
+ 0.149135, -0.954466, -0.258366, 0.856377, 0.031450, 0.698893,
+ 0.123177, -0.962458, 0.241862, 0.876593, 0.033631, 0.711037,
+ 0.021956, -0.416878, 0.908693, 0.884642, 0.038831, 0.716832,
+ -0.082283, 0.381857, 0.920550, 0.881722, 0.045037, 0.716556,
+ -0.131879, 0.781597, 0.609677, 0.869028, 0.050236, 0.710484,
+ 0.439825, -0.625530, -0.644411, 0.827490, 0.020967, 0.698893,
+ 0.516600, -0.831320, -0.205017, 0.841177, 0.022420, 0.709867,
+ 0.224528, -0.423910, 0.877431, 0.843391, 0.025887, 0.715272,
+ -0.168884, 0.217723, 0.961285, 0.836455, 0.030024, 0.715191,
+ -0.334755, 0.458291, 0.823348, 0.822692, 0.033491, 0.709704,
+};
+
+int stripIndices[] = {
+ 12,
+ 1,
+ 2,
+ 0,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 2,
+ 12,
+ 3,
+ 13,
+ 5,
+ 14,
+ 7,
+ 15,
+ 9,
+ 16,
+ 11,
+ 17,
+ 12,
+ 12,
+ 18,
+ 13,
+ 19,
+ 14,
+ 20,
+ 15,
+ 21,
+ 16,
+ 22,
+ 17,
+ 23,
+ 12,
+ 18,
+ 24,
+ 19,
+ 25,
+ 20,
+ 26,
+ 21,
+ 27,
+ 22,
+ 28,
+ 23,
+ 29,
+ 12,
+ 24,
+ 30,
+ 25,
+ 31,
+ 26,
+ 32,
+ 27,
+ 33,
+ 28,
+ 34,
+ 29,
+ 35,
+ 12,
+ 37,
+ 38,
+ 36,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 12,
+ 38,
+ 48,
+ 39,
+ 49,
+ 41,
+ 50,
+ 43,
+ 51,
+ 45,
+ 52,
+ 47,
+ 53,
+ 12,
+ 48,
+ 54,
+ 49,
+ 55,
+ 50,
+ 56,
+ 51,
+ 57,
+ 52,
+ 58,
+ 53,
+ 59,
+ 12,
+ 54,
+ 60,
+ 55,
+ 61,
+ 56,
+ 62,
+ 57,
+ 63,
+ 58,
+ 64,
+ 59,
+ 65,
+ 12,
+ 60,
+ 1,
+ 61,
+ 0,
+ 62,
+ 4,
+ 63,
+ 6,
+ 64,
+ 8,
+ 65,
+ 10,
+ 12,
+ 30,
+ 66,
+ 31,
+ 67,
+ 32,
+ 68,
+ 33,
+ 69,
+ 34,
+ 70,
+ 35,
+ 71,
+ 12,
+ 66,
+ 72,
+ 67,
+ 73,
+ 68,
+ 74,
+ 69,
+ 75,
+ 70,
+ 76,
+ 71,
+ 77,
+ 12,
+ 72,
+ 78,
+ 73,
+ 79,
+ 74,
+ 80,
+ 75,
+ 81,
+ 76,
+ 82,
+ 77,
+ 83,
+ 12,
+ 78,
+ 84,
+ 79,
+ 85,
+ 80,
+ 86,
+ 81,
+ 87,
+ 82,
+ 88,
+ 83,
+ 89,
+ 12,
+ 84,
+ 90,
+ 85,
+ 91,
+ 86,
+ 92,
+ 87,
+ 93,
+ 88,
+ 94,
+ 89,
+ 95,
+ 12,
+ 90,
+ 96,
+ 91,
+ 97,
+ 92,
+ 98,
+ 93,
+ 99,
+ 94,
+ 100,
+ 95,
+ 101,
+ 12,
+ 96,
+ 102,
+ 97,
+ 103,
+ 98,
+ 104,
+ 99,
+ 105,
+ 100,
+ 106,
+ 101,
+ 107,
+ 12,
+ 102,
+ 108,
+ 103,
+ 109,
+ 104,
+ 110,
+ 105,
+ 111,
+ 106,
+ 112,
+ 107,
+ 113,
+ 12,
+ 108,
+ 114,
+ 109,
+ 115,
+ 110,
+ 116,
+ 111,
+ 117,
+ 112,
+ 118,
+ 113,
+ 119,
+ 12,
+ 114,
+ 37,
+ 115,
+ 36,
+ 116,
+ 40,
+ 117,
+ 42,
+ 118,
+ 44,
+ 119,
+ 46,
+ 12,
+ 121,
+ 122,
+ 120,
+ 123,
+ 124,
+ 125,
+ 126,
+ 127,
+ 128,
+ 129,
+ 1,
+ 2,
+ 12,
+ 122,
+ 130,
+ 123,
+ 131,
+ 125,
+ 132,
+ 127,
+ 133,
+ 129,
+ 134,
+ 2,
+ 12,
+ 12,
+ 130,
+ 135,
+ 131,
+ 136,
+ 132,
+ 137,
+ 133,
+ 138,
+ 134,
+ 139,
+ 12,
+ 18,
+ 12,
+ 135,
+ 140,
+ 136,
+ 141,
+ 137,
+ 142,
+ 138,
+ 143,
+ 139,
+ 144,
+ 18,
+ 24,
+ 12,
+ 140,
+ 145,
+ 141,
+ 146,
+ 142,
+ 147,
+ 143,
+ 148,
+ 144,
+ 149,
+ 24,
+ 30,
+ 12,
+ 151,
+ 152,
+ 150,
+ 153,
+ 154,
+ 155,
+ 156,
+ 157,
+ 158,
+ 159,
+ 37,
+ 38,
+ 12,
+ 152,
+ 160,
+ 153,
+ 161,
+ 155,
+ 162,
+ 157,
+ 163,
+ 159,
+ 164,
+ 38,
+ 48,
+ 12,
+ 160,
+ 165,
+ 161,
+ 166,
+ 162,
+ 167,
+ 163,
+ 168,
+ 164,
+ 169,
+ 48,
+ 54,
+ 12,
+ 165,
+ 170,
+ 166,
+ 171,
+ 167,
+ 172,
+ 168,
+ 173,
+ 169,
+ 174,
+ 54,
+ 60,
+ 12,
+ 170,
+ 121,
+ 171,
+ 120,
+ 172,
+ 124,
+ 173,
+ 126,
+ 174,
+ 128,
+ 60,
+ 1,
+ 12,
+ 145,
+ 175,
+ 146,
+ 176,
+ 147,
+ 177,
+ 148,
+ 178,
+ 149,
+ 179,
+ 30,
+ 66,
+ 12,
+ 175,
+ 180,
+ 176,
+ 181,
+ 177,
+ 182,
+ 178,
+ 183,
+ 179,
+ 184,
+ 66,
+ 72,
+ 12,
+ 180,
+ 185,
+ 181,
+ 186,
+ 182,
+ 187,
+ 183,
+ 188,
+ 184,
+ 189,
+ 72,
+ 78,
+ 12,
+ 185,
+ 190,
+ 186,
+ 191,
+ 187,
+ 192,
+ 188,
+ 193,
+ 189,
+ 194,
+ 78,
+ 84,
+ 12,
+ 190,
+ 195,
+ 191,
+ 196,
+ 192,
+ 197,
+ 193,
+ 198,
+ 194,
+ 199,
+ 84,
+ 90,
+ 12,
+ 195,
+ 200,
+ 196,
+ 201,
+ 197,
+ 202,
+ 198,
+ 203,
+ 199,
+ 204,
+ 90,
+ 96,
+ 12,
+ 200,
+ 205,
+ 201,
+ 206,
+ 202,
+ 207,
+ 203,
+ 208,
+ 204,
+ 209,
+ 96,
+ 102,
+ 12,
+ 205,
+ 210,
+ 206,
+ 211,
+ 207,
+ 212,
+ 208,
+ 213,
+ 209,
+ 214,
+ 102,
+ 108,
+ 12,
+ 210,
+ 215,
+ 211,
+ 216,
+ 212,
+ 217,
+ 213,
+ 218,
+ 214,
+ 219,
+ 108,
+ 114,
+ 12,
+ 215,
+ 151,
+ 216,
+ 150,
+ 217,
+ 154,
+ 218,
+ 156,
+ 219,
+ 158,
+ 114,
+ 37,
+ 12,
+ 221,
+ 222,
+ 220,
+ 223,
+ 224,
+ 225,
+ 226,
+ 227,
+ 228,
+ 229,
+ 121,
+ 122,
+ 12,
+ 222,
+ 230,
+ 223,
+ 231,
+ 225,
+ 232,
+ 227,
+ 233,
+ 229,
+ 234,
+ 122,
+ 130,
+ 12,
+ 230,
+ 235,
+ 231,
+ 236,
+ 232,
+ 237,
+ 233,
+ 238,
+ 234,
+ 239,
+ 130,
+ 135,
+ 12,
+ 235,
+ 240,
+ 236,
+ 241,
+ 237,
+ 242,
+ 238,
+ 243,
+ 239,
+ 244,
+ 135,
+ 140,
+ 12,
+ 240,
+ 245,
+ 241,
+ 246,
+ 242,
+ 247,
+ 243,
+ 248,
+ 244,
+ 249,
+ 140,
+ 145,
+ 12,
+ 251,
+ 252,
+ 250,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 258,
+ 259,
+ 151,
+ 152,
+ 12,
+ 252,
+ 260,
+ 253,
+ 261,
+ 255,
+ 262,
+ 257,
+ 263,
+ 259,
+ 264,
+ 152,
+ 160,
+ 12,
+ 260,
+ 265,
+ 261,
+ 266,
+ 262,
+ 267,
+ 263,
+ 268,
+ 264,
+ 269,
+ 160,
+ 165,
+ 12,
+ 265,
+ 270,
+ 266,
+ 271,
+ 267,
+ 272,
+ 268,
+ 273,
+ 269,
+ 274,
+ 165,
+ 170,
+ 12,
+ 270,
+ 221,
+ 271,
+ 220,
+ 272,
+ 224,
+ 273,
+ 226,
+ 274,
+ 228,
+ 170,
+ 121,
+ 12,
+ 245,
+ 275,
+ 246,
+ 276,
+ 247,
+ 277,
+ 248,
+ 278,
+ 249,
+ 279,
+ 145,
+ 175,
+ 12,
+ 275,
+ 280,
+ 276,
+ 281,
+ 277,
+ 282,
+ 278,
+ 283,
+ 279,
+ 284,
+ 175,
+ 180,
+ 12,
+ 280,
+ 285,
+ 281,
+ 286,
+ 282,
+ 287,
+ 283,
+ 288,
+ 284,
+ 289,
+ 180,
+ 185,
+ 12,
+ 285,
+ 290,
+ 286,
+ 291,
+ 287,
+ 292,
+ 288,
+ 293,
+ 289,
+ 294,
+ 185,
+ 190,
+ 12,
+ 290,
+ 295,
+ 291,
+ 296,
+ 292,
+ 297,
+ 293,
+ 298,
+ 294,
+ 299,
+ 190,
+ 195,
+ 12,
+ 295,
+ 300,
+ 296,
+ 301,
+ 297,
+ 302,
+ 298,
+ 303,
+ 299,
+ 304,
+ 195,
+ 200,
+ 12,
+ 300,
+ 305,
+ 301,
+ 306,
+ 302,
+ 307,
+ 303,
+ 308,
+ 304,
+ 309,
+ 200,
+ 205,
+ 12,
+ 305,
+ 310,
+ 306,
+ 311,
+ 307,
+ 312,
+ 308,
+ 313,
+ 309,
+ 314,
+ 205,
+ 210,
+ 12,
+ 310,
+ 315,
+ 311,
+ 316,
+ 312,
+ 317,
+ 313,
+ 318,
+ 314,
+ 319,
+ 210,
+ 215,
+ 12,
+ 315,
+ 251,
+ 316,
+ 250,
+ 317,
+ 254,
+ 318,
+ 256,
+ 319,
+ 258,
+ 215,
+ 151,
+ 12,
+ 321,
+ 322,
+ 320,
+ 323,
+ 324,
+ 325,
+ 326,
+ 327,
+ 328,
+ 329,
+ 330,
+ 330,
+ 12,
+ 322,
+ 331,
+ 323,
+ 332,
+ 325,
+ 333,
+ 327,
+ 334,
+ 329,
+ 335,
+ 330,
+ 330,
+ 12,
+ 331,
+ 336,
+ 332,
+ 337,
+ 333,
+ 338,
+ 334,
+ 339,
+ 335,
+ 340,
+ 330,
+ 330,
+ 12,
+ 336,
+ 341,
+ 337,
+ 342,
+ 338,
+ 343,
+ 339,
+ 344,
+ 340,
+ 345,
+ 330,
+ 330,
+ 12,
+ 341,
+ 346,
+ 342,
+ 347,
+ 343,
+ 348,
+ 344,
+ 349,
+ 345,
+ 350,
+ 330,
+ 330,
+ 12,
+ 352,
+ 353,
+ 351,
+ 354,
+ 355,
+ 356,
+ 357,
+ 358,
+ 359,
+ 360,
+ 330,
+ 330,
+ 12,
+ 353,
+ 361,
+ 354,
+ 362,
+ 356,
+ 363,
+ 358,
+ 364,
+ 360,
+ 365,
+ 330,
+ 330,
+ 12,
+ 361,
+ 366,
+ 362,
+ 367,
+ 363,
+ 368,
+ 364,
+ 369,
+ 365,
+ 370,
+ 330,
+ 330,
+ 12,
+ 366,
+ 371,
+ 367,
+ 372,
+ 368,
+ 373,
+ 369,
+ 374,
+ 370,
+ 375,
+ 330,
+ 330,
+ 12,
+ 371,
+ 321,
+ 372,
+ 320,
+ 373,
+ 324,
+ 374,
+ 326,
+ 375,
+ 328,
+ 330,
+ 330,
+ 12,
+ 346,
+ 376,
+ 347,
+ 377,
+ 348,
+ 378,
+ 349,
+ 379,
+ 350,
+ 380,
+ 330,
+ 330,
+ 12,
+ 376,
+ 381,
+ 377,
+ 382,
+ 378,
+ 383,
+ 379,
+ 384,
+ 380,
+ 385,
+ 330,
+ 330,
+ 12,
+ 381,
+ 386,
+ 382,
+ 387,
+ 383,
+ 388,
+ 384,
+ 389,
+ 385,
+ 390,
+ 330,
+ 330,
+ 12,
+ 386,
+ 391,
+ 387,
+ 392,
+ 388,
+ 393,
+ 389,
+ 394,
+ 390,
+ 395,
+ 330,
+ 330,
+ 12,
+ 391,
+ 396,
+ 392,
+ 397,
+ 393,
+ 398,
+ 394,
+ 399,
+ 395,
+ 400,
+ 330,
+ 330,
+ 12,
+ 396,
+ 401,
+ 397,
+ 402,
+ 398,
+ 403,
+ 399,
+ 404,
+ 400,
+ 405,
+ 330,
+ 330,
+ 12,
+ 401,
+ 406,
+ 402,
+ 407,
+ 403,
+ 408,
+ 404,
+ 409,
+ 405,
+ 410,
+ 330,
+ 330,
+ 12,
+ 406,
+ 411,
+ 407,
+ 412,
+ 408,
+ 413,
+ 409,
+ 414,
+ 410,
+ 415,
+ 330,
+ 330,
+ 12,
+ 411,
+ 416,
+ 412,
+ 417,
+ 413,
+ 418,
+ 414,
+ 419,
+ 415,
+ 420,
+ 330,
+ 330,
+ 12,
+ 416,
+ 352,
+ 417,
+ 351,
+ 418,
+ 355,
+ 419,
+ 357,
+ 420,
+ 359,
+ 330,
+ 330,
+ 12,
+ 422,
+ 423,
+ 421,
+ 424,
+ 425,
+ 426,
+ 427,
+ 428,
+ 429,
+ 430,
+ 321,
+ 322,
+ 12,
+ 423,
+ 431,
+ 424,
+ 432,
+ 426,
+ 433,
+ 428,
+ 434,
+ 430,
+ 435,
+ 322,
+ 331,
+ 12,
+ 431,
+ 436,
+ 432,
+ 437,
+ 433,
+ 438,
+ 434,
+ 439,
+ 435,
+ 440,
+ 331,
+ 336,
+ 12,
+ 436,
+ 441,
+ 437,
+ 442,
+ 438,
+ 443,
+ 439,
+ 444,
+ 440,
+ 445,
+ 336,
+ 341,
+ 12,
+ 441,
+ 446,
+ 442,
+ 447,
+ 443,
+ 448,
+ 444,
+ 449,
+ 445,
+ 450,
+ 341,
+ 346,
+ 12,
+ 452,
+ 453,
+ 451,
+ 454,
+ 455,
+ 456,
+ 457,
+ 458,
+ 459,
+ 460,
+ 352,
+ 353,
+ 12,
+ 453,
+ 461,
+ 454,
+ 462,
+ 456,
+ 463,
+ 458,
+ 464,
+ 460,
+ 465,
+ 353,
+ 361,
+ 12,
+ 461,
+ 466,
+ 462,
+ 467,
+ 463,
+ 468,
+ 464,
+ 469,
+ 465,
+ 470,
+ 361,
+ 366,
+ 12,
+ 466,
+ 471,
+ 467,
+ 472,
+ 468,
+ 473,
+ 469,
+ 474,
+ 470,
+ 475,
+ 366,
+ 371,
+ 12,
+ 471,
+ 422,
+ 472,
+ 421,
+ 473,
+ 425,
+ 474,
+ 427,
+ 475,
+ 429,
+ 371,
+ 321,
+ 12,
+ 446,
+ 476,
+ 447,
+ 477,
+ 448,
+ 478,
+ 449,
+ 479,
+ 450,
+ 480,
+ 346,
+ 376,
+ 12,
+ 476,
+ 481,
+ 477,
+ 482,
+ 478,
+ 483,
+ 479,
+ 484,
+ 480,
+ 485,
+ 376,
+ 381,
+ 12,
+ 481,
+ 486,
+ 482,
+ 487,
+ 483,
+ 488,
+ 484,
+ 489,
+ 485,
+ 490,
+ 381,
+ 386,
+ 12,
+ 486,
+ 491,
+ 487,
+ 492,
+ 488,
+ 493,
+ 489,
+ 494,
+ 490,
+ 495,
+ 386,
+ 391,
+ 12,
+ 491,
+ 496,
+ 492,
+ 497,
+ 493,
+ 498,
+ 494,
+ 499,
+ 495,
+ 500,
+ 391,
+ 396,
+ 12,
+ 496,
+ 501,
+ 497,
+ 502,
+ 498,
+ 503,
+ 499,
+ 504,
+ 500,
+ 505,
+ 396,
+ 401,
+ 12,
+ 501,
+ 506,
+ 502,
+ 507,
+ 503,
+ 508,
+ 504,
+ 509,
+ 505,
+ 510,
+ 401,
+ 406,
+ 12,
+ 506,
+ 511,
+ 507,
+ 512,
+ 508,
+ 513,
+ 509,
+ 514,
+ 510,
+ 515,
+ 406,
+ 411,
+ 12,
+ 511,
+ 516,
+ 512,
+ 517,
+ 513,
+ 518,
+ 514,
+ 519,
+ 515,
+ 520,
+ 411,
+ 416,
+ 12,
+ 516,
+ 452,
+ 517,
+ 451,
+ 518,
+ 455,
+ 519,
+ 457,
+ 520,
+ 459,
+ 416,
+ 352,
+ 12,
+ 245,
+ 240,
+ 521,
+ 522,
+ 523,
+ 524,
+ 525,
+ 526,
+ 527,
+ 528,
+ 529,
+ 529,
+ 12,
+ 240,
+ 235,
+ 522,
+ 530,
+ 524,
+ 531,
+ 526,
+ 532,
+ 528,
+ 533,
+ 529,
+ 529,
+ 12,
+ 235,
+ 230,
+ 530,
+ 534,
+ 531,
+ 535,
+ 532,
+ 536,
+ 533,
+ 537,
+ 529,
+ 529,
+ 12,
+ 230,
+ 222,
+ 534,
+ 538,
+ 535,
+ 539,
+ 536,
+ 540,
+ 537,
+ 541,
+ 529,
+ 529,
+ 12,
+ 222,
+ 221,
+ 538,
+ 542,
+ 539,
+ 543,
+ 540,
+ 544,
+ 541,
+ 545,
+ 529,
+ 529,
+ 12,
+ 221,
+ 270,
+ 542,
+ 546,
+ 543,
+ 547,
+ 544,
+ 548,
+ 545,
+ 549,
+ 529,
+ 529,
+ 12,
+ 270,
+ 265,
+ 546,
+ 550,
+ 547,
+ 551,
+ 548,
+ 552,
+ 549,
+ 553,
+ 529,
+ 529,
+ 12,
+ 265,
+ 260,
+ 550,
+ 554,
+ 551,
+ 555,
+ 552,
+ 556,
+ 553,
+ 557,
+ 529,
+ 529,
+ 12,
+ 260,
+ 252,
+ 554,
+ 558,
+ 555,
+ 559,
+ 556,
+ 560,
+ 557,
+ 561,
+ 529,
+ 529,
+ 12,
+ 252,
+ 251,
+ 558,
+ 562,
+ 559,
+ 563,
+ 560,
+ 564,
+ 561,
+ 565,
+ 529,
+ 529,
+ 12,
+ 295,
+ 290,
+ 566,
+ 567,
+ 568,
+ 569,
+ 570,
+ 571,
+ 572,
+ 573,
+ 529,
+ 529,
+ 12,
+ 290,
+ 285,
+ 567,
+ 574,
+ 569,
+ 575,
+ 571,
+ 576,
+ 573,
+ 577,
+ 529,
+ 529,
+ 12,
+ 285,
+ 280,
+ 574,
+ 578,
+ 575,
+ 579,
+ 576,
+ 580,
+ 577,
+ 581,
+ 529,
+ 529,
+ 12,
+ 280,
+ 275,
+ 578,
+ 582,
+ 579,
+ 583,
+ 580,
+ 584,
+ 581,
+ 585,
+ 529,
+ 529,
+ 12,
+ 275,
+ 245,
+ 582,
+ 521,
+ 583,
+ 523,
+ 584,
+ 525,
+ 585,
+ 527,
+ 529,
+ 529,
+ 12,
+ 251,
+ 315,
+ 562,
+ 586,
+ 563,
+ 587,
+ 564,
+ 588,
+ 565,
+ 589,
+ 529,
+ 529,
+ 12,
+ 315,
+ 310,
+ 586,
+ 590,
+ 587,
+ 591,
+ 588,
+ 592,
+ 589,
+ 593,
+ 529,
+ 529,
+ 12,
+ 310,
+ 305,
+ 590,
+ 594,
+ 591,
+ 595,
+ 592,
+ 596,
+ 593,
+ 597,
+ 529,
+ 529,
+ 12,
+ 305,
+ 300,
+ 594,
+ 598,
+ 595,
+ 599,
+ 596,
+ 600,
+ 597,
+ 601,
+ 529,
+ 529,
+ 12,
+ 300,
+ 295,
+ 598,
+ 566,
+ 599,
+ 568,
+ 600,
+ 570,
+ 601,
+ 572,
+ 529,
+ 529,
+ 12,
+ 603,
+ 604,
+ 602,
+ 605,
+ 606,
+ 607,
+ 608,
+ 609,
+ 610,
+ 611,
+ 612,
+ 613,
+ 12,
+ 604,
+ 614,
+ 605,
+ 615,
+ 607,
+ 616,
+ 609,
+ 617,
+ 611,
+ 618,
+ 613,
+ 619,
+ 12,
+ 614,
+ 620,
+ 615,
+ 621,
+ 616,
+ 622,
+ 617,
+ 623,
+ 618,
+ 624,
+ 619,
+ 625,
+ 12,
+ 620,
+ 626,
+ 621,
+ 627,
+ 622,
+ 628,
+ 623,
+ 629,
+ 624,
+ 630,
+ 625,
+ 631,
+ 12,
+ 626,
+ 632,
+ 627,
+ 633,
+ 628,
+ 634,
+ 629,
+ 635,
+ 630,
+ 636,
+ 631,
+ 637,
+ 12,
+ 632,
+ 638,
+ 633,
+ 639,
+ 634,
+ 640,
+ 635,
+ 641,
+ 636,
+ 642,
+ 637,
+ 643,
+ 12,
+ 638,
+ 644,
+ 639,
+ 645,
+ 640,
+ 646,
+ 641,
+ 647,
+ 642,
+ 648,
+ 643,
+ 649,
+ 12,
+ 644,
+ 650,
+ 645,
+ 651,
+ 646,
+ 652,
+ 647,
+ 653,
+ 648,
+ 654,
+ 649,
+ 655,
+ 12,
+ 650,
+ 656,
+ 651,
+ 657,
+ 652,
+ 658,
+ 653,
+ 659,
+ 654,
+ 660,
+ 655,
+ 661,
+ 12,
+ 656,
+ 603,
+ 657,
+ 602,
+ 658,
+ 606,
+ 659,
+ 608,
+ 660,
+ 610,
+ 661,
+ 612,
+ 12,
+ 195,
+ 663,
+ 662,
+ 664,
+ 665,
+ 666,
+ 667,
+ 668,
+ 669,
+ 670,
+ 603,
+ 604,
+ 12,
+ 663,
+ 671,
+ 664,
+ 672,
+ 666,
+ 673,
+ 668,
+ 674,
+ 670,
+ 675,
+ 604,
+ 614,
+ 12,
+ 671,
+ 676,
+ 672,
+ 677,
+ 673,
+ 678,
+ 674,
+ 679,
+ 675,
+ 680,
+ 614,
+ 620,
+ 12,
+ 676,
+ 681,
+ 677,
+ 682,
+ 678,
+ 683,
+ 679,
+ 684,
+ 680,
+ 685,
+ 620,
+ 626,
+ 12,
+ 681,
+ 686,
+ 682,
+ 687,
+ 683,
+ 688,
+ 684,
+ 689,
+ 685,
+ 690,
+ 626,
+ 632,
+ 12,
+ 686,
+ 691,
+ 687,
+ 692,
+ 688,
+ 693,
+ 689,
+ 694,
+ 690,
+ 695,
+ 632,
+ 638,
+ 12,
+ 691,
+ 696,
+ 692,
+ 697,
+ 693,
+ 698,
+ 694,
+ 699,
+ 695,
+ 700,
+ 638,
+ 644,
+ 12,
+ 696,
+ 701,
+ 697,
+ 702,
+ 698,
+ 703,
+ 699,
+ 704,
+ 700,
+ 705,
+ 644,
+ 650,
+ 12,
+ 701,
+ 706,
+ 702,
+ 707,
+ 703,
+ 708,
+ 704,
+ 709,
+ 705,
+ 710,
+ 650,
+ 656,
+ 12,
+ 706,
+ 195,
+ 707,
+ 662,
+ 708,
+ 665,
+ 709,
+ 667,
+ 710,
+ 669,
+ 656,
+ 603,
+ 12,
+ 712,
+ 713,
+ 711,
+ 714,
+ 715,
+ 716,
+ 717,
+ 718,
+ 719,
+ 720,
+ 721,
+ 722,
+ 12,
+ 713,
+ 723,
+ 714,
+ 724,
+ 716,
+ 725,
+ 718,
+ 726,
+ 720,
+ 727,
+ 722,
+ 728,
+ 12,
+ 723,
+ 729,
+ 724,
+ 730,
+ 725,
+ 731,
+ 726,
+ 732,
+ 727,
+ 733,
+ 728,
+ 734,
+ 12,
+ 729,
+ 735,
+ 730,
+ 736,
+ 731,
+ 737,
+ 732,
+ 738,
+ 733,
+ 739,
+ 734,
+ 740,
+ 12,
+ 735,
+ 741,
+ 736,
+ 742,
+ 737,
+ 743,
+ 738,
+ 744,
+ 739,
+ 745,
+ 740,
+ 746,
+ 12,
+ 741,
+ 747,
+ 742,
+ 748,
+ 743,
+ 749,
+ 744,
+ 750,
+ 745,
+ 751,
+ 746,
+ 752,
+ 12,
+ 747,
+ 753,
+ 748,
+ 754,
+ 749,
+ 755,
+ 750,
+ 756,
+ 751,
+ 757,
+ 752,
+ 758,
+ 12,
+ 753,
+ 759,
+ 754,
+ 760,
+ 755,
+ 761,
+ 756,
+ 762,
+ 757,
+ 763,
+ 758,
+ 764,
+ 12,
+ 759,
+ 765,
+ 760,
+ 766,
+ 761,
+ 767,
+ 762,
+ 768,
+ 763,
+ 769,
+ 764,
+ 770,
+ 12,
+ 765,
+ 712,
+ 766,
+ 711,
+ 767,
+ 715,
+ 768,
+ 717,
+ 769,
+ 719,
+ 770,
+ 721,
+ 12,
+ 772,
+ 773,
+ 771,
+ 774,
+ 775,
+ 776,
+ 777,
+ 778,
+ 779,
+ 780,
+ 712,
+ 713,
+ 12,
+ 773,
+ 781,
+ 774,
+ 782,
+ 776,
+ 783,
+ 778,
+ 784,
+ 780,
+ 785,
+ 713,
+ 723,
+ 12,
+ 781,
+ 786,
+ 782,
+ 787,
+ 783,
+ 788,
+ 784,
+ 789,
+ 785,
+ 790,
+ 723,
+ 729,
+ 12,
+ 786,
+ 791,
+ 787,
+ 792,
+ 788,
+ 793,
+ 789,
+ 794,
+ 790,
+ 795,
+ 729,
+ 735,
+ 12,
+ 791,
+ 796,
+ 792,
+ 797,
+ 793,
+ 798,
+ 794,
+ 799,
+ 795,
+ 800,
+ 735,
+ 741,
+ 12,
+ 796,
+ 801,
+ 797,
+ 802,
+ 798,
+ 803,
+ 799,
+ 804,
+ 800,
+ 805,
+ 741,
+ 747,
+ 12,
+ 801,
+ 806,
+ 802,
+ 807,
+ 803,
+ 808,
+ 804,
+ 809,
+ 805,
+ 810,
+ 747,
+ 753,
+ 12,
+ 806,
+ 811,
+ 807,
+ 812,
+ 808,
+ 813,
+ 809,
+ 814,
+ 810,
+ 815,
+ 753,
+ 759,
+ 12,
+ 811,
+ 816,
+ 812,
+ 817,
+ 813,
+ 818,
+ 814,
+ 819,
+ 815,
+ 820,
+ 759,
+ 765,
+ 12,
+ 816,
+ 772,
+ 817,
+ 771,
+ 818,
+ 775,
+ 819,
+ 777,
+ 820,
+ 779,
+ 765,
+ 712,
+ 0
+};
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+TeapotTest::runOne(TeapotResult& res, Window& w) {
+
+ glCullFace(GL_BACK);
+ glDepthFunc(GL_LESS);
+
+
+// glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
+
+ glEnable(GL_LIGHT0);
+ glLightfv(GL_LIGHT0, GL_POSITION, position);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, lights[lightWhite].specular);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE,lights[lightWhite].diffuse);
+ glLightfv(GL_LIGHT0, GL_AMBIENT,lights[lightWhite].ambient);
+
+ glEnable(GL_LIGHT1);
+ glLightfv(GL_LIGHT1, GL_POSITION, position2);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, lights[lightBlue].specular);
+ glLightfv(GL_LIGHT1, GL_DIFFUSE,lights[lightBlue].diffuse);
+ glLightfv(GL_LIGHT1, GL_AMBIENT,lights[lightBlue].ambient);
+
+ glFrontFace(GL_CW);
+
+ glShadeModel(GL_SMOOTH);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+
+// glEnable(GL_AUTO_NORMAL);
+// glEnable(GL_NORMALIZE);
+
+ glMaterialf(GL_FRONT, GL_SHININESS, 0.6*128.0);
+
+ glClearColor(bgColor[0],bgColor[1],bgColor[2], 1.0);
+ glColor3f(1.0, 1.0, 1.0);
+
+ glViewport(0, 0, (GLint)fWidth, (GLint)fHeight);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ const float scale=1.0;
+
+ glOrtho(-scale, scale, -scale, scale, -scale*depthOfView, scale*depthOfView);
+////////////////////////////////// End of Viewport Set-up /////////////////////
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ int color = 4;
+ float c[3][4];
+ c[0][0] = materials[color].ambient[0];
+ c[0][1] = materials[color].ambient[1];
+ c[0][2] = materials[color].ambient[2];
+ c[1][0] = materials[color].diffuse[0];
+ c[1][1] = materials[color].diffuse[1];
+ c[1][2] = materials[color].diffuse[2];
+ c[2][0] = materials[color].specular[0];
+ c[2][1] = materials[color].specular[1];
+ c[2][2] = materials[color].specular[2];
+
+ const int solidity = 0;
+ float alpha;
+ if (solidity == 0)
+ alpha = 1.0;
+ else if (solidity == 1)
+ alpha = 0.95;
+ else if (solidity == 2)
+ alpha = 0.6;
+ c[0][3] = c[1][3] = c[2][3] = alpha;
+
+ if (solidity != 0) {
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+ glEnable(GL_BLEND);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_CULL_FACE);
+ } else {
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+ }
+
+ glMaterialfv(GL_FRONT, GL_AMBIENT, c[0]);
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, c[1]);
+ glMaterialfv(GL_FRONT, GL_SPECULAR, c[2]);
+
+///////////////////////// End of materials set-up //////////////////////
+
+ glInterleavedArrays( GL_N3F_V3F, 0, vertexArrayData );
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glEnableClientState( GL_NORMAL_ARRAY );
+
+
+ // XXX The timing code here doesn't calibrate the timer
+ // overhead, doesn't scale the size of the test to insure
+ // consistent results on a wide range of hardware, and doesn't
+ // flush the pipeline before or after rendering, so the
+ // numbers that result are only a rough approximation of the
+ // actual performance. A better solution would be to use the
+ // timing methodology that's illustrated in tchgperf.cpp.
+
+ Timer tTimer;
+ double start = tTimer.getClock();
+
+ const int startX = 0;
+ const int endX = 360;
+
+ for (int rotX=startX; rotX < endX; rotX++) {
+ glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT );
+ glPushMatrix();
+ glRotatef(rotX, 1.0,0.0,0.0);
+ glRotatef(rotX, 0.0,1.0,0.0);
+
+ for (int* p = stripIndices; *p; ) {
+ glBegin(GL_QUAD_STRIP);
+ for (int nVertices = *p++; nVertices; --nVertices, ++p)
+ glArrayElement(*p);
+ glEnd();
+ }
+ w.swap();
+ glPopMatrix();
+ }
+
+ double finish = tTimer.getClock();
+
+ res.fTps = (endX - startX) / (finish - start);
+ res.pass = true;
+} // TeapotTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+TeapotTest::logOne(TeapotResult& r) {
+ logPassFail(r);
+ env->log << "Teapots/Sec: " << r.fTps << " ";
+ logConcise(r);
+} // TeapotTest::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+TeapotTest::compareOne(TeapotResult& oldR, TeapotResult& newR) {
+ comparePassFail(oldR, newR);
+ if (oldR.pass == newR.pass) {
+ if (env->options.verbosity)
+ env->log << "\tTeapots Comparison: "
+ << oldR.fTps
+ << " vs. "
+ << newR.fTps
+ << '\n';
+ } else {
+ env->log << "\tTeapots Comparison: "
+ << oldR.fTps
+ << " vs. "
+ << newR.fTps
+ << '\n';
+ }
+} // TeapotTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+TeapotTest teapotTest("teapot", "window, rgb, z",
+ "This test simply displays a teapot, rotates it, and attempts to\n"
+ "determine the frame/sec the pipeline can generate\n");
+
+} // namespace GLEAN
diff --git a/tests/glean/tteapot.h b/tests/glean/tteapot.h
new file mode 100644
index 00000000..0840a4f7
--- /dev/null
+++ b/tests/glean/tteapot.h
@@ -0,0 +1,63 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Adam Haberlach All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+#ifndef __tteapot_h_
+#define __tteapot_h_
+
+#include "tbase.h"
+
+
+// Simple teapot-drawing benchmark provided by Adam Haberlach.
+
+namespace GLEAN {
+
+class TeapotResult: public BaseResult {
+public:
+ bool pass;
+ double fTps; // speed in "Teapots per Second"
+
+ void putresults(ostream& s) const {
+ s << pass << '\n';
+ s << fTps << '\n';
+ }
+
+ bool getresults(istream& s) {
+ s >> pass;
+ s >> fTps;
+ return s.good();
+ }
+};
+
+class TeapotTest: public BaseTest<TeapotResult> {
+public:
+ GLEAN_CLASS_WH(TeapotTest, TeapotResult, 300, 315);
+};
+
+} // namespace GLEAN
+
+#endif // __tteapot_h_
diff --git a/tests/glean/ttexcombine.cpp b/tests/glean/ttexcombine.cpp
new file mode 100644
index 00000000..ed2ed33b
--- /dev/null
+++ b/tests/glean/ttexcombine.cpp
@@ -0,0 +1,1584 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// ttexcombine.cpp: Test the GL_EXT_texture_env_combine extension
+// Author: Brian Paul (brianp@valinux.com) September 2000
+//
+// GL_EXT_texture_env_dot3 extension test
+// Author: Gareth Hughes (gareth@valinux.com) January 2001
+//
+// GL_ARB_texture_env_crossbar extension test
+// Author: Brian Paul (brian@tungstengraphics.com) December 2002
+//
+// The challenge with testing this extension is dealing with combinatorial
+// explosion. There are 16 state variables in this extension:
+//
+// GL_COMBINE_RGB_EXT which has 5 possible values
+// GL_COMBINE_ALPHA_EXT which has 5 possible values
+// GL_SOURCE0_RGB_EXT which has 4 possible values
+// GL_SOURCE1_RGB_EXT which has 4 possible values
+// GL_SOURCE2_RGB_EXT which has 4 possible values
+// GL_SOURCE0_ALPHA_EXT which has 4 possible values
+// GL_SOURCE1_ALPHA_EXT which has 4 possible values
+// GL_SOURCE2_ALPHA_EXT which has 4 possible values
+// GL_OPERAND0_RGB_EXT which has 4 possible values
+// GL_OPERAND1_RGB_EXT which has 4 possible values
+// GL_OPERAND2_RGB_EXT which has 2 possible values
+// GL_OPERAND0_ALPHA_EXT which has 2 possible values
+// GL_OPERAND1_ALPHA_EXT which has 2 possible values
+// GL_OPERAND2_ALPHA_EXT which has 1 possible value
+// GL_RGB_SCALE_EXT which has 3 possible values
+// GL_ALPHA_SCALE which has 3 possible values
+//
+// The product of those values is 117,964,800. And that's just for one
+// texture unit! If we wanted to fully exercise N texture units we'd
+// need to run 117,964,800 ^ N tests! Ideally we'd also like to test
+// with a number of different fragment, texenv and texture colors.
+// Clearly we can't test everything.
+//
+// So, we've partitioned the combination space into subsets defined
+// by the ReplaceParams[], AddParams[], InterpolateParams[], etc arrays.
+// For multitexture, we do an even more limited set of tests: testing
+// all permutations of the 5 combine modes on all texture units.
+//
+// In the future we might look at programs that use the combine
+// extension to see which mode combination are important to them and
+// put them into this test.
+//
+
+#include "ttexcombine.h"
+#include <cassert>
+#include <stdio.h>
+#include <cmath>
+
+#define CLAMP(VAL, MIN, MAX) \
+ ((VAL) < (MIN) ? (MIN) : ((VAL) > (MAX) ? (MAX) : (VAL)))
+
+#define COPY4(DST, SRC) \
+{ \
+ (DST)[0] = (SRC)[0]; \
+ (DST)[1] = (SRC)[1]; \
+ (DST)[2] = (SRC)[2]; \
+ (DST)[3] = (SRC)[3]; \
+}
+
+
+namespace GLEAN {
+
+//
+// These objects define the space of tex-env combinations that we exercise.
+// Each array element is { state-var, { list of possible values, 0 } }.
+//
+
+TexCombineTest::test_param TexCombineTest::ReplaceParams[] = {
+ { GL_COMBINE_RGB_EXT, { GL_REPLACE, 0 } },
+ { GL_COMBINE_ALPHA_EXT, { GL_REPLACE, 0 } },
+ { GL_SOURCE0_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE0_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_OPERAND0_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND0_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_RGB_SCALE_EXT, { 1, 2, 4, 0 } },
+ { GL_ALPHA_SCALE, { 1, 2, 4, 0 } },
+ { 0, { 0, 0, 0, 0, 0 } }
+};
+
+TexCombineTest::test_param TexCombineTest::AddParams[] = {
+ { GL_COMBINE_RGB_EXT, { GL_ADD, 0 } },
+ { GL_COMBINE_ALPHA_EXT, { GL_ADD, 0 } },
+ { GL_SOURCE0_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE1_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE0_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE1_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_OPERAND0_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND0_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_RGB_SCALE_EXT, { 1, 2, 4, 0 } },
+ { GL_ALPHA_SCALE, { 1, 2, 4, 0 } },
+ { 0, { 0, 0, 0, 0, 0 } }
+};
+
+TexCombineTest::test_param TexCombineTest::ModulateParams[] = {
+ { GL_COMBINE_RGB_EXT, { GL_MODULATE, 0 } },
+ { GL_COMBINE_ALPHA_EXT, { GL_MODULATE, 0 } },
+ { GL_SOURCE0_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE0_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_OPERAND0_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND0_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_RGB_SCALE_EXT, { 1, 2, 4, 0 } },
+ { GL_ALPHA_SCALE, { 1, 2, 4, 0 } },
+ { 0, { 0, 0, 0, 0, 0 } }
+};
+
+TexCombineTest::test_param TexCombineTest::AddSignedParams[] = {
+ { GL_COMBINE_RGB_EXT, { GL_ADD_SIGNED_EXT, 0 } },
+ { GL_COMBINE_ALPHA_EXT, { GL_ADD_SIGNED_EXT, 0 } },
+ { GL_SOURCE0_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE0_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_OPERAND0_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND0_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_RGB_SCALE_EXT, { 1, 2, 4, 0 } },
+ { GL_ALPHA_SCALE, { 1, 2, 4, 0 } },
+ { 0, { 0, 0, 0, 0, 0 } }
+};
+
+TexCombineTest::test_param TexCombineTest::InterpolateParams[] = {
+ { GL_COMBINE_RGB_EXT, { GL_INTERPOLATE_EXT, 0 } },
+ { GL_COMBINE_ALPHA_EXT, { GL_INTERPOLATE_EXT, 0 } },
+ { GL_SOURCE0_RGB_EXT, { GL_TEXTURE, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE2_RGB_EXT, { GL_TEXTURE, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE0_ALPHA_EXT, { GL_TEXTURE, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE2_ALPHA_EXT, { GL_TEXTURE, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_OPERAND0_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND2_RGB_EXT, { GL_SRC_ALPHA, 0 } },
+ { GL_OPERAND0_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND2_ALPHA_EXT, { GL_SRC_ALPHA, 0 } },
+ { GL_RGB_SCALE_EXT, { 1, 4, 0 } },
+ { GL_ALPHA_SCALE, { 1, 2, 0 } },
+ { 0, { 0, 0, 0, 0, 0 } }
+};
+
+TexCombineTest::test_param TexCombineTest::Dot3RGBParams[] = {
+ { GL_COMBINE_RGB_EXT, { GL_DOT3_RGB_EXT, 0 } },
+ { GL_COMBINE_ALPHA_EXT, { GL_MODULATE, 0 } },
+ { GL_SOURCE0_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE0_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_OPERAND0_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND0_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_RGB_SCALE_EXT, { 1, 2, 4, 0 } },
+ { GL_ALPHA_SCALE, { 1, 2, 4, 0 } },
+ { 0, { 0, 0, 0, 0, 0 } }
+};
+
+TexCombineTest::test_param TexCombineTest::Dot3RGBAParams[] = {
+ { GL_COMBINE_RGB_EXT, { GL_DOT3_RGBA_EXT, 0 } },
+ { GL_COMBINE_ALPHA_EXT, { GL_MODULATE, 0 } },
+ { GL_SOURCE0_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_RGB_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_SOURCE0_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, 0 } },
+ { GL_SOURCE1_ALPHA_EXT, { GL_TEXTURE, GL_CONSTANT_EXT, GL_PRIMARY_COLOR_EXT, GL_PREVIOUS_EXT, 0 } },
+ { GL_OPERAND0_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_RGB_EXT, { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND0_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_OPERAND1_ALPHA_EXT, { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 0 } },
+ { GL_RGB_SCALE_EXT, { 1, 2, 4, 0 } },
+ { GL_ALPHA_SCALE, { 1, 2, 4, 0 } },
+ { 0, { 0, 0, 0, 0, 0 } }
+};
+
+
+static void
+problem(const char *s) {
+ cerr << "Problem in combine():" << s << "\n";
+}
+
+
+//
+// Set machine parameters to default values.
+//
+void
+TexCombineTest::ResetMachine(glmachine &machine) {
+ for (int u = 0; u < MAX_TEX_UNITS; u++) {
+ machine.COMBINE_RGB[u] = GL_MODULATE;
+ machine.COMBINE_ALPHA[u] = GL_MODULATE;
+ machine.SOURCE0_RGB[u] = GL_TEXTURE;
+ machine.SOURCE1_RGB[u] = GL_PREVIOUS_EXT;
+ machine.SOURCE2_RGB[u] = GL_CONSTANT_EXT;
+ machine.SOURCE0_ALPHA[u] = GL_TEXTURE;
+ machine.SOURCE1_ALPHA[u] = GL_PREVIOUS_EXT;
+ machine.SOURCE2_ALPHA[u] = GL_CONSTANT_EXT;
+ machine.OPERAND0_RGB[u] = GL_SRC_COLOR;
+ machine.OPERAND1_RGB[u] = GL_SRC_COLOR;
+ machine.OPERAND2_RGB[u] = GL_SRC_ALPHA;
+ machine.OPERAND0_ALPHA[u] = GL_SRC_ALPHA;
+ machine.OPERAND1_ALPHA[u] = GL_SRC_ALPHA;
+ machine.OPERAND2_ALPHA[u] = GL_SRC_ALPHA;
+ machine.RGB_SCALE[u] = 1.0;
+ machine.ALPHA_SCALE[u] = 1.0;
+ machine.TexFormat[u] = GL_RGBA;
+ }
+}
+
+
+//
+// This computes the expected texcombine result for one texture unit.
+//
+void
+TexCombineTest::ComputeTexCombine(const glmachine &machine, int texUnit,
+ const GLfloat prevColor[4],
+ GLfloat result[4]) const {
+ GLfloat term0[4], term1[4], term2[4], dot;
+ const GLfloat *colorSrc0, *colorSrc1, *colorSrc2;
+ const GLfloat *alphaSrc0, *alphaSrc1 = NULL, *alphaSrc2 = NULL;
+ const GLfloat *fragColor = machine.FragColor;
+ const GLfloat *constColor = machine.EnvColor[texUnit];
+ const GLfloat *texColor = machine.TexColor[texUnit];
+ int srcUnit;
+
+ switch (machine.SOURCE0_RGB[texUnit]) {
+ case GL_PRIMARY_COLOR_EXT:
+ colorSrc0 = fragColor;
+ break;
+ case GL_TEXTURE:
+ colorSrc0 = texColor;
+ break;
+ case GL_CONSTANT_EXT:
+ colorSrc0 = constColor;
+ break;
+ case GL_PREVIOUS_EXT:
+ colorSrc0 = prevColor;
+ break;
+ case GL_TEXTURE0_ARB:
+ case GL_TEXTURE1_ARB:
+ case GL_TEXTURE2_ARB:
+ case GL_TEXTURE3_ARB:
+ case GL_TEXTURE4_ARB:
+ case GL_TEXTURE5_ARB:
+ case GL_TEXTURE6_ARB:
+ case GL_TEXTURE7_ARB:
+ /* GL_ARB_texture_env_crossbar */
+ srcUnit = machine.SOURCE0_RGB[texUnit] - GL_TEXTURE0_ARB;
+ colorSrc0 = machine.TexColor[srcUnit];
+ break;
+ default:
+ problem("bad rgbSource0");
+ return;
+ }
+
+ switch (machine.SOURCE0_ALPHA[texUnit]) {
+ case GL_PRIMARY_COLOR_EXT:
+ alphaSrc0 = fragColor;
+ break;
+ case GL_TEXTURE:
+ alphaSrc0 = texColor;
+ break;
+ case GL_CONSTANT_EXT:
+ alphaSrc0 = constColor;
+ break;
+ case GL_PREVIOUS_EXT:
+ alphaSrc0 = prevColor;
+ break;
+ case GL_TEXTURE0_ARB:
+ case GL_TEXTURE1_ARB:
+ case GL_TEXTURE2_ARB:
+ case GL_TEXTURE3_ARB:
+ case GL_TEXTURE4_ARB:
+ case GL_TEXTURE5_ARB:
+ case GL_TEXTURE6_ARB:
+ case GL_TEXTURE7_ARB:
+ /* GL_ARB_texture_env_crossbar */
+ srcUnit = machine.SOURCE0_ALPHA[texUnit] - GL_TEXTURE0_ARB;
+ alphaSrc0 = machine.TexColor[srcUnit];
+ break;
+ default:
+ problem("bad alphaSource0");
+ return;
+ }
+
+ switch (machine.SOURCE1_RGB[texUnit]) {
+ case GL_PRIMARY_COLOR_EXT:
+ colorSrc1 = fragColor;
+ break;
+ case GL_TEXTURE:
+ colorSrc1 = texColor;
+ break;
+ case GL_CONSTANT_EXT:
+ colorSrc1 = constColor;
+ break;
+ case GL_PREVIOUS_EXT:
+ colorSrc1 = prevColor;
+ break;
+ case GL_TEXTURE0_ARB:
+ case GL_TEXTURE1_ARB:
+ case GL_TEXTURE2_ARB:
+ case GL_TEXTURE3_ARB:
+ case GL_TEXTURE4_ARB:
+ case GL_TEXTURE5_ARB:
+ case GL_TEXTURE6_ARB:
+ case GL_TEXTURE7_ARB:
+ /* GL_ARB_texture_env_crossbar */
+ srcUnit = machine.SOURCE1_RGB[texUnit] - GL_TEXTURE0_ARB;
+ colorSrc1 = machine.TexColor[srcUnit];
+ break;
+ default:
+ problem("bad rgbSource1");
+ return;
+ }
+
+ switch (machine.SOURCE1_ALPHA[texUnit]) {
+ case GL_PRIMARY_COLOR_EXT:
+ alphaSrc1 = fragColor;
+ break;
+ case GL_TEXTURE:
+ alphaSrc1 = texColor;
+ break;
+ case GL_CONSTANT_EXT:
+ alphaSrc1 = constColor;
+ break;
+ case GL_PREVIOUS_EXT:
+ alphaSrc1 = prevColor;
+ break;
+ case GL_TEXTURE0_ARB:
+ case GL_TEXTURE1_ARB:
+ case GL_TEXTURE2_ARB:
+ case GL_TEXTURE3_ARB:
+ case GL_TEXTURE4_ARB:
+ case GL_TEXTURE5_ARB:
+ case GL_TEXTURE6_ARB:
+ case GL_TEXTURE7_ARB:
+ /* GL_ARB_texture_env_crossbar */
+ srcUnit = machine.SOURCE1_ALPHA[texUnit] - GL_TEXTURE0_ARB;
+ alphaSrc1 = machine.TexColor[srcUnit];
+ break;
+ default:
+ problem("bad alphaSource1");
+ return;
+ }
+
+ switch (machine.SOURCE2_RGB[texUnit]) {
+ case GL_PRIMARY_COLOR_EXT:
+ colorSrc2 = fragColor;
+ break;
+ case GL_TEXTURE:
+ colorSrc2 = texColor;
+ break;
+ case GL_CONSTANT_EXT:
+ colorSrc2 = constColor;
+ break;
+ case GL_PREVIOUS_EXT:
+ colorSrc2 = prevColor;
+ break;
+ case GL_TEXTURE0_ARB:
+ case GL_TEXTURE1_ARB:
+ case GL_TEXTURE2_ARB:
+ case GL_TEXTURE3_ARB:
+ case GL_TEXTURE4_ARB:
+ case GL_TEXTURE5_ARB:
+ case GL_TEXTURE6_ARB:
+ case GL_TEXTURE7_ARB:
+ /* GL_ARB_texture_env_crossbar */
+ srcUnit = machine.SOURCE2_RGB[texUnit] - GL_TEXTURE0_ARB;
+ colorSrc2 = machine.TexColor[srcUnit];
+ break;
+ default:
+ problem("bad rgbSource2");
+ return;
+ }
+
+ switch (machine.SOURCE2_ALPHA[texUnit]) {
+ case GL_PRIMARY_COLOR_EXT:
+ alphaSrc2 = fragColor;
+ break;
+ case GL_TEXTURE:
+ alphaSrc2 = texColor;
+ break;
+ case GL_CONSTANT_EXT:
+ alphaSrc2 = constColor;
+ break;
+ case GL_PREVIOUS_EXT:
+ alphaSrc2 = prevColor;
+ break;
+ case GL_TEXTURE0_ARB:
+ case GL_TEXTURE1_ARB:
+ case GL_TEXTURE2_ARB:
+ case GL_TEXTURE3_ARB:
+ case GL_TEXTURE4_ARB:
+ case GL_TEXTURE5_ARB:
+ case GL_TEXTURE6_ARB:
+ case GL_TEXTURE7_ARB:
+ /* GL_ARB_texture_env_crossbar */
+ srcUnit = machine.SOURCE2_ALPHA[texUnit] - GL_TEXTURE0_ARB;
+ alphaSrc2 = machine.TexColor[srcUnit];
+ break;
+ default:
+ problem("bad alphaSource2");
+ return;
+ }
+
+ switch (machine.OPERAND0_RGB[texUnit]) {
+ case GL_SRC_COLOR:
+ term0[0] = colorSrc0[0];
+ term0[1] = colorSrc0[1];
+ term0[2] = colorSrc0[2];
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ term0[0] = 1.0 - colorSrc0[0];
+ term0[1] = 1.0 - colorSrc0[1];
+ term0[2] = 1.0 - colorSrc0[2];
+ break;
+ case GL_SRC_ALPHA:
+ term0[0] = colorSrc0[3];
+ term0[1] = colorSrc0[3];
+ term0[2] = colorSrc0[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ term0[0] = 1.0 - colorSrc0[3];
+ term0[1] = 1.0 - colorSrc0[3];
+ term0[2] = 1.0 - colorSrc0[3];
+ break;
+ default:
+ problem("bad rgbOperand0");
+ return;
+ }
+
+ switch (machine.OPERAND0_ALPHA[texUnit]) {
+ case GL_SRC_ALPHA:
+ term0[3] = alphaSrc0[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ term0[3] = 1.0 - alphaSrc0[3];
+ break;
+ default:
+ problem("bad alphaOperand0");
+ return;
+ }
+
+ switch (machine.OPERAND1_RGB[texUnit]) {
+ case GL_SRC_COLOR:
+ term1[0] = colorSrc1[0];
+ term1[1] = colorSrc1[1];
+ term1[2] = colorSrc1[2];
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ term1[0] = 1.0 - colorSrc1[0];
+ term1[1] = 1.0 - colorSrc1[1];
+ term1[2] = 1.0 - colorSrc1[2];
+ break;
+ case GL_SRC_ALPHA:
+ term1[0] = colorSrc1[3];
+ term1[1] = colorSrc1[3];
+ term1[2] = colorSrc1[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ term1[0] = 1.0 - colorSrc1[3];
+ term1[1] = 1.0 - colorSrc1[3];
+ term1[2] = 1.0 - colorSrc1[3];
+ break;
+ default:
+ problem("bad rgbOperand1");
+ return;
+ }
+
+ switch (machine.OPERAND1_ALPHA[texUnit]) {
+ case GL_SRC_ALPHA:
+ term1[3] = alphaSrc1[3];
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ term1[3] = 1.0 - alphaSrc1[3];
+ break;
+ default:
+ problem("bad alphaOperand1");
+ return;
+ }
+
+ switch (machine.OPERAND2_RGB[texUnit]) {
+ case GL_SRC_ALPHA:
+ term2[0] = colorSrc2[3];
+ term2[1] = colorSrc2[3];
+ term2[2] = colorSrc2[3];
+ break;
+ default:
+ problem("bad rgbOperand2");
+ return;
+ }
+
+ switch (machine.OPERAND2_ALPHA[texUnit]) {
+ case GL_SRC_ALPHA:
+ term2[3] = alphaSrc2[3];
+ break;
+ default:
+ problem("bad alphaOperand2");
+ return;
+ }
+
+ // Final combine
+ switch (machine.COMBINE_RGB[texUnit]) {
+ case GL_REPLACE:
+ result[0] = term0[0];
+ result[1] = term0[1];
+ result[2] = term0[2];
+ break;
+ case GL_MODULATE:
+ result[0] = term0[0] * term1[0];
+ result[1] = term0[1] * term1[1];
+ result[2] = term0[2] * term1[2];
+ break;
+ case GL_ADD:
+ result[0] = term0[0] + term1[0];
+ result[1] = term0[1] + term1[1];
+ result[2] = term0[2] + term1[2];
+ break;
+ case GL_ADD_SIGNED_EXT:
+ result[0] = term0[0] + term1[0] - 0.5;
+ result[1] = term0[1] + term1[1] - 0.5;
+ result[2] = term0[2] + term1[2] - 0.5;
+ break;
+ case GL_INTERPOLATE_EXT:
+ result[0] = term0[0] * term2[0] + term1[0] * (1.0 - term2[0]);
+ result[1] = term0[1] * term2[1] + term1[1] * (1.0 - term2[1]);
+ result[2] = term0[2] * term2[2] + term1[2] * (1.0 - term2[2]);
+ break;
+ case GL_DOT3_RGB_EXT:
+ case GL_DOT3_RGBA_EXT:
+ dot = ((term0[0] - 0.5) * (term1[0] - 0.5) +
+ (term0[1] - 0.5) * (term1[1] - 0.5) +
+ (term0[2] - 0.5) * (term1[2] - 0.5));
+ result[0] = dot;
+ result[1] = dot;
+ result[2] = dot;
+ if (machine.COMBINE_RGB[texUnit] == GL_DOT3_RGBA_EXT)
+ result[3] = dot;
+ break;
+ default:
+ problem("bad rgbCombine");
+ return;
+ }
+
+ switch (machine.COMBINE_ALPHA[texUnit]) {
+ case GL_REPLACE:
+ result[3] = term0[3];
+ break;
+ case GL_MODULATE:
+ result[3] = term0[3] * term1[3];
+ break;
+ case GL_ADD:
+ result[3] = term0[3] + term1[3];
+ break;
+ case GL_ADD_SIGNED_EXT:
+ result[3] = term0[3] + term1[3] - 0.5;
+ break;
+ case GL_INTERPOLATE_EXT:
+ result[3] = term0[3] * term2[3] + term1[3] * (1.0 - term2[3]);
+ break;
+ default:
+ problem("bad alphaCombine");
+ return;
+ }
+
+ if (machine.COMBINE_RGB[texUnit] == GL_DOT3_RGBA_EXT) {
+ result[3] = result[0];
+ }
+
+
+ // scaling
+ // GH: Remove this crud when the ARB extension is done. It
+ // most likely won't have this scale factor restriction.
+ switch (machine.COMBINE_RGB[texUnit]) {
+ case GL_DOT3_RGB_EXT:
+ case GL_DOT3_RGBA_EXT:
+ result[0] *= 4.0;
+ result[1] *= 4.0;
+ result[2] *= 4.0;
+ break;
+ default:
+ result[0] *= machine.RGB_SCALE[texUnit];
+ result[1] *= machine.RGB_SCALE[texUnit];
+ result[2] *= machine.RGB_SCALE[texUnit];
+ break;
+ }
+ switch (machine.COMBINE_RGB[texUnit]) {
+ case GL_DOT3_RGBA_EXT:
+ result[3] *= 4.0;
+ break;
+ default:
+ result[3] *= machine.ALPHA_SCALE[texUnit];
+ break;
+ }
+
+ // final clamping
+ result[0] = CLAMP(result[0], 0.0, 1.0);
+ result[1] = CLAMP(result[1], 0.0, 1.0);
+ result[2] = CLAMP(result[2], 0.0, 1.0);
+ result[3] = CLAMP(result[3], 0.0, 1.0);
+}
+
+
+//
+// Return string for an enum value.
+//
+const char *
+EnumString(GLenum pname)
+{
+ static char s[100];
+ switch (pname) {
+ case GL_COMBINE_RGB_EXT:
+ return "GL_COMBINE_RGB_EXT";
+ case GL_COMBINE_ALPHA_EXT:
+ return "GL_COMBINE_ALPHA_EXT";
+ case GL_REPLACE:
+ return "GL_REPLACE";
+ case GL_MODULATE:
+ return "GL_MODULATE";
+ case GL_ADD:
+ return "GL_ADD";
+ case GL_ADD_SIGNED_EXT:
+ return "GL_ADD_SIGNED_EXT";
+ case GL_INTERPOLATE_EXT:
+ return "GL_INTERPOLATE_EXT";
+ case GL_DOT3_RGB_EXT:
+ return "GL_DOT3_RGB_EXT";
+ case GL_DOT3_RGBA_EXT:
+ return "GL_DOT3_RGBA_EXT";
+ case GL_TEXTURE:
+ return "GL_TEXTURE";
+ case GL_CONSTANT_EXT:
+ return "GL_CONSTANT_EXT";
+ case GL_PRIMARY_COLOR_EXT:
+ return "GL_PRIMARY_COLOR_EXT";
+ case GL_PREVIOUS_EXT:
+ return "GL_PREVIOUS_EXT";
+ case GL_SRC_COLOR:
+ return "GL_SRC_COLOR";
+ case GL_ONE_MINUS_SRC_COLOR:
+ return "GL_ONE_MINUS_SRC_COLOR";
+ case GL_SRC_ALPHA:
+ return "GL_SRC_ALPHA";
+ case GL_ONE_MINUS_SRC_ALPHA:
+ return "GL_ONE_MINUS_SRC_ALPHA";
+ case GL_TEXTURE0_ARB:
+ return "GL_TEXTURE0_ARB";
+ case GL_TEXTURE1_ARB:
+ return "GL_TEXTURE1_ARB";
+ case GL_TEXTURE2_ARB:
+ return "GL_TEXTURE2_ARB";
+ case GL_TEXTURE3_ARB:
+ return "GL_TEXTURE3_ARB";
+ case GL_TEXTURE4_ARB:
+ return "GL_TEXTURE4_ARB";
+ case GL_TEXTURE5_ARB:
+ return "GL_TEXTURE5_ARB";
+ case GL_TEXTURE6_ARB:
+ return "GL_TEXTURE6_ARB";
+ case GL_TEXTURE7_ARB:
+ return "GL_TEXTURE7_ARB";
+ default:
+ sprintf(s, "0x%04x", (unsigned int) pname);
+ return s;
+ }
+}
+
+
+//
+// Print current values of all machine state vars.
+// Used when reporting failures.
+//
+void
+TexCombineTest::PrintMachineState(const glmachine &machine) const {
+
+ env->log << "\tCurrent combine state:\n";
+ env->log << "\tIncoming Fragment RGBA = "
+ << machine.FragColor[0] << ", "
+ << machine.FragColor[1] << ", "
+ << machine.FragColor[2] << ", "
+ << machine.FragColor[3] << "\n";
+ for (int u = 0; u < machine.NumTexUnits; u++) {
+ env->log << "\tTexture Unit " << u << ":\n";
+ env->log << "\t GL_COMBINE_RGB_EXT = "
+ << EnumString(machine.COMBINE_RGB[u]) << "\n";
+ env->log << "\t GL_COMBINE_ALPHA_EXT = "
+ << EnumString(machine.COMBINE_ALPHA[u]) << "\n";
+ env->log << "\t GL_SOURCE0_RGB_EXT = "
+ << EnumString(machine.SOURCE0_RGB[u]) << "\n";
+ env->log << "\t GL_SOURCE1_RGB_EXT = "
+ << EnumString(machine.SOURCE1_RGB[u]) << "\n";
+ env->log << "\t GL_SOURCE2_RGB_EXT = "
+ << EnumString(machine.SOURCE2_RGB[u]) << "\n";
+ env->log << "\t GL_SOURCE0_ALPHA_EXT = "
+ << EnumString(machine.SOURCE0_ALPHA[u]) << "\n";
+ env->log << "\t GL_SOURCE1_ALPHA_EXT = "
+ << EnumString(machine.SOURCE1_ALPHA[u]) << "\n";
+ env->log << "\t GL_SOURCE2_ALPHA_EXT = "
+ << EnumString(machine.SOURCE2_ALPHA[u]) << "\n";
+ env->log << "\t GL_OPERAND0_RGB_EXT = "
+ << EnumString(machine.OPERAND0_RGB[u]) << "\n";
+ env->log << "\t GL_OPERAND1_RGB_EXT = "
+ << EnumString(machine.OPERAND1_RGB[u]) << "\n";
+ env->log << "\t GL_OPERAND2_RGB_EXT = "
+ << EnumString(machine.OPERAND2_RGB[u]) << "\n";
+ env->log << "\t GL_OPERAND0_ALPHA_EXT = "
+ << EnumString(machine.OPERAND0_ALPHA[u]) << "\n";
+ env->log << "\t GL_OPERAND1_ALPHA_EXT = "
+ << EnumString(machine.OPERAND1_ALPHA[u]) << "\n";
+ env->log << "\t GL_OPERAND2_ALPHA_EXT = "
+ << EnumString(machine.OPERAND2_ALPHA[u]) << "\n";
+ env->log << "\t GL_RGB_SCALE_EXT = "
+ << machine.RGB_SCALE[u] << "\n";
+ env->log << "\t GL_ALPHA_SCALE = "
+ << machine.ALPHA_SCALE[u] << "\n";
+ env->log << "\t Tex Env RGBA = "
+ << machine.EnvColor[u][0] << ", "
+ << machine.EnvColor[u][1] << ", "
+ << machine.EnvColor[u][2] << ", "
+ << machine.EnvColor[u][3] << "\n";
+ switch (machine.TexFormat[u]) {
+ case GL_ALPHA:
+ env->log << "\t Texture ALPHA = "
+ << machine.TexColor[u][3] << "\n";
+ break;
+ case GL_LUMINANCE:
+ env->log << "\t Texture LUMINANCE = "
+ << machine.TexColor[u][0] << "\n";
+ break;
+ case GL_LUMINANCE_ALPHA:
+ env->log << "\t Texture RGBA = "
+ << machine.TexColor[u][0] << ", "
+ << machine.TexColor[u][3] << "\n";
+ break;
+ case GL_INTENSITY:
+ env->log << "\t Texture INTENSITY = "
+ << machine.TexColor[u][0] << "\n";
+ break;
+ case GL_RGB:
+ env->log << "\t Texture RGB = "
+ << machine.TexColor[u][0] << ", "
+ << machine.TexColor[u][1] << ", "
+ << machine.TexColor[u][2] << "\n";
+ break;
+ case GL_RGBA:
+ env->log << "\t Texture RGBA = "
+ << machine.TexColor[u][0] << ", "
+ << machine.TexColor[u][1] << ", "
+ << machine.TexColor[u][2] << ", "
+ << machine.TexColor[u][3] << "\n";
+ break;
+ }
+
+ }
+}
+
+
+//
+// Check that the actual GL implementation's texture state matches what's
+// in the given glean machine state. This is only used for debugging.
+//
+bool
+TexCombineTest::VerifyMachineState(const glmachine &machine) const {
+
+#define VERIFY(var, expected) \
+ glGetTexEnviv(GL_TEXTURE_ENV, var, &actual); \
+ if ((GLint) (expected) != (actual)) { \
+ cerr << "Expected " << var << " = " \
+ << EnumString(expected) \
+ << " but got " \
+ << EnumString(actual) \
+ << "\n"; \
+ return false; \
+ }
+#define VERIFYF(var, expected) \
+ glGetTexEnvfv(GL_TEXTURE_ENV, var, &actualf); \
+ if ((expected) != (actualf)) { \
+ cerr << "Expected " << var << " = " \
+ << expected \
+ << " but got " \
+ << actualf \
+ << "\n"; \
+ return false; \
+ }
+
+
+ for (int u = 0; u < machine.NumTexUnits; u++) {
+ GLint actual;
+ GLfloat actualf;
+ VERIFY(GL_COMBINE_RGB_EXT, machine.COMBINE_RGB[u]);
+ VERIFY(GL_COMBINE_ALPHA_EXT, machine.COMBINE_ALPHA[u]);
+ VERIFY(GL_SOURCE0_RGB_EXT, machine.SOURCE0_RGB[u]);
+ VERIFY(GL_SOURCE1_RGB_EXT, machine.SOURCE1_RGB[u]);
+ VERIFY(GL_SOURCE2_RGB_EXT, machine.SOURCE2_RGB[u]);
+ VERIFY(GL_OPERAND0_RGB_EXT, machine.OPERAND0_RGB[u]);
+ VERIFY(GL_OPERAND1_RGB_EXT, machine.OPERAND1_RGB[u]);
+ VERIFY(GL_OPERAND2_RGB_EXT, machine.OPERAND2_RGB[u]);
+ VERIFYF(GL_RGB_SCALE_EXT, machine.RGB_SCALE[u]);
+ VERIFYF(GL_ALPHA_SCALE, machine.ALPHA_SCALE[u]);
+ }
+
+ return true; // state is AOK
+}
+
+
+//
+// Print an error report.
+//
+void
+TexCombineTest::ReportFailure(const glmachine &machine,
+ const GLfloat expected[4],
+ const GLfloat rendered[4],
+ BasicResult& r,
+ const char *where) {
+
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n'
+ << "\texpected "
+ << expected[0] << ", "
+ << expected[1] << ", "
+ << expected[2] << ", "
+ << expected[3] << ", got "
+ << rendered[0] << ", "
+ << rendered[1] << ", "
+ << rendered[2] << ", "
+ << rendered[3]
+ << " in " << where << "\n";
+ PrintMachineState(machine);
+}
+
+
+//
+// Examine a set of test params and compute the number of possible
+// state combinations.
+//
+int
+TexCombineTest::CountTestCombinations(const test_param testParams[]) const {
+
+ int numTests = 1;
+ for (int t = 0; testParams[t].target; t++) {
+ int values = 0;
+ for (int val = 0; testParams[t].validValues[val]; val++) {
+ values++;
+ }
+ numTests *= values;
+ }
+ return numTests;
+}
+
+
+//
+// Setup the actual GL state and our internal simulated GL state.
+//
+void
+TexCombineTest::TexEnv(glmachine &machine, int texUnit,
+ GLenum target, GLenum value) {
+
+ if (machine.NumTexUnits > 1)
+ p_glActiveTextureARB(GL_TEXTURE0_ARB + texUnit);
+
+ glTexEnvi(GL_TEXTURE_ENV, target, value);
+ int err = glGetError();
+ if (err != GL_NO_ERROR)
+ printf("Problem: glTexEnvi() generated error 0x%x\n", err);
+
+ switch (target) {
+ case GL_COMBINE_RGB_EXT:
+ machine.COMBINE_RGB[texUnit] = value;
+ break;
+ case GL_COMBINE_ALPHA_EXT:
+ machine.COMBINE_ALPHA[texUnit] = value;
+ break;
+ case GL_SOURCE0_RGB_EXT:
+ machine.SOURCE0_RGB[texUnit] = value;
+ break;
+ case GL_SOURCE1_RGB_EXT:
+ machine.SOURCE1_RGB[texUnit] = value;
+ break;
+ case GL_SOURCE2_RGB_EXT:
+ machine.SOURCE2_RGB[texUnit] = value;
+ break;
+ case GL_SOURCE0_ALPHA_EXT:
+ machine.SOURCE0_ALPHA[texUnit] = value;
+ break;
+ case GL_SOURCE1_ALPHA_EXT:
+ machine.SOURCE1_ALPHA[texUnit] = value;
+ break;
+ case GL_SOURCE2_ALPHA_EXT:
+ machine.SOURCE2_ALPHA[texUnit] = value;
+ break;
+ case GL_OPERAND0_RGB_EXT:
+ machine.OPERAND0_RGB[texUnit] = value;
+ break;
+ case GL_OPERAND1_RGB_EXT:
+ machine.OPERAND1_RGB[texUnit] = value;
+ break;
+ case GL_OPERAND2_RGB_EXT:
+ machine.OPERAND2_RGB[texUnit] = value;
+ break;
+ case GL_OPERAND0_ALPHA_EXT:
+ machine.OPERAND0_ALPHA[texUnit] = value;
+ break;
+ case GL_OPERAND1_ALPHA_EXT:
+ machine.OPERAND1_ALPHA[texUnit] = value;
+ break;
+ case GL_OPERAND2_ALPHA_EXT:
+ machine.OPERAND2_ALPHA[texUnit] = value;
+ break;
+ case GL_RGB_SCALE_EXT:
+ machine.RGB_SCALE[texUnit] = value;
+ break;
+ case GL_ALPHA_SCALE:
+ machine.ALPHA_SCALE[texUnit] = value;
+ break;
+ }
+}
+
+
+//
+// Make the glTexEnv calls to setup one particular set of test parameters
+// from <testParams>.
+// <testNum> must be between 0 and CountTestCombinations(testParams)-1.
+//
+void
+TexCombineTest::SetupTestEnv(struct glmachine &machine, int texUnit,
+ int testNum, const struct test_param testParams[]) {
+
+ int divisor = 1;
+ for (int t = 0; testParams[t].target; t++) {
+ int numValues = 0;
+ for (int val = 0; testParams[t].validValues[val]; val++) {
+ numValues++;
+ }
+ int v = (testNum / divisor) % numValues;
+ GLenum target = testParams[t].target;
+ GLenum value = testParams[t].validValues[v];
+ TexEnv(machine, texUnit, target, value);
+ divisor *= numValues;
+ }
+}
+
+
+//
+// Set the fragment, texenv (constant), and texture colors for all the
+// machine's texture units.
+//
+void
+TexCombineTest::SetupColors(glmachine &machine) {
+
+ static const GLfloat fragColor[4] = { 0.00, 0.25, 0.50, 0.75 };
+ static const GLfloat envColors[][4] = {
+ { 0.25, 0.50, 0.75, 1.00 },
+ { 0.50, 0.75, 1.00, 0.00 },
+ { 0.75, 1.00, 0.00, 0.25 },
+ { 1.00, 0.00, 0.25, 0.50 }
+ };
+ static const GLfloat texColors[][8] = {
+ { 1.00, 0.00, 0.25, 0.50 },
+ { 0.75, 1.00, 0.00, 0.25 },
+ { 0.50, 0.75, 1.00, 0.00 },
+ { 0.25, 0.50, 0.75, 1.00 },
+ // extra colors that'll only be used for crossbar test
+ { 0.00, 0.00, 0.00, 0.00 },
+ { 0.25, 0.50, 0.50, 0.00 },
+ { 0.50, 0.25, 0.75, 0.25 },
+ { 0.75, 1.00, 0.25, 0.00 }
+ };
+
+ COPY4(machine.FragColor, fragColor);
+ glColor4fv(fragColor);
+
+ for (int u = 0; u < machine.NumTexUnits; u++) {
+ if (machine.NumTexUnits > 1)
+ p_glActiveTextureARB(GL_TEXTURE0_ARB + u);
+ glBindTexture(GL_TEXTURE_2D, mTextures[u]);
+ glEnable(GL_TEXTURE_2D);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
+ machine.EnvColor[u][0] = envColors[u % 4][0];
+ machine.EnvColor[u][1] = envColors[u % 4][1];
+ machine.EnvColor[u][2] = envColors[u % 4][2];
+ machine.EnvColor[u][3] = envColors[u % 4][3];
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
+ envColors[u % 4]);
+
+ const GLfloat *texCol = texColors[u % 8];
+
+ // Setup texture color, according to texture format
+ switch (machine.TexFormat[u]) {
+ case GL_RGBA:
+ machine.TexColor[u][0] = texCol[0];
+ machine.TexColor[u][1] = texCol[1];
+ machine.TexColor[u][2] = texCol[2];
+ machine.TexColor[u][3] = texCol[3];
+ break;
+ case GL_RGB:
+ machine.TexColor[u][0] = texCol[0];
+ machine.TexColor[u][1] = texCol[1];
+ machine.TexColor[u][2] = texCol[2];
+ machine.TexColor[u][3] = 1.0;
+ break;
+ case GL_ALPHA:
+ machine.TexColor[u][0] = 0.0;
+ machine.TexColor[u][1] = 0.0;
+ machine.TexColor[u][2] = 0.0;
+ machine.TexColor[u][3] = texCol[3];
+ break;
+ case GL_LUMINANCE:
+ machine.TexColor[u][0] = texCol[0];
+ machine.TexColor[u][1] = texCol[0];
+ machine.TexColor[u][2] = texCol[0];
+ machine.TexColor[u][3] = 1.0;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ machine.TexColor[u][0] = texCol[0];
+ machine.TexColor[u][1] = texCol[0];
+ machine.TexColor[u][2] = texCol[0];
+ machine.TexColor[u][3] = texCol[3];
+ break;
+ case GL_INTENSITY:
+ machine.TexColor[u][0] = texCol[0];
+ machine.TexColor[u][1] = texCol[0];
+ machine.TexColor[u][2] = texCol[0];
+ machine.TexColor[u][3] = texCol[0];
+ break;
+ default:
+ problem("bad texture format");
+ return;
+ }
+
+ // Make a 4x4 solid color texture
+ GLfloat image[16][4];
+ int i;
+ for (i = 0; i < 16; i++) {
+ image[i][0] = texColors[u % 8][0];
+ image[i][1] = texColors[u % 8][1];
+ image[i][2] = texColors[u % 8][2];
+ image[i][3] = texColors[u % 8][3];
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, machine.TexFormat[u],
+ 4, 4, 0, GL_RGBA, GL_FLOAT, image);
+
+#if 0 // Debug
+ GLfloat check[16][4];
+ GLint r, g, b, a;
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_RED_SIZE, &r);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_GREEN_SIZE, &g);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_BLUE_SIZE, &b);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_ALPHA_SIZE, &a);
+ printf("Texture bits: %d %d %d %d\n", r, g, b, a);
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT,
+ check);
+ for (i = 0;i < 16; i++) {
+ printf("%2d: %4f %4f %4f %4f %4f %4f %4f %4f\n", i,
+ image[i][0], image[i][1],
+ image[i][2], image[i][3],
+ check[i][0], check[i][1],
+ check[i][2], check[i][3]);
+ }
+#endif
+ }
+}
+
+
+//
+// Test texenv-combine with a single texture unit.
+//
+bool
+TexCombineTest::RunSingleTextureTest(glmachine &machine,
+ const test_param testParams[], BasicResult &r, Window& w) {
+
+ assert(machine.NumTexUnits == 1);
+ SetupColors(machine);
+
+ const int numTests = CountTestCombinations(testParams);
+ //printf("Testing %d combinations\n", numTests);
+
+ for (int test = 0; test < numTests; test++) {
+ // 0. Setup state
+ ResetMachine(machine);
+ SetupTestEnv(machine, 0, test, testParams);
+
+ // 1. Render with OpenGL
+ GLfloat renderedResult[4];
+ glTexCoord2f(0, 0); // use texcoord (0,0) for all vertices
+ glBegin(GL_POLYGON);
+ glVertex2f(-1.0, -1.0);
+ glVertex2f( 1.0, -1.0);
+ glVertex2f( 1.0, 1.0);
+ glVertex2f(-1.0, 1.0);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, renderedResult);
+ w.swap();
+
+ // 2. Compute expected result
+ GLfloat expected[4];
+ ComputeTexCombine(machine, 0, machine.FragColor, expected);
+
+ // 3. Compare rendered result to expected result
+ const GLfloat dr = fabs(expected[0] - renderedResult[0]);
+ const GLfloat dg = fabs(expected[1] - renderedResult[1]);
+ const GLfloat db = fabs(expected[2] - renderedResult[2]);
+ const GLfloat da = fabs(expected[3] - renderedResult[3]);
+ if (dr > mTolerance[0] || dg > mTolerance[1] ||
+ db > mTolerance[2] || da > mTolerance[3]) {
+ ReportFailure(machine, expected, renderedResult, r,
+ "Single Texture Test");
+#if 0 // Debug
+ VerifyMachineState(machine);
+ // For debugging, printing the state of the previous
+ // test is useful to see what's changed when we've
+ // failed a test but passed the previous one.
+ printf("single-texture test %d failed\n", test);
+ if (test > 0) {
+ printf("prev test:\n");
+ SetupTestEnv(machine, 0, test - 1, testParams);
+ PrintMachineState(machine);
+ }
+#endif
+ return false;
+ }
+#if 0 // Debug
+ else {
+ printf("PASSED test %d!\n", test);
+ env->log << "\texpected "
+ << expected[0] << ", "
+ << expected[1] << ", "
+ << expected[2] << ", "
+ << expected[3] << ", got "
+ << renderedResult[0] << ", "
+ << renderedResult[1] << ", "
+ << renderedResult[2] << ", "
+ << renderedResult[3] << "\n";
+ // PrintMachineState(machine);
+ }
+#endif
+ }
+ return true;
+}
+
+
+
+//
+// For each texture unit, test each texenv-combine mode.
+// That's 5 ^ NumTexUnits combinations.
+// Or 7 ^ numTexUnits if DOT3 combine mode is supported
+//
+int
+TexCombineTest::CountMultiTextureTestCombinations(const glmachine &machine) const {
+
+ int numTests = 1;
+ int numUnits = machine.NumTexUnits > 4 ? 4 : machine.NumTexUnits;
+ for (int i = 0; i < numUnits; i++)
+ numTests *= (haveDot3 ? 7 : 5);
+
+ return numTests;
+}
+
+
+//
+// Test texenv-combine with multiple texture units.
+//
+bool
+TexCombineTest::RunMultiTextureTest(glmachine &machine, BasicResult &r,
+ Window& w) {
+
+ static const GLenum combineModes[7] = {
+ GL_REPLACE,
+ GL_ADD,
+ GL_ADD_SIGNED_EXT,
+ GL_MODULATE,
+ GL_INTERPOLATE_EXT,
+ GL_DOT3_RGB_EXT,
+ GL_DOT3_RGBA_EXT
+ };
+ static const int numModes = haveDot3 ? 7 : 5;
+
+ // four texture units is enough to test
+ if (machine.NumTexUnits > 4)
+ machine.NumTexUnits = 4;
+
+ const int numTests = CountMultiTextureTestCombinations(machine);
+ //printf("Testing %d multitexture combinations\n", numTests);
+
+ SetupColors(machine);
+ for (int testNum = 0; testNum < numTests; testNum++) {
+ // 0. Set up texture units
+ ResetMachine(machine);
+ int divisor = 1;
+ int u;
+ for (u = 0; u < machine.NumTexUnits; u++) {
+ const int m = (testNum / divisor) % numModes;
+ const GLenum mode = combineModes[m];
+
+ // Set GL_COMBINE_RGB_EXT and GL_COMBINE_ALPHA_EXT
+ TexEnv(machine, u, GL_COMBINE_RGB_EXT, mode);
+ TexEnv(machine, u, GL_COMBINE_ALPHA_EXT,
+ (mode == GL_DOT3_RGB_EXT ||
+ mode == GL_DOT3_RGBA_EXT) ? GL_REPLACE : mode);
+ TexEnv(machine, u, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
+ TexEnv(machine, u, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT);
+ TexEnv(machine, u, GL_SOURCE2_RGB_EXT, GL_TEXTURE);
+ TexEnv(machine, u, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT);
+ TexEnv(machine, u, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT);
+ TexEnv(machine, u, GL_SOURCE2_ALPHA_EXT, GL_TEXTURE);
+ TexEnv(machine, u, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
+ TexEnv(machine, u, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_COLOR);
+ TexEnv(machine, u, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
+ TexEnv(machine, u, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA);
+ TexEnv(machine, u, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
+ TexEnv(machine, u, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
+ TexEnv(machine, u, GL_RGB_SCALE_EXT, 1);
+ TexEnv(machine, u, GL_ALPHA_SCALE, 1);
+
+ //printf("texenv%d = %s ", u, EnumString(mode));
+ divisor *= numModes;
+ }
+ //printf("\n");
+
+ // 1. Render with OpenGL
+ GLfloat renderedResult[4];
+ // use texcoord (0,0) for all vertices
+ for (int u = 0; u < machine.NumTexUnits; u++)
+ p_glMultiTexCoord2fARB(GL_TEXTURE0_ARB + u, 0, 0);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1.0, -1.0);
+ glVertex2f( 1.0, -1.0);
+ glVertex2f( 1.0, 1.0);
+ glVertex2f(-1.0, 1.0);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, renderedResult);
+ w.swap();
+
+ // 2. Compute expected result
+ GLfloat prevColor[4];
+ GLfloat expected[4];
+ for (u = 0; u < machine.NumTexUnits; u++) {
+ if (u == 0) {
+ COPY4(prevColor, machine.FragColor);
+ } else {
+ COPY4(prevColor, expected);
+ }
+ ComputeTexCombine(machine, u, prevColor, expected);
+ }
+
+ // 3. Compare rendered result to expected result
+ const GLfloat dr = fabs(expected[0] - renderedResult[0]);
+ const GLfloat dg = fabs(expected[1] - renderedResult[1]);
+ const GLfloat db = fabs(expected[2] - renderedResult[2]);
+ const GLfloat da = fabs(expected[3] - renderedResult[3]);
+ if (dr > mTolerance[0] || dg > mTolerance[1] ||
+ db > mTolerance[2] || da > mTolerance[3]) {
+ ReportFailure(machine, expected, renderedResult, r,
+ "Multi-texture test");
+#if 0 // Debug
+ printf("multitex test %d failed\n", testNum);
+ if (testNum > 0) {
+ printf("prev test:\n");
+ SetupTestEnv(machine, 0, testNum - 1, testParams);
+ PrintMachineState(machine);
+ }
+#endif
+
+ return false;
+ }
+ }
+ return true;
+}
+
+
+int
+TexCombineTest::CountCrossbarCombinations() const
+{
+ GLint numUnits;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &numUnits);
+ return numUnits;
+}
+
+
+bool
+TexCombineTest::RunCrossbarTest(glmachine &machine, BasicResult &r, Window& w) {
+ // We do a really short, simple test for GL_ARB_texture_env_crossbar
+ // since the preceeding tests are pretty comprehensive and the
+ // crossbar feature is just an incremental addition.
+ // Basically, if we have N texture units we run N tests.
+ // For test [i] we set texture unit [i] to fetch the texture color
+ // from unit [numUnits - i - 1]. For units != i we use the constant
+ // color (0,0,0,0). We use GL_ADD mode to compute the sum over all units.
+ // So effectively, the result of texture combine is simply the incoming
+ // fragment color plus unit [numUnits - test - 1]'s texture color.
+
+ int unit;
+
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint *) &Machine.NumTexUnits);
+
+ // Set up constant texture state for all tests
+ ResetMachine(machine);
+ SetupColors(machine);
+ for (unit = 0; unit < machine.NumTexUnits; unit++) {
+ TexEnv(machine, unit, GL_COMBINE_RGB_EXT, GL_ADD);
+ TexEnv(machine, unit, GL_COMBINE_ALPHA_EXT, GL_ADD);
+ TexEnv(machine, unit, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
+ TexEnv(machine, unit, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT);
+ // SOURCE1_RGB/ALPHA is set below, per test
+ TexEnv(machine, unit, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
+ TexEnv(machine, unit, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
+ TexEnv(machine, unit, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
+ TexEnv(machine, unit, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA);
+ TexEnv(machine, unit, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA);
+ TexEnv(machine, unit, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
+ TexEnv(machine, unit, GL_RGB_SCALE_EXT, 1);
+ TexEnv(machine, unit, GL_ALPHA_SCALE, 1);
+
+ machine.EnvColor[unit][0] = 0.0F;
+ machine.EnvColor[unit][1] = 0.0F;
+ machine.EnvColor[unit][2] = 0.0F;
+ machine.EnvColor[unit][3] = 0.0F;
+ p_glActiveTextureARB(GL_TEXTURE0_ARB + unit);
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
+ machine.EnvColor[unit]);
+ }
+
+ for (int test = 0; test < machine.NumTexUnits; test++) {
+ // 1. Set up texture state
+ for (unit = 0; unit < machine.NumTexUnits; unit++) {
+ if (unit == test) {
+ const int revUnit = machine.NumTexUnits - unit - 1;
+ TexEnv(machine, unit, GL_SOURCE1_RGB_EXT,
+ GL_TEXTURE0_ARB + revUnit);
+ TexEnv(machine, unit, GL_SOURCE1_ALPHA_EXT,
+ GL_TEXTURE0_ARB + revUnit);
+ }
+ else {
+ TexEnv(machine, unit, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT);
+ TexEnv(machine, unit, GL_SOURCE1_ALPHA_EXT, GL_CONSTANT_EXT);
+ }
+ }
+
+ // 2. Render with OpenGL
+ GLfloat renderedResult[4];
+ // texcoord (0,) for all vertices is OK
+ for (unit = 0; unit < machine.NumTexUnits; unit++)
+ p_glMultiTexCoord2fARB(GL_TEXTURE0_ARB + unit, 0, 0);
+ glColor4fv(machine.FragColor);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1.0, -1.0);
+ glVertex2f( 1.0, -1.0);
+ glVertex2f( 1.0, 1.0);
+ glVertex2f(-1.0, 1.0);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, renderedResult);
+ w.swap();
+
+ // 3. Compute expected result
+ GLfloat prevColor[4];
+ GLfloat expected[4];
+ for (unit = 0; unit < machine.NumTexUnits; unit++) {
+ if (unit == 0) {
+ COPY4(prevColor, machine.FragColor);
+ } else {
+ COPY4(prevColor, expected);
+ }
+ ComputeTexCombine(machine, unit, prevColor, expected);
+ }
+
+ // 4. Compare rendered result to expected result
+ const GLfloat dr = fabs(expected[0] - renderedResult[0]);
+ const GLfloat dg = fabs(expected[1] - renderedResult[1]);
+ const GLfloat db = fabs(expected[2] - renderedResult[2]);
+ const GLfloat da = fabs(expected[3] - renderedResult[3]);
+ if (dr > mTolerance[0] || dg > mTolerance[1] ||
+ db > mTolerance[2] || da > mTolerance[3]) {
+ ReportFailure(machine, expected, renderedResult, r,
+ "Texture crossbar test");
+#if 0 // Debug
+ printf("crossbar test %d failed\n", testNum);
+ PrintMachineState(machine);
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+// XXX should we run a number of individual tests instead?
+void
+TexCombineTest::runOne(BasicResult& r, Window& w) {
+ // Grab pointers to the extension functions. It's safe to use
+ // these without testing them because we already know that we
+ // won't be invoked except on contexts that support the
+ // extension.
+ p_glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)
+ (GLUtils::getProcAddress("glActiveTextureARB"));
+ p_glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)
+ (GLUtils::getProcAddress("glMultiTexCoord2fARB"));
+
+ // Test the availability of the DOT3 extenstion
+ haveDot3 = GLUtils::haveExtensions("GL_EXT_texture_env_dot3");
+ if (0 == haveDot3)
+ haveDot3 = GLUtils::haveExtensions("GL_ARB_texture_env_dot3");
+
+ haveCrossbar = GLUtils::haveExtensions("GL_ARB_texture_env_crossbar");
+
+ // compute RGB error tolerance
+ {
+ GLint rBits, gBits, bBits, aBits;
+ GLint rTexBits, gTexBits, bTexBits, aTexBits;
+ GLfloat texImage[4][4][4];
+ // Make dummy texture image
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0,
+ GL_RGBA, GL_FLOAT, texImage);
+ glGetIntegerv(GL_RED_BITS, &rBits);
+ glGetIntegerv(GL_GREEN_BITS, &gBits);
+ glGetIntegerv(GL_BLUE_BITS, &bBits);
+ glGetIntegerv(GL_ALPHA_BITS, &aBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_RED_SIZE, &rTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_GREEN_SIZE, &gTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_BLUE_SIZE, &bTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
+ GL_TEXTURE_ALPHA_SIZE, &aTexBits);
+ // find smaller of frame buffer and texture bits
+ rBits = (rBits < rTexBits) ? rBits : rTexBits;
+ gBits = (gBits < gTexBits) ? gBits : gTexBits;
+ bBits = (bBits < bTexBits) ? bBits : bTexBits;
+ aBits = (aBits < aTexBits) ? aBits : aTexBits;
+ // tolerance is 3 bits of error
+ mTolerance[0] = 8.0 / (1 << rBits);
+ mTolerance[1] = 8.0 / (1 << gBits);
+ mTolerance[2] = 8.0 / (1 << bBits);
+ if (aBits == 0)
+ mTolerance[3] = 1.0;
+ else
+ mTolerance[3] = 8.0 / (1 << aBits);
+ /*
+ printf("Tolerance: %g %g %g %g\n",
+ mTolerance[0], mTolerance[1],
+ mTolerance[2], mTolerance[3]);
+ */
+ }
+
+ // Allocate our textures
+ glGenTextures(MAX_TEX_UNITS, mTextures);
+
+ // We'll only render a 4-pixel polygon
+ glViewport(0, 0, 2, 2);
+
+ ResetMachine(Machine);
+ Machine.NumTexUnits = 1;
+
+ // Do single texture unit tests first.
+ bool passed = RunSingleTextureTest(Machine, ReplaceParams, r, w);
+ if (passed)
+ passed = RunSingleTextureTest(Machine, AddParams, r, w);
+ if (passed)
+ passed = RunSingleTextureTest(Machine, AddSignedParams, r, w);
+ if (passed)
+ passed = RunSingleTextureTest(Machine, ModulateParams, r, w);
+ if (passed)
+ passed = RunSingleTextureTest(Machine, InterpolateParams, r, w);
+ if (passed && haveDot3)
+ passed = RunSingleTextureTest(Machine, Dot3RGBParams, r, w);
+ if (passed && haveDot3)
+ passed = RunSingleTextureTest(Machine, Dot3RGBAParams, r, w);
+
+ // Now do some multi-texture tests
+ if (passed) {
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,
+ (GLint *) &Machine.NumTexUnits);
+ if (Machine.NumTexUnits > 1) {
+ passed = RunMultiTextureTest(Machine, r, w);
+ }
+ }
+
+ // Do crossbar tests
+ if (passed && haveCrossbar) {
+ passed = RunCrossbarTest(Machine, r, w);
+ }
+
+ r.pass = passed;
+
+ // Delete our textures
+ glDeleteTextures(MAX_TEX_UNITS, mTextures);
+
+} // TexCombineTest::runOne
+
+void
+TexCombineTest::logOne(BasicResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ env->log << "\tTested "
+ << CountTestCombinations(ReplaceParams)
+ << " GL_REPLACE combinations\n";
+ env->log << "\tTested "
+ << CountTestCombinations(AddParams)
+ << " GL_ADD combinations\n";
+ env->log << "\tTested "
+ << CountTestCombinations(AddSignedParams)
+ << " GL_ADD_SIGNED_EXT combinations\n";
+ env->log << "\tTested "
+ << CountTestCombinations(ModulateParams)
+ << " GL_MODULATE combinations\n";
+ env->log << "\tTested "
+ << CountTestCombinations(InterpolateParams)
+ << " GL_INTERPOLATE_EXT combinations\n";
+ if (haveDot3) {
+ env->log << "\tTested "
+ << CountTestCombinations(Dot3RGBParams)
+ << " GL_DOT3_RGB_EXT combinations\n";
+ env->log << "\tTested "
+ << CountTestCombinations(Dot3RGBAParams)
+ << " GL_DOT3_RGBA_EXT combinations\n";
+ }
+ env->log << "\tTested "
+ << CountMultiTextureTestCombinations(Machine)
+ << " multitexture combinations\n";
+ if (haveCrossbar) {
+ env->log << "\tTested "
+ << CountCrossbarCombinations()
+ << " crossbar combinations\n";
+ }
+ }
+} // TexCombineTest::logOne
+
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+TexCombineTest texCombTest("texCombine", "window, rgb",
+
+ "GL_EXT_texture_env_combine verification test.\n"
+ "We only test a subset of all possible texture env combinations\n"
+ "because there's simply too many to exhaustively test them all.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/ttexcombine.h b/tests/glean/ttexcombine.h
new file mode 100644
index 00000000..59b3b33b
--- /dev/null
+++ b/tests/glean/ttexcombine.h
@@ -0,0 +1,135 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// ttexcombing.h: Test the GL_EXT_texture_env_combine extension
+// Author: Brian Paul (brianp@valinux.com) September 2000
+
+
+#ifndef __ttexcombine_h__
+#define __ttexcombine_h__
+
+#include "tbasic.h"
+
+namespace GLEAN {
+
+#define MAX_TEX_UNITS 8
+
+class TexCombineTest: public BasicTest {
+ public:
+ TexCombineTest(const char* testName, const char* filter,
+ const char* description):
+#if (__AGL__)
+ BasicTest(testName, filter, "GL_ARB_texture_env_combine",
+ description) {
+#else
+ BasicTest(testName, filter, "GL_EXT_texture_env_combine",
+ description) {
+#endif
+ fWidth = 2;
+ fHeight = 2;
+ }
+
+ virtual void runOne(BasicResult& r, Window& w);
+ virtual void logOne(BasicResult& r);
+
+ private:
+ // Our model of GL machine state
+ struct glmachine {
+ GLenum COMBINE_RGB[MAX_TEX_UNITS];
+ GLenum COMBINE_ALPHA[MAX_TEX_UNITS];
+ GLenum SOURCE0_RGB[MAX_TEX_UNITS];
+ GLenum SOURCE1_RGB[MAX_TEX_UNITS];
+ GLenum SOURCE2_RGB[MAX_TEX_UNITS];
+ GLenum SOURCE0_ALPHA[MAX_TEX_UNITS];
+ GLenum SOURCE1_ALPHA[MAX_TEX_UNITS];
+ GLenum SOURCE2_ALPHA[MAX_TEX_UNITS];
+ GLenum OPERAND0_RGB[MAX_TEX_UNITS];
+ GLenum OPERAND1_RGB[MAX_TEX_UNITS];
+ GLenum OPERAND2_RGB[MAX_TEX_UNITS];
+ GLenum OPERAND0_ALPHA[MAX_TEX_UNITS];
+ GLenum OPERAND1_ALPHA[MAX_TEX_UNITS];
+ GLenum OPERAND2_ALPHA[MAX_TEX_UNITS];
+ GLfloat RGB_SCALE[MAX_TEX_UNITS];
+ GLfloat ALPHA_SCALE[MAX_TEX_UNITS];
+ GLfloat FragColor[4]; // fragment color
+ GLfloat EnvColor[MAX_TEX_UNITS][4]; // texture env color
+ GLfloat TexColor[MAX_TEX_UNITS][4]; // texture image color
+ GLenum TexFormat[MAX_TEX_UNITS]; // texture base format
+ int NumTexUnits;
+ };
+
+ // describes possible state combinations
+ struct test_param {
+ GLenum target;
+ GLenum validValues[6];
+ };
+
+ glmachine Machine;
+ static test_param ReplaceParams[];
+ static test_param ModulateParams[];
+ static test_param AddParams[];
+ static test_param AddSignedParams[];
+ static test_param InterpolateParams[];
+ static test_param Dot3RGBParams[];
+ static test_param Dot3RGBAParams[];
+ static test_param MultitexParams[];
+ static test_param CrossbarParams[];
+ bool haveDot3;
+ bool haveCrossbar;
+ GLfloat mTolerance[4];
+ GLuint mTextures[MAX_TEX_UNITS];
+
+ void ResetMachine(glmachine &machine);
+ void ComputeTexCombine(const glmachine &machine, int texUnit,
+ const GLfloat prevColor[4], GLfloat result[4]) const;
+ void PrintMachineState(const glmachine &machine) const;
+ bool VerifyMachineState(const glmachine &machine) const;
+ void ReportFailure(const glmachine &machine, const GLfloat expected[4],
+ const GLfloat rendered[4], BasicResult &r, const char *where);
+ void TexEnv(glmachine &machine, int texUnit, GLenum target,
+ GLenum value);
+ void SetupTestEnv(glmachine &machine, int texUnit, int testNum,
+ const test_param testParams[]);
+ void SetupColors(struct glmachine &machine);
+ int CountTestCombinations(const test_param testParams[]) const;
+ bool RunSingleTextureTest(glmachine &machine,
+ const test_param testParams[], BasicResult &r, Window &w);
+ int CountMultiTextureTestCombinations(const glmachine &machine) const;
+ bool RunMultiTextureTest(glmachine &machine, BasicResult &r, Window &w);
+ int CountCrossbarCombinations() const;
+ bool RunCrossbarTest(glmachine &machine, BasicResult &r, Window &w);
+
+ PFNGLACTIVETEXTUREARBPROC p_glActiveTextureARB;
+ PFNGLMULTITEXCOORD2FARBPROC p_glMultiTexCoord2fARB;
+
+}; // class TexCombineTest
+
+} // namespace GLEAN
+
+#endif // __ttexcombine_h__
diff --git a/tests/glean/ttexcube.cpp b/tests/glean/ttexcube.cpp
new file mode 100644
index 00000000..1d8ac29f
--- /dev/null
+++ b/tests/glean/ttexcube.cpp
@@ -0,0 +1,426 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// ttexcube.cpp: Test the GL_ARB_texture_cube_map extension
+// Author: Brian Paul (brianp@valinux.com) March 2001
+//
+// Test procedure:
+// We build a 6-sided texture cube map in which each side is a simple 2x2
+// checkboard pattern with known colors. Then we do three sets of tests.
+// Each test draws a single quadrilateral. The tests are:
+//
+// 1. Directly specify texture coordinates. By changing the texture coords
+// we can sample specific regions of the cube map. Check the rendered
+// quad colors for correctness.
+// 2. Use GL_NORMAL_MAP_ARB texgen mode with specific normal vectors to
+// sample specific regions of the cube map. Check for correctness.
+// 3. Test GL_REFLECTION_MAP_ARB texgen mode by specifying a quad with
+// fixed vertices and normals but rotating the texture coordinate
+// matrix to select each side of the cube map. Check that the rendered
+// quad's four colors match the cube face.
+//
+
+#include "ttexcube.h"
+#include <stdio.h>
+#include <cmath>
+
+namespace GLEAN {
+
+
+#define VP_SIZE 20
+
+static const char *faceName[6] = {
+ "POSITIVE_X",
+ "NEGATIVE_X",
+ "POSITIVE_Y",
+ "NEGATIVE_Y",
+ "POSITIVE_Z",
+ "NEGATIVE_Z"
+};
+
+
+//
+// Test if two colors are close enough to be considered the same
+//
+bool
+TexCubeTest::TestColor(const GLfloat c1[3], const GLfloat c2[3]) {
+ if (fabs(c1[0] - c2[0]) <= mTolerance[0] &&
+ fabs(c1[1] - c2[1]) <= mTolerance[1] &&
+ fabs(c1[2] - c2[2]) <= mTolerance[2])
+ return true;
+ else
+ return false;
+}
+
+
+//
+// Define a 2x2 checkerboard texture image using the given four colors.
+//
+void
+TexCubeTest::BuildTexImage(GLenum target, const GLfloat color[4][3]) {
+ const GLint w = 8, h = 8;
+ GLfloat texImage[8][8][4];
+ for (int i = 0; i < h; i++) {
+ const int ibit = (i >= (h / 2));
+ for (int j = 0; j < w; j++) {
+ const int jbit = (j >= (w / 2));
+ const int c = ibit * 2 + jbit;
+ texImage[i][j][0] = color[c][0];
+ texImage[i][j][1] = color[c][1];
+ texImage[i][j][2] = color[c][2];
+ texImage[i][j][3] = 1.0;
+ }
+ }
+ glTexImage2D(target, 0, GL_RGB, w, h, 0, GL_RGBA, GL_FLOAT, texImage);
+}
+
+
+//
+// Draw a polygon either with texcoords or normal vectors and check that
+// we hit the correct quadrant of each of the six cube faces.
+// Return: true = pass, false = fail
+//
+bool
+TexCubeTest::TestNormalMap(bool texCoordMode, const char *modeName) {
+
+ // We use the coordinates both directly as texture coordinates
+ // and as normal vectors for testing NORMAL_MAP_ARB texgen mode).
+ static const GLfloat coords[6][4][3] = {
+ // +X
+ {
+ { 1.0, 0.5, 0.5 },
+ { 1.0, 0.5, -0.5 },
+ { 1.0, -0.5, 0.5 },
+ { 1.0, -0.5, -0.5 },
+ },
+ // -X
+ {
+ { -1.0, 0.5, -0.5 },
+ { -1.0, 0.5, 0.5 },
+ { -1.0, -0.5, -0.5 },
+ { -1.0, -0.5, 0.5 },
+ },
+ // +Y
+ {
+ { -0.5, 1.0, -0.5 },
+ { 0.5, 1.0, -0.5 },
+ { -0.5, 1.0, 0.5 },
+ { 0.5, 1.0, 0.5 },
+ },
+ // -Y
+ {
+ { -0.5, -1.0, 0.5 },
+ { 0.5, -1.0, 0.5 },
+ { -0.5, -1.0, -0.5 },
+ { 0.5, -1.0, -0.5 },
+ },
+ // +Z
+ {
+ { -0.5, 0.5, 1.0 },
+ { 0.5, 0.5, 1.0 },
+ { -0.5, -0.5, 1.0 },
+ { 0.5, -0.5, 1.0 },
+ },
+ // -Z
+ {
+ { 0.5, 0.5, -1.0 },
+ { -0.5, 0.5, -1.0 },
+ { 0.5, -0.5, -1.0 },
+ { -0.5, -0.5, -1.0 },
+ }
+ };
+
+ // normal vectors to hit the four colors of each cube face when
+
+ for (int face = 0; face < 6; face++) {
+ for (int quadrant = 0; quadrant < 4; quadrant++) {
+
+ // draw the test quad
+ if (texCoordMode)
+ glTexCoord3fv(coords[face][quadrant]);
+ else
+ glNormal3fv(coords[face][quadrant]);
+ glColor3f(0, 1, 0);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ // check the color
+ GLfloat result[3];
+ glReadPixels(1, 1, 1, 1, GL_RGB, GL_FLOAT, result);
+
+ if (!TestColor(mColors[face][quadrant], result)) {
+ env->log << name
+ << ": FAIL: mode='"
+ << modeName
+ << "' face="
+ << faceName[face]
+ << " quadrant="
+ << quadrant
+ << " expected=("
+ << mColors[face][quadrant][0] << ", "
+ << mColors[face][quadrant][1] << ", "
+ << mColors[face][quadrant][2]
+ << ") measured=("
+ << result[0] << ", "
+ << result[1] << ", "
+ << result[2]
+ << ")\n";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+//
+// Test GL_REFLECTION_MAP_ARB texgen mode.
+// Return: true = pass, false = fail
+//
+bool
+TexCubeTest::TestReflectionMap(const char *modeName) {
+
+// These are the glReadPixels coords we'll use for pixel testing
+#define X0 ((int) (VP_SIZE * 0.25))
+#define X1 ((int) (VP_SIZE * 0.75))
+#define Y0 ((int) (VP_SIZE * 0.25))
+#define Y1 ((int) (VP_SIZE * 0.75))
+
+ // We'll rotate the texture coordinates to map each cube face
+ // onto a screen-aligned quad.
+ static const GLfloat rotation[6][4] = {
+ { -90, 0, 1, 0 }, // +X
+ { 90, 0, 1, 0 }, // -X
+ { 90, 1, 0, 0 }, // +Y
+ { -90, 1, 0, 0 }, // -Y
+ { 180, 1, 0, 0 }, // -Z
+ { 0, 1, 0, 0 } // +Z
+ };
+
+ // For each face we'll test the four quadrants to be sure test
+ // if the expected color is where it should be.
+ // These are the glReadPixels coordinates at which we should
+ // find the colors in the mColors[6][4] array.
+ static const GLint readPos[6][4][2] = {
+ // +X
+ {
+ { X1, Y1 }, { X0, Y1 }, { X1, Y0 }, { X0, Y0 }
+ },
+ // -X
+ {
+ { X1, Y1 }, { X0, Y1 }, { X1, Y0 }, { X0, Y0 }
+ },
+ // +Y
+ {
+ { X0, Y0 }, { X1, Y0 }, { X0, Y1 }, { X1, Y1 }
+ },
+ // -Y
+ {
+ { X0, Y0 }, { X1, Y0 }, { X0, Y1 }, { X1, Y1 }
+ },
+ // +Z
+ {
+ { X0, Y0 }, { X1, Y0 }, { X0, Y1 }, { X1, Y1 }
+ },
+ // -Z
+ {
+ { X1, Y1 }, { X0, Y1 }, { X1, Y0 }, { X0, Y0 }
+ }
+ };
+
+ for (int face = 0; face < 6; face++) {
+
+ // Draw the test quad.
+ // It'll be textured with one face of the cube map texture.
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glRotatef(rotation[face][0], rotation[face][1],
+ rotation[face][2], rotation[face][3]);
+ glNormal3f(0, 0, 1);
+ glColor3f(0, 1, 0);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, 1);
+ glVertex3f( 1, -1, 1);
+ glVertex3f( 1, 1, 1);
+ glVertex3f(-1, 1, 1);
+ glEnd();
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+
+ // Verify the colors
+ for (int quadrant = 0; quadrant < 4; quadrant++) {
+
+ GLfloat result[3];
+ glReadPixels(readPos[face][quadrant][0],
+ readPos[face][quadrant][1],
+ 1, 1, GL_RGB, GL_FLOAT, result);
+
+ if (!TestColor(mColors[face][quadrant], result)) {
+ env->log << name
+ << ": FAIL: mode='"
+ << modeName
+ << "' face="
+ << faceName[face]
+ << " quadrant="
+ << quadrant
+ << " expected=("
+ << mColors[face][quadrant][0] << ", "
+ << mColors[face][quadrant][1] << ", "
+ << mColors[face][quadrant][2]
+ << ") measured=("
+ << result[0] << ", "
+ << result[1] << ", "
+ << result[2]
+ << ")\n";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+void
+TexCubeTest::runOne(BasicResult& r, Window& w) {
+
+ (void) w;
+
+ // each of six faces needs four test colors
+ for (int i = 0; i < 6 * 4; i++) {
+ GLint r = i % 3;
+ GLint g = (i / 3) % 3;
+ GLint b = (i / 9) % 3;
+ mColors[i / 4][i % 4][0] = r * 0.5;
+ mColors[i / 4][i % 4][1] = g * 0.5;
+ mColors[i / 4][i % 4][2] = b * 0.5;
+ //printf("mColors[%d][%d] = %g %g %g\n", i/4, i%4,
+ // mColors[i/4][i%4][0],
+ // mColors[i/4][i%4][1],
+ // mColors[i/4][i%4][2]);
+ }
+
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ BuildTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, mColors[0]);
+ BuildTexImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, mColors[1]);
+ BuildTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, mColors[2]);
+ BuildTexImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, mColors[3]);
+ BuildTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, mColors[4]);
+ BuildTexImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, mColors[5]);
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+
+ // compute RGB error tolerance
+ {
+ GLint rBits, gBits, bBits;
+ GLint rTexBits, gTexBits, bTexBits;
+ glGetIntegerv(GL_RED_BITS, &rBits);
+ glGetIntegerv(GL_GREEN_BITS, &gBits);
+ glGetIntegerv(GL_BLUE_BITS, &bBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ 0, GL_TEXTURE_RED_SIZE, &rTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ 0, GL_TEXTURE_GREEN_SIZE, &gTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ 0, GL_TEXTURE_BLUE_SIZE, &bTexBits);
+ // find smaller of frame buffer and texture bits
+ rBits = (rBits < rTexBits) ? rBits : rTexBits;
+ gBits = (gBits < gTexBits) ? gBits : gTexBits;
+ bBits = (bBits < bTexBits) ? bBits : bTexBits;
+ mTolerance[0] = 2.0 / (1 << rBits);
+ mTolerance[1] = 2.0 / (1 << gBits);
+ mTolerance[2] = 2.0 / (1 << bBits);
+ }
+
+ glViewport(0, 0, VP_SIZE, VP_SIZE);
+
+ bool passed = true;
+
+ if (passed) {
+ // Test directly specifying texture coords
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_R);
+ passed = TestNormalMap(true,
+ "Direct specification of texture coordinates");
+ }
+
+ if (passed) {
+ // Test GL_NORMAL_MAP_ARB mode
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
+ glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+ glEnable(GL_TEXTURE_GEN_R);
+ passed = TestNormalMap(false, "GL_NORMAL_MAP_ARB texgen");
+ }
+
+ if (passed) {
+ // Test GL_REFLECTION_MAP_ARB mode
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
+ glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+ glEnable(GL_TEXTURE_GEN_R);
+ glEnable(GL_NORMALIZE);
+ passed = TestReflectionMap("GL_REFLECTION_MAP_ARB texgen");
+ }
+
+ r.pass = passed;
+} // TexCubeTest::runOne
+
+
+void
+TexCubeTest::logOne(BasicResult& r) {
+ logPassFail(r);
+ logConcise(r);
+} // TexCubeTest::logOne
+
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+TexCubeTest texCubeTest("texCube", "window, rgb",
+
+ "GL_ARB_texture_cube_map verification test.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/ttexcube.h b/tests/glean/ttexcube.h
new file mode 100644
index 00000000..8ca15e3e
--- /dev/null
+++ b/tests/glean/ttexcube.h
@@ -0,0 +1,65 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// ttexcube.h: Test the GL_ARB_texture_cube_map extension
+// Author: Brian Paul (brianp@valinux.com) March 2001
+
+
+#ifndef __ttexcube_h__
+#define __ttexcube_h__
+
+#include "tbasic.h"
+
+namespace GLEAN {
+
+class TexCubeTest: public BasicTest {
+ public:
+ TexCubeTest(const char* testName, const char* filter,
+ const char* description):
+ BasicTest(testName, filter, "GL_ARB_texture_cube_map",
+ description) {
+ }
+
+ virtual void runOne(BasicResult& r, Window& w);
+ virtual void logOne(BasicResult& r);
+
+ private:
+ bool TestColor(const GLfloat c1[3], const GLfloat c2[3]);
+ void BuildTexImage(GLenum target, const GLfloat color[4][3]);
+ bool TestNormalMap(bool testTexCoords, const char *modeName);
+ bool TestReflectionMap(const char *modeName);
+
+ GLfloat mColors[6][4][3];
+ GLfloat mTolerance[3];
+
+}; // class TexCubeTest
+
+} // namespace GLEAN
+
+#endif // __ttexcube_h__
diff --git a/tests/glean/ttexenv.cpp b/tests/glean/ttexenv.cpp
new file mode 100644
index 00000000..223f53cf
--- /dev/null
+++ b/tests/glean/ttexenv.cpp
@@ -0,0 +1,667 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// ttexenv.cpp: Test the basic texture env modes
+// Author: Brian Paul (brianp@valinux.com) April 2001
+//
+// Test procedure:
+// Setup a texture with 81 columns of unique RGBA colors, 3 texels each.
+// Draw a 81 uniquely-colored flat-shaded quads as wide horizontal bands,
+// with the above texture. This makes a matrix of 81*81 colored squares
+// for which we test that the current texture environment mode and texture
+// format produced the correct color.
+// Finally, we blend over a gray background in order to verify that the
+// post-texture alpha value is correct.
+//
+
+#include "ttexenv.h"
+#include <cassert>
+#include <stdio.h>
+#include <cmath>
+
+namespace GLEAN {
+
+
+// If this is true, we enable blending over a gray background in order
+// to test the alpha results of the texture env. If this is false,
+// we don't blend. It might be useful to disable blending in order to
+// diagnose failures
+#define BLEND_WITH_BACKGROUND 1
+
+static GLfloat BgColor[4] = { 0.5, 0.5, 0.5, 0.5 };
+
+
+static const GLenum FormatEnums[] = {
+ GL_ALPHA,
+ GL_LUMINANCE,
+ GL_LUMINANCE_ALPHA,
+ GL_INTENSITY,
+ GL_RGB,
+ GL_RGBA
+};
+
+static const char *FormatNames[] = {
+ "GL_ALPHA",
+ "GL_LUMINANCE",
+ "GL_LUMINANCE_ALPHA",
+ "GL_INTENSITY",
+ "GL_RGB",
+ "GL_RGBA"
+};
+
+static const GLenum EnvModeEnums[] = {
+ GL_REPLACE,
+ GL_MODULATE,
+ GL_DECAL,
+ GL_BLEND,
+ GL_ADD
+};
+
+static const char *EnvModeNames[] = {
+ "GL_REPLACE",
+ "GL_MODULATE",
+ "GL_DECAL",
+ "GL_BLEND",
+ "GL_ADD"
+};
+
+
+//
+// Test if two colors are close enough to be considered the same
+//
+bool
+TexEnvTest::TestColor(const GLfloat c1[3], const GLfloat c2[3]) {
+ if (fabs(c1[0] - c2[0]) <= mTolerance[0] &&
+ fabs(c1[1] - c2[1]) <= mTolerance[1] &&
+ fabs(c1[2] - c2[2]) <= mTolerance[2])
+ return true;
+ else
+ return false;
+}
+
+//
+// Compute expected texenv result given the texture env mode, the texture
+// base format, texture color, fragment color, and texture env color.
+// This also blends the result with the background color if that option
+// is enabled (see above).
+//
+void
+TexEnvTest::ComputeExpectedColor(GLenum envMode, GLenum texFormat,
+ const GLfloat texColor[4], const GLfloat fragColor[4],
+ const GLfloat envColor[4], GLfloat result[4]) {
+
+ switch (envMode) {
+ case GL_REPLACE:
+ switch (texFormat) {
+ case GL_ALPHA:
+ result[0] = fragColor[0];
+ result[1] = fragColor[1];
+ result[2] = fragColor[2];
+ result[3] = texColor[3]; // alpha
+ break;
+ case GL_LUMINANCE:
+ result[0] = texColor[0]; // lum
+ result[1] = texColor[0];
+ result[2] = texColor[0];
+ result[3] = fragColor[3];
+ break;
+ case GL_LUMINANCE_ALPHA:
+ result[0] = texColor[0]; // lum
+ result[1] = texColor[0];
+ result[2] = texColor[0];
+ result[3] = texColor[3]; // alpha
+ break;
+ case GL_INTENSITY:
+ result[0] = texColor[0]; // intensity
+ result[1] = texColor[0];
+ result[2] = texColor[0];
+ result[3] = texColor[0];
+ break;
+ case GL_RGB:
+ result[0] = texColor[0]; // r
+ result[1] = texColor[1]; // g
+ result[2] = texColor[2]; // b
+ result[3] = fragColor[3];
+ break;
+ case GL_RGBA:
+ result[0] = texColor[0]; // r
+ result[1] = texColor[1]; // g
+ result[2] = texColor[2]; // b
+ result[3] = texColor[3]; // a
+ break;
+ default:
+ abort(); // implementation error
+ }
+ break;
+ case GL_MODULATE:
+ switch (texFormat) {
+ case GL_ALPHA:
+ result[0] = fragColor[0];
+ result[1] = fragColor[1];
+ result[2] = fragColor[2];
+ result[3] = fragColor[3] * texColor[3];
+ break;
+ case GL_LUMINANCE:
+ result[0] = fragColor[0] * texColor[0];
+ result[1] = fragColor[1] * texColor[0];
+ result[2] = fragColor[2] * texColor[0];
+ result[3] = fragColor[3];
+ break;
+ case GL_LUMINANCE_ALPHA:
+ result[0] = fragColor[0] * texColor[0];
+ result[1] = fragColor[1] * texColor[0];
+ result[2] = fragColor[2] * texColor[0];
+ result[3] = fragColor[3] * texColor[3];
+ break;
+ case GL_INTENSITY:
+ result[0] = fragColor[0] * texColor[0];
+ result[1] = fragColor[1] * texColor[0];
+ result[2] = fragColor[2] * texColor[0];
+ result[3] = fragColor[3] * texColor[0];
+ break;
+ case GL_RGB:
+ result[0] = fragColor[0] * texColor[0];
+ result[1] = fragColor[1] * texColor[1];
+ result[2] = fragColor[2] * texColor[2];
+ result[3] = fragColor[3];
+ break;
+ case GL_RGBA:
+ result[0] = fragColor[0] * texColor[0];
+ result[1] = fragColor[1] * texColor[1];
+ result[2] = fragColor[2] * texColor[2];
+ result[3] = fragColor[3] * texColor[3];
+ break;
+ default:
+ abort(); // implementation error
+ }
+ break;
+ case GL_DECAL:
+ switch (texFormat) {
+ case GL_ALPHA:
+ result[0] = 0; // undefined
+ result[1] = 0;
+ result[2] = 0;
+ result[3] = 0;
+ break;
+ case GL_LUMINANCE:
+ result[0] = 0; // undefined
+ result[1] = 0;
+ result[2] = 0;
+ result[3] = 0;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ result[0] = 0; // undefined
+ result[1] = 0;
+ result[2] = 0;
+ result[3] = 0;
+ break;
+ case GL_INTENSITY:
+ result[0] = 0; // undefined
+ result[1] = 0;
+ result[2] = 0;
+ result[3] = 0;
+ break;
+ case GL_RGB:
+ result[0] = texColor[0];
+ result[1] = texColor[1];
+ result[2] = texColor[2];
+ result[3] = fragColor[3];
+ break;
+ case GL_RGBA: {
+ const GLfloat a = texColor[3];
+ const GLfloat oma = 1.0 - a;
+ result[0] = fragColor[0] * oma + texColor[0] * a;
+ result[1] = fragColor[1] * oma + texColor[1] * a;
+ result[2] = fragColor[2] * oma + texColor[2] * a;
+ result[3] = fragColor[3];
+ } break;
+ default:
+ abort(); // implementation error
+ }
+ break;
+ case GL_BLEND:
+ switch (texFormat) {
+ case GL_ALPHA:
+ result[0] = fragColor[0];
+ result[1] = fragColor[1];
+ result[2] = fragColor[2];
+ result[3] = fragColor[3] * texColor[3];
+ break;
+ case GL_LUMINANCE: {
+ const GLfloat l = texColor[0];
+ const GLfloat oml = 1.0 - l;
+ result[0] = fragColor[0] * oml + envColor[0] * l;
+ result[1] = fragColor[1] * oml + envColor[1] * l;
+ result[2] = fragColor[2] * oml + envColor[2] * l;
+ result[3] = fragColor[3];
+ } break;
+ case GL_LUMINANCE_ALPHA: {
+ const GLfloat l = texColor[0];
+ const GLfloat oml = 1.0 - l;
+ result[0] = fragColor[0] * oml + envColor[0] * l;
+ result[1] = fragColor[1] * oml + envColor[1] * l;
+ result[2] = fragColor[2] * oml + envColor[2] * l;
+ result[3] = fragColor[3] * texColor[3];
+ } break;
+ case GL_INTENSITY: {
+ const GLfloat i = texColor[0];
+ const GLfloat omi = 1.0 - i;
+ result[0] = fragColor[0] * omi + envColor[0] * i;
+ result[1] = fragColor[1] * omi + envColor[1] * i;
+ result[2] = fragColor[2] * omi + envColor[2] * i;
+ result[3] = fragColor[3] * omi + envColor[3] * i;
+ } break;
+ case GL_RGB: {
+ const GLfloat r = texColor[0];
+ const GLfloat omr = 1.0 - r;
+ const GLfloat g = texColor[1];
+ const GLfloat omg = 1.0 - g;
+ const GLfloat b = texColor[2];
+ const GLfloat omb = 1.0 - b;
+ result[0] = fragColor[0] * omr + envColor[0] * r;
+ result[1] = fragColor[1] * omg + envColor[1] * g;
+ result[2] = fragColor[2] * omb + envColor[2] * b;
+ result[3] = fragColor[3];
+ } break;
+ case GL_RGBA: {
+ const GLfloat r = texColor[0];
+ const GLfloat omr = 1.0 - r;
+ const GLfloat g = texColor[1];
+ const GLfloat omg = 1.0 - g;
+ const GLfloat b = texColor[2];
+ const GLfloat omb = 1.0 - b;
+ result[0] = fragColor[0] * omr + envColor[0] * r;
+ result[1] = fragColor[1] * omg + envColor[1] * g;
+ result[2] = fragColor[2] * omb + envColor[2] * b;
+ result[3] = fragColor[3] * texColor[3];
+ } break;
+ default:
+ abort(); // implementation error
+ }
+ break;
+ case GL_ADD:
+ switch (texFormat) {
+ case GL_ALPHA:
+ result[0] = fragColor[0];
+ result[1] = fragColor[1];
+ result[2] = fragColor[2];
+ result[3] = fragColor[3] * texColor[3];
+ break;
+ case GL_LUMINANCE:
+ result[0] = fragColor[0] + texColor[0];
+ result[1] = fragColor[1] + texColor[0];
+ result[2] = fragColor[2] + texColor[0];
+ result[3] = fragColor[3];
+ break;
+ case GL_LUMINANCE_ALPHA:
+ result[0] = fragColor[0] + texColor[0];
+ result[1] = fragColor[1] + texColor[0];
+ result[2] = fragColor[2] + texColor[0];
+ result[3] = fragColor[3] * texColor[3];
+ break;
+ case GL_INTENSITY:
+ result[0] = fragColor[0] + texColor[0];
+ result[1] = fragColor[1] + texColor[0];
+ result[2] = fragColor[2] + texColor[0];
+ result[3] = fragColor[3] + texColor[0];
+ break;
+ case GL_RGB:
+ result[0] = fragColor[0] + texColor[0];
+ result[1] = fragColor[1] + texColor[1];
+ result[2] = fragColor[2] + texColor[2];
+ result[3] = fragColor[3];
+ break;
+ case GL_RGBA:
+ result[0] = fragColor[0] + texColor[0];
+ result[1] = fragColor[1] + texColor[1];
+ result[2] = fragColor[2] + texColor[2];
+ result[3] = fragColor[3] * texColor[3];
+ break;
+ default:
+ abort(); // implementation error
+ }
+ // clamping
+ if (result[0] > 1.0) result[0] = 1.0;
+ if (result[1] > 1.0) result[1] = 1.0;
+ if (result[2] > 1.0) result[2] = 1.0;
+ if (result[3] > 1.0) result[3] = 1.0;
+ break;
+ default:
+ // implementation error
+ abort();
+ }
+
+#if BLEND_WITH_BACKGROUND
+ // now blend result over a gray background
+ const GLfloat alpha = result[3];
+ const GLfloat omAlpha = 1.0 - alpha;
+ result[0] = result[0] * alpha + BgColor[0] * omAlpha;
+ result[1] = result[1] * alpha + BgColor[1] * omAlpha;
+ result[2] = result[2] * alpha + BgColor[2] * omAlpha;
+ result[3] = result[3] * alpha + BgColor[3] * omAlpha;
+#endif
+}
+
+
+// Make a texture in which the colors vary along the length
+// according to the colors[] array. For example, we use
+// 243 columns of the texture to store 81 colors, 3 texels each.
+void
+TexEnvTest::MakeTexImage(GLenum baseFormat, int numColors,
+ const GLfloat colors[][4]) {
+
+ const int width = 256;
+ const int height = 4;
+ GLfloat img[width * height][4];
+
+ assert(numColors == 81); // for now
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int c = j / 3;
+ if (c >= numColors) {
+ img[i * width + j][0] = 0.0;
+ img[i * width + j][1] = 0.0;
+ img[i * width + j][2] = 0.0;
+ img[i * width + j][3] = 0.0;
+ }
+ else {
+ img[i * width + j][0] = colors[c][0];
+ img[i * width + j][1] = colors[c][1];
+ img[i * width + j][2] = colors[c][2];
+ img[i * width + j][3] = colors[c][3];
+ }
+ }
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, baseFormat, width, height, 0,
+ GL_RGBA, GL_FLOAT, (void *) img);
+
+ // Recompute color tolerance now because it depends on the
+ // texel resolution in the new texture.
+ {
+ // Get fb resolution
+ GLint rBits, gBits, bBits;
+ glGetIntegerv(GL_RED_BITS, &rBits);
+ glGetIntegerv(GL_GREEN_BITS, &gBits);
+ glGetIntegerv(GL_BLUE_BITS, &bBits);
+ // Get tex resolution
+ GLint rTexBits, gTexBits, bTexBits, aTexBits;
+ GLint iTexBits, lTexBits;
+ glGetTexLevelParameteriv(GL_TEXTURE_2D,
+ 0, GL_TEXTURE_RED_SIZE, &rTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D,
+ 0, GL_TEXTURE_GREEN_SIZE, &gTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D,
+ 0, GL_TEXTURE_BLUE_SIZE, &bTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D,
+ 0, GL_TEXTURE_ALPHA_SIZE, &aTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D,
+ 0, GL_TEXTURE_INTENSITY_SIZE, &iTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D,
+ 0, GL_TEXTURE_LUMINANCE_SIZE, &lTexBits);
+ // Special cases
+ if (baseFormat == GL_INTENSITY) {
+ rTexBits = gTexBits = bTexBits = iTexBits;
+ }
+ if (baseFormat == GL_ALPHA) {
+ rTexBits = gTexBits = bTexBits = aTexBits;
+ }
+ else if (baseFormat == GL_LUMINANCE ||
+ baseFormat == GL_LUMINANCE_ALPHA) {
+ rTexBits = gTexBits = bTexBits = lTexBits;
+ }
+ // Find smaller of frame buffer and texture bits
+ rBits = (rBits < rTexBits) ? rBits : rTexBits;
+ gBits = (gBits < gTexBits) ? gBits : gTexBits;
+ bBits = (bBits < bTexBits) ? bBits : bTexBits;
+ // If these fail, something's seriously wrong.
+ assert(rBits > 0);
+ assert(gBits > 0);
+ assert(bBits > 0);
+ mTolerance[0] = 3.0 / (1 << rBits);
+ mTolerance[1] = 3.0 / (1 << gBits);
+ mTolerance[2] = 3.0 / (1 << bBits);
+ //printf("tol: %g %g %g\n", mTolerance[0],
+ // mTolerance[1], mTolerance[2]);
+ }
+
+
+}
+
+
+// Do numColors * numColors tests in one batch.
+// Setup a texture in which the colors vary by column.
+// Draw a quadstrip in which we draw horizontal bands of colors.
+// Drawing the textured quadstrips will fill the window with
+// numColors * numColors test squares.
+// Verify that they're all correct.
+// Return: true = pass, false = fail
+bool
+TexEnvTest::MatrixTest(GLenum envMode, GLenum texFormat,
+ const char *envName, const char *formatName,
+ int numColors, const GLfloat colors[][4],
+ const GLfloat envColor[4], Window &w) {
+
+ if (envMode == GL_DECAL && (texFormat != GL_RGB &&
+ texFormat != GL_RGBA)) {
+ // undefined mode
+ return true;
+ }
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // The texture colors are the columns
+ MakeTexImage(texFormat, numColors, colors);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, envMode);
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor);
+
+ // The fragment colors are the rows
+ GLfloat W = numColors * 3;
+ GLfloat S = (float) (numColors*3) / (float) 256;
+ glBegin(GL_QUAD_STRIP);
+ glTexCoord2f(0, 0); glVertex2f(0, 0);
+ glTexCoord2f(S, 0); glVertex2f(W, 0);
+ for (int i = 0; i < numColors; i++) {
+ glColor4fv(colors[i]);
+ GLfloat y = i * 3 + 3;
+ GLfloat t = y / (numColors * 3);
+ glTexCoord2f(0, t); glVertex2f(0, y);
+ glTexCoord2f(S, t); glVertex2f(W, y);
+ }
+ glEnd();
+
+ GLfloat image[256][256][4];
+ glReadPixels(0, 0, 256, 256, GL_RGBA, GL_FLOAT, image);
+
+ w.swap(); // lets us watch the progress
+
+ // Check results
+ for (int row = 0; row < numColors; row++) {
+ for (int col = 0; col < numColors; col++) {
+
+ // compute expected
+ GLfloat expected[4];
+ ComputeExpectedColor(envMode, texFormat,
+ colors[col], colors[row],
+ envColor, expected);
+
+ // fetch actual pixel
+ int x = col * 3 + 1;
+ int y = row * 3 + 1;
+ const GLfloat *actual = image[y][x];
+
+ // compare
+ if (!TestColor(expected, actual)) {
+ // Report the error
+ env->log << name
+ << ": FAIL: GL_TEXTURE_ENV_MODE="
+ << envName
+ << " Texture Format="
+ << formatName
+ << " Fragment Color=("
+ << colors[row][0] << ", "
+ << colors[row][1] << ", "
+ << colors[row][2] << ", "
+ << colors[row][3] << ") "
+ << " Texture Color=("
+ << colors[col][0] << ", "
+ << colors[col][1] << ", "
+ << colors[col][2] << ", "
+ << colors[col][3] << ") "
+ << " Tex Env Color=("
+ << envColor[0] << ", "
+ << envColor[1] << ", "
+ << envColor[2] << ", "
+ << envColor[3] << ") "
+#if BLEND_WITH_BACKGROUND
+ << " Blend over=("
+ << BgColor[0] << ", "
+ << BgColor[1] << ", "
+ << BgColor[2] << ", "
+ << BgColor[3] << ") "
+#endif
+ << " Expected=("
+ << expected[0] << ", "
+ << expected[1] << ", "
+ << expected[2] << ", "
+ << expected[3] << ") "
+ << " Measured=("
+ << actual[0] << ", "
+ << actual[1] << ", "
+ << actual[2] << ", "
+ << actual[3] << ")\n";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+void
+TexEnvTest::runOne(BasicResult& r, Window& w) {
+
+ (void) w;
+
+#define COLORS (3*3*3*3)
+
+ GLfloat colors[COLORS][4];
+
+ // colors[] is an array of all possible RGBA colors with component
+ // values of 0, 0.5, and 1.0
+ for (int i = 0; i < COLORS; i++) {
+ GLint r = i % 3;
+ GLint g = (i / 3) % 3;
+ GLint b = (i / 9) % 3;
+ GLint a = (i / 27) % 3;
+ colors[i][0] = (float) r / 2.0;
+ colors[i][1] = (float) g / 2.0;
+ colors[i][2] = (float) b / 2.0;
+ colors[i][3] = (float) a / 2.0;
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glEnable(GL_TEXTURE_2D);
+
+#if BLEND_WITH_BACKGROUND
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+#endif
+
+ glClearColor(BgColor[0], BgColor[1], BgColor[2], BgColor[3]);
+ glShadeModel(GL_FLAT);
+
+ glViewport(0, 0, 256, 256);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, 256, 0, 256, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.375, 0.375, 0.0);
+
+ int numModes;
+ if (GLUtils::haveExtensions("GL_EXT_texture_env_add") ||
+ GLUtils::haveExtensions("GL_ARB_texture_env_add"))
+ numModes = 5;
+ else
+ numModes = 4;
+
+ r.pass = true;
+
+ for (int fmt = 0; fmt < 6; fmt++) {
+ const GLenum format = FormatEnums[fmt];
+ const char *formatName = FormatNames[fmt];
+ for (int mode = 0; mode < numModes; mode++) {
+ const GLenum envMode = EnvModeEnums[mode];
+ const char *envName = EnvModeNames[mode];
+ //printf("format %s mode %s\n", FormatNames[fmt],
+ // EnvModeNames[mode]);
+ if (envMode == GL_BLEND && format != GL_ALPHA) {
+ // also vary texenv color, every 5th is OK.
+ for (int eCol = 0; eCol < COLORS; eCol += 5) {
+ const GLfloat *envColor = colors[eCol];
+ if (!MatrixTest(envMode, format,
+ envName, formatName,
+ COLORS, colors, envColor, w)) {
+ r.pass = false;
+ break;
+ }
+ }
+ }
+ else {
+ // texenv color not significant
+ if (!MatrixTest(envMode, format,
+ envName, formatName,
+ COLORS, colors, colors[0], w)) {
+ r.pass = false;
+ }
+ }
+ }
+ }
+} // TexEnvTest::runOne
+
+
+void
+TexEnvTest::logOne(BasicResult& r) {
+ logPassFail(r);
+ logConcise(r);
+} // TexEnvTest::logOne
+
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+TexEnvTest texEnvTest("texEnv", "window, rgb",
+
+ "Test basic texture env modes for all base texture formats.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/ttexenv.h b/tests/glean/ttexenv.h
new file mode 100644
index 00000000..6cf1f1e9
--- /dev/null
+++ b/tests/glean/ttexenv.h
@@ -0,0 +1,68 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// ttexenv.h: Test the basic texture env modes
+// Author: Brian Paul (brianp@valinux.com) April 2001
+
+
+#ifndef __ttexenv_h__
+#define __ttexenv_h__
+
+#include "tbasic.h"
+
+namespace GLEAN {
+
+class TexEnvTest: public BasicTest {
+ public:
+ TexEnvTest(const char* testName, const char* filter,
+ const char* description):
+ BasicTest(testName, filter, description) {
+ }
+
+ virtual void runOne(BasicResult& r, Window& w);
+ virtual void logOne(BasicResult& r);
+
+ private:
+ bool TestColor(const GLfloat c1[3], const GLfloat c2[3]);
+ void ComputeExpectedColor(GLenum envMode, GLenum texFormat,
+ const GLfloat texColor[4], const GLfloat fragColor[4],
+ const GLfloat envColor[4], GLfloat result[4]);
+ void MakeTexImage(GLenum baseFormat, int numColors,
+ const GLfloat colors[][4]);
+ bool MatrixTest(GLenum envMode, GLenum texFormat,
+ const char *envName, const char *formatName,
+ int numColors, const GLfloat colors[][4],
+ const GLfloat envColor[4], Window &w);
+ GLfloat mTolerance[3];
+
+}; // class TexEnvTest
+
+} // namespace GLEAN
+
+#endif // __ttexenv_h__
diff --git a/tests/glean/ttexgen.cpp b/tests/glean/ttexgen.cpp
new file mode 100644
index 00000000..55dd7fae
--- /dev/null
+++ b/tests/glean/ttexgen.cpp
@@ -0,0 +1,371 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// ttexgen.cpp: Basic test of GL texture coordinate generation.
+// This test does a basic test of the glTexGen functions, including
+// object_linear, eye_linear, and sphere_map. We use the Sphere3D with
+// a GeomRenderer to draw a sphere, and map a check texture onto it. We
+// use an ortho projection to keep it simple. The result should be a 1:1
+// mapping of the check texture for all three modes (sphere map maps 1:1
+// because mapping it onto a sphere inverts the spheremap math).
+//
+// Note that accuracy issues might cause this test to fail if the
+// texcoords near the center are a little warped; I've specifically tried
+// to keep the matrices as "pure" as possible (no rotations) to
+// keep the numerical precision high. So far it seems to work fine.
+// Introducing a rotation by 90 degrees about the x axis resulted,
+// on one driver, in a warping at the center of the sphere which caused
+// the test to fail.
+//
+// For the second test of the three, we offset the texture by 0.5,
+// so that each test's rendering is visually distinct from the
+// previous.
+//
+// To test for pass/fail we examine the color buffer for red and blue,
+// (the check colors) in the appropriate places.
+//
+// Author: Brian Sharp (brian@maniacal.org) December 2000
+
+#include "ttexgen.h"
+#include <stdio.h>
+#include "geomutil.h"
+
+
+const GLuint viewSize=50;
+
+
+namespace GLEAN {
+
+void
+TexgenTest::FailMessage(BasicResult &r, const std::string& texgenMode,
+ GeomRenderer::DrawMethod method, bool arraysCompiled,
+ int retainedMode,
+ const std::string& colorMismatch) const {
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n';
+ env->log << "\t" << "during mode " << texgenMode << ", ";
+ switch(method)
+ {
+ case GeomRenderer::GLVERTEX_MODE: env->log << "glVertex-style rendering, "; break;
+ case GeomRenderer::GLARRAYELEMENT_MODE: env->log << "glArrayElement-style rendering, "; break;
+ case GeomRenderer::GLDRAWELEMENTS_MODE: env->log << "glDrawElements-style rendering, "; break;
+ case GeomRenderer::GLDRAWARRAYS_MODE: env->log << "glDrawArrays-style rendering, "; break;
+ }
+ if (arraysCompiled) env->log << "arrays locked, ";
+ else env->log << "arrays not locked, ";
+
+ if (retainedMode) env->log << "built into a display list, ";
+ else env->log << "called immediately (not display listed), ";
+
+ env->log << colorMismatch << std::endl;
+}
+
+bool
+TexgenTest::compareColors(GLfloat* color0, GLfloat* color1, std::string& failureInfo) const {
+
+ // Compare the colors; fail and report why if they don't match.
+ if (color0[0] != color1[0] || color0[1] != color1[1] || color0[2] != color1[2])
+ {
+ // Assemble the error message into a C-string, then hand it back in the string.
+ char failureOut[1024];
+ sprintf(failureOut, "expected [%f,%f,%f], read back [%f,%f,%f]",
+ color0[0], color0[1], color0[2],
+ color1[0], color1[1], color1[2]);
+
+ failureInfo = std::string(failureOut);
+ return false;
+ }
+
+ return true;
+}
+
+bool
+TexgenTest::verifyCheckers(GLfloat* pixels, GLfloat* upperLeftColor, GLfloat* upperRightColor, std::string& failureInfo) const {
+
+ // My loop control variable, since gcc and MSVC do things differently.
+ GLint samp;
+
+ // It's a viewSize x viewSize pixel block; since we drew a sphere that doesn't quite touch the
+ // edges, we need to be careful not to sample from what should be background.
+ // These pairs are hand-picked coordinates on the image that fall on the bottom-left quadrant
+ // of the sphere.
+ // XXX FIX ME: these sample coordinates assume that viewSize == 50.
+ GLuint samples[6][2] = {{13,13}, {4,22}, {22,4}, {20,20}, {20,10}, {10,20}};
+
+ // Run through those sample points in the bottom-left corner and make sure they're all the right color.
+ for (samp=0; samp<6; samp++)
+ {
+ GLuint sampleOffset = (samples[samp][0] + (viewSize*samples[samp][1]))*3;
+ if (!compareColors(upperRightColor, pixels + sampleOffset, failureInfo))
+ {
+ return false;
+ }
+ }
+
+ // Run through those sample points in the bottom-right corner and make sure they're all the right color.
+ // Note the "viewSize - samples[samp][0]" to flip it to the bottom-right quadrant.
+ for (samp=0; samp<6; samp++)
+ {
+ GLuint sampleOffset = ((viewSize - samples[samp][0]) + (viewSize*samples[samp][1]))*3;
+ if (!compareColors(upperLeftColor, pixels + sampleOffset, failureInfo))
+ {
+ return false;
+ }
+ }
+
+ // Run through those sample points in the upper-right corner and make sure they're all the right color.
+ for (samp=0; samp<6; samp++)
+ {
+ GLuint sampleOffset = ((viewSize - samples[samp][0]) + (viewSize*(viewSize - samples[samp][1])))*3;
+ if (!compareColors(upperRightColor, pixels + sampleOffset, failureInfo))
+ {
+ return false;
+ }
+ }
+
+ // Run through those sample points in the upper-left corner and make sure they're all the right color.
+ for (samp=0; samp<6; samp++)
+ {
+ GLuint sampleOffset = (samples[samp][0] + (viewSize*(viewSize - samples[samp][1])))*3;
+ if (!compareColors(upperLeftColor, pixels + sampleOffset, failureInfo))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+TexgenTest::runOne(BasicResult& r, Window&) {
+
+ // Temporary buffer to store pixels we've read back for verification.
+ GLfloat pixels[50*50*3];
+
+ // Colors for matching against when we readback pixels.
+ GLfloat matchBlue[3] = {0,0,1};
+ GLfloat matchRed[3] = {1,0,0};
+
+ // A sphere to draw.
+ Sphere3D theSphere(9.9, 32, 16);
+
+ // A GeomRenderer to draw it with.
+ GeomRenderer sphereRenderer;
+ sphereRenderer.setDrawMethod(GeomRenderer::GLVERTEX_MODE);
+ sphereRenderer.setParameterBits(GeomRenderer::NORMAL_BIT);
+ sphereRenderer.setVArrayIndices(theSphere.getNumIndices(),GL_UNSIGNED_INT,theSphere.getIndices());
+ sphereRenderer.setVertexPointer(theSphere.getNumVertices(), 3, GL_FLOAT, 0, theSphere.getVertices());
+ sphereRenderer.setNormalPointer(GL_FLOAT, 0, theSphere.getNormals());
+
+ // draw the sphere in a 50x50 pixel window for some precision.
+ glViewport(0, 0, 50, 50);
+
+ // Basic GL setup.
+ glDisable(GL_DITHER);
+ glEnable(GL_CULL_FACE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glColor3f(1,1,1);
+
+ // Setup the projection.
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-10,10,-10,10,-10,10);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ // Set up our texture.
+ glEnable(GL_TEXTURE_2D);
+ GLuint checkerTextureHandle;
+ glGenTextures(1, &checkerTextureHandle);
+ glBindTexture(GL_TEXTURE_2D, checkerTextureHandle);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+
+ // Make a little checker texture.
+ unsigned char redBlueCheck[256*256*3];
+ for (int x=0; x<256; x++)
+ {
+ for (int y=0; y<256; y++)
+ {
+ bool xPastHalf = x >= 128;
+ bool yPastHalf = y >= 128;
+
+ redBlueCheck[(x+(256*y))*3 + 0] = ((xPastHalf && yPastHalf) || (!xPastHalf && !yPastHalf)) ? 255 : 0;
+ redBlueCheck[(x+(256*y))*3 + 1] = 0;
+ redBlueCheck[(x+(256*y))*3 + 2] = ((xPastHalf && !yPastHalf) || (!xPastHalf && yPastHalf)) ? 255 : 0;
+ }
+ }
+ gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, 256, 256, GL_RGB, GL_UNSIGNED_BYTE, redBlueCheck);
+
+ // Setup our arrays of configuration info; we loop over the rendering pass a number of times,
+ // using a different GL primitive path each time.
+ GeomRenderer::DrawMethod drawMethods[] = {GeomRenderer::GLVERTEX_MODE, GeomRenderer::GLARRAYELEMENT_MODE,
+ GeomRenderer::GLDRAWELEMENTS_MODE, GeomRenderer::GLARRAYELEMENT_MODE,
+ GeomRenderer::GLDRAWELEMENTS_MODE};
+
+ bool arraysCompiled[] = {false, false, false, true, true};
+
+ // Iterate once for all immediate mode styles, then once for retained mode styles.
+ for (int retainedMode=0; retainedMode<2; retainedMode++)
+ {
+ for (int testIteration=0; testIteration<5; testIteration++)
+ {
+ sphereRenderer.setDrawMethod(drawMethods[testIteration]);
+ if (!sphereRenderer.setArraysCompiled(arraysCompiled[testIteration]))
+ {
+ // We don't have the extension... not sure what we should do.
+ // May as well just keep going, it's no big deal (it should still
+ // yield correct results, of course, it's just redundant).
+ }
+
+ // GL_SPHERE_MAP: with spheremap, the UL corner is blue
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ renderSphere(retainedMode, sphereRenderer);
+ glReadPixels(0,0,50,50, GL_RGB, GL_FLOAT, pixels);
+
+ // Validate it.
+ std::string sphereMapResult;
+ if (!verifyCheckers(pixels, matchBlue, matchRed, sphereMapResult))
+ {
+ FailMessage(r, std::string("GL_SPHERE_MAP"), drawMethods[testIteration],
+ arraysCompiled[testIteration], retainedMode, sphereMapResult);
+ r.pass = false;
+ glDeleteTextures(1, &checkerTextureHandle);
+ return;
+ }
+
+ // GL_OBJECT_LINEAR: with object linear and the below planes, the UL corner is red.
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ float sObjPlane[4] = {0,0.05,0,1.5}; // We flip the checker by setting W to 1.5 (phases by half a period)
+ float tObjPlane[4] = {0.05,0,0,1};
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, sObjPlane);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, tObjPlane);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ renderSphere(retainedMode, sphereRenderer);
+ glReadPixels(0,0,50,50, GL_RGB, GL_FLOAT, pixels);
+
+ // Validate it.
+ std::string objectLinearResult;
+ if (!verifyCheckers(pixels, matchRed, matchBlue, objectLinearResult))
+ {
+ FailMessage(r, std::string("GL_OBJECT_LINEAR"), drawMethods[testIteration],
+ arraysCompiled[testIteration], retainedMode, objectLinearResult);
+ r.pass = false;
+ glDeleteTextures(1, &checkerTextureHandle);
+ return;
+ }
+
+ // GL_EYE_LINEAR: with eye linear and the below planes, the UL corner is blue.
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ float sEyePlane[4] = {0,0.05,0,1};
+ float tEyePlane[4] = {0.05,0,0,1};
+ glTexGenfv(GL_S, GL_EYE_PLANE, sEyePlane);
+ glTexGenfv(GL_T, GL_EYE_PLANE, tEyePlane);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ renderSphere(retainedMode, sphereRenderer);
+ glReadPixels(0,0,50,50, GL_RGB, GL_FLOAT, pixels);
+
+ // Validate it.
+ std::string eyeLinearResult;
+ if (!verifyCheckers(pixels, matchBlue, matchRed, eyeLinearResult))
+ {
+ FailMessage(r, std::string("GL_EYE_LINEAR"), drawMethods[testIteration],
+ arraysCompiled[testIteration], retainedMode, eyeLinearResult);
+ r.pass = false;
+ glDeleteTextures(1, &checkerTextureHandle);
+ return;
+ }
+ }
+ }
+
+ // success
+ r.pass = true;
+} // TexgenTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+TexgenTest::logOne(BasicResult& r) {
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+} // TexgenTest::logOne
+
+void
+TexgenTest::renderSphere(int retainedMode, GeomRenderer& sphereRenderer)
+{
+ if (retainedMode)
+ {
+ GLint displayList;
+ assert(sphereRenderer.generateDisplayList(GL_TRIANGLES, displayList));
+ glCallList(displayList);
+ glDeleteLists(displayList, 1);
+ }
+ else
+ {
+ assert(sphereRenderer.renderPrimitives(GL_TRIANGLES));
+ }
+} // TexgenTest::renderSphere
+
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+TexgenTest texgenTest("texgen", "window, rgb",
+
+ "This test verifies that the three basic OpenGL texture coordinate\n"
+ "modes: object_linear, eye_linear, and sphere_map, work for a simple\n"
+ "case.\n");
+
+
+} // namespace GLEAN
+
+
+
+
+
diff --git a/tests/glean/ttexgen.h b/tests/glean/ttexgen.h
new file mode 100644
index 00000000..2a214b03
--- /dev/null
+++ b/tests/glean/ttexgen.h
@@ -0,0 +1,67 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// ttexgen.h: Basic test of GL texture coordinate generation.
+// Author: Brian Sharp (brian@maniacal.org) December 2000
+
+
+#ifndef __ttexgen_h__
+#define __ttexgen_h__
+
+#include "tbasic.h"
+#include "geomrend.h"
+
+namespace GLEAN {
+
+class TexgenTest: public BasicTest {
+public:
+ TexgenTest(const char* testName, const char* filter,
+ const char* description):
+ BasicTest(testName, filter, description) {
+ }
+ virtual void runOne(BasicResult& r, Window& w);
+ virtual void logOne(BasicResult& r);
+
+private:
+ void FailMessage(BasicResult &r, const std::string& texgenMode,
+ GeomRenderer::DrawMethod,
+ bool arraysCompiled, int retainedMode,
+ const std::string& colorMismatch) const;
+ void renderSphere(int retainedMode, GeomRenderer& sphereRenderer);
+ bool compareColors(GLfloat* color0, GLfloat* color1,
+ std::string& failureInfo) const;
+ bool verifyCheckers(GLfloat* pixels, GLfloat* upperLeftColor,
+ GLfloat* upperRightColor,
+ std::string& failureInfo) const;
+
+}; // class TexgenTest
+
+} // namespace GLEAN
+
+#endif // __ttexgen_h__
diff --git a/tests/glean/ttexrect.cpp b/tests/glean/ttexrect.cpp
new file mode 100644
index 00000000..7adcb3a0
--- /dev/null
+++ b/tests/glean/ttexrect.cpp
@@ -0,0 +1,217 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+
+/*
+ * Copyright © 2006 Intel Corporation
+ * Copyright © 1999 Allen Akin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+/* ttexrect.cpp: Test the ARB_texture_rectangle extension
+ * Author: Eric Anholt <eric@anholt.net>
+ *
+ * Test procedure:
+ * Create a 255x127 texture of varying colors and bind it as a
+ * GL_ARB_texture_recangle target. Draw that rectangle to the window, and
+ * check that the texture was drawn correctly. The common failure to be
+ * caught with this test is not adjusting the non-normalized coordinates on
+ * hardware that expects normalized coordinates.
+ */
+
+#include "ttexrect.h"
+#include <cassert>
+#include <stdio.h>
+#include <cmath>
+
+namespace GLEAN {
+
+/**
+ * Test if two colors are close enough to be considered the same.
+ */
+bool
+TexRectTest::TestColor(const GLfloat c1[3], const GLfloat c2[3])
+{
+ if (fabs(c1[0] - c2[0]) <= mTolerance[0] &&
+ fabs(c1[1] - c2[1]) <= mTolerance[1] &&
+ fabs(c1[2] - c2[2]) <= mTolerance[2])
+ return true;
+ else
+ return false;
+}
+
+void
+TexRectTest::CalculateTolerance()
+{
+ GLint rBits, gBits, bBits;
+ GLint rTexBits, gTexBits, bTexBits;
+
+ // Get fb resolution
+ glGetIntegerv(GL_RED_BITS, &rBits);
+ glGetIntegerv(GL_GREEN_BITS, &gBits);
+ glGetIntegerv(GL_BLUE_BITS, &bBits);
+
+ // Get tex resolution
+ glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB,
+ 0, GL_TEXTURE_RED_SIZE, &rTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB,
+ 0, GL_TEXTURE_GREEN_SIZE, &gTexBits);
+ glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB,
+ 0, GL_TEXTURE_BLUE_SIZE, &bTexBits);
+
+ // Find smaller of frame buffer and texture bits
+ rBits = (rBits < rTexBits) ? rBits : rTexBits;
+ gBits = (gBits < gTexBits) ? gBits : gTexBits;
+ bBits = (bBits < bTexBits) ? bBits : bTexBits;
+
+ // If these fail, something's seriously wrong.
+ assert(rBits > 0);
+ assert(gBits > 0);
+ assert(bBits > 0);
+ mTolerance[0] = 3.0 / (1 << rBits);
+ mTolerance[1] = 3.0 / (1 << gBits);
+ mTolerance[2] = 3.0 / (1 << bBits);
+}
+
+#define TEXTURE_WIDTH 255
+#define TEXTURE_HEIGHT 127
+
+/**
+ * Creates a TEXTURE_WIDTH * TEXTURE_HEIGHT rectangular texture and draws it to
+ * the window. It then reads the output back to verify that the texture stayed
+ * intact.
+ */
+void
+TexRectTest::runOne(BasicResult& r, Window& w)
+{
+ float image[TEXTURE_WIDTH * TEXTURE_HEIGHT * 3];
+ float actual[TEXTURE_WIDTH * TEXTURE_HEIGHT * 3];
+ (void) w;
+
+ /* Set up a texture that is color ramps with red to black top to
+ * bottom and green to black left to right.
+ */
+ for (int y = 0; y < TEXTURE_HEIGHT; y++) {
+ for (int x = 0; x < TEXTURE_WIDTH; x++) {
+ int i = (y * TEXTURE_WIDTH + x) * 3;
+
+ image[i + 0] = (float)x / (TEXTURE_WIDTH - 1);
+ image[i + 1] = 1.0 - ((float) y / (TEXTURE_HEIGHT - 1));
+ image[i + 2] = 0.0;
+ }
+ }
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glShadeModel(GL_FLAT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, 256, 0, 256, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glViewport(0, 0, windowSize, windowSize);
+
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, 255, 127, 0,
+ GL_RGB, GL_FLOAT, image);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+
+ if (w.config->db) {
+ glDrawBuffer(GL_BACK);
+ glReadBuffer(GL_BACK);
+ }
+
+ r.pass = true;
+
+ /* Draw our texture to the window such that each texel should map
+ * to the corresponding pixel of the window.
+ */
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0);
+ glVertex2f(0, 0);
+
+ glTexCoord2f(TEXTURE_WIDTH, 0);
+ glVertex2f(TEXTURE_WIDTH, 0);
+
+ glTexCoord2f(TEXTURE_WIDTH, TEXTURE_HEIGHT);
+ glVertex2f(TEXTURE_WIDTH, TEXTURE_HEIGHT);
+
+ glTexCoord2f(0, TEXTURE_HEIGHT);
+ glVertex2f(0, TEXTURE_HEIGHT);
+ glEnd();
+
+ /* Read back the output */
+ glReadPixels(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT,
+ GL_RGB, GL_FLOAT, actual);
+
+ w.swap(); // lets us watch the progress
+
+ CalculateTolerance();
+
+ /* Verify the output */
+ for (int y = 0; y < TEXTURE_HEIGHT; y++) {
+ for (int x = 0; x < TEXTURE_WIDTH; x++) {
+ int i = (y * TEXTURE_WIDTH + x) * 3;
+
+ if (!TestColor(&image[i], &actual[i])) {
+ // Report the error
+ env->log << name
+ << ": FAIL at (" << x << "," << y
+ << "):\n"
+ << " Expected=("
+ << image[i + 0] << ", "
+ << image[i + 1] << ", "
+ << image[i + 2] << ")\n"
+ << " Measured=("
+ << actual[i + 0] << ", "
+ << actual[i + 1] << ", "
+ << actual[i + 2] << ")\n";
+ r.pass = false;
+ }
+ }
+ }
+} // TexRectTest::runOne
+
+
+void
+TexRectTest::logOne(BasicResult& r) {
+ logPassFail(r);
+ logConcise(r);
+} // TexRectTest::logOne
+
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+TexRectTest texRectTest("texRect", "window, rgb",
+ "GL_ARB_texture_rectangle",
+ "Test basic texture rectangle functionality.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/ttexrect.h b/tests/glean/ttexrect.h
new file mode 100644
index 00000000..5e8675bc
--- /dev/null
+++ b/tests/glean/ttexrect.h
@@ -0,0 +1,61 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+
+// ttexenv.h: Test basic ARB_texture_rectangle support.
+// Author: Eric Anholt <eric@anholt.net>
+
+#ifndef __ttexrect_h__
+#define __ttexrect_h__
+
+#include "tbasic.h"
+
+#define windowSize 256
+namespace GLEAN {
+
+class TexRectTest: public BasicTest {
+ public:
+ TexRectTest(const char* testName, const char* filter,
+ const char *prereqs, const char* description):
+ BasicTest(testName, filter, prereqs, description) {
+ }
+
+ virtual void runOne(BasicResult& r, Window& w);
+ virtual void logOne(BasicResult& r);
+
+ private:
+ bool TestColor(const GLfloat c1[3], const GLfloat c2[3]);
+ void CalculateTolerance();
+ GLfloat mTolerance[3];
+
+}; // class TexRectTest
+
+} // namespace GLEAN
+
+#endif // __ttexrect_h__
diff --git a/tests/glean/ttexture_srgb.cpp b/tests/glean/ttexture_srgb.cpp
new file mode 100644
index 00000000..809a56a6
--- /dev/null
+++ b/tests/glean/ttexture_srgb.cpp
@@ -0,0 +1,373 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// ttexture_srgb.h: Test GL_EXT_texture_sRGB extension.
+// Brian Paul August 2006
+
+
+#include "ttexture_srgb.h"
+#include "rand.h"
+#include <cassert>
+#include <cmath>
+
+#ifdef GL_EXT_texture_sRGB
+
+namespace GLEAN {
+
+
+static const struct {
+ GLenum sFormat;
+ GLenum baseFormat;
+ GLint components;
+} Formats[] = {
+ { GL_SRGB_EXT, GL_RGB, 3 },
+ { GL_SRGB8_EXT, GL_RGB, 3 },
+ { GL_SRGB_ALPHA_EXT, GL_RGBA, 4 },
+ { GL_SRGB8_ALPHA8_EXT, GL_RGBA, 4 },
+ { GL_SLUMINANCE_ALPHA_EXT, GL_LUMINANCE_ALPHA, 2 },
+ { GL_SLUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 2 },
+ { GL_SLUMINANCE_EXT, GL_LUMINANCE, 1 },
+ { GL_SLUMINANCE8_EXT, GL_LUMINANCE, 1 },
+ { 0, 0, 0 }
+};
+
+
+
+
+// Convert an 8-bit sRGB value from non-linear space to a
+// linear RGB value in [0, 1].
+// Implemented with a 256-entry lookup table.
+static float
+nonlinear_to_linear(GLubyte cs8)
+{
+ static GLfloat table[256];
+ static GLboolean tableReady = GL_FALSE;
+ if (!tableReady) {
+ // compute lookup table now
+ GLuint i;
+ for (i = 0; i < 256; i++) {
+ const GLfloat cs = i / 255.0;
+ if (cs <= 0.04045) {
+ table[i] = cs / 12.92;
+ }
+ else {
+ table[i] = pow((cs + 0.055) / 1.055, 2.4);
+ }
+ }
+ tableReady = GL_TRUE;
+ }
+ return table[cs8];
+}
+
+
+// allocate and fill an array with random values
+static GLubyte *
+randomArray(int bytes, int seed)
+{
+ GLEAN::RandomBits r(8, seed);
+ GLubyte *img = new GLubyte [bytes];
+
+ for (int i = 0; i < bytes; i++)
+ img[i] = r.next();
+
+ return img;
+}
+
+
+// Test glTexImage and glGetTexImage functionality
+bool
+TextureSRGBTest::testImageTransfer(void)
+{
+ const GLubyte *image = randomArray(128 * 128 * 4, 0);
+ GLubyte image2[128 * 128 * 4];
+ int i, j;
+
+ for (i = 0; Formats[i].sFormat; i++) {
+ // upload tex image
+ glTexImage2D(GL_TEXTURE_2D, 0, Formats[i].sFormat, 128, 128, 0,
+ Formats[i].baseFormat, GL_UNSIGNED_BYTE, image);
+
+ // retrieve tex image
+ glGetTexImage(GL_TEXTURE_2D, 0,
+ Formats[i].baseFormat, GL_UNSIGNED_BYTE, image2);
+
+ // compare original and returned images
+ const int comps = Formats[i].components;
+ for (j = 0; j < 128 * 128 * comps; j++) {
+ if (image[j] != image2[j]) {
+ env->log << '\n'
+ << name
+ << " glGetTexImage failed for internalFormat "
+ << Formats[i].sFormat
+ << "\n";
+ env->log << "Expected value at ["
+ << j
+ << "] should be "
+ << image[j]
+ << " found "
+ << image2[j]
+ << "\n";
+ delete [] image;
+ return false;
+ }
+ image2[j] = 0; // reset for next GetTexImage
+ }
+ }
+
+ delete [] image;
+ return true;
+}
+
+
+bool
+TextureSRGBTest::testTextureFormat(GLenum intFormat, GLint components,
+ GLEAN::Environment &env)
+{
+ const GLubyte *image = randomArray(128 * 128 * 4, intFormat);
+ GLfloat readback[128 * 128 * 4];
+ int i;
+ GLint redBits, alphaBits;
+
+ glGetIntegerv(GL_RED_BITS, &redBits);
+ glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
+ const float tolerance = 1.0 / ((1 << redBits) - 1);
+
+ // setup matrices
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glViewport(0, 0, windowSize, windowSize);
+
+ // setup texture
+ glTexImage2D(GL_TEXTURE_2D, 0, intFormat, 128, 128, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ // draw test polygon
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-1, -1);
+ glTexCoord2f(1, 0); glVertex2f( 1, -1);
+ glTexCoord2f(1, 1); glVertex2f( 1, 1);
+ glTexCoord2f(0, 1); glVertex2f(-1, 1);
+ glEnd();
+
+ glReadPixels(0, 0, windowSize, windowSize,
+ GL_RGBA, GL_FLOAT, readback);
+
+ // compare rendered results to expected values
+ for (i = 0; i < 128 * 128; i++) {
+ const GLfloat *actual = readback + i * 4;
+ GLfloat expected[4];
+
+ expected[0] = nonlinear_to_linear(image[i * 4 + 0]);
+ expected[1] = nonlinear_to_linear(image[i * 4 + 1]);
+ expected[2] = nonlinear_to_linear(image[i * 4 + 2]);
+ expected[3] = image[i * 4 + 3] / 255.0;
+
+ if (components <= 2) {
+ if (fabs(actual[0] - expected[0]) > tolerance) {
+ env.log << '\n'
+ << name
+ << " failed for internalFormat "
+ << intFormat
+ << "\n";
+ env.log << "Expected luminance "
+ << expected[0]
+ << " found "
+ << actual[0]
+ << "\n";
+ delete [] image;
+ return GL_FALSE;
+ }
+
+ }
+ else {
+ assert(components == 3 || components == 4);
+ if (fabs(actual[0] - expected[0]) > tolerance ||
+ fabs(actual[1] - expected[1]) > tolerance ||
+ fabs(actual[2] - expected[2]) > tolerance) {
+ env.log << '\n'
+ << name
+ << " failed for internalFormat "
+ << intFormat
+ << "\n";
+ env.log << "Expected color "
+ << expected[0]
+ << ", "
+ << expected[1]
+ << ", "
+ << expected[2]
+ << " found "
+ << actual[0]
+ << ", "
+ << actual[1]
+ << ", "
+ << actual[2]
+ << "\n";
+ delete [] image;
+ return GL_FALSE;
+ }
+ }
+
+ if (alphaBits >= redBits
+ && components == 4
+ && fabs(actual[3] - expected[3]) > tolerance) {
+ env.log << '\n'
+ << name
+ << " failed for internalFormat "
+ << intFormat
+ << "\n";
+ env.log << "Expected alpha "
+ << expected[3]
+ << " found "
+ << actual[3]
+ << "\n";
+ delete [] image;
+ return GL_FALSE;
+ }
+ }
+
+ delete [] image;
+ return GL_TRUE;
+}
+
+
+// Test actual texture mapping using each of the sRGB formats
+// Return GL_TRUE if all format tests pass, GL_FALSE if any fail.
+bool
+TextureSRGBTest::testTexturing(void)
+{
+ for (int i = 0; Formats[i].sFormat; i++) {
+ if (!testTextureFormat(Formats[i].sFormat,
+ Formats[i].components, *env))
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+void
+TextureSRGBTest::runOne(TextureSRGBResult &r, Window &w)
+{
+ (void) w; // silence warning
+ r.pass = true;
+ errorCode = 0;
+ errorPos = NULL;
+ errorMsg[0] = 0;
+
+ if (r.pass)
+ r.pass = testImageTransfer();
+ if (r.pass)
+ r.pass = testTexturing();
+}
+
+
+void
+TextureSRGBTest::logOne(TextureSRGBResult &r)
+{
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ }
+ else {
+ env->log << name << " FAIL\n";
+ if (errorCode) {
+ env->log << "\tOpenGL Error " << gluErrorString(errorCode)
+ << " at " << errorPos << "\n";
+ }
+ else if (errorMsg[0]) {
+ env->log << "\t" << errorMsg << "\n";
+ }
+ }
+}
+
+
+void
+TextureSRGBTest::compareOne(TextureSRGBResult &oldR,
+ TextureSRGBResult &newR)
+{
+ comparePassFail(oldR, newR);
+
+ if (newR.pass && oldR.pass == newR.pass) {
+ // XXX
+ }
+ else {
+ env->log << "\tNew: ";
+ env->log << (newR.pass ? "PASS" : "FAIL");
+ env->log << "\tOld: ";
+ env->log << (oldR.pass ? "PASS" : "FAIL");
+ }
+}
+
+
+void
+TextureSRGBResult::putresults(ostream &s) const
+{
+ if (pass) {
+ s << "PASS\n";
+ }
+ else {
+ s << "FAIL\n";
+ }
+}
+
+
+bool
+TextureSRGBResult::getresults(istream &s)
+{
+ char result[1000];
+ s >> result;
+
+ if (strcmp(result, "FAIL") == 0) {
+ pass = false;
+ }
+ else {
+ pass = true;
+ }
+ return s.good();
+}
+
+
+// The test object itself:
+TextureSRGBTest srgbTest("texture_srgb", "window, rgb",
+ "GL_EXT_texture_sRGB",
+ "Test the GL_EXT_texture_sRGB extension.\n");
+
+
+
+} // namespace GLEAN
+
+#endif // GL_EXT_texture_sRGB
diff --git a/tests/glean/ttexture_srgb.h b/tests/glean/ttexture_srgb.h
new file mode 100644
index 00000000..1095565d
--- /dev/null
+++ b/tests/glean/ttexture_srgb.h
@@ -0,0 +1,73 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// ttexture_srgb.h: Test GL_EXT_texture_sRGB extension.
+// Brian Paul August 2006
+
+#ifndef __ttexture_srgb_h__
+#define __ttexture_srgb_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define windowSize 128
+
+class TextureSRGBResult: public BaseResult
+{
+public:
+ bool pass;
+
+ virtual void putresults(ostream& s) const;
+ virtual bool getresults(istream& s);
+};
+
+
+class TextureSRGBTest: public BaseTest<TextureSRGBResult>
+{
+public:
+ GLEAN_CLASS_WH(TextureSRGBTest, TextureSRGBResult,
+ windowSize, windowSize);
+
+private:
+ GLenum errorCode;
+ const char *errorPos;
+ char errorMsg[1000];
+
+ bool testImageTransfer(void);
+ bool testTextureFormat(GLenum intFormat, GLint components,
+ GLEAN::Environment &env);
+ bool testTexturing(void);
+
+ void testPerformance(TextureSRGBResult &r);
+};
+
+} // namespace GLEAN
+
+#endif // __ttexture_srgb_h__
+
diff --git a/tests/glean/tvertattrib.cpp b/tests/glean/tvertattrib.cpp
new file mode 100644
index 00000000..fd7e12cb
--- /dev/null
+++ b/tests/glean/tvertattrib.cpp
@@ -0,0 +1,1620 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+// tvertattrib.cpp: Test vertex attribute functions.
+//
+// Indexed vertex attributes may either alias with conventional attributes
+// or name a separate set of generic attributes. The following extensions/
+// versions are tested (and whether aliasing is allowed):
+// GL_NV_vertex_program (aliasing required)
+// GL_ARB_vertex_program (aliasing optional)
+// GL_ARB_vertex_shader (aliasing disallowed)
+// OpenGL 2.0 (aliasing disallowed)
+//
+// If either GL_ARB_vertex_shader or OpenGL 2.0 is supported, that means
+// aliasing is required for GL_ARB_vertex_program too.
+//
+// We test both immediate mode and display list mode.
+//
+// Author: Brian Paul (brian.paul a t tungstengraphics.com) October 2004
+
+
+#include <math.h>
+#include "tvertattrib.h"
+#include "glutils.h"
+#include <cassert>
+
+namespace GLEAN {
+
+#define COPY1(DST, SRC) DST[0] = SRC[0]; DST[1] = 0.0F; DST[2] = 0.0F; DST[3] = 1.0F
+
+#define COPY2(DST, SRC) DST[0] = SRC[0]; DST[1] = SRC[1]; DST[2] = 0.0F; DST[3] = 1.0F
+
+#define COPY3(DST, SRC) DST[0] = SRC[0]; DST[1] = SRC[1]; DST[2] = SRC[2]; DST[3] = 1.0F
+
+#define COPY4(DST, SRC) DST[0] = SRC[0]; DST[1] = SRC[1]; DST[2] = SRC[2]; DST[3] = SRC[3]
+
+#define FLOAT_TO_BYTE(X) ( (((GLint) (255.0F * (X))) - 1) / 2 )
+
+#define FLOAT_TO_UBYTE(X) ((GLubyte) (GLint) ((X) * 255.0F))
+
+#define FLOAT_TO_SHORT(X) ( (((GLint) (65535.0F * (X))) - 1) / 2 )
+
+#define FLOAT_TO_USHORT(X) ((GLushort) (GLint) ((X) * 65535.0F))
+
+#define FLOAT_TO_INT(X) ( (GLint) (2147483647.0 * (X)) )
+
+#define FLOAT_TO_UINT(X) ((GLuint) ((X) * 4294967295.0))
+
+
+#define NUM_NV_ATTRIB_FUNCS 26
+#define NUM_ARB_ATTRIB_FUNCS 36
+#define NUM_2_0_ATTRIB_FUNCS 36
+
+static const char *
+AttribFuncNames[NUM_NV_ATTRIB_FUNCS + NUM_ARB_ATTRIB_FUNCS + NUM_2_0_ATTRIB_FUNCS] = {
+ "glVertexAttrib1fNV",
+ "glVertexAttrib2fNV",
+ "glVertexAttrib3fNV",
+ "glVertexAttrib4fNV",
+ "glVertexAttrib1fvNV",
+ "glVertexAttrib2fvNV",
+ "glVertexAttrib3fvNV",
+ "glVertexAttrib4fvNV",
+ "glVertexAttrib1dNV",
+ "glVertexAttrib2dNV",
+ "glVertexAttrib3dNV",
+ "glVertexAttrib4dNV",
+ "glVertexAttrib1dvNV",
+ "glVertexAttrib2dvNV",
+ "glVertexAttrib3dvNV",
+ "glVertexAttrib4dvNV",
+ "glVertexAttrib1sNV",
+ "glVertexAttrib2sNV",
+ "glVertexAttrib3sNV",
+ "glVertexAttrib4sNV",
+ "glVertexAttrib1svNV",
+ "glVertexAttrib2svNV",
+ "glVertexAttrib3svNV",
+ "glVertexAttrib4svNV",
+ "glVertexAttrib4ubNV",
+ "glVertexAttrib4ubvNV",
+
+ "glVertexAttrib1fARB",
+ "glVertexAttrib2fARB",
+ "glVertexAttrib3fARB",
+ "glVertexAttrib4fARB",
+ "glVertexAttrib1fvARB",
+ "glVertexAttrib2fvARB",
+ "glVertexAttrib3fvARB",
+ "glVertexAttrib4fvARB",
+ "glVertexAttrib1dARB",
+ "glVertexAttrib2dARB",
+ "glVertexAttrib3dARB",
+ "glVertexAttrib4dARB",
+ "glVertexAttrib1dvARB",
+ "glVertexAttrib2dvARB",
+ "glVertexAttrib3dvARB",
+ "glVertexAttrib4dvARB",
+ "glVertexAttrib1sARB",
+ "glVertexAttrib2sARB",
+ "glVertexAttrib3sARB",
+ "glVertexAttrib4sARB",
+ "glVertexAttrib1svARB",
+ "glVertexAttrib2svARB",
+ "glVertexAttrib3svARB",
+ "glVertexAttrib4svARB",
+ "glVertexAttrib4NsvARB",
+ "glVertexAttrib4NubARB",
+ "glVertexAttrib4NubvARB",
+ "glVertexAttrib4ubvARB",
+ "glVertexAttrib4NbvARB",
+ "glVertexAttrib4bvARB",
+ "glVertexAttrib4NivARB",
+ "glVertexAttrib4ivARB",
+ "glVertexAttrib4NuivARB",
+ "glVertexAttrib4uivARB",
+ "glVertexAttrib4NusvARB",
+ "glVertexAttrib4usvARB",
+
+ "glVertexAttrib1f",
+ "glVertexAttrib2f",
+ "glVertexAttrib3f",
+ "glVertexAttrib4f",
+ "glVertexAttrib1fv",
+ "glVertexAttrib2fv",
+ "glVertexAttrib3fv",
+ "glVertexAttrib4fv",
+ "glVertexAttrib1d",
+ "glVertexAttrib2d",
+ "glVertexAttrib3d",
+ "glVertexAttrib4d",
+ "glVertexAttrib1dv",
+ "glVertexAttrib2dv",
+ "glVertexAttrib3dv",
+ "glVertexAttrib4dv",
+ "glVertexAttrib1s",
+ "glVertexAttrib2s",
+ "glVertexAttrib3s",
+ "glVertexAttrib4s",
+ "glVertexAttrib1sv",
+ "glVertexAttrib2sv",
+ "glVertexAttrib3sv",
+ "glVertexAttrib4sv",
+ "glVertexAttrib4Nsv"
+ "glVertexAttrib4Nub",
+ "glVertexAttrib4Nubv",
+ "glVertexAttrib4ubv",
+ "glVertexAttrib4Nbv",
+ "glVertexAttrib4bv",
+ "glVertexAttrib4Niv",
+ "glVertexAttrib4iv",
+ "glVertexAttrib4Nuiv",
+ "glVertexAttrib4uiv",
+ "glVertexAttrib4Nusv",
+ "glVertexAttrib4usv"
+};
+
+
+// Set a vertex attribute with one of the many glVertexAttrib* functions.
+// index = the vertex attribute
+// v = the 4-element attribute value
+// funcIndex = indicates which glVertexAttrib* function to use
+// refOut = returns the value which should now be in the attribute register
+//
+// Yeah, calling getProcAddress every time isn't very efficient. Oh well.
+//
+static void
+SetAttrib(GLuint index, const GLfloat v[4], GLuint funcIndex, GLfloat refOut[4])
+{
+ switch (funcIndex) {
+ // ** GLfloat-valued functions
+#if defined(GL_NV_vertex_program)
+ case 0:
+ {
+ PFNGLVERTEXATTRIB1FNVPROC f = (PFNGLVERTEXATTRIB1FNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1fNV");
+ f(index, v[0]);
+ COPY1(refOut, v);
+ }
+ break;
+ case 1:
+ {
+ PFNGLVERTEXATTRIB2FNVPROC f = (PFNGLVERTEXATTRIB2FNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2fNV");
+ f(index, v[0], v[1]);
+ COPY2(refOut, v);
+ }
+ break;
+ case 2:
+ {
+ PFNGLVERTEXATTRIB3FNVPROC f = (PFNGLVERTEXATTRIB3FNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3fNV");
+ f(index, v[0], v[1], v[2]);
+ COPY3(refOut, v);
+ }
+ break;
+ case 3:
+ {
+ PFNGLVERTEXATTRIB4FNVPROC f = (PFNGLVERTEXATTRIB4FNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4fNV");
+ f(index, v[0], v[1], v[2], v[3]);
+ COPY4(refOut, v);
+ }
+ break;
+ case 4:
+ {
+ PFNGLVERTEXATTRIB1FVNVPROC f = (PFNGLVERTEXATTRIB1FVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1fvNV");
+ f(index, v);
+ COPY1(refOut, v);
+ }
+ break;
+ case 5:
+ {
+ PFNGLVERTEXATTRIB2FVNVPROC f = (PFNGLVERTEXATTRIB2FVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2fvNV");
+ f(index, v);
+ COPY2(refOut, v);
+ }
+ break;
+ case 6:
+ {
+ PFNGLVERTEXATTRIB3FVNVPROC f = (PFNGLVERTEXATTRIB3FVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3fvNV");
+ f(index, v);
+ COPY3(refOut, v);
+ }
+ break;
+ case 7:
+ {
+ PFNGLVERTEXATTRIB4FVNVPROC f = (PFNGLVERTEXATTRIB4FVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4fvNV");
+ f(index, v);
+ COPY4(refOut, v);
+ }
+ break;
+ // ** GLdouble-valued functions
+ case 8:
+ {
+ PFNGLVERTEXATTRIB1DNVPROC f = (PFNGLVERTEXATTRIB1DNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1dNV");
+ f(index, v[0]);
+ COPY1(refOut, v);
+ }
+ break;
+ case 9:
+ {
+ PFNGLVERTEXATTRIB2DNVPROC f = (PFNGLVERTEXATTRIB2DNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2dNV");
+ f(index, v[0], v[1]);
+ COPY2(refOut, v);
+ }
+ break;
+ case 10:
+ {
+ PFNGLVERTEXATTRIB3DNVPROC f = (PFNGLVERTEXATTRIB3DNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3dNV");
+ f(index, v[0], v[1], v[2]);
+ COPY3(refOut, v);
+ }
+ break;
+ case 11:
+ {
+ PFNGLVERTEXATTRIB4DNVPROC f = (PFNGLVERTEXATTRIB4DNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4dNV");
+ f(index, v[0], v[1], v[2], v[3]);
+ COPY4(refOut, v);
+ }
+ break;
+ case 12:
+ {
+ PFNGLVERTEXATTRIB1DVNVPROC f = (PFNGLVERTEXATTRIB1DVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1dvNV");
+ GLdouble d[1];
+ d[0] = v[0];
+ f(index, d);
+ COPY1(refOut, v);
+ }
+ break;
+ case 13:
+ {
+ PFNGLVERTEXATTRIB2DVNVPROC f = (PFNGLVERTEXATTRIB2DVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2dvNV");
+ GLdouble d[2];
+ d[0] = v[0];
+ d[1] = v[1];
+ f(index, d);
+ COPY2(refOut, v);
+ }
+ break;
+ case 14:
+ {
+ PFNGLVERTEXATTRIB3DVNVPROC f = (PFNGLVERTEXATTRIB3DVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3dvNV");
+ GLdouble d[3];
+ d[0] = v[0];
+ d[1] = v[1];
+ d[2] = v[2];
+ f(index, d);
+ COPY3(refOut, v);
+ }
+ break;
+ case 15:
+ {
+ PFNGLVERTEXATTRIB4DVNVPROC f = (PFNGLVERTEXATTRIB4DVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4dvNV");
+ GLdouble d[4];
+ d[0] = v[0];
+ d[1] = v[1];
+ d[2] = v[2];
+ d[3] = v[3];
+ f(index, d);
+ COPY4(refOut, v);
+ }
+ break;
+ // ** GLshort-valued functions
+ case 16:
+ {
+ PFNGLVERTEXATTRIB1SNVPROC f = (PFNGLVERTEXATTRIB1SNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1sNV");
+ f(index, (GLshort) v[0]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = 0.0F;
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 17:
+ {
+ PFNGLVERTEXATTRIB2SNVPROC f = (PFNGLVERTEXATTRIB2SNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2sNV");
+ f(index, (GLshort) v[0], (GLshort) v[1]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 18:
+ {
+ PFNGLVERTEXATTRIB3SNVPROC f = (PFNGLVERTEXATTRIB3SNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3sNV");
+ f(index, (GLshort) v[0], (GLshort) v[1], (GLshort) v[2]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 19:
+ {
+ PFNGLVERTEXATTRIB4SNVPROC f = (PFNGLVERTEXATTRIB4SNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4sNV");
+ f(index, (GLshort) v[0], (GLshort) v[1], (GLshort) v[2], (GLshort) v[3]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = (GLfloat) (GLshort) v[3];
+ }
+ break;
+ case 20:
+ {
+ PFNGLVERTEXATTRIB1SVNVPROC f = (PFNGLVERTEXATTRIB1SVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1svNV");
+ GLshort s[1];
+ s[0] = (GLshort) v[0];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = 0.0F;
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 21:
+ {
+ PFNGLVERTEXATTRIB2SVNVPROC f = (PFNGLVERTEXATTRIB2SVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2svNV");
+ GLshort s[2];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 22:
+ {
+ PFNGLVERTEXATTRIB3SVNVPROC f = (PFNGLVERTEXATTRIB3SVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3svNV");
+ GLshort s[3];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ s[2] = (GLshort) v[2];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 23:
+ {
+ PFNGLVERTEXATTRIB4SVNVPROC f = (PFNGLVERTEXATTRIB4SVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4svNV");
+ GLshort s[4];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ s[2] = (GLshort) v[2];
+ s[3] = (GLshort) v[3];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = (GLfloat) (GLshort) v[3];
+ }
+ break;
+ // ** GLubyte-valued functions
+ case 24:
+ {
+ PFNGLVERTEXATTRIB4UBNVPROC f = (PFNGLVERTEXATTRIB4UBNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4ubNV");
+ f(index, FLOAT_TO_UBYTE(v[0]), FLOAT_TO_UBYTE(v[1]), FLOAT_TO_UBYTE(v[2]), FLOAT_TO_UBYTE(v[3]));
+ refOut[0] = v[0];
+ refOut[1] = v[1];
+ refOut[2] = v[2];
+ refOut[3] = v[3];
+ }
+ break;
+ case 25:
+ {
+ PFNGLVERTEXATTRIB4UBVNVPROC f = (PFNGLVERTEXATTRIB4UBVNVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4ubvNV");
+ GLubyte ub[4];
+ for (int i = 0; i < 4; i++ )
+ ub[i] = FLOAT_TO_UBYTE(v[i]);
+ f(index, ub);
+ refOut[0] = v[0];
+ refOut[1] = v[1];
+ refOut[2] = v[2];
+ refOut[3] = v[3];
+ }
+ break;
+ /* XXX Also test glVertexAttribs* functions? */
+#endif
+
+#if defined(GL_ARB_vertex_program) || defined (GL_ARB_vertex_shader)
+ // ** GLfloat-valued functions
+ case 26:
+ {
+ PFNGLVERTEXATTRIB1FARBPROC f = (PFNGLVERTEXATTRIB1FARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib1fARB");
+ f(index, v[0]);
+ COPY1(refOut, v);
+ }
+ break;
+ case 27:
+ {
+ PFNGLVERTEXATTRIB2FARBPROC f = (PFNGLVERTEXATTRIB2FARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib2fARB");
+ f(index, v[0], v[1]);
+ COPY2(refOut, v);
+ }
+ break;
+ case 28:
+ {
+ PFNGLVERTEXATTRIB3FARBPROC f = (PFNGLVERTEXATTRIB3FARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib3fARB");
+ f(index, v[0], v[1], v[2]);
+ COPY3(refOut, v);
+ }
+ break;
+ case 29:
+ {
+ PFNGLVERTEXATTRIB4FARBPROC f = (PFNGLVERTEXATTRIB4FARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4fARB");
+ f(index, v[0], v[1], v[2], v[3]);
+ COPY4(refOut, v);
+ }
+ break;
+ case 30:
+ {
+ PFNGLVERTEXATTRIB1FVARBPROC f = (PFNGLVERTEXATTRIB1FVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib1fvARB");
+ f(index, v);
+ COPY1(refOut, v);
+ }
+ break;
+ case 31:
+ {
+ PFNGLVERTEXATTRIB2FVARBPROC f = (PFNGLVERTEXATTRIB2FVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib2fvARB");
+ f(index, v);
+ COPY2(refOut, v);
+ }
+ break;
+ case 32:
+ {
+ PFNGLVERTEXATTRIB3FVARBPROC f = (PFNGLVERTEXATTRIB3FVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib3fvARB");
+ f(index, v);
+ COPY3(refOut, v);
+ }
+ break;
+ case 33:
+ {
+ PFNGLVERTEXATTRIB4FVARBPROC f = (PFNGLVERTEXATTRIB4FVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4fvARB");
+ f(index, v);
+ COPY4(refOut, v);
+ }
+ break;
+ // ** GLdouble-valued functions
+ case 34:
+ {
+ PFNGLVERTEXATTRIB1DARBPROC f = (PFNGLVERTEXATTRIB1DARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib1dARB");
+ f(index, v[0]);
+ COPY1(refOut, v);
+ }
+ break;
+ case 35:
+ {
+ PFNGLVERTEXATTRIB2DARBPROC f = (PFNGLVERTEXATTRIB2DARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib2dARB");
+ f(index, v[0], v[1]);
+ COPY2(refOut, v);
+ }
+ break;
+ case 36:
+ {
+ PFNGLVERTEXATTRIB3DARBPROC f = (PFNGLVERTEXATTRIB3DARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib3dARB");
+ f(index, v[0], v[1], v[2]);
+ COPY3(refOut, v);
+ }
+ break;
+ case 37:
+ {
+ PFNGLVERTEXATTRIB4DARBPROC f = (PFNGLVERTEXATTRIB4DARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4dARB");
+ f(index, v[0], v[1], v[2], v[3]);
+ COPY4(refOut, v);
+ }
+ break;
+ case 38:
+ {
+ PFNGLVERTEXATTRIB1DVARBPROC f = (PFNGLVERTEXATTRIB1DVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib1dvARB");
+ GLdouble d[1];
+ d[0] = v[0];
+ f(index, d);
+ COPY1(refOut, v);
+ }
+ break;
+ case 39:
+ {
+ PFNGLVERTEXATTRIB2DVARBPROC f = (PFNGLVERTEXATTRIB2DVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib2dvARB");
+ GLdouble d[2];
+ d[0] = v[0];
+ d[1] = v[1];
+ f(index, d);
+ COPY2(refOut, v);
+ }
+ break;
+ case 40:
+ {
+ PFNGLVERTEXATTRIB3DVARBPROC f = (PFNGLVERTEXATTRIB3DVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib3dvARB");
+ GLdouble d[3];
+ d[0] = v[0];
+ d[1] = v[1];
+ d[2] = v[2];
+ f(index, d);
+ COPY3(refOut, v);
+ }
+ break;
+ case 41:
+ {
+ PFNGLVERTEXATTRIB4DVARBPROC f = (PFNGLVERTEXATTRIB4DVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4dvARB");
+ GLdouble d[4];
+ d[0] = v[0];
+ d[1] = v[1];
+ d[2] = v[2];
+ d[3] = v[3];
+ f(index, d);
+ COPY4(refOut, v);
+ }
+ break;
+ // ** GLshort-valued functions
+ case 42:
+ {
+ PFNGLVERTEXATTRIB1SARBPROC f = (PFNGLVERTEXATTRIB1SARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib1sARB");
+ f(index, (GLshort) v[0]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = 0.0F;
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 43:
+ {
+ PFNGLVERTEXATTRIB2SARBPROC f = (PFNGLVERTEXATTRIB2SARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib2sARB");
+ f(index, (GLshort) v[0], (GLshort) v[1]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 44:
+ {
+ PFNGLVERTEXATTRIB3SARBPROC f = (PFNGLVERTEXATTRIB3SARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib3sARB");
+ f(index, (GLshort) v[0], (GLshort) v[1], (GLshort) v[2]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 45:
+ {
+ PFNGLVERTEXATTRIB4SARBPROC f = (PFNGLVERTEXATTRIB4SARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4sARB");
+ f(index, (GLshort) v[0], (GLshort) v[1], (GLshort) v[2], (GLshort) v[3]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = (GLfloat) (GLshort) v[3];
+ }
+ break;
+ case 46:
+ {
+ PFNGLVERTEXATTRIB1SVARBPROC f = (PFNGLVERTEXATTRIB1SVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib1svARB");
+ GLshort s[1];
+ s[0] = (GLshort) v[0];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = 0.0F;
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 47:
+ {
+ PFNGLVERTEXATTRIB2SVARBPROC f = (PFNGLVERTEXATTRIB2SVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib2svARB");
+ GLshort s[2];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 48:
+ {
+ PFNGLVERTEXATTRIB3SVARBPROC f = (PFNGLVERTEXATTRIB3SVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib3svARB");
+ GLshort s[3];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ s[2] = (GLshort) v[2];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 49:
+ {
+ PFNGLVERTEXATTRIB4SVARBPROC f = (PFNGLVERTEXATTRIB4SVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4svARB");
+ GLshort s[4];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ s[2] = (GLshort) v[2];
+ s[3] = (GLshort) v[3];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = (GLfloat) (GLshort) v[3];
+ }
+ break;
+ case 50:
+ {
+ PFNGLVERTEXATTRIB4NSVARBPROC f = (PFNGLVERTEXATTRIB4NSVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4NsvARB");
+ GLshort s[4];
+ for (int i = 0; i < 4; i++)
+ s[i] = FLOAT_TO_SHORT(v[i]);
+ f(index, s);
+ COPY4(refOut, v);
+ }
+ break;
+ // ** GLubyte-valued functions
+ case 51:
+ {
+ PFNGLVERTEXATTRIB4NUBARBPROC f = (PFNGLVERTEXATTRIB4NUBARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4NubARB");
+ f(index, FLOAT_TO_UBYTE(v[0]), FLOAT_TO_UBYTE(v[1]), FLOAT_TO_UBYTE(v[2]), FLOAT_TO_UBYTE(v[3]));
+ COPY4(refOut, v);
+ }
+ break;
+ case 52:
+ {
+ PFNGLVERTEXATTRIB4NUBVARBPROC f = (PFNGLVERTEXATTRIB4NUBVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4NubvARB");
+ GLubyte ub[4];
+ for (int i = 0; i < 4; i++ )
+ ub[i] = FLOAT_TO_UBYTE(v[i]);
+ f(index, ub);
+ COPY4(refOut, v);
+ }
+ break;
+ case 53:
+ {
+ PFNGLVERTEXATTRIB4UBVARBPROC f = (PFNGLVERTEXATTRIB4UBVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4ubvARB");
+ GLubyte ub[4];
+ for (int i = 0; i < 4; i++ )
+ ub[i] = (GLubyte) v[i];
+ f(index, ub);
+ refOut[0] = (GLfloat) (GLubyte) v[0];
+ refOut[1] = (GLfloat) (GLubyte) v[1];
+ refOut[2] = (GLfloat) (GLubyte) v[2];
+ refOut[3] = (GLfloat) (GLubyte) v[3];
+ }
+ break;
+ // ** GLbyte-valued functions
+ case 54:
+ {
+ PFNGLVERTEXATTRIB4NBVARBPROC f = (PFNGLVERTEXATTRIB4NBVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4NbvARB");
+ GLbyte b[4];
+ for (int i = 0; i < 4; i++ )
+ b[i] = FLOAT_TO_BYTE(v[i]);
+ f(index, b);
+ COPY4(refOut, v);
+ }
+ break;
+ case 55:
+ {
+ PFNGLVERTEXATTRIB4BVARBPROC f = (PFNGLVERTEXATTRIB4BVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4bvARB");
+ GLbyte b[4];
+ for (int i = 0; i < 4; i++ )
+ b[i] = (GLbyte) v[i];
+ f(index, b);
+ refOut[0] = (GLfloat) (GLbyte) v[0];
+ refOut[1] = (GLfloat) (GLbyte) v[1];
+ refOut[2] = (GLfloat) (GLbyte) v[2];
+ refOut[3] = (GLfloat) (GLbyte) v[3];
+ }
+ break;
+ // ** GLint-valued functions
+ case 56:
+ {
+ PFNGLVERTEXATTRIB4NIVARBPROC f = (PFNGLVERTEXATTRIB4NIVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4NivARB");
+ GLint iv[4];
+ for (int i = 0; i < 4; i++ )
+ iv[i] = FLOAT_TO_INT(v[i]);
+ f(index, iv);
+ COPY4(refOut, v);
+ }
+ break;
+ case 57:
+ {
+ PFNGLVERTEXATTRIB4IVARBPROC f = (PFNGLVERTEXATTRIB4IVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4ivARB");
+ GLint iv[4];
+ for (int i = 0; i < 4; i++ )
+ iv[i] = (GLint) v[i];
+ f(index, iv);
+ refOut[0] = (GLfloat) (GLint) v[0];
+ refOut[1] = (GLfloat) (GLint) v[1];
+ refOut[2] = (GLfloat) (GLint) v[2];
+ refOut[3] = (GLfloat) (GLint) v[3];
+ }
+ break;
+ // ** GLuint-valued functions
+ case 58:
+ {
+ PFNGLVERTEXATTRIB4NUIVARBPROC f = (PFNGLVERTEXATTRIB4NUIVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4NuivARB");
+ GLuint ui[4];
+ for (int i = 0; i < 4; i++ )
+ ui[i] = FLOAT_TO_UINT(v[i]);
+ f(index, ui);
+ COPY4(refOut, v);
+ }
+ break;
+ case 59:
+ {
+ PFNGLVERTEXATTRIB4UIVARBPROC f = (PFNGLVERTEXATTRIB4UIVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4uivARB");
+ GLuint ui[4];
+ for (int i = 0; i < 4; i++ )
+ ui[i] = (GLint) v[i];
+ f(index, ui);
+ refOut[0] = (GLfloat) (GLint) v[0];
+ refOut[1] = (GLfloat) (GLint) v[1];
+ refOut[2] = (GLfloat) (GLint) v[2];
+ refOut[3] = (GLfloat) (GLint) v[3];
+ }
+ break;
+ // ** GLushort-valued functions
+ case 60:
+ {
+ PFNGLVERTEXATTRIB4NUSVARBPROC f = (PFNGLVERTEXATTRIB4NUSVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4NusvARB");
+ GLushort us[4];
+ for (int i = 0; i < 4; i++ )
+ us[i] = FLOAT_TO_USHORT(v[i]);
+ f(index, us);
+ COPY4(refOut, v);
+ }
+ break;
+ case 61:
+ {
+ PFNGLVERTEXATTRIB4USVARBPROC f = (PFNGLVERTEXATTRIB4USVARBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4usvARB");
+ GLushort us[4];
+ for (int i = 0; i < 4; i++ )
+ us[i] = (GLint) v[i];
+ f(index, us);
+ refOut[0] = (GLfloat) (GLint) v[0];
+ refOut[1] = (GLfloat) (GLint) v[1];
+ refOut[2] = (GLfloat) (GLint) v[2];
+ refOut[3] = (GLfloat) (GLint) v[3];
+ }
+ break;
+#endif
+
+#if defined(GL_VERSION_2_0)
+ case 62:
+ {
+ PFNGLVERTEXATTRIB1FPROC f = (PFNGLVERTEXATTRIB1FPROC)
+ GLUtils::getProcAddress("glVertexAttrib1f");
+ f(index, v[0]);
+ COPY1(refOut, v);
+ }
+ break;
+ case 63:
+ {
+ PFNGLVERTEXATTRIB2FPROC f = (PFNGLVERTEXATTRIB2FPROC)
+ GLUtils::getProcAddress("glVertexAttrib2f");
+ f(index, v[0], v[1]);
+ COPY2(refOut, v);
+ }
+ break;
+ case 64:
+ {
+ PFNGLVERTEXATTRIB3FPROC f = (PFNGLVERTEXATTRIB3FPROC)
+ GLUtils::getProcAddress("glVertexAttrib3f");
+ f(index, v[0], v[1], v[2]);
+ COPY3(refOut, v);
+ }
+ break;
+ case 65:
+ {
+ PFNGLVERTEXATTRIB4FPROC f = (PFNGLVERTEXATTRIB4FPROC)
+ GLUtils::getProcAddress("glVertexAttrib4f");
+ f(index, v[0], v[1], v[2], v[3]);
+ COPY4(refOut, v);
+ }
+ break;
+ case 66:
+ {
+ PFNGLVERTEXATTRIB1FVPROC f = (PFNGLVERTEXATTRIB1FVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1fv");
+ f(index, v);
+ COPY1(refOut, v);
+ }
+ break;
+ case 67:
+ {
+ PFNGLVERTEXATTRIB2FVPROC f = (PFNGLVERTEXATTRIB2FVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2fv");
+ f(index, v);
+ COPY2(refOut, v);
+ }
+ break;
+ case 68:
+ {
+ PFNGLVERTEXATTRIB3FVPROC f = (PFNGLVERTEXATTRIB3FVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3fv");
+ f(index, v);
+ COPY3(refOut, v);
+ }
+ break;
+ case 69:
+ {
+ PFNGLVERTEXATTRIB4FVPROC f = (PFNGLVERTEXATTRIB4FVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4fv");
+ f(index, v);
+ COPY4(refOut, v);
+ }
+ break;
+ // ** GLdouble-valued functions
+ case 70:
+ {
+ PFNGLVERTEXATTRIB1DPROC f = (PFNGLVERTEXATTRIB1DPROC)
+ GLUtils::getProcAddress("glVertexAttrib1d");
+ f(index, v[0]);
+ COPY1(refOut, v);
+ }
+ break;
+ case 71:
+ {
+ PFNGLVERTEXATTRIB2DPROC f = (PFNGLVERTEXATTRIB2DPROC)
+ GLUtils::getProcAddress("glVertexAttrib2d");
+ f(index, v[0], v[1]);
+ COPY2(refOut, v);
+ }
+ break;
+ case 72:
+ {
+ PFNGLVERTEXATTRIB3DPROC f = (PFNGLVERTEXATTRIB3DPROC)
+ GLUtils::getProcAddress("glVertexAttrib3d");
+ f(index, v[0], v[1], v[2]);
+ COPY3(refOut, v);
+ }
+ break;
+ case 73:
+ {
+ PFNGLVERTEXATTRIB4DPROC f = (PFNGLVERTEXATTRIB4DPROC)
+ GLUtils::getProcAddress("glVertexAttrib4d");
+ f(index, v[0], v[1], v[2], v[3]);
+ COPY4(refOut, v);
+ }
+ break;
+ case 74:
+ {
+ PFNGLVERTEXATTRIB1DVPROC f = (PFNGLVERTEXATTRIB1DVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1dv");
+ GLdouble d[1];
+ d[0] = v[0];
+ f(index, d);
+ COPY1(refOut, v);
+ }
+ break;
+ case 75:
+ {
+ PFNGLVERTEXATTRIB2DVPROC f = (PFNGLVERTEXATTRIB2DVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2dv");
+ GLdouble d[2];
+ d[0] = v[0];
+ d[1] = v[1];
+ f(index, d);
+ COPY2(refOut, v);
+ }
+ break;
+ case 76:
+ {
+ PFNGLVERTEXATTRIB3DVPROC f = (PFNGLVERTEXATTRIB3DVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3dv");
+ GLdouble d[3];
+ d[0] = v[0];
+ d[1] = v[1];
+ d[2] = v[2];
+ f(index, d);
+ COPY3(refOut, v);
+ }
+ break;
+ case 77:
+ {
+ PFNGLVERTEXATTRIB4DVPROC f = (PFNGLVERTEXATTRIB4DVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4dv");
+ GLdouble d[4];
+ d[0] = v[0];
+ d[1] = v[1];
+ d[2] = v[2];
+ d[3] = v[3];
+ f(index, d);
+ COPY4(refOut, v);
+ }
+ break;
+ // ** GLshort-valued functions
+ case 78:
+ {
+ PFNGLVERTEXATTRIB1SPROC f = (PFNGLVERTEXATTRIB1SPROC)
+ GLUtils::getProcAddress("glVertexAttrib1s");
+ f(index, (GLshort) v[0]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = 0.0F;
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 79:
+ {
+ PFNGLVERTEXATTRIB2SPROC f = (PFNGLVERTEXATTRIB2SPROC)
+ GLUtils::getProcAddress("glVertexAttrib2s");
+ f(index, (GLshort) v[0], (GLshort) v[1]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 80:
+ {
+ PFNGLVERTEXATTRIB3SPROC f = (PFNGLVERTEXATTRIB3SPROC)
+ GLUtils::getProcAddress("glVertexAttrib3s");
+ f(index, (GLshort) v[0], (GLshort) v[1], (GLshort) v[2]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 81:
+ {
+ PFNGLVERTEXATTRIB4SPROC f = (PFNGLVERTEXATTRIB4SPROC)
+ GLUtils::getProcAddress("glVertexAttrib4s");
+ f(index, (GLshort) v[0], (GLshort) v[1], (GLshort) v[2], (GLshort) v[3]);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = (GLfloat) (GLshort) v[3];
+ }
+ break;
+ case 82:
+ {
+ PFNGLVERTEXATTRIB1SVPROC f = (PFNGLVERTEXATTRIB1SVPROC)
+ GLUtils::getProcAddress("glVertexAttrib1sv");
+ GLshort s[1];
+ s[0] = (GLshort) v[0];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = 0.0F;
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 83:
+ {
+ PFNGLVERTEXATTRIB2SVPROC f = (PFNGLVERTEXATTRIB2SVPROC)
+ GLUtils::getProcAddress("glVertexAttrib2sv");
+ GLshort s[2];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = 0.0F;
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 84:
+ {
+ PFNGLVERTEXATTRIB3SVPROC f = (PFNGLVERTEXATTRIB3SVPROC)
+ GLUtils::getProcAddress("glVertexAttrib3sv");
+ GLshort s[3];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ s[2] = (GLshort) v[2];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = 1.0F;
+ }
+ break;
+ case 85:
+ {
+ PFNGLVERTEXATTRIB4SVPROC f = (PFNGLVERTEXATTRIB4SVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4sv");
+ GLshort s[4];
+ s[0] = (GLshort) v[0];
+ s[1] = (GLshort) v[1];
+ s[2] = (GLshort) v[2];
+ s[3] = (GLshort) v[3];
+ f(index, s);
+ refOut[0] = (GLfloat) (GLshort) v[0];
+ refOut[1] = (GLfloat) (GLshort) v[1];
+ refOut[2] = (GLfloat) (GLshort) v[2];
+ refOut[3] = (GLfloat) (GLshort) v[3];
+ }
+ break;
+ case 86:
+ {
+ PFNGLVERTEXATTRIB4NSVPROC f = (PFNGLVERTEXATTRIB4NSVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4Nsv");
+ GLshort s[4];
+ for (int i = 0; i < 4; i++)
+ s[i] = FLOAT_TO_SHORT(v[i]);
+ f(index, s);
+ COPY4(refOut, v);
+ }
+ break;
+ // ** GLubyte-valued functions
+ case 87:
+ {
+ PFNGLVERTEXATTRIB4NUBPROC f = (PFNGLVERTEXATTRIB4NUBPROC)
+ GLUtils::getProcAddress("glVertexAttrib4Nub");
+ f(index, FLOAT_TO_UBYTE(v[0]), FLOAT_TO_UBYTE(v[1]), FLOAT_TO_UBYTE(v[2]), FLOAT_TO_UBYTE(v[3]));
+ COPY4(refOut, v);
+ }
+ break;
+ case 88:
+ {
+ PFNGLVERTEXATTRIB4NUBVPROC f = (PFNGLVERTEXATTRIB4NUBVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4Nubv");
+ GLubyte ub[4];
+ for (int i = 0; i < 4; i++ )
+ ub[i] = FLOAT_TO_UBYTE(v[i]);
+ f(index, ub);
+ COPY4(refOut, v);
+ }
+ break;
+ case 89:
+ {
+ PFNGLVERTEXATTRIB4UBVPROC f = (PFNGLVERTEXATTRIB4UBVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4ubv");
+ GLubyte ub[4];
+ for (int i = 0; i < 4; i++ )
+ ub[i] = (GLubyte) v[i];
+ f(index, ub);
+ refOut[0] = (GLfloat) (GLubyte) v[0];
+ refOut[1] = (GLfloat) (GLubyte) v[1];
+ refOut[2] = (GLfloat) (GLubyte) v[2];
+ refOut[3] = (GLfloat) (GLubyte) v[3];
+ }
+ break;
+ // ** GLbyte-valued functions
+ case 90:
+ {
+ PFNGLVERTEXATTRIB4NBVPROC f = (PFNGLVERTEXATTRIB4NBVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4Nbv");
+ GLbyte b[4];
+ for (int i = 0; i < 4; i++ )
+ b[i] = FLOAT_TO_BYTE(v[i]);
+ f(index, b);
+ COPY4(refOut, v);
+ }
+ break;
+ case 91:
+ {
+ PFNGLVERTEXATTRIB4BVPROC f = (PFNGLVERTEXATTRIB4BVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4bv");
+ GLbyte b[4];
+ for (int i = 0; i < 4; i++ )
+ b[i] = (GLbyte) v[i];
+ f(index, b);
+ refOut[0] = (GLfloat) (GLbyte) v[0];
+ refOut[1] = (GLfloat) (GLbyte) v[1];
+ refOut[2] = (GLfloat) (GLbyte) v[2];
+ refOut[3] = (GLfloat) (GLbyte) v[3];
+ }
+ break;
+ // ** GLint-valued functions
+ case 92:
+ {
+ PFNGLVERTEXATTRIB4NIVPROC f = (PFNGLVERTEXATTRIB4NIVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4Niv");
+ GLint iv[4];
+ for (int i = 0; i < 4; i++ )
+ iv[i] = FLOAT_TO_INT(v[i]);
+ f(index, iv);
+ COPY4(refOut, v);
+ }
+ break;
+ case 93:
+ {
+ PFNGLVERTEXATTRIB4IVPROC f = (PFNGLVERTEXATTRIB4IVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4iv");
+ GLint iv[4];
+ for (int i = 0; i < 4; i++ )
+ iv[i] = (GLint) v[i];
+ f(index, iv);
+ refOut[0] = (GLfloat) (GLint) v[0];
+ refOut[1] = (GLfloat) (GLint) v[1];
+ refOut[2] = (GLfloat) (GLint) v[2];
+ refOut[3] = (GLfloat) (GLint) v[3];
+ }
+ break;
+ // ** GLuint-valued functions
+ case 94:
+ {
+ PFNGLVERTEXATTRIB4NUIVPROC f = (PFNGLVERTEXATTRIB4NUIVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4Nuiv");
+ GLuint ui[4];
+ for (int i = 0; i < 4; i++ )
+ ui[i] = FLOAT_TO_UINT(v[i]);
+ f(index, ui);
+ COPY4(refOut, v);
+ }
+ break;
+ case 95:
+ {
+ PFNGLVERTEXATTRIB4UIVPROC f = (PFNGLVERTEXATTRIB4UIVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4uiv");
+ GLuint ui[4];
+ for (int i = 0; i < 4; i++ )
+ ui[i] = (GLint) v[i];
+ f(index, ui);
+ refOut[0] = (GLfloat) (GLint) v[0];
+ refOut[1] = (GLfloat) (GLint) v[1];
+ refOut[2] = (GLfloat) (GLint) v[2];
+ refOut[3] = (GLfloat) (GLint) v[3];
+ }
+ break;
+ // ** GLushort-valued functions
+ case 96:
+ {
+ PFNGLVERTEXATTRIB4NUSVPROC f = (PFNGLVERTEXATTRIB4NUSVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4Nusv");
+ GLushort us[4];
+ for (int i = 0; i < 4; i++ )
+ us[i] = FLOAT_TO_USHORT(v[i]);
+ f(index, us);
+ COPY4(refOut, v);
+ }
+ break;
+ case 97:
+ {
+ PFNGLVERTEXATTRIB4USVPROC f = (PFNGLVERTEXATTRIB4USVPROC)
+ GLUtils::getProcAddress("glVertexAttrib4usv");
+ GLushort us[4];
+ for (int i = 0; i < 4; i++ )
+ us[i] = (GLint) v[i];
+ f(index, us);
+ refOut[0] = (GLfloat) (GLint) v[0];
+ refOut[1] = (GLfloat) (GLint) v[1];
+ refOut[2] = (GLfloat) (GLint) v[2];
+ refOut[3] = (GLfloat) (GLint) v[3];
+ }
+ break;
+#endif
+
+ default:
+ // never get here!
+ abort();
+ }
+
+ assert(98 == NUM_NV_ATTRIB_FUNCS + NUM_ARB_ATTRIB_FUNCS + NUM_2_0_ATTRIB_FUNCS);
+}
+
+
+// Test if 'a and 'b' are within an epsilon of each other
+static bool
+NearlyEqual(const GLfloat a[4], const GLfloat b[4])
+{
+ const GLfloat epsilon = 0.05;
+ if (fabsf(a[0] - b[0]) > epsilon ||
+ fabsf(a[1] - b[1]) > epsilon ||
+ fabsf(a[2] - b[2]) > epsilon ||
+ fabsf(a[3] - b[3]) > epsilon)
+ return 0;
+ else
+ return 1;
+}
+
+
+void VertAttribTest::FailMessage(VertAttribResult &r, const char *msg,
+ const char *func, int dlistMode) const
+{
+ // record the failure
+ r.pass = false;
+
+ // print the message
+ env->log << name << ": FAIL "
+ << r.config->conciseDescription() << '\n';
+ env->log << "\t" << msg << " (Testing " << func << " in ";
+
+ if (dlistMode)
+ env->log << "display list mode)\n";
+ else
+ env->log << "immediate mode)\n";
+}
+
+
+
+// Test setting/getting a set of vertex attribute values
+// Return true if pass, false if fail
+bool
+VertAttribTest::TestAttribs(VertAttribResult &r,
+ int attribFunc,
+ PFNGLGETVERTEXATTRIBFVARBPROC getAttribfv,
+ Aliasing aliasing,
+ int numAttribs)
+{
+ static const GLfloat refValues[7] = { 1.0F, 0.8F, 0.6F, 0.5F, 0.4F, 0.2F, 0.0F };
+ GLfloat refValue[32][4];
+ GLfloat refOut[32][4];
+ bool result = true;
+
+ assert(numAttribs <= 32);
+
+ // Initialize the refValue array
+ int refIndex = 0;
+ for (int i = 1; i < numAttribs; i++) {
+ refValue[i][0] = refValues[refIndex++ % 7];
+ refValue[i][1] = refValues[refIndex++ % 7];
+ refValue[i][2] = refValues[refIndex++ % 7];
+ refValue[i][3] = refValues[refIndex++ % 7];
+ }
+
+ for (int dlist = 0; dlist < 2; dlist++) {
+
+ // set a couple conventional attribs for later aliasing tests
+ glNormal3f(-1.0F, -2.0F, -3.0F);
+ glTexCoord4f(-1.0F, -2.0F, -3.0F, -4.0F);
+
+ if (dlist == 1) {
+ glNewList(42, GL_COMPILE);
+ }
+
+ // Set all the vertex attributes
+ for (int i = 1; i < numAttribs; i++) {
+ SetAttrib(i, refValue[i], attribFunc, refOut[i]);
+ }
+
+ if (dlist == 1) {
+ glEndList();
+ glCallList(42);
+ }
+
+ // Test all the vertex attributes
+ for (int i = 1; i < numAttribs; i++) {
+ const GLfloat *expected = refOut[i];
+ GLfloat v[4];
+ getAttribfv(i, GL_CURRENT_VERTEX_ATTRIB_ARB, v);
+ if (!NearlyEqual(v, expected)) {
+ char msg[1000];
+ sprintf(msg, "Vertex Attribute %d is (%g, %g, %g, %g) but expected (%g, %g, %g, %g)",
+ i, v[0], v[1], v[2], v[3],
+ expected[0], expected[1], expected[2], expected[3]);
+ FailMessage(r, msg, AttribFuncNames[attribFunc], dlist);
+ result = false;
+ }
+ }
+
+ if (aliasing == REQUIRED) {
+ // spot check a few aliased attribs
+ GLfloat v[4];
+ glGetFloatv(GL_CURRENT_NORMAL, v);
+ v[3] = refOut[2][3];
+ if (!NearlyEqual(v, refOut[2])) {
+ FailMessage(r, "Setting attribute 2 did not update GL_CURRENT_NORMAL", AttribFuncNames[attribFunc], dlist);
+ result = false;
+ }
+
+ glGetFloatv(GL_CURRENT_TEXTURE_COORDS, v);
+ if (!NearlyEqual(v, refOut[8])) {
+ FailMessage(r, "Setting attribute 8 did not update GL_CURRENT_TEXTURE_COORDS", AttribFuncNames[attribFunc], dlist);
+ result = false;
+ }
+ }
+ else if (aliasing == DISALLOWED) {
+ // spot check a few non-aliased attribs
+ GLfloat v[4];
+ glGetFloatv(GL_CURRENT_NORMAL, v);
+ if (v[0] != -1.0F ||
+ v[1] != -2.0F ||
+ v[2] != -3.0F) {
+ FailMessage(r, "GL_CURRENT_NORMAL was erroneously set by a glVertexAttrib call", AttribFuncNames[attribFunc], dlist);
+ result = false;
+ }
+ glGetFloatv(GL_CURRENT_TEXTURE_COORDS, v);
+ if (v[0] != -1.0F ||
+ v[1] != -2.0F ||
+ v[2] != -3.0F ||
+ v[3] != -4.0F) {
+ FailMessage(r, "GL_CURRENT_TEXTURE_COORDS was erroneously set by a glVertexAttrib call", AttribFuncNames[attribFunc], dlist);
+ result = false;
+ }
+ }
+
+ } // dlist loop
+
+ return result;
+}
+
+
+// Test the GL_NV_vertex_program functions
+// Return true if pass, false if fail
+bool
+VertAttribTest::TestNVfuncs(VertAttribResult &r)
+{
+ bool result = true;
+#ifdef GL_NV_vertex_program
+ PFNGLGETVERTEXATTRIBFVNVPROC getAttribfv;
+ const GLint numAttribs = 16;
+ const Aliasing aliasing = REQUIRED;
+
+ getAttribfv = (PFNGLGETVERTEXATTRIBFVNVPROC) GLUtils::getProcAddress("glGetVertexAttribfvNV");
+ assert(getAttribfv);
+
+ r.numNVtested = 0;
+
+ for (int attribFunc = 0; attribFunc < NUM_NV_ATTRIB_FUNCS; attribFunc++) {
+ bool b;
+ b = TestAttribs(r, attribFunc, getAttribfv, aliasing, numAttribs);
+ if (!b)
+ result = false;
+ r.numNVtested++;
+ }
+#else
+ (void) r;
+#endif
+ return result;
+}
+
+
+// Test the GL_ARB_vertex_program/shader functions
+// Return true if pass, false if fail
+bool
+VertAttribTest::TestARBfuncs(VertAttribResult &r, bool shader)
+{
+ bool result = true;
+#if defined(GL_ARB_vertex_program) || defined(GL_ARB_vertex_shader)
+ PFNGLGETVERTEXATTRIBFVARBPROC getAttribfv;
+ GLint numAttribs;
+
+ getAttribfv = (PFNGLGETVERTEXATTRIBFVARBPROC) GLUtils::getProcAddress("glGetVertexAttribfvARB");
+ assert(getAttribfv);
+
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &numAttribs);
+ assert(numAttribs > 0);
+
+ r.numARBtested = 0;
+
+ if (shader) {
+ // test GL_ARB_vertex_shader (aliasing is disallowed)
+ const Aliasing aliasing = DISALLOWED;
+ for (int i = 0; i < NUM_ARB_ATTRIB_FUNCS; i++) {
+ int attribFunc = NUM_NV_ATTRIB_FUNCS + i;
+ bool b;
+ b = TestAttribs(r, attribFunc, getAttribfv, aliasing, numAttribs);
+ if (!b)
+ result = false;
+ r.numARBtested++;
+ }
+ }
+ else {
+ // test GL_ARB_vertex_program:
+ // Determine if attribute aliasing is allowed
+ Aliasing aliasing;
+ if (GLUtils::haveExtension("GL_ARB_vertex_shader")) {
+ aliasing = DISALLOWED;
+ }
+ else {
+ // check for OpenGL 2.x support
+ char *vers = (char *) glGetString(GL_VERSION);
+ if (vers[0] == '2' && vers[1] == '.') {
+ aliasing = DISALLOWED;
+ }
+ else {
+ assert(vers[0] == '1'); /* revisit when we have OpenGL 3.x */
+ aliasing = OPTIONAL;
+ }
+ }
+ for (int i = 0; i < NUM_ARB_ATTRIB_FUNCS; i++) {
+ int attribFunc = NUM_NV_ATTRIB_FUNCS + i;
+ bool b;
+ b = TestAttribs(r, attribFunc, getAttribfv, aliasing, numAttribs);
+ if (!b)
+ result = false;
+ r.numARBtested++;
+ }
+ }
+#else
+ (void) r;
+#endif
+ return result;
+}
+
+
+// Test the OpenGL 2.x glVertexAttrib functions
+// Return true if pass, false if fail
+bool
+VertAttribTest::Test20funcs(VertAttribResult &r)
+{
+ bool result = true;
+#ifdef GL_VERSION_2_0
+ PFNGLGETVERTEXATTRIBFVPROC getAttribfv;
+ GLint numAttribs;
+ const Aliasing aliasing = DISALLOWED;
+
+ getAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) GLUtils::getProcAddress("glGetVertexAttribfv");
+ assert(getAttribfv);
+
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &numAttribs);
+ assert(numAttribs > 0);
+
+ r.num20tested = 0;
+
+ for (int i = 0; i < NUM_2_0_ATTRIB_FUNCS; i++) {
+ int attribFunc = NUM_NV_ATTRIB_FUNCS + NUM_ARB_ATTRIB_FUNCS+ i;
+ bool b;
+ b = TestAttribs(r, attribFunc, getAttribfv, aliasing, numAttribs);
+ if (!b)
+ result = false;
+ r.num20tested++;
+ }
+#else
+ (void) r;
+#endif
+ return result;
+}
+
+
+void
+VertAttribTest::runOne(VertAttribResult& r, Window&)
+{
+
+ assert(sizeof(AttribFuncNames) / sizeof(char *) ==
+ NUM_NV_ATTRIB_FUNCS + NUM_ARB_ATTRIB_FUNCS + NUM_2_0_ATTRIB_FUNCS);
+
+ r.pass = true;
+#ifdef GL_NV_vertex_program
+ if (GLUtils::haveExtension("GL_NV_vertex_program")) {
+ bool p = TestNVfuncs(r);
+ if (!p)
+ r.pass = false;
+ }
+#endif
+#ifdef GL_ARB_vertex_program
+ if (GLUtils::haveExtension("GL_ARB_vertex_program")) {
+ bool p = TestARBfuncs(r, false);
+ if (!p)
+ r.pass = false;
+ }
+#endif
+#ifdef GL_ARB_vertex_shader
+ if (GLUtils::haveExtension("GL_ARB_vertex_shader")) {
+ bool p = TestARBfuncs(r, true);
+ if (!p)
+ r.pass = false;
+ }
+#endif
+#ifdef GL_VERSION_2_0
+ const char *vers = (const char *) glGetString(GL_VERSION);
+ if (vers[0] == '2' && vers[1] == '.') {
+ bool p = Test20funcs(r);
+ if (!p)
+ r.pass = false;
+ }
+#endif
+}
+
+
+void
+VertAttribTest::logOne(VertAttribResult& r)
+{
+ logPassFail(r);
+ logConcise(r);
+ logStats(r);
+}
+
+
+void
+VertAttribTest::logStats(VertAttribResult& r)
+{
+ env->log << "\t" << r.numNVtested << " GL_NV_vertex_program functions tested\n";
+ env->log << "\t" << r.numARBtested << " GL_ARB_vertex_program/shader functions tested\n";
+ env->log << "\t" << r.num20tested << " OpenGL 2.0 functions tested\n";
+}
+
+
+void
+VertAttribTest::compareOne(VertAttribResult& oldR, VertAttribResult& newR)
+{
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR);
+ env->log << env->options.db2Name << ':';
+ logStats(newR);
+ }
+}
+
+
+// Instantiate this test object
+VertAttribTest vertAttribTest("vertattrib", "window, rgb",
+ "Verify that the glVertexAttribNV, glVertexAttribARB, and glVertexAttrib\n"
+ "functions all work correctly.\n");
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tvertattrib.h b/tests/glean/tvertattrib.h
new file mode 100644
index 00000000..3729dc00
--- /dev/null
+++ b/tests/glean/tvertattrib.h
@@ -0,0 +1,93 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+#ifndef __tvertattrib_h__
+#define __tvertattrib_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+
+class VertAttribResult: public BaseResult
+{
+public:
+ bool pass;
+ int numNVtested, numARBtested, num20tested;
+
+ VertAttribResult()
+ {
+ numNVtested = numARBtested = num20tested = 0;
+ }
+
+ virtual void putresults(ostream& s) const
+ {
+ s << pass
+ << ' ' << numNVtested
+ << ' ' << numARBtested
+ << ' ' << num20tested
+ << '\n';
+ }
+
+ virtual bool getresults(istream& s)
+ {
+ s >> pass >> numNVtested >> numARBtested >> num20tested;
+ return s.good();
+ }
+};
+
+
+class VertAttribTest: public BaseTest<VertAttribResult>
+{
+public:
+ GLEAN_CLASS(VertAttribTest, VertAttribResult);
+ virtual void logStats(VertAttribResult& r);
+
+private:
+ enum Aliasing {
+ REQUIRED,
+ DISALLOWED,
+ OPTIONAL
+ };
+
+ void FailMessage(VertAttribResult &r, const char *msg,
+ const char *ext, int dlistMode) const;
+ bool TestAttribs(VertAttribResult &r,
+ int attribFunc,
+ PFNGLGETVERTEXATTRIBFVARBPROC getAttribfv,
+ Aliasing aliasing,
+ int numAttribs);
+ bool TestNVfuncs(VertAttribResult &r);
+ bool TestARBfuncs(VertAttribResult &r, bool shader);
+ bool Test20funcs(VertAttribResult &r);
+};
+
+} // namespace GLEAN
+
+#endif // __tvertattrib_h__
diff --git a/tests/glean/tvertprog1.cpp b/tests/glean/tvertprog1.cpp
new file mode 100644
index 00000000..ac65fc6c
--- /dev/null
+++ b/tests/glean/tvertprog1.cpp
@@ -0,0 +1,1042 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tvertprog1.cpp: Test GL_ARB_vertex_program extension.
+// Brian Paul 22 October 2005
+//
+// See tfragprog.cpp for comments (this test is very similar).
+
+#include "tvertprog1.h"
+#include <cassert>
+#include <cmath>
+#include <math.h>
+
+
+namespace GLEAN {
+
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB_func;
+static PFNGLGENPROGRAMSARBPROC glGenProgramsARB_func;
+static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB_func;
+static PFNGLBINDPROGRAMARBPROC glBindProgramARB_func;
+static PFNGLISPROGRAMARBPROC glIsProgramARB_func;
+static PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB_func;
+
+static GLuint progID;
+
+
+// Clamp X to [0, 1]
+#define CLAMP01( X ) ( (X)<(0.0) ? (0.0) : ((X)>(1.0) ? (1.0) : (X)) )
+// Absolute value
+#define ABS(X) ( (X) < 0.0 ? -(X) : (X) )
+// Max
+#define MAX( A, B ) ( (A) > (B) ? (A) : (B) )
+// Min
+#define MIN( A, B ) ( (A) < (B) ? (A) : (B) )
+// Duplicate value four times
+#define SMEAR(X) (X), (X), (X), (X)
+
+#define DONT_CARE_Z -1.0
+#define DONT_CARE_COLOR -1.0
+
+#define VERTCOLOR { 0.25, 0.75, 0.5, 0.25 }
+#define PARAM0 { 0.0, 0.0, 0.0, 0.0 } // all zero
+#define PARAM1 { 0.5, 0.25, 0.9, 0.5 } // in [0,1]
+#define PARAM2 { -1.0, 0.0, 0.25, -0.5 } // in [-1,1]
+#define AMBIENT { 0.2, 0.4, 0.6, 0.8 }
+#define DIFFUSE { 0.1, 0.3, 0.5, 0.7 }
+static const GLfloat VertColor[4] = VERTCOLOR;
+static const GLfloat Param0[4] = PARAM0;
+static const GLfloat Param1[4] = PARAM1;
+static const GLfloat Param2[4] = PARAM2;
+static const GLfloat Ambient[4] = AMBIENT;
+static const GLfloat Diffuse[4] = DIFFUSE;
+static const GLfloat FogDensity = 0.5;
+static const GLfloat FogStart = 0.2;
+static const GLfloat FogEnd = 0.9;
+static GLfloat InfNan[4];
+
+
+// These are the specific vertex programs which we'll test.
+// Alphabetical order, please.
+static const VertexProgram Programs[] = {
+ // ============= Basic instructions tests =============================
+ {
+ "ABS test",
+ "!!ARBvp1.0\n"
+ "PARAM p2 = program.local[2]; \n"
+ "MOV result.position, vertex.position; \n"
+ "ABS result.color, p2; \n"
+ "END \n",
+ { CLAMP01(ABS(Param2[0])),
+ CLAMP01(ABS(Param2[1])),
+ CLAMP01(ABS(Param2[2])),
+ CLAMP01(ABS(Param2[3])),
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "ADD test",
+ "!!ARBvp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "ADD result.color, vertex.color, p; \n"
+ "END \n",
+ { CLAMP01(VertColor[0] + Param1[0]),
+ CLAMP01(VertColor[1] + Param1[1]),
+ CLAMP01(VertColor[2] + Param1[2]),
+ CLAMP01(VertColor[3] + Param1[3])
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "ARL test",
+ "!!ARBvp1.0\n"
+ "ADDRESS addr; \n"
+ "PARAM indexes = {-1, 0, 1, 2}; \n"
+ "PARAM myArray[4] = {{0.11, 0.12, 0.13, 0.14}, \n"
+ " {0.21, 0.22, 0.23, 0.24}, \n"
+ " {0.31, 0.32, 0.33, 0.34}, \n"
+ " {0.41, 0.42, 0.43, 0.44}}; \n"
+ "MOV result.position, vertex.position; \n"
+ ""
+ "# Load ARL with -1, get array[0].x \n"
+ "ARL addr.x, indexes.x; \n"
+ "MOV result.color.x, myArray[addr.x + 1]; \n"
+ ""
+ "# Load ARL with 0, get array[1].y \n"
+ "ARL addr.x, indexes.y; \n"
+ "MOV result.color.y, myArray[addr.x + 1]; \n"
+ ""
+ "# Load ARL with 1, get array[2].z \n"
+ "ARL addr.x, indexes.z; \n"
+ "MOV result.color.z, myArray[addr.x + 1]; \n"
+ ""
+ "# Load ARL with 2, get array[3].w\n"
+ "ARL addr.x, indexes.w; \n"
+ "MOV result.color.w, myArray[addr.x + 1]; \n"
+ "END \n",
+ { 0.11,
+ 0.22,
+ 0.33,
+ 0.44
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "DP3 test",
+ "!!ARBvp1.0\n"
+ "PARAM p2 = program.local[2]; \n"
+ "PARAM bias = { 0.5, 0.5, 0.5, 0.5 }; \n"
+ "TEMP t; \n"
+ "MOV result.position, vertex.position; \n"
+ "DP3 t, p2, vertex.color; \n"
+ "ADD result.color, t, bias; \n"
+ "END \n",
+ { SMEAR(Param2[0] * VertColor[0] +
+ Param2[1] * VertColor[1] +
+ Param2[2] * VertColor[2] + 0.5)
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "DP4 test",
+ "!!ARBvp1.0\n"
+ "PARAM p2 = program.local[2]; \n"
+ "PARAM bias = { 0.5, 0.5, 0.5, 0.5 }; \n"
+ "TEMP t; \n"
+ "MOV result.position, vertex.position; \n"
+ "DP4 t, p2, vertex.color; \n"
+ "ADD result.color, t, bias; \n"
+ "END \n",
+ { SMEAR(Param2[0] * VertColor[0] +
+ Param2[1] * VertColor[1] +
+ Param2[2] * VertColor[2] +
+ Param2[3] * VertColor[3] + 0.5)
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "DPH test",
+ "!!ARBvp1.0\n"
+ "PARAM p2 = program.local[2]; \n"
+ "TEMP t; \n"
+ "MOV result.position, vertex.position; \n"
+ "DPH result.color, p2, vertex.color; \n"
+ "END \n",
+ { SMEAR(CLAMP01(Param2[0] * VertColor[0] +
+ Param2[1] * VertColor[1] +
+ Param2[2] * VertColor[2] +
+ VertColor[3]))
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "DST test",
+ "!!ARBvp1.0\n"
+ "# let d = 0.4 \n"
+ "PARAM v1 = {9.9, 0.16, 0.16, 9.9}; \n"
+ "PARAM v2 = {9.9, 2.5, 9.9, 2.5}; \n"
+ "MOV result.position, vertex.position; \n"
+ "DST result.color, v1, v2; \n"
+ "END \n",
+ { 1.0,
+ 0.4, // v1.y * v2.y
+ 0.16, // v1.z
+ CLAMP01(2.5) // v2.w
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "EX2 test",
+ "!!ARBvp1.0\n"
+ "PARAM scale = {0.01, 0.01, 0.01, 0.01}; \n"
+ "PARAM values = {0.0, 1.0, 4.0, -2.0 }; \n"
+ "TEMP t; \n"
+ "MOV result.position, vertex.position; \n"
+ "EX2 t.x, values.x; \n"
+ "EX2 t.y, values.y; \n"
+ "EX2 t.z, values.z; \n"
+ "EX2 t.w, values.w; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { 1.0 * 0.01,
+ 2.0 * 0.01,
+ 16.0 * 0.01,
+ 0.25 * 0.01 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "EXP test",
+ "!!ARBvp1.0\n"
+ "PARAM scale = {0.01, 0.01, 0.01, 0.01}; \n"
+ "PARAM values = {4.5, 0, 0, 0}; \n"
+ "TEMP t; \n"
+ "MOV result.position, vertex.position; \n"
+ "EXP t, values.x; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { 16.0 * 0.01,
+ 0.5 * 0.01,
+ 22.627 * 0.01,
+ 1.0 * 0.01 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "FLR test",
+ "!!ARBvp1.0\n"
+ "PARAM values = {4.8, 0.3, -0.2, 1.2}; \n"
+ "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
+ "MOV result.position, vertex.position; \n"
+ "TEMP t; \n"
+ "FLR t, values; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { 0.4,
+ 0.0,
+ CLAMP01(-0.1),
+ 0.1
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "FRC test",
+ "!!ARBvp1.0\n"
+ "PARAM values = {1.344, -1.5, -10.1, 4.2}; \n"
+ "MOV result.position, vertex.position; \n"
+ "FRC result.color, values; \n"
+ "END \n",
+ { 0.344,
+ 0.5,
+ 0.9,
+ 0.2
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "LG2 test",
+ "!!ARBvp1.0\n"
+ "PARAM values = {64.0, 1, 30, 4}; \n"
+ "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
+ "MOV result.position, vertex.position; \n"
+ "TEMP t; \n"
+ "LG2 t.x, values.x; \n"
+ "LG2 t.y, values.y; \n"
+ "LG2 t.z, values.z; \n"
+ "LG2 t.w, values.w; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { 0.6,
+ 0.0,
+ 0.49,
+ 0.2
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "LIT test 1",
+ "!!ARBvp1.0\n"
+ "PARAM values = {0.65, 0.9, 0.0, 8.0}; \n"
+ "MOV result.position, vertex.position; \n"
+ "LIT result.color, values; \n"
+ "END \n",
+ { 1.0,
+ 0.65, // values.x
+ 0.430, // roughly Pow(values.y, values.w)
+ 1.0
+ },
+ DONT_CARE_Z,
+ FLAG_LOOSE
+ },
+ {
+ "LIT test 2 (degenerate case: 0 ^ 0 -> 1)",
+ "!!ARBvp1.0\n"
+ "PARAM values = {0.65, 0.0, 0.0, 0.0}; \n"
+ "MOV result.position, vertex.position; \n"
+ "LIT result.color, values; \n"
+ "END \n",
+ { 1.0,
+ 0.65, // values.x
+ 1.0, // 0^0
+ 1.0
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "LIT test 3 (case x < 0)",
+ "!!ARBvp1.0\n"
+ "PARAM values = {-0.5, 0.0, 0.0, 0.0}; \n"
+ "MOV result.position, vertex.position; \n"
+ "LIT result.color, values; \n"
+ "END \n",
+ { 1.0,
+ CLAMP01(-0.5), // values.x
+ 0.0,
+ 1.0
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "LOG test",
+ "!!ARBvp1.0\n"
+ "PARAM values = {64.0, 50, 30, 4}; \n"
+ "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
+ "MOV result.position, vertex.position; \n"
+ "TEMP t; \n"
+ "LOG t.x, values.x; \n"
+ "LOG t.y, values.y; \n"
+ "LOG t.z, values.z; \n"
+ "LOG t.w, values.w; \n"
+ "MUL result.color, t, scale; \n"
+ "END \n",
+ { 0.6, // floor(log2(value.x))
+ 0.15, // value.y / 2^(floor(log2(value.y)))
+ 0.49, // roughApproxLog2(value.z)
+ 0.1
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "MAD test",
+ "!!ARBvp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "MOV result.position, vertex.position; \n"
+ "MAD result.color, vertex.color, p1, p2; \n"
+ "END \n",
+ { CLAMP01(VertColor[0] * Param1[0] + Param2[0]),
+ CLAMP01(VertColor[1] * Param1[1] + Param2[1]),
+ CLAMP01(VertColor[2] * Param1[2] + Param2[2]),
+ CLAMP01(VertColor[3] * Param1[3] + Param2[3])
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "MAX test",
+ "!!ARBvp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "MOV result.position, vertex.position; \n"
+ "MAX result.color, p1, p2; \n"
+ "END \n",
+ { MAX(Param1[0], Param2[0]),
+ MAX(Param1[1], Param2[1]),
+ MAX(Param1[2], Param2[2]),
+ MAX(Param1[3], Param2[3]),
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "MIN test",
+ "!!ARBvp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "MIN result.color, p1, vertex.color; \n"
+ "END \n",
+ { MIN(Param1[0], VertColor[0]),
+ MIN(Param1[1], VertColor[1]),
+ MIN(Param1[2], VertColor[2]),
+ MIN(Param1[3], VertColor[3]),
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "MOV test (with swizzle)",
+ "!!ARBvp1.0\n"
+ "MOV result.position, vertex.position; \n"
+ "MOV result.color, vertex.color.wzxy; \n"
+ "END \n",
+ { VertColor[3],
+ VertColor[2],
+ VertColor[0],
+ VertColor[1]
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "MUL test (with swizzle and masking)",
+ "!!ARBvp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "MUL result.color.xy, p1.wzww, vertex.color.wzww; \n"
+ "MUL result.color.zw, p1.xxyx, vertex.color.xxyx; \n"
+ "END \n",
+ { CLAMP01(Param1[3] * VertColor[3]),
+ CLAMP01(Param1[2] * VertColor[2]),
+ CLAMP01(Param1[1] * VertColor[1]),
+ CLAMP01(Param1[0] * VertColor[0]),
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "POW test (exponentiation)",
+ "!!ARBvp1.0\n"
+ "PARAM values = {0.5, 2, 3, 4}; \n"
+ "MOV result.position, vertex.position; \n"
+ "POW result.color.x, values.x, values.y; \n"
+ "POW result.color.y, values.x, values.z; \n"
+ "POW result.color.z, values.x, values.w; \n"
+ "POW result.color.w, values.w, values.x; \n"
+ "END \n",
+ { 0.5 * 0.5,
+ 0.5 * 0.5 * 0.5,
+ 0.5 * 0.5 * 0.5 * 0.5,
+ CLAMP01(2.0) },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "RCP test (reciprocal)",
+ "!!ARBvp1.0\n"
+ "PARAM values = {8, -10, 1, 12 }; \n"
+ "MOV result.position, vertex.position; \n"
+ "RCP result.color.x, values.x; \n"
+ "RCP result.color.y, values.y; \n"
+ "RCP result.color.z, values.z; \n"
+ "RCP result.color.w, values.w; \n"
+ "END \n",
+ { 1.0 / 8.0, CLAMP01(1.0 / -10.0), 1, 1.0 / 12.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "RSQ test 1 (reciprocal square root)",
+ "!!ARBvp1.0\n"
+ "PARAM values = {1, 4, 9, 100 }; \n"
+ "MOV result.position, vertex.position; \n"
+ "RSQ result.color.x, values.x; \n"
+ "RSQ result.color.y, values.y; \n"
+ "RSQ result.color.z, values.z; \n"
+ "RSQ result.color.w, values.w; \n"
+ "END \n",
+ { 1.0, 0.5, 0.3333, 0.1 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "RSQ test 2 (reciprocal square root of negative value)",
+ "!!ARBvp1.0\n"
+ "PARAM values = {0, -100, -5, -1}; \n"
+ "MOV result.position, vertex.position; \n"
+ "RSQ result.color.x, values.x; \n"
+ "RSQ result.color.y, values.y; \n"
+ "RSQ result.color.z, values.z; \n"
+ "RSQ result.color.w, values.w; \n"
+ "END \n",
+ { DONT_CARE_COLOR,
+ 0.1,
+ 0.447,
+ 1.0,
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "SGE test",
+ "!!ARBvp1.0\n"
+ "PARAM p0 = program.local[0]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "MOV result.position, vertex.position; \n"
+ "SGE result.color, p2, p0; \n"
+ "END \n",
+ { Param2[0] >= Param0[0] ? 1.0 : 0.0,
+ Param2[1] >= Param0[1] ? 1.0 : 0.0,
+ Param2[2] >= Param0[2] ? 1.0 : 0.0,
+ Param2[3] >= Param0[3] ? 1.0 : 0.0,
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "SLT test",
+ "!!ARBvp1.0\n"
+ "PARAM p0 = program.local[0]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "MOV result.position, vertex.position; \n"
+ "SLT result.color, p2, p0; \n"
+ "END \n",
+ { Param2[0] < Param0[0] ? 1.0 : 0.0,
+ Param2[1] < Param0[1] ? 1.0 : 0.0,
+ Param2[2] < Param0[2] ? 1.0 : 0.0,
+ Param2[3] < Param0[3] ? 1.0 : 0.0,
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "SUB test (with swizzle)",
+ "!!ARBvp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "SUB result.color, p1.yxwz, vertex.color.primary.yxwz; \n"
+ "END \n",
+ { CLAMP01(Param1[1] - VertColor[1]),
+ CLAMP01(Param1[0] - VertColor[0]),
+ CLAMP01(Param1[3] - VertColor[3]),
+ CLAMP01(Param1[2] - VertColor[2])
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "SWZ test 1",
+ "!!ARBvp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "SWZ result.color, p, w,x,x,y; \n"
+ "END \n",
+ { Param1[3],
+ Param1[0],
+ Param1[0],
+ Param1[1]
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "SWZ test 2",
+ "!!ARBvp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "SWZ result.color, p, -w,-x,x,y; \n"
+ "END \n",
+ { CLAMP01(-Param1[3]),
+ CLAMP01(-Param1[0]),
+ Param1[0],
+ Param1[1]
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "SWZ test 3",
+ "!!ARBvp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "SWZ result.color, p, 0,1,0,1; \n"
+ "END \n",
+ { 0.0, 1.0, 0.0, 1.0 },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "SWZ test 4",
+ "!!ARBvp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "SWZ result.color, p, 1,x,z,0; \n"
+ "END \n",
+ { 1.0,
+ Param1[0],
+ Param1[2],
+ 0.0
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "SWZ test 5",
+ "!!ARBvp1.0\n"
+ "PARAM p = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "SWZ result.color, p, z,-y,-1,0; \n"
+ "END \n",
+ { CLAMP01(Param1[2]),
+ CLAMP01(-Param1[1]),
+ CLAMP01(-1),
+ 0.0
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "XPD test 1",
+ "!!ARBvp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "MOV result.position, vertex.position; \n"
+ "XPD result.color, p1, p2; \n"
+ "END \n",
+ { CLAMP01(Param1[1] * Param2[2] - Param1[2] * Param2[1]),
+ CLAMP01(Param1[2] * Param2[0] - Param1[0] * Param2[2]),
+ CLAMP01(Param1[0] * Param2[1] - Param1[1] * Param2[0]),
+ DONT_CARE_COLOR
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "XPD test 2 (same src/dst arg)",
+ "!!ARBvp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "PARAM p2 = program.local[2]; \n"
+ "TEMP t; \n"
+ "MOV result.position, vertex.position; \n"
+ "MOV t, p1; \n"
+ "XPD t, t, p2; \n"
+ "MOV result.color, t; \n"
+ "END \n",
+ { CLAMP01(Param1[1] * Param2[2] - Param1[2] * Param2[1]),
+ CLAMP01(Param1[2] * Param2[0] - Param1[0] * Param2[2]),
+ CLAMP01(Param1[0] * Param2[1] - Param1[1] * Param2[0]),
+ DONT_CARE_COLOR
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // ============= Test result.position writes ==========================
+ {
+ "Position write test (compute position from texcoord)",
+ "!!ARBvp1.0\n"
+ "ATTRIB texcoord = vertex.texcoord[0]; \n"
+ "PARAM scale = {0.5, 0.5, 0.0, 1.0}; \n"
+ "PARAM bias = {-0.25, -0.25, 0.0, 0.0}; \n"
+ "MAD result.position, texcoord, scale, bias; \n"
+ "MOV result.color, vertex.color; \n"
+ "END \n",
+ VERTCOLOR,
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "Z-write test",
+ "!!ARBvp1.0\n"
+ "PARAM p1 = program.local[1]; \n"
+ "MOV result.position, vertex.position; \n"
+ "MOV result.position.z, p1.y; \n"
+ "MOV result.color, vertex.color; \n"
+ "END \n",
+ VERTCOLOR,
+ Param1[1] * 0.5 + 0.5, // map clip Z to win Z
+ FLAG_NONE
+ },
+
+ // ============= Global state reference tests =========================
+ {
+ "State reference test 1 (material ambient)",
+ "!!ARBvp1.0\n"
+ "PARAM ambient = state.material.front.ambient; \n"
+ "MOV result.position, vertex.position; \n"
+ "MOV result.color, ambient; \n"
+ "END \n",
+ AMBIENT,
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ // Note: material.diffuse = VertColor
+ // light.diffuse = Diffuse
+ "State reference test 2 (light products)",
+ "!!ARBvp1.0\n"
+ "PARAM dprod = state.lightprod[0].diffuse; \n"
+ "MOV result.position, vertex.position; \n"
+ "MOV result.color, dprod; \n"
+ "END \n",
+ { CLAMP01(Diffuse[0] * VertColor[0]),
+ CLAMP01(Diffuse[1] * VertColor[1]),
+ CLAMP01(Diffuse[2] * VertColor[2]),
+ CLAMP01(VertColor[3]) // material's diffuse alpha
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "State reference test 3 (fog params)",
+ "!!ARBvp1.0\n"
+ "PARAM fog = state.fog.params; \n"
+ "PARAM scale = {1.0, 1.0, 1.0, 0.1}; \n"
+ "MOV result.position, vertex.position; \n"
+ "MUL result.color, fog, scale; \n"
+ "END \n",
+ { FogDensity,
+ FogStart,
+ FogEnd,
+ (1.0 / (FogEnd - FogStart)) * 0.1
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // ============= Numeric stress tests =================================
+ // Basically just check that we don't crash when we do divides by
+ // zero, etc.
+ {
+ "Divide by zero test",
+ "!!ARBvp1.0\n"
+ "PARAM zero = program.local[0]; \n"
+ "MOV result.position, vertex.position; \n"
+ "RCP result.color.x, zero.x; \n"
+ "RCP result.color.y, zero.y; \n"
+ "RCP result.color.z, zero.z; \n"
+ "RCP result.color.w, zero.w; \n"
+ "END \n",
+ { DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+ {
+ "Infinity / nan test",
+ "!!ARBvp1.0\n"
+ "PARAM zero = program.local[0]; \n"
+ "PARAM infNan = program.local[9]; \n"
+ "MOV result.position, vertex.position; \n"
+ "ADD result.color, infNan, zero; \n"
+ "END \n",
+ { DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR,
+ DONT_CARE_COLOR
+ },
+ DONT_CARE_Z,
+ FLAG_NONE
+ },
+
+ // ============= Texcoord output tests ================================
+ // XXX to do
+
+ // XXX add lots more tests here!
+ { NULL, NULL, {0,0,0,0}, 0, FLAG_NONE } // end of list sentinal
+};
+
+
+
+void
+VertexProgramTest::setup(void)
+{
+ // setup Infinity, Nan values
+ int nan;
+ float *nanPtr;
+
+ nan = (0xff << 23) | (1 << 0);
+ nanPtr = (float *) &nan;
+ InfNan[0] = HUGE_VAL;
+ InfNan[1] = -HUGE_VAL;
+ InfNan[2] = (float) (*nanPtr);
+ InfNan[3] = 1.0 / HUGE_VAL;
+ /*
+ printf("InfNan = %f %f %f %f\n",
+ InfNan[0], InfNan[1], InfNan[2], InfNan[3]);
+ */
+
+ // get function pointers
+ glProgramLocalParameter4fvARB_func = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLUtils::getProcAddress("glProgramLocalParameter4fvARB");
+ assert(glProgramLocalParameter4fvARB_func);
+
+ glGenProgramsARB_func = (PFNGLGENPROGRAMSARBPROC) GLUtils::getProcAddress("glGenProgramsARB");
+ assert(glGenProgramsARB_func);
+
+ glProgramStringARB_func = (PFNGLPROGRAMSTRINGARBPROC) GLUtils::getProcAddress("glProgramStringARB");
+ assert(glProgramStringARB_func);
+
+ glBindProgramARB_func = (PFNGLBINDPROGRAMARBPROC) GLUtils::getProcAddress("glBindProgramARB");
+ assert(glBindProgramARB_func);
+
+ glIsProgramARB_func = (PFNGLISPROGRAMARBPROC) GLUtils::getProcAddress("glIsProgramARB");
+ assert(glIsProgramARB_func);
+
+ glDeleteProgramsARB_func = (PFNGLDELETEPROGRAMSARBPROC) GLUtils::getProcAddress("glDeleteProgramsARB");
+ assert(glDeleteProgramsARB_func);
+
+ glGenProgramsARB_func(1, &progID);
+ glBindProgramARB_func(GL_VERTEX_PROGRAM_ARB, progID);
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+
+ // load program inputs
+ glColor4fv(VertColor);
+ glProgramLocalParameter4fvARB_func(GL_VERTEX_PROGRAM_ARB, 0, Param0);
+ glProgramLocalParameter4fvARB_func(GL_VERTEX_PROGRAM_ARB, 1, Param1);
+ glProgramLocalParameter4fvARB_func(GL_VERTEX_PROGRAM_ARB, 2, Param2);
+ glProgramLocalParameter4fvARB_func(GL_VERTEX_PROGRAM_ARB, 9, InfNan);
+
+ // other GL state
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Ambient);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, Diffuse);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, VertColor);
+ glFogf(GL_FOG_DENSITY, FogDensity);
+ glFogf(GL_FOG_START, FogStart);
+ glFogf(GL_FOG_END, FogEnd);
+
+ GLenum err = glGetError();
+ assert(!err); // should be OK
+
+ // setup vertex transform (we'll draw a quad in middle of window)
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-4.0, 4.0, -4.0, 4.0, 0.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+
+ // compute error tolerances (may need fine-tuning)
+ int bufferBits[5];
+ glGetIntegerv(GL_RED_BITS, &bufferBits[0]);
+ glGetIntegerv(GL_GREEN_BITS, &bufferBits[1]);
+ glGetIntegerv(GL_BLUE_BITS, &bufferBits[2]);
+ glGetIntegerv(GL_ALPHA_BITS, &bufferBits[3]);
+ glGetIntegerv(GL_DEPTH_BITS, &bufferBits[4]);
+
+ tolerance[0] = 2.0 / (1 << bufferBits[0]);
+ tolerance[1] = 2.0 / (1 << bufferBits[1]);
+ tolerance[2] = 2.0 / (1 << bufferBits[2]);
+ if (bufferBits[3])
+ tolerance[3] = 2.0 / (1 << bufferBits[3]);
+ else
+ tolerance[3] = 1.0;
+ if (bufferBits[4])
+ tolerance[4] = 16.0 / (1 << bufferBits[4]);
+ else
+ tolerance[4] = 1.0;
+
+ // Some tests request a looser tolerance:
+ // XXX a factor of 4 may be too much...
+ for (int i = 0; i < 5; i++)
+ looseTolerance[i] = 4.0 * tolerance[i];
+}
+
+
+void
+VertexProgramTest::reportFailure(const char *programName,
+ const GLfloat expectedColor[4],
+ const GLfloat actualColor[4] ) const
+{
+ env->log << "FAILURE:\n";
+ env->log << " Program: " << programName << "\n";
+ env->log << " Expected color: ";
+ env->log << expectedColor[0] << ", ";
+ env->log << expectedColor[1] << ", ";
+ env->log << expectedColor[2] << ", ";
+ env->log << expectedColor[3] << "\n";
+ env->log << " Observed color: ";
+ env->log << actualColor[0] << ", ";
+ env->log << actualColor[1] << ", ";
+ env->log << actualColor[2] << ", ";
+ env->log << actualColor[3] << "\n";
+}
+
+void
+VertexProgramTest::reportZFailure(const char *programName,
+ GLfloat expectedZ, GLfloat actualZ) const
+{
+ env->log << "FAILURE:\n";
+ env->log << " Program: " << programName << "\n";
+ env->log << " Expected Z: " << expectedZ << "\n";
+ env->log << " Observed Z: " << actualZ << "\n";
+}
+
+
+
+// Compare actual and expected colors
+bool
+VertexProgramTest::equalColors(const GLfloat act[4], const GLfloat exp[4], int flags) const
+{
+ const GLfloat *tol;
+ if (flags & FLAG_LOOSE)
+ tol = looseTolerance;
+ else
+ tol = tolerance;
+ if ((fabsf(act[0] - exp[0]) > tol[0] && exp[0] != DONT_CARE_COLOR) ||
+ (fabsf(act[1] - exp[1]) > tol[1] && exp[1] != DONT_CARE_COLOR) ||
+ (fabsf(act[2] - exp[2]) > tol[2] && exp[2] != DONT_CARE_COLOR) ||
+ (fabsf(act[3] - exp[3]) > tol[3] && exp[3] != DONT_CARE_COLOR))
+ return false;
+ else
+ return true;
+}
+
+
+bool
+VertexProgramTest::equalDepth(GLfloat z0, GLfloat z1) const
+{
+ if (fabsf(z0 - z1) > tolerance[4])
+ return false;
+ else
+ return true;
+}
+
+
+bool
+VertexProgramTest::testProgram(const VertexProgram &p)
+{
+ const GLfloat r = 0.25;
+
+ glProgramStringARB_func(GL_VERTEX_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(p.progString),
+ (const GLubyte *) p.progString);
+
+ GLenum err = glGetError();
+ if (err) {
+ GLint errorPos;
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ env->log << "OpenGL error " << (int) err << "\n";
+ env->log << "Invalid Vertex Program:\n";
+ env->log << p.progString;
+ env->log << "Error position: " << errorPos << "\n";
+ env->log << "Error message: " << glGetString(GL_PROGRAM_ERROR_STRING_ARB) << "\n";
+ return false;
+ }
+
+ // to avoid potential issue with undefined result.depth.z
+ if (p.expectedZ == DONT_CARE_Z)
+ glDisable(GL_DEPTH_TEST);
+ else
+ glEnable(GL_DEPTH_TEST);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-r, -r);
+ glTexCoord2f(1, 0); glVertex2f( r, -r);
+ glTexCoord2f(1, 1); glVertex2f( r, r);
+ glTexCoord2f(0, 1); glVertex2f(-r, r);
+ glEnd();
+
+ GLfloat pixel[4];
+ glReadPixels(windowSize / 2, windowSize / 2, 1, 1,
+ GL_RGBA, GL_FLOAT, pixel);
+
+ if (0) // debug
+ printf("%s: Expect: %.3f %.3f %.3f %.3f found: %.3f %.3f %.3f %.3f\n",
+ p.name,
+ p.expectedColor[0], p.expectedColor[1],
+ p.expectedColor[2], p.expectedColor[3],
+ pixel[0], pixel[1], pixel[2], pixel[3]);
+
+ if (!equalColors(pixel, p.expectedColor, p.flags)) {
+ reportFailure(p.name, p.expectedColor, pixel);
+ return false;
+ }
+
+ if (p.expectedZ != DONT_CARE_Z) {
+ GLfloat z;
+ glReadPixels(windowSize / 2, windowSize / 2, 1, 1,
+ GL_DEPTH_COMPONENT, GL_FLOAT, &z);
+ if (!equalDepth(z, p.expectedZ)) {
+ reportZFailure(p.name, p.expectedZ, z);
+ return false;
+ }
+ }
+
+ if (0) // debug
+ printf("%s passed\n", p.name);
+
+ return true;
+}
+
+void
+VertexProgramTest::runOne(MultiTestResult &r, Window &w)
+{
+ (void) w;
+ setup();
+
+ for (int i = 0; Programs[i].name; i++) {
+ if (!testProgram(Programs[i])) {
+ r.numFailed++;
+ }
+ else {
+ r.numPassed++;
+ }
+ }
+ r.pass = (r.numFailed == 0);
+}
+
+
+// The test object itself:
+VertexProgramTest vertexProgramTest("vertProg1", "window, rgb, z",
+ "GL_ARB_vertex_program",
+ "Vertex Program test 1: test a specific set of vertex programs.\n"
+ );
+
+
+
+} // namespace GLEAN
diff --git a/tests/glean/tvertprog1.h b/tests/glean/tvertprog1.h
new file mode 100644
index 00000000..df42073c
--- /dev/null
+++ b/tests/glean/tvertprog1.h
@@ -0,0 +1,85 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tvertprog.h: Test GL_ARB_vertex_program extension.
+// Brian Paul 22 October 2005
+
+#ifndef __tvertprog_h__
+#define __tvertprog_h__
+
+#include "tmultitest.h"
+
+namespace GLEAN {
+
+#define windowSize 100
+
+// to indicate a looser tolerance test is needed
+#define FLAG_NONE 0
+#define FLAG_LOOSE 1
+
+class VertexProgram
+{
+public:
+ const char *name;
+ const char *progString;
+ const GLfloat expectedColor[4];
+ const GLfloat expectedZ;
+ int flags;
+};
+
+
+
+class VertexProgramTest: public MultiTest
+{
+public:
+ VertexProgramTest(const char* testName, const char* filter,
+ const char *extensions, const char* description):
+ MultiTest(testName, filter, extensions, description)
+ {
+ }
+
+ virtual void runOne(MultiTestResult &r, Window &w);
+
+private:
+ GLfloat tolerance[5];
+ GLfloat looseTolerance[5];
+ void setup(void);
+ bool equalColors(const GLfloat a[4], const GLfloat b[4], int flags) const;
+ bool equalDepth(GLfloat z0, GLfloat z1) const;
+ bool testProgram(const VertexProgram &p);
+ void reportFailure(const char *programName,
+ const GLfloat expectedColor[4],
+ const GLfloat actualColor[4] ) const;
+ void reportZFailure(const char *programName,
+ GLfloat expectedZ, GLfloat actualZ) const;
+
+};
+
+} // namespace GLEAN
+
+#endif // __tvertprog_h__
diff --git a/tests/glean/tvtxperf.cpp b/tests/glean/tvtxperf.cpp
new file mode 100644
index 00000000..fa5bd877
--- /dev/null
+++ b/tests/glean/tvtxperf.cpp
@@ -0,0 +1,1424 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tvtxperf.cpp: Test performance of various ways to specify vertex data
+
+#include "tvtxperf.h"
+#include "geomutil.h"
+#include "timer.h"
+#include "rand.h"
+#include "image.h"
+#include "codedid.h"
+#include "treadpix.h"
+
+namespace {
+struct C4UB_N3F_V3F {
+ GLubyte c[4];
+ GLfloat n[3];
+ GLfloat v[3];
+};
+
+struct C4UB_T2F_V3F {
+ GLubyte c[4];
+ GLfloat t[2];
+ GLfloat v[3];
+};
+
+class TvtxBaseTimer: public GLEAN::Timer {
+public:
+ int nVertices;
+ GLuint* indices;
+ int nTris;
+ GLEAN::Window* w;
+ GLEAN::Environment* env;
+
+ TvtxBaseTimer(int v, GLuint* i, int t, GLEAN::Window* win,
+ GLEAN::Environment* e) {
+ nVertices = v;
+ indices = i;
+ nTris = t;
+ w = win;
+ env = e;
+ }
+
+ virtual double compute(double t) { return nTris/t; }
+ virtual void premeasure() {
+ // Clear both front and back buffers and swap, to avoid
+ // confusing this test with results of the previous
+ // test:
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ w->swap();
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+ virtual void postmeasure() { w->swap(); }
+ virtual void preop() { env->quiesce(); glFinish(); }
+ virtual void postop() { glFinish(); }
+};
+
+class ColoredLit_imIndTri: public TvtxBaseTimer {
+public:
+ C4UB_N3F_V3F* data;
+ ColoredLit_imIndTri(int v, C4UB_N3F_V3F* c, int t, GLEAN::Window* w,
+ GLEAN::Environment* env):
+ TvtxBaseTimer(v, 0, t, w, env) {
+ data = c;
+ }
+
+ virtual void op() {
+ C4UB_N3F_V3F* p = data;
+ glBegin(GL_TRIANGLES);
+ // Assume that the data is complete, thus allowing us
+ // to unroll 3X and do one tri per iteration rather than
+ // one vertex.
+ for (int i = nVertices / 3; i; --i) {
+ glColor4ubv(p[0].c);
+ glNormal3fv(p[0].n);
+ glVertex3fv(p[0].v);
+ glColor4ubv(p[1].c);
+ glNormal3fv(p[1].n);
+ glVertex3fv(p[1].v);
+ glColor4ubv(p[2].c);
+ glNormal3fv(p[2].n);
+ glVertex3fv(p[2].v);
+ p += 3;
+ }
+ glEnd();
+ }
+}; // coloredLit_imIndTri
+
+class ColoredTex_imIndTri: public TvtxBaseTimer {
+public:
+ C4UB_T2F_V3F* data;
+ ColoredTex_imIndTri(int v, C4UB_T2F_V3F* c, int t, GLEAN::Window* w,
+ GLEAN::Environment* env):
+ TvtxBaseTimer(v, 0, t, w, env) {
+ data = c;
+ }
+
+ virtual void op() {
+ C4UB_T2F_V3F* p = data;
+ glBegin(GL_TRIANGLES);
+ // Assume that the data is complete, thus allowing us
+ // to unroll 3X and do one tri per iteration rather than
+ // one vertex.
+ for (int i = nVertices / 3; i; --i) {
+ glColor4ubv(p[0].c);
+ glTexCoord2fv(p[0].t);
+ glVertex3fv(p[0].v);
+ glColor4ubv(p[1].c);
+ glTexCoord2fv(p[0].t);
+ glVertex3fv(p[1].v);
+ glColor4ubv(p[2].c);
+ glTexCoord2fv(p[0].t);
+ glVertex3fv(p[2].v);
+ p += 3;
+ }
+ glEnd();
+ }
+}; // coloredTex_imIndTri
+
+class ColoredLit_imTriStrip: public TvtxBaseTimer {
+public:
+ C4UB_N3F_V3F* data;
+ ColoredLit_imTriStrip(int v, C4UB_N3F_V3F* c, int t,
+ GLEAN::Window* w, GLEAN::Environment* env):
+ TvtxBaseTimer(v, 0, t, w, env) {
+ data = c;
+ }
+
+ virtual void op() {
+ C4UB_N3F_V3F* p = data;
+ glBegin(GL_TRIANGLE_STRIP);
+
+ int n = (nVertices + 3) >> 2;
+ // Duff's device. Yes, this is legal C (and C++).
+ // See Stroustrup, 3rd ed., p. 141
+ switch (nVertices & 0x3) {
+ case 0: do {
+ glColor4ubv(p->c);
+ glNormal3fv(p->n);
+ glVertex3fv(p->v);
+ ++p;
+ case 3:
+ glColor4ubv(p->c);
+ glNormal3fv(p->n);
+ glVertex3fv(p->v);
+ ++p;
+ case 2:
+ glColor4ubv(p->c);
+ glNormal3fv(p->n);
+ glVertex3fv(p->v);
+ ++p;
+ case 1:
+ glColor4ubv(p->c);
+ glNormal3fv(p->n);
+ glVertex3fv(p->v);
+ ++p;
+ } while (--n > 0);
+ }
+ glEnd();
+ }
+}; // coloredLit_imTriStrip
+
+class ColoredTex_imTriStrip: public TvtxBaseTimer {
+public:
+ C4UB_T2F_V3F* data;
+
+ ColoredTex_imTriStrip(int v, C4UB_T2F_V3F* c, int t,
+ GLEAN::Window* w, GLEAN::Environment* env):
+ TvtxBaseTimer(v, 0, t, w, env) {
+ data = c;
+ }
+
+ virtual void op() {
+ C4UB_T2F_V3F* p = data;
+ glBegin(GL_TRIANGLE_STRIP);
+
+ int n = (nVertices + 3) >> 2;
+ // Duff's device. Yes, this is legal C (and C++).
+ // See Stroustrup, 3rd ed., p. 141
+ switch (nVertices & 0x3) {
+ case 0: do {
+ glColor4ubv(p->c);
+ glTexCoord2fv(p->t);
+ glVertex3fv(p->v);
+ ++p;
+ case 3:
+ glColor4ubv(p->c);
+ glTexCoord2fv(p->t);
+ glVertex3fv(p->v);
+ ++p;
+ case 2:
+ glColor4ubv(p->c);
+ glTexCoord2fv(p->t);
+ glVertex3fv(p->v);
+ ++p;
+ case 1:
+ glColor4ubv(p->c);
+ glTexCoord2fv(p->t);
+ glVertex3fv(p->v);
+ ++p;
+ } while (--n > 0);
+ }
+ glEnd();
+ }
+}; // coloredTex_imTriStrip
+
+class daIndTriTimer: public TvtxBaseTimer {
+public:
+ daIndTriTimer(int v, GLuint* i, int t, GLEAN::Window* w,
+ GLEAN::Environment* env):
+ TvtxBaseTimer(v, i, t, w, env) {
+ }
+ virtual void op() {glDrawArrays(GL_TRIANGLES, 0, nVertices); }
+}; // daIndTriTimer
+
+class daTriStripTimer: public TvtxBaseTimer {
+public:
+ daTriStripTimer(int v, int t, GLEAN::Window* w,
+ GLEAN::Environment* env):
+ TvtxBaseTimer(v, 0, t, w, env) {
+ }
+ virtual void op() { glDrawArrays(GL_TRIANGLE_STRIP, 0, nVertices); }
+}; // daTriStripTimer
+
+class deIndTriTimer: public TvtxBaseTimer {
+public:
+ deIndTriTimer(int v, GLuint* i, int t, GLEAN::Window* w,
+ GLEAN::Environment* env):
+ TvtxBaseTimer(v, i, t, w, env) {
+ }
+ virtual void op() {
+ glDrawElements(GL_TRIANGLES, nVertices, GL_UNSIGNED_INT,
+ indices);
+ }
+}; // deIndTriTimer
+
+class deTriStripTimer: public TvtxBaseTimer {
+public:
+ deTriStripTimer(int v, GLuint* i, int t, GLEAN::Window* w,
+ GLEAN::Environment* env):
+ TvtxBaseTimer(v, i, t, w, env) {
+ }
+ virtual void op() {
+ glDrawElements(GL_TRIANGLE_STRIP, nVertices, GL_UNSIGNED_INT,
+ indices);
+ }
+}; // deTriStripTimer
+
+
+class callDListTimer: public TvtxBaseTimer {
+public:
+ int dList;
+ callDListTimer(int d, int t, GLEAN::Window* w,
+ GLEAN::Environment* env):
+ TvtxBaseTimer(0, 0, t, w, env) {
+ dList = d;
+ }
+ virtual void op() { glCallList(dList); }
+}; // callDList
+
+void
+logStats1(const char* title, GLEAN::VPSubResult& r,
+ GLEAN::Environment* env) {
+ env->log << '\t' << title << " rate = "
+ << r.tps << " tri/sec.\n"
+ << "\t\tRange of valid measurements = ["
+ << r.tpsLow << ", " << r.tpsHigh << "]\n"
+ << "\t\tImage sanity check "
+ << (r.imageOK? "passed\n": "failed\n")
+ << "\t\tImage consistency check "
+ << (r.imageMatch? "passed\n": "failed\n");
+
+} // logStats1
+
+void
+diffHeader(bool& same, const string& name,
+ GLEAN::DrawingSurfaceConfig* config, GLEAN::Environment* env) {
+ if (same) {
+ same = false;
+ env->log << name << ": DIFF "
+ << config->conciseDescription() << '\n';
+ }
+} // diffHeader
+
+void
+failHeader(bool& pass, const string& name,
+ GLEAN::DrawingSurfaceConfig* config, GLEAN::Environment* env) {
+ if (pass) {
+ pass = false;
+ env->log << name << ": FAIL "
+ << config->conciseDescription() << '\n';
+ }
+} // failHeader
+
+void
+doComparison(const GLEAN::VPSubResult& oldR,
+ const GLEAN::VPSubResult& newR,
+ GLEAN::DrawingSurfaceConfig* config,
+ bool& same, const string& name, GLEAN::Environment* env,
+ const char* title) {
+ if (newR.tps < oldR.tpsLow) {
+ int percent = static_cast<int>(
+ 100.0 * (oldR.tps - newR.tps) / newR.tps + 0.5);
+ diffHeader(same, name, config, env);
+ env->log << '\t' << env->options.db1Name
+ << " may be " << percent << "% faster on "
+ << title << " drawing.\n";
+ }
+ if (newR.tps > oldR.tpsHigh) {
+ int percent = static_cast<int>(
+ 100.0 * (newR.tps - oldR.tps) / oldR.tps + 0.5);
+ diffHeader(same, name, config, env);
+ env->log << '\t' << env->options.db2Name
+ << " may be " << percent << "% faster on "
+ << title << " drawing.\n";
+ }
+ if (newR.imageOK != oldR.imageOK) {
+ diffHeader(same, name, config, env);
+ env->log << '\t' << env->options.db1Name << " image check "
+ << (oldR.imageOK? "passed\n": "failed\n");
+ env->log << '\t' << env->options.db2Name << " image check "
+ << (newR.imageOK? "passed\n": "failed\n");
+ }
+ if (newR.imageMatch != oldR.imageMatch) {
+ diffHeader(same, name, config, env);
+ env->log << '\t' << env->options.db1Name << " image compare "
+ << (oldR.imageMatch? "passed\n": "failed\n");
+ env->log << '\t' << env->options.db2Name << " image compare "
+ << (newR.imageMatch? "passed\n": "failed\n");
+ }
+} // doComparison
+
+bool
+imagesDiffer(GLEAN::Image& testImage, GLEAN::Image& goldenImage) {
+ GLEAN::Image::Registration imageReg(testImage.reg(goldenImage));
+ return (imageReg.stats[0].max()
+ + imageReg.stats[1].max()
+ + imageReg.stats[2].max()) != 0.0;
+} // imagesDiffer
+
+void
+missingSome(GLEAN::Environment* env, const char* title) {
+ env->log << '\t' << title << " rendering is missing\n"
+ << "\t\tsome triangles.\n";
+} // missingSome
+
+void
+theyDiffer(GLEAN::Environment* env, const char* title) {
+ env->log << '\t' << title << " image differs from\n"
+ << "\t\tthe reference image.\n";
+} // theyDiffer
+
+void
+verifyVtxPerf(GLEAN::Image& testImage, GLEAN::RGBCodedID& colorGen,
+ int firstID, int lastID, GLEAN::Image& refImage,
+ bool& passed, string& name, GLEAN::DrawingSurfaceConfig* config,
+ GLEAN::VPSubResult& res, GLEAN::Environment* env, const char* title) {
+
+ // Verify that the entire range of RGB coded identifiers is
+ // present in the image. (This is an indicator that all triangles
+ // were actually drawn.)
+ testImage.read(0, 0);
+ if (!colorGen.allPresent(testImage, firstID, lastID)) {
+ failHeader(passed, name, config, env);
+ missingSome(env, title);
+ res.imageOK = false;
+ }
+
+ // Verify that the test image is the same as the reference image.
+ if (imagesDiffer(testImage, refImage)) {
+ failHeader(passed, name, config, env);
+ theyDiffer(env, title);
+ res.imageMatch = false;
+ }
+} // verify
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+void
+ColoredLitPerf::runOne(VPResult& r, Window& w) {
+ // Don't bother running if the ExactRGBA test for this display
+ // surface configuration failed:
+ vector<ExactRGBAResult*>::const_iterator erRes;
+ for (erRes = exactRGBATest.results.begin();
+ erRes != exactRGBATest.results.end();
+ ++erRes)
+ if ((*erRes)->config == r.config)
+ break;
+ if (erRes == exactRGBATest.results.end() || !(*erRes)->ub.pass) {
+ r.skipped = true;
+ r.pass = false;
+ return;
+ }
+
+ bool passed = true;
+ PFNGLLOCKARRAYSEXTPROC glLockArraysEXT = 0;
+ PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT = 0;
+ if (GLUtils::haveExtension("GL_EXT_compiled_vertex_array")) {
+ glLockArraysEXT = reinterpret_cast<PFNGLLOCKARRAYSEXTPROC>
+ (GLUtils::getProcAddress("glLockArraysEXT"));
+ glUnlockArraysEXT = reinterpret_cast<PFNGLUNLOCKARRAYSEXTPROC>
+ (GLUtils::getProcAddress("glUnlockArraysEXT"));
+ }
+
+ Image imTriImage(drawingSize, drawingSize, GL_RGB, GL_UNSIGNED_BYTE);
+ Image testImage(drawingSize, drawingSize, GL_RGB, GL_UNSIGNED_BYTE);
+
+ // Make colors deterministic, so we can check them:
+ RGBCodedID colorGen(r.config->r, r.config->g, r.config->b);
+ int IDModulus = colorGen.maxID() + 1;
+
+ // We need to minimize the number of pixels per triangle, so that
+ // we're measuring vertex-processing rate rather than fill rate.
+ // However, we'd also like to guarantee that every triangle covers
+ // at least one pixel, so that we can confirm drawing actually took
+ // place. As a compromise, we'll choose a number of triangles that
+ // yields approximately 3 pixels per triangle.
+ // We're drawing a filled spiral that approximates a circular area,
+ // so pi * (drawingSize/2)**2 / nTris = 3 implies...
+ const int nTris = static_cast<int>
+ (((3.14159 / 4.0) * drawingSize * drawingSize) / 3.0 + 0.5);
+ int nVertices = nTris * 3;
+ int lastID = min(IDModulus - 1, nTris - 1);
+
+ C4UB_N3F_V3F *c4ub_n3f_v3f = new C4UB_N3F_V3F[nVertices];
+ SpiralTri2D it(nTris, 0, drawingSize, 0, drawingSize);
+ int k = 0;
+ for (int j = 0; j < nTris; ++j) {
+ float* t = it(j);
+ GLubyte r, g, b;
+ colorGen.toRGB(j % IDModulus, r, g, b);
+
+ c4ub_n3f_v3f[k+0].c[0] = r;
+ c4ub_n3f_v3f[k+0].c[1] = g;
+ c4ub_n3f_v3f[k+0].c[2] = b;
+ c4ub_n3f_v3f[k+0].c[3] = 0xFF;
+ c4ub_n3f_v3f[k+0].n[0] = 0.0;
+ c4ub_n3f_v3f[k+0].n[1] = 0.0;
+ c4ub_n3f_v3f[k+0].n[2] = 1.0;
+ c4ub_n3f_v3f[k+0].v[0] = t[0];
+ c4ub_n3f_v3f[k+0].v[1] = t[1];
+ c4ub_n3f_v3f[k+0].v[2] = 0.0;
+
+ c4ub_n3f_v3f[k+1].c[0] = r;
+ c4ub_n3f_v3f[k+1].c[1] = g;
+ c4ub_n3f_v3f[k+1].c[2] = b;
+ c4ub_n3f_v3f[k+1].c[3] = 0xFF;
+ c4ub_n3f_v3f[k+1].n[0] = 0.0;
+ c4ub_n3f_v3f[k+1].n[1] = 0.0;
+ c4ub_n3f_v3f[k+1].n[2] = 1.0;
+ c4ub_n3f_v3f[k+1].v[0] = t[2];
+ c4ub_n3f_v3f[k+1].v[1] = t[3];
+ c4ub_n3f_v3f[k+1].v[2] = 0.0;
+
+ c4ub_n3f_v3f[k+2].c[0] = r;
+ c4ub_n3f_v3f[k+2].c[1] = g;
+ c4ub_n3f_v3f[k+2].c[2] = b;
+ c4ub_n3f_v3f[k+2].c[3] = 0xFF;
+ c4ub_n3f_v3f[k+2].n[0] = 0.0;
+ c4ub_n3f_v3f[k+2].n[1] = 0.0;
+ c4ub_n3f_v3f[k+2].n[2] = 1.0;
+ c4ub_n3f_v3f[k+2].v[0] = t[4];
+ c4ub_n3f_v3f[k+2].v[1] = t[5];
+ c4ub_n3f_v3f[k+2].v[2] = 0.0;
+
+ k += 3;
+ }
+
+ GLuint *indices = new GLuint[nVertices];
+ for (k = 0; k < nVertices; ++k)
+ indices[k] = k;
+
+ GLUtils::useScreenCoords(drawingSize, drawingSize);
+
+ // Diffuse white light at infinity, behind the eye:
+ GLUtils::Light light(0);
+ light.ambient(0, 0, 0, 0);
+ light.diffuse(1, 1, 1, 0);
+ light.specular(0, 0, 0, 0);
+ light.position(0, 0, 1, 0);
+ light.spotCutoff(180);
+ light.constantAttenuation(1);
+ light.linearAttenuation(0);
+ light.quadraticAttenuation(0);
+ light.enable();
+
+ GLUtils::LightModel lm;
+ lm.ambient(0, 0, 0, 0);
+ lm.localViewer(false);
+ lm.twoSide(false);
+ lm.colorControl(GL_SINGLE_COLOR);
+
+ glFrontFace(GL_CCW);
+ glEnable(GL_NORMALIZE);
+ GLUtils::Material mat;
+ mat.ambient(0, 0, 0, 1);
+ mat.ambientAndDiffuse(1, 1, 1, 1);
+ mat.specular(0, 0, 0, 1);
+ mat.emission(0, 0, 0, 1);
+ mat.shininess(0);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+ glEnable(GL_COLOR_MATERIAL);
+
+ glEnable(GL_LIGHTING);
+
+ glDisable(GL_FOG);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glReadBuffer(GL_FRONT);
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode independent triangles
+ ////////////////////////////////////////////////////////////
+ ColoredLit_imIndTri coloredLit_imIndTri(nVertices, c4ub_n3f_v3f,
+ nTris, &w, env);
+ coloredLit_imIndTri.measure(5, &r.imTri.tpsLow, &r.imTri.tps,
+ &r.imTri.tpsHigh);
+ imTriImage.read(0, 0);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.imTri, env,
+ "Immediate-mode independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // Display-listed independent triangles
+ ////////////////////////////////////////////////////////////
+ int dList = glGenLists(1);
+ glNewList(dList, GL_COMPILE);
+ coloredLit_imIndTri.op();
+ glEndList();
+ callDListTimer callDList(dList, nTris, &w, env);
+ callDList.measure(5, &r.dlTri.tpsLow, &r.dlTri.tps, &r.dlTri.tpsHigh);
+ glDeleteLists(dList, 1);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.dlTri, env,
+ "Display-listed independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // DrawArrays on independent triangles
+ ////////////////////////////////////////////////////////////
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(c4ub_n3f_v3f[0]),
+ c4ub_n3f_v3f[0].c);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glNormalPointer(GL_FLOAT, sizeof(c4ub_n3f_v3f[0]),
+ c4ub_n3f_v3f[0].n);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glVertexPointer(3, GL_FLOAT, sizeof(c4ub_n3f_v3f[0]),
+ c4ub_n3f_v3f[0].v);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ daIndTriTimer daIndTri(nVertices, indices, nTris, &w, env);
+ daIndTri.measure(5, &r.daTri.tpsLow, &r.daTri.tps, &r.daTri.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.daTri, env,
+ "DrawArrays independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // Locked DrawArrays on independent triangles
+ // XXX This is probably unrealistically favorable to
+ // locked arrays.
+ ////////////////////////////////////////////////////////////
+ if (glLockArraysEXT)
+ glLockArraysEXT(0, nVertices);
+ daIndTri.measure(5, &r.ldaTri.tpsLow, &r.ldaTri.tps,
+ &r.ldaTri.tpsHigh);
+ if (glUnlockArraysEXT)
+ glUnlockArraysEXT();
+ if (!glLockArraysEXT)
+ r.ldaTri.tps = r.ldaTri.tpsLow = r.ldaTri.tpsHigh = 0.0;
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.ldaTri, env,
+ "Locked DrawArrays independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // DrawElements on independent triangles
+ ////////////////////////////////////////////////////////////
+ deIndTriTimer deIndTri(nVertices, indices, nTris, &w, env);
+ deIndTri.measure(5, &r.deTri.tpsLow, &r.deTri.tps, &r.deTri.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.deTri, env,
+ "DrawElements independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // Locked DrawElements on independent triangles
+ ////////////////////////////////////////////////////////////
+ if (glLockArraysEXT)
+ glLockArraysEXT(0, nVertices);
+ deIndTri.measure(5, &r.ldeTri.tpsLow, &r.ldeTri.tps,
+ &r.ldeTri.tpsHigh);
+ if (glUnlockArraysEXT)
+ glUnlockArraysEXT();
+ if (!glLockArraysEXT)
+ r.ldeTri.tps = r.ldeTri.tpsLow = r.ldeTri.tpsHigh = 0.0;
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.ldeTri, env,
+ "Locked DrawElements independent triangle");
+
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ delete[] c4ub_n3f_v3f;
+ delete[] indices;
+
+ // Now we test triangle strips, rather than independent triangles.
+
+ nVertices = nTris + 2;
+ lastID = min(IDModulus - 1, nTris - 1);
+
+ c4ub_n3f_v3f = new C4UB_N3F_V3F[nVertices];
+ SpiralStrip2D is(nVertices, 0, drawingSize, 0, drawingSize);
+ for (int j2 = 0; j2 < nVertices; ++j2) {
+ float* t = is(j2);
+ GLubyte r, g, b;
+ // Take care to get the correct color on the provoking vertex:
+ colorGen.toRGB((j2 - 2) % IDModulus, r, g, b);
+
+ c4ub_n3f_v3f[j2].c[0] = r;
+ c4ub_n3f_v3f[j2].c[1] = g;
+ c4ub_n3f_v3f[j2].c[2] = b;
+ c4ub_n3f_v3f[j2].c[3] = 0xFF;
+ c4ub_n3f_v3f[j2].n[0] = 0.0;
+ c4ub_n3f_v3f[j2].n[1] = 0.0;
+ c4ub_n3f_v3f[j2].n[2] = 1.0;
+ c4ub_n3f_v3f[j2].v[0] = t[0];
+ c4ub_n3f_v3f[j2].v[1] = t[1];
+ c4ub_n3f_v3f[j2].v[2] = 0.0;
+ }
+
+ indices = new GLuint[nVertices];
+ for (int j3 = 0; j3 < nVertices; ++j3)
+ indices[j3] = j3;
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode triangle strips
+ ////////////////////////////////////////////////////////////
+ ColoredLit_imTriStrip coloredLit_imTriStrip(nVertices, c4ub_n3f_v3f,
+ nTris, &w, env);
+ coloredLit_imTriStrip.measure(5, &r.imTS.tpsLow, &r.imTS.tps,
+ &r.imTS.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.imTS, env,
+ "Immediate-mode triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // Display-listed triangle strips
+ ////////////////////////////////////////////////////////////
+ dList = glGenLists(1);
+ glNewList(dList, GL_COMPILE);
+ coloredLit_imTriStrip.op();
+ glEndList();
+ callDList.dList = dList;
+ callDList.measure(5, &r.dlTS.tpsLow, &r.dlTS.tps, &r.dlTS.tpsHigh);
+ glDeleteLists(dList, 1);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.dlTS, env,
+ "Display-listed triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // DrawArrays on triangle strips
+ ////////////////////////////////////////////////////////////
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(c4ub_n3f_v3f[0]),
+ c4ub_n3f_v3f[0].c);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glNormalPointer(GL_FLOAT, sizeof(c4ub_n3f_v3f[0]),
+ c4ub_n3f_v3f[0].n);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glVertexPointer(3, GL_FLOAT, sizeof(c4ub_n3f_v3f[0]),
+ c4ub_n3f_v3f[0].v);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ daTriStripTimer daTriStrip(nVertices, nTris, &w, env);
+ daTriStrip.measure(5, &r.daTS.tpsLow, &r.daTS.tps, &r.daTS.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.daTS, env,
+ "DrawArrays triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // Locked DrawArrays on triangle strips
+ ////////////////////////////////////////////////////////////
+ if (glLockArraysEXT)
+ glLockArraysEXT(0, nVertices);
+ daTriStrip.measure(5, &r.ldaTS.tpsLow, &r.ldaTS.tps, &r.ldaTS.tpsHigh);
+ if (glUnlockArraysEXT)
+ glUnlockArraysEXT();
+ if (!glLockArraysEXT)
+ r.ldaTS.tps = r.ldaTS.tpsLow = r.ldaTS.tpsHigh = 0.0;
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.ldaTS, env,
+ "Locked DrawArrays triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // DrawElements on triangle strips
+ ////////////////////////////////////////////////////////////
+ deTriStripTimer deTriStrip(nVertices, indices, nTris, &w, env);
+ deTriStrip.measure(5, &r.deTS.tpsLow, &r.deTS.tps, &r.deTS.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.deTS, env,
+ "DrawElements triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // Locked DrawElements on triangle strips
+ ////////////////////////////////////////////////////////////
+ if (glLockArraysEXT)
+ glLockArraysEXT(0, nVertices);
+ deTriStrip.measure(5, &r.ldeTS.tpsLow, &r.ldeTS.tps, &r.ldeTS.tpsHigh);
+ if (glUnlockArraysEXT)
+ glUnlockArraysEXT();
+ if (!glLockArraysEXT)
+ r.ldeTS.tps = r.ldeTS.tpsLow = r.ldeTS.tpsHigh = 0.0;
+
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.ldeTS, env,
+ "Locked DrawElements triangle strip");
+
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ delete[] c4ub_n3f_v3f;
+ delete[] indices;
+
+ r.pass = passed;
+ r.skipped = false;
+} // ColoredLitPerf::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ColoredLitPerf::logOne(VPResult& r) {
+ if (r.skipped) {
+ env->log << name << ": NOTE ";
+ logConcise(r);
+ env->log << "\tTest skipped; prerequisite test "
+ << exactRGBATest.name
+ << " failed or was not run\n";
+ return;
+ }
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ } else env->log << '\n'; // because verify logs failure
+ logStats(r, env);
+} // ColoredLitPerf::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ColoredLitPerf::compareOne(VPResult& oldR, VPResult& newR) {
+ if (oldR.skipped || newR.skipped) {
+ env->log << name
+ << ((oldR.skipped && newR.skipped)? ": SAME "
+ : ": DIFF ")
+ << newR.config->conciseDescription()
+ << '\n';
+ if (oldR.skipped)
+ env->log << "\t"
+ << env->options.db1Name
+ << " skipped\n";
+ if (newR.skipped)
+ env->log << "\t"
+ << env->options.db2Name
+ << " skipped\n";
+ env->log << "\tNo comparison is possible.\n";
+ return;
+ }
+
+ bool same = true;
+ doComparison(oldR.imTri, newR.imTri, newR.config, same, name,
+ env, "immediate-mode independent triangle");
+ doComparison(oldR.dlTri, newR.dlTri, newR.config, same, name,
+ env, "display-listed independent triangle");
+ doComparison(oldR.daTri, newR.daTri, newR.config, same, name,
+ env, "DrawArrays independent triangle");
+ doComparison(oldR.ldaTri, newR.ldaTri, newR.config, same, name,
+ env, "Locked DrawArrays independent triangle");
+ doComparison(oldR.deTri, newR.deTri, newR.config, same, name,
+ env, "DrawElements independent triangle");
+ doComparison(oldR.ldeTri, newR.ldeTri, newR.config, same, name,
+ env, "Locked DrawElements independent triangle");
+ doComparison(oldR.imTS, newR.imTS, newR.config, same, name,
+ env, "immediate-mode triangle strip");
+ doComparison(oldR.dlTS, newR.dlTS, newR.config, same, name,
+ env, "display-listed triangle strip");
+ doComparison(oldR.daTS, newR.daTS, newR.config, same, name,
+ env, "DrawArrays triangle strip");
+ doComparison(oldR.ldaTS, newR.ldaTS, newR.config, same, name,
+ env, "Locked DrawArrays triangle strip");
+ doComparison(oldR.deTS, newR.deTS, newR.config, same, name,
+ env, "DrawElements triangle strip");
+ doComparison(oldR.ldeTS, newR.ldeTS, newR.config, same, name,
+ env, "Locked DrawElements triangle strip");
+
+ if (same && env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n\t"
+ << env->options.db2Name
+ << " test time falls within the "
+ << "valid measurement range of\n\t"
+ << env->options.db1Name
+ << " test time; both have the same"
+ << " image comparison results.\n";
+ }
+
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR, env);
+ env->log << env->options.db2Name << ':';
+ logStats(newR, env);
+ }
+} // ColoredLitPerf::compareOne
+
+void
+ColoredLitPerf::logStats(VPResult& r, GLEAN::Environment* env) {
+ logStats1("Immediate-mode independent triangle", r.imTri, env);
+ logStats1("Display-listed independent triangle", r.dlTri, env);
+ logStats1("DrawArrays independent triangle", r.daTri, env);
+ logStats1("Locked DrawArrays independent triangle", r.ldaTri, env);
+ logStats1("DrawElements independent triangle", r.deTri, env);
+ logStats1("Locked DrawElements independent triangle", r.ldeTri, env);
+ logStats1("Immediate-mode triangle strip", r.imTS, env);
+ logStats1("Display-listed triangle strip", r.dlTS, env);
+ logStats1("DrawArrays triangle strip", r.daTS, env);
+ logStats1("Locked DrawArrays triangle strip", r.ldaTS, env);
+ logStats1("DrawElements triangle strip", r.deTS, env);
+ logStats1("Locked DrawElements triangle strip", r.ldeTS, env);
+} // ColoredLitPerf::logStats
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+
+Test* coloredLitPerfTestPrereqs[] = {&exactRGBATest, 0};
+
+ColoredLitPerf coloredLitPerfTest("coloredLitPerf2", "window, rgb, z, fast",
+ coloredLitPerfTestPrereqs,
+
+ "This test examines rendering performance for colored, lit,\n"
+ "flat-shaded triangles. It checks several different ways to\n"
+ "specify the vertex data in order to determine which is\n"
+ "fastest: fine-grained API calls, DrawArrays, DrawElements,\n"
+ "locked (compiled) DrawArrays, and locked DrawElements; for\n"
+ "independent triangles and for triangle strips. The test\n"
+ "result is performance measured in triangles per second for\n"
+ "each of the various vertex specification methods.\n"
+
+ "\nAs a sanity-check on the correctness of each method, the test\n"
+ "colors each triangle with a unique color, and verifies that all\n"
+ "such colors are actually present in the final image. For\n"
+ "consistency, the test also verifies that the images are identical\n"
+ "for each of the specification methods.\n"
+
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+void
+ColoredTexPerf::runOne(VPResult& r, Window& w) {
+ // Don't bother running if the ExactRGBA test for this display
+ // surface configuration failed:
+ vector<ExactRGBAResult*>::const_iterator erRes;
+ for (erRes = exactRGBATest.results.begin();
+ erRes != exactRGBATest.results.end();
+ ++erRes)
+ if ((*erRes)->config == r.config)
+ break;
+ if (erRes == exactRGBATest.results.end() || !(*erRes)->ub.pass) {
+ r.skipped = true;
+ r.pass = false;
+ return;
+ }
+
+ PFNGLLOCKARRAYSEXTPROC glLockArraysEXT = 0;
+ PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT = 0;
+ if (GLUtils::haveExtension("GL_EXT_compiled_vertex_array")) {
+ glLockArraysEXT = reinterpret_cast<PFNGLLOCKARRAYSEXTPROC>
+ (GLUtils::getProcAddress("glLockArraysEXT"));
+ glUnlockArraysEXT = reinterpret_cast<PFNGLUNLOCKARRAYSEXTPROC>
+ (GLUtils::getProcAddress("glUnlockArraysEXT"));
+ }
+
+ Image imTriImage(drawingSize, drawingSize, GL_RGB, GL_UNSIGNED_BYTE);
+ Image testImage(drawingSize, drawingSize, GL_RGB, GL_UNSIGNED_BYTE);
+ bool passed = true;
+
+ // Make colors deterministic, so we can check them:
+ RGBCodedID colorGen(r.config->r, r.config->g, r.config->b);
+ int IDModulus = colorGen.maxID() + 1;
+
+ // We need to minimize the number of pixels per triangle, so that
+ // we're measuring vertex-processing rate rather than fill rate.
+ // However, we'd also like to guarantee that every triangle covers
+ // at least one pixel, so that we can confirm drawing actually took
+ // place. As a compromise, we'll choose a number of triangles that
+ // yields approximately 3 pixels per triangle.
+ // We're drawing a filled spiral that approximates a circular area,
+ // so pi * (drawingSize/2)**2 / nTris = 3 implies...
+ const int nTris = static_cast<int>
+ (((3.14159 / 4.0) * drawingSize * drawingSize) / 3.0 + 0.5);
+ int nVertices = nTris * 3;
+ int lastID = min(IDModulus - 1, nTris - 1);
+
+ C4UB_T2F_V3F *c4ub_t2f_v3f = new C4UB_T2F_V3F[nVertices];
+ SpiralTri2D it(nTris, 0, drawingSize, 0, drawingSize);
+ int k = 0;
+ for (int j = 0; j < nTris; ++j) {
+ float* t = it(j);
+ GLubyte r, g, b;
+ colorGen.toRGB(j % IDModulus, r, g, b);
+
+ c4ub_t2f_v3f[k+0].c[0] = r;
+ c4ub_t2f_v3f[k+0].c[1] = g;
+ c4ub_t2f_v3f[k+0].c[2] = b;
+ c4ub_t2f_v3f[k+0].c[3] = 0xFF;
+ c4ub_t2f_v3f[k+0].t[0] = 0.5;
+ c4ub_t2f_v3f[k+0].t[1] = 0.5;
+ c4ub_t2f_v3f[k+0].v[0] = t[0];
+ c4ub_t2f_v3f[k+0].v[1] = t[1];
+ c4ub_t2f_v3f[k+0].v[2] = 0.0;
+
+ c4ub_t2f_v3f[k+1].c[0] = r;
+ c4ub_t2f_v3f[k+1].c[1] = g;
+ c4ub_t2f_v3f[k+1].c[2] = b;
+ c4ub_t2f_v3f[k+1].c[3] = 0xFF;
+ c4ub_t2f_v3f[k+1].t[0] = 0.5;
+ c4ub_t2f_v3f[k+1].t[1] = 0.5;
+ c4ub_t2f_v3f[k+1].v[0] = t[2];
+ c4ub_t2f_v3f[k+1].v[1] = t[3];
+ c4ub_t2f_v3f[k+1].v[2] = 0.0;
+
+ c4ub_t2f_v3f[k+2].c[0] = r;
+ c4ub_t2f_v3f[k+2].c[1] = g;
+ c4ub_t2f_v3f[k+2].c[2] = b;
+ c4ub_t2f_v3f[k+2].c[3] = 0xFF;
+ c4ub_t2f_v3f[k+2].t[0] = 0.5;
+ c4ub_t2f_v3f[k+2].t[1] = 0.5;
+ c4ub_t2f_v3f[k+2].v[0] = t[4];
+ c4ub_t2f_v3f[k+2].v[1] = t[5];
+ c4ub_t2f_v3f[k+2].v[2] = 0.0;
+
+ k += 3;
+ }
+
+ GLuint *indices = new GLuint[nVertices];
+ for (k = 0; k < nVertices; ++k)
+ indices[k] = k;
+
+ GLUtils::useScreenCoords(drawingSize, drawingSize);
+
+ glFrontFace(GL_CCW);
+ glDisable(GL_NORMALIZE);
+ glDisable(GL_COLOR_MATERIAL);
+
+ glDisable(GL_LIGHTING);
+
+ // Set up an all-white RGB texture, including mipmap levels:
+ {
+ const int width = 8;
+ const int height = 8;
+ GLubyte whiteTex[width * height * 3];
+ for (int i = 0; i < width * height * 3; ++i)
+ whiteTex[i] = 255;
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
+ glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
+ glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
+ glPixelTransferf(GL_RED_SCALE, 1.0);
+ glPixelTransferf(GL_GREEN_SCALE, 1.0);
+ glPixelTransferf(GL_BLUE_SCALE, 1.0);
+ glPixelTransferf(GL_ALPHA_SCALE, 1.0);
+ glPixelTransferf(GL_RED_BIAS, 0.0);
+ glPixelTransferf(GL_GREEN_BIAS, 0.0);
+ glPixelTransferf(GL_BLUE_BIAS, 0.0);
+ glPixelTransferf(GL_ALPHA_BIAS, 0.0);
+ gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, width, height, GL_RGB,
+ GL_UNSIGNED_BYTE, whiteTex);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ glDisable(GL_FOG);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glShadeModel(GL_FLAT);
+
+ glReadBuffer(GL_FRONT);
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode independent triangles
+ ////////////////////////////////////////////////////////////
+ ColoredTex_imIndTri coloredTex_imIndTri(nVertices, c4ub_t2f_v3f,
+ nTris, &w, env);
+ coloredTex_imIndTri.measure(5, &r.imTri.tpsLow, &r.imTri.tps,
+ &r.imTri.tpsHigh);
+ imTriImage.read(0, 0);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.imTri, env,
+ "Immediate-mode independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // Display-listed independent triangles
+ ////////////////////////////////////////////////////////////
+ int dList = glGenLists(1);
+ glNewList(dList, GL_COMPILE);
+ coloredTex_imIndTri.op();
+ glEndList();
+ callDListTimer callDList(dList, nTris, &w, env);
+ callDList.measure(5, &r.dlTri.tpsLow, &r.dlTri.tps, &r.dlTri.tpsHigh);
+ glDeleteLists(dList, 1);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.dlTri, env,
+ "Display-listed independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // DrawArrays on independent triangles
+ ////////////////////////////////////////////////////////////
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(c4ub_t2f_v3f[0]),
+ c4ub_t2f_v3f[0].c);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, sizeof(c4ub_t2f_v3f[0]),
+ c4ub_t2f_v3f[0].t);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(3, GL_FLOAT, sizeof(c4ub_t2f_v3f[0]),
+ c4ub_t2f_v3f[0].v);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ daIndTriTimer daIndTri(nVertices, indices, nTris, &w, env);
+ daIndTri.measure(5, &r.daTri.tpsLow, &r.daTri.tps, &r.daTri.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.daTri, env,
+ "DrawArrays independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // Locked DrawArrays on independent triangles
+ // XXX This is probably unrealistically favorable to
+ // locked arrays.
+ ////////////////////////////////////////////////////////////
+ if (glLockArraysEXT)
+ glLockArraysEXT(0, nVertices);
+ daIndTri.measure(5, &r.ldaTri.tpsLow, &r.ldaTri.tps,
+ &r.ldaTri.tpsHigh);
+ if (glUnlockArraysEXT)
+ glUnlockArraysEXT();
+ if (!glLockArraysEXT)
+ r.ldaTri.tps = r.ldaTri.tpsLow = r.ldaTri.tpsHigh = 0.0;
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.ldaTri, env,
+ "Locked DrawArrays independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // DrawElements on independent triangles
+ ////////////////////////////////////////////////////////////
+ deIndTriTimer deIndTri(nVertices, indices, nTris, &w, env);
+ deIndTri.measure(5, &r.deTri.tpsLow, &r.deTri.tps, &r.deTri.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.deTri, env,
+ "DrawElements independent triangle");
+
+ ////////////////////////////////////////////////////////////
+ // Locked DrawElements on independent triangles
+ ////////////////////////////////////////////////////////////
+ if (glLockArraysEXT)
+ glLockArraysEXT(0, nVertices);
+ deIndTri.measure(5, &r.ldeTri.tpsLow, &r.ldeTri.tps,
+ &r.ldeTri.tpsHigh);
+ if (glUnlockArraysEXT)
+ glUnlockArraysEXT();
+ if (!glLockArraysEXT)
+ r.ldeTri.tps = r.ldeTri.tpsLow = r.ldeTri.tpsHigh = 0.0;
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.ldeTri, env,
+ "Locked DrawElements independent triangle");
+
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ delete[] c4ub_t2f_v3f;
+ delete[] indices;
+
+ // Now we test triangle strips, rather than independent triangles.
+
+ nVertices = nTris + 2;
+ lastID = min(IDModulus - 1, nTris - 1);
+
+ c4ub_t2f_v3f = new C4UB_T2F_V3F[nVertices];
+ SpiralStrip2D is(nVertices, 0, drawingSize, 0, drawingSize);
+ for (int j2 = 0; j2 < nVertices; ++j2) {
+ float* t = is(j2);
+ GLubyte r, g, b;
+ // Take care to get the correct color on the provoking vertex:
+ colorGen.toRGB((j2 - 2) % IDModulus, r, g, b);
+
+ c4ub_t2f_v3f[j2].c[0] = r;
+ c4ub_t2f_v3f[j2].c[1] = g;
+ c4ub_t2f_v3f[j2].c[2] = b;
+ c4ub_t2f_v3f[j2].c[3] = 0xFF;
+ c4ub_t2f_v3f[j2].t[0] = 0.5;
+ c4ub_t2f_v3f[j2].t[1] = 0.5;
+ c4ub_t2f_v3f[j2].v[0] = t[0];
+ c4ub_t2f_v3f[j2].v[1] = t[1];
+ c4ub_t2f_v3f[j2].v[2] = 0.0;
+ }
+
+ indices = new GLuint[nVertices];
+ for (int j3 = 0; j3 < nVertices; ++j3)
+ indices[j3] = j3;
+
+ ////////////////////////////////////////////////////////////
+ // Immediate-mode triangle strips
+ ////////////////////////////////////////////////////////////
+ ColoredTex_imTriStrip coloredTex_imTriStrip(nVertices, c4ub_t2f_v3f,
+ nTris, &w, env);
+ coloredTex_imTriStrip.measure(5, &r.imTS.tpsLow, &r.imTS.tps,
+ &r.imTS.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.imTS, env,
+ "Immediate-mode triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // Display-listed triangle strips
+ ////////////////////////////////////////////////////////////
+ dList = glGenLists(1);
+ glNewList(dList, GL_COMPILE);
+ coloredTex_imTriStrip.op();
+ glEndList();
+ callDList.dList = dList;
+ callDList.measure(5, &r.dlTS.tpsLow, &r.dlTS.tps, &r.dlTS.tpsHigh);
+ glDeleteLists(dList, 1);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.dlTS, env,
+ "Display-listed triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // DrawArrays on triangle strips
+ ////////////////////////////////////////////////////////////
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(c4ub_t2f_v3f[0]),
+ c4ub_t2f_v3f[0].c);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, sizeof(c4ub_t2f_v3f[0]),
+ c4ub_t2f_v3f[0].t);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(3, GL_FLOAT, sizeof(c4ub_t2f_v3f[0]),
+ c4ub_t2f_v3f[0].v);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ daTriStripTimer daTriStrip(nVertices, nTris, &w, env);
+ daTriStrip.measure(5, &r.daTS.tpsLow, &r.daTS.tps, &r.daTS.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.daTS, env,
+ "DrawArrays triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // Locked DrawArrays on triangle strips
+ ////////////////////////////////////////////////////////////
+ if (glLockArraysEXT)
+ glLockArraysEXT(0, nVertices);
+ daTriStrip.measure(5, &r.ldaTS.tpsLow, &r.ldaTS.tps, &r.ldaTS.tpsHigh);
+ if (glUnlockArraysEXT)
+ glUnlockArraysEXT();
+ if (!glLockArraysEXT)
+ r.ldaTS.tps = r.ldaTS.tpsLow = r.ldaTS.tpsHigh = 0.0;
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.ldaTS, env,
+ "Locked DrawArrays triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // DrawElements on triangle strips
+ ////////////////////////////////////////////////////////////
+ deTriStripTimer deTriStrip(nVertices, indices, nTris, &w, env);
+ deTriStrip.measure(5, &r.deTS.tpsLow, &r.deTS.tps, &r.deTS.tpsHigh);
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.deTS, env,
+ "DrawElements triangle strip");
+
+ ////////////////////////////////////////////////////////////
+ // Locked DrawElements on triangle strips
+ ////////////////////////////////////////////////////////////
+ if (glLockArraysEXT)
+ glLockArraysEXT(0, nVertices);
+ deTriStrip.measure(5, &r.ldeTS.tpsLow, &r.ldeTS.tps, &r.ldeTS.tpsHigh);
+ if (glUnlockArraysEXT)
+ glUnlockArraysEXT();
+ if (!glLockArraysEXT)
+ r.ldeTS.tps = r.ldeTS.tpsLow = r.ldeTS.tpsHigh = 0.0;
+ verifyVtxPerf(testImage, colorGen, 0, lastID, imTriImage,
+ passed, name, r.config, r.ldeTS, env,
+ "Locked DrawElements triangle strip");
+
+
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ delete[] c4ub_t2f_v3f;
+ delete[] indices;
+
+ r.pass = passed;
+ r.skipped = false;
+} // ColoredTexPerf::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logOne: Log a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ColoredTexPerf::logOne(VPResult& r) {
+ if (r.skipped) {
+ env->log << name << ": NOTE ";
+ logConcise(r);
+ env->log << "\tTest skipped; prerequisite test "
+ << exactRGBATest.name
+ << " failed or was not run\n"
+ ;
+ return;
+ }
+ if (r.pass) {
+ logPassFail(r);
+ logConcise(r);
+ } else env->log << '\n'; // because verify logs failure
+ logStats(r, env);
+} // ColoredTexPerf::logOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+ColoredTexPerf::compareOne(VPResult& oldR, VPResult& newR) {
+ if (oldR.skipped || newR.skipped) {
+ env->log << name
+ << ((oldR.skipped && newR.skipped)? ": SAME "
+ : ": DIFF ")
+ << newR.config->conciseDescription()
+ << '\n';
+ if (oldR.skipped)
+ env->log << "\t"
+ << env->options.db1Name
+ << " skipped\n";
+ if (newR.skipped)
+ env->log << "\t"
+ << env->options.db2Name
+ << " skipped\n";
+ env->log << "\tNo comparison is possible.\n";
+ return;
+ }
+
+ bool same = true;
+ doComparison(oldR.imTri, newR.imTri, newR.config, same, name,
+ env, "immediate-mode independent triangle");
+ doComparison(oldR.dlTri, newR.dlTri, newR.config, same, name,
+ env, "display-listed independent triangle");
+ doComparison(oldR.daTri, newR.daTri, newR.config, same, name,
+ env, "DrawArrays independent triangle");
+ doComparison(oldR.ldaTri, newR.ldaTri, newR.config, same, name,
+ env, "Locked DrawArrays independent triangle");
+ doComparison(oldR.deTri, newR.deTri, newR.config, same, name,
+ env, "DrawElements independent triangle");
+ doComparison(oldR.ldeTri, newR.ldeTri, newR.config, same, name,
+ env, "Locked DrawElements independent triangle");
+ doComparison(oldR.imTS, newR.imTS, newR.config, same, name,
+ env, "immediate-mode triangle strip");
+ doComparison(oldR.dlTS, newR.dlTS, newR.config, same, name,
+ env, "display-listed triangle strip");
+ doComparison(oldR.daTS, newR.daTS, newR.config, same, name,
+ env, "DrawArrays triangle strip");
+ doComparison(oldR.ldaTS, newR.ldaTS, newR.config, same, name,
+ env, "Locked DrawArrays triangle strip");
+ doComparison(oldR.deTS, newR.deTS, newR.config, same, name,
+ env, "DrawElements triangle strip");
+ doComparison(oldR.ldeTS, newR.ldeTS, newR.config, same, name,
+ env, "Locked DrawElements triangle strip");
+
+ if (same && env->options.verbosity) {
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n\t"
+ << env->options.db2Name
+ << " test time falls within the "
+ << "valid measurement range of\n\t"
+ << env->options.db1Name
+ << " test time; both have the same"
+ << " image comparison results.\n";
+ }
+
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR, env);
+ env->log << env->options.db2Name << ':';
+ logStats(newR, env);
+ }
+} // ColoredTexPerf::compareOne
+
+void
+ColoredTexPerf::logStats(VPResult& r, GLEAN::Environment* env) {
+ logStats1("Immediate-mode independent triangle", r.imTri, env);
+ logStats1("Display-listed independent triangle", r.dlTri, env);
+ logStats1("DrawArrays independent triangle", r.daTri, env);
+ logStats1("Locked DrawArrays independent triangle", r.ldaTri, env);
+ logStats1("DrawElements independent triangle", r.deTri, env);
+ logStats1("Locked DrawElements independent triangle", r.ldeTri, env);
+ logStats1("Immediate-mode triangle strip", r.imTS, env);
+ logStats1("Display-listed triangle strip", r.dlTS, env);
+ logStats1("DrawArrays triangle strip", r.daTS, env);
+ logStats1("Locked DrawArrays triangle strip", r.ldaTS, env);
+ logStats1("DrawElements triangle strip", r.deTS, env);
+ logStats1("Locked DrawElements triangle strip", r.ldeTS, env);
+} // ColoredTexPerf::logStats
+
+///////////////////////////////////////////////////////////////////////////////
+// The test object itself:
+///////////////////////////////////////////////////////////////////////////////
+//
+Test* coloredTexPerfTestPrereqs[] = {&exactRGBATest, 0};
+
+ColoredTexPerf coloredTexPerfTest("coloredTexPerf2", "window, rgb, z, fast",
+ coloredTexPerfTestPrereqs,
+
+ "This test examines rendering performance for colored, textured,\n"
+ "flat-shaded triangles. It checks several different ways to\n"
+ "specify the vertex data in order to determine which is\n"
+ "fastest: fine-grained API calls, DrawArrays, DrawElements,\n"
+ "locked (compiled) DrawArrays, and locked DrawElements; for\n"
+ "independent triangles and for triangle strips. The test\n"
+ "result is performance measured in triangles per second for\n"
+ "each of the various vertex specification methods.\n"
+
+ "\nAs a sanity-check on the correctness of each method, the test\n"
+ "colors each triangle with a unique color, and verifies that all\n"
+ "such colors are actually present in the final image. For\n"
+ "consistency, the test also verifies that the images are identical\n"
+ "for each of the specification methods.\n"
+
+ );
+
+} // namespace GLEAN
diff --git a/tests/glean/tvtxperf.h b/tests/glean/tvtxperf.h
new file mode 100644
index 00000000..755902ea
--- /dev/null
+++ b/tests/glean/tvtxperf.h
@@ -0,0 +1,147 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 2000 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+// tvtxperf.h: Test performance of various ways to specify vertex data
+
+#ifndef __tvtxperf_h__
+#define __tvtxperf_h__
+
+#include "tbase.h"
+
+namespace GLEAN {
+
+#define drawingSize 256
+
+// Auxiliary struct for holding a vertex-performance result:
+class VPSubResult {
+public:
+ double tps; // Triangles Per Second
+ double tpsLow; // Low end of tps range
+ double tpsHigh; // High end of tps range
+ bool imageOK; // Image sanity-check status
+ bool imageMatch; // Image comparison status
+
+ VPSubResult() {
+ tps = tpsLow = tpsHigh = 0.0;
+ imageOK = imageMatch = true;
+ }
+
+ void put(ostream& s) const {
+ s << tps
+ << ' ' << tpsLow
+ << ' ' << tpsHigh
+ << ' ' << imageOK
+ << ' ' << imageMatch
+ << '\n';
+ }
+
+ void get(istream& s) {
+ s >> tps >> tpsLow >> tpsHigh >> imageOK >> imageMatch;
+ }
+};
+
+class VPResult: public BaseResult {
+public:
+ bool skipped; // prerequisite tests failed
+ bool pass;
+
+ VPSubResult imTri; // immediate-mode independent triangles
+ VPSubResult dlTri; // display-listed independent triangles
+ VPSubResult daTri; // DrawArrays independent triangles
+ VPSubResult ldaTri; // Locked DrawArrays independent tris
+ VPSubResult deTri; // DrawElements independent triangles
+ VPSubResult ldeTri; // Locked DrawElements ind. tris
+
+ VPSubResult imTS; // immediate-mode triangle strip
+ VPSubResult dlTS; // display-listed triangle strip
+ VPSubResult daTS; // DrawArrays triangle strip
+ VPSubResult ldaTS; // Locked DrawArrays triangle strip
+ VPSubResult deTS; // DrawElements triangle strip
+ VPSubResult ldeTS; // Locked DrawElements triangle strip
+
+ virtual void putresults(ostream& s) const {
+ s
+ << skipped << '\n'
+ << pass << '\n'
+ ;
+
+ imTri.put(s);
+ dlTri.put(s);
+ daTri.put(s);
+ ldaTri.put(s);
+ deTri.put(s);
+ ldeTri.put(s);
+
+ imTS.put(s);
+ dlTS.put(s);
+ daTS.put(s);
+ ldaTS.put(s);
+ deTS.put(s);
+ ldeTS.put(s);
+ }
+
+ virtual bool getresults(istream& s) {
+ s
+ >> skipped
+ >> pass
+ ;
+ imTri.get(s);
+ dlTri.get(s);
+ daTri.get(s);
+ ldaTri.get(s);
+ deTri.get(s);
+ ldeTri.get(s);
+
+ imTS.get(s);
+ dlTS.get(s);
+ daTS.get(s);
+ ldaTS.get(s);
+ deTS.get(s);
+ ldeTS.get(s);
+
+ return s.good();
+ }
+};
+
+class ColoredLitPerf: public BaseTest<VPResult> {
+public:
+ GLEAN_CLASS_WHO(ColoredLitPerf, VPResult,
+ drawingSize, drawingSize, true);
+ void logStats(VPResult& r, GLEAN::Environment* env);
+}; // class ColoredLitPerf
+
+class ColoredTexPerf: public BaseTest<VPResult> {
+public:
+ GLEAN_CLASS_WHO(ColoredTexPerf, VPResult,
+ drawingSize, drawingSize, true);
+ void logStats(VPResult& r, GLEAN::Environment* env);
+}; // class ColoredTexPerf
+
+} // namespace GLEAN
+
+#endif // __tvtxperf_h__
diff --git a/tests/glean/unpack.cpp b/tests/glean/unpack.cpp
new file mode 100644
index 00000000..5c0c9a6f
--- /dev/null
+++ b/tests/glean/unpack.cpp
@@ -0,0 +1,271 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// Data unpacking utilities. Note that these map component values per
+// the usual OpenGL conventions.
+
+// XXX The construction of SCALE and BIAS is clumsy, and the need to
+// test bias is really unfortunate, but egcs 1.1.2 won't propagate
+// floating-point constant expressions from equivalent const
+// declarations.
+
+#include "image.h"
+
+namespace {
+
+#define SCALE (static_cast<double>(num) / static_cast<double>(denom))
+#define BIAS (static_cast<double>(bias) / static_cast<double>(denom))
+
+// See comments in pack.cpp concerning this workaround for a VC6 problem.
+
+template<class component, int num, unsigned int denom, int bias>
+class Unpack
+{
+public :
+ // unpack_l
+ static void unpack_l(GLsizei n, double* rgba, char* src)
+ {
+ component* in = reinterpret_cast<component*>(src);
+ // XXX It seems to me that static_cast should be sufficient,
+ // but egcs 1.1.2 thinks otherwise.
+
+ double* end = rgba + 4 * n;
+ for (; rgba != end; rgba += 4) {
+ if (bias)
+ rgba[0] = SCALE * in[0] + BIAS;
+ else
+ rgba[0] = SCALE * in[0];
+ rgba[1] = rgba[2] = rgba[3] = 0.0;
+ in += 1;
+ }
+ }
+
+ // unpack_la
+ static void unpack_la(GLsizei n, double* rgba, char* src)
+ {
+ component* in = reinterpret_cast<component*>(src);
+ double* end = rgba + 4 * n;
+ for (; rgba != end; rgba += 4) {
+ if (bias) {
+ rgba[0] = SCALE * in[0] + BIAS;
+ rgba[3] = SCALE * in[1] + BIAS;
+ } else {
+ rgba[0] = SCALE * in[0];
+ rgba[3] = SCALE * in[1];
+ }
+ rgba[1] = rgba[2] = 0.0;
+ in += 2;
+ }
+ }
+
+ // unpack_rgb
+ static void unpack_rgb(GLsizei n, double* rgba, char* src)
+ {
+ component* in = reinterpret_cast<component*>(src);
+ double* end = rgba + 4 * n;
+ for (; rgba != end; rgba += 4) {
+ if (bias) {
+ rgba[0] = SCALE * in[0] + BIAS;
+ rgba[1] = SCALE * in[1] + BIAS;
+ rgba[2] = SCALE * in[2] + BIAS;
+ } else {
+ rgba[0] = SCALE * in[0];
+ rgba[1] = SCALE * in[1];
+ rgba[2] = SCALE * in[2];
+ }
+ rgba[3] = 0.0;
+ in += 3;
+ }
+ }
+
+ // unpack_rgba
+ static void unpack_rgba(GLsizei n, double* rgba, char* src)
+ {
+ component* in = reinterpret_cast<component*>(src);
+ double* end = rgba + 4 * n;
+ for (; rgba != end; rgba += 4) {
+ if (bias) {
+ rgba[0] = SCALE * in[0] + BIAS;
+ rgba[1] = SCALE * in[1] + BIAS;
+ rgba[2] = SCALE * in[2] + BIAS;
+ rgba[3] = SCALE * in[3] + BIAS;
+ } else {
+ rgba[0] = SCALE * in[0];
+ rgba[1] = SCALE * in[1];
+ rgba[2] = SCALE * in[2];
+ rgba[3] = SCALE * in[3];
+ }
+ in += 4;
+ }
+ }
+
+}; // class Unpack
+
+#undef SCALE
+#undef BIAS
+
+}; // anonymous namespace
+
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Public interface
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::unpack(GLsizei n, double* rgba, char* nextPixel) {
+ (*(valid(vbUnpacker)? _unpacker: validateUnpacker()))
+ (n, rgba, nextPixel);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// validateUnpacker - select appropriate pixel-unpacking utility
+///////////////////////////////////////////////////////////////////////////////
+Image::Unpacker*
+Image::validateUnpacker() {
+ switch (format()) {
+ case GL_LUMINANCE:
+ switch (type()) {
+ case GL_BYTE:
+ _unpacker = Unpack<GLbyte, 2, 255, 1>::unpack_l;
+ break;
+ case GL_UNSIGNED_BYTE:
+ _unpacker = Unpack<GLubyte, 1, 255, 0>::unpack_l;
+ break;
+ case GL_SHORT:
+ _unpacker = Unpack<GLshort, 2, 65535, 1>::unpack_l;
+ break;
+ case GL_UNSIGNED_SHORT:
+ _unpacker = Unpack<GLushort, 1, 65535, 0>::unpack_l;
+ break;
+ case GL_INT:
+ _unpacker = Unpack<GLint, 2, 4294967295U, 1>::unpack_l;
+ break;
+ case GL_UNSIGNED_INT:
+ _unpacker = Unpack<GLuint, 1, 4294967295U, 0>::unpack_l;
+ break;
+ case GL_FLOAT:
+ _unpacker = Unpack<GLfloat, 1, 1, 0>::unpack_l;
+ break;
+ default:
+ throw BadType(type());
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ switch (type()) {
+ case GL_BYTE:
+ _unpacker = Unpack<GLbyte, 2, 255, 1>::unpack_la;
+ break;
+ case GL_UNSIGNED_BYTE:
+ _unpacker = Unpack<GLubyte, 1, 255, 0>::unpack_la;
+ break;
+ case GL_SHORT:
+ _unpacker = Unpack<GLshort, 2, 65535, 1>::unpack_la;
+ break;
+ case GL_UNSIGNED_SHORT:
+ _unpacker = Unpack<GLushort, 1, 65535, 0>::unpack_la;
+ break;
+ case GL_INT:
+ _unpacker = Unpack<GLint, 2, 4294967295U, 1>::unpack_la;
+ break;
+ case GL_UNSIGNED_INT:
+ _unpacker = Unpack<GLuint, 2, 4294967295U, 0>::unpack_la;
+ break;
+ case GL_FLOAT:
+ _unpacker = Unpack<GLfloat, 1, 1, 0>::unpack_la;
+ break;
+ default:
+ throw BadType(type());
+ }
+ break;
+ case GL_RGB:
+ switch (type()) {
+ case GL_BYTE:
+ _unpacker = Unpack<GLbyte, 2, 255, 1>::unpack_rgb;
+ break;
+ case GL_UNSIGNED_BYTE:
+ _unpacker = Unpack<GLubyte, 1, 255, 0>::unpack_rgb;
+ break;
+ case GL_SHORT:
+ _unpacker = Unpack<GLshort, 2, 65535, 1>::unpack_rgb;
+ break;
+ case GL_UNSIGNED_SHORT:
+ _unpacker = Unpack<GLushort, 1, 65535, 0>::unpack_rgb;
+ break;
+ case GL_INT:
+ _unpacker = Unpack<GLint, 2, 4294967295U, 1>::unpack_rgb;
+ break;
+ case GL_UNSIGNED_INT:
+ _unpacker = Unpack<GLuint, 1, 4294967295U, 0>::unpack_rgb;
+ break;
+ case GL_FLOAT:
+ _unpacker = Unpack<GLfloat, 1, 1, 0>::unpack_rgb;
+ break;
+ default:
+ throw BadType(type());
+ }
+ break;
+ case GL_RGBA:
+ switch (type()) {
+ case GL_BYTE:
+ _unpacker = Unpack<GLbyte, 2, 255, 1>::unpack_rgba;
+ break;
+ case GL_UNSIGNED_BYTE:
+ _unpacker = Unpack<GLubyte, 1, 255, 0>::unpack_rgba;
+ break;
+ case GL_SHORT:
+ _unpacker = Unpack<GLshort, 2, 65535, 1>::unpack_rgba;
+ break;
+ case GL_UNSIGNED_SHORT:
+ _unpacker = Unpack<GLushort, 1, 65535, 0>::unpack_rgba;
+ break;
+ case GL_INT:
+ _unpacker = Unpack<GLint, 2, 4294967295U, 1>::unpack_rgba;
+ break;
+ case GL_UNSIGNED_INT:
+ _unpacker = Unpack<GLuint, 1, 4294967295U, 0>::unpack_rgba;
+ break;
+ case GL_FLOAT:
+ _unpacker = Unpack<GLfloat, 1, 1, 0>::unpack_rgba;
+ break;
+ default:
+ throw BadType(type());
+ }
+ break;
+ default:
+ throw BadFormat(format());
+ }
+
+ validate(vbUnpacker);
+ return _unpacker;
+}
+
+}; // namespace GLEAN
diff --git a/tests/glean/version.h b/tests/glean/version.h
new file mode 100644
index 00000000..c9706890
--- /dev/null
+++ b/tests/glean/version.h
@@ -0,0 +1,47 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// GLEAN version information
+
+
+#ifndef __version_h__
+#define __version_h__
+
+#define GLEAN_MAJOR_VERSION 1
+#define GLEAN_MINOR_VERSION 1
+
+namespace GLEAN {
+
+const char* versionString = "glean v1.1 20 January 2000";
+
+} // namespace GLEAN
+
+#endif // __version_h__
diff --git a/tests/glean/winsys.cpp b/tests/glean/winsys.cpp
new file mode 100644
index 00000000..e91b4eea
--- /dev/null
+++ b/tests/glean/winsys.cpp
@@ -0,0 +1,273 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// winsys.cpp: implementation of window-system services class
+
+using namespace std;
+
+#include <iostream>
+#include "options.h"
+#include "winsys.h"
+#include "dsconfig.h"
+#include "dsfilt.h"
+#include "dsurf.h"
+#include "rc.h"
+
+namespace GLEAN {
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors
+///////////////////////////////////////////////////////////////////////////////
+#if defined(__X11__)
+WindowSystem::WindowSystem(Options& o) {
+ // If running in "compare" mode we never actually use the window
+ // system, so we don't initialize it here. This allows us to run
+ // on systems without graphics hardware/software.
+ if (o.mode == Options::compare) {
+ dpy = 0;
+ GLXVersMajor = GLXVersMinor = 0;
+ vip = 0;
+ return;
+ }
+
+ // Open the X11 display:
+ dpy = XOpenDisplay(o.dpyName.c_str());
+ if (!dpy)
+ throw CantOpenDisplay();
+
+ // Verify that GLX is supported:
+ int error_base, event_base;
+ if (glXQueryExtension(dpy, &error_base, &event_base) == False)
+ throw NoOpenGL();
+
+ // Record version numbers for later use:
+ if (glXQueryVersion(dpy, &GLXVersMajor, &GLXVersMinor) == False)
+ throw Error(); // this should never happen :-)
+
+ // Get the list of raw XVisualInfo structures:
+ XVisualInfo vit;
+ vit.screen = DefaultScreen(dpy);
+ int n;
+ vip = XGetVisualInfo(dpy, VisualScreenMask, &vit, &n);
+
+ // Construct a vector of DrawingSurfaceConfigs corresponding to the
+ // XVisualInfo structures that indicate they support OpenGL:
+ vector<DrawingSurfaceConfig*> glxv;
+ for (int i = 0; i < n; ++i) {
+ int supportsOpenGL;
+ glXGetConfig(dpy, &vip[i], GLX_USE_GL, &supportsOpenGL);
+ if (supportsOpenGL)
+ glxv.push_back(new DrawingSurfaceConfig (dpy, &vip[i]));
+ }
+
+ // Filter the basic list of DrawingSurfaceConfigs according to
+ // constraints provided by the user. (This makes it convenient
+ // to run tests on just a subset of all available configs.)
+ DrawingSurfaceFilter f(o.visFilter); // may throw an exception!
+ surfConfigs = f.filter(glxv);
+} // WindowSystem::WindowSystem
+
+#elif defined(__WIN__)
+WindowSystem::WindowSystem(Options& o) {
+ // register an window class
+ WNDCLASS wc;
+
+ wc.style = CS_OWNDC;
+ wc.lpfnWndProc = Window::WindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(wc.hInstance, "glean");
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "glean";
+
+ if (!RegisterClass(&wc))
+ throw Error();
+
+
+ HDC hDC = GetDC(GetDesktopWindow());
+
+ PIXELFORMATDESCRIPTOR pfd;
+ int n = DescribePixelFormat(hDC,0,sizeof(pfd),0);
+
+ vector<DrawingSurfaceConfig*> glpf;
+
+ for (int i = 1;i <= n;++i) {
+ DescribePixelFormat(hDC,i,sizeof(pfd),&pfd);
+
+ glpf.push_back(new DrawingSurfaceConfig(i,&pfd));
+ }
+
+ ReleaseDC(GetDesktopWindow(),hDC);
+
+ // Filter the basic list of DrawingSurfaceConfigs according to
+ // constraints provided by the user. (This makes it convenient
+ // to run tests on just a subset of all available configs.)
+ DrawingSurfaceFilter f(o.visFilter); // may throw an exception!
+ surfConfigs = f.filter(glpf);
+}
+
+#elif defined(__BEWIN__)
+WindowSystem::WindowSystem(Options& o) {
+ //cout << "Implement Me! WindowSystem::WindowSystem(Options& o)\n";
+
+ theApp = new BApplication("application/x-AJH-glean");
+
+ /* for BeOS, we just stack the current config onto the vector so */
+ /* there is at least one thing to iterate over */
+ vector<DrawingSurfaceConfig*> glconfigs;
+ glconfigs.push_back(new DrawingSurfaceConfig());
+
+ DrawingSurfaceFilter f(o.visFilter); // may throw an exception!
+ surfConfigs = f.filter(glconfigs);
+
+}
+
+#elif defined(__AGL__)
+WindowSystem::WindowSystem(Options& o) {
+ GDHandle mainGD;
+ //HW/SW Depth Reserved
+ GLint testTypes[][3] = {
+ {AGL_ACCELERATED, 16, 0 },
+ {AGL_ACCELERATED, 16, 0 },
+ {AGL_ACCELERATED, 16, 0 },
+ {0, 16, 0 },
+ {0, 16, 0 },
+ {0, 0, 0 }
+ };
+ GLint testAttrib[][10]= {
+ { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_ACCELERATED, 16, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE},
+ { AGL_RGBA, AGL_ACCELERATED, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 16, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE},
+ { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE},
+ { AGL_RENDERER_ID, AGL_RENDERER_GENERIC_ID, AGL_RGBA, AGL_DOUBLEBUFFER, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE},
+ { AGL_RENDERER_ID, AGL_RENDERER_GENERIC_ID, AGL_RGBA, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 16 , AGL_NONE, AGL_NONE, AGL_NONE, AGL_NONE}
+ };
+ AGLPixelFormat pf;
+ GLint index = 0;
+
+ mainGD = GetMainDevice();
+ if (!mainGD)
+ throw CantOpenDisplay();
+
+ // Construct a vector of DrawingSurfaceConfigs corresponding to the
+ // returned pixel formats
+ vector<DrawingSurfaceConfig*> glpf;
+
+ while (testTypes[index][1] != 0)
+ {
+ pf = aglChoosePixelFormat(&mainGD, 1, testAttrib[index]);
+ if ( (pf == NULL) && ( testTypes[index][0] == 0) )
+ {
+ testAttrib[index][1] = 0x30300;
+ pf = aglChoosePixelFormat(&mainGD, 1, testAttrib[index]);
+ }
+ if (pf != NULL) glpf.push_back(new DrawingSurfaceConfig (index+1, pf));
+
+ index++;
+ }
+
+ // Filter the basic list of DrawingSurfaceConfigs according to
+ // constraints provided by the user. (This makes it convenient
+ // to run tests on just a subset of all available configs.)
+ DrawingSurfaceFilter f(o.visFilter); // may throw an exception!
+ surfConfigs = f.filter(glpf);
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Destructors
+///////////////////////////////////////////////////////////////////////////////
+#if defined(__X11__)
+WindowSystem::~WindowSystem() {
+ XFree(vip);
+} // WindowSystem:: ~WindowSystem
+
+#elif defined(__WIN__)
+WindowSystem::~WindowSystem() {
+}
+#elif defined(__BEWIN__)
+WindowSystem::~WindowSystem() {
+ delete theApp;
+} // WindowSystem:: ~WindowSystem
+#elif defined(__AGL__)
+WindowSystem::~WindowSystem() {
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// makeCurrent and friends - binding contexts and drawing surfaces
+///////////////////////////////////////////////////////////////////////////////
+
+bool
+WindowSystem::makeCurrent() {
+# if defined(__X11__)
+# if defined(GLX_VERSION_1_3)
+ // XXX Need to write GLX 1.3 MakeCurrent code
+# endif
+ return glXMakeCurrent(dpy, None, 0);
+# elif defined(__WIN__)
+ return wglMakeCurrent(0,0);
+# elif defined(__AGL__)
+ return aglSetCurrentContext(NULL);
+# endif
+} // WindowSystem::makeCurrent
+
+bool
+WindowSystem::makeCurrent(RenderingContext& r, Window& w) {
+# if defined(__X11__)
+# if defined(GLX_VERSION_1_3)
+ // XXX Need to write GLX 1.3 MakeCurrent code
+# endif
+ return glXMakeCurrent(dpy, w.xWindow, r.rc);
+# elif defined(__WIN__)
+ return wglMakeCurrent(w.get_dc(),r.rc);
+# elif defined(__AGL__)
+ if (GL_FALSE == aglSetDrawable(r.rc, (AGLDrawable) GetWindowPort (w.macWindow)))
+ return GL_FALSE;
+ if (GL_FALSE == aglSetCurrentContext(r.rc))
+ return GL_FALSE;
+ return true;
+# endif
+} // WindowSystem::makeCurrent
+
+void
+WindowSystem::quiesce() {
+# if defined(__X11__)
+ XSync(dpy, False);
+# elif defined(__WIN__)
+# endif
+} // WindowSystem::quiesce
+
+} // namespace GLEAN
diff --git a/tests/glean/winsys.h b/tests/glean/winsys.h
new file mode 100644
index 00000000..595fb64f
--- /dev/null
+++ b/tests/glean/winsys.h
@@ -0,0 +1,117 @@
+// BEGIN_COPYRIGHT -*- glean -*-
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// winsys.h: facade for common window-system operations
+
+// This class and related classes provide window system operations
+// that are sufficient to support most basic rendering tests. These
+// operations include initializing the window system, creating and
+// destroying windows and rendering contexts, selecting pixel
+// configurations, etc.
+
+// Tests using this set of classes for all window system services are
+// ``portable'' in a useful sense. Not all tests are portable,
+// however; in particular, tests of window-system-specific
+// functionality must execute window system commands directly. Such
+// tests may require access to class members that would ideally be
+// private; for example, the X11 Display pointer. Thus most members
+// of this class are public.
+
+
+
+#ifndef __winsys_h__
+#define __winsys_h__
+
+using namespace std;
+
+#include <string>
+#include <vector>
+#include "glwrap.h"
+
+namespace GLEAN {
+
+class DrawingSurface; // Forward and mutually-recursive references.
+class Window;
+class DrawingSurfaceConfig;
+class RenderingContext;
+class Options;
+
+class WindowSystem {
+ public:
+ // Constructors/Destructor:
+
+ WindowSystem(Options& o);
+ ~WindowSystem();
+
+ // Exceptions:
+
+ struct Error { }; // Base class for window system errors.
+ struct CantOpenDisplay: public Error { // Can't initialize display.
+ };
+ struct NoOpenGL: public Error { // Missing GLX, WGL, etc.
+ };
+
+ // Utilities:
+
+ bool makeCurrent(); // Remove context/surface binding.
+ bool makeCurrent(RenderingContext& r, Window& w);
+ // Bind given context and surface.
+ void quiesce(); // Wait for system to go idle.
+
+ // State information:
+
+ vector<DrawingSurfaceConfig*> surfConfigs;
+ // All available drawing surface configurations.
+ vector<DrawingSurface*> surfaces;
+ // All currently-active surfaces.
+ vector<RenderingContext*> contexts;
+ // All currently-active rendering contexts.
+
+# if defined(__X11__)
+ Display* dpy; // Pointer to X11 Display structure.
+
+ int GLXVersMajor; // GLX major version number.
+ int GLXVersMinor; // GLX minor version number.
+
+ XVisualInfo* vip; // Array of raw XVisualInfo structures.
+
+# elif defined(__WIN__)
+
+# elif defined(__BEWIN__)
+ BApplication *theApp;
+
+# endif
+
+}; // class WindowSystem
+
+} // namespace GLEAN
+
+#endif // __winsys_h__
diff --git a/tests/glean/wrtiff.cpp b/tests/glean/wrtiff.cpp
new file mode 100644
index 00000000..f4b95bac
--- /dev/null
+++ b/tests/glean/wrtiff.cpp
@@ -0,0 +1,134 @@
+// BEGIN_COPYRIGHT
+//
+// Copyright (C) 1999 Allen Akin All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// END_COPYRIGHT
+
+
+
+
+// Implementation of image data, attribute, and I/O
+
+#include "image.h"
+#include "tiffio.h"
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// writeTIFF - write image to TIFF file
+///////////////////////////////////////////////////////////////////////////////
+void
+Image::writeTIFF(const char* filename) {
+ static uint16 unassocAlpha[] = {EXTRASAMPLE_UNASSALPHA};
+ GLsizei rowStep = rowSizeInBytes();
+
+ TIFF* tf = TIFFOpen(filename, "w");
+ if (!tf)
+ throw CantOpen(filename);
+
+ TIFFSetField(tf, TIFFTAG_IMAGELENGTH, height());
+ TIFFSetField(tf, TIFFTAG_IMAGEWIDTH, width());
+ TIFFSetField(tf, TIFFTAG_XRESOLUTION, 100.0);
+ TIFFSetField(tf, TIFFTAG_YRESOLUTION, 100.0);
+ TIFFSetField(tf, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ TIFFSetField(tf, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tf, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tf, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ // LZW would have been acceptable, were it not for patent
+ // issues.
+ TIFFSetField(tf, TIFFTAG_ROWSPERSTRIP, height());
+
+ switch (format()) {
+ case GL_LUMINANCE:
+ TIFFSetField(tf, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(tf, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ TIFFSetField(tf, TIFFTAG_SAMPLESPERPIXEL, 2);
+ TIFFSetField(tf, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ TIFFSetField(tf, TIFFTAG_EXTRASAMPLES, 1, unassocAlpha);
+ break;
+ case GL_RGB:
+ TIFFSetField(tf, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tf, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ break;
+ case GL_RGBA:
+ TIFFSetField(tf, TIFFTAG_SAMPLESPERPIXEL, 4);
+ TIFFSetField(tf, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tf, TIFFTAG_EXTRASAMPLES, 1, unassocAlpha);
+ break;
+ default:
+ TIFFClose(tf);
+ throw BadFormat(format());
+ }
+
+ switch (type()) {
+ case GL_BYTE:
+ TIFFSetField(tf, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tf, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
+ break;
+ case GL_UNSIGNED_BYTE:
+ TIFFSetField(tf, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tf, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ break;
+ case GL_SHORT:
+ TIFFSetField(tf, TIFFTAG_BITSPERSAMPLE, 16);
+ TIFFSetField(tf, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
+ break;
+ case GL_UNSIGNED_SHORT:
+ TIFFSetField(tf, TIFFTAG_BITSPERSAMPLE, 16);
+ TIFFSetField(tf, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ break;
+ case GL_INT:
+ TIFFSetField(tf, TIFFTAG_BITSPERSAMPLE, 32);
+ TIFFSetField(tf, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
+ break;
+ case GL_UNSIGNED_INT:
+ TIFFSetField(tf, TIFFTAG_BITSPERSAMPLE, 32);
+ TIFFSetField(tf, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ break;
+ case GL_FLOAT:
+ TIFFSetField(tf, TIFFTAG_BITSPERSAMPLE, 32);
+ TIFFSetField(tf, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
+ break;
+ default:
+ TIFFClose(tf);
+ throw BadType(type());
+ }
+
+ {
+ // Write rows in reverse order, so that the usual OpenGL
+ // orientation won't result in an upside-down image for
+ // naive TIFF readers:
+ char* row = pixels() + (height() - 1) * rowStep;
+ for (GLsizei r = 0; r < height(); ++r, row -= rowStep)
+ TIFFWriteScanline(tf, row, r, 0);
+ }
+
+ TIFFClose(tf);
+}; // Image::writeTIFF
+
+
+}; // namespace GLEAN
diff --git a/tests/mesa/CMakeLists.txt b/tests/mesa/CMakeLists.txt
new file mode 100644
index 00000000..56731284
--- /dev/null
+++ b/tests/mesa/CMakeLists.txt
@@ -0,0 +1,3 @@
+
+add_subdirectory (util)
+add_subdirectory (tests)
diff --git a/tests/mesa/tests/CMakeLists.txt b/tests/mesa/tests/CMakeLists.txt
new file mode 100644
index 00000000..fee398f2
--- /dev/null
+++ b/tests/mesa/tests/CMakeLists.txt
@@ -0,0 +1,23 @@
+
+#add_definitions ( -D__X11__ -D__UNIX__ )
+
+include_directories(
+ ${OPENGL_INCLUDE_PATH}
+ ${GLUT_INCLUDE_DIR}
+ ${piglit_SOURCE_DIR}/tests/mesa/util
+)
+
+link_directories (
+ ${piglit_SOURCE_DIR}/tests/mesa/util
+)
+
+link_libraries (
+ ${OPENGL_gl_LIBRARY}
+ ${OPENGL_glu_LIBRARY}
+ ${GLUT_glut_LIBRARY}
+ ${TIFF_LIBRARY}
+ mesautil
+)
+
+add_executable (crossbar crossbar.c)
+#add_executable (arbfptest1 arbfptest1.c)
diff --git a/tests/mesa/tests/afsmultiarb.c b/tests/mesa/tests/afsmultiarb.c
new file mode 100644
index 00000000..c026ecd4
--- /dev/null
+++ b/tests/mesa/tests/afsmultiarb.c
@@ -0,0 +1,469 @@
+/*
+ * GL_ATI_fragment_shader test
+ * Roland Scheidegger
+ *
+ * Command line options:
+ * -info print GL implementation information
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+#include "readtex.h"
+
+#define TEXTURE_1_FILE "../images/girl.rgb"
+#define TEXTURE_2_FILE "../images/reflect.rgb"
+
+#define TEX0 1
+#define TEX7 8
+#define ANIMATE 10
+#define SHADER 20
+#define QUIT 100
+
+static GLboolean Animate = GL_TRUE;
+static GLint NumUnits = 6;
+static GLboolean TexEnabled[8];
+static GLuint boringshaderID = 0;
+static GLuint boring2passID = 0;
+static GLboolean Shader = GL_FALSE;
+
+static GLfloat Drift = 0.0;
+static GLfloat drift_increment = 0.005;
+static GLfloat Xrot = 20.0, Yrot = 30.0, Zrot = 0.0;
+static GLfloat shaderconstant[4] = {0.5, 0.0, 0.0, 0.0};
+
+static void Idle( void )
+{
+ if (Animate) {
+ GLint i;
+
+ Drift += drift_increment;
+ if (Drift >= 1.0)
+ Drift = 0.0;
+
+ for (i = 0; i < NumUnits; i++) {
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ if (i == 0) {
+ glTranslatef(Drift, 0.0, 0.0);
+ glScalef(2, 2, 1);
+ }
+ else if (i == 1) {
+ glTranslatef(0.0, Drift, 0.0);
+ }
+ else {
+ glTranslatef(0.5, 0.5, 0.0);
+ glRotatef(180.0 * Drift, 0, 0, 1);
+ glScalef(1.0/i, 1.0/i, 1.0/i);
+ glTranslatef(-0.5, -0.5, 0.0);
+ }
+ }
+ glMatrixMode(GL_MODELVIEW);
+
+ glutPostRedisplay();
+ }
+}
+
+
+static void DrawObject(void)
+{
+ GLint i;
+ GLint j;
+ static const GLfloat tex_coords[] = { 0.0, 0.0, 1.0, 1.0, 0.0 };
+ static const GLfloat vtx_coords[] = { -1.0, -1.0, 1.0, 1.0, -1.0 };
+
+ if (!TexEnabled[0] && !TexEnabled[1])
+ glColor3f(0.1, 0.1, 0.1); /* add onto this */
+ else
+ glColor3f(1, 1, 1); /* modulate this */
+
+ glBegin(GL_QUADS);
+
+ /* Toggle between the vector and scalar entry points. This is done purely
+ * to hit multiple paths in the driver.
+ */
+ if ( Drift > 0.49 ) {
+ for (j = 0; j < 4; j++ ) {
+ for (i = 0; i < NumUnits; i++)
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB + i,
+ tex_coords[j], tex_coords[j+1]);
+ glVertex2f( vtx_coords[j], vtx_coords[j+1] );
+ }
+ }
+ else {
+ for (j = 0; j < 4; j++ ) {
+ for (i = 0; i < NumUnits; i++)
+ glMultiTexCoord2fvARB(GL_TEXTURE0_ARB + i, & tex_coords[j]);
+ glVertex2fv( & vtx_coords[j] );
+ }
+ }
+
+ glEnd();
+}
+
+
+
+static void Display( void )
+{
+ static GLint T0 = 0;
+ static GLint Frames = 0;
+ GLint t;
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ glScalef(5.0, 5.0, 5.0);
+ DrawObject();
+ glPopMatrix();
+
+ glutSwapBuffers();
+
+ Frames++;
+
+ t = glutGet(GLUT_ELAPSED_TIME);
+ if (t - T0 >= 2500) {
+ GLfloat seconds = (t - T0) / 1000.0;
+ GLfloat fps = Frames / seconds;
+ drift_increment = 2.2 * seconds / Frames;
+ printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps);
+ T0 = t;
+ Frames = 0;
+ }
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
+ /*glOrtho( -6.0, 6.0, -6.0, 6.0, 10.0, 100.0 );*/
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -70.0 );
+}
+
+
+static void ModeMenu(int entry)
+{
+ if (entry >= TEX0 && entry <= TEX7) {
+ /* toggle */
+ GLint i = entry - TEX0;
+ TexEnabled[i] = !TexEnabled[i];
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ if (TexEnabled[i])
+ glEnable(GL_TEXTURE_2D);
+ else
+ glDisable(GL_TEXTURE_2D);
+ printf("Enabled: ");
+ for (i = 0; i < NumUnits; i++)
+ printf("%d ", (int) TexEnabled[i]);
+ printf("\n");
+ }
+ else if (entry==ANIMATE) {
+ Animate = !Animate;
+ }
+ else if (entry==SHADER) {
+ Shader = !Shader;
+ if (Shader) {
+ fprintf(stderr, "using 2-pass shader\n");
+ glBindFragmentShaderATI(boring2passID);
+ }
+ else {
+ fprintf(stderr, "using 1-pass shader\n");
+ glBindFragmentShaderATI(boringshaderID);
+ }
+ }
+ else if (entry==QUIT) {
+ exit(0);
+ }
+
+ glutPostRedisplay();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( int argc, char *argv[] )
+{
+ GLuint texObj[8];
+ GLint size, i;
+
+ const char *exten = (const char *) glGetString(GL_EXTENSIONS);
+ if (!strstr(exten, "GL_ATI_fragment_shader")) {
+ printf("Sorry, GL_ATI_fragment_shader not supported by this renderer.\n");
+ exit(1);
+ }
+
+
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
+ printf("%d x %d max texture size\n", size, size);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ for (i = 0; i < NumUnits; i++) {
+ if (i < 6)
+ TexEnabled[i] = GL_TRUE;
+ else
+ TexEnabled[i] = GL_FALSE;
+ }
+
+ /* allocate two texture objects */
+ glGenTextures(NumUnits, texObj);
+
+ /* setup the texture objects */
+ for (i = 0; i < NumUnits; i++) {
+
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ glBindTexture(GL_TEXTURE_2D, texObj[i]);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ if (i == 0) {
+ if (!LoadRGBMipmaps(TEXTURE_1_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image\n");
+ exit(1);
+ }
+ }
+ else if (i == 1) {
+ if (!LoadRGBMipmaps(TEXTURE_2_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image\n");
+ exit(1);
+ }
+ }
+ else {
+ /* checker */
+ GLubyte image[8][8][3];
+ GLint i, j;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ if ((i + j) & 1) {
+ image[i][j][0] = 50;
+ image[i][j][1] = 50;
+ image[i][j][2] = 50;
+ }
+ else {
+ image[i][j][0] = 25;
+ image[i][j][1] = 25;
+ image[i][j][2] = 25;
+ }
+ }
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *) image);
+ }
+
+ /* Bind texObj[i] to ith texture unit */
+/* if (i < 2)
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ else
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);*/
+
+ if (TexEnabled[i])
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ boringshaderID = glGenFragmentShadersATI(1);
+ boring2passID = glGenFragmentShadersATI(1);
+ if (boring2passID == 0)
+ {
+ fprintf(stderr, "couldn't get frag shader id\n");
+ exit(1);
+ }
+ glBindFragmentShaderATI(boringshaderID);
+/* maybe not the most creative shader but at least I know how it should look like! */
+ glBeginFragmentShaderATI();
+ glSampleMapATI(GL_REG_0_ATI, GL_TEXTURE0_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_1_ATI, GL_TEXTURE1_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_2_ATI, GL_TEXTURE2_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_3_ATI, GL_TEXTURE3_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_4_ATI, GL_TEXTURE4_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_5_ATI, GL_TEXTURE5_ARB, GL_SWIZZLE_STR_ATI);
+ glColorFragmentOp2ATI(GL_MUL_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_PRIMARY_COLOR, GL_NONE, GL_NONE);
+ glAlphaFragmentOp1ATI(GL_MOV_ATI,
+ GL_REG_0_ATI, GL_NONE,
+ GL_PRIMARY_COLOR, GL_NONE, GL_NONE);
+ glColorFragmentOp3ATI(GL_MAD_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_REG_1_ATI, GL_NONE, GL_NONE,
+ GL_REG_2_ATI, GL_NONE, GL_NONE);
+ glColorFragmentOp2ATI(GL_ADD_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_REG_3_ATI, GL_NONE, GL_NONE);
+ glColorFragmentOp2ATI(GL_ADD_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_REG_4_ATI, GL_NONE, GL_NONE);
+ glColorFragmentOp2ATI(GL_ADD_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_REG_5_ATI, GL_NONE, GL_NONE);
+ glEndFragmentShaderATI();
+
+/* mathematically equivalent to first shader but using 2 passes together with
+ some tex coord rerouting */
+ glBindFragmentShaderATI(boring2passID);
+ glBeginFragmentShaderATI();
+ glPassTexCoordATI(GL_REG_1_ATI, GL_TEXTURE0_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_2_ATI, GL_TEXTURE2_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_3_ATI, GL_TEXTURE3_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_4_ATI, GL_TEXTURE4_ARB, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_5_ATI, GL_TEXTURE5_ARB, GL_SWIZZLE_STR_ATI);
+ glColorFragmentOp2ATI(GL_ADD_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_2_ATI, GL_NONE, GL_NONE,
+ GL_REG_3_ATI, GL_NONE, GL_NONE);
+ glColorFragmentOp2ATI(GL_ADD_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_REG_4_ATI, GL_NONE, GL_NONE);
+ glColorFragmentOp2ATI(GL_ADD_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_REG_5_ATI, GL_NONE, GL_NONE);
+ /* not really a dependant read */
+ glSampleMapATI(GL_REG_0_ATI, GL_REG_1_ATI, GL_SWIZZLE_STR_ATI);
+ glSampleMapATI(GL_REG_1_ATI, GL_TEXTURE1_ARB, GL_SWIZZLE_STR_ATI);
+ glPassTexCoordATI(GL_REG_5_ATI, GL_REG_0_ATI, GL_SWIZZLE_STR_ATI);
+ glColorFragmentOp2ATI(GL_MUL_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_PRIMARY_COLOR, GL_NONE, GL_NONE);
+ glAlphaFragmentOp1ATI(GL_MOV_ATI,
+ GL_REG_0_ATI, GL_NONE,
+ GL_PRIMARY_COLOR, GL_NONE, GL_NONE);
+ glColorFragmentOp3ATI(GL_MAD_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_REG_1_ATI, GL_NONE, GL_NONE,
+ GL_REG_5_ATI, GL_NONE, GL_NONE);
+ /* in principle we're finished here, but to test a bit more
+ we do some fun with dot ops, replication et al. */
+ glSetFragmentShaderConstantATI(GL_CON_3_ATI, shaderconstant);
+ glColorFragmentOp2ATI(GL_DOT4_ATI,
+ GL_REG_3_ATI, GL_GREEN_BIT_ATI, GL_EIGHTH_BIT_ATI,
+ GL_ZERO, GL_NONE, GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI,
+ GL_CON_3_ATI, GL_RED, GL_2X_BIT_ATI);
+ /* those args must get ignored, except dstReg */
+ glAlphaFragmentOp2ATI(GL_DOT4_ATI,
+ GL_REG_4_ATI, GL_NONE,
+ GL_ZERO, GL_NONE, GL_NONE,
+ GL_ZERO, GL_NONE, GL_NONE);
+ /* -> reg3 g = reg4 alpha = -0.5 */
+ glAlphaFragmentOp2ATI(GL_ADD_ATI,
+ GL_REG_5_ATI, GL_NONE,
+ GL_REG_3_ATI, GL_GREEN, GL_NONE,
+ GL_REG_4_ATI, GL_NONE, GL_NONE);
+ /* -> reg5 a = -1 */
+ glColorFragmentOp3ATI(GL_DOT2_ADD_ATI,
+ GL_REG_4_ATI, GL_BLUE_BIT_ATI, GL_HALF_BIT_ATI,
+ GL_REG_5_ATI, GL_ALPHA, GL_NEGATE_BIT_ATI,
+ GL_ONE, GL_NONE, GL_BIAS_BIT_ATI,
+ GL_ONE, GL_ALPHA, GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI);
+ /* -> reg 4 b = -0.5 */
+ glColorFragmentOp2ATI(GL_MUL_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE,
+ GL_REG_4_ATI, GL_BLUE, GL_NEGATE_BIT_ATI | GL_2X_BIT_ATI,
+ GL_REG_0_ATI, GL_NONE, GL_NONE);
+ glEndFragmentShaderATI();
+
+ glBindFragmentShaderATI(boringshaderID);
+ glEnable(GL_FRAGMENT_SHADER_ATI);
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.3, 0.3, 0.4, 1.0);
+
+ if (argc > 1 && strcmp(argv[1], "-info")==0) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+ printf("output should be identical with both shaders to multiarb demo when 6 textures are enabled\n");
+}
+
+
+int main( int argc, char *argv[] )
+{
+/* GLint i;*/
+
+ glutInit( &argc, argv );
+ glutInitWindowSize( 300, 300 );
+ glutInitWindowPosition( 0, 0 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0] );
+
+ Init( argc, argv );
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ glutIdleFunc( Idle );
+
+ glutCreateMenu(ModeMenu);
+
+/* for (i = 0; i < NumUnits; i++) {
+ char s[100];
+ sprintf(s, "Toggle Texture %d", i);
+ glutAddMenuEntry(s, TEX0 + i);
+ }*/
+ glutAddMenuEntry("Toggle 1/2 Pass Shader", SHADER);
+ glutAddMenuEntry("Toggle Animation", ANIMATE);
+ glutAddMenuEntry("Quit", QUIT);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/antialias.c b/tests/mesa/tests/antialias.c
new file mode 100644
index 00000000..79b5ab75
--- /dev/null
+++ b/tests/mesa/tests/antialias.c
@@ -0,0 +1,229 @@
+/* $Id: antialias.c,v 1.2 2003/03/29 16:42:57 brianp Exp $ */
+
+/*
+ * Test multisampling and polygon smoothing.
+ *
+ * Brian Paul
+ * 4 November 2002
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+static GLfloat Zrot = 0;
+static GLboolean Anim = GL_TRUE;
+static GLboolean HaveMultisample = GL_TRUE;
+
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static void
+Polygon( GLint verts, GLfloat radius, GLfloat z )
+{
+ int i;
+ for (i = 0; i < verts; i++) {
+ float a = (i * 2.0 * 3.14159) / verts;
+ float x = radius * cos(a);
+ float y = radius * sin(a);
+ glVertex3f(x, y, z);
+ }
+}
+
+
+static void
+DrawObject( void )
+{
+ glLineWidth(3.0);
+ glColor3f(1, 1, 1);
+ glBegin(GL_LINE_LOOP);
+ Polygon(12, 1.2, 0);
+ glEnd();
+
+ glLineWidth(1.0);
+ glColor3f(1, 1, 1);
+ glBegin(GL_LINE_LOOP);
+ Polygon(12, 1.1, 0);
+ glEnd();
+
+ glColor3f(1, 0, 0);
+ glBegin(GL_POLYGON);
+ Polygon(12, 0.4, 0.3);
+ glEnd();
+
+ glColor3f(0, 1, 0);
+ glBegin(GL_POLYGON);
+ Polygon(12, 0.6, 0.2);
+ glEnd();
+
+ glColor3f(0, 0, 1);
+ glBegin(GL_POLYGON);
+ Polygon(12, 0.8, 0.1);
+ glEnd();
+
+ glColor3f(1, 1, 1);
+ glBegin(GL_POLYGON);
+ Polygon(12, 1.0, 0);
+ glEnd();
+}
+
+
+static void
+Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glColor3f(1, 1, 1);
+ if (HaveMultisample) {
+ glRasterPos2f(-3.1, -1.6);
+ PrintString("MULTISAMPLE");
+ }
+ glRasterPos2f(-0.8, -1.6);
+ PrintString("No antialiasing");
+ glRasterPos2f(1.6, -1.6);
+ PrintString("GL_POLYGON_SMOOTH");
+
+ /* multisample */
+ if (HaveMultisample) {
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_MULTISAMPLE_ARB);
+ glPushMatrix();
+ glTranslatef(-2.5, 0, 0);
+ glPushMatrix();
+ glRotatef(Zrot, 0, 0, 1);
+ DrawObject();
+ glPopMatrix();
+ glPopMatrix();
+ glDisable(GL_MULTISAMPLE_ARB);
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ /* non-aa */
+ glEnable(GL_DEPTH_TEST);
+ glPushMatrix();
+ glTranslatef(0, 0, 0);
+ glPushMatrix();
+ glRotatef(Zrot, 0, 0, 1);
+ DrawObject();
+ glPopMatrix();
+ glPopMatrix();
+ glDisable(GL_DEPTH_TEST);
+
+ /* polygon smooth */
+ glEnable(GL_POLYGON_SMOOTH);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glPushMatrix();
+ glTranslatef(2.5, 0, 0);
+ glPushMatrix();
+ glRotatef(Zrot, 0, 0, 1);
+ DrawObject();
+ glPopMatrix();
+ glPopMatrix();
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_POLYGON_SMOOTH);
+ glDisable(GL_BLEND);
+
+ glutSwapBuffers();
+}
+
+
+static void
+Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho(-2.0*ar, 2.0*ar, -2.0, 2.0, -1.0, 1.0);
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+static void
+Idle( void )
+{
+ Zrot = 0.01 * glutGet(GLUT_ELAPSED_TIME);
+ glutPostRedisplay();
+}
+
+
+static void
+Key( unsigned char key, int x, int y )
+{
+ const GLfloat step = 1.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'z':
+ Zrot = (int) (Zrot - step);
+ break;
+ case 'Z':
+ Zrot = (int) (Zrot + step);
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init( void )
+{
+ /* GLUT imposes the four samples/pixel requirement */
+ int s;
+ glGetIntegerv(GL_SAMPLES_ARB, &s);
+ if (!glutExtensionSupported("GL_ARB_multisample") || s < 1) {
+ printf("Warning: multisample antialiasing not supported.\n");
+ HaveMultisample = GL_FALSE;
+ }
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_SAMPLES_ARB = %d\n", s);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
+
+ glGetIntegerv(GL_MULTISAMPLE_ARB, &s);
+ printf("GL_MULTISAMPLE_ARB = %d\n", s);
+}
+
+
+int
+main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 600, 300 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE |
+ GLUT_DEPTH | GLUT_MULTISAMPLE );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc( Idle );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/api_speed.c b/tests/mesa/tests/api_speed.c
new file mode 100644
index 00000000..aed65b35
--- /dev/null
+++ b/tests/mesa/tests/api_speed.c
@@ -0,0 +1,146 @@
+/*
+ * (C) Copyright IBM Corporation 2002
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file api_speed.c
+ * Simple test to measure the overhead of making GL calls.
+ *
+ * The main purpose of this test is to measure the difference in calling
+ * overhead of different dispatch methods. Since it uses asm/timex.h to
+ * access the Pentium's cycle counters, it will probably only compile on
+ * Linux (though most architectures have a get_cycles function in timex.h).
+ * That is why it isn't in the default Makefile.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glut.h>
+
+#define inline __inline__
+#include <asm/timex.h>
+
+static float Width = 400;
+static float Height = 400;
+static unsigned count = 1000000;
+
+
+static void Idle( void )
+{
+ glutPostRedisplay();
+}
+
+#define DO_FUNC(f,p) \
+ do { \
+ t0 = get_cycles(); \
+ for ( i = 0 ; i < count ; i++ ) { \
+ f p ; \
+ } \
+ t1 = get_cycles(); \
+ printf("%u calls to % 20s required %llu cycles.\n", count, # f, t1 - t0); \
+ } while( 0 )
+
+/**
+ * Main display function. This is the place to add more API calls.
+ */
+static void Display( void )
+{
+ int i;
+ const float v[3] = { 1.0, 0.0, 0.0 };
+ cycles_t t0;
+ cycles_t t1;
+
+ glBegin(GL_TRIANGLE_STRIP);
+
+ DO_FUNC( glColor3fv, (v) );
+ DO_FUNC( glNormal3fv, (v) );
+ DO_FUNC( glTexCoord2fv, (v) );
+ DO_FUNC( glTexCoord3fv, (v) );
+ DO_FUNC( glMultiTexCoord2fv, (GL_TEXTURE0, v) );
+ DO_FUNC( glMultiTexCoord2f, (GL_TEXTURE0, 0.0, 0.0) );
+ DO_FUNC( glFogCoordfvEXT, (v) );
+ DO_FUNC( glFogCoordfEXT, (0.5) );
+
+ glEnd();
+
+ exit(0);
+}
+
+
+static void Reshape( int width, int height )
+{
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho(0.0, width, 0.0, height, -1.0, 1.0);
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowSize( (int) Width, (int) Height );
+ glutInitWindowPosition( 0, 0 );
+
+ glutInitDisplayMode( GLUT_RGB );
+
+ glutCreateWindow( argv[0] );
+
+ if ( argc > 1 ) {
+ count = strtoul( argv[1], NULL, 0 );
+ if ( count == 0 ) {
+ fprintf( stderr, "Usage: %s [iterations]\n", argv[0] );
+ exit(1);
+ }
+ }
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ glutIdleFunc( Idle );
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbfpspec.c b/tests/mesa/tests/arbfpspec.c
new file mode 100644
index 00000000..eac2a910
--- /dev/null
+++ b/tests/mesa/tests/arbfpspec.c
@@ -0,0 +1,192 @@
+/*
+ * To demo that specular color gets lost someplace after vertex
+ * program completion and fragment program startup
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Xrot = 0.0, Yrot = 0.0, Zrot = 0.0;
+static GLboolean Anim = GL_TRUE;
+
+
+static void Idle( void )
+{
+ Xrot += .3;
+ Yrot += .4;
+ Zrot += .2;
+ glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+ glutSolidTorus(0.75, 2.0, 10, 20);
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -12.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case ' ':
+ Xrot = Yrot = Zrot = 0;
+ break;
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'z':
+ Zrot -= 5.0;
+ break;
+ case 'Z':
+ Zrot += 5.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ GLint errno;
+ GLuint prognum, fprognum;
+
+ static const char prog[] =
+ "!!ARBvp1.0\n"
+ "DP4 result.position.x, state.matrix.mvp.row[0], vertex.position ;\n"
+ "DP4 result.position.y, state.matrix.mvp.row[1], vertex.position ;\n"
+ "DP4 result.position.z, state.matrix.mvp.row[2], vertex.position ;\n"
+ "DP4 result.position.w, state.matrix.mvp.row[3], vertex.position ;\n"
+ "MOV result.color.front.primary, {.5, .5, .5, 1};\n"
+ "MOV result.color.front.secondary, {1, 1, 1, 1};\n"
+ "END";
+
+ static const char fprog[] =
+ "!!ARBfp1.0\n"
+ "MOV result.color, fragment.color.secondary;\n"
+ "END";
+
+ if (!glutExtensionSupported("GL_ARB_vertex_program")) {
+ printf("Sorry, this program requires GL_ARB_vertex_program");
+ exit(1);
+ }
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ printf("Sorry, this program requires GL_ARB_fragment_program");
+ exit(1);
+ }
+
+ glGenProgramsARB(1, &prognum);
+ glGenProgramsARB(1, &fprognum);
+
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+ glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(prog), (const GLubyte *) prog);
+
+ assert(glIsProgramARB(prognum));
+ errno = glGetError();
+ printf("glGetError = %d\n", errno);
+ if (errno != GL_NO_ERROR)
+ {
+ GLint errorpos;
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+ printf("errorpos: %d\n", errorpos);
+ printf("%s\n", (char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ }
+
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fprognum);
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(fprog), (const GLubyte *) fprog);
+ errno = glGetError();
+ printf("glGetError = %d\n", errno);
+ if (errno != GL_NO_ERROR)
+ {
+ GLint errorpos;
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+ printf("errorpos: %d\n", errorpos);
+ printf("%s\n", (char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ }
+
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ glEnable(GL_DEPTH_TEST);
+ glClearColor(0.3, 0.3, 0.3, 1);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbfptest1.c b/tests/mesa/tests/arbfptest1.c
new file mode 100644
index 00000000..7949f87e
--- /dev/null
+++ b/tests/mesa/tests/arbfptest1.c
@@ -0,0 +1,210 @@
+/* Test GL_ARB_fragment_program */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+
+ glColor4f(0, 0.5, 0, 1);
+ glColor4f(0, 1, 0, 1);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 0, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+static void load_program(const char *prog, GLuint prognum)
+{
+ int a;
+ GLint errorpos, errno;
+
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prognum);
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(prog), (const GLubyte *) prog);
+
+ assert(glIsProgramARB(prognum));
+ errno = glGetError();
+ printf("glGetError = %d\n", errno);
+ if (errno != GL_NO_ERROR)
+ {
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+ printf("errorpos: %d\n", errorpos);
+ printf("%s\n", (char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+
+ for (a=-10; a<10; a++)
+ {
+ if ((errorpos+a < 0) || (errorpos+a >= strlen(prog))) continue;
+ printf("%c", prog[errorpos+a]);
+ }
+ printf("\n");
+ exit(1);
+ }
+}
+
+static void Init( void )
+{
+ static const char *prog0 =
+ "!!ARBfp1.0\n"
+ "TEMP R0, RC, HC, H0, H1, H2, H3, H30 ;\n"
+ "MUL result.color, R0, fragment.position; \n"
+ "ADD result.color, H3, fragment.texcoord; \n"
+ "ADD_SAT result.color, H3, fragment.texcoord; \n"
+ "MUL result.color.xy, R0.wzyx, fragment.position; \n"
+ "MUL result.color, H0, fragment.position; \n"
+ "MUL result.color, -H0, fragment.position; \n"
+ "MOV RC, H1; \n"
+ "MOV HC, H2; \n"
+ "END \n"
+ ;
+ /* masked updates, defines, declarations */
+ static const char *prog1 =
+ "!!ARBfp1.0\n"
+ "PARAM foo = {1., 2., 3., 4.}; \n"
+ "PARAM foo2 = 5.; \n"
+ "PARAM foo3 = {5., 6., 7., 8.}; \n"
+ "PARAM bar = 3.; \n"
+ "TEMP R0, R1, RC, EQ, NE, bar2; \n"
+ "ALIAS bar3 = bar; \n"
+ "MOV result.color.xy, R0; \n"
+ "MOV result.color, R0; \n"
+ "MOV result.color.xyzw, R0; \n"
+ "MOV result.color.xy, R0; \n"
+ "MOV RC.x, R1.x; \n"
+ "KIL NE; \n"
+ "KIL EQ.xyxy; \n"
+ "END \n"
+ ;
+
+ /* texture instructions */
+ static const char *prog2 =
+ "!!ARBfp1.0\n"
+ "TEMP R0, R1, R2, R3;\n"
+ "TEX R0, fragment.texcoord, texture[0], 2D; \n"
+ "TEX R1, fragment.texcoord[1], texture[1], CUBE; \n"
+ "TEX R2, fragment.texcoord[2], texture[2], 3D; \n"
+ "TXP R3, fragment.texcoord[3], texture[3], RECT; \n"
+ "MUL result.color, R0, fragment.color; \n"
+ "END \n"
+ ;
+
+ /* test negation, absolute value */
+ static const char *prog3 =
+ "!!ARBfp1.0\n"
+ "TEMP R0, R1;\n"
+ "MOV R0, R1; \n"
+ "MOV R0, -R1; \n"
+ "MOV result.color, R0; \n"
+ "END \n"
+ ;
+
+ /* literal constant sources */
+ static const char *prog4 =
+ "!!ARBfp1.0\n"
+ "TEMP R0, R1;\n"
+ "PARAM Pi = 3.14159; \n"
+ "MOV R0, {1., -2., +3., 4.}; \n"
+ "MOV R0, 5.; \n"
+ "MOV R0, -5.; \n"
+ "MOV R0, 5.; \n"
+ "MOV R0, Pi; \n"
+ "MOV result.color, R0; \n"
+ "END \n"
+ ;
+
+ /* change the fragment color in a simple way */
+ static const char *prog10 =
+ "!!ARBfp1.0\n"
+ "PARAM blue = {0., 0., 1., 0.};\n"
+ "PARAM color = {1., 0., 0., 1.};\n"
+ "TEMP R0; \n"
+ "MOV R0, fragment.color; \n"
+ "#ADD result.color, R0, fragment.color; \n"
+ "#ADD result.color, blue, fragment.color; \n"
+ "#ADD result.color, {1., 0., 0., 0.}, fragment.color; \n"
+ "ADD result.color, color, fragment.color; \n"
+ "END \n"
+ ;
+
+ GLuint progs[20];
+
+ glGenProgramsARB(20, progs);
+ assert(progs[0]);
+ assert(progs[1]);
+ assert(progs[0] != progs[1]);
+
+
+ printf("program 0:\n");
+ load_program(prog0, progs[0]);
+ printf("program 1:\n");
+ load_program(prog1, progs[1]);
+ printf("program 2:\n");
+ load_program(prog2, progs[2]);
+ printf("program 3:\n");
+ load_program(prog3, progs[3]);
+ printf("program 4:\n");
+ load_program(prog4, progs[4]);
+ printf("program 10:\n");
+ load_program(prog10, progs[5]);
+
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(GL_ALWAYS, 0.0);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbfptexture.c b/tests/mesa/tests/arbfptexture.c
new file mode 100644
index 00000000..a854908c
--- /dev/null
+++ b/tests/mesa/tests/arbfptexture.c
@@ -0,0 +1,153 @@
+/* GL_ARB_fragment_program texture test */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+#include "readtex.c"
+
+
+#define TEXTURE_FILE "../images/girl.rgb"
+
+static GLfloat Xrot = 0.0, Yrot = 0.0, Zrot = 0.0;
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+
+ glBegin(GL_POLYGON);
+#define Q 2
+ glColor4f(1.0, 1.0, 1.0, 1); glTexCoord4f(0, 0, 0, Q); glVertex2f(-1, -1);
+ glColor4f(0.2, 0.2, 1.0, 1); glTexCoord4f(1, 0, 0, Q); glVertex2f( 1, -1);
+ glColor4f(0.2, 1.0, 0.2, 1); glTexCoord4f(1, 1, 0, Q); glVertex2f( 1, 1);
+ glColor4f(1.0, 0.2, 0.2, 1); glTexCoord4f(0, 1, 0, Q); glVertex2f(-1, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -8.0 );
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ static const char *modulate2D =
+ "!!ARBfp1.0\n"
+ "TEMP R0;\n"
+ "TEX R0, fragment.texcoord[0], texture[0], 2D; \n"
+ "MUL result.color, R0, fragment.color; \n"
+ "END"
+ ;
+ GLuint modulateProg;
+ GLuint Texture;
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ printf("Error: GL_ARB_fragment_program not supported!\n");
+ exit(1);
+ }
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ /* Setup the fragment program */
+ glGenProgramsARB(1, &modulateProg);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, modulateProg);
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(modulate2D), (const GLubyte *)modulate2D);
+
+ printf("glGetError = 0x%x\n", (int) glGetError());
+ printf("glError(GL_PROGRAM_ERROR_STRING_ARB) = %s\n",
+ (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ assert(glIsProgramARB(modulateProg));
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ /* Load texture */
+ glGenTextures(1, &Texture);
+ glBindTexture(GL_TEXTURE_2D, Texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
+ exit(1);
+ }
+ /* XXX this enable shouldn't really be needed!!! */
+ glEnable(GL_TEXTURE_2D);
+
+ glClearColor(.3, .3, .3, 0);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbfptrig.c b/tests/mesa/tests/arbfptrig.c
new file mode 100644
index 00000000..26b68c6b
--- /dev/null
+++ b/tests/mesa/tests/arbfptrig.c
@@ -0,0 +1,156 @@
+/* GL_ARB_fragment_program texture test */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+#include "readtex.c"
+
+
+#define TEXTURE_FILE "../images/girl.rgb"
+
+static GLfloat Xrot = 0.0, Yrot = 0.0, Zrot = 0.0;
+
+#define PI 3.141592
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+
+ glBegin(GL_POLYGON);
+ glTexCoord2f(-PI, 0); glVertex2f(-1, -1);
+ glTexCoord2f(PI, 0); glVertex2f( 1, -1);
+ glTexCoord2f(PI, 1); glVertex2f( 1, 1);
+ glTexCoord2f(-PI, 1); glVertex2f(-1, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -8.0 );
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ static const char *modulate2D =
+ "!!ARBfp1.0\n"
+ "TEMP R0;\n"
+ "MOV R0, {0,0,0,1};\n"
+ "SCS R0, fragment.texcoord[0].x; \n"
+ "ADD R0, R0, {1.0}.x;\n"
+ "MUL R0, R0, {0.5}.x;\n"
+ "MOV result.color, R0; \n"
+ "END"
+ ;
+ GLuint modulateProg;
+ GLuint Texture;
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ printf("Error: GL_ARB_fragment_program not supported!\n");
+ exit(1);
+ }
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ /* Setup the fragment program */
+ glGenProgramsARB(1, &modulateProg);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, modulateProg);
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(modulate2D), (const GLubyte *)modulate2D);
+
+ printf("glGetError = 0x%x\n", (int) glGetError());
+ printf("glError(GL_PROGRAM_ERROR_STRING_ARB) = %s\n",
+ (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ assert(glIsProgramARB(modulateProg));
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ /* Load texture */
+ glGenTextures(1, &Texture);
+ glBindTexture(GL_TEXTURE_2D, Texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
+ exit(1);
+ }
+ /* XXX this enable shouldn't really be needed!!! */
+ glEnable(GL_TEXTURE_2D);
+
+ glClearColor(.3, .3, .3, 0);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbnpot-mipmap.c b/tests/mesa/tests/arbnpot-mipmap.c
new file mode 100644
index 00000000..4ed84e7a
--- /dev/null
+++ b/tests/mesa/tests/arbnpot-mipmap.c
@@ -0,0 +1,184 @@
+
+/* Copyright (c) Mark J. Kilgard, 1994. */
+
+/*
+ * (c) Copyright 1993, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States. Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/* mipmap.c
+ * This program demonstrates using mipmaps for texture maps.
+ * To overtly show the effect of mipmaps, each mipmap reduction
+ * level has a solidly colored, contrasting texture image.
+ * Thus, the quadrilateral which is drawn is drawn with several
+ * different colors.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <GL/glut.h>
+
+GLubyte mipmapImage32[40][46][3];
+GLubyte mipmapImage16[20][23][3];
+GLubyte mipmapImage8[10][11][3];
+GLubyte mipmapImage4[5][5][3];
+GLubyte mipmapImage2[2][2][3];
+GLubyte mipmapImage1[1][1][3];
+
+static void makeImages(void)
+{
+ int i, j;
+
+ for (i = 0; i < 40; i++) {
+ for (j = 0; j < 46; j++) {
+ mipmapImage32[i][j][0] = 255;
+ mipmapImage32[i][j][1] = 255;
+ mipmapImage32[i][j][2] = 0;
+ }
+ }
+ for (i = 0; i < 20; i++) {
+ for (j = 0; j < 23; j++) {
+ mipmapImage16[i][j][0] = 255;
+ mipmapImage16[i][j][1] = 0;
+ mipmapImage16[i][j][2] = 255;
+ }
+ }
+ for (i = 0; i < 10; i++) {
+ for (j = 0; j < 11; j++) {
+ mipmapImage8[i][j][0] = 255;
+ mipmapImage8[i][j][1] = 0;
+ mipmapImage8[i][j][2] = 0;
+ }
+ }
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 5; j++) {
+ mipmapImage4[i][j][0] = 0;
+ mipmapImage4[i][j][1] = 255;
+ mipmapImage4[i][j][2] = 0;
+ }
+ }
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ mipmapImage2[i][j][0] = 0;
+ mipmapImage2[i][j][1] = 0;
+ mipmapImage2[i][j][2] = 255;
+ }
+ }
+ mipmapImage1[0][0][0] = 255;
+ mipmapImage1[0][0][1] = 255;
+ mipmapImage1[0][0][2] = 255;
+}
+
+static void myinit(void)
+{
+ if (!glutExtensionSupported("GL_ARB_texture_non_power_of_two")) {
+ printf("Sorry, this program requires GL_ARB_texture_non_power_of_two\n");
+ exit(1);
+ }
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glShadeModel(GL_FLAT);
+
+ glTranslatef(0.0, 0.0, -3.6);
+ makeImages();
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, 40, 46, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage32[0][0][0]);
+ glTexImage2D(GL_TEXTURE_2D, 1, 3, 20, 23, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage16[0][0][0]);
+ glTexImage2D(GL_TEXTURE_2D, 2, 3, 10, 11, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage8[0][0][0]);
+ glTexImage2D(GL_TEXTURE_2D, 3, 3, 5, 5, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage4[0][0][0]);
+ glTexImage2D(GL_TEXTURE_2D, 4, 3, 2, 2, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage2[0][0][0]);
+ glTexImage2D(GL_TEXTURE_2D, 5, 3, 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage1[0][0][0]);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_NEAREST);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ glEnable(GL_TEXTURE_2D);
+}
+
+static void display(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
+ glTexCoord2f(0.0, 8.0); glVertex3f(-2.0, 1.0, 0.0);
+ glTexCoord2f(8.0, 8.0); glVertex3f(2000.0, 1.0, -6000.0);
+ glTexCoord2f(8.0, 0.0); glVertex3f(2000.0, -1.0, -6000.0);
+ glEnd();
+ glFlush();
+}
+
+static void myReshape(int w, int h)
+{
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(60.0, 1.0*(GLfloat)w/(GLfloat)h, 1.0, 30000.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+ switch (k) {
+ case 27: /* Escape */
+ exit(0);
+ break;
+ default:
+ return;
+ }
+ glutPostRedisplay();
+}
+
+int main(int argc, char** argv)
+{
+ glutInit(&argc, argv);
+ glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
+ glutInitWindowSize (500, 500);
+ glutCreateWindow (argv[0]);
+ myinit();
+ glutReshapeFunc (myReshape);
+ glutDisplayFunc(display);
+ glutKeyboardFunc(key);
+ glutMainLoop();
+ return 0; /* ANSI C requires main to return int. */
+}
diff --git a/tests/mesa/tests/arbnpot.c b/tests/mesa/tests/arbnpot.c
new file mode 100644
index 00000000..8107717e
--- /dev/null
+++ b/tests/mesa/tests/arbnpot.c
@@ -0,0 +1,174 @@
+/*
+ * Test NPOT textures with the GL_ARB_texture_non_power_of_two extension.
+ * Brian Paul
+ * 2 July 2003
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+#include "../util/readtex.c"
+
+#define IMAGE_FILE "../images/girl.rgb"
+
+static GLfloat Zrot = 0;
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Zrot, 0, 0, 1);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0);
+ glVertex2f(-1, -1);
+ glTexCoord2f(1, 0);
+ glVertex2f(1, -1);
+ glTexCoord2f(1, 1);
+ glVertex2f(1, 1);
+ glTexCoord2f(0, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -7.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'z':
+ Zrot -= 1.0;
+ break;
+ case 'Z':
+ Zrot += 1.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ GLubyte *image;
+ int imgWidth, imgHeight, minDim, w;
+ GLenum imgFormat;
+
+ if (!glutExtensionSupported("GL_ARB_texture_non_power_of_two")) {
+ printf("Sorry, this program requires GL_ARB_texture_non_power_of_two\n");
+ exit(1);
+ }
+
+#if 1
+ image = LoadRGBImage( IMAGE_FILE, &imgWidth, &imgHeight, &imgFormat );
+ if (!image) {
+ printf("Couldn't read %s\n", IMAGE_FILE);
+ exit(0);
+ }
+#else
+ int i, j;
+ imgFormat = GL_RGB;
+ imgWidth = 3;
+ imgHeight = 3;
+ image = malloc(imgWidth * imgHeight * 3);
+ for (i = 0; i < imgHeight; i++) {
+ for (j = 0; j < imgWidth; j++) {
+ int k = (i * imgWidth + j) * 3;
+ if ((i + j) & 1) {
+ image[k+0] = 255;
+ image[k+1] = 0;
+ image[k+2] = 0;
+ }
+ else {
+ image[k+0] = 0;
+ image[k+1] = 255;
+ image[k+2] = 0;
+ }
+ }
+ }
+#endif
+
+ printf("Read %d x %d\n", imgWidth, imgHeight);
+
+ minDim = imgWidth < imgHeight ? imgWidth : imgHeight;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, imgWidth, 0,
+ imgFormat, GL_UNSIGNED_BYTE, image);
+ assert(glGetError() == GL_NO_ERROR);
+
+ glTexImage1D(GL_PROXY_TEXTURE_1D, 0, GL_RGB, imgWidth, 0,
+ imgFormat, GL_UNSIGNED_BYTE, image);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &w);
+ assert(w == imgWidth);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imgWidth, imgHeight, 0,
+ imgFormat, GL_UNSIGNED_BYTE, image);
+ assert(glGetError() == GL_NO_ERROR);
+
+ glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB, imgWidth, imgHeight, 0,
+ imgFormat, GL_UNSIGNED_BYTE, image);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
+ assert(w == imgWidth);
+
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, imgWidth, imgHeight, 1, 0,
+ imgFormat, GL_UNSIGNED_BYTE, image);
+ assert(glGetError() == GL_NO_ERROR);
+
+ glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_RGB, imgWidth, imgHeight, 1, 0,
+ imgFormat, GL_UNSIGNED_BYTE, image);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &w);
+ assert(w == imgWidth);
+
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB,
+ minDim, minDim, 0,
+ imgFormat, GL_UNSIGNED_BYTE, image);
+ assert(glGetError() == GL_NO_ERROR);
+
+ glTexImage2D(GL_PROXY_TEXTURE_CUBE_MAP, 0, GL_RGB,
+ minDim, minDim, 0,
+ imgFormat, GL_UNSIGNED_BYTE, image);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_CUBE_MAP, 0, GL_TEXTURE_WIDTH, &w);
+ assert(w == minDim);
+
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glEnable(GL_TEXTURE_2D);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 400, 400 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbvptest1.c b/tests/mesa/tests/arbvptest1.c
new file mode 100644
index 00000000..0ebd3987
--- /dev/null
+++ b/tests/mesa/tests/arbvptest1.c
@@ -0,0 +1,164 @@
+/* Test glGenProgramsARB(), glIsProgramARB(), glLoadProgramARB() */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+
+ glBegin(GL_POLYGON);
+ glVertexAttrib2fARB(0, -1, -1);
+ glVertexAttrib2fARB(0, 1, -1);
+ glVertexAttrib2fARB(0, 0, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+static void load_program(const char *prog, GLuint prognum)
+{
+ int a;
+ GLint errorpos, errno;
+
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+ glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(prog), (const GLubyte *) prog);
+
+ assert(glIsProgramARB(prognum));
+ errno = glGetError();
+ printf("glGetError = %d\n", errno);
+ if (errno != GL_NO_ERROR)
+ {
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+ printf("errorpos: %d\n", errorpos);
+ printf("%s\n", (char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+
+ for (a=-10; a<10; a++)
+ {
+ if ((errorpos+a < 0) || (errorpos+a >= strlen(prog))) continue;
+ printf("%c", prog[errorpos+a]);
+ }
+ printf("\n");
+ exit(1);
+ }
+}
+
+static void Init( void )
+{
+ GLuint prognum[4];
+
+ static const char *prog1 =
+ "!!ARBvp1.0\n"
+ "TEMP R0;\n"
+ "MUL result.color.primary.xyz, R0, program.local[35]; \n"
+ "END\n";
+ static const char *prog2 =
+ "!!ARBvp1.0\n"
+ "#\n"
+ "# c[0-3] = modelview projection (composite) matrix\n"
+ "# c[32] = normalized light direction in object-space\n"
+ "# c[35] = yellow diffuse material, (1.0, 1.0, 0.0, 1.0)\n"
+ "# c[64].x = 0.0\n"
+ "# c[64].z = 0.125, a scaling factor\n"
+ "TEMP R0, R1;\n"
+ "#\n"
+ "# outputs diffuse illumination for color and perturbed position\n"
+ "#\n"
+ "DP3 R0, program.local[32], vertex.normal; # light direction DOT normal\n"
+ "MUL result.color.primary.xyz, R0, program.local[35]; \n"
+ "MAX R0, program.local[64].x, R0; \n"
+ "MUL R0, R0, vertex.normal; \n"
+ "MUL R0, R0, program.local[64].z; \n"
+ "ADD R1, vertex.position, -R0; # perturb object space position\n"
+ "DP4 result.position.x, state.matrix.mvp.row[3], R1; \n"
+ "DP4 result.position.y, state.matrix.mvp.row[1], R1; \n"
+ "DP4 result.position.z, state.matrix.mvp.row[2], R1; \n"
+ "DP4 result.position.w, state.matrix.mvp.row[3], R1; \n"
+ "END\n";
+ static const char *prog3 =
+ "!!ARBvp1.0\n"
+ "TEMP R0, R1, R2, R3;\n"
+ "DP4 result.position.x, state.matrix.mvp.row[0], vertex.position;\n"
+ "DP4 result.position.y, state.matrix.mvp.row[1], vertex.position;\n"
+ "DP4 result.position.z, state.matrix.mvp.row[2], vertex.position;\n"
+ "DP4 result.position.w, state.matrix.mvp.row[3], vertex.position;\n"
+ "DP3 R0.x, state.matrix.modelview.inverse.row[0], vertex.normal;\n"
+ "DP3 R0.y, state.matrix.modelview.inverse.row[1], vertex.normal;\n"
+ "DP3 R0.z, state.matrix.modelview.inverse.row[2], vertex.normal;\n"
+ "DP3 R1.x, program.env[32], R0; # R1.x = Lpos DOT n'\n"
+ "DP3 R1.y, program.env[33], R0; # R1.y = hHat DOT n'\n"
+ "MOV R1.w, program.local[38].x; # R1.w = specular power\n"
+ "LIT R2, R1; # Compute lighting values\n"
+ "MAD R3, program.env[35].x, R2.y, program.env[35].y; # diffuse + emissive\n"
+ "MAD result.color.primary.xyz, program.env[36], R2.z, R3; # + specular\n"
+ "END\n";
+ static const char *prog4 =
+ "!!ARBvp1.0\n"
+ "TEMP R2, R3;\n"
+ "PARAM foo = {0., 0., 0., 1.};\n"
+ "PARAM blah[] = { program.local[0..8] };\n"
+ "ADDRESS A0;\n"
+ "ARL A0.x, foo.x;\n"
+ "DP4 R2, R3, blah[A0.x].x;\n"
+ "DP4 R2, R3, blah[A0.x + 5];\n"
+ "DP4 result.position, R3, blah[A0.x - 4];\n"
+ "END\n";
+
+ glGenProgramsARB(4, prognum);
+
+ load_program(prog1, prognum[0]);
+ load_program(prog2, prognum[1]);
+ load_program(prog3, prognum[2]);
+ load_program(prog4, prognum[3]);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbvptest3.c b/tests/mesa/tests/arbvptest3.c
new file mode 100644
index 00000000..64370629
--- /dev/null
+++ b/tests/mesa/tests/arbvptest3.c
@@ -0,0 +1,127 @@
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Zrot = 0.0;
+
+
+static void Display( void )
+{
+ glClearColor(0.3, 0.3, 0.3, 1);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+
+ glLoadIdentity();
+ glRotatef(Zrot, 0, 0, 1);
+
+ glPushMatrix();
+
+ glVertexAttrib3fARB(3, 1, 0.5, 0.25);
+ glBegin(GL_TRIANGLES);
+#if 1
+ glVertexAttrib3fARB(3, 1.0, 0.0, 0.0);
+ glVertexAttrib2fARB(0, -0.5, -0.5);
+ glVertexAttrib3fARB(3, 0.0, 1.0, 0.0);
+ glVertexAttrib2fARB(0, 0.5, -0.5);
+ glVertexAttrib3fARB(3, 0.0, 0.0, 1.0);
+ glVertexAttrib2fARB(0, 0, 0.5);
+#else
+ glVertex2f( -1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 0, 1);
+#endif
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ /* glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
+ glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ /*glTranslatef( 0.0, 0.0, -15.0 );*/
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'z':
+ Zrot -= 5.0;
+ break;
+ case 'Z':
+ Zrot += 5.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ GLint errno;
+ GLuint prognum;
+
+ static const char *prog1 =
+ "!!ARBvp1.0\n"
+ "MOV result.color, vertex.attrib[3];\n"
+
+ "DP4 result.position.x, vertex.position, state.matrix.modelview.row[0];\n"
+ "DP4 result.position.y, vertex.position, state.matrix.modelview.row[1];\n"
+ "DP4 result.position.z, vertex.position, state.matrix.modelview.row[2];\n"
+ "DP4 result.position.w, vertex.position, state.matrix.modelview.row[3];\n"
+ "END\n";
+
+ glGenProgramsARB(1, &prognum);
+
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+ glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(prog1), (const GLubyte *) prog1);
+
+ assert(glIsProgramARB(prognum));
+ errno = glGetError();
+ printf("glGetError = %d\n", errno);
+ if (errno != GL_NO_ERROR)
+ {
+ GLint errorpos;
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+ printf("errorpos: %d\n", errorpos);
+ printf("%s\n", (char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbvptorus.c b/tests/mesa/tests/arbvptorus.c
new file mode 100644
index 00000000..9d19ef90
--- /dev/null
+++ b/tests/mesa/tests/arbvptorus.c
@@ -0,0 +1,186 @@
+/*
+ * A lit, rotating torus via vertex program
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Xrot = 0.0, Yrot = 0.0, Zrot = 0.0;
+static GLboolean Anim = GL_TRUE;
+
+
+static void Idle( void )
+{
+ Xrot += .3;
+ Yrot += .4;
+ Zrot += .2;
+ glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+ glutSolidTorus(0.75, 2.0, 10, 20);
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -12.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case ' ':
+ Xrot = Yrot = Zrot = 0;
+ break;
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'z':
+ Zrot -= 5.0;
+ break;
+ case 'Z':
+ Zrot += 5.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ GLint errno;
+ GLuint prognum;
+
+ /* borrowed from an nvidia demo:
+ * c[0..3] = modelview matrix
+ * c[4..7] = invtrans modelview matrix
+ * c[32] = light pos
+ * c[35] = diffuse color
+ */
+ static const char prog[] =
+ "!!ARBvp1.0\n"
+ "OPTION ARB_position_invariant ;"
+ "TEMP R0, R1; \n"
+
+ "# normal x MV-1T -> lighting normal\n"
+ "DP3 R1.x, state.matrix.modelview.invtrans.row[0], vertex.normal ;\n"
+ "DP3 R1.y, state.matrix.modelview.invtrans.row[1], vertex.normal;\n"
+ "DP3 R1.z, state.matrix.modelview.invtrans.row[2], vertex.normal;\n"
+
+ "DP3 R0, program.local[32], R1; # L.N\n"
+#if 0
+ "MUL result.color.xyz, R0, program.local[35] ; # col = L.N * diffuse\n"
+#else
+ "MUL result.color.primary.xyz, R0, program.local[35] ; # col = L.N * diffuse\n"
+#endif
+ "MOV result.texcoord, vertex.texcoord;\n"
+ "END";
+
+ if (!glutExtensionSupported("GL_ARB_vertex_program")) {
+ printf("Sorry, this program requires GL_ARB_vertex_program");
+ exit(1);
+ }
+
+
+ glGenProgramsARB(1, &prognum);
+
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+ glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(prog), (const GLubyte *) prog);
+
+ assert(glIsProgramARB(prognum));
+ errno = glGetError();
+ printf("glGetError = %d\n", errno);
+ if (errno != GL_NO_ERROR)
+ {
+ GLint errorpos;
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+ printf("errorpos: %d\n", errorpos);
+ printf("%s\n", (char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ }
+
+ /* Light position */
+ glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 32, 2, 2, 4, 1);
+ /* Diffuse material color */
+ glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 35, 0.25, 0, 0.25, 1);
+
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+ glEnable(GL_DEPTH_TEST);
+ glClearColor(0.3, 0.3, 0.3, 1);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/arbvpwarpmesh.c b/tests/mesa/tests/arbvpwarpmesh.c
new file mode 100644
index 00000000..3dfe94f7
--- /dev/null
+++ b/tests/mesa/tests/arbvpwarpmesh.c
@@ -0,0 +1,246 @@
+/*
+ * Warp a triangle mesh with a vertex program.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Xrot = -60.0, Yrot = 0.0, Zrot = 0.0;
+static GLboolean Anim = GL_TRUE;
+static GLfloat Phi = 0.0;
+
+
+static void Idle( void )
+{
+ Phi += 0.01;
+ glutPostRedisplay();
+}
+
+
+static void DrawMesh( int rows, int cols )
+{
+ static const GLfloat colorA[3] = { 0, 1, 0 };
+ static const GLfloat colorB[3] = { 0, 0, 1 };
+ const float dx = 2.0 / (cols - 1);
+ const float dy = 2.0 / (rows - 1);
+ float x, y;
+ int i, j;
+
+#if 1
+#define COLOR3FV(c) glVertexAttrib3fvARB(3, c)
+#define VERTEX2F(x, y) glVertexAttrib2fARB(0, x, y)
+#else
+#define COLOR3FV(c) glColor3fv(c)
+#define VERTEX2F(x, y) glVertex2f(x, y)
+#endif
+
+ y = -1.0;
+ for (i = 0; i < rows - 1; i++) {
+ glBegin(GL_QUAD_STRIP);
+ x = -1.0;
+ for (j = 0; j < cols; j++) {
+ if ((i + j) & 1)
+ COLOR3FV(colorA);
+ else
+ COLOR3FV(colorB);
+ VERTEX2F(x, y);
+ VERTEX2F(x, y + dy);
+ x += dx;
+ }
+ glEnd();
+ y += dy;
+ }
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+
+ /* Position the gravity source */
+ {
+ GLfloat x, y, z, r = 0.5;
+ x = r * cos(Phi);
+ y = r * sin(Phi);
+ z = 1.0;
+ glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 30, x, y, z, 1);
+ glDisable(GL_VERTEX_PROGRAM_ARB);
+ glBegin(GL_POINTS);
+ glColor3f(1,1,1);
+ glVertex3f(x, y, z);
+ glEnd();
+ }
+
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+ DrawMesh(8, 8);
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ float ar = (float) width / (float) height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0 * ar, 1.0 * ar, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -12.0 );
+ glScalef(2, 2, 2);
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'p':
+ Phi += 0.2;
+ break;
+ case 'z':
+ Zrot -= 5.0;
+ break;
+ case 'Z':
+ Zrot += 5.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ GLuint prognum;
+ GLint errno;
+
+ /*
+ * c[0..3] = modelview matrix
+ * c[4..7] = inverse modelview matrix
+ * c[30] = gravity source location
+ * c[31] = gravity source strength
+ * c[32] = light pos
+ * c[35] = diffuse color
+ */
+ static const char prog[] =
+ "!!ARBvp1.0\n"
+ "TEMP R1, R2, R3; "
+
+ "# Compute distance from vertex to gravity source\n"
+ "ADD R1, program.local[30], -vertex.position; # vector from vertex to gravity\n"
+ "DP3 R2, R1, R1; # dot product\n"
+ "RSQ R2, R2.x; # square root = distance\n"
+ "MUL R2, R2, program.local[31].xxxx; # scale by the gravity factor\n"
+
+ "# Displace vertex by gravity factor along R1 vector\n"
+ "MAD R3, R1, R2, vertex.position;\n"
+
+ "# Continue with typical modelview/projection\n"
+ "DP4 result.position.x, state.matrix.mvp.row[0], R3 ; # object x MVP -> clip\n"
+ "DP4 result.position.y, state.matrix.mvp.row[1], R3 ;\n"
+ "DP4 result.position.z, state.matrix.mvp.row[2], R3 ;\n"
+ "DP4 result.position.w, state.matrix.mvp.row[3], R3 ;\n"
+
+ "MOV result.color, vertex.attrib[3];\n # copy input color to output color\n"
+
+ "END";
+
+ if (!glutExtensionSupported("GL_ARB_vertex_program")) {
+ printf("Sorry, this program requires GL_ARB_vertex_program\n");
+ exit(1);
+ }
+
+ glGenProgramsARB(1, &prognum);
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+ glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(prog), (const GLubyte *)prog);
+ errno = glGetError();
+ printf("glGetError = %d\n", errno);
+
+ if (errno != GL_NO_ERROR)
+ {
+ GLint errorpos;
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+ printf("errorpos: %d\n", errorpos);
+ printf("%s\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ }
+
+ /* Light position */
+ glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 32, 2, 2, 4, 1);
+ /* Diffuse material color */
+ glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 35, 0.25, 0, 0.25, 1);
+
+ /* Gravity strength */
+ glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 31, .5, 0, 0, 0);
+
+ glEnable(GL_DEPTH_TEST);
+ glClearColor(0.3, 0.3, 0.3, 1);
+ glShadeModel(GL_FLAT);
+ glPointSize(3);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/auxbuffer.c b/tests/mesa/tests/auxbuffer.c
new file mode 100644
index 00000000..70f0b739
--- /dev/null
+++ b/tests/mesa/tests/auxbuffer.c
@@ -0,0 +1,499 @@
+/*
+ * Test AUX buffer rendering
+ * Use GLX since GLUT doesn't support AUX buffers
+ */
+
+
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
+ * Port by Brian Paul 23 March 2001
+ *
+ * Command line options:
+ * -info print GL implementation information
+ *
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+
+static int
+current_time(void)
+{
+ return 0;
+}
+
+
+
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+static int WinWidth = 300, WinHeight = 300;
+static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+
+
+/*
+ *
+ * Draw a gear wheel. You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input: inner_radius - radius of hole at center
+ * outer_radius - radius at center of teeth
+ * width - width of gear
+ * teeth - number of teeth
+ * tooth_depth - depth of tooth
+ */
+static void
+gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth)
+{
+ GLint i;
+ GLfloat r0, r1, r2;
+ GLfloat angle, da;
+ GLfloat u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / teeth / 4.0;
+
+ glShadeModel(GL_FLAT);
+
+ glNormal3f(0.0, 0.0, 1.0);
+
+ /* draw front face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw front sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ glEnd();
+
+ glNormal3f(0.0, 0.0, -1.0);
+
+ /* draw back face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw back sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ }
+ glEnd();
+
+ /* draw outward faces of teeth */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ u = r2 * cos(angle + da) - r1 * cos(angle);
+ v = r2 * sin(angle + da) - r1 * sin(angle);
+ len = sqrt(u * u + v * v);
+ u /= len;
+ v /= len;
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
+ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ }
+
+ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
+ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
+
+ glEnd();
+
+ glShadeModel(GL_SMOOTH);
+
+ /* draw inside radius cylinder */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glNormal3f(-cos(angle), -sin(angle), 0.0);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ }
+ glEnd();
+}
+
+
+static void
+draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(view_rotx, 1.0, 0.0, 0.0);
+ glRotatef(view_roty, 0.0, 1.0, 0.0);
+ glRotatef(view_rotz, 0.0, 0.0, 1.0);
+
+ glPushMatrix();
+ glTranslatef(-3.0, -2.0, 0.0);
+ glRotatef(angle, 0.0, 0.0, 1.0);
+ glCallList(gear1);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(3.1, -2.0, 0.0);
+ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
+ glCallList(gear2);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(-3.1, 4.2, 0.0);
+ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
+ glCallList(gear3);
+ glPopMatrix();
+
+ glPopMatrix();
+}
+
+
+/* new window size or exposure */
+static void
+reshape(int width, int height)
+{
+ GLfloat h = (GLfloat) height / (GLfloat) width;
+
+ WinWidth = width;
+ WinHeight = height;
+ glViewport(0, 0, (GLint) width, (GLint) height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -40.0);
+}
+
+
+static void
+init(void)
+{
+ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
+ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+ int i;
+
+ glGetIntegerv(GL_AUX_BUFFERS, &i);
+ printf("AUX BUFFERS: %d\n", i);
+
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+
+ /* make the gears */
+ gear1 = glGenLists(1);
+ glNewList(gear1, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
+ gear(1.0, 4.0, 1.0, 20, 0.7);
+ glEndList();
+
+ gear2 = glGenLists(1);
+ glNewList(gear2, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
+ gear(0.5, 2.0, 2.0, 10, 0.7);
+ glEndList();
+
+ gear3 = glGenLists(1);
+ glNewList(gear3, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
+ gear(1.3, 2.0, 0.5, 10, 0.7);
+ glEndList();
+
+ glEnable(GL_NORMALIZE);
+}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet, GLXContext *ctxRet)
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ GLX_AUX_BUFFERS, 1,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ XFree(visinfo);
+
+ *winRet = win;
+ *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win)
+{
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ /* we'll redraw below */
+ break;
+ case ConfigureNotify:
+ reshape(event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ if (code == XK_Left) {
+ view_roty += 5.0;
+ }
+ else if (code == XK_Right) {
+ view_roty -= 5.0;
+ }
+ else if (code == XK_Up) {
+ view_rotx += 5.0;
+ }
+ else if (code == XK_Down) {
+ view_rotx -= 5.0;
+ }
+ else {
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /* next frame */
+ angle += 2.0;
+
+ /* draw to aux buffer */
+ glDrawBuffer(GL_AUX0);
+
+ draw();
+
+ /* Copy aux buffer image to back color buffer */
+ glReadBuffer(GL_AUX0);
+ glDrawBuffer(GL_BACK);
+ glWindowPos2iARB(0, 0);
+ glDisable(GL_DEPTH_TEST);
+ glCopyPixels(0, 0, WinWidth, WinHeight, GL_COLOR);
+ glEnable(GL_DEPTH_TEST);
+
+ glXSwapBuffers(dpy, win);
+
+ /* calc framerate */
+ {
+ static int t0 = -1;
+ static int frames = 0;
+ int t = current_time();
+
+ if (t0 < 0)
+ t0 = t;
+
+ frames++;
+
+ if (t - t0 >= 5.0) {
+ GLfloat seconds = t - t0;
+ GLfloat fps = frames / seconds;
+ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
+ fps);
+ t0 = t;
+ frames = 0;
+ }
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ char *dpyName = ":0";
+ GLboolean printInfo = GL_FALSE;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-info") == 0) {
+ printInfo = GL_TRUE;
+ }
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n", dpyName);
+ return -1;
+ }
+
+ make_window(dpy, "glxgears", 0, 0, WinWidth, WinHeight, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+
+ if (printInfo) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+
+ init();
+
+ event_loop(dpy, win);
+
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return 0;
+}
diff --git a/tests/mesa/tests/blendminmax.c b/tests/mesa/tests/blendminmax.c
new file mode 100644
index 00000000..2aab1a39
--- /dev/null
+++ b/tests/mesa/tests/blendminmax.c
@@ -0,0 +1,209 @@
+/*
+ * (C) Copyright IBM Corporation 2004
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file blendminmax.c
+ *
+ * Simple test of GL_EXT_blend_minmax functionality. Four squares are drawn
+ * with different blending modes, but all should be rendered with the same
+ * final color.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+
+static int Width = 400;
+static int Height = 200;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+
+ /* This is the "reference" square.
+ */
+
+ glTranslatef(-4.5, 0, 0);
+ glBlendEquation( GL_FUNC_ADD );
+ glBlendFunc( GL_ONE, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+ /* GL_MIN and GL_MAX are supposed to ignore the blend function setting.
+ * To test that, we set the blend function to GL_ZERO for both color and
+ * alpha each time GL_MIN or GL_MAX is used.
+ *
+ * Apple ships an extension called GL_ATI_blend_weighted_minmax (supported
+ * on Mac OS X 10.2 and later). I believe the difference with that
+ * extension is that it uses the blend function. However, I have no idea
+ * what the enums are for it. The extension is listed at Apple's developer
+ * site, but there is no documentation.
+ *
+ * http://developer.apple.com/opengl/extensions.html
+ */
+
+ glTranslatef(3.0, 0, 0);
+ glBlendEquation( GL_FUNC_ADD );
+ glBlendFunc( GL_ONE, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glBlendEquation( GL_MAX );
+ glBlendFunc( GL_ZERO, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.2, 0.2, 0.2 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+ glTranslatef(3.0, 0, 0);
+ glBlendEquation( GL_FUNC_ADD );
+ glBlendFunc( GL_ONE, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glBlendEquation( GL_MIN );
+ glBlendFunc( GL_ZERO, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.8, 0.8, 0.8 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+ glTranslatef(3.0, 0, 0);
+ glBlendEquation( GL_FUNC_ADD );
+ glBlendFunc( GL_ONE, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.8, 0.8, 0.8 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glBlendEquation( GL_MIN );
+ glBlendFunc( GL_ZERO, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ if ( !glutExtensionSupported("GL_ARB_imaging") && !glutExtensionSupported("GL_EXT_blend_minmax")) {
+ printf("Sorry, this program requires either GL_ARB_imaging or GL_EXT_blend_minmax.\n");
+ exit(1);
+ }
+
+ printf("\nAll 4 squares should be the same color.\n");
+ glEnable( GL_BLEND );
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "GL_EXT_blend_minmax test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/blendsquare.c b/tests/mesa/tests/blendsquare.c
new file mode 100644
index 00000000..1694866a
--- /dev/null
+++ b/tests/mesa/tests/blendsquare.c
@@ -0,0 +1,178 @@
+/*
+ * (C) Copyright IBM Corporation 2004
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file blendsquare.c
+ *
+ * Simple test of GL_NV_blend_square functionality. Four squares are drawn
+ * with different blending modes, but all should be rendered with the same
+ * final color.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+
+static int Width = 400;
+static int Height = 200;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+
+ glTranslatef(-4.5, 0, 0);
+ glBlendFunc( GL_ONE, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.5 * 0.5, 0.5 * 0.5, 0.5 * 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+ glTranslatef(3.0, 0, 0);
+ glBlendFunc( GL_ONE, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glBlendFunc( GL_DST_COLOR, GL_ZERO );
+ glBegin(GL_QUADS);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+ glTranslatef(3.0, 0, 0);
+ glBlendFunc( GL_SRC_COLOR, GL_ZERO );
+ glBegin(GL_QUADS);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+ glTranslatef(3.0, 0, 0);
+ glBlendFunc( GL_ONE, GL_ZERO );
+ glBegin(GL_QUADS);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glBlendFunc( GL_ZERO, GL_DST_COLOR );
+ glBegin(GL_QUADS);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+ const double version = strtod( ver_string, NULL );
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ if ( (version < 1.4) && !glutExtensionSupported("GL_NV_blend_square")) {
+ printf("Sorry, this program requires either OpenGL 1.4 or GL_NV_blend_square\n");
+ exit(1);
+ }
+
+ printf("\nAll 4 squares should be the same color. The two on the left are drawn\n"
+ "without NV_blend_square functionality, and the two on the right are drawn\n"
+ "with NV_blend_square functionality. If the two on the left are dark, but\n"
+ "the two on the right are not, then NV_blend_square is broken.\n");
+ glEnable( GL_BLEND );
+ glBlendEquation( GL_FUNC_ADD );
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "GL_NV_blend_square test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/bufferobj.c b/tests/mesa/tests/bufferobj.c
new file mode 100644
index 00000000..50ab5cdf
--- /dev/null
+++ b/tests/mesa/tests/bufferobj.c
@@ -0,0 +1,371 @@
+/*
+ * Test GL_ARB_vertex_buffer_object
+ *
+ * Brian Paul
+ * 16 Sep 2003
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+#define NUM_OBJECTS 10
+
+struct object
+{
+ GLuint BufferID;
+ GLuint ElementsBufferID;
+ GLuint NumVerts;
+ GLuint VertexOffset;
+ GLuint ColorOffset;
+ GLuint NumElements;
+};
+
+static struct object Objects[NUM_OBJECTS];
+static GLuint NumObjects;
+
+static GLuint Win;
+
+static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
+static GLboolean Anim = GL_TRUE;
+
+
+static void CheckError(int line)
+{
+ GLenum err = glGetError();
+ if (err) {
+ printf("GL Error 0x%x at line %d\n", (int) err, line);
+ }
+}
+
+
+static void DrawObject( const struct object *obj )
+{
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->BufferID);
+ glVertexPointer(3, GL_FLOAT, 0, (void *) obj->VertexOffset);
+ glEnable(GL_VERTEX_ARRAY);
+
+ /* test push/pop attrib */
+ /* XXX this leads to a segfault with NVIDIA's 53.36 driver */
+#if 0
+ if (1)
+ {
+ glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
+ /*glVertexPointer(3, GL_FLOAT, 0, (void *) (obj->VertexOffset + 10000));*/
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 999999);
+ glPopClientAttrib();
+ }
+#endif
+ glColorPointer(3, GL_FLOAT, 0, (void *) obj->ColorOffset);
+ glEnable(GL_COLOR_ARRAY);
+
+ if (obj->NumElements > 0) {
+ /* indexed arrays */
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, obj->ElementsBufferID);
+ glDrawElements(GL_LINE_LOOP, obj->NumElements, GL_UNSIGNED_INT, NULL);
+ }
+ else {
+ /* non-indexed arrays */
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ glDrawArrays(GL_LINE_LOOP, 0, obj->NumVerts);
+ }
+}
+
+
+static void Idle( void )
+{
+ Zrot = 0.05 * glutGet(GLUT_ELAPSED_TIME);
+ glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+ int i;
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ for (i = 0; i < NumObjects; i++) {
+ float x = 5.0 * ((float) i / (NumObjects-1) - 0.5);
+ glPushMatrix();
+ glTranslatef(x, 0, 0);
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+
+ DrawObject(Objects + i);
+
+ glPopMatrix();
+ }
+
+ CheckError(__LINE__);
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ float ar = (float) width / (float) height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void FreeBuffers(void)
+{
+ int i;
+ for (i = 0; i < NUM_OBJECTS; i++)
+ glDeleteBuffersARB(1, &Objects[i].BufferID);
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'z':
+ Zrot -= step;
+ break;
+ case 'Z':
+ Zrot += step;
+ break;
+ case 27:
+ FreeBuffers();
+ glutDestroyWindow(Win);
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+
+static void MakeObject1(struct object *obj)
+{
+ GLfloat *v, *c;
+ void *p;
+ int i;
+ GLubyte buffer[500];
+
+ for (i = 0; i < 500; i++)
+ buffer[i] = i & 0xff;
+
+ obj->BufferID = 0;
+ glGenBuffersARB(1, &obj->BufferID);
+ assert(obj->BufferID != 0);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->BufferID);
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB, 500, buffer, GL_STATIC_DRAW_ARB);
+
+ for (i = 0; i < 500; i++)
+ buffer[i] = 0;
+
+ glGetBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 500, buffer);
+
+ for (i = 0; i < 500; i++)
+ assert(buffer[i] == (i & 0xff));
+
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAPPED_ARB, &i);
+ assert(!i);
+
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_USAGE_ARB, &i);
+
+ v = (GLfloat *) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+
+ /* do some sanity tests */
+ glGetBufferPointervARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAP_POINTER_ARB, &p);
+ assert(p == v);
+
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &i);
+ assert(i == 500);
+
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_USAGE_ARB, &i);
+ assert(i == GL_STATIC_DRAW_ARB);
+
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_ACCESS_ARB, &i);
+ assert(i == GL_WRITE_ONLY_ARB);
+
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAPPED_ARB, &i);
+ assert(i);
+
+ /* Make rectangle */
+ v[0] = -1; v[1] = -1; v[2] = 0;
+ v[3] = 1; v[4] = -1; v[5] = 0;
+ v[6] = 1; v[7] = 1; v[8] = 0;
+ v[9] = -1; v[10] = 1; v[11] = 0;
+ c = v + 12;
+ c[0] = 1; c[1] = 0; c[2] = 0;
+ c[3] = 1; c[4] = 0; c[5] = 0;
+ c[6] = 1; c[7] = 0; c[8] = 1;
+ c[9] = 1; c[10] = 0; c[11] = 1;
+ obj->NumVerts = 4;
+ obj->VertexOffset = 0;
+ obj->ColorOffset = 3 * sizeof(GLfloat) * obj->NumVerts;
+ obj->NumElements = 0;
+
+ glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+
+ glGetBufferPointervARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAP_POINTER_ARB, &p);
+ assert(!p);
+
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAPPED_ARB, &i);
+ assert(!i);
+}
+
+
+static void MakeObject2(struct object *obj)
+{
+ GLfloat *v, *c;
+
+ glGenBuffersARB(1, &obj->BufferID);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->BufferID);
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB, 1000, NULL, GL_STATIC_DRAW_ARB);
+ v = (GLfloat *) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+
+ /* Make triangle */
+ v[0] = -1; v[1] = -1; v[2] = 0;
+ v[3] = 1; v[4] = -1; v[5] = 0;
+ v[6] = 0; v[7] = 1; v[8] = 0;
+ c = v + 9;
+ c[0] = 0; c[1] = 1; c[2] = 0;
+ c[3] = 0; c[4] = 1; c[5] = 0;
+ c[6] = 1; c[7] = 1; c[8] = 0;
+ obj->NumVerts = 3;
+ obj->VertexOffset = 0;
+ obj->ColorOffset = 3 * sizeof(GLfloat) * obj->NumVerts;
+ obj->NumElements = 0;
+
+ glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+}
+
+
+static void MakeObject3(struct object *obj)
+{
+ GLfloat vertexData[1000];
+ GLfloat *v, *c;
+ GLuint *i;
+ int bytes;
+
+ /* Make rectangle */
+ v = vertexData;
+ v[0] = -1; v[1] = -0.5; v[2] = 0;
+ v[3] = 1; v[4] = -0.5; v[5] = 0;
+ v[6] = 1; v[7] = 0.5; v[8] = 0;
+ v[9] = -1; v[10] = 0.5; v[11] = 0;
+ c = vertexData + 12;
+ c[0] = 0; c[1] = 0; c[2] = 1;
+ c[3] = 0; c[4] = 0; c[5] = 1;
+ c[6] = 0; c[7] = 1; c[8] = 1;
+ c[9] = 0; c[10] = 1; c[11] = 1;
+ obj->NumVerts = 4;
+ obj->VertexOffset = 0;
+ obj->ColorOffset = 3 * sizeof(GLfloat) * obj->NumVerts;
+
+ bytes = obj->NumVerts * (3 + 3) * sizeof(GLfloat);
+
+ /* Don't use glMap/UnmapBuffer for this object */
+ glGenBuffersARB(1, &obj->BufferID);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->BufferID);
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB, bytes, vertexData, GL_STATIC_DRAW_ARB);
+
+ /* Setup a buffer of indices to test the ELEMENTS path */
+ glGenBuffersARB(1, &obj->ElementsBufferID);
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, obj->ElementsBufferID);
+ glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 100, NULL, GL_STATIC_DRAW_ARB);
+ i = (GLuint *) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_READ_WRITE_ARB);
+ i[0] = 0;
+ i[1] = 1;
+ i[2] = 2;
+ i[3] = 3;
+ glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+ obj->NumElements = 4;
+}
+
+
+
+static void Init( void )
+{
+ if (!glutExtensionSupported("GL_ARB_vertex_buffer_object")) {
+ printf("GL_ARB_vertex_buffer_object not found!\n");
+ exit(0);
+ }
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ /* Test buffer object deletion */
+ if (1) {
+ static GLubyte data[1000];
+ GLuint id = 999;
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, id);
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB, 1000, data, GL_STATIC_DRAW_ARB);
+ glVertexPointer(3, GL_FLOAT, 0, (void *) 0);
+ glDeleteBuffersARB(1, &id);
+ assert(!glIsBufferARB(id));
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ glVertexPointer(3, GL_FLOAT, 0, (void *) 0);
+ assert(!glIsBufferARB(id));
+ }
+
+ MakeObject1(Objects + 0);
+ MakeObject2(Objects + 1);
+ MakeObject3(Objects + 2);
+ NumObjects = 3;
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 600, 300 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ Win = glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/bug_3050.c b/tests/mesa/tests/bug_3050.c
new file mode 100644
index 00000000..4ea7b80f
--- /dev/null
+++ b/tests/mesa/tests/bug_3050.c
@@ -0,0 +1,162 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file bug_3050.c
+ *
+ * Simple regression test for bug #3050. Create a texture and make a few
+ * calls to \c glGetTexLevelParameteriv. If the bug still exists, trying
+ * to get \c GL_TEXTURE_WITDH will cause a protocol error.
+ *
+ * This test \b only applies to indirect-rendering. This may mean that the
+ * test needs to be run with the environment variable \c LIBGL_ALWAYS_INDIRECT
+ * set to a non-zero value.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <GL/glut.h>
+
+static int Width = 400;
+static int Height = 200;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+}
+
+
+static void Reshape( int width, int height )
+{
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ unsigned i;
+ static const GLenum pnames[] = {
+ GL_TEXTURE_RED_SIZE,
+ GL_TEXTURE_GREEN_SIZE,
+ GL_TEXTURE_BLUE_SIZE,
+ GL_TEXTURE_ALPHA_SIZE,
+ GL_TEXTURE_LUMINANCE_SIZE,
+ GL_TEXTURE_INTENSITY_SIZE,
+ GL_TEXTURE_BORDER,
+ GL_TEXTURE_INTERNAL_FORMAT,
+ GL_TEXTURE_WIDTH,
+ GL_TEXTURE_HEIGHT,
+ GL_TEXTURE_DEPTH,
+ ~0
+ };
+
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+
+ printf("\nThis program should log some data about a texture and exit.\n");
+ printf("This is a regression test for bug #3050. If the bug still\n");
+ printf("exists, a GLX protocol error will be generated.\n");
+ printf("https://bugs.freedesktop.org/show_bug.cgi?id=3050\n\n");
+
+
+ if ( ! glutExtensionSupported( "GL_NV_texture_rectangle" )
+ && ! glutExtensionSupported( "GL_EXT_texture_rectangle" )
+ && ! glutExtensionSupported( "GL_ARB_texture_rectangle" ) ) {
+ printf( "This test requires one of GL_ARB_texture_rectangle, GL_EXT_texture_rectangle,\n"
+ "or GL_NV_texture_rectangle be supported\n." );
+ exit( 1 );
+ }
+
+
+ glBindTexture( GL_TEXTURE_RECTANGLE_NV, 1 );
+ glTexImage2D( GL_PROXY_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, 8, 8, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+
+ for ( i = 0 ; pnames[i] != ~0 ; i++ ) {
+ GLint param_i;
+ GLfloat param_f;
+ GLenum err;
+
+ glGetTexLevelParameteriv( GL_PROXY_TEXTURE_RECTANGLE_NV, 0, pnames[i], & param_i );
+ err = glGetError();
+
+ if ( err ) {
+ printf("glGetTexLevelParameteriv(GL_PROXY_TEXTURE_RECTANGLE_NV, 0, 0x%04x, & param) generated a GL\n"
+ "error of 0x%04x!",
+ pnames[i], err );
+ exit( 1 );
+ }
+ else {
+ printf("glGetTexLevelParameteriv(GL_PROXY_TEXTURE_RECTANGLE_NV, 0, 0x%04x, & param) = 0x%04x\n",
+ pnames[i], param_i );
+ }
+
+
+ glGetTexLevelParameterfv( GL_PROXY_TEXTURE_RECTANGLE_NV, 0, pnames[i], & param_f );
+ err = glGetError();
+
+ if ( err ) {
+ printf("glGetTexLevelParameterfv(GL_PROXY_TEXTURE_RECTANGLE_NV, 0, 0x%04x, & param) generated a GL\n"
+ "error of 0x%04x!\n",
+ pnames[i], err );
+ exit( 1 );
+ }
+ else {
+ printf("glGetTexLevelParameterfv(GL_PROXY_TEXTURE_RECTANGLE_NV, 0, 0x%04x, & param) = %.1f (0x%04x)\n",
+ pnames[i], param_f, (GLint) param_f );
+ }
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "Bug #3050 Test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ return 0;
+}
diff --git a/tests/mesa/tests/bug_3101.c b/tests/mesa/tests/bug_3101.c
new file mode 100644
index 00000000..761dcbb9
--- /dev/null
+++ b/tests/mesa/tests/bug_3101.c
@@ -0,0 +1,128 @@
+/*
+ * (C) Copyright IBM Corporation 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file bug_3101.c
+ *
+ * Simple regression test for bug #3101. Attempt to draw a single square.
+ * After emiting the first vertex, call \c glEdgeFlag to change the vertex
+ * format. If the bug still exists, this will cause a segfault.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+
+static int Width = 400;
+static int Height = 200;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+
+ /* This is the "reference" square.
+ */
+
+ glTranslatef(-4.5, 0, 0);
+ glBlendEquation( GL_FUNC_ADD );
+ glBlendFunc( GL_ONE, GL_ZERO );
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glEdgeFlag(GL_TRUE);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ printf("\nThis program should draw a single square, but not crash.\n");
+ printf("This is a regression test for bug #3101.\n");
+ printf("https://bugs.freedesktop.org/show_bug.cgi?id=3101\n");
+ glEnable( GL_BLEND );
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "Bug #3101 Test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/bug_3195.c b/tests/mesa/tests/bug_3195.c
new file mode 100644
index 00000000..4aceae04
--- /dev/null
+++ b/tests/mesa/tests/bug_3195.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file bug_3195.c
+ *
+ * Simple regression test for bug #3195. A bug in the i180 driver caused
+ * a segfault (inside the driver) when the LOD bias is adjusted and no texture
+ * is enabled. This test, which is based on progs/demos/lodbias.c, sets up
+ * all the texturing, disables all textures, adjusts the LOD bias, then
+ * re-enables \c GL_TEXTURE_2D.
+ *
+ * \author Brian Paul
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <GL/glut.h>
+#include <GL/glext.h>
+
+#include "readtex.h"
+
+#define TEXTURE_FILE "../images/girl.rgb"
+
+static GLfloat Xrot = 0, Yrot = -30, Zrot = 0;
+static GLint Bias = 0, BiasStepSign = +1; /* ints avoid fp precision problem */
+static GLint BiasMin = -400, BiasMax = 400;
+
+
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+static void Idle( void )
+{
+ static int lastTime = 0;
+ int time = glutGet(GLUT_ELAPSED_TIME);
+ int step;
+
+ if (lastTime == 0)
+ lastTime = time;
+ else if (time - lastTime < 10)
+ return;
+
+ step = (time - lastTime) / 10 * BiasStepSign;
+ lastTime = time;
+
+ Bias += step;
+ if (Bias < BiasMin) {
+ exit(0);
+ }
+ else if (Bias > BiasMax) {
+ Bias = BiasMax;
+ BiasStepSign = -1;
+ }
+
+ glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+ char str[100];
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho(-1, 1, -1, 1, -1, 1);
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glDisable(GL_TEXTURE_2D);
+ glColor3f(1,1,1);
+ glRasterPos3f(-0.9, -0.9, 0.0);
+ sprintf(str, "Texture LOD Bias = %4.1f", Bias * 0.01);
+ PrintString(str);
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -8.0 );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+
+ glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.01 * Bias);
+ glEnable(GL_TEXTURE_2D);
+
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-1, -1);
+ glTexCoord2f(2, 0); glVertex2f( 1, -1);
+ glTexCoord2f(2, 2); glVertex2f( 1, 1);
+ glTexCoord2f(0, 2); glVertex2f(-1, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ GLfloat maxBias;
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ printf("\nThis program should function nearly identically to Mesa's lodbias demo.\n"
+ "It should cycle through the complet LOD bias range once and exit. If bug\n"
+ "#3195 still exists, the demo should crash almost immediatly.\n");
+ printf("This is a regression test for bug #3195.\n");
+ printf("https://bugs.freedesktop.org/show_bug.cgi?id=3195\n");
+
+ if (!glutExtensionSupported("GL_EXT_texture_lod_bias")) {
+ printf("Sorry, GL_EXT_texture_lod_bias not supported by this renderer.\n");
+ exit(1);
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ if (glutExtensionSupported("GL_SGIS_generate_mipmap")) {
+ /* test auto mipmap generation */
+ GLint width, height, i;
+ GLenum format;
+ GLubyte *image = LoadRGBImage(TEXTURE_FILE, &width, &height, &format);
+ if (!image) {
+ printf("Error: could not load texture image %s\n", TEXTURE_FILE);
+ exit(1);
+ }
+ /* resize to 256 x 256 */
+ if (width != 256 || height != 256) {
+ GLubyte *newImage = malloc(256 * 256 * 4);
+ gluScaleImage(format, width, height, GL_UNSIGNED_BYTE, image,
+ 256, 256, GL_UNSIGNED_BYTE, newImage);
+ free(image);
+ image = newImage;
+ }
+ printf("Using GL_SGIS_generate_mipmap\n");
+ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
+ glTexImage2D(GL_TEXTURE_2D, 0, format, 256, 256, 0,
+ format, GL_UNSIGNED_BYTE, image);
+ free(image);
+
+ /* make sure mipmap was really generated correctly */
+ width = height = 256;
+ for (i = 0; i < 9; i++) {
+ GLint w, h;
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_WIDTH, &w);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_HEIGHT, &h);
+ printf("Level %d size: %d x %d\n", i, w, h);
+ assert(w == width);
+ assert(h == height);
+ width /= 2;
+ height /= 2;
+ }
+
+ }
+ else if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
+ printf("Error: could not load texture image %s\n", TEXTURE_FILE);
+ exit(1);
+ }
+
+ /* mipmapping required for this extension */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &maxBias);
+ printf("LOD bias range: [%g, %g]\n", -maxBias, maxBias);
+ BiasMin = -100 * maxBias;
+ BiasMax = 100 * maxBias;
+
+ /* Since we have (about) 8 mipmap levels, no need to bias beyond
+ * the range [-1, +8].
+ */
+ if (BiasMin < -100)
+ BiasMin = -100;
+ if (BiasMax > 800)
+ BiasMax = 800;
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 350, 350 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "Bug #3195 Test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/copypixrate.c b/tests/mesa/tests/copypixrate.c
new file mode 100644
index 00000000..e9a42a1c
--- /dev/null
+++ b/tests/mesa/tests/copypixrate.c
@@ -0,0 +1,259 @@
+/*
+ * Measure glCopyPixels speed
+ *
+ * Brian Paul
+ * 26 Jan 2006
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static GLint WinWidth = 1000, WinHeight = 800;
+static GLint ImgWidth, ImgHeight;
+
+static GLenum Buffer = GL_FRONT;
+static GLenum AlphaTest = GL_FALSE;
+static GLboolean UseBlit = GL_FALSE;
+
+static PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT_func = NULL;
+
+
+/**
+ * draw teapot in lower-left corner of window
+ */
+static void
+DrawTestImage(void)
+{
+ GLfloat ar;
+
+ ImgWidth = WinWidth / 3;
+ ImgHeight = WinHeight / 3;
+
+ glViewport(0, 0, ImgWidth, ImgHeight);
+ glScissor(0, 0, ImgWidth, ImgHeight);
+ glEnable(GL_SCISSOR_TEST);
+
+ glClearColor(0.5, 0.5, 0.5, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ar = (float) WinWidth / WinHeight;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-ar, ar, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+ glFrontFace(GL_CW);
+ glPushMatrix();
+ glRotatef(45, 1, 0, 0);
+ glutSolidTeapot(2.0);
+ glPopMatrix();
+ glFrontFace(GL_CCW);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_SCISSOR_TEST);
+
+ glViewport(0, 0, WinWidth, WinHeight);
+ glFinish();
+}
+
+
+static int
+Rand(int max)
+{
+ return ((int) random()) % max;
+}
+
+
+/**
+ * Measure glCopyPixels rate
+ */
+static void
+RunTest(void)
+{
+ double t1, t0 = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+ int iters = 0;
+ float copyRate, mbRate;
+ int r, g, b, a, bpp;
+
+ if (AlphaTest) {
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(GL_GREATER, 0.0);
+ }
+
+ glGetIntegerv(GL_RED_BITS, &r);
+ glGetIntegerv(GL_GREEN_BITS, &g);
+ glGetIntegerv(GL_BLUE_BITS, &b);
+ glGetIntegerv(GL_ALPHA_BITS, &a);
+ bpp = (r + g + b + a) / 8;
+
+ do {
+ int x, y;
+ x = Rand(WinWidth);
+ y = Rand(WinHeight);
+
+ if (x > ImgWidth || y > ImgHeight) {
+#ifdef GL_EXT_framebuffer_blit
+ if (UseBlit)
+ {
+ glBlitFramebufferEXT_func(0, 0, ImgWidth, ImgHeight,
+ x, y, x + ImgWidth, y + ImgHeight,
+ GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ }
+ else
+#endif
+ {
+ glWindowPos2iARB(x, y);
+ glCopyPixels(0, 0, ImgWidth, ImgHeight, GL_COLOR);
+ }
+ glFinish(); /* XXX OK? */
+
+ iters++;
+
+ t1 = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+ }
+ } while (t1 - t0 < 5.0);
+
+ glDisable(GL_ALPHA_TEST);
+
+ copyRate = iters / (t1 - t0);
+ mbRate = ImgWidth * ImgHeight * bpp * copyRate / (1024 * 1024);
+
+ printf("Image size: %d x %d, %d Bpp\n", ImgWidth, ImgHeight, bpp);
+ printf("%d copies in %.2f = %.2f copies/sec, %.2f MB/s\n",
+ iters, t1-t0, copyRate, mbRate);
+}
+
+
+static void
+Draw(void)
+{
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glReadBuffer(Buffer);
+ glDrawBuffer(Buffer);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ DrawTestImage();
+
+ RunTest();
+
+ if (Buffer == GL_FRONT)
+ glFinish();
+ else
+ glutSwapBuffers();
+
+ printf("exiting\n");
+ exit(0);
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -15.0);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ break;
+ case GLUT_KEY_DOWN:
+ break;
+ case GLUT_KEY_LEFT:
+ break;
+ case GLUT_KEY_RIGHT:
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+ParseArgs(int argc, char *argv[])
+{
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-back") == 0)
+ Buffer = GL_BACK;
+ else if (strcmp(argv[i], "-alpha") == 0)
+ AlphaTest = GL_TRUE;
+ else if (strcmp(argv[i], "-blit") == 0)
+ UseBlit = GL_TRUE;
+ }
+}
+
+
+static void
+Init(void)
+{
+ if (glutExtensionSupported("GL_EXT_framebuffer_blit")) {
+ glBlitFramebufferEXT_func = (PFNGLBLITFRAMEBUFFEREXTPROC)
+ glutGetProcAddress("glBlitFramebufferEXT");
+ }
+ else if (UseBlit) {
+ printf("Warning: GL_EXT_framebuffer_blit not supported.\n");
+ UseBlit = GL_FALSE;
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ GLint mode = GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH;
+ glutInit(&argc, argv);
+
+ ParseArgs(argc, argv);
+ if (AlphaTest)
+ mode |= GLUT_ALPHA;
+
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(WinWidth, WinHeight);
+ glutInitDisplayMode(mode);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Draw);
+
+ printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
+ printf("Draw Buffer: %s\n", (Buffer == GL_BACK) ? "Back" : "Front");
+ Init();
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/crossbar.c b/tests/mesa/tests/crossbar.c
new file mode 100644
index 00000000..2a8452ff
--- /dev/null
+++ b/tests/mesa/tests/crossbar.c
@@ -0,0 +1,305 @@
+/*
+ * (C) Copyright IBM Corporation 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file crossbar.c
+ *
+ * Simple test of GL_ARB_texture_env_crossbar functionality. Several squares
+ * are drawn with different texture combine modes, but all should be rendered
+ * with the same final color.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <GL/glut.h>
+
+static const GLint tests[][8] = {
+ { 1, GL_REPLACE, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR,
+ 2, GL_REPLACE, GL_TEXTURE, GL_PRIMARY_COLOR },
+ { 3, GL_REPLACE, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR,
+ 2, GL_SUBTRACT, GL_TEXTURE0, GL_TEXTURE1 },
+ { 2, GL_REPLACE, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR,
+ 2, GL_REPLACE, GL_TEXTURE0, GL_TEXTURE0 },
+ { 2, GL_REPLACE, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR,
+ 1, GL_SUBTRACT, GL_TEXTURE0, GL_TEXTURE1 },
+ { 3, GL_ADD, GL_TEXTURE1, GL_TEXTURE1,
+ 2, GL_MODULATE, GL_TEXTURE1, GL_PREVIOUS },
+ { 3, GL_ADD, GL_TEXTURE1, GL_TEXTURE1,
+ 4, GL_MODULATE, GL_TEXTURE0, GL_PREVIOUS },
+};
+
+#define NUM_TESTS (sizeof(tests) / sizeof(tests[0]))
+
+static int Width = 100 * (NUM_TESTS + 1);
+static int Height = 100;
+static int Interactive = 1;
+
+
+static void DoFrame( void )
+{
+ unsigned i;
+
+ glClearColor(0.0, 0.0, 1.0, 0);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+
+ /* This is the "reference" square.
+ */
+
+ glActiveTexture( GL_TEXTURE0 );
+ glDisable( GL_TEXTURE_2D );
+ glActiveTexture( GL_TEXTURE1 );
+ glDisable( GL_TEXTURE_2D );
+
+ glTranslatef(1.5, 0.0, 0.0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+ for ( i = 0 ; i < NUM_TESTS ; i++ ) {
+ glActiveTexture( GL_TEXTURE0 );
+ glEnable( GL_TEXTURE_2D );
+ glBindTexture( GL_TEXTURE_2D, tests[i][0] );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
+ glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, tests[i][1] );
+ glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, tests[i][2] );
+ glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, tests[i][3] );
+
+ glActiveTexture( GL_TEXTURE1 );
+ glEnable( GL_TEXTURE_2D );
+ glBindTexture( GL_TEXTURE_2D, tests[i][4] );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
+ glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, tests[i][5] );
+ glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, tests[i][6] );
+ glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, tests[i][7] );
+
+ glCallList(1);
+ }
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+static int DoTest( void )
+{
+ int i;
+ GLfloat probe[NUM_TESTS+1][4];
+ GLfloat dr, dg, db;
+ GLfloat dmax;
+
+ glReadBuffer( GL_FRONT );
+
+ dmax = 0;
+ for( i = 0; i <= NUM_TESTS; ++i ) {
+ glReadPixels(Width*(2*i+1)/((NUM_TESTS+1)*2), Height/2, 1, 1, GL_RGBA, GL_FLOAT, probe[i]);
+ printf("Probe %i: %f,%f,%f\n", i, probe[i][0], probe[i][1], probe[i][2]);
+ dr = probe[i][0] - 0.5f;
+ dg = probe[i][1] - 0.5f;
+ db = probe[i][2] - 0.5f;
+ printf(" Delta: %f,%f,%f\n", dr, dg, db);
+ if (dr > dmax) dmax = dr;
+ else if (-dr > dmax) dmax = -dr;
+ if (dg > dmax) dmax = dg;
+ else if (-dg > dmax) dmax = -dg;
+ if (db > dmax) dmax = db;
+ else if (-db > dmax) dmax = -db;
+ }
+
+ printf("Max delta: %f\n", dmax);
+
+ if (dmax >= 0.07) // roughly 1/128
+ return 0;
+ else
+ return 1;
+}
+
+static void Display( void )
+{
+ if (Interactive) {
+ DoFrame();
+ } else {
+ int success, retry;
+
+ printf("\nFirst frame\n-----------\n");
+ DoFrame();
+ success = DoTest();
+
+ printf("\nSecond frame\n------------\n");
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0, 3*(NUM_TESTS+1), -1.5, 1.5, -1, 1 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ DoFrame();
+ retry = DoTest();
+
+ if (retry && success) {
+ printf("\nPIGLIT: { 'result': 'pass' }\n");
+ } else if (retry || success) {
+ printf("\nPIGLIT: { 'result': 'warn', 'note': 'Inconsistent results in first and second frame' }\n");
+ } else {
+ printf("\nPIGLIT: { 'result': 'fail' }\n");
+ }
+
+ exit(0);
+ }
+}
+
+
+static void Reshape( int width, int height )
+{
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0, 3*(NUM_TESTS+1), -1.5, 1.5, -1, 1 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+ float ver = strtof( ver_string, NULL );
+ GLint tex_units;
+ GLint temp[ 256 ];
+
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ if ( (!glutExtensionSupported("GL_ARB_multitexture")
+ && (ver < 1.3))
+ || (!glutExtensionSupported("GL_ARB_texture_env_combine")
+ && !glutExtensionSupported("GL_EXT_texture_env_combine")
+ && (ver < 1.3))
+ || (!glutExtensionSupported("GL_ARB_texture_env_crossbar")
+ && !glutExtensionSupported("GL_NV_texture_env_combine4")
+ && (ver < 1.4)) ) {
+ printf("\nSorry, this program requires GL_ARB_multitexture and either\n"
+ "GL_ARB_texture_env_combine or GL_EXT_texture_env_combine (or OpenGL 1.3).\n"
+ "Either GL_ARB_texture_env_crossbar or GL_NV_texture_env_combine4 (or\n"
+ "OpenGL 1.4) are also required.\n");
+ if (!Interactive)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+
+ glGetIntegerv( GL_MAX_TEXTURE_UNITS, & tex_units );
+ if ( tex_units < 2 ) {
+ printf("\nSorry, this program requires at least 2 texture units.\n");
+ if (!Interactive)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+
+ if (Interactive)
+ printf("\nAll %u squares should be the same color.\n", NUM_TESTS + 1);
+
+ (void) memset( temp, 0x00, sizeof( temp ) );
+ glBindTexture( GL_TEXTURE_2D, 1 );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, temp );
+
+ (void) memset( temp, 0x7f, sizeof( temp ) );
+ glBindTexture( GL_TEXTURE_2D, 2 );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, temp );
+
+ (void) memset( temp, 0xff, sizeof( temp ) );
+ glBindTexture( GL_TEXTURE_2D, 3 );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, temp );
+
+ (void) memset( temp, 0x3f, sizeof( temp ) );
+ glBindTexture( GL_TEXTURE_2D, 4 );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, temp );
+
+
+ glNewList( 1, GL_COMPILE );
+ glTranslatef(3.0, 0, 0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.9, 0.0, 0.0 );
+ glMultiTexCoord2f( GL_TEXTURE0, 0.5, 0.5 );
+ glMultiTexCoord2f( GL_TEXTURE1, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+ glEndList();
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ if (argc == 2 && !strcmp(argv[1], "-auto"))
+ Interactive = 0;
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "GL_ARB_texture_env_crossbar test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/cva.c b/tests/mesa/tests/cva.c
new file mode 100644
index 00000000..c7677990
--- /dev/null
+++ b/tests/mesa/tests/cva.c
@@ -0,0 +1,164 @@
+/* $Id: cva.c,v 1.8 2006/11/22 19:37:21 sroland Exp $ */
+
+/*
+ * Trivial CVA test, good for testing driver fastpaths (especially
+ * indexed vertex buffers if they are supported).
+ *
+ * Gareth Hughes
+ * November 2000
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef __VMS
+# include <stddef.h> /* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
+#else
+# include <malloc.h> /* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#define GL_GLEXT_LEGACY
+#include <GL/glut.h>
+
+
+GLfloat verts[][4] = {
+ { -0.5, -0.5, -2.0, 0.0 },
+ { 0.5, -0.5, -2.0, 0.0 },
+ { -0.5, 0.5, -2.0, 0.0 },
+ { 0.5, 0.5, -2.0, 0.0 },
+};
+
+GLubyte color[][4] = {
+ { 0xff, 0x00, 0x00, 0x00 },
+ { 0x00, 0xff, 0x00, 0x00 },
+ { 0x00, 0x00, 0xff, 0x00 },
+ { 0xff, 0xff, 0xff, 0x00 },
+};
+
+GLuint indices[] = { 0, 1, 2, 3 };
+
+GLboolean compiled = GL_TRUE;
+GLboolean doubleBuffer = GL_TRUE;
+
+
+void init( void )
+{
+ glClearColor( 0.0, 0.0, 0.0, 0.0 );
+ glShadeModel( GL_SMOOTH );
+
+ glFrontFace( GL_CCW );
+ glCullFace( GL_BACK );
+ glEnable( GL_CULL_FACE );
+
+ glEnable( GL_DEPTH_TEST );
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glEnableClientState( GL_COLOR_ARRAY );
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 2.0, 10.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glVertexPointer( 3, GL_FLOAT, sizeof(verts[0]), verts );
+ glColorPointer( 4, GL_UNSIGNED_BYTE, 0, color );
+
+#ifdef GL_EXT_compiled_vertex_array
+ if ( compiled ) {
+ glLockArraysEXT( 0, 4 );
+ }
+#endif
+}
+
+void display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glDrawElements( GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices );
+
+ glFlush();
+ if ( doubleBuffer ) {
+ glutSwapBuffers();
+ }
+}
+
+void keyboard( unsigned char key, int x, int y )
+{
+ switch ( key ) {
+ case 27:
+ exit( 0 );
+ break;
+ }
+
+ glutPostRedisplay();
+}
+
+GLboolean args( int argc, char **argv )
+{
+ GLint i;
+
+ doubleBuffer = GL_TRUE;
+
+ for ( i = 1 ; i < argc ; i++ ) {
+ if ( strcmp( argv[i], "-sb" ) == 0 ) {
+ doubleBuffer = GL_FALSE;
+ } else if ( strcmp( argv[i], "-db" ) == 0 ) {
+ doubleBuffer = GL_TRUE;
+ } else {
+ fprintf( stderr, "%s (Bad option).\n", argv[i] );
+ return GL_FALSE;
+ }
+ }
+ return GL_TRUE;
+}
+
+int main( int argc, char **argv )
+{
+ GLenum type;
+ char *string;
+ double version;
+
+ glutInit( &argc, argv );
+
+ if ( args( argc, argv ) == GL_FALSE ) {
+ exit( 1 );
+ }
+
+ type = GLUT_RGB | GLUT_DEPTH;
+ type |= ( doubleBuffer ) ? GLUT_DOUBLE : GLUT_SINGLE;
+
+ glutInitDisplayMode( type );
+ glutInitWindowSize( 250, 250 );
+ glutInitWindowPosition( 100, 100 );
+ glutCreateWindow( "CVA Test" );
+
+ /* Make sure the server supports GL 1.2 vertex arrays.
+ */
+ string = (char *) glGetString( GL_VERSION );
+
+ version = atof(string);
+ if ( version < 1.2 ) {
+ fprintf( stderr, "This program requires OpenGL 1.2 vertex arrays.\n" );
+ exit( -1 );
+ }
+
+ /* See if the server supports compiled vertex arrays.
+ */
+ string = (char *) glGetString( GL_EXTENSIONS );
+
+ if ( !strstr( string, "GL_EXT_compiled_vertex_array" ) ) {
+ fprintf( stderr, "Compiled vertex arrays not supported by this renderer.\n" );
+ compiled = GL_FALSE;
+ }
+
+ init();
+
+ glutDisplayFunc( display );
+ glutKeyboardFunc( keyboard );
+ glutMainLoop();
+
+ return 0;
+}
diff --git a/tests/mesa/tests/debugger.c b/tests/mesa/tests/debugger.c
new file mode 100644
index 00000000..4c6955bc
--- /dev/null
+++ b/tests/mesa/tests/debugger.c
@@ -0,0 +1,733 @@
+/*
+ * Test the GL_MESA_program_debug extension
+ */
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+
+/*
+ * Print the string with line numbers
+ */
+static void list_program(const GLubyte *string, GLsizei len)
+{
+ const char *c = (const char *) string;
+ int i, line = 1, printNumber = 1;
+
+ for (i = 0; i < len; i++) {
+ if (printNumber) {
+ printf("%3d ", line);
+ printNumber = 0;
+ }
+ if (*c == '\n') {
+ line++;
+ printNumber = 1;
+ }
+ putchar(*c);
+ c++;
+ }
+ putchar('\n');
+}
+
+
+/*
+ * Return the line number and column number that corresponds to the
+ * given program position. Also return a null-terminated copy of that
+ * line of the program string.
+ */
+static const GLubyte *
+find_line_column(const GLubyte *string, const GLubyte *pos,
+ GLint *line, GLint *col)
+{
+ const GLubyte *lineStart = string;
+ const GLubyte *p = string;
+ GLubyte *s;
+ int len;
+
+ *line = 1;
+
+ while (p != pos) {
+ if (*p == (GLubyte) '\n') {
+ (*line)++;
+ lineStart = p + 1;
+ }
+ p++;
+ }
+
+ *col = (pos - lineStart) + 1;
+
+ /* return copy of this line */
+ while (*p != 0 && *p != '\n')
+ p++;
+ len = p - lineStart;
+ s = (GLubyte *) malloc(len + 1);
+ memcpy(s, lineStart, len);
+ s[len] = 0;
+
+ return s;
+}
+
+
+#define ARB_VERTEX_PROGRAM 1
+#define ARB_FRAGMENT_PROGRAM 2
+#define NV_VERTEX_PROGRAM 3
+#define NV_FRAGMENT_PROGRAM 4
+
+
+struct breakpoint {
+ enum {PIXEL, LINE} type;
+ int x, y;
+ int line;
+ GLboolean enabled;
+};
+
+#define MAX_BREAKPOINTS 100
+static struct breakpoint Breakpoints[MAX_BREAKPOINTS];
+static int NumBreakpoints = 0;
+
+
+
+/*
+ * Interactive debugger
+ */
+static void Debugger2(GLenum target, GLvoid *data)
+{
+ static GLuint skipCount = 0;
+ const GLubyte *ln;
+ GLint pos, line, column;
+ GLint id;
+ int progType;
+ GLint len;
+ GLubyte *program;
+ GLboolean stop;
+ int i;
+
+ /* Sigh, GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV so it's a bit
+ * hard to distinguish between them.
+ */
+ if (target == GL_FRAGMENT_PROGRAM_ARB)
+ progType = ARB_FRAGMENT_PROGRAM;
+ else if (target == GL_FRAGMENT_PROGRAM_NV)
+ progType = NV_FRAGMENT_PROGRAM;
+ else
+ progType = NV_VERTEX_PROGRAM;
+
+ /* Until we hit zero, continue rendering */
+ if (skipCount > 0) {
+ skipCount--;
+ return;
+ }
+
+ /* Get id of the program and current position */
+ switch (progType) {
+ case ARB_FRAGMENT_PROGRAM:
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
+ glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
+ break;
+ case NV_FRAGMENT_PROGRAM:
+ glGetIntegerv(GL_FRAGMENT_PROGRAM_BINDING_NV, &id);
+ glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
+ break;
+ case ARB_VERTEX_PROGRAM:
+ glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
+ glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
+ break;
+ case NV_VERTEX_PROGRAM:
+ glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &id);
+ glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
+ break;
+ default:
+ abort();
+ }
+
+ /* get program string */
+ if (progType == ARB_VERTEX_PROGRAM ||
+ progType == ARB_FRAGMENT_PROGRAM)
+ glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &len);
+ else
+ glGetProgramivNV(id, GL_PROGRAM_LENGTH_NV, &len);
+ program = malloc(len + 1);
+ if (progType == ARB_VERTEX_PROGRAM ||
+ progType == ARB_FRAGMENT_PROGRAM)
+ glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, program);
+ else
+ glGetProgramStringNV(id, GL_PROGRAM_STRING_NV, program);
+
+
+ /* Get current line number, column, line string */
+ ln = find_line_column(program, program + pos, &line, &column);
+
+ /* test breakpoints */
+ if (NumBreakpoints > 0)
+ stop = GL_FALSE;
+ else
+ stop = GL_TRUE;
+ for (i = 0; i < NumBreakpoints; i++) {
+ if (Breakpoints[i].enabled) {
+ switch (Breakpoints[i].type) {
+ case PIXEL:
+ if (progType == ARB_FRAGMENT_PROGRAM) {
+
+ }
+ else if (progType == NV_FRAGMENT_PROGRAM) {
+ GLfloat pos[4];
+ int px, py;
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ 6, (GLubyte *) "f[WPOS]", pos);
+ px = (int) pos[0];
+ py = (int) pos[1];
+ printf("%d, %d\n", px, py);
+ if (px == Breakpoints[i].x &&
+ py == Breakpoints[i].y) {
+ printf("Break at pixel (%d, %d)\n", px, py);
+ stop = GL_TRUE;
+ }
+ }
+ break;
+ case LINE:
+ if (line == Breakpoints[i].line) {
+ /* hit a breakpoint! */
+ printf("Break at line %d\n", line);
+ stop = GL_TRUE;
+ }
+ break;
+ }
+ }
+ }
+ if (!stop) {
+ free(program);
+ return;
+ }
+
+ printf("%d: %s\n", line, ln);
+
+ /* get commands from stdin */
+ while (1) {
+ char command[1000], *cmd;
+
+ /* print prompt and get command */
+ printf("(%s %d) ", (target == GL_VERTEX_PROGRAM_ARB ? "vert" : "frag"),
+ line);
+ fgets(command, 999, stdin);
+
+ /* skip leading whitespace */
+ for (cmd = command; cmd[0] == ' '; cmd++)
+ ;
+
+ if (!cmd[0])
+ /* nothing (repeat the previous cmd?) */
+ continue;
+
+ switch (cmd[0]) {
+ case 's':
+ /* skip N instructions */
+ i = atoi(cmd + 2);
+ skipCount = i;
+ printf("Skipping %d instructions\n", i);
+ return;
+ case 'n':
+ /* next */
+ return;
+ case 'c':
+ return;
+ case 'd':
+ /* dump machine state */
+ if (progType == NV_FRAGMENT_PROGRAM) {
+ static const char *inRegs[] = {
+ "f[WPOS]", "f[COL0]", "f[COL1]", "f[FOGC]",
+ "f[TEX0]", "f[TEX1]", "f[TEX2]", "f[TEX3]",
+ NULL
+ };
+ static const char *outRegs[] = {
+ "o[COLR]", "o[COLH]", "o[DEPR]", NULL
+ };
+ GLfloat v[4];
+ int i;
+ printf("Fragment input attributes:\n");
+ for (i = 0; inRegs[i]; i++) {
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ strlen(inRegs[i]),
+ (const GLubyte *) inRegs[i], v);
+ printf(" %s: %g, %g, %g, %g\n", inRegs[i],
+ v[0], v[1], v[2], v[3]);
+ }
+ printf("Fragment output attributes:\n");
+ for (i = 0; outRegs[i]; i++) {
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ strlen(outRegs[i]),
+ (const GLubyte *) outRegs[i], v);
+ printf(" %s: %g, %g, %g, %g\n", outRegs[i],
+ v[0], v[1], v[2], v[3]);
+ }
+ printf("Temporaries:\n");
+ for (i = 0; i < 4; i++) {
+ char temp[100];
+ GLfloat v[4];
+ sprintf(temp, "R%d", i);
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ strlen(temp),
+ (const GLubyte *) temp, v);
+ printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
+ }
+ }
+ else if (progType == NV_VERTEX_PROGRAM) {
+ GLfloat v[4];
+ int i;
+ static const char *inRegs[] = {
+ "v[OPOS]", "v[WGHT]", "v[NRML]", "v[COL0]",
+ "v[COL1]", "v[FOGC]", "v[6]", "v[7]",
+ "v[TEX0]", "v[TEX1]", "v[TEX2]", "v[TEX3]",
+ "v[TEX4]", "v[TEX5]", "v[TEX6]", "v[TEX7]",
+ NULL
+ };
+ static const char *outRegs[] = {
+ "o[HPOS]", "o[COL0]", "o[COL1]", "o[BFC0]",
+ "o[BFC1]", "o[FOGC]", "o[PSIZ]",
+ "o[TEX0]", "o[TEX1]", "o[TEX2]", "o[TEX3]",
+ "o[TEX4]", "o[TEX5]", "o[TEX6]", "o[TEX7]",
+ NULL
+ };
+ printf("Vertex input attributes:\n");
+ for (i = 0; inRegs[i]; i++) {
+ glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
+ strlen(inRegs[i]),
+ (const GLubyte *) inRegs[i], v);
+ printf(" %s: %g, %g, %g, %g\n", inRegs[i],
+ v[0], v[1], v[2], v[3]);
+ }
+ printf("Vertex output attributes:\n");
+ for (i = 0; outRegs[i]; i++) {
+ glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
+ strlen(outRegs[i]),
+ (const GLubyte *) outRegs[i], v);
+ printf(" %s: %g, %g, %g, %g\n", outRegs[i],
+ v[0], v[1], v[2], v[3]);
+ }
+ printf("Temporaries:\n");
+ for (i = 0; i < 4; i++) {
+ char temp[100];
+ GLfloat v[4];
+ sprintf(temp, "R%d", i);
+ glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
+ strlen(temp),
+ (const GLubyte *) temp, v);
+ printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
+ }
+ }
+ break;
+ case 'l':
+ /* list */
+ list_program(program, len);
+ break;
+ case 'p':
+ /* print */
+ {
+ GLfloat v[4];
+ char *c;
+ cmd++;
+ while (*cmd == ' ')
+ cmd++;
+ c = cmd;
+ while (*c) {
+ if (*c == '\n' || *c == '\r')
+ *c = 0;
+ else
+ c++;
+ }
+ glGetProgramRegisterfvMESA(target, strlen(cmd),
+ (const GLubyte *) cmd, v);
+ if (glGetError() == GL_NO_ERROR)
+ printf("%s = %g, %g, %g, %g\n", cmd, v[0], v[1], v[2], v[3]);
+ else
+ printf("Invalid expression\n");
+ }
+ break;
+ case 'b':
+ if (cmd[1] == ' ' && isdigit(cmd[2])) {
+ char *comma = strchr(cmd, ',');
+ if (comma) {
+ /* break at pixel */
+ int x = atoi(cmd + 2);
+ int y = atoi(comma + 1);
+ if (NumBreakpoints < MAX_BREAKPOINTS) {
+ Breakpoints[NumBreakpoints].type = PIXEL;
+ Breakpoints[NumBreakpoints].x = x;
+ Breakpoints[NumBreakpoints].y = y;
+ Breakpoints[NumBreakpoints].enabled = GL_TRUE;
+ NumBreakpoints++;
+ printf("Breakpoint %d: break at pixel (%d, %d)\n",
+ NumBreakpoints, x, y);
+ }
+ }
+ else {
+ /* break at line */
+ int l = atoi(cmd + 2);
+ if (l && NumBreakpoints < MAX_BREAKPOINTS) {
+ Breakpoints[NumBreakpoints].type = LINE;
+ Breakpoints[NumBreakpoints].line = l;
+ Breakpoints[NumBreakpoints].enabled = GL_TRUE;
+ NumBreakpoints++;
+ printf("Breakpoint %d: break at line %d\n",
+ NumBreakpoints, l);
+ }
+ }
+ }
+ else {
+ /* list breakpoints */
+ printf("Breakpoints:\n");
+ for (i = 0; i < NumBreakpoints; i++) {
+ switch (Breakpoints[i].type) {
+ case LINE:
+ printf(" %d: break at line %d\n",
+ i + 1, Breakpoints[i].line);
+ break;
+ case PIXEL:
+ printf(" %d: break at pixel (%d, %d)\n",
+ i + 1, Breakpoints[i].x, Breakpoints[i].y);
+ break;
+ }
+ }
+ }
+ break;
+ case 'h':
+ /* help */
+ printf("Debugger commands:\n");
+ printf(" b list breakpoints\n");
+ printf(" b N break at line N\n");
+ printf(" b x,y break at pixel x,y\n");
+ printf(" c continue execution\n");
+ printf(" d display register values\n");
+ printf(" h help\n");
+ printf(" l list program\n");
+ printf(" n next instruction\n");
+ printf(" p V print value V\n");
+ printf(" s N skip N instructions\n");
+ break;
+ default:
+ printf("Unknown command: %c\n", cmd[0]);
+ }
+ }
+}
+
+
+/*
+ * Print current line, some registers, and continue.
+ */
+static void Debugger(GLenum target, GLvoid *data)
+{
+ GLint pos;
+ const GLubyte *ln;
+ GLint line, column;
+ GLfloat v[4];
+
+ assert(target == GL_FRAGMENT_PROGRAM_NV);
+
+ glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
+
+ ln = find_line_column((const GLubyte *) data, (const GLubyte *) data + pos,
+ &line, &column);
+ printf("%d:%d: %s\n", line, column, (char *) ln);
+
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ 2, (const GLubyte *) "R0", v);
+ printf(" R0 = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ 7, (const GLubyte *) "f[WPOS]", v);
+ printf(" o[WPOS] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ 7, (const GLubyte *) "o[COLR]", v);
+ printf(" o[COLR] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
+
+ free((void *) ln);
+}
+
+
+
+
+/**********************************************************************/
+
+static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 };
+static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 };
+static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 };
+static GLfloat Delta = 1.0;
+
+static GLuint FragProg;
+static GLuint VertProg;
+static GLboolean Anim = GL_TRUE;
+static GLboolean Wire = GL_FALSE;
+static GLboolean PixelLight = GL_TRUE;
+
+static GLfloat Xrot = 0, Yrot = 0;
+
+
+#define NAMED_PARAMETER4FV(prog, name, v) \
+ glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v)
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ if (PixelLight) {
+ NAMED_PARAMETER4FV(FragProg, "LightPos", LightPos);
+ glEnable(GL_FRAGMENT_PROGRAM_NV);
+ glEnable(GL_VERTEX_PROGRAM_NV);
+ glDisable(GL_LIGHTING);
+ }
+ else {
+ glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+ glDisable(GL_FRAGMENT_PROGRAM_NV);
+ glDisable(GL_VERTEX_PROGRAM_NV);
+ glEnable(GL_LIGHTING);
+ }
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+
+#if 1
+ glutSolidSphere(2.0, 10, 5);
+#else
+ {
+ GLUquadricObj *q = gluNewQuadric();
+ gluQuadricNormals(q, GL_SMOOTH);
+ gluQuadricTexture(q, GL_TRUE);
+ glRotatef(90, 1, 0, 0);
+ glTranslatef(0, 0, -1);
+ gluCylinder(q, 1.0, 1.0, 2.0, 24, 1);
+ gluDeleteQuadric(q);
+ }
+#endif
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Idle(void)
+{
+ LightPos[0] += Delta;
+ if (LightPos[0] > 25.0)
+ Delta = -1.0;
+ else if (LightPos[0] <- 25.0)
+ Delta = 1.0;
+ glutPostRedisplay();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ /*glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case ' ':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'x':
+ LightPos[0] -= 1.0;
+ break;
+ case 'X':
+ LightPos[0] += 1.0;
+ break;
+ case 'w':
+ Wire = !Wire;
+ if (Wire)
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ else
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ break;
+ case 'p':
+ PixelLight = !PixelLight;
+ if (PixelLight) {
+ printf("Per-pixel lighting\n");
+ }
+ else {
+ printf("Conventional lighting\n");
+ }
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( int argc, char *argv[] )
+{
+ static const char *fragProgramText =
+ "!!FP1.0\n"
+ "DECLARE Diffuse; \n"
+ "DECLARE Specular; \n"
+ "DECLARE LightPos; \n"
+
+ "# Compute normalized LightPos, put it in R0\n"
+ "DP3 R0.x, LightPos, LightPos;\n"
+ "RSQ R0.y, R0.x;\n"
+ "MUL R0, LightPos, R0.y;\n"
+
+ "# Compute normalized normal, put it in R1\n"
+ "DP3 R1, f[TEX0], f[TEX0]; \n"
+ "RSQ R1.y, R1.x;\n"
+ "MUL R1, f[TEX0], R1.y;\n"
+
+ "# Compute dot product of light direction and normal vector\n"
+ "DP3 R2, R0, R1;\n"
+
+ "MUL R3, Diffuse, R2; # diffuse attenuation\n"
+
+ "POW R4, R2.x, {20.0}.x; # specular exponent\n"
+
+ "MUL R5, Specular, R4; # specular attenuation\n"
+
+ "ADD o[COLR], R3, R5; # add diffuse and specular colors\n"
+ "END \n"
+ ;
+
+ static const char *vertProgramText =
+ "!!VP1.0\n"
+ "# typical modelview/projection transform\n"
+ "DP4 o[HPOS].x, c[0], v[OPOS] ;\n"
+ "DP4 o[HPOS].y, c[1], v[OPOS] ;\n"
+ "DP4 o[HPOS].z, c[2], v[OPOS] ;\n"
+ "DP4 o[HPOS].w, c[3], v[OPOS] ;\n"
+ "# transform normal by inv transpose of modelview, put in tex0\n"
+ "DP4 o[TEX0].x, c[4], v[NRML] ;\n"
+ "DP4 o[TEX0].y, c[5], v[NRML] ;\n"
+ "DP4 o[TEX0].z, c[6], v[NRML] ;\n"
+ "DP4 o[TEX0].w, c[7], v[NRML] ;\n"
+ "END\n";
+ ;
+
+ if (!glutExtensionSupported("GL_NV_vertex_program")) {
+ printf("Sorry, this demo requires GL_NV_vertex_program\n");
+ exit(1);
+ }
+ if (!glutExtensionSupported("GL_NV_fragment_program")) {
+ printf("Sorry, this demo requires GL_NV_fragment_program\n");
+ exit(1);
+ }
+
+ glGenProgramsNV(1, &FragProg);
+ assert(FragProg > 0);
+ glGenProgramsNV(1, &VertProg);
+ assert(VertProg > 0);
+
+ /*
+ * Fragment program
+ */
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg,
+ strlen(fragProgramText),
+ (const GLubyte *) fragProgramText);
+ assert(glIsProgramNV(FragProg));
+ glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg);
+
+ NAMED_PARAMETER4FV(FragProg, "Diffuse", Diffuse);
+ NAMED_PARAMETER4FV(FragProg, "Specular", Specular);
+
+ /*
+ * Vertex program
+ */
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, VertProg,
+ strlen(vertProgramText),
+ (const GLubyte *) vertProgramText);
+ assert(glIsProgramNV(VertProg));
+ glBindProgramNV(GL_VERTEX_PROGRAM_NV, VertProg);
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV);
+
+ /*
+ * Misc init
+ */
+ glClearColor(0.3, 0.3, 0.3, 0.0);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHTING);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("Press p to toggle between per-pixel and per-vertex lighting\n");
+
+#ifdef GL_MESA_program_debug
+ if (argc > 1 && strcmp(argv[1], "fragment") == 0) {
+ printf(">> Debugging fragment program\n");
+ glProgramCallbackMESA(GL_FRAGMENT_PROGRAM_ARB, Debugger2,
+ (GLvoid *) fragProgramText);
+ glEnable(GL_FRAGMENT_PROGRAM_CALLBACK_MESA);
+ }
+ else {
+ printf(">> Debugging vertex program\n");
+ glProgramCallbackMESA(GL_VERTEX_PROGRAM_ARB, Debugger2,
+ (GLvoid *) fragProgramText);
+ glEnable(GL_VERTEX_PROGRAM_CALLBACK_MESA);
+ }
+#endif
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 200, 200 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init(argc, argv);
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/dinoshade.c b/tests/mesa/tests/dinoshade.c
new file mode 100644
index 00000000..ed7b879b
--- /dev/null
+++ b/tests/mesa/tests/dinoshade.c
@@ -0,0 +1,914 @@
+
+/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
+
+/* This program is freely distributable without licensing fees
+ and is provided without guarantee or warrantee expressed or
+ implied. This program is -not- in the public domain. */
+
+/* Example for PC game developers to show how to *combine* texturing,
+ reflections, and projected shadows all in real-time with OpenGL.
+ Robust reflections use stenciling. Robust projected shadows
+ use both stenciling and polygon offset. PC game programmers
+ should realize that neither stenciling nor polygon offset are
+ supported by Direct3D, so these real-time rendering algorithms
+ are only really viable with OpenGL.
+
+ The program has modes for disabling the stenciling and polygon
+ offset uses. It is worth running this example with these features
+ toggled off so you can see the sort of artifacts that result.
+
+ Notice that the floor texturing, reflections, and shadowing
+ all co-exist properly. */
+
+/* When you run this program: Left mouse button controls the
+ view. Middle mouse button controls light position (left &
+ right rotates light around dino; up & down moves light
+ position up and down). Right mouse button pops up menu. */
+
+/* Check out the comments in the "redraw" routine to see how the
+ reflection blending and surface stenciling is done. You can
+ also see in "redraw" how the projected shadows are rendered,
+ including the use of stenciling and polygon offset. */
+
+/* This program is derived from glutdino.c */
+
+/* Compile: cc -o dinoshade dinoshade.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h> /* for cos(), sin(), and sqrt() */
+#ifdef __VMS
+# include <stddef.h> /* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
+#else
+# include <malloc.h> /* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#define GL_GLEXT_LEGACY
+#include <GL/glut.h> /* OpenGL Utility Toolkit header */
+
+/* Some <math.h> files do not define M_PI... */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Variable controlling various rendering modes. */
+static int stencilReflection = 1, stencilShadow = 1, offsetShadow = 1;
+static int renderShadow = 1, renderDinosaur = 1, renderReflection = 1;
+static int linearFiltering = 0, useMipmaps = 0, useTexture = 1;
+static int reportSpeed = 0;
+static int animation = 1;
+static GLboolean lightSwitch = GL_TRUE;
+static int directionalLight = 1;
+static int forceExtension = 0;
+
+/* Time varying or user-controled variables. */
+static float jump = 0.0;
+static float lightAngle = 0.0, lightHeight = 20;
+GLfloat angle = -150; /* in degrees */
+GLfloat angle2 = 30; /* in degrees */
+
+int moving, startx, starty;
+int lightMoving = 0, lightStartX, lightStartY;
+
+enum {
+ MISSING, EXTENSION, ONE_DOT_ONE
+};
+int polygonOffsetVersion;
+
+static GLdouble bodyWidth = 3.0;
+/* *INDENT-OFF* */
+static GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
+ {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
+ {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
+ {1, 2} };
+static GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
+ {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
+ {13, 9}, {11, 11}, {9, 11} };
+static GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
+ {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
+static GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
+ {9.6, 15.25}, {9, 15.25} };
+static GLfloat lightPosition[4];
+static GLfloat lightColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
+static GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
+/* *INDENT-ON* */
+
+/* Nice floor texture tiling pattern. */
+static char *circles[] = {
+ "....xxxx........",
+ "..xxxxxxxx......",
+ ".xxxxxxxxxx.....",
+ ".xxx....xxx.....",
+ "xxx......xxx....",
+ "xxx......xxx....",
+ "xxx......xxx....",
+ "xxx......xxx....",
+ ".xxx....xxx.....",
+ ".xxxxxxxxxx.....",
+ "..xxxxxxxx......",
+ "....xxxx........",
+ "................",
+ "................",
+ "................",
+ "................",
+};
+
+static void
+makeFloorTexture(void)
+{
+ GLubyte floorTexture[16][16][3];
+ GLubyte *loc;
+ int s, t;
+
+ /* Setup RGB image for the texture. */
+ loc = (GLubyte*) floorTexture;
+ for (t = 0; t < 16; t++) {
+ for (s = 0; s < 16; s++) {
+ if (circles[t][s] == 'x') {
+ /* Nice green. */
+ loc[0] = 0x1f;
+ loc[1] = 0x8f;
+ loc[2] = 0x1f;
+ } else {
+ /* Light gray. */
+ loc[0] = 0xaa;
+ loc[1] = 0xaa;
+ loc[2] = 0xaa;
+ }
+ loc += 3;
+ }
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ if (useMipmaps) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
+ GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
+ } else {
+ if (linearFiltering) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
+ }
+}
+
+enum {
+ X, Y, Z, W
+};
+enum {
+ A, B, C, D
+};
+
+/* Create a matrix that will project the desired shadow. */
+void
+shadowMatrix(GLfloat shadowMat[4][4],
+ GLfloat groundplane[4],
+ GLfloat lightpos[4])
+{
+ GLfloat dot;
+
+ /* Find dot product between light position vector and ground plane normal. */
+ dot = groundplane[X] * lightpos[X] +
+ groundplane[Y] * lightpos[Y] +
+ groundplane[Z] * lightpos[Z] +
+ groundplane[W] * lightpos[W];
+
+ shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
+ shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
+ shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
+ shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
+
+ shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
+ shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
+ shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
+ shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
+
+ shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
+ shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
+ shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
+ shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
+
+ shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
+ shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
+ shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
+ shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
+
+}
+
+/* Find the plane equation given 3 points. */
+void
+findPlane(GLfloat plane[4],
+ GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
+{
+ GLfloat vec0[3], vec1[3];
+
+ /* Need 2 vectors to find cross product. */
+ vec0[X] = v1[X] - v0[X];
+ vec0[Y] = v1[Y] - v0[Y];
+ vec0[Z] = v1[Z] - v0[Z];
+
+ vec1[X] = v2[X] - v0[X];
+ vec1[Y] = v2[Y] - v0[Y];
+ vec1[Z] = v2[Z] - v0[Z];
+
+ /* find cross product to get A, B, and C of plane equation */
+ plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];
+ plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);
+ plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];
+
+ plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);
+}
+
+void
+extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
+ GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
+{
+ static GLUtriangulatorObj *tobj = NULL;
+ GLdouble vertex[3], dx, dy, len;
+ int i;
+ int count = (int) (dataSize / (2 * sizeof(GLfloat)));
+
+ if (tobj == NULL) {
+ tobj = gluNewTess(); /* create and initialize a GLU
+ polygon tesselation object */
+ gluTessCallback(tobj, GLU_BEGIN, glBegin);
+ gluTessCallback(tobj, GLU_VERTEX, glVertex2fv); /* semi-tricky */
+ gluTessCallback(tobj, GLU_END, glEnd);
+ }
+ glNewList(side, GL_COMPILE);
+ glShadeModel(GL_SMOOTH); /* smooth minimizes seeing
+ tessellation */
+ gluBeginPolygon(tobj);
+ for (i = 0; i < count; i++) {
+ vertex[0] = data[i][0];
+ vertex[1] = data[i][1];
+ vertex[2] = 0;
+ gluTessVertex(tobj, vertex, data[i]);
+ }
+ gluEndPolygon(tobj);
+ glEndList();
+ glNewList(edge, GL_COMPILE);
+ glShadeModel(GL_FLAT); /* flat shade keeps angular hands
+ from being "smoothed" */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= count; i++) {
+#if 1 /* weird, but seems to be legal */
+ /* mod function handles closing the edge */
+ glVertex3f(data[i % count][0], data[i % count][1], 0.0);
+ glVertex3f(data[i % count][0], data[i % count][1], thickness);
+ /* Calculate a unit normal by dividing by Euclidean
+ distance. We * could be lazy and use
+ glEnable(GL_NORMALIZE) so we could pass in * arbitrary
+ normals for a very slight performance hit. */
+ dx = data[(i + 1) % count][1] - data[i % count][1];
+ dy = data[i % count][0] - data[(i + 1) % count][0];
+ len = sqrt(dx * dx + dy * dy);
+ glNormal3f(dx / len, dy / len, 0.0);
+#else /* the nice way of doing it */
+ /* Calculate a unit normal by dividing by Euclidean
+ distance. We * could be lazy and use
+ glEnable(GL_NORMALIZE) so we could pass in * arbitrary
+ normals for a very slight performance hit. */
+ dx = data[i % count][1] - data[(i - 1 + count) % count][1];
+ dy = data[(i - 1 + count) % count][0] - data[i % count][0];
+ len = sqrt(dx * dx + dy * dy);
+ glNormal3f(dx / len, dy / len, 0.0);
+ /* mod function handles closing the edge */
+ glVertex3f(data[i % count][0], data[i % count][1], 0.0);
+ glVertex3f(data[i % count][0], data[i % count][1], thickness);
+#endif
+ }
+ glEnd();
+ glEndList();
+ glNewList(whole, GL_COMPILE);
+ glFrontFace(GL_CW);
+ glCallList(edge);
+ glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */
+ glCallList(side);
+ glPushMatrix();
+ glTranslatef(0.0, 0.0, thickness);
+ glFrontFace(GL_CCW);
+ glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */
+ glCallList(side);
+ glPopMatrix();
+ glEndList();
+}
+
+/* Enumerants for refering to display lists. */
+typedef enum {
+ RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
+ LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE
+} displayLists;
+
+static void
+makeDinosaur(void)
+{
+ extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
+ BODY_SIDE, BODY_EDGE, BODY_WHOLE);
+ extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
+ ARM_SIDE, ARM_EDGE, ARM_WHOLE);
+ extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
+ LEG_SIDE, LEG_EDGE, LEG_WHOLE);
+ extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
+ EYE_SIDE, EYE_EDGE, EYE_WHOLE);
+}
+
+static void
+drawDinosaur(void)
+
+{
+ glPushMatrix();
+ /* Translate the dinosaur to be at (0,8,0). */
+ glTranslatef(-8, 0, -bodyWidth / 2);
+ glTranslatef(0.0, jump, 0.0);
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
+ glCallList(BODY_WHOLE);
+ glTranslatef(0.0, 0.0, bodyWidth);
+ glCallList(ARM_WHOLE);
+ glCallList(LEG_WHOLE);
+ glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
+ glCallList(ARM_WHOLE);
+ glTranslatef(0.0, 0.0, -bodyWidth / 4);
+ glCallList(LEG_WHOLE);
+ glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
+ glCallList(EYE_WHOLE);
+ glPopMatrix();
+}
+
+static GLfloat floorVertices[4][3] = {
+ { -20.0, 0.0, 20.0 },
+ { 20.0, 0.0, 20.0 },
+ { 20.0, 0.0, -20.0 },
+ { -20.0, 0.0, -20.0 },
+};
+
+/* Draw a floor (possibly textured). */
+static void
+drawFloor(void)
+{
+ glDisable(GL_LIGHTING);
+
+ if (useTexture) {
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, 0.0);
+ glVertex3fv(floorVertices[0]);
+ glTexCoord2f(0.0, 16.0);
+ glVertex3fv(floorVertices[1]);
+ glTexCoord2f(16.0, 16.0);
+ glVertex3fv(floorVertices[2]);
+ glTexCoord2f(16.0, 0.0);
+ glVertex3fv(floorVertices[3]);
+ glEnd();
+
+ if (useTexture) {
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ glEnable(GL_LIGHTING);
+}
+
+static GLfloat floorPlane[4];
+static GLfloat floorShadow[4][4];
+
+static void
+redraw(void)
+{
+ int start, end;
+
+ if (reportSpeed) {
+ start = glutGet(GLUT_ELAPSED_TIME);
+ }
+
+ /* Clear; default stencil clears to zero. */
+ if ((stencilReflection && renderReflection) || (stencilShadow && renderShadow)) {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ } else {
+ /* Avoid clearing stencil when not using it. */
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+
+ /* Reposition the light source. */
+ lightPosition[0] = 12*cos(lightAngle);
+ lightPosition[1] = lightHeight;
+ lightPosition[2] = 12*sin(lightAngle);
+ if (directionalLight) {
+ lightPosition[3] = 0.0;
+ } else {
+ lightPosition[3] = 1.0;
+ }
+
+ shadowMatrix(floorShadow, floorPlane, lightPosition);
+
+ glPushMatrix();
+ /* Perform scene rotations based on user mouse input. */
+ glRotatef(angle2, 1.0, 0.0, 0.0);
+ glRotatef(angle, 0.0, 1.0, 0.0);
+
+ /* Tell GL new light source position. */
+ glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
+
+ if (renderReflection) {
+ if (stencilReflection) {
+ /* We can eliminate the visual "artifact" of seeing the "flipped"
+ dinosaur underneath the floor by using stencil. The idea is
+ draw the floor without color or depth update but so that
+ a stencil value of one is where the floor will be. Later when
+ rendering the dinosaur reflection, we will only update pixels
+ with a stencil value of 1 to make sure the reflection only
+ lives on the floor, not below the floor. */
+
+ /* Don't update color or depth. */
+ glDisable(GL_DEPTH_TEST);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ /* Draw 1 into the stencil buffer. */
+ glEnable(GL_STENCIL_TEST);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
+
+ /* Now render floor; floor pixels just get their stencil set to 1. */
+ drawFloor();
+
+ /* Re-enable update of color and depth. */
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+
+ /* Now, only render where stencil is set to 1. */
+ glStencilFunc(GL_EQUAL, 1, 0xffffffff); /* draw if ==1 */
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ }
+
+ glPushMatrix();
+
+ /* The critical reflection step: Reflect dinosaur through the floor
+ (the Y=0 plane) to make a relection. */
+ glScalef(1.0, -1.0, 1.0);
+
+ /* Reflect the light position. */
+ glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
+
+ /* To avoid our normals getting reversed and hence botched lighting
+ on the reflection, turn on normalize. */
+ glEnable(GL_NORMALIZE);
+ glCullFace(GL_FRONT);
+
+ /* Draw the reflected dinosaur. */
+ drawDinosaur();
+
+ /* Disable noramlize again and re-enable back face culling. */
+ glDisable(GL_NORMALIZE);
+ glCullFace(GL_BACK);
+
+ glPopMatrix();
+
+ /* Switch back to the unreflected light position. */
+ glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
+
+ if (stencilReflection) {
+ glDisable(GL_STENCIL_TEST);
+ }
+ }
+
+ /* Back face culling will get used to only draw either the top or the
+ bottom floor. This let's us get a floor with two distinct
+ appearances. The top floor surface is reflective and kind of red.
+ The bottom floor surface is not reflective and blue. */
+
+ /* Draw "bottom" of floor in blue. */
+ glFrontFace(GL_CW); /* Switch face orientation. */
+ glColor4f(0.1, 0.1, 0.7, 1.0);
+ drawFloor();
+ glFrontFace(GL_CCW);
+
+ if (renderShadow) {
+ if (stencilShadow) {
+ /* Draw the floor with stencil value 3. This helps us only
+ draw the shadow once per floor pixel (and only on the
+ floor pixels). */
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 3, 0xffffffff);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ }
+ }
+
+ /* Draw "top" of floor. Use blending to blend in reflection. */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(0.7, 0.0, 0.0, 0.3);
+ glColor4f(1.0, 1.0, 1.0, 0.3);
+ drawFloor();
+ glDisable(GL_BLEND);
+
+ if (renderDinosaur) {
+ /* Draw "actual" dinosaur, not its reflection. */
+ drawDinosaur();
+ }
+
+ if (renderShadow) {
+
+ /* Render the projected shadow. */
+
+ if (stencilShadow) {
+
+ /* Now, only render where stencil is set above 2 (ie, 3 where
+ the top floor is). Update stencil with 2 where the shadow
+ gets drawn so we don't redraw (and accidently reblend) the
+ shadow). */
+ glStencilFunc(GL_LESS, 2, 0xffffffff); /* draw if ==1 */
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ }
+
+ /* To eliminate depth buffer artifacts, we use polygon offset
+ to raise the depth of the projected shadow slightly so
+ that it does not depth buffer alias with the floor. */
+ if (offsetShadow) {
+ switch (polygonOffsetVersion) {
+ case EXTENSION:
+#ifdef GL_EXT_polygon_offset
+ glEnable(GL_POLYGON_OFFSET_EXT);
+ break;
+#endif
+#ifdef GL_VERSION_1_1
+ case ONE_DOT_ONE:
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ break;
+#endif
+ case MISSING:
+ /* Oh well. */
+ break;
+ }
+ }
+
+ /* Render 50% black shadow color on top of whatever the
+ floor appareance is. */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_LIGHTING); /* Force the 50% black. */
+ glColor4f(0.0, 0.0, 0.0, 0.5);
+
+ glPushMatrix();
+ /* Project the shadow. */
+ glMultMatrixf((GLfloat *) floorShadow);
+ drawDinosaur();
+ glPopMatrix();
+
+ glDisable(GL_BLEND);
+ glEnable(GL_LIGHTING);
+
+ if (offsetShadow) {
+ switch (polygonOffsetVersion) {
+#ifdef GL_EXT_polygon_offset
+ case EXTENSION:
+ glDisable(GL_POLYGON_OFFSET_EXT);
+ break;
+#endif
+#ifdef GL_VERSION_1_1
+ case ONE_DOT_ONE:
+ glDisable(GL_POLYGON_OFFSET_FILL);
+ break;
+#endif
+ case MISSING:
+ /* Oh well. */
+ break;
+ }
+ }
+ if (stencilShadow) {
+ glDisable(GL_STENCIL_TEST);
+ }
+ }
+
+ glPushMatrix();
+ glDisable(GL_LIGHTING);
+ glColor3f(1.0, 1.0, 0.0);
+ if (directionalLight) {
+ /* Draw an arrowhead. */
+ glDisable(GL_CULL_FACE);
+ glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
+ glRotatef(lightAngle * -180.0 / M_PI, 0, 1, 0);
+ glRotatef(atan(lightHeight/12) * 180.0 / M_PI, 0, 0, 1);
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex3f(0, 0, 0);
+ glVertex3f(2, 1, 1);
+ glVertex3f(2, -1, 1);
+ glVertex3f(2, -1, -1);
+ glVertex3f(2, 1, -1);
+ glVertex3f(2, 1, 1);
+ glEnd();
+ /* Draw a white line from light direction. */
+ glColor3f(1.0, 1.0, 1.0);
+ glBegin(GL_LINES);
+ glVertex3f(0, 0, 0);
+ glVertex3f(5, 0, 0);
+ glEnd();
+ glEnable(GL_CULL_FACE);
+ } else {
+ /* Draw a yellow ball at the light source. */
+ glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
+ glutSolidSphere(1.0, 5, 5);
+ }
+ glEnable(GL_LIGHTING);
+ glPopMatrix();
+
+ glPopMatrix();
+
+ if (reportSpeed) {
+ glFinish();
+ end = glutGet(GLUT_ELAPSED_TIME);
+ printf("Speed %.3g frames/sec (%d ms)\n", 1000.0/(end-start), end-start);
+ }
+
+ glutSwapBuffers();
+}
+
+/* ARGSUSED2 */
+static void
+mouse(int button, int state, int x, int y)
+{
+ if (button == GLUT_LEFT_BUTTON) {
+ if (state == GLUT_DOWN) {
+ moving = 1;
+ startx = x;
+ starty = y;
+ }
+ if (state == GLUT_UP) {
+ moving = 0;
+ }
+ }
+ if (button == GLUT_MIDDLE_BUTTON) {
+ if (state == GLUT_DOWN) {
+ lightMoving = 1;
+ lightStartX = x;
+ lightStartY = y;
+ }
+ if (state == GLUT_UP) {
+ lightMoving = 0;
+ }
+ }
+}
+
+/* ARGSUSED1 */
+static void
+motion(int x, int y)
+{
+ if (moving) {
+ angle = angle + (x - startx);
+ angle2 = angle2 + (y - starty);
+ startx = x;
+ starty = y;
+ glutPostRedisplay();
+ }
+ if (lightMoving) {
+ lightAngle += (x - lightStartX)/40.0;
+ lightHeight += (lightStartY - y)/20.0;
+ lightStartX = x;
+ lightStartY = y;
+ glutPostRedisplay();
+ }
+}
+
+/* Advance time varying state when idle callback registered. */
+static void
+idle(void)
+{
+ static float time = 0.0;
+
+ time = glutGet(GLUT_ELAPSED_TIME) / 500.0;
+
+ jump = 4.0 * fabs(sin(time)*0.5);
+ if (!lightMoving) {
+ lightAngle += 0.03;
+ }
+ glutPostRedisplay();
+}
+
+enum {
+ M_NONE, M_MOTION, M_LIGHT, M_TEXTURE, M_SHADOWS, M_REFLECTION, M_DINOSAUR,
+ M_STENCIL_REFLECTION, M_STENCIL_SHADOW, M_OFFSET_SHADOW,
+ M_POSITIONAL, M_DIRECTIONAL, M_PERFORMANCE
+};
+
+static void
+controlLights(int value)
+{
+ switch (value) {
+ case M_NONE:
+ return;
+ case M_MOTION:
+ animation = 1 - animation;
+ if (animation) {
+ glutIdleFunc(idle);
+ } else {
+ glutIdleFunc(NULL);
+ }
+ break;
+ case M_LIGHT:
+ lightSwitch = !lightSwitch;
+ if (lightSwitch) {
+ glEnable(GL_LIGHT0);
+ } else {
+ glDisable(GL_LIGHT0);
+ }
+ break;
+ case M_TEXTURE:
+ useTexture = !useTexture;
+ break;
+ case M_SHADOWS:
+ renderShadow = 1 - renderShadow;
+ break;
+ case M_REFLECTION:
+ renderReflection = 1 - renderReflection;
+ break;
+ case M_DINOSAUR:
+ renderDinosaur = 1 - renderDinosaur;
+ break;
+ case M_STENCIL_REFLECTION:
+ stencilReflection = 1 - stencilReflection;
+ break;
+ case M_STENCIL_SHADOW:
+ stencilShadow = 1 - stencilShadow;
+ break;
+ case M_OFFSET_SHADOW:
+ offsetShadow = 1 - offsetShadow;
+ break;
+ case M_POSITIONAL:
+ directionalLight = 0;
+ break;
+ case M_DIRECTIONAL:
+ directionalLight = 1;
+ break;
+ case M_PERFORMANCE:
+ reportSpeed = 1 - reportSpeed;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+/* When not visible, stop animating. Restart when visible again. */
+static void
+visible(int vis)
+{
+ if (vis == GLUT_VISIBLE) {
+ if (animation)
+ glutIdleFunc(idle);
+ } else {
+ if (!animation)
+ glutIdleFunc(NULL);
+ }
+}
+
+/* Press any key to redraw; good when motion stopped and
+ performance reporting on. */
+/* ARGSUSED */
+static void
+key(unsigned char c, int x, int y)
+{
+ if (c == 27) {
+ exit(0); /* IRIS GLism, Escape quits. */
+ }
+ glutPostRedisplay();
+}
+
+/* Press any key to redraw; good when motion stopped and
+ performance reporting on. */
+/* ARGSUSED */
+static void
+special(int k, int x, int y)
+{
+ glutPostRedisplay();
+}
+
+static int
+supportsOneDotOne(void)
+{
+ const char *version;
+ int major, minor;
+
+ version = (char *) glGetString(GL_VERSION);
+ if (sscanf(version, "%d.%d", &major, &minor) == 2)
+ return major >= 1 && minor >= 1;
+ return 0; /* OpenGL version string malformed! */
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ glutInit(&argc, argv);
+
+ for (i=1; i<argc; i++) {
+ if (!strcmp("-linear", argv[i])) {
+ linearFiltering = 1;
+ } else if (!strcmp("-mipmap", argv[i])) {
+ useMipmaps = 1;
+ } else if (!strcmp("-ext", argv[i])) {
+ forceExtension = 1;
+ }
+ }
+
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
+
+#if 0
+ /* In GLUT 4.0, you'll be able to do this an be sure to
+ get 2 bits of stencil if the machine has it for you. */
+ glutInitDisplayString("samples stencil>=2 rgb double depth");
+#endif
+
+ glutCreateWindow("Shadowy Leapin' Lizards");
+
+ if (glutGet(GLUT_WINDOW_STENCIL_SIZE) <= 1) {
+ printf("dinoshade: Sorry, I need at least 2 bits of stencil.\n");
+ exit(1);
+ }
+
+ /* Register GLUT callbacks. */
+ glutDisplayFunc(redraw);
+ glutMouseFunc(mouse);
+ glutMotionFunc(motion);
+ glutVisibilityFunc(visible);
+ glutKeyboardFunc(key);
+ glutSpecialFunc(special);
+
+ glutCreateMenu(controlLights);
+
+ glutAddMenuEntry("Toggle motion", M_MOTION);
+ glutAddMenuEntry("-----------------------", M_NONE);
+ glutAddMenuEntry("Toggle light", M_LIGHT);
+ glutAddMenuEntry("Toggle texture", M_TEXTURE);
+ glutAddMenuEntry("Toggle shadows", M_SHADOWS);
+ glutAddMenuEntry("Toggle reflection", M_REFLECTION);
+ glutAddMenuEntry("Toggle dinosaur", M_DINOSAUR);
+ glutAddMenuEntry("-----------------------", M_NONE);
+ glutAddMenuEntry("Toggle reflection stenciling", M_STENCIL_REFLECTION);
+ glutAddMenuEntry("Toggle shadow stenciling", M_STENCIL_SHADOW);
+ glutAddMenuEntry("Toggle shadow offset", M_OFFSET_SHADOW);
+ glutAddMenuEntry("----------------------", M_NONE);
+ glutAddMenuEntry("Positional light", M_POSITIONAL);
+ glutAddMenuEntry("Directional light", M_DIRECTIONAL);
+ glutAddMenuEntry("-----------------------", M_NONE);
+ glutAddMenuEntry("Toggle performance", M_PERFORMANCE);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+ makeDinosaur();
+
+#ifdef GL_VERSION_1_1
+ if (supportsOneDotOne() && !forceExtension) {
+ polygonOffsetVersion = ONE_DOT_ONE;
+ glPolygonOffset(-2.0, -9.0);
+ } else
+#endif
+ {
+#ifdef GL_EXT_polygon_offset
+ /* check for the polygon offset extension */
+ if (glutExtensionSupported("GL_EXT_polygon_offset")) {
+ polygonOffsetVersion = EXTENSION;
+ glPolygonOffsetEXT(-2.0, -0.002);
+ } else
+#endif
+ {
+ polygonOffsetVersion = MISSING;
+ printf("\ndinoshine: Missing polygon offset.\n");
+ printf(" Expect shadow depth aliasing artifacts.\n\n");
+ }
+ }
+
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ glLineWidth(3.0);
+
+ glMatrixMode(GL_PROJECTION);
+ gluPerspective( /* field of view in degree */ 40.0,
+ /* aspect ratio */ 1.0,
+ /* Z near */ 20.0, /* Z far */ 100.0);
+ glMatrixMode(GL_MODELVIEW);
+ gluLookAt(0.0, 8.0, 60.0, /* eye is at (0,8,60) */
+ 0.0, 8.0, 0.0, /* center is at (0,8,0) */
+ 0.0, 1.0, 0.); /* up is in postivie Y direction */
+
+ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
+ glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
+ glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHTING);
+
+ makeFloorTexture();
+
+ /* Setup floor plane for projected shadow calculations. */
+ findPlane(floorPlane, floorVertices[1], floorVertices[2], floorVertices[3]);
+
+ glutMainLoop();
+ return 0; /* ANSI C requires main to return int. */
+}
diff --git a/tests/mesa/tests/ext422square.c b/tests/mesa/tests/ext422square.c
new file mode 100644
index 00000000..6533514d
--- /dev/null
+++ b/tests/mesa/tests/ext422square.c
@@ -0,0 +1,258 @@
+/*
+ * Exercise the EXT_422_pixels extension, a less convenient
+ * alternative to MESA_ycbcr_texture. Requires ARB_fragment_program
+ * to perform the final YUV->RGB conversion.
+ *
+ * Brian Paul 13 September 2002
+ * Keith Whitwell 30 November 2004
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+#include <assert.h>
+
+#include "../util/readtex.c" /* I know, this is a hack. */
+
+#define TEXTURE_FILE "../images/tile.rgb"
+
+static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
+static GLint ImgWidth, ImgHeight;
+static GLushort *ImageYUV = NULL;
+static const GLuint yuvObj = 100;
+static const GLuint rgbObj = 101;
+
+static void Init( int argc, char *argv[] );
+
+static void DrawObject(void)
+{
+ glBegin(GL_QUADS);
+
+ glTexCoord2f(0, 0);
+ glVertex2f(-1.0, -1.0);
+
+ glTexCoord2f(1, 0);
+ glVertex2f(1.0, -1.0);
+
+ glTexCoord2f(1, 1);
+ glVertex2f(1.0, 1.0);
+
+ glTexCoord2f(0, 1);
+ glVertex2f(-1.0, 1.0);
+
+ glEnd();
+}
+
+static void Display( void )
+{
+ static int firsttime = 1;
+
+ if (firsttime) {
+ firsttime = 0;
+ Init( 0, 0 ); /* don't ask */
+ }
+
+ glClear( GL_COLOR_BUFFER_BIT );
+ glBindTexture(GL_TEXTURE_2D, yuvObj);
+
+ glPushMatrix();
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ glTranslatef( -1.1, 0.0, -15.0 );
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ glBindTexture(GL_TEXTURE_2D, yuvObj);
+ DrawObject();
+ glPopMatrix();
+
+ glPushMatrix();
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ glTranslatef( 1.1, 0.0, -15.0 );
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ glBindTexture(GL_TEXTURE_2D, rgbObj);
+ DrawObject();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.1, 1.1, -1.1, 1.1, 10.0, 100.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+
+
+/* #define LINEAR_FILTER */
+
+static void Init( int argc, char *argv[] )
+{
+ const char *file;
+ const GLfloat yuvtorgb[16] = {
+ 1.164, 1.164, 1.164, 0,
+ 0, -.391, 2.018, 0,
+ 1.596, -.813, 0.0, 0,
+ (-.0625*1.164 + -.5*1.596), (-.0625*1.164 + -.5*-.813 + -.5*-.391), (-.0625*1.164 + -.5*2.018), 1
+ };
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ printf("Error: GL_ARB_fragment_program not supported!\n");
+ exit(1);
+ }
+
+ if (!glutExtensionSupported("GL_EXT_422_pixels")) {
+ printf("Error: GL_EXT_422_pixels not supported!\n");
+ exit(1);
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ file = TEXTURE_FILE;
+
+ /* Load the texture as YCbCr.
+ */
+ glBindTexture(GL_TEXTURE_2D, yuvObj);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ ImageYUV = LoadYUVImage(file, &ImgWidth, &ImgHeight );
+ if (!ImageYUV) {
+ printf("Couldn't read %s\n", TEXTURE_FILE);
+ exit(0);
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB,
+ ImgWidth, ImgHeight, 0,
+ GL_422_EXT,
+ GL_UNSIGNED_BYTE, ImageYUV);
+
+ glEnable(GL_TEXTURE_2D);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ {
+ static const char *modulateYUV =
+ "!!ARBfp1.0\n"
+ "TEMP R0;\n"
+ "TEX R0, fragment.texcoord[0], texture[0], 2D; \n"
+
+ "ADD R0, R0, {-0.0625, -0.5, -0.5, 0.0}; \n"
+ "DP3 result.color.x, R0, {1.164, 1.596, 0.0}; \n"
+ "DP3 result.color.y, R0, {1.164, -0.813, -0.391}; \n"
+ "DP3 result.color.z, R0, {1.164, 0.0, 2.018}; \n"
+ "MOV result.color.w, R0.w; \n"
+
+ "END"
+ ;
+
+ GLuint modulateProg;
+
+
+ /* Setup the fragment program */
+ glGenProgramsARB(1, &modulateProg);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, modulateProg);
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(modulateYUV), (const GLubyte *)modulateYUV);
+
+ printf("glGetError = 0x%x\n", (int) glGetError());
+ printf("glError(GL_PROGRAM_ERROR_STRING_ARB) = %s\n",
+ (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ assert(glIsProgramARB(modulateProg));
+
+ }
+
+ /* Now the same, but use a color matrix to do the conversion at
+ * upload time:
+ */
+ glBindTexture(GL_TEXTURE_2D, rgbObj);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glMatrixMode( GL_COLOR_MATRIX );
+ glLoadMatrixf( yuvtorgb );
+
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB,
+ ImgWidth, ImgHeight, 0,
+ GL_422_EXT,
+ GL_UNSIGNED_BYTE, ImageYUV);
+
+ glLoadIdentity();
+ glMatrixMode( GL_MODELVIEW );
+
+ glEnable(GL_TEXTURE_2D);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.3, 0.3, 0.4, 1.0);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowSize( 300, 300 );
+ glutInitWindowPosition( 0, 0 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0] );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/fbotest1.c b/tests/mesa/tests/fbotest1.c
new file mode 100644
index 00000000..8f4569ff
--- /dev/null
+++ b/tests/mesa/tests/fbotest1.c
@@ -0,0 +1,206 @@
+/*
+ * Test GL_EXT_framebuffer_object
+ *
+ * Brian Paul
+ * 7 Feb 2005
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static int Win;
+static int Width = 400, Height = 400;
+static GLuint MyFB, MyRB;
+
+
+static void
+CheckError(int line)
+{
+ GLenum err = glGetError();
+ if (err) {
+ printf("GL Error 0x%x at line %d\n", (int) err, line);
+ }
+}
+
+
+static void
+Display( void )
+{
+ GLubyte *buffer = malloc(Width * Height * 4);
+ GLenum status;
+
+ /* draw to user framebuffer */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
+ glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
+ glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
+
+ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ printf("Framebuffer incomplete!!!\n");
+ }
+
+ glClearColor(0.5, 0.5, 1.0, 0.0);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glBegin(GL_POLYGON);
+ glColor3f(1, 0, 0);
+ glVertex2f(-1, -1);
+ glColor3f(0, 1, 0);
+ glVertex2f(1, -1);
+ glColor3f(0, 0, 1);
+ glVertex2f(0, 1);
+ glEnd();
+
+ /* read from user framebuffer */
+ glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+ /* draw to window */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glWindowPos2iARB(0, 0);
+ glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+ free(buffer);
+ glutSwapBuffers();
+ CheckError(__LINE__);
+}
+
+
+static void
+Reshape( int width, int height )
+{
+#if 0
+ float ar = (float) width / (float) height;
+#endif
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+#if 0
+ glFrustum( -ar, ar, -1.0, 1.0, 5.0, 25.0 );
+#else
+ glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+#endif
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+ Width = width;
+ Height = height;
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height);
+}
+
+
+static void
+CleanUp(void)
+{
+ glDeleteFramebuffersEXT(1, &MyFB);
+ glDeleteRenderbuffersEXT(1, &MyRB);
+ assert(!glIsFramebufferEXT(MyFB));
+ assert(!glIsRenderbufferEXT(MyRB));
+ glutDestroyWindow(Win);
+ exit(0);
+}
+
+
+static void
+Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ CleanUp();
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init( void )
+{
+ GLint i;
+
+ if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
+ printf("GL_EXT_framebuffer_object not found!\n");
+ /*exit(0);*/
+ }
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ glGenFramebuffersEXT(1, &MyFB);
+ assert(MyFB);
+ assert(!glIsFramebufferEXT(MyFB));
+ glDeleteFramebuffersEXT(1, &MyFB);
+ assert(!glIsFramebufferEXT(MyFB));
+ /* Note, continue to use MyFB below */
+
+ glGenRenderbuffersEXT(1, &MyRB);
+ assert(MyRB);
+ assert(!glIsRenderbufferEXT(MyRB));
+ glDeleteRenderbuffersEXT(1, &MyRB);
+ assert(!glIsRenderbufferEXT(MyRB));
+ MyRB = 42; /* an arbitrary ID */
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
+ assert(glIsFramebufferEXT(MyFB));
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, MyRB);
+ assert(glIsRenderbufferEXT(MyRB));
+
+ glGetIntegerv(GL_RENDERBUFFER_BINDING_EXT, &i);
+ assert(i == MyRB);
+
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &i);
+ assert(i == MyFB);
+
+ CheckError(__LINE__);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,
+ GL_RENDERBUFFER_EXT, MyRB);
+
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height);
+
+ CheckError(__LINE__);
+
+ {
+ GLint r, g, b, a;
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
+ GL_RENDERBUFFER_RED_SIZE_EXT, &r);
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
+ GL_RENDERBUFFER_GREEN_SIZE_EXT, &g);
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
+ GL_RENDERBUFFER_BLUE_SIZE_EXT, &b);
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
+ GL_RENDERBUFFER_ALPHA_SIZE_EXT, &a);
+ CheckError(__LINE__);
+ printf("renderbuffer RGBA sizes = %d %d %d %d\n", r, g, b, a);
+
+ glGetIntegerv(GL_RED_BITS, &r);
+ glGetIntegerv(GL_GREEN_BITS, &g);
+ glGetIntegerv(GL_BLUE_BITS, &b);
+ glGetIntegerv(GL_ALPHA_BITS, &a);
+ printf("Visual RGBA sizes = %d %d %d %d\n", r, g, b, a);
+ }
+
+ /* restore to default */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ CheckError(__LINE__);
+}
+
+
+int
+main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ Win = glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/fbotest2.c b/tests/mesa/tests/fbotest2.c
new file mode 100644
index 00000000..c3117b0f
--- /dev/null
+++ b/tests/mesa/tests/fbotest2.c
@@ -0,0 +1,199 @@
+/*
+ * Test GL_EXT_framebuffer_object
+ *
+ * Brian Paul
+ * 19 Mar 2006
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static int Width = 400, Height = 400;
+static GLuint MyFB, ColorRb, DepthRb;
+static GLboolean Animate = GL_TRUE;
+static GLfloat Rotation = 0.0;
+
+
+static void
+CheckError(int line)
+{
+ GLenum err = glGetError();
+ if (err) {
+ printf("fbotest2: GL Error 0x%x at line %d\n", (int) err, line);
+ }
+}
+
+
+static void
+Display( void )
+{
+ GLubyte *buffer = malloc(Width * Height * 4);
+ GLenum status;
+
+ CheckError(__LINE__);
+
+ /* draw to user framebuffer */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
+ glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
+ glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
+
+ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ printf("fbotest2: Error: Framebuffer is incomplete!!!\n");
+ }
+
+ CheckError(__LINE__);
+
+ glClearColor(0.5, 0.5, 1.0, 0.0);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+
+ glPushMatrix();
+ glRotatef(30.0, 1, 0, 0);
+ glRotatef(Rotation, 0, 1, 0);
+ glutSolidTeapot(2.0);
+ glPopMatrix();
+
+ /* read from user framebuffer */
+ glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+ /* draw to window */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glWindowPos2iARB(0, 0);
+ glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+ free(buffer);
+ glutSwapBuffers();
+ CheckError(__LINE__);
+}
+
+
+static void
+Reshape( int width, int height )
+{
+ float ar = (float) width / (float) height;
+
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, 5.0, 25.0 );
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, ColorRb);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, width, height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthRb);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
+ width, height);
+
+ Width = width;
+ Height = height;
+}
+
+
+static void
+CleanUp(void)
+{
+ glDeleteFramebuffersEXT(1, &MyFB);
+ glDeleteRenderbuffersEXT(1, &ColorRb);
+ glDeleteRenderbuffersEXT(1, &DepthRb);
+ assert(!glIsFramebufferEXT(MyFB));
+ assert(!glIsRenderbufferEXT(ColorRb));
+ assert(!glIsRenderbufferEXT(DepthRb));
+ exit(0);
+}
+
+
+static void
+Idle(void)
+{
+ Rotation = glutGet(GLUT_ELAPSED_TIME) * 0.1;
+ glutPostRedisplay();
+}
+
+
+static void
+Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Animate = !Animate;
+ if (Animate)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 27:
+ CleanUp();
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init( void )
+{
+ if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
+ printf("fbotest2: GL_EXT_framebuffer_object not found!\n");
+ exit(0);
+ }
+ printf("fbotest2: GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ glGenFramebuffersEXT(1, &MyFB);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
+ assert(glIsFramebufferEXT(MyFB));
+
+ /* set color buffer */
+ glGenRenderbuffersEXT(1, &ColorRb);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, ColorRb);
+ assert(glIsRenderbufferEXT(ColorRb));
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,
+ GL_RENDERBUFFER_EXT, ColorRb);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height);
+
+ /* setup depth buffer */
+ glGenRenderbuffersEXT(1, &DepthRb);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthRb);
+ assert(glIsRenderbufferEXT(DepthRb));
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, DepthRb);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, Width, Height);
+
+ CheckError(__LINE__);
+
+ /* restore to default */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ CheckError(__LINE__);
+}
+
+
+int
+main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ if (Animate)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/fbotexture.c b/tests/mesa/tests/fbotexture.c
new file mode 100644
index 00000000..aa9f6171
--- /dev/null
+++ b/tests/mesa/tests/fbotexture.c
@@ -0,0 +1,407 @@
+/*
+ * Test GL_EXT_framebuffer_object render-to-texture
+ *
+ * Draw a teapot into a texture image with stenciling.
+ * Then draw a textured quad using that texture.
+ *
+ * Brian Paul
+ * 18 Apr 2005
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* For debug */
+#define DEPTH 1
+#define STENCIL 1
+#define DRAW 1
+
+
+static int Win = 0;
+static int Width = 400, Height = 400;
+
+static GLenum TexTarget = GL_TEXTURE_2D; /*GL_TEXTURE_RECTANGLE_ARB;*/
+static int TexWidth = 512, TexHeight = 512;
+/*static int TexWidth = 600, TexHeight = 600;*/
+
+static GLuint MyFB;
+static GLuint TexObj;
+static GLuint DepthRB, StencilRB;
+static GLboolean Anim = GL_FALSE;
+static GLfloat Rot = 0.0;
+static GLboolean UsePackedDepthStencil = GL_FALSE;
+static GLuint TextureLevel = 1; /* which texture level to render to */
+static GLenum TexIntFormat = GL_RGB; /* either GL_RGB or GL_RGBA */
+
+
+static void
+CheckError(int line)
+{
+ GLenum err = glGetError();
+ if (err) {
+ printf("GL Error 0x%x at line %d\n", (int) err, line);
+ }
+}
+
+
+static void
+Idle(void)
+{
+ Rot = glutGet(GLUT_ELAPSED_TIME) * 0.1;
+ glutPostRedisplay();
+}
+
+
+static void
+RenderTexture(void)
+{
+ GLenum status;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -15.0);
+
+ /* draw to texture image */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
+
+ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ printf("Framebuffer incomplete!!!\n");
+ }
+
+ glViewport(0, 0, TexWidth, TexHeight);
+
+ glClearColor(0.5, 0.5, 1.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ CheckError(__LINE__);
+
+#if DEPTH
+ glEnable(GL_DEPTH_TEST);
+#endif
+
+#if STENCIL
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_NEVER, 1, ~0);
+ glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE);
+#endif
+
+ CheckError(__LINE__);
+
+#if DEPTH || STENCIL
+ /* draw diamond-shaped stencil pattern */
+ glColor3f(0, 1, 0);
+ glBegin(GL_POLYGON);
+ glVertex2f(-0.2, 0.0);
+ glVertex2f( 0.0, -0.2);
+ glVertex2f( 0.2, 0.0);
+ glVertex2f( 0.0, 0.2);
+ glEnd();
+#endif
+
+ /* draw teapot where stencil != 1 */
+#if STENCIL
+ glStencilFunc(GL_NOTEQUAL, 1, ~0);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+#endif
+
+ CheckError(__LINE__);
+
+#if 0
+ glBegin(GL_POLYGON);
+ glColor3f(1, 0, 0);
+ glVertex2f(-1, -1);
+ glColor3f(0, 1, 0);
+ glVertex2f(1, -1);
+ glColor3f(0, 0, 1);
+ glVertex2f(0, 1);
+ glEnd();
+#else
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glPushMatrix();
+ glRotatef(0.5 * Rot, 1.0, 0.0, 0.0);
+ glutSolidTeapot(0.5);
+ glPopMatrix();
+ glDisable(GL_LIGHTING);
+ /*
+ PrintStencilHistogram(TexWidth, TexHeight);
+ */
+#endif
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_STENCIL_TEST);
+
+#if DRAW
+ /* Bind normal framebuffer */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+#endif
+
+ CheckError(__LINE__);
+}
+
+
+
+static void
+Display(void)
+{
+ float ar = (float) Width / (float) Height;
+
+ RenderTexture();
+
+ /* draw textured quad in the window */
+#if DRAW
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-ar, ar, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -7.0);
+
+ glViewport(0, 0, Width, Height);
+
+ glClearColor(0.25, 0.25, 0.25, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(Rot, 0, 1, 0);
+ glEnable(TexTarget);
+ glBindTexture(TexTarget, TexObj);
+ glBegin(GL_POLYGON);
+ glColor3f(0.25, 0.25, 0.25);
+ if (TexTarget == GL_TEXTURE_2D) {
+ glTexCoord2f(0, 0);
+ glVertex2f(-1, -1);
+ glTexCoord2f(1, 0);
+ glVertex2f(1, -1);
+ glColor3f(1.0, 1.0, 1.0);
+ glTexCoord2f(1, 1);
+ glVertex2f(1, 1);
+ glTexCoord2f(0, 1);
+ glVertex2f(-1, 1);
+ }
+ else {
+ assert(TexTarget == GL_TEXTURE_RECTANGLE_ARB);
+ glTexCoord2f(0, 0);
+ glVertex2f(-1, -1);
+ glTexCoord2f(TexWidth, 0);
+ glVertex2f(1, -1);
+ glColor3f(1.0, 1.0, 1.0);
+ glTexCoord2f(TexWidth, TexHeight);
+ glVertex2f(1, 1);
+ glTexCoord2f(0, TexHeight);
+ glVertex2f(-1, 1);
+ }
+ glEnd();
+ glPopMatrix();
+ glDisable(TexTarget);
+#endif
+
+ glutSwapBuffers();
+ CheckError(__LINE__);
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ Width = width;
+ Height = height;
+}
+
+
+static void
+CleanUp(void)
+{
+#if DEPTH
+ glDeleteRenderbuffersEXT(1, &DepthRB);
+#endif
+#if STENCIL
+ if (!UsePackedDepthStencil)
+ glDeleteRenderbuffersEXT(1, &StencilRB);
+#endif
+ glDeleteFramebuffersEXT(1, &MyFB);
+
+ glDeleteTextures(1, &TexObj);
+
+ glutDestroyWindow(Win);
+
+ exit(0);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 's':
+ Rot += 2.0;
+ break;
+ case 27:
+ CleanUp();
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(int argc, char *argv[])
+{
+ static const GLfloat mat[4] = { 1.0, 0.5, 0.5, 1.0 };
+ GLint i;
+
+ if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
+ printf("GL_EXT_framebuffer_object not found!\n");
+ exit(0);
+ }
+
+ if (argc > 1 && strcmp(argv[1], "-ds") == 0) {
+ if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
+ printf("GL_EXT_packed_depth_stencil not found!\n");
+ exit(0);
+ }
+ UsePackedDepthStencil = GL_TRUE;
+ printf("Using GL_EXT_packed_depth_stencil\n");
+ }
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ /* gen framebuffer id, delete it, do some assertions, just for testing */
+ glGenFramebuffersEXT(1, &MyFB);
+ assert(MyFB);
+ assert(!glIsFramebufferEXT(MyFB));
+ glDeleteFramebuffersEXT(1, &MyFB);
+ assert(!glIsFramebufferEXT(MyFB));
+ /* Note, continue to use MyFB below */
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
+ assert(glIsFramebufferEXT(MyFB));
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &i);
+ assert(i == MyFB);
+
+ /* Make texture object/image */
+ glGenTextures(1, &TexObj);
+ glBindTexture(TexTarget, TexObj);
+ /* make two image levels */
+ glTexImage2D(TexTarget, 0, TexIntFormat, TexWidth, TexHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(TexTarget, 1, TexIntFormat, TexWidth/2, TexHeight/2, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ TexWidth = TexWidth >> TextureLevel;
+ TexHeight = TexHeight >> TextureLevel;
+
+ glTexParameteri(TexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(TexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameteri(TexTarget, GL_TEXTURE_BASE_LEVEL, TextureLevel);
+ glTexParameteri(TexTarget, GL_TEXTURE_MAX_LEVEL, TextureLevel);
+
+ CheckError(__LINE__);
+
+ /* Render color to texture */
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ TexTarget, TexObj, TextureLevel);
+
+
+#if DEPTH
+ /* make depth renderbuffer */
+ glGenRenderbuffersEXT(1, &DepthRB);
+ assert(DepthRB);
+ assert(!glIsRenderbufferEXT(DepthRB));
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthRB);
+ assert(glIsRenderbufferEXT(DepthRB));
+ if (UsePackedDepthStencil)
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT,
+ TexWidth, TexHeight);
+ else
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
+ TexWidth, TexHeight);
+ CheckError(__LINE__);
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
+ GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
+ CheckError(__LINE__);
+ printf("Depth renderbuffer size = %d bits\n", i);
+ assert(i > 0);
+
+ /* attach DepthRB to MyFB */
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, DepthRB);
+#endif
+
+ CheckError(__LINE__);
+
+#if STENCIL
+ if (UsePackedDepthStencil) {
+ /* DepthRb is a combined depth/stencil renderbuffer */
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, DepthRB);
+ }
+ else {
+ /* make stencil renderbuffer */
+ glGenRenderbuffersEXT(1, &StencilRB);
+ assert(StencilRB);
+ assert(!glIsRenderbufferEXT(StencilRB));
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilRB);
+ assert(glIsRenderbufferEXT(StencilRB));
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
+ TexWidth, TexHeight);
+ /* attach StencilRB to MyFB */
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, StencilRB);
+ }
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
+ GL_RENDERBUFFER_STENCIL_SIZE_EXT, &i);
+ CheckError(__LINE__);
+ printf("Stencil renderbuffer size = %d bits\n", i);
+ assert(i > 0);
+#endif
+
+ CheckError(__LINE__);
+
+ /* bind regular framebuffer */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+
+ /* lighting */
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+ Win = glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Display);
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init(argc, argv);
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/floattex.c b/tests/mesa/tests/floattex.c
new file mode 100644
index 00000000..2345a49b
--- /dev/null
+++ b/tests/mesa/tests/floattex.c
@@ -0,0 +1,169 @@
+/*
+ * Test floating point textures.
+ * No actual rendering, yet.
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+/* XXX - temporary */
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float 1
+#define GL_TEXTURE_RED_TYPE_ARB 0x9000
+#define GL_TEXTURE_GREEN_TYPE_ARB 0x9001
+#define GL_TEXTURE_BLUE_TYPE_ARB 0x9002
+#define GL_TEXTURE_ALPHA_TYPE_ARB 0x9003
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x9004
+#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x9005
+#define GL_TEXTURE_DEPTH_TYPE_ARB 0x9006
+#define GL_UNSIGNED_NORMALIZED_ARB 0x9007
+#define GL_RGBA32F_ARB 0x8814
+#define GL_RGB32F_ARB 0x8815
+#define GL_ALPHA32F_ARB 0x8816
+#define GL_INTENSITY32F_ARB 0x8817
+#define GL_LUMINANCE32F_ARB 0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB 0x8819
+#define GL_RGBA16F_ARB 0x881A
+#define GL_RGB16F_ARB 0x881B
+#define GL_ALPHA16F_ARB 0x881C
+#define GL_INTENSITY16F_ARB 0x881D
+#define GL_LUMINANCE16F_ARB 0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB 0x881F
+#endif
+
+
+static GLboolean
+CheckError( int line )
+{
+ GLenum error = glGetError();
+ if (error) {
+ char *err = (char *) gluErrorString( error );
+ fprintf( stderr, "GL Error: %s at line %d\n", err, line );
+ return GL_TRUE;
+ }
+ return GL_FALSE;
+}
+
+
+static void
+Draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+
+ glutSolidCube(2.0);
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -15.0);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+
+static void
+Init(void)
+{
+ GLfloat tex[16][16][4];
+ GLfloat tex2[16][16][4];
+ GLint i, j, t;
+
+ if (!glutExtensionSupported("GL_MESAX_texture_float")) {
+ printf("Sorry, this test requires GL_MESAX_texture_float\n");
+ exit(1);
+ }
+
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ GLfloat s = i / 15.0;
+ tex[i][j][0] = s;
+ tex[i][j][1] = 2.0 * s;
+ tex[i][j][2] = -3.0 * s;
+ tex[i][j][3] = 4.0 * s;
+ }
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, 16, 16, 0, GL_RGBA,
+ GL_FLOAT, tex);
+ CheckError(__LINE__);
+
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_RED_TYPE_ARB, &t);
+ assert(t == GL_FLOAT);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_GREEN_TYPE_ARB, &t);
+ assert(t == GL_FLOAT);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BLUE_TYPE_ARB, &t);
+ assert(t == GL_FLOAT);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_TYPE_ARB, &t);
+ assert(t == GL_FLOAT);
+
+ CheckError(__LINE__);
+
+ /* read back the texture and make sure values are correct */
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, tex2);
+ CheckError(__LINE__);
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ if (tex[i][j][0] != tex2[i][j][0] ||
+ tex[i][j][1] != tex2[i][j][1] ||
+ tex[i][j][2] != tex2[i][j][2] ||
+ tex[i][j][3] != tex2[i][j][3]) {
+ printf("tex[%d][%d] %g %g %g %g != tex2[%d][%d] %g %g %g %g\n",
+ i, j,
+ tex[i][j][0], tex[i][j][1], tex[i][j][2], tex[i][j][3],
+ i, j,
+ tex2[i][j][0], tex2[i][j][1], tex2[i][j][2], tex2[i][j][3]);
+ }
+ }
+ }
+
+
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(400, 400);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Draw);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/fog.c b/tests/mesa/tests/fog.c
new file mode 100644
index 00000000..ecd9f533
--- /dev/null
+++ b/tests/mesa/tests/fog.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2005 Eric Anholt
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <anholt@FreeBSD.org>
+ * Brian Paul (fogcoord.c used as a skeleton)
+ */
+
+/*
+ * Test to exercise fog modes and for comparison with GL_EXT_fog_coord.
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static int Width = 600;
+static int Height = 600;
+static GLfloat Near = 0.0, Far = 1.0;
+GLboolean has_fogcoord;
+
+static void drawString( const char *string )
+{
+ glRasterPos2f(0, .5);
+ while ( *string ) {
+ glutBitmapCharacter( GLUT_BITMAP_TIMES_ROMAN_10, *string );
+ string++;
+ }
+}
+
+static void Display( void )
+{
+ GLint i, depthi;
+ GLfloat fogcolor[4] = {1, 1, 1, 1};
+
+ glEnable(GL_FOG);
+ glFogfv(GL_FOG_COLOR, fogcolor);
+
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ for (i = 0; i < 6; i++) {
+ if (i >= 3 && !has_fogcoord)
+ break;
+
+ glPushMatrix();
+ for (depthi = 0; depthi < 5; depthi++) {
+ GLfloat depth = Near + (Far - Near) * depthi / 4;
+
+ switch (i % 3) {
+ case 0:
+ glFogi(GL_FOG_MODE, GL_LINEAR);
+ glFogf(GL_FOG_START, Near);
+ glFogf(GL_FOG_END, Far);
+ break;
+ case 1:
+ glFogi(GL_FOG_MODE, GL_EXP);
+ glFogf(GL_FOG_DENSITY, 2);
+ break;
+ case 2:
+ glFogi(GL_FOG_MODE, GL_EXP2);
+ glFogf(GL_FOG_DENSITY, 2);
+ break;
+ }
+
+ glColor4f(0, 0, 0, 0);
+ if (i < 3) {
+ if (has_fogcoord)
+ glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
+
+ glBegin(GL_POLYGON);
+ glVertex3f(0, 0, depth);
+ glVertex3f(1, 0, depth);
+ glVertex3f(1, 1, depth);
+ glVertex3f(0, 1, depth);
+ glEnd();
+ } else {
+ glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
+ glFogCoordfEXT(depth);
+
+ glBegin(GL_POLYGON);
+ glVertex3f(0, 0, (Near + Far) / 2);
+ glVertex3f(1, 0, (Near + Far) / 2);
+ glVertex3f(1, 1, (Near + Far) / 2);
+ glVertex3f(0, 1, (Near + Far) / 2);
+ glEnd();
+ }
+ glTranslatef(1.5, 0, 0);
+ }
+
+ glTranslatef(.1, 0, 0);
+ switch (i) {
+ case 0:
+ drawString("GL_LINEAR");
+ break;
+ case 1:
+ drawString("GL_EXP");
+ break;
+ case 2:
+ drawString("GL_EXP2");
+ break;
+ case 3:
+ drawString("GL_FOGCOORD GL_LINEAR");
+ break;
+ case 4:
+ drawString("GL_FOGCOORD GL_EXP");
+ break;
+ case 5:
+ drawString("GL_FOGCOORD GL_EXP2");
+ break;
+ }
+
+ glPopMatrix();
+ glTranslatef(0, 1.5, 0);
+ }
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0, 11, 9, 0, -Near, -Far );
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef(.25, .25, 0);
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ /* setup lighting, etc */
+ has_fogcoord = glutExtensionSupported("GL_EXT_fog_coord");
+ if (!has_fogcoord) {
+ printf("Some output of this program requires GL_EXT_fog_coord\n");
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/fogcoord.c b/tests/mesa/tests/fogcoord.c
new file mode 100644
index 00000000..89355742
--- /dev/null
+++ b/tests/mesa/tests/fogcoord.c
@@ -0,0 +1,102 @@
+/*
+ * Exercise GL_EXT_fog_coord
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static int Width = 600;
+static int Height = 200;
+static GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+ GLfloat t;
+
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ for (t = 0.0; t <= 1.0; t += 0.25) {
+ GLfloat f = Near + t * (Far - Near);
+ printf("glFogCoord(%4.1f)\n", f);
+ glFogCoordfEXT(f);
+
+ glPushMatrix();
+ glTranslatef(t * 10.0 - 5.0, 0, 0);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+ glPopMatrix();
+ }
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ /* setup lighting, etc */
+ if (!glutExtensionSupported("GL_EXT_fog_coord")) {
+ printf("Sorry, this program requires GL_EXT_fog_coord\n");
+ exit(1);
+ }
+ glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
+ glFogi(GL_FOG_MODE, GL_LINEAR);
+ glFogf(GL_FOG_START, Near);
+ glFogf(GL_FOG_END, Far);
+ glEnable(GL_FOG);
+ printf("Squares should be colored from white -> gray -> black.\n");
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/fptest1.c b/tests/mesa/tests/fptest1.c
new file mode 100644
index 00000000..095190a8
--- /dev/null
+++ b/tests/mesa/tests/fptest1.c
@@ -0,0 +1,225 @@
+/* Test GL_NV_fragment_program */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+
+ glColor4f(0, 0.5, 0, 1);
+ glColor4f(0, 1, 0, 1);
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 0, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ static const char *prog0 =
+ "!!FP1.0\n"
+ "MUL o[COLR], R0, f[WPOS]; \n"
+ "ADD o[COLH], H3, f[TEX0]; \n"
+ "ADD_SAT o[COLH], H3, f[TEX0]; \n"
+ "ADDX o[COLH], H3, f[TEX0]; \n"
+ "ADDHC o[COLH], H3, f[TEX0]; \n"
+ "ADDXC o[COLH], H3, f[TEX0]; \n"
+ "ADDXC_SAT o[COLH], H30, f[TEX0]; \n"
+ "MUL o[COLR].xy, R0.wzyx, f[WPOS]; \n"
+ "MUL o[COLR], H0, f[WPOS]; \n"
+ "MUL o[COLR], -H0, f[WPOS]; \n"
+ "MOV RC, H1; \n"
+ "MOV HC, H2; \n"
+ "END \n"
+ ;
+
+ /* masked updates, defines, declarations */
+ static const char *prog1 =
+ "!!FP1.0\n"
+ "DEFINE foo = {1, 2, 3, 4}; \n"
+ "DEFINE foo2 = 5; \n"
+ "DECLARE foo3 = {5, 6, 7, 8}; \n"
+ "DECLARE bar = 3; \n"
+ "DECLARE bar2; \n"
+ "DECLARE bar3 = bar; \n"
+ "#DECLARE bar4 = { a, b, c, d }; \n"
+ "MOV o[COLR].xy, R0; \n"
+ "MOV o[COLR] (NE), R0; \n"
+ "MOV o[COLR] (NE.wzyx), R0; \n"
+ "MOV o[COLR].xy (NE.wzyx), R0; \n"
+ "MOV RC.x (EQ), R1.x; \n"
+ "KIL NE; \n"
+ "KIL EQ.xyxy; \n"
+ "END \n"
+ ;
+
+ /* texture instructions */
+ static const char *prog2 =
+ "!!FP1.0\n"
+ "TEX R0, f[TEX0], TEX0, 2D; \n"
+ "TEX R1, f[TEX1], TEX1, CUBE; \n"
+ "TEX R2, f[TEX2], TEX2, 3D; \n"
+ "TXP R3, f[TEX3], TEX3, RECT; \n"
+ "TXD R3, R2, R1, f[TEX3], TEX3, RECT; \n"
+ "MUL o[COLR], R0, f[COL0]; \n"
+ "END \n"
+ ;
+
+ /* test negation, absolute value */
+ static const char *prog3 =
+ "!!FP1.0\n"
+ "MOV R0, -R1; \n"
+ "MOV R0, +R1; \n"
+ "MOV R0, |-R1|; \n"
+ "MOV R0, |+R1|; \n"
+ "MOV R0, -|R1|; \n"
+ "MOV R0, +|R1|; \n"
+ "MOV R0, -|-R1|; \n"
+ "MOV R0, -|+R1|; \n"
+ "MOV o[COLR], R0; \n"
+ "END \n"
+ ;
+
+ /* literal constant sources */
+ static const char *prog4 =
+ "!!FP1.0\n"
+ "DEFINE Pi = 3.14159; \n"
+ "MOV R0, {1, -2, +3, 4}; \n"
+ "MOV R0, 5; \n"
+ "MOV R0, -5; \n"
+ "MOV R0, +5; \n"
+ "MOV R0, Pi; \n"
+ "MOV o[COLR], R0; \n"
+ "END \n"
+ ;
+
+ /* change the fragment color in a simple way */
+ static const char *prog10 =
+ "!!FP1.0\n"
+ "DEFINE blue = {0, 0, 1, 0};\n"
+ "DECLARE color; \n"
+ "MOV R0, f[COL0]; \n"
+ "#ADD o[COLR], R0, f[COL0]; \n"
+ "#ADD o[COLR], blue, f[COL0]; \n"
+ "#ADD o[COLR], {1, 0, 0, 0}, f[COL0]; \n"
+ "ADD o[COLR], color, f[COL0]; \n"
+ "END \n"
+ ;
+
+ GLuint progs[20];
+
+ if (!glutExtensionSupported ("GL_NV_fragment_program")) {
+ printf("Sorry, this program requires GL_NV_fragment_program\n");
+ exit(1);
+ }
+
+ glGenProgramsNV(20, progs);
+ assert(progs[0]);
+ assert(progs[1]);
+ assert(progs[0] != progs[1]);
+
+#if 0
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[0],
+ strlen(prog0),
+ (const GLubyte *) prog0);
+ assert(glIsProgramNV(progs[0]));
+#endif
+
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[1],
+ strlen(prog1),
+ (const GLubyte *) prog1);
+ assert(glIsProgramNV(progs[1]));
+
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[2],
+ strlen(prog2),
+ (const GLubyte *) prog2);
+ assert(glIsProgramNV(progs[2]));
+ glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[2]);
+
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[3],
+ strlen(prog3),
+ (const GLubyte *) prog3);
+ assert(glIsProgramNV(progs[3]));
+ glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[3]);
+
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[4],
+ strlen(prog4),
+ (const GLubyte *) prog4);
+ assert(glIsProgramNV(progs[4]));
+ glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[4]);
+
+
+ /* a real program */
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[10],
+ strlen(prog10),
+ (const GLubyte *) prog10);
+ assert(glIsProgramNV(progs[10]));
+ glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, progs[10]);
+
+ glProgramNamedParameter4fNV(progs[10],
+ strlen("color"), (const GLubyte *) "color",
+ 1, 0, 0, 1);
+
+ glEnable(GL_FRAGMENT_PROGRAM_NV);
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(GL_ALWAYS, 0.0);
+
+ printf("glGetError = %d\n", (int) glGetError());
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/fptexture.c b/tests/mesa/tests/fptexture.c
new file mode 100644
index 00000000..f57ad628
--- /dev/null
+++ b/tests/mesa/tests/fptexture.c
@@ -0,0 +1,151 @@
+/* GL_NV_fragment_program texture test */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+#include "../util/readtex.c"
+
+
+#define TEXTURE_FILE "../images/girl.rgb"
+
+static GLfloat Xrot = 0.0, Yrot = 0.0, Zrot = 0.0;
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+
+ glBegin(GL_POLYGON);
+ glColor4f(1.0, 1.0, 1.0, 1); glTexCoord2f(0, 0); glVertex2f(-1, -1);
+ glColor4f(0.2, 0.2, 1.0, 1); glTexCoord2f(1, 0); glVertex2f( 1, -1);
+ glColor4f(0.2, 1.0, 0.2, 1); glTexCoord2f(1, 1); glVertex2f( 1, 1);
+ glColor4f(1.0, 0.2, 0.2, 1); glTexCoord2f(0, 1); glVertex2f(-1, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -8.0 );
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ static const char *modulate2D =
+ "!!FP1.0\n"
+ "TEX R0, f[TEX0], TEX0, 2D; \n"
+ "MUL o[COLR], R0, f[COL0]; \n"
+ "END"
+ ;
+ GLuint modulateProg;
+ GLuint Texture;
+
+ if (!glutExtensionSupported("GL_NV_fragment_program")) {
+ printf("Error: GL_NV_fragment_program not supported!\n");
+ exit(1);
+ }
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ /* Setup the fragment program */
+ glGenProgramsNV(1, &modulateProg);
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, modulateProg,
+ strlen(modulate2D),
+ (const GLubyte *) modulate2D);
+ printf("glGetError = 0x%x\n", (int) glGetError());
+ printf("glError(GL_PROGRAM_ERROR_STRING_NV) = %s\n",
+ (char *) glGetString(GL_PROGRAM_ERROR_STRING_NV));
+ assert(glIsProgramNV(modulateProg));
+
+ glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, modulateProg);
+ glEnable(GL_FRAGMENT_PROGRAM_NV);
+
+ /* Load texture */
+ glGenTextures(1, &Texture);
+ glBindTexture(GL_TEXTURE_2D, Texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
+ exit(1);
+ }
+ /* XXX this enable shouldn't really be needed!!! */
+ glEnable(GL_TEXTURE_2D);
+
+ glClearColor(.3, .3, .3, 0);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/getprocaddress.c b/tests/mesa/tests/getprocaddress.c
new file mode 100644
index 00000000..8b000d23
--- /dev/null
+++ b/tests/mesa/tests/getprocaddress.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Test that glXGetProcAddress works.
+ */
+
+#define GLX_GLXEXT_PROTOTYPES
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+
+typedef void (*generic_func)();
+
+#define EQUAL(X, Y) (fabs((X) - (Y)) < 0.001)
+
+/**
+ * The following functions are used to check that the named OpenGL function
+ * actually does what it's supposed to do.
+ * The naming of these functions is signficant. The getprocaddress.py script
+ * scans this file and extracts these function names.
+ */
+
+
+static GLboolean
+test_ActiveTextureARB(generic_func func)
+{
+ PFNGLACTIVETEXTUREARBPROC activeTexture = (PFNGLACTIVETEXTUREARBPROC) func;
+ GLint t;
+ GLboolean pass;
+ (*activeTexture)(GL_TEXTURE1_ARB);
+ glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &t);
+ pass = (t == GL_TEXTURE1_ARB);
+ (*activeTexture)(GL_TEXTURE0_ARB); /* restore default */
+ return pass;
+}
+
+
+static GLboolean
+test_SecondaryColor3fEXT(generic_func func)
+{
+ PFNGLSECONDARYCOLOR3FEXTPROC secColor3f = (PFNGLSECONDARYCOLOR3FEXTPROC) func;
+ GLfloat color[4];
+ GLboolean pass;
+ (*secColor3f)(1.0, 1.0, 0.0);
+ glGetFloatv(GL_CURRENT_SECONDARY_COLOR_EXT, color);
+ pass = (color[0] == 1.0 && color[1] == 1.0 && color[2] == 0.0);
+ (*secColor3f)(0.0, 0.0, 0.0); /* restore default */
+ return pass;
+}
+
+
+static GLboolean
+test_ActiveStencilFaceEXT(generic_func func)
+{
+ PFNGLACTIVESTENCILFACEEXTPROC activeFace = (PFNGLACTIVESTENCILFACEEXTPROC) func;
+ GLint face;
+ GLboolean pass;
+ (*activeFace)(GL_BACK);
+ glGetIntegerv(GL_ACTIVE_STENCIL_FACE_EXT, &face);
+ pass = (face == GL_BACK);
+ (*activeFace)(GL_FRONT); /* restore default */
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib1fvARB(generic_func func)
+{
+ PFNGLVERTEXATTRIB1FVARBPROC vertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) func;
+ PFNGLGETVERTEXATTRIBFVARBPROC getVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvARB");
+
+ const GLfloat v[1] = {25.0};
+ const GLfloat def[1] = {0};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib1fvARB)(6, v);
+ (*getVertexAttribfvARB)(6, GL_CURRENT_VERTEX_ATTRIB_ARB, res);
+ pass = (res[0] == 25.0 && res[1] == 0.0 && res[2] == 0.0 && res[3] == 1.0);
+ (*vertexAttrib1fvARB)(6, def);
+ return pass;
+}
+
+static GLboolean
+test_VertexAttrib4NubvARB(generic_func func)
+{
+ PFNGLVERTEXATTRIB4NUBVARBPROC vertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) func;
+ PFNGLGETVERTEXATTRIBFVARBPROC getVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvARB");
+
+ const GLubyte v[4] = {255, 0, 255, 0};
+ const GLubyte def[4] = {0, 0, 0, 255};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib4NubvARB)(6, v);
+ (*getVertexAttribfvARB)(6, GL_CURRENT_VERTEX_ATTRIB_ARB, res);
+ pass = (res[0] == 1.0 && res[1] == 0.0 && res[2] == 1.0 && res[3] == 0.0);
+ (*vertexAttrib4NubvARB)(6, def);
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib4NuivARB(generic_func func)
+{
+ PFNGLVERTEXATTRIB4NUIVARBPROC vertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) func;
+ PFNGLGETVERTEXATTRIBFVARBPROC getVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvARB");
+
+ const GLuint v[4] = {0xffffffff, 0, 0xffffffff, 0};
+ const GLuint def[4] = {0, 0, 0, 0xffffffff};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib4NuivARB)(6, v);
+ (*getVertexAttribfvARB)(6, GL_CURRENT_VERTEX_ATTRIB_ARB, res);
+ pass = (EQUAL(res[0], 1.0) && EQUAL(res[1], 0.0) && EQUAL(res[2], 1.0) && EQUAL(res[3], 0.0));
+ (*vertexAttrib4NuivARB)(6, def);
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib4ivARB(generic_func func)
+{
+ PFNGLVERTEXATTRIB4IVARBPROC vertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) func;
+ PFNGLGETVERTEXATTRIBFVARBPROC getVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvARB");
+
+ const GLint v[4] = {1, 2, -3, 4};
+ const GLint def[4] = {0, 0, 0, 1};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib4ivARB)(6, v);
+ (*getVertexAttribfvARB)(6, GL_CURRENT_VERTEX_ATTRIB_ARB, res);
+ pass = (EQUAL(res[0], 1.0) && EQUAL(res[1], 2.0) && EQUAL(res[2], -3.0) && EQUAL(res[3], 4.0));
+ (*vertexAttrib4ivARB)(6, def);
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib4NsvARB(generic_func func)
+{
+ PFNGLVERTEXATTRIB4NSVARBPROC vertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) func;
+ PFNGLGETVERTEXATTRIBFVARBPROC getVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvARB");
+
+ const GLshort v[4] = {0, 32767, 32767, 0};
+ const GLshort def[4] = {0, 0, 0, 32767};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib4NsvARB)(6, v);
+ (*getVertexAttribfvARB)(6, GL_CURRENT_VERTEX_ATTRIB_ARB, res);
+ pass = (EQUAL(res[0], 0.0) && EQUAL(res[1], 1.0) && EQUAL(res[2], 1.0) && EQUAL(res[3], 0.0));
+ (*vertexAttrib4NsvARB)(6, def);
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib4NusvARB(generic_func func)
+{
+ PFNGLVERTEXATTRIB4NUSVARBPROC vertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) func;
+ PFNGLGETVERTEXATTRIBFVARBPROC getVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvARB");
+
+ const GLushort v[4] = {0xffff, 0, 0xffff, 0};
+ const GLushort def[4] = {0, 0, 0, 0xffff};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib4NusvARB)(6, v);
+ (*getVertexAttribfvARB)(6, GL_CURRENT_VERTEX_ATTRIB_ARB, res);
+ pass = (EQUAL(res[0], 1.0) && EQUAL(res[1], 0.0) && EQUAL(res[2], 1.0) && EQUAL(res[3], 0.0));
+ (*vertexAttrib4NusvARB)(6, def);
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib4ubNV(generic_func func)
+{
+ PFNGLVERTEXATTRIB4UBNVPROC vertexAttrib4ubNV = (PFNGLVERTEXATTRIB4UBNVPROC) func;
+ PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV");
+
+ const GLubyte v[4] = {255, 0, 255, 0};
+ const GLubyte def[4] = {0, 0, 0, 255};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib4ubNV)(6, v[0], v[1], v[2], v[3]);
+ (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res);
+ pass = (res[0] == 1.0 && res[1] == 0.0 && res[2] == 1.0 && res[3] == 0.0);
+ (*vertexAttrib4ubNV)(6, def[0], def[1], def[2], def[3]);
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib2sNV(generic_func func)
+{
+ PFNGLVERTEXATTRIB2SNVPROC vertexAttrib2sNV = (PFNGLVERTEXATTRIB2SNVPROC) func;
+ PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV");
+
+ const GLshort v[2] = {2, -4,};
+ const GLshort def[2] = {0, 0};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib2sNV)(6, v[0], v[1]);
+ (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res);
+ pass = (EQUAL(res[0], 2) && EQUAL(res[1], -4) && EQUAL(res[2], 0) && res[3] == 1.0);
+ (*vertexAttrib2sNV)(6, def[0], def[1]);
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib3fNV(generic_func func)
+{
+ PFNGLVERTEXATTRIB3FNVPROC vertexAttrib3fNV = (PFNGLVERTEXATTRIB3FNVPROC) func;
+ PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV");
+
+ const GLfloat v[3] = {0.2, 0.4, 0.8};
+ const GLfloat def[3] = {0, 0, 0};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib3fNV)(6, v[0], v[1], v[2]);
+ (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res);
+ pass = (EQUAL(res[0], 0.2) && EQUAL(res[1], 0.4) && EQUAL(res[2], 0.8) && res[3] == 1.0);
+ (*vertexAttrib3fNV)(6, def[0], def[1], def[2]);
+ return pass;
+}
+
+
+static GLboolean
+test_VertexAttrib4dvNV(generic_func func)
+{
+ PFNGLVERTEXATTRIB4DVNVPROC vertexAttrib4dvNV = (PFNGLVERTEXATTRIB4DVNVPROC) func;
+ PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV");
+
+ const GLdouble v[4] = {0.2, 0.4, 0.8, 1.2};
+ const GLdouble def[4] = {0, 0, 0, 1};
+ GLfloat res[4];
+ GLboolean pass;
+ (*vertexAttrib4dvNV)(6, v);
+ (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res);
+ pass = (EQUAL(res[0], 0.2) && EQUAL(res[1], 0.4) && EQUAL(res[2], 0.8) && EQUAL(res[3], 1.2));
+ (*vertexAttrib4dvNV)(6, def);
+ return pass;
+}
+
+
+static GLboolean
+test_StencilFuncSeparate(generic_func func)
+{
+#ifdef GL_VERSION_2_0
+ PFNGLSTENCILFUNCSEPARATEPROC stencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) func;
+ GLint frontFunc, backFunc;
+ GLint frontRef, backRef;
+ GLint frontMask, backMask;
+ (*stencilFuncSeparate)(GL_BACK, GL_GREATER, 2, 0xa);
+ glGetIntegerv(GL_STENCIL_FUNC, &frontFunc);
+ glGetIntegerv(GL_STENCIL_BACK_FUNC, &backFunc);
+ glGetIntegerv(GL_STENCIL_REF, &frontRef);
+ glGetIntegerv(GL_STENCIL_BACK_REF, &backRef);
+ glGetIntegerv(GL_STENCIL_VALUE_MASK, &frontMask);
+ glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &backMask);
+ if (frontFunc != GL_ALWAYS ||
+ backFunc != GL_GREATER ||
+ frontRef != 0 ||
+ backRef != 2 ||
+ frontMask == 0xa || /* might be 0xff or ~0 */
+ backMask != 0xa)
+ return GL_FALSE;
+#endif
+ return GL_TRUE;
+}
+
+static GLboolean
+test_StencilOpSeparate(generic_func func)
+{
+#ifdef GL_VERSION_2_0
+ PFNGLSTENCILOPSEPARATEPROC stencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) func;
+ GLint frontFail, backFail;
+ GLint frontZFail, backZFail;
+ GLint frontZPass, backZPass;
+ (*stencilOpSeparate)(GL_BACK, GL_INCR, GL_DECR, GL_INVERT);
+ glGetIntegerv(GL_STENCIL_FAIL, &frontFail);
+ glGetIntegerv(GL_STENCIL_BACK_FAIL, &backFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &frontZFail);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &backZFail);
+ glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &frontZPass);
+ glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &backZPass);
+ if (frontFail != GL_KEEP ||
+ backFail != GL_INCR ||
+ frontZFail != GL_KEEP ||
+ backZFail != GL_DECR ||
+ frontZPass != GL_KEEP ||
+ backZPass != GL_INVERT)
+ return GL_FALSE;
+#endif
+ return GL_TRUE;
+}
+
+static GLboolean
+test_StencilMaskSeparate(generic_func func)
+{
+#ifdef GL_VERSION_2_0
+ PFNGLSTENCILMASKSEPARATEPROC stencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) func;
+ GLint frontMask, backMask;
+ (*stencilMaskSeparate)(GL_BACK, 0x1b);
+ glGetIntegerv(GL_STENCIL_WRITEMASK, &frontMask);
+ glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &backMask);
+ if (frontMask == 0x1b ||
+ backMask != 0x1b)
+ return GL_FALSE;
+#endif
+ return GL_TRUE;
+}
+
+
+/*
+ * The following file is auto-generated with Python.
+ */
+#include "getproclist.h"
+
+
+
+static int
+extension_supported(const char *haystack, const char *needle)
+{
+ const char *p = strstr(haystack, needle);
+ if (p) {
+ /* found string, make sure next char is space or zero */
+ const int len = strlen(needle);
+ if (p[len] == ' ' || p[len] == 0)
+ return 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+
+static void
+check_functions( const char *extensions )
+{
+ struct name_test_pair *entry;
+ int failures = 0, passes = 0;
+ int totalFail = 0, totalPass = 0;
+ int doTests;
+
+ for (entry = functions; entry->name; entry++) {
+ if (entry->name[0] == '-') {
+ const char *version = (const char *) glGetString(GL_VERSION);
+ if (entry->name[1] == '1') {
+ /* check GL version 1.x */
+ if (version[0] == '1' &&
+ version[1] == '.' &&
+ version[2] >= entry->name[3])
+ doTests = 1;
+ else
+ doTests = 0;
+ }
+ else if (entry->name[1] == '2') {
+ if (version[0] == '2' &&
+ version[1] == '.' &&
+ version[2] >= entry->name[3])
+ doTests = 1;
+ else
+ doTests = 0;
+ }
+ else {
+ /* check if the named extension is available */
+ doTests = extension_supported(extensions, entry->name+1);
+ }
+ if (doTests)
+ printf("Testing %s functions\n", entry->name + 1);
+ totalFail += failures;
+ totalPass += passes;
+ failures = 0;
+ passes = 0;
+ }
+ else if (doTests) {
+ generic_func funcPtr = (generic_func) glXGetProcAddressARB((const GLubyte *) entry->name);
+ if (funcPtr) {
+ if (entry->test) {
+ GLboolean b;
+ printf(" Validating %s:", entry->name);
+ b = (*entry->test)(funcPtr);
+ if (b) {
+ printf(" Pass\n");
+ passes++;
+ }
+ else {
+ printf(" FAIL!!!\n");
+ failures++;
+ }
+ }
+ else {
+ passes++;
+ }
+ }
+ else {
+ printf(" glXGetProcAddress(%s) failed!\n", entry->name);
+ failures++;
+ }
+ }
+
+ if (doTests && (!(entry+1)->name || (entry+1)->name[0] == '-')) {
+ if (failures > 0) {
+ printf(" %d failed.\n", failures);
+ }
+ if (passes > 0) {
+ printf(" %d passed.\n", passes);
+ }
+ }
+ }
+ totalFail += failures;
+ totalPass += passes;
+
+ printf("-----------------------------\n");
+ printf("Total: %d pass %d fail\n", totalPass, totalFail);
+}
+
+
+
+static void
+print_screen_info(Display *dpy, int scrnum, Bool allowDirect)
+{
+ Window win;
+ int attribSingle[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_STENCIL_SIZE, 1,
+ None };
+ int attribDouble[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_STENCIL_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+ int width = 100, height = 100;
+
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
+ if (!visinfo) {
+ visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
+ if (!visinfo) {
+ fprintf(stderr, "Error: couldn't find RGB GLX visual\n");
+ return;
+ }
+ }
+
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+ win = XCreateWindow(dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect );
+ if (!ctx) {
+ fprintf(stderr, "Error: glXCreateContext failed\n");
+ XDestroyWindow(dpy, win);
+ return;
+ }
+
+ if (glXMakeCurrent(dpy, win, ctx)) {
+ check_functions( (const char *) glGetString(GL_EXTENSIONS) );
+ }
+ else {
+ fprintf(stderr, "Error: glXMakeCurrent failed\n");
+ }
+
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ char *displayName = NULL;
+ Display *dpy;
+
+ dpy = XOpenDisplay(displayName);
+ if (!dpy) {
+ fprintf(stderr, "Error: unable to open display %s\n", displayName);
+ return -1;
+ }
+
+ print_screen_info(dpy, 0, GL_TRUE);
+
+ XCloseDisplay(dpy);
+
+ return 0;
+}
diff --git a/tests/mesa/tests/interleave.c b/tests/mesa/tests/interleave.c
new file mode 100644
index 00000000..e98b3ed0
--- /dev/null
+++ b/tests/mesa/tests/interleave.c
@@ -0,0 +1,406 @@
+/*
+ * (C) Copyright IBM Corporation 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file interleave.c
+ *
+ * Simple test of glInterleavedArrays functionality. For each mode, two
+ * meshes are drawn. One is drawn using interleaved arrays and the othe is
+ * drawn using immediate mode. Both should look identical.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <GL/glut.h>
+
+static int Width = 400;
+static int Height = 300;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+static const GLfloat t[][4] = {
+ { 0.5, 0.0, 0.0, 1.0 },
+
+ { 0.25, 0.5, 0.0, 1.0 },
+ { 0.75, 0.5, 0.0, 1.0 },
+
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.5, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+};
+
+static const GLfloat c_f[][4] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+};
+
+static const GLubyte c_ub[][4] = {
+ { 0xff, 0x00, 0x00, 0xff },
+
+ { 0x00, 0xff, 0x00, 0xff },
+ { 0x00, 0xff, 0x00, 0xff },
+
+ { 0x00, 0x00, 0xff, 0xff },
+ { 0xff, 0x00, 0xff, 0xff },
+ { 0x00, 0x00, 0xff, 0xff },
+};
+
+static const GLfloat n[][3] = {
+ { 0.0, 0.0, -1.0 },
+
+ { 0.0, 0.0, -1.0 },
+ { 0.0, 0.0, -1.0 },
+
+ { 0.0, 0.0, -1.0 },
+ { 0.0, 0.0, -1.0 },
+ { 0.0, 0.0, -1.0 },
+};
+
+static const GLfloat v[][4] = {
+ { 0.0, 1.0, 0.0, 1.0, },
+
+ { -0.5, 0.0, 0.0, 1.0, },
+ { 0.5, 0.0, 0.0, 1.0, },
+
+ { -1.0, -1.0, 0.0, 1.0, },
+ { 0.0, -1.0, 0.0, 1.0, },
+ { 1.0, -1.0, 0.0, 1.0, },
+};
+
+static const unsigned indicies[12] = {
+ 0, 1, 2,
+ 1, 3, 4,
+ 2, 4, 5,
+ 1, 4, 2
+};
+
+#define NONE { NULL, 0, 0, 0 }
+#define V2F { v, 2, 2 * sizeof( GLfloat ), GL_FLOAT, sizeof( v[0] ) }
+#define V3F { v, 3, 3 * sizeof( GLfloat ), GL_FLOAT, sizeof( v[0] ) }
+#define V4F { v, 4, 4 * sizeof( GLfloat ), GL_FLOAT, sizeof( v[0] ) }
+
+#define C4UB { c_ub, 4, 4 * sizeof( GLubyte ), GL_UNSIGNED_BYTE, sizeof( c_ub[0] ) }
+#define C3F { c_f, 3, 3 * sizeof( GLfloat ), GL_FLOAT, sizeof( c_f[0] ) }
+#define C4F { c_f, 4, 4 * sizeof( GLfloat ), GL_FLOAT, sizeof( c_f[0] ) }
+
+#define T2F { t, 2, 2 * sizeof( GLfloat ), GL_FLOAT, sizeof( t[0] ) }
+#define T4F { t, 4, 4 * sizeof( GLfloat ), GL_FLOAT, sizeof( t[0] ) }
+
+#define N3F { n, 3, 3 * sizeof( GLfloat ), GL_FLOAT, sizeof( n[0] ) }
+
+struct interleave_info {
+ const void * data;
+ unsigned count;
+ unsigned size;
+ GLenum type;
+ unsigned stride;
+};
+
+#define NUM_MODES 14
+#define INVALID_MODE 14
+#define INVALID_STRIDE 15
+
+struct interleave_info info[ NUM_MODES ][4] = {
+ { NONE, NONE, NONE, V2F },
+ { NONE, NONE, NONE, V3F },
+ { NONE, C4UB, NONE, V2F },
+ { NONE, C4UB, NONE, V3F },
+ { NONE, C3F, NONE, V3F },
+
+ { NONE, NONE, N3F, V3F },
+ { NONE, C4F, N3F, V3F },
+
+ { T2F, NONE, NONE, V3F },
+ { T4F, NONE, NONE, V4F },
+
+ { T2F, C4UB, NONE, V3F },
+ { T2F, C3F, NONE, V3F },
+ { T2F, NONE, N3F, V3F },
+ { T2F, C4F, N3F, V3F },
+ { T4F, C4F, N3F, V4F },
+};
+
+const char * const mode_names[ NUM_MODES ] = {
+ "GL_V2F",
+ "GL_V3F",
+ "GL_C4UB_V2F",
+ "GL_C4UB_V3F",
+ "GL_C3F_V3F",
+ "GL_N3F_V3F",
+ "GL_C4F_N3F_V3F",
+ "GL_T2F_V3F",
+ "GL_T4F_V4F",
+ "GL_T2F_C4UB_V3F",
+ "GL_T2F_C3F_V3F",
+ "GL_T2F_N3F_V3F",
+ "GL_T2F_C4F_N3F_V3F",
+ "GL_T4F_C4F_N3F_V4F",
+};
+
+static unsigned interleave_mode = 0;
+static GLboolean use_invalid_mode = GL_FALSE;
+static GLboolean use_invalid_stride = GL_FALSE;
+
+#define DEREF(item,idx) (void *) & ((char *)curr_info[item].data)[idx * curr_info[item].stride]
+
+static void Display( void )
+{
+ const struct interleave_info * const curr_info = info[ interleave_mode ];
+
+ /* 4 floats for 12 verticies for 4 data elements.
+ */
+ char data[ (sizeof( GLfloat ) * 4) * 12 * 4 ];
+
+ unsigned i;
+ unsigned offset;
+ GLenum err;
+ GLenum format;
+ GLsizei stride;
+
+
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+
+ glTranslatef(-1.5, 0, 0);
+
+ glColor3fv( c_f[0] );
+
+ if ( curr_info[0].data != NULL ) {
+ glEnable( GL_TEXTURE_2D );
+ }
+ else {
+ glDisable( GL_TEXTURE_2D );
+ }
+
+
+ offset = 0;
+ glBegin(GL_TRIANGLES);
+ for ( i = 0 ; i < 12 ; i++ ) {
+ const unsigned index = indicies[i];
+
+
+ /* Handle the vertex texture coordinate.
+ */
+ if ( curr_info[0].data != NULL ) {
+ if ( curr_info[0].count == 2 ) {
+ glTexCoord2fv( DEREF(0, index) );
+ }
+ else {
+ glTexCoord4fv( DEREF(0, index) );
+ }
+
+ (void) memcpy( & data[ offset ], DEREF(0, index),
+ curr_info[0].size );
+ offset += curr_info[0].size;
+ }
+
+
+ /* Handle the vertex color.
+ */
+ if ( curr_info[1].data != NULL ) {
+ if ( curr_info[1].type == GL_FLOAT ) {
+ if ( curr_info[1].count == 3 ) {
+ glColor3fv( DEREF(1, index) );
+ }
+ else {
+ glColor4fv( DEREF(1, index) );
+ }
+ }
+ else {
+ glColor4ubv( DEREF(1, index) );
+ }
+
+ (void) memcpy( & data[ offset ], DEREF(1, index),
+ curr_info[1].size );
+ offset += curr_info[1].size;
+ }
+
+
+ /* Handle the vertex normal.
+ */
+ if ( curr_info[2].data != NULL ) {
+ glNormal3fv( DEREF(2, index) );
+
+ (void) memcpy( & data[ offset ], DEREF(2, index),
+ curr_info[2].size );
+ offset += curr_info[2].size;
+ }
+
+
+ switch( curr_info[3].count ) {
+ case 2:
+ glVertex2fv( DEREF(3, index) );
+ break;
+ case 3:
+ glVertex3fv( DEREF(3, index) );
+ break;
+ case 4:
+ glVertex4fv( DEREF(3, index) );
+ break;
+ }
+
+ (void) memcpy( & data[ offset ], DEREF(3, index),
+ curr_info[3].size );
+ offset += curr_info[3].size;
+ }
+ glEnd();
+
+
+ glTranslatef(3.0, 0, 0);
+
+ /* The masking with ~0x2A00 is a bit of a hack to make sure that format
+ * ends up with an invalid value no matter what rand() returns.
+ */
+ format = (use_invalid_mode)
+ ? (rand() & ~0x2A00) : GL_V2F + interleave_mode;
+ stride = (use_invalid_stride) ? -abs(rand()) : 0;
+
+ (void) glGetError();
+ glInterleavedArrays( format, stride, data );
+ err = glGetError();
+ if ( err ) {
+ printf("glInterleavedArrays(0x%04x, %d, %p) generated the error 0x%04x\n",
+ format, stride, data, err );
+ }
+ else {
+ glDrawArrays( GL_TRIANGLES, 0, 12 );
+ }
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void ModeMenu( int entry )
+{
+ if ( entry == INVALID_MODE ) {
+ use_invalid_mode = GL_TRUE;
+ use_invalid_stride = GL_FALSE;
+ }
+ else if ( entry == INVALID_STRIDE ) {
+ use_invalid_mode = GL_FALSE;
+ use_invalid_stride = GL_TRUE;
+ }
+ else {
+ use_invalid_mode = GL_FALSE;
+ use_invalid_stride = GL_FALSE;
+ interleave_mode = entry;
+ }
+}
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+ const GLubyte tex[16] = {
+ 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0xff,
+ };
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, tex );
+
+ printf("Use the context menu (right click) to select the interleaved array mode.\n");
+ printf("Press ESCAPE to exit.\n\n");
+ printf("NOTE: This is *NOT* a very good test of the modes that use normals.\n");
+}
+
+
+int main( int argc, char *argv[] )
+{
+ unsigned i;
+
+ srand( time( NULL ) );
+
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "glInterleavedArrays test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+
+ glutCreateMenu( ModeMenu );
+ for ( i = 0 ; i < NUM_MODES ; i++ ) {
+ glutAddMenuEntry( mode_names[i], i);
+ }
+
+ glutAddMenuEntry( "Random invalid mode", INVALID_MODE);
+ glutAddMenuEntry( "Random invalid stride", INVALID_STRIDE);
+
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/invert.c b/tests/mesa/tests/invert.c
new file mode 100644
index 00000000..750592ed
--- /dev/null
+++ b/tests/mesa/tests/invert.c
@@ -0,0 +1,195 @@
+/*
+ * (C) Copyright IBM Corporation 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file invert.c
+ *
+ * Simple test of GL_MESA_pack_invert functionality. Three squares are
+ * drawn. The first two should look the same, and the third one should
+ * look inverted.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <GL/glut.h>
+
+#include "readtex.h"
+
+#define IMAGE_FILE "../images/tree3.rgb"
+
+static int Width = 420;
+static int Height = 150;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+static GLubyte * image = NULL;
+static GLubyte * temp_image = NULL;
+static GLuint img_width = 0;
+static GLuint img_height = 0;
+static GLuint img_format = 0;
+
+PFNGLWINDOWPOS2IPROC win_pos_2i = NULL;
+
+
+static void Display( void )
+{
+ GLint err;
+
+
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+
+ /* This is the "reference" square.
+ */
+
+ (*win_pos_2i)( 5, 5 );
+ glDrawPixels( img_width, img_height, img_format, GL_UNSIGNED_BYTE, image );
+
+ glPixelStorei( GL_PACK_INVERT_MESA, GL_FALSE );
+ err = glGetError();
+ if ( err != GL_NO_ERROR ) {
+ printf( "Setting PACK_INVERT_MESA to false generated an error (0x%04x).\n",
+ err );
+ }
+
+ glReadPixels( 5, 5, img_width, img_height, img_format, GL_UNSIGNED_BYTE, temp_image );
+ (*win_pos_2i)( 5 + 1 * (10 + img_width), 5 );
+ glDrawPixels( img_width, img_height, img_format, GL_UNSIGNED_BYTE, temp_image );
+
+ glPixelStorei( GL_PACK_INVERT_MESA, GL_TRUE );
+ err = glGetError();
+ if ( err != GL_NO_ERROR ) {
+ printf( "Setting PACK_INVERT_MESA to true generated an error (0x%04x).\n",
+ err );
+ }
+
+ glReadPixels( 5, 5, img_width, img_height, img_format, GL_UNSIGNED_BYTE, temp_image );
+ (*win_pos_2i)( 5 + 2 * (10 + img_width), 5 );
+ glDrawPixels( img_width, img_height, img_format, GL_UNSIGNED_BYTE, temp_image );
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+ const float ver = strtof( ver_string, NULL );
+
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ if ( !glutExtensionSupported("GL_MESA_pack_invert") ) {
+ printf("\nSorry, this program requires GL_MESA_pack_invert.\n");
+ exit(1);
+ }
+
+ if ( ver >= 1.4 ) {
+ win_pos_2i = (PFNGLWINDOWPOS2IPROC) glutGetProcAddress( "glWindowPos2i" );
+ }
+ else if ( glutExtensionSupported("GL_ARB_window_pos") ) {
+ win_pos_2i = (PFNGLWINDOWPOS2IPROC) glutGetProcAddress( "glWindowPos2iARB" );
+ }
+ else if ( glutExtensionSupported("GL_MESA_window_pos") ) {
+ win_pos_2i = (PFNGLWINDOWPOS2IPROC) glutGetProcAddress( "glWindowPos2iMESA" );
+ }
+
+
+ /* Do this check as a separate if-statement instead of as an else in case
+ * one of the required extensions is supported but glutGetProcAddress
+ * returns NULL.
+ */
+
+ if ( win_pos_2i == NULL ) {
+ printf("\nSorry, this program requires either GL 1.4 (or higher),\n"
+ "GL_ARB_window_pos, or GL_MESA_window_pos.\n");
+ exit(1);
+ }
+
+ printf("\nThe left 2 squares should be the same color, and the right\n"
+ "square should look upside-down.\n");
+
+
+ image = LoadRGBImage( IMAGE_FILE, & img_width, & img_height,
+ & img_format );
+ if ( image == NULL ) {
+ printf( "Could not open image file \"%s\".\n", IMAGE_FILE );
+ exit(1);
+ }
+
+ temp_image = malloc( 3 * img_height * img_width );
+ if ( temp_image == NULL ) {
+ printf( "Could not allocate memory for temporary image.\n" );
+ exit(1);
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "GL_MESA_pack_invert test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/jkrahntest.c b/tests/mesa/tests/jkrahntest.c
new file mode 100644
index 00000000..85bda8d0
--- /dev/null
+++ b/tests/mesa/tests/jkrahntest.c
@@ -0,0 +1,181 @@
+/* $Id: jkrahntest.c,v 1.2 2006/01/30 17:12:10 brianp Exp $ */
+
+/* This is a good test for glXSwapBuffers on non-current windows,
+ * and the glXCopyContext function. Fixed several Mesa/DRI bugs with
+ * this program on 15 June 2002.
+ *
+ * Joe's comments follow:
+ *
+ * I have tried some different approaches for being able to
+ * draw to multiple windows using one context, or a copied
+ * context. Mesa/indirect rendering works to use one context
+ * for multiple windows, but crashes with glXCopyContext.
+ * DRI is badly broken, at least for ATI.
+ *
+ * I also noticed that glXMakeCurrent allows a window and context
+ * from different visuals to be attached (haven't tested recently).
+ *
+ * Joe Krahn <jkrahn@nc.rr.com>
+ */
+
+#include <GL/glx.h>
+#include <GL/gl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159
+#endif
+
+#define DEGTOR (M_PI/180.0)
+
+static int AttributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
+
+int main(int argc, char **argv)
+{
+ Window win1, win2;
+ XVisualInfo *vi;
+ XSetWindowAttributes swa;
+ Display *dpy;
+ GLXContext ctx1, ctx2;
+ float angle;
+ int test;
+
+ if (argc < 2) {
+ fprintf(stderr, "This program tests GLX context switching.\n");
+ fprintf(stderr, "Usage: cxbug <n>\n");
+ fprintf(stderr, "Where n is:\n");
+ fprintf(stderr, "\t1) Use two contexts and swap only when the context is current (typical case).\n");
+ fprintf(stderr, "\t2) Use two contexts and swap at the same time.\n");
+ fprintf(stderr, "\t\t Used to crash Mesa & nVidia, and DRI artifacts. Seems OK now.\n");
+ fprintf(stderr, "\t3) Use one context, but only swap when a context is current.\n");
+ fprintf(stderr, "\t\t Serious artifacts for DRI at least with ATI.\n");
+ fprintf(stderr, "\t4) Use one context, swap both windows at the same time, so the left\n");
+ fprintf(stderr, "\t\t window has no context at swap time. Severe artifacts for DRI.\n");
+ fprintf(stderr, "\t5) Use two contexts, copying one to the other when switching windows.\n");
+ fprintf(stderr, "\t\t DRI gives an error, indirect rendering crashes server.\n");
+
+ exit(1);
+ }
+ test = atoi(argv[1]);
+
+ /* get a connection */
+ dpy = XOpenDisplay(NULL);
+
+ /* Get an appropriate visual */
+ vi = glXChooseVisual(dpy, DefaultScreen(dpy), AttributeList);
+ if (vi == 0) {
+ fprintf(stderr, "No matching visuals found.\n");
+ exit(-1);
+ }
+
+ /* Create two GLX contexts, with list sharing */
+ ctx1 = glXCreateContext(dpy, vi, 0, True);
+ ctx2 = glXCreateContext(dpy, vi, ctx1, True);
+
+ /* create a colormap */
+ swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocNone);
+ swa.border_pixel = 0;
+
+ /* Create two windows */
+ win1 = XCreateWindow(dpy, RootWindow(dpy, vi->screen),
+ 10, 10, 200, 200,
+ 0, vi->depth, InputOutput, vi->visual,
+ CWBorderPixel | CWColormap, &swa);
+ XStoreName(dpy, win1, "Test [L]");
+ XMapWindow(dpy, win1);
+ XMoveWindow(dpy, win1, 10, 10); /* Initial requested x,y may not be honored */
+ {
+ XSizeHints sizehints;
+ static const char *name = "window";
+ sizehints.x = 10;
+ sizehints.y = 10;
+ sizehints.width = 200;
+ sizehints.height = 200;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win1, &sizehints);
+ XSetStandardProperties(dpy, win1, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+
+ win2 = XCreateWindow(dpy, RootWindow(dpy, vi->screen),
+ 250, 10, 200, 200,
+ 0, vi->depth, InputOutput, vi->visual,
+ CWBorderPixel | CWColormap, &swa);
+ XStoreName(dpy, win1, "Test [R]");
+ XMapWindow(dpy, win2);
+ XMoveWindow(dpy, win2, 260, 10);
+ {
+ XSizeHints sizehints;
+ static const char *name = "window";
+ sizehints.x = 10;
+ sizehints.y = 10;
+ sizehints.width = 200;
+ sizehints.height = 200;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win2, &sizehints);
+ XSetStandardProperties(dpy, win2, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+
+ /* Now draw some spinning things */
+ for (angle = 0; angle < 360*4; angle += 10.0) {
+ /* Connect the context to window 1 */
+ glXMakeCurrent(dpy, win1, ctx1);
+
+ /* Clear and draw in window 1 */
+ glDrawBuffer(GL_BACK);
+ glClearColor(1, 1, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glColor3f(1, 0, 0);
+ glBegin(GL_TRIANGLES);
+ glVertex2f(0, 0);
+ glVertex2f(cos(angle * DEGTOR), sin(angle * DEGTOR));
+ glVertex2f(cos((angle + 20.0) * DEGTOR),
+ sin((angle + 20.0) * DEGTOR));
+ glEnd();
+ glFlush();
+
+ if (test == 1 || test == 3 || test == 5)
+ glXSwapBuffers(dpy, win1);
+
+ if (test == 5)
+ glXCopyContext(dpy, ctx1, ctx2, GL_ALL_ATTRIB_BITS);
+ /* Connect the context to window 2 */
+ if (test == 3 || test == 4) {
+ glXMakeCurrent(dpy, win2, ctx1);
+ } else {
+ glXMakeCurrent(dpy, win2, ctx2);
+ }
+
+ /* Clear and draw in window 2 */
+ glDrawBuffer(GL_BACK);
+ glClearColor(0, 0, 1, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor3f(1, 1, 0);
+ glBegin(GL_TRIANGLES);
+ glVertex2f(0, 0);
+ glVertex2f(cos(angle * DEGTOR), sin(angle * DEGTOR));
+ glVertex2f(cos((angle + 20.0) * DEGTOR),
+ sin((angle + 20.0) * DEGTOR));
+ glEnd();
+ glFlush();
+
+ /* Swap buffers */
+ if (test == 2 || test == 4)
+ glXSwapBuffers(dpy, win1);
+ glXSwapBuffers(dpy, win2);
+
+ /* wait a while */
+ glXWaitX();
+ usleep(20000);
+ }
+
+ return 0;
+}
diff --git a/tests/mesa/tests/manytex.c b/tests/mesa/tests/manytex.c
new file mode 100644
index 00000000..61a1519a
--- /dev/null
+++ b/tests/mesa/tests/manytex.c
@@ -0,0 +1,382 @@
+/* $Id: manytex.c,v 1.5 2005/09/15 01:58:39 brianp Exp $ */
+
+/*
+ * test handling of many texture maps
+ * Also tests texture priority and residency.
+ *
+ * Brian Paul
+ * August 2, 2000
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+static GLint NumTextures = 20;
+static GLuint *TextureID = NULL;
+static GLint *TextureWidth = NULL, *TextureHeight = NULL;
+static GLboolean *TextureResidency = NULL;
+static GLint TexWidth = 128, TexHeight = 128;
+static GLfloat Zrot = 0;
+static GLboolean Anim = GL_TRUE;
+static GLint WinWidth = 500, WinHeight = 400;
+static GLboolean MipMap = GL_FALSE;
+static GLboolean LinearFilter = GL_FALSE;
+static GLboolean RandomSize = GL_FALSE;
+static GLint Rows, Columns;
+static GLint LowPriorityCount = 0;
+
+
+static void Idle( void )
+{
+ Zrot += 1.0;
+ glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+ GLfloat spacing = WinWidth / Columns;
+ GLfloat size = spacing * 0.4;
+ GLint i;
+
+ /* test residency */
+ if (0)
+ {
+ GLboolean b;
+ GLint i, resident;
+ b = glAreTexturesResident(NumTextures, TextureID, TextureResidency);
+ if (b) {
+ printf("all resident\n");
+ }
+ else {
+ resident = 0;
+ for (i = 0; i < NumTextures; i++) {
+ if (TextureResidency[i]) {
+ resident++;
+ }
+ }
+ printf("%d of %d texture resident\n", resident, NumTextures);
+ }
+ }
+
+ /* render the textured quads */
+ glClear( GL_COLOR_BUFFER_BIT );
+ for (i = 0; i < NumTextures; i++) {
+ GLint row = i / Columns;
+ GLint col = i % Columns;
+ GLfloat x = col * spacing + spacing * 0.5;
+ GLfloat y = row * spacing + spacing * 0.5;
+
+ GLfloat maxDim = (TextureWidth[i] > TextureHeight[i])
+ ? TextureWidth[i] : TextureHeight[i];
+ GLfloat w = TextureWidth[i] / maxDim;
+ GLfloat h = TextureHeight[i] / maxDim;
+
+ glPushMatrix();
+ glTranslatef(x, y, 0.0);
+ glRotatef(Zrot, 0, 0, 1);
+ glScalef(size, size, 1);
+
+ glBindTexture(GL_TEXTURE_2D, TextureID[i]);
+ glBegin(GL_POLYGON);
+#if 0
+ glTexCoord2f(0, 0); glVertex2f(-1, -1);
+ glTexCoord2f(1, 0); glVertex2f( 1, -1);
+ glTexCoord2f(1, 1); glVertex2f( 1, 1);
+ glTexCoord2f(0, 1); glVertex2f(-1, 1);
+#else
+ glTexCoord2f(0, 0); glVertex2f(-w, -h);
+ glTexCoord2f(1, 0); glVertex2f( w, -h);
+ glTexCoord2f(1, 1); glVertex2f( w, h);
+ glTexCoord2f(0, 1); glVertex2f(-w, h);
+#endif
+ glEnd();
+ glPopMatrix();
+ }
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ WinWidth = width;
+ WinHeight = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho(0, width, 0, height, -1, 1);
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+/*
+ * Return a random int in [min, max].
+ */
+static int RandomInt(int min, int max)
+{
+ int i = rand();
+ int j = i % (max - min + 1);
+ return min + j;
+}
+
+
+
+static void Init( void )
+{
+ GLint i;
+
+ if (RandomSize) {
+ printf("Creating %d %s random-size textures, ", NumTextures,
+ MipMap ? "Mipmapped" : "non-Mipmapped");
+ }
+ else {
+ printf("Creating %d %s %d x %d textures, ", NumTextures,
+ MipMap ? "Mipmapped" : "non-Mipmapped",
+ TexWidth, TexHeight);
+ }
+
+ if (LinearFilter) {
+ printf("bilinear filtering\n");
+ }
+ else {
+ printf("nearest filtering\n");
+ }
+
+
+ /* compute number of rows and columns of rects */
+ {
+ GLfloat area = (GLfloat) (WinWidth * WinHeight) / (GLfloat) NumTextures;
+ GLfloat edgeLen = sqrt(area);
+
+ Columns = WinWidth / edgeLen;
+ Rows = (NumTextures + Columns - 1) / Columns;
+ printf("Rows: %d Cols: %d\n", Rows, Columns);
+ }
+
+
+ if (!TextureID) {
+ TextureID = (GLuint *) malloc(sizeof(GLuint) * NumTextures);
+ assert(TextureID);
+ glGenTextures(NumTextures, TextureID);
+ }
+
+ if (!TextureResidency) {
+ TextureResidency = (GLboolean *) malloc(sizeof(GLboolean) * NumTextures);
+ assert(TextureResidency);
+ }
+
+ if (!TextureWidth) {
+ TextureWidth = (GLint *) malloc(sizeof(GLint) * NumTextures);
+ assert(TextureWidth);
+ }
+ if (!TextureHeight) {
+ TextureHeight = (GLint *) malloc(sizeof(GLint) * NumTextures);
+ assert(TextureHeight);
+ }
+
+ for (i = 0; i < NumTextures; i++) {
+ GLubyte color[4];
+ GLubyte *texImage;
+ GLint j, row, col;
+
+ row = i / Columns;
+ col = i % Columns;
+
+ glBindTexture(GL_TEXTURE_2D, TextureID[i]);
+
+ if (i < LowPriorityCount)
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 0.5F);
+
+ if (RandomSize) {
+#if 0
+ int k = (glutGet(GLUT_ELAPSED_TIME) % 7) + 2;
+ TexWidth = 1 << k;
+ TexHeight = 1 << k;
+#else
+ TexWidth = 1 << RandomInt(2, 7);
+ TexHeight = 1 << RandomInt(2, 7);
+ printf("Random size of %3d: %d x %d\n", i, TexWidth, TexHeight);
+#endif
+ }
+
+ TextureWidth[i] = TexWidth;
+ TextureHeight[i] = TexHeight;
+
+ texImage = (GLubyte*) malloc(4 * TexWidth * TexHeight * sizeof(GLubyte));
+ assert(texImage);
+
+ /* determine texture color */
+ color[0] = (GLint) (255.0 * ((float) col / (Columns - 1)));
+ color[1] = 127;
+ color[2] = (GLint) (255.0 * ((float) row / (Rows - 1)));
+ color[3] = 255;
+
+ /* fill in solid-colored teximage */
+ for (j = 0; j < TexWidth * TexHeight; j++) {
+ texImage[j*4+0] = color[0];
+ texImage[j*4+1] = color[1];
+ texImage[j*4+2] = color[2];
+ texImage[j*4+3] = color[3];
+ }
+
+ if (MipMap) {
+ GLint level = 0;
+ GLint w = TexWidth, h = TexHeight;
+ while (1) {
+ glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, w, h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texImage);
+ if (w == 1 && h == 1)
+ break;
+ if (w > 1)
+ w /= 2;
+ if (h > 1)
+ h /= 2;
+ level++;
+ /*printf("%d: %d x %d\n", level, w, h);*/
+ }
+ if (LinearFilter) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+ }
+ else {
+ /* Set corners to white */
+ int k = 0;
+ texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255;
+ k = (TexWidth - 1) * 4;
+ texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255;
+ k = (TexWidth * TexHeight - TexWidth) * 4;
+ texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255;
+ k = (TexWidth * TexHeight - 1) * 4;
+ texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255;
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TexWidth, TexHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texImage);
+ if (LinearFilter) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+ }
+
+ free(texImage);
+ }
+
+ glEnable(GL_TEXTURE_2D);
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 's':
+ Idle();
+ break;
+ case 'z':
+ Zrot -= step;
+ break;
+ case 'Z':
+ Zrot += step;
+ break;
+ case ' ':
+ Init();
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+int main( int argc, char *argv[] )
+{
+ GLint i;
+
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( WinWidth, WinHeight );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-n") == 0) {
+ NumTextures = atoi(argv[i+1]);
+ if (NumTextures <= 0) {
+ printf("Error, bad number of textures\n");
+ return 1;
+ }
+ i++;
+ }
+ else if (strcmp(argv[i], "-mipmap") == 0) {
+ MipMap = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-linear") == 0) {
+ LinearFilter = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-size") == 0) {
+ TexWidth = atoi(argv[i+1]);
+ TexHeight = atoi(argv[i+2]);
+ assert(TexWidth >= 1);
+ assert(TexHeight >= 1);
+ i += 2;
+ }
+ else if (strcmp(argv[i], "-randomsize") == 0) {
+ RandomSize = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-lowpri") == 0) {
+ LowPriorityCount = atoi(argv[i+1]);
+ i++;
+ }
+ else {
+ printf("Usage:\n");
+ printf(" manytex [options]\n");
+ printf("Options:\n");
+ printf(" -n <number of texture objects>\n");
+ printf(" -size <width> <height> - specify texture size\n");
+ printf(" -randomsize - use random size textures\n");
+ printf(" -mipmap - generate mipmaps\n");
+ printf(" -linear - use linear filtering instead of nearest\n");
+ printf(" -lowpri <n> - Set lower priority on <n> textures\n");
+ return 0;
+ }
+ }
+
+ Init();
+
+ glutMainLoop();
+
+ return 0;
+}
diff --git a/tests/mesa/tests/mipmap_limits.c b/tests/mesa/tests/mipmap_limits.c
new file mode 100644
index 00000000..dc066cab
--- /dev/null
+++ b/tests/mesa/tests/mipmap_limits.c
@@ -0,0 +1,252 @@
+/* Test GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL
+ * Brian Paul
+ * 10 May 2006
+ */
+
+
+/* Copyright (c) Mark J. Kilgard, 1994. */
+
+/*
+ * (c) Copyright 1993, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States. Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/* mipmap.c
+ * This program demonstrates using mipmaps for texture maps.
+ * To overtly show the effect of mipmaps, each mipmap reduction
+ * level has a solidly colored, contrasting texture image.
+ * Thus, the quadrilateral which is drawn is drawn with several
+ * different colors.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <GL/glut.h>
+
+static GLint BaseLevel = 0, MaxLevel = 8;
+static GLfloat MinLod = -1, MaxLod = 9;
+static GLfloat LodBias = 0.0;
+static GLboolean NearestFilter = GL_TRUE;
+
+
+static void MakeImage(int level, int width, int height, const GLubyte color[4])
+{
+ const int makeStripes = 0;
+ GLubyte img[256*256*3];
+ int i, j;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ int k = (i * width + j) * 3;
+ int p = (i/8) & makeStripes;
+ if (p == 0) {
+ img[k + 0] = color[0];
+ img[k + 1] = color[1];
+ img[k + 2] = color[2];
+ }
+ else {
+ img[k + 0] = 0;
+ img[k + 1] = 0;
+ img[k + 2] = 0;
+ }
+ }
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, width, height, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, img);
+}
+
+
+static void makeImages(void)
+{
+ static const GLubyte colors[8][3] = {
+ {128, 128, 128 },
+ { 0, 255, 255 },
+ { 255, 255, 0 },
+ { 255, 0, 255 },
+ { 255, 0, 0 },
+ { 0, 255, 0 },
+ { 0, 0, 255 },
+ { 255, 255, 255 }
+ };
+ int i, sz = 128;
+
+ for (i = 0; i < 8; i++) {
+ MakeImage(i, sz, sz, colors[i]);
+ sz /= 2;
+ }
+}
+
+static void myinit(void)
+{
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glShadeModel(GL_FLAT);
+
+ glTranslatef(0.0, 0.0, -3.6);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ makeImages();
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ glEnable(GL_TEXTURE_2D);
+}
+
+static void display(void)
+{
+ GLfloat tcm = 4.0;
+ printf("BASE_LEVEL = %d MAX_LEVEL = %d MIN_LOD = %f MAX_LOD = %f Bias = %.2g filter = %s\n",
+ BaseLevel, MaxLevel, MinLod, MaxLod, LodBias,
+ NearestFilter ? "NEAREST" : "LINEAR");
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, BaseLevel);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, MaxLevel);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, MinLod);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, MaxLod);
+
+ if (NearestFilter) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_NEAREST);
+ }
+ else {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ }
+
+ glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, LodBias);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
+ glTexCoord2f(0.0, tcm); glVertex3f(-2.0, 1.0, 0.0);
+ glTexCoord2f(tcm, tcm); glVertex3f(3000.0, 1.0, -6000.0);
+ glTexCoord2f(tcm, 0.0); glVertex3f(3000.0, -1.0, -6000.0);
+ glEnd();
+ glFlush();
+}
+
+static void myReshape(int w, int h)
+{
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(60.0, 1.0*(GLfloat)w/(GLfloat)h, 1.0, 30000.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (k) {
+ case 'b':
+ BaseLevel--;
+ if (BaseLevel < 0)
+ BaseLevel = 0;
+ break;
+ case 'B':
+ BaseLevel++;
+ if (BaseLevel > 10)
+ BaseLevel = 10;
+ break;
+ case 'm':
+ MaxLevel--;
+ if (MaxLevel < 0)
+ MaxLevel = 0;
+ break;
+ case 'M':
+ MaxLevel++;
+ if (MaxLevel > 10)
+ MaxLevel = 10;
+ break;
+ case 'l':
+ LodBias -= 0.02;
+ break;
+ case 'L':
+ LodBias += 0.02;
+ break;
+ case 'n':
+ MinLod -= 0.02;
+ break;
+ case 'N':
+ MinLod += 0.02;
+ break;
+ case 'x':
+ MaxLod -= 0.02;
+ break;
+ case 'X':
+ MaxLod += 0.02;
+ break;
+ case 'f':
+ NearestFilter = !NearestFilter;
+ break;
+ case 27: /* Escape */
+ exit(0);
+ break;
+ default:
+ return;
+ }
+ glutPostRedisplay();
+}
+
+
+static void usage(void)
+{
+ printf("usage:\n");
+ printf(" b/B decrease/increase GL_TEXTURE_BASE_LEVEL\n");
+ printf(" m/M decrease/increase GL_TEXTURE_MAX_LEVEL\n");
+ printf(" n/N decrease/increase GL_TEXTURE_MIN_LOD\n");
+ printf(" x/X decrease/increase GL_TEXTURE_MAX_LOD\n");
+ printf(" l/L decrease/increase GL_TEXTURE_LOD_BIAS\n");
+ printf(" f toggle nearest/linear filtering\n");
+}
+
+
+int main(int argc, char** argv)
+{
+ glutInit(&argc, argv);
+ glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
+ glutInitWindowSize (600, 600);
+ glutCreateWindow (argv[0]);
+ myinit();
+ glutReshapeFunc (myReshape);
+ glutDisplayFunc(display);
+ glutKeyboardFunc(key);
+ usage();
+ glutMainLoop();
+ return 0; /* ANSI C requires main to return int. */
+}
diff --git a/tests/mesa/tests/multipal.c b/tests/mesa/tests/multipal.c
new file mode 100644
index 00000000..c824b387
--- /dev/null
+++ b/tests/mesa/tests/multipal.c
@@ -0,0 +1,377 @@
+/* $Id: multipal.c,v 1.6 2003/12/08 09:03:36 joukj Exp $ */
+
+/*
+ * Test multitexture and paletted textures.
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __VMS
+# include <stddef.h> /* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
+#else
+# include <malloc.h> /* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#define GL_GLEXT_LEGACY
+#include <GL/glut.h>
+
+#include "../util/readtex.c" /* I know, this is a hack. */
+
+#define TEXTURE_1_FILE "../images/tile.rgb"
+#define TEXTURE_2_FILE "../images/reflect.rgb"
+
+#define TEX0 1
+#define TEX1 2
+#define TEXBOTH 3
+#define ANIMATE 10
+#define QUIT 100
+
+static GLboolean Animate = GL_TRUE;
+
+static GLfloat Drift = 0.0;
+static GLfloat Xrot = 20.0, Yrot = 30.0, Zrot = 0.0;
+
+
+
+static void Idle( void )
+{
+ if (Animate) {
+ Drift += 0.05;
+ if (Drift >= 1.0)
+ Drift = 0.0;
+
+#ifdef GL_ARB_multitexture
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+#endif
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glTranslatef(Drift, 0.0, 0.0);
+ glMatrixMode(GL_MODELVIEW);
+
+#ifdef GL_ARB_multitexture
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+#endif
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glTranslatef(0.0, Drift, 0.0);
+ glMatrixMode(GL_MODELVIEW);
+
+ glutPostRedisplay();
+ }
+}
+
+
+static void DrawObject(void)
+{
+ glBegin(GL_QUADS);
+
+#ifdef GL_ARB_multitexture
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0, 0.0);
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 0.0);
+ glVertex2f(-1.0, -1.0);
+
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 2.0, 0.0);
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0, 0.0);
+ glVertex2f(1.0, -1.0);
+
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 2.0, 2.0);
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0, 1.0);
+ glVertex2f(1.0, 1.0);
+
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0, 2.0);
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 1.0);
+ glVertex2f(-1.0, 1.0);
+#else
+ glTexCoord2f(0.0, 0.0);
+ glVertex2f(-1.0, -1.0);
+
+ glTexCoord2f(1.0, 0.0);
+ glVertex2f(1.0, -1.0);
+
+ glTexCoord2f(1.0, 1.0);
+ glVertex2f(1.0, 1.0);
+
+ glTexCoord2f(0.0, 1.0);
+ glVertex2f(-1.0, 1.0);
+#endif
+
+ glEnd();
+}
+
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ glScalef(5.0, 5.0, 5.0);
+ DrawObject();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
+ /*glOrtho( -6.0, 6.0, -6.0, 6.0, 10.0, 100.0 );*/
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -70.0 );
+}
+
+
+static void ModeMenu(int entry)
+{
+ GLboolean enable0 = GL_FALSE, enable1 = GL_FALSE;
+ if (entry==TEX0) {
+ enable0 = GL_TRUE;
+ }
+ else if (entry==TEX1) {
+ enable1 = GL_TRUE;
+ }
+ else if (entry==TEXBOTH) {
+ enable0 = GL_TRUE;
+ enable1 = GL_TRUE;
+ }
+ else if (entry==ANIMATE) {
+ Animate = !Animate;
+ }
+ else if (entry==QUIT) {
+ exit(0);
+ }
+
+ if (entry != ANIMATE) {
+#ifdef GL_ARB_multitexture
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+#endif
+ if (enable0) {
+ glEnable(GL_TEXTURE_2D);
+ }
+ else
+ glDisable(GL_TEXTURE_2D);
+
+#ifdef GL_ARB_multitexture
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+#endif
+ if (enable1) {
+ glEnable(GL_TEXTURE_2D);
+ }
+ else
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ glutPostRedisplay();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void load_tex(const char *fname, int channel)
+{
+ GLubyte *image;
+ GLenum format;
+ GLint w, h;
+ GLubyte *grayImage;
+ int i;
+ GLubyte table[256][4];
+
+ image = LoadRGBImage(fname, &w, &h, &format);
+ if (!image)
+ exit(1);
+
+ printf("%s %d x %d\n", fname, w, h);
+ grayImage = malloc(w * h * 1);
+ assert(grayImage);
+ for (i = 0; i < w * h; i++) {
+ int g = (image[i*3+0] + image[i*3+1] + image[i*3+2]) / 3;
+ assert(g < 256);
+ grayImage[i] = g;
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX, w, h, 0, GL_COLOR_INDEX,
+ GL_UNSIGNED_BYTE, grayImage);
+
+ for (i = 0; i < 256; i++) {
+ table[i][0] = channel ? i : 0;
+ table[i][1] = i;
+ table[i][2] = channel ? 0 : i;
+ table[i][3] = 255;
+ }
+
+ glColorTableEXT(GL_TEXTURE_2D, /* target */
+ GL_RGBA, /* internal format */
+ 256, /* table size */
+ GL_RGBA, /* table format */
+ GL_UNSIGNED_BYTE, /* table type */
+ table); /* the color table */
+
+ free(grayImage);
+ free(image);
+}
+
+
+
+static void Init( int argc, char *argv[] )
+{
+ GLuint texObj[2];
+ GLint units;
+
+ if (!glutExtensionSupported("GL_ARB_multitexture")) {
+ printf("Sorry, GL_ARB_multitexture not supported by this renderer.\n");
+ exit(1);
+ }
+ if (!glutExtensionSupported("GL_EXT_paletted_texture")) {
+ printf("Sorry, GL_EXT_paletted_texture not supported by this renderer.\n");
+ exit(1);
+ }
+
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &units);
+ printf("%d texture units supported\n", units);
+
+ /* allocate two texture objects */
+ glGenTextures(2, texObj);
+
+ /* setup texture obj 0 */
+ glBindTexture(GL_TEXTURE_2D, texObj[0]);
+#ifdef LINEAR_FILTER
+ /* linear filtering looks much nicer but is much slower for Mesa */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+foo
+#else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#endif
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ load_tex(TEXTURE_1_FILE, 0);
+#if 0
+ if (!LoadRGBMipmaps(TEXTURE_1_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image\n");
+ exit(1);
+ }
+#endif
+
+ /* setup texture obj 1 */
+ glBindTexture(GL_TEXTURE_2D, texObj[1]);
+#ifdef LINEAR_FILTER
+ /* linear filtering looks much nicer but is much slower for Mesa */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+foo
+#else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#endif
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ load_tex(TEXTURE_2_FILE, 1);
+#if 0
+ if (!LoadRGBMipmaps(TEXTURE_2_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image\n");
+ exit(1);
+ }
+#endif
+
+ /* now bind the texture objects to the respective texture units */
+#ifdef GL_ARB_multitexture
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ glBindTexture(GL_TEXTURE_2D, texObj[0]);
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+ glBindTexture(GL_TEXTURE_2D, texObj[1]);
+#endif
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.3, 0.3, 0.4, 1.0);
+
+ ModeMenu(TEXBOTH);
+
+ if (argc > 1 && strcmp(argv[1], "-info")==0) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowSize( 300, 300 );
+ glutInitWindowPosition( 0, 0 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0] );
+
+ Init( argc, argv );
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ glutIdleFunc( Idle );
+
+ glutCreateMenu(ModeMenu);
+ glutAddMenuEntry("Texture 0", TEX0);
+ glutAddMenuEntry("Texture 1", TEX1);
+ glutAddMenuEntry("Multi-texture", TEXBOTH);
+ glutAddMenuEntry("Toggle Animation", ANIMATE);
+ glutAddMenuEntry("Quit", QUIT);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/multitexarray.c b/tests/mesa/tests/multitexarray.c
new file mode 100644
index 00000000..b4fab004
--- /dev/null
+++ b/tests/mesa/tests/multitexarray.c
@@ -0,0 +1,238 @@
+/*
+ * Test vertex arrays and multitexture.
+ * Press 'a' to toggle vertex arrays on/off.
+ * When you run this program you should see a square with four colors:
+ *
+ * +------+------+
+ * |yellow| pink |
+ * +------+------+
+ * |green | blue |
+ * +------+------+
+ */
+
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "GL/glut.h"
+
+static GLuint Window = 0;
+
+static GLuint TexObj[2];
+static GLfloat Angle = 0.0f;
+static GLboolean UseArrays = 1, Anim = 0;
+
+static GLfloat VertArray[4][2] = {
+ {-1.2, -1.2}, {1.2, -1.2}, {1.2, 1.2}, {-1.2, 1.2}
+};
+
+static GLfloat Tex0Array[4][2] = {
+ {0, 0}, {1, 0}, {1, 1}, {0, 1}
+};
+
+static GLfloat Tex1Array[4][2] = {
+ {0, 0}, {1, 0}, {1, 1}, {0, 1}
+};
+
+
+static void init_arrays(void)
+{
+ glVertexPointer(2, GL_FLOAT, 0, VertArray);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ glTexCoordPointer(2, GL_FLOAT, 0, Tex0Array);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glClientActiveTextureARB(GL_TEXTURE1_ARB);
+ glTexCoordPointer(2, GL_FLOAT, 0, Tex1Array);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+
+static void draw( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glColor3f( 0.0, 0.0, 0.0 );
+
+ /* draw first polygon */
+ glPushMatrix();
+ glRotatef( Angle, 0.0, 0.0, 1.0 );
+
+ if (UseArrays) {
+ glDrawArrays(GL_POLYGON, 0, 4);
+ }
+ else {
+ glBegin( GL_POLYGON );
+ glTexCoord2f( 0.0, 0.0 );
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 0.0);
+ glVertex2f( -1.0, -1.0 );
+
+ glTexCoord2f( 1.0, 0.0 );
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0, 0.0);
+ glVertex2f( 1.0, -1.0 );
+
+ glTexCoord2f( 1.0, 1.0 );
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0, 1.0);
+ glVertex2f( 1.0, 1.0 );
+
+ glTexCoord2f( 0.0, 1.0 );
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 1.0);
+ glVertex2f( -1.0, 1.0 );
+ glEnd();
+ }
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+
+static void idle( void )
+{
+ Angle += 2.0;
+ glutPostRedisplay();
+}
+
+
+
+/* change view Angle, exit upon ESC */
+static void key(unsigned char k, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (k) {
+ case 'a':
+ UseArrays = !UseArrays;
+ printf("UseArrays: %d\n", UseArrays);
+ break;
+ case ' ':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 27:
+ glDeleteTextures( 2, TexObj );
+ glutDestroyWindow(Window);
+ exit(0);
+ }
+ glutPostRedisplay();
+}
+
+
+
+/* new window size or exposure */
+static void reshape( int width, int height )
+{
+ glViewport(0, 0, (GLint)width, (GLint)height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ /* glOrtho( -3.0, 3.0, -3.0, 3.0, -10.0, 10.0 );*/
+ glFrustum( -2.0, 2.0, -2.0, 2.0, 6.0, 20.0 );
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -8.0 );
+}
+
+
+static void init( void )
+{
+ static int width=8, height=8;
+ GLubyte tex[64][3];
+ GLint i, j;
+
+ /* generate texture object IDs */
+ glGenTextures( 2, TexObj );
+
+ /*
+ * setup first texture object
+ */
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ glEnable( GL_TEXTURE_2D );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
+
+ glBindTexture( GL_TEXTURE_2D, TexObj[0] );
+ assert(glIsTexture(TexObj[0]));
+
+ /* red over black */
+ for (i=0;i<height;i++) {
+ for (j=0;j<width;j++) {
+ int p = i*width+j;
+ if (i < height / 2) {
+ tex[p][0] = 0; tex[p][1] = 0; tex[p][2] = 0;
+ }
+ else {
+ tex[p][0] = 255; tex[p][1] = 0; tex[p][2] = 0;
+ }
+ }
+ }
+
+ glTexImage2D( GL_TEXTURE_2D, 0, 3, width, height, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, tex );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+
+
+ /*
+ * setup second texture object
+ */
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+ glEnable( GL_TEXTURE_2D );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
+
+ glBindTexture( GL_TEXTURE_2D, TexObj[1] );
+ assert(glIsTexture(TexObj[1]));
+
+ /* left=green, right = blue */
+ for (i=0;i<height;i++) {
+ for (j=0;j<width;j++) {
+ int p = i*width+j;
+ if (j < width / 2) {
+ tex[p][0] = 0; tex[p][1] = 255; tex[p][2] = 0;
+ }
+ else {
+ tex[p][0] = 0; tex[p][1] = 0; tex[p][2] = 255;
+ }
+ }
+ }
+ glTexImage2D( GL_TEXTURE_2D, 0, 3, width, height, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, tex );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+}
+
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(300, 300);
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+
+ Window = glutCreateWindow("Texture Objects");
+ if (!Window) {
+ exit(1);
+ }
+
+ init();
+ init_arrays();
+
+ glutReshapeFunc( reshape );
+ glutKeyboardFunc( key );
+ if (Anim)
+ glutIdleFunc( idle );
+ glutDisplayFunc( draw );
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/multiwindow.c b/tests/mesa/tests/multiwindow.c
new file mode 100644
index 00000000..e004b033
--- /dev/null
+++ b/tests/mesa/tests/multiwindow.c
@@ -0,0 +1,169 @@
+/* $Id: multiwindow.c,v 1.1 2001/08/21 14:25:31 brianp Exp $ */
+
+/*
+ * A skeleton/template GLUT program
+ *
+ * Written by Brian Paul and in the public domain.
+ */
+
+
+/*
+ * $Log: multiwindow.c,v $
+ * Revision 1.1 2001/08/21 14:25:31 brianp
+ * simple multi-window GLUT test prog
+ *
+ * Revision 1.1.1.1 1999/08/19 00:55:42 jtg
+ * Imported sources
+ *
+ * Revision 1.2 1998/11/07 14:20:14 brianp
+ * added simple rotation, animation of cube
+ *
+ * Revision 1.1 1998/11/07 14:14:37 brianp
+ * Initial revision
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+static GLint Window[2];
+
+static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
+static GLboolean Anim = GL_TRUE;
+
+
+static void Idle( void )
+{
+ Xrot += 3.0;
+ Yrot += 4.0;
+ Zrot += 2.0;
+
+ glutSetWindow(Window[0]);
+ glutPostRedisplay();
+ glutSetWindow(Window[1]);
+ glutPostRedisplay();
+}
+
+
+static void Display0( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+
+ glColor3f(0, 1, 0);
+ glutSolidCube(2.0);
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Display1( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+
+ glShadeModel(GL_FLAT);
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glColor3f(1, 0, 0);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glColor3f(1, 0, 0);
+ glVertex2f( -1, 1);
+ glColor3f(0, 0, 1);
+ glVertex2f( 1, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'z':
+ Zrot -= step;
+ break;
+ case 'Z':
+ Zrot += step;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 400, 400 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ Window[0] = glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display0 );
+ glutIdleFunc(Idle);
+ printf("GL_RENDERER[0] = %s\n", (char *) glGetString(GL_RENDERER));
+
+ glutInitWindowPosition( 500, 0 );
+ glutInitWindowSize( 400, 400 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ Window[1] = glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display1 );
+ glutIdleFunc(Idle);
+ printf("GL_RENDERER[1] = %s\n", (char *) glGetString(GL_RENDERER));
+
+ glutMainLoop();
+
+ return 0;
+}
diff --git a/tests/mesa/tests/no_s3tc.c b/tests/mesa/tests/no_s3tc.c
new file mode 100644
index 00000000..d3383ff9
--- /dev/null
+++ b/tests/mesa/tests/no_s3tc.c
@@ -0,0 +1,97 @@
+/*
+ * (C) Copyright IBM Corporation 2004
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file no_s3tc.c
+ * Test program to verify the behavior of an OpenGL implementation when
+ * an application calls \c glCompressedTexImage2D with an unsupported (but
+ * valid) compression format. The most common example is calling it with
+ * \c GL_COMPRESSED_RGBA_S3TC_DXT1_EXT when GL_EXT_texture_compression_s3tc
+ * is not supported.
+ *
+ * This tests Mesa bug #1028405.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <GL/glut.h>
+#include <GL/glext.h>
+
+static unsigned data[16];
+
+int
+main( int argc, char ** argv )
+{
+ float gl_version;
+ GLenum format;
+ GLuint size;
+ GLuint width;
+ GLenum err;
+
+
+ glutInit( & argc, argv );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
+
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 300, 300 );
+ glutCreateWindow( "No S3TC Test" );
+
+ gl_version = strtod( (const char *) glGetString( GL_VERSION ), NULL );
+ if ( ! glutExtensionSupported( "GL_ARB_texture_compression" )
+ && (gl_version < 1.3) ) {
+ fprintf( stderr, "Either OpenGL 1.3 or GL_ARB_texture_compression "
+ "must be supported.\n" );
+ return( EXIT_SUCCESS );
+ }
+
+
+ if ( ! glutExtensionSupported( "GL_EXT_texture_compression_s3tc" ) ) {
+ format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ width = 4;
+ size = 8;
+ }
+ else if ( ! glutExtensionSupported( "GL_3DFX_texture_compression_FXT1" ) ) {
+ format = GL_COMPRESSED_RGBA_FXT1_3DFX;
+ width = 8;
+ size = 16;
+ }
+ else {
+ fprintf( stderr, "Either GL_EXT_texture_compression_s3tc or "
+ "GL_3DFX_texture_compression_FXT1 must NOT be supported.\n" );
+ return( EXIT_SUCCESS );
+ }
+
+ glCompressedTexImage2D( GL_TEXTURE_2D, 0, format, width, 4, 0,
+ size, data );
+ err = glGetError();
+ if ( err != GL_INVALID_ENUM ) {
+ fprintf( stderr, "GL error 0x%04x should have been generated, but "
+ "0x%04x was generated instead.\n", GL_INVALID_ENUM, err );
+ }
+
+ return (err == GL_INVALID_ENUM) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tests/mesa/tests/packedpixels.c b/tests/mesa/tests/packedpixels.c
new file mode 100644
index 00000000..67ffe088
--- /dev/null
+++ b/tests/mesa/tests/packedpixels.c
@@ -0,0 +1,342 @@
+/*
+ * Test packed pixel formats for textures.
+ * Brian Paul
+ * 12 May 2004
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <GL/glut.h>
+
+
+struct pixel_format {
+ const char *name;
+ GLenum format;
+ GLenum type;
+ GLint bytes;
+ GLuint redTexel, greenTexel;
+};
+
+static const struct pixel_format Formats[] = {
+
+ { "GL_RGBA/GL_UNSIGNED_INT_8_8_8_8",
+ GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 4, 0xff000000, 0x00ff0000 },
+ { "GL_RGBA/GL_UNSIGNED_INT_8_8_8_8_REV",
+ GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 4, 0x000000ff, 0x0000ff00 },
+ { "GL_RGBA/GL_UNSIGNED_INT_10_10_10_2",
+ GL_RGBA, GL_UNSIGNED_INT_10_10_10_2, 4, 0xffc00000, 0x3ff000 },
+ { "GL_RGBA/GL_UNSIGNED_INT_2_10_10_10_REV",
+ GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, 4, 0x3ff, 0xffc00 },
+ { "GL_RGBA/GL_UNSIGNED_SHORT_4_4_4_4",
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 2, 0xf000, 0x0f00 },
+ { "GL_RGBA/GL_UNSIGNED_SHORT_4_4_4_4_REV",
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, 2, 0x000f, 0x00f0 },
+ { "GL_RGBA/GL_UNSIGNED_SHORT_5_5_5_1",
+ GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 2, 0xf800, 0x7c0 },
+ { "GL_RGBA/GL_UNSIGNED_SHORT_1_5_5_5_REV",
+ GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, 0x1f, 0x3e0 },
+
+ { "GL_BGRA/GL_UNSIGNED_INT_8_8_8_8",
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, 4, 0x0000ff00, 0x00ff0000 },
+ { "GL_BGRA/GL_UNSIGNED_INT_8_8_8_8_REV",
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 4, 0x00ff0000, 0x0000ff00 },
+ { "GL_BGRA/GL_UNSIGNED_SHORT_4_4_4_4",
+ GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4, 2, 0x00f0, 0x0f00 },
+ { "GL_BGRA/GL_UNSIGNED_SHORT_4_4_4_4_REV",
+ GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, 2, 0x0f00, 0x00f0 },
+ { "GL_BGRA/GL_UNSIGNED_SHORT_5_5_5_1",
+ GL_BGRA, GL_UNSIGNED_SHORT_5_5_5_1, 2, 0x3e, 0x7c0 },
+ { "GL_BGRA/GL_UNSIGNED_SHORT_1_5_5_5_REV",
+ GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, 0x7c00, 0x3e0 },
+
+ { "GL_ABGR_EXT/GL_UNSIGNED_INT_8_8_8_8",
+ GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8, 4, 0x000000ff, 0x0000ff00 },
+ { "GL_ABGR_EXT/GL_UNSIGNED_INT_8_8_8_8_REV",
+ GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, 4, 0xff000000, 0x00ff0000 },
+ { "GL_ABGR_EXT/GL_UNSIGNED_SHORT_4_4_4_4",
+ GL_ABGR_EXT, GL_UNSIGNED_SHORT_4_4_4_4, 2, 0x000f, 0x00f0 },
+ { "GL_ABGR_EXT/GL_UNSIGNED_SHORT_4_4_4_4_REV",
+ GL_ABGR_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV, 2, 0xf000, 0x0f00 },
+ { "GL_ABGR_EXT/GL_UNSIGNED_SHORT_5_5_5_1",
+ GL_ABGR_EXT, GL_UNSIGNED_SHORT_5_5_5_1, 2, 0x1, 0x3e },
+ { "GL_ABGR_EXT/GL_UNSIGNED_SHORT_1_5_5_5_REV",
+ GL_ABGR_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, 0x8000, 0x7c00 },
+
+ { "GL_RGB/GL_UNSIGNED_SHORT_5_6_5",
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 2, 0xf800, 0x7e0 },
+ { "GL_RGB/GL_UNSIGNED_SHORT_5_6_5_REV",
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, 2, 0x1f, 0x7e0 },
+ { "GL_RGB/GL_UNSIGNED_BYTE_3_3_2",
+ GL_RGB, GL_UNSIGNED_BYTE_3_3_2, 1, 0xe0, 0x1c },
+ { "GL_RGB/GL_UNSIGNED_BYTE_2_3_3_REV",
+ GL_RGB, GL_UNSIGNED_BYTE_2_3_3_REV, 1, 0x7, 0x38 },
+
+ { NULL, 0, 0, 0, 0, 0 }
+};
+
+
+struct name_format {
+ const char *name;
+ GLenum format;
+};
+
+static const struct name_format IntFormats[] = {
+ { "GL_RGBA", GL_RGBA },
+ { "GL_RGBA2", GL_RGBA2 },
+ { "GL_RGBA4", GL_RGBA4 },
+ { "GL_RGB5_A1", GL_RGB5_A1 },
+ { "GL_RGBA8", GL_RGBA8 },
+ { "GL_RGBA12", GL_RGBA12 },
+ { "GL_RGBA16", GL_RGBA16 },
+ { "GL_RGB10_A2", GL_RGB10_A2 },
+
+ { "GL_RGB", GL_RGB },
+ { "GL_R3_G3_B2", GL_R3_G3_B2 },
+ { "GL_RGB4", GL_RGB4 },
+ { "GL_RGB5", GL_RGB5 },
+ { "GL_RGB8", GL_RGB8 },
+ { "GL_RGB10", GL_RGB10 },
+ { "GL_RGB12", GL_RGB12 },
+ { "GL_RGB16", GL_RGB16 },
+
+};
+
+#define NUM_INT_FORMATS (sizeof(IntFormats) / sizeof(IntFormats[0]))
+static GLuint CurFormat = 0;
+
+static GLboolean Test3D = GL_FALSE;
+
+
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static void
+MakeTexture(const struct pixel_format *format, GLenum intFormat, GLboolean swap)
+{
+ GLubyte texBuffer[1000];
+ int i;
+
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, swap);
+
+ if (format->bytes == 1) {
+ for (i = 0; i < 8; i++) {
+ texBuffer[i] = format->redTexel;
+ }
+ for (i = 8; i < 16; i++) {
+ texBuffer[i] = format->greenTexel;
+ }
+ }
+ else if (format->bytes == 2) {
+ GLushort *us = (GLushort *) texBuffer;
+ for (i = 0; i < 8; i++) {
+ us[i] = format->redTexel;
+ }
+ for (i = 8; i < 16; i++) {
+ us[i] = format->greenTexel;
+ }
+ if (swap) {
+ for (i = 0; i < 16; i++)
+ us[i] = (us[i] << 8) | (us[i] >> 8);
+ }
+ }
+ else if (format->bytes == 4) {
+ GLuint *ui = (GLuint *) texBuffer;
+ for (i = 0; i < 8; i++) {
+ ui[i] = format->redTexel;
+ }
+ for (i = 8; i < 16; i++) {
+ ui[i] = format->greenTexel;
+ }
+ if (swap) {
+ for (i = 0; i < 16; i++) {
+ GLuint b = ui[i];
+ ui[i] = (b >> 24)
+ | ((b >> 8) & 0xff00)
+ | ((b << 8) & 0xff0000)
+ | ((b << 24) & 0xff000000);
+ }
+ }
+ }
+ else {
+ abort();
+ }
+
+ if (Test3D) {
+ /* 4 x 4 x 4 texture, undefined data */
+ glTexImage3D(GL_TEXTURE_3D, 0, intFormat, 4, 4, 4, 0,
+ format->format, format->type, NULL);
+ /* fill in Z=1 and Z=2 slices with the real texture data */
+ glTexSubImage3D(GL_TEXTURE_3D, 0,
+ 0, 0, 1, /* offset */
+ 4, 4, 1, /* size */
+ format->format, format->type, texBuffer);
+ glTexSubImage3D(GL_TEXTURE_3D, 0,
+ 0, 0, 2, /* offset */
+ 4, 4, 1, /* size */
+ format->format, format->type, texBuffer);
+ }
+ else {
+ glTexImage2D(GL_TEXTURE_2D, 0, intFormat, 4, 4, 0,
+ format->format, format->type, texBuffer);
+ }
+
+ if (glGetError()) {
+ printf("GL Error for %s\n", format->name);
+ memset(texBuffer, 255, 1000);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, texBuffer);
+ }
+}
+
+
+
+static void
+Draw(void)
+{
+ char s[1000];
+ int w = 350, h = 20;
+ int i, swap;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ for (swap = 0; swap < 2; swap++) {
+ for (i = 0; Formats[i].name; i++) {
+ glPushMatrix();
+ glTranslatef(swap * (w + 2), i * (h + 2), 0);
+
+ MakeTexture(Formats + i, IntFormats[CurFormat].format, swap);
+
+ if (Test3D)
+ glEnable(GL_TEXTURE_3D);
+ else
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_POLYGON);
+ glTexCoord3f(0, 0, 0.5); glVertex2f(0, 0);
+ glTexCoord3f(1, 0, 0.5); glVertex2f(w, 0);
+ glTexCoord3f(1, 1, 0.5); glVertex2f(w, h);
+ glTexCoord3f(0, 1, 0.5); glVertex2f(0, h);
+ glEnd();
+
+ if (Test3D)
+ glDisable(GL_TEXTURE_3D);
+ else
+ glDisable(GL_TEXTURE_2D);
+ glColor3f(0, 0, 0);
+ glRasterPos2i(8, 6);
+ PrintString(Formats[i].name);
+
+ glPopMatrix();
+ }
+ }
+
+ glPushMatrix();
+ glTranslatef(2, i * (h + 2), 0);
+ glColor3f(1, 1, 1);
+ glRasterPos2i(8, 6);
+ PrintString("Normal");
+ glRasterPos2i(w + 2, 6);
+ PrintString("Byte Swapped");
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(2, (i + 1) * (h + 2), 0);
+ glRasterPos2i(8, 6);
+ sprintf(s, "Internal Texture Format [f/F]: %s (%d of %d)",
+ IntFormats[CurFormat].name, CurFormat + 1, NUM_INT_FORMATS);
+ PrintString(s);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(2, (i + 2) * (h + 2), 0);
+ glRasterPos2i(8, 6);
+ if (Test3D)
+ PrintString("Target [2/3]: GL_TEXTURE_3D");
+ else
+ PrintString("Target [2/3]: GL_TEXTURE_2D");
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, width, 0, height, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'F':
+ if (CurFormat == 0)
+ CurFormat = NUM_INT_FORMATS - 1;
+ else
+ CurFormat--;
+ break;
+ case 'f':
+ CurFormat++;
+ if (CurFormat == NUM_INT_FORMATS)
+ CurFormat = 0;
+ break;
+ case '2':
+ Test3D = GL_FALSE;
+ break;
+ case '3':
+ Test3D = GL_TRUE;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(700, 800);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Draw);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/pbo.c b/tests/mesa/tests/pbo.c
new file mode 100644
index 00000000..b31b36cc
--- /dev/null
+++ b/tests/mesa/tests/pbo.c
@@ -0,0 +1,296 @@
+/*
+ * GL_EXT_pixel_buffer_object test
+ *
+ * Brian Paul
+ * 11 March 2004
+ */
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+#include "../util/readtex.c" /* a hack, I know */
+
+#define IMAGE_FILE "../images/girl.rgb"
+
+static int ImgWidth, ImgHeight;
+static GLenum ImgFormat;
+static GLubyte *Image = NULL;
+
+static int APosX, APosY; /* simple drawpixels */
+static int BPosX, BPosY; /* read/draw pixels */
+static int CPosX, CPosY; /* copypixels */
+
+static GLboolean DrawFront = GL_FALSE;
+static GLboolean ScaleAndBias = GL_FALSE;
+static GLboolean Benchmark = GL_FALSE;
+
+static GLuint DrawPBO, TempPBO;
+
+
+static GLenum ReadFormat = GL_BGRA;
+static GLenum ReadType = GL_UNSIGNED_INT_8_8_8_8_REV;
+
+
+
+static void
+CheckError(int line)
+{
+ GLenum err = glGetError();
+ if (err) {
+ printf("GL Error 0x%x at line %d\n", (int) err, line);
+ }
+}
+
+
+static void
+Reset( void )
+{
+ APosX = 5; APosY = 20;
+ BPosX = APosX + ImgWidth + 5; BPosY = 20;
+ CPosX = BPosX + ImgWidth + 5; CPosY = 20;
+}
+
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static void
+SetupPixelTransfer(GLboolean invert)
+{
+ if (invert) {
+ glPixelTransferf(GL_RED_SCALE, -1.0);
+ glPixelTransferf(GL_RED_BIAS, 1.0);
+ glPixelTransferf(GL_GREEN_SCALE, -1.0);
+ glPixelTransferf(GL_GREEN_BIAS, 1.0);
+ glPixelTransferf(GL_BLUE_SCALE, -1.0);
+ glPixelTransferf(GL_BLUE_BIAS, 1.0);
+ }
+ else {
+ glPixelTransferf(GL_RED_SCALE, 1.0);
+ glPixelTransferf(GL_RED_BIAS, 0.0);
+ glPixelTransferf(GL_GREEN_SCALE, 1.0);
+ glPixelTransferf(GL_GREEN_BIAS, 0.0);
+ glPixelTransferf(GL_BLUE_SCALE, 1.0);
+ glPixelTransferf(GL_BLUE_BIAS, 0.0);
+ }
+}
+
+
+static void
+Display( void )
+{
+ glClearColor(.3, .3, .3, 1);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ CheckError(__LINE__);
+
+ /** Unbind UNPACK pixel buffer before calling glBitmap */
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+
+ glRasterPos2i(5, ImgHeight+25);
+ PrintString("f = toggle front/back s = toggle scale/bias b = benchmark");
+
+ glRasterPos2i(5, ImgHeight+40);
+ PrintString("GL_EXT_pixel_buffer_object test");
+
+ /* draw original image */
+ glRasterPos2i(APosX, 5);
+ PrintString("Original");
+ glRasterPos2i(APosX, APosY);
+ glEnable(GL_DITHER);
+ SetupPixelTransfer(GL_FALSE);
+ /*** Draw from the DrawPBO */
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, DrawPBO);
+ glDrawPixels(ImgWidth, ImgHeight, ImgFormat, GL_UNSIGNED_BYTE, 0);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+
+ CheckError(__LINE__);
+
+ /* do readpixels, drawpixels */
+ glRasterPos2i(BPosX, 5);
+ PrintString("Read/DrawPixels");
+ SetupPixelTransfer(ScaleAndBias);
+ /*** read into the Temp PBO */
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, TempPBO);
+ CheckError(__LINE__);
+ if (Benchmark) {
+ GLint reads = 0;
+ GLint endTime;
+ GLint startTime = glutGet(GLUT_ELAPSED_TIME);
+ GLdouble seconds, pixelsPerSecond;
+ printf("Benchmarking...\n");
+ do {
+ glReadPixels(APosX, APosY, ImgWidth, ImgHeight,
+ ReadFormat, ReadType, 0);
+ reads++;
+ endTime = glutGet(GLUT_ELAPSED_TIME);
+ } while (endTime - startTime < 4000); /* 4 seconds */
+ seconds = (double) (endTime - startTime) / 1000.0;
+ pixelsPerSecond = reads * ImgWidth * ImgHeight / seconds;
+ printf("Result: %d reads in %f seconds = %f pixels/sec\n",
+ reads, seconds, pixelsPerSecond);
+ Benchmark = GL_FALSE;
+ }
+ else {
+ glReadPixels(APosX, APosY, ImgWidth, ImgHeight,
+ ReadFormat, ReadType, 0);
+ }
+ CheckError(__LINE__);
+ glRasterPos2i(BPosX, BPosY);
+ glDisable(GL_DITHER);
+ SetupPixelTransfer(GL_FALSE);
+
+ CheckError(__LINE__);
+
+ /*** draw from the Temp PBO */
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, TempPBO);
+ glDrawPixels(ImgWidth, ImgHeight, ReadFormat, ReadType, 0);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
+
+ CheckError(__LINE__);
+
+ /* do copypixels */
+ glRasterPos2i(CPosX, 5);
+ PrintString("CopyPixels");
+ glRasterPos2i(CPosX, CPosY);
+ glDisable(GL_DITHER);
+ SetupPixelTransfer(ScaleAndBias);
+ glCopyPixels(APosX, APosY, ImgWidth, ImgHeight, GL_COLOR);
+
+ CheckError(__LINE__);
+
+ if (!DrawFront)
+ glutSwapBuffers();
+ else
+ glFinish();
+}
+
+
+static void
+Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, width, 0.0, height, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+static void
+Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'b':
+ Benchmark = GL_TRUE;
+ break;
+ case 's':
+ ScaleAndBias = !ScaleAndBias;
+ break;
+ case 'f':
+ DrawFront = !DrawFront;
+ if (DrawFront) {
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+ }
+ else {
+ glDrawBuffer(GL_BACK);
+ glReadBuffer(GL_BACK);
+ }
+ printf("glDrawBuffer(%s)\n", DrawFront ? "GL_FRONT" : "GL_BACK");
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ if (!glutExtensionSupported("GL_EXT_pixel_buffer_object")) {
+ printf("Sorry, this demo requires GL_EXT_pixel_buffer_object\n");
+ exit(0);
+ }
+
+ Image = LoadRGBImage( IMAGE_FILE, &ImgWidth, &ImgHeight, &ImgFormat );
+ if (!Image) {
+ printf("Couldn't read %s\n", IMAGE_FILE);
+ exit(0);
+ }
+
+ printf("Loaded %d by %d image\n", ImgWidth, ImgHeight );
+
+ if (ImgFormat == GL_RGB) {
+ /* convert to RGBA */
+ int i;
+ GLubyte *image2 = (GLubyte *) malloc(ImgWidth * ImgHeight * 4);
+ printf("Converting RGB image to RGBA\n");
+ for (i = 0; i < ImgWidth * ImgHeight; i++) {
+ image2[i*4+0] = Image[i*3+0];
+ image2[i*4+1] = Image[i*3+1];
+ image2[i*4+2] = Image[i*3+2];
+ image2[i*4+3] = 255;
+ }
+ free(Image);
+ Image = image2;
+ ImgFormat = GL_RGBA;
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, ImgWidth);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ROW_LENGTH, ImgWidth);
+
+ Reset();
+
+ /* put image into DrawPBO */
+ glGenBuffersARB(1, &DrawPBO);
+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, DrawPBO);
+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT,
+ ImgWidth * ImgHeight * 4, Image, GL_STATIC_DRAW);
+
+ /* Setup TempPBO - used for glReadPixels & glDrawPixels */
+ glGenBuffersARB(1, &TempPBO);
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, TempPBO);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT,
+ ImgWidth * ImgHeight * 4, NULL, GL_DYNAMIC_COPY);
+
+}
+
+
+int
+main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 750, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0]);
+ Init();
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/prog_parameter.c b/tests/mesa/tests/prog_parameter.c
new file mode 100644
index 00000000..96697e5b
--- /dev/null
+++ b/tests/mesa/tests/prog_parameter.c
@@ -0,0 +1,285 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file prog_parameter.c
+ *
+ * Test various aspects of setting (and getting) low-level program parameters.
+ * This is primarilly intended as a test for GL_EXT_gpu_program_parameters,
+ * but it turns out that it hits some other functionality along the way.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+#ifndef GL_EXT_gpu_program_parameters
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC)(GLenum,
+ GLuint, GLsizei, const GLfloat *);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC)(GLenum,
+ GLuint, GLsizei, const GLfloat *);
+#endif
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC program_local_parameter4fv = NULL;
+static PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC get_program_local_parameterfv = NULL;
+static PFNGLPROGRAMENVPARAMETER4FVARBPROC program_env_parameter4fv = NULL;
+static PFNGLGETPROGRAMENVPARAMETERFVARBPROC get_program_env_parameterfv = NULL;
+static PFNGLBINDPROGRAMARBPROC bind_program = NULL;
+static PFNGLGETPROGRAMIVARBPROC get_program = NULL;
+
+static PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC program_local_parameters4fv = NULL;
+static PFNGLPROGRAMENVPARAMETERS4FVEXTPROC program_env_parameters4fv = NULL;
+
+static int Width = 400;
+static int Height = 200;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+}
+
+
+static void Idle( void )
+{
+}
+
+
+static void Visible( int vis )
+{
+ if ( vis == GLUT_VISIBLE ) {
+ glutIdleFunc( Idle );
+ }
+ else {
+ glutIdleFunc( NULL );
+ }
+}
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static int set_parameter_batch( GLsizei count, GLfloat * param,
+ const char * name,
+ PFNGLPROGRAMLOCALPARAMETER4FVARBPROC set_parameter,
+ PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC set_parameters,
+ PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC get_parameter
+ )
+{
+ unsigned i;
+ int pass = 1;
+
+
+ for ( i = 0 ; i < (4 * count) ; i++ ) {
+ param[i] = (GLfloat) random() / (GLfloat) random();
+ }
+
+ /* Try using the "classic" interface.
+ */
+ printf("Testing glProgram%sParameter4fvARB (count = %u)...\n", name, count);
+ for ( i = 0 ; i < count ; i++ ) {
+ (*set_parameter)(GL_VERTEX_PROGRAM_ARB, i, & param[i * 4]);
+ }
+
+ for ( i = 0 ; i < count ; i++ ) {
+ GLfloat temp[4];
+
+ (*get_parameter)(GL_VERTEX_PROGRAM_ARB, i, temp);
+
+ if ( (temp[0] != param[(i * 4) + 0])
+ || (temp[1] != param[(i * 4) + 1])
+ || (temp[2] != param[(i * 4) + 2])
+ || (temp[3] != param[(i * 4) + 3]) ) {
+ printf("Mismatch in glProgram%sParameter4fvARB index %u!\n", name, i);
+ printf("Got { %f, %f, %f, %f }, expected { %f, %f, %f, %f }!\n",
+ temp[0], temp[1],
+ temp[2], temp[3],
+ param[(i * 4) + 0], param[(i * 4) + 1],
+ param[(i * 4) + 2], param[(i * 4) + 3]);
+ pass = 0;
+ break;
+ }
+ }
+
+
+ if ( set_parameters == NULL ) {
+ return pass;
+ }
+
+
+ for ( i = 0 ; i < (4 * count) ; i++ ) {
+ param[i] = (GLfloat) random() / (GLfloat) random();
+ }
+
+ printf("Testing glProgram%sParameters4fvEXT (count = %u)...\n", name, count);
+ (*set_parameters)(GL_VERTEX_PROGRAM_ARB, 0, count, param);
+
+ for ( i = 0 ; i < count ; i++ ) {
+ GLfloat temp[4];
+
+ (*get_parameter)(GL_VERTEX_PROGRAM_ARB, i, temp);
+
+ if ( (temp[0] != param[(i * 4) + 0])
+ || (temp[1] != param[(i * 4) + 1])
+ || (temp[2] != param[(i * 4) + 2])
+ || (temp[3] != param[(i * 4) + 3]) ) {
+ printf("Mismatch in glProgram%sParameters4fvEXT index %u!\n", name, i);
+ printf("Got { %f, %f, %f, %f }, expected { %f, %f, %f, %f }!\n",
+ temp[0], temp[1],
+ temp[2], temp[3],
+ param[(i * 4) + 0], param[(i * 4) + 1],
+ param[(i * 4) + 2], param[(i * 4) + 3]);
+ pass = 0;
+ break;
+ }
+ }
+
+
+ return pass;
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+ int pass = 1;
+ GLfloat * params;
+ GLint max_program_env_parameters;
+ GLint max_program_local_parameters;
+
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n\n", ver_string);
+
+ if ( !glutExtensionSupported("GL_ARB_vertex_program") ) {
+ printf("Sorry, this program requires GL_ARB_vertex_program\n");
+ exit(2);
+ }
+
+
+ program_local_parameter4fv = glutGetProcAddress( "glProgramLocalParameter4fvARB" );
+ program_env_parameter4fv = glutGetProcAddress( "glProgramEnvParameter4fvARB" );
+
+ get_program_local_parameterfv = glutGetProcAddress( "glGetProgramLocalParameterfvARB" );
+ get_program_env_parameterfv = glutGetProcAddress( "glGetProgramEnvParameterfvARB" );
+
+ bind_program = glutGetProcAddress( "glBindProgramARB" );
+ get_program = glutGetProcAddress( "glGetProgramivARB" );
+
+ if ( glutExtensionSupported("GL_EXT_gpu_program_parameters") ) {
+ printf("GL_EXT_gpu_program_parameters available, testing that path.\n");
+
+ program_local_parameters4fv = glutGetProcAddress( "glProgramLocalParameters4fvEXT" );
+ program_env_parameters4fv = glutGetProcAddress( "glProgramEnvParameters4fvEXT" );
+ }
+ else {
+ printf("GL_EXT_gpu_program_parameters not available.\n");
+
+ program_local_parameters4fv = NULL;
+ program_env_parameters4fv = NULL;
+ }
+
+
+
+ /* Since the test sets program local parameters, a program must be bound.
+ * Program source, however, is not needed.
+ */
+ (*bind_program)(GL_VERTEX_PROGRAM_ARB, 1);
+
+
+ (*get_program)(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB,
+ & max_program_env_parameters);
+
+ params = malloc(max_program_env_parameters * 4 * sizeof(GLfloat));
+
+ pass &= set_parameter_batch(max_program_env_parameters, params, "Env",
+ program_env_parameter4fv,
+ program_env_parameters4fv,
+ get_program_env_parameterfv);
+
+
+ (*get_program)(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB,
+ & max_program_local_parameters);
+
+ if (max_program_local_parameters > max_program_env_parameters) {
+ params = realloc(params,
+ max_program_local_parameters * 4 * sizeof(GLfloat));
+ }
+
+ pass &= set_parameter_batch(max_program_local_parameters, params, "Local",
+ program_local_parameter4fv,
+ program_local_parameters4fv,
+ get_program_local_parameterfv);
+
+ free(params);
+
+ if (! pass) {
+ printf("FAIL!\n");
+ exit(1);
+ }
+
+ printf("PASS!\n");
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB );
+ glutCreateWindow( "Program Parameters Test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ glutVisibilityFunc( Visible );
+
+ Init();
+
+ return 0;
+}
diff --git a/tests/mesa/tests/projtex.c b/tests/mesa/tests/projtex.c
new file mode 100644
index 00000000..e3ef948a
--- /dev/null
+++ b/tests/mesa/tests/projtex.c
@@ -0,0 +1,1028 @@
+
+/* projtex.c - by David Yu and David Blythe, SGI */
+
+/**
+ ** Demonstrates simple projective texture mapping.
+ **
+ ** Button1 changes view, Button2 moves texture.
+ **
+ ** (See: Segal, Korobkin, van Widenfelt, Foran, and Haeberli
+ ** "Fast Shadows and Lighting Effects Using Texture Mapping", SIGGRAPH '92)
+ **
+ ** 1994,1995 -- David G Yu
+ **
+ ** cc -o projtex projtex.c texture.c -lglut -lGLU -lGL -lX11 -lm
+ **/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+#if 0
+#include "texture.h"
+#else
+#include "../util/readtex.c"
+#endif
+
+
+/* Some <math.h> files do not define M_PI... */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define MAX_TEX 4
+int NumTextures = 1;
+
+int winWidth, winHeight;
+
+GLboolean redrawContinuously = GL_FALSE;
+
+float angle, axis[3];
+enum MoveModes {
+ MoveNone, MoveView, MoveObject, MoveTexture
+};
+enum MoveModes mode = MoveNone;
+
+GLfloat objectXform[4][4];
+GLfloat textureXform[MAX_TEX][4][4];
+
+void (*drawObject) (void);
+void (*loadTexture) (void);
+GLboolean textureEnabled = GL_TRUE;
+GLboolean showProjection = GL_TRUE;
+GLboolean linearFilter = GL_TRUE;
+
+char *texFilename[MAX_TEX] = {
+ "../images/girl.rgb",
+ "../images/tile.rgb",
+ "../images/bw.rgb",
+ "../images/reflect.rgb"
+};
+
+
+GLfloat zoomFactor = 1.0;
+
+/*****************************************************************/
+
+
+void ActiveTexture(int i)
+{
+ glActiveTextureARB(i);
+}
+
+
+/* matrix = identity */
+void
+matrixIdentity(GLfloat matrix[16])
+{
+ matrix[0] = 1.0;
+ matrix[1] = 0.0;
+ matrix[2] = 0.0;
+ matrix[3] = 0.0;
+ matrix[4] = 0.0;
+ matrix[5] = 1.0;
+ matrix[6] = 0.0;
+ matrix[7] = 0.0;
+ matrix[8] = 0.0;
+ matrix[9] = 0.0;
+ matrix[10] = 1.0;
+ matrix[11] = 0.0;
+ matrix[12] = 0.0;
+ matrix[13] = 0.0;
+ matrix[14] = 0.0;
+ matrix[15] = 1.0;
+}
+
+/* matrix2 = transpose(matrix1) */
+void
+matrixTranspose(GLfloat matrix2[16], GLfloat matrix1[16])
+{
+ matrix2[0] = matrix1[0];
+ matrix2[1] = matrix1[4];
+ matrix2[2] = matrix1[8];
+ matrix2[3] = matrix1[12];
+
+ matrix2[4] = matrix1[1];
+ matrix2[5] = matrix1[5];
+ matrix2[6] = matrix1[9];
+ matrix2[7] = matrix1[13];
+
+ matrix2[8] = matrix1[2];
+ matrix2[9] = matrix1[6];
+ matrix2[10] = matrix1[10];
+ matrix2[11] = matrix1[14];
+
+ matrix2[12] = matrix1[3];
+ matrix2[13] = matrix1[7];
+ matrix2[14] = matrix1[14];
+ matrix2[15] = matrix1[15];
+}
+
+/*****************************************************************/
+
+/* load SGI .rgb image (pad with a border of the specified width and color) */
+#if 0
+static void
+imgLoad(char *filenameIn, int borderIn, GLfloat borderColorIn[4],
+ int *wOut, int *hOut, GLubyte ** imgOut)
+{
+ int border = borderIn;
+ int width, height;
+ int w, h;
+ GLubyte *image, *img, *p;
+ int i, j, components;
+
+ image = (GLubyte *) read_texture(filenameIn, &width, &height, &components);
+ w = width + 2 * border;
+ h = height + 2 * border;
+ img = (GLubyte *) calloc(w * h, 4 * sizeof(unsigned char));
+
+ p = img;
+ for (j = -border; j < height + border; ++j) {
+ for (i = -border; i < width + border; ++i) {
+ if (0 <= j && j <= height - 1 && 0 <= i && i <= width - 1) {
+ p[0] = image[4 * (j * width + i) + 0];
+ p[1] = image[4 * (j * width + i) + 1];
+ p[2] = image[4 * (j * width + i) + 2];
+ p[3] = 0xff;
+ } else {
+ p[0] = borderColorIn[0] * 0xff;
+ p[1] = borderColorIn[1] * 0xff;
+ p[2] = borderColorIn[2] * 0xff;
+ p[3] = borderColorIn[3] * 0xff;
+ }
+ p += 4;
+ }
+ }
+ free(image);
+ *wOut = w;
+ *hOut = h;
+ *imgOut = img;
+}
+#endif
+
+
+/*****************************************************************/
+
+/* Load the image file specified on the command line as the current texture */
+void
+loadImageTextures(void)
+{
+ GLfloat borderColor[4] =
+ {1.0, 1.0, 1.0, 1.0};
+ int tex;
+
+ for (tex = 0; tex < NumTextures; tex++) {
+ GLubyte *image, *texData3, *texData4;
+ GLint imgWidth, imgHeight;
+ GLenum imgFormat;
+ int i, j;
+
+ printf("loading %s\n", texFilename[tex]);
+ image = LoadRGBImage(texFilename[tex], &imgWidth, &imgHeight, &imgFormat);
+ if (!image) {
+ printf("can't find %s\n", texFilename[tex]);
+ exit(1);
+ }
+ assert(imgFormat == GL_RGB);
+
+ /* scale to 256x256 */
+ texData3 = malloc(256 * 256 * 4);
+ texData4 = malloc(256 * 256 * 4);
+ assert(texData3);
+ assert(texData4);
+ gluScaleImage(imgFormat, imgWidth, imgHeight, GL_UNSIGNED_BYTE, image,
+ 256, 256, GL_UNSIGNED_BYTE, texData3);
+
+ /* convert to rgba */
+ for (i = 0; i < 256 * 256; i++) {
+ texData4[i*4+0] = texData3[i*3+0];
+ texData4[i*4+1] = texData3[i*3+1];
+ texData4[i*4+2] = texData3[i*3+2];
+ texData4[i*4+3] = 128;
+ }
+
+ /* put transparent border around image */
+ for (i = 0; i < 256; i++) {
+ texData4[i*4+0] = 255;
+ texData4[i*4+1] = 255;
+ texData4[i*4+2] = 255;
+ texData4[i*4+3] = 0;
+ }
+ j = 256 * 255 * 4;
+ for (i = 0; i < 256; i++) {
+ texData4[j + i*4+0] = 255;
+ texData4[j + i*4+1] = 255;
+ texData4[j + i*4+2] = 255;
+ texData4[j + i*4+3] = 0;
+ }
+ for (i = 0; i < 256; i++) {
+ j = i * 256 * 4;
+ texData4[j+0] = 255;
+ texData4[j+1] = 255;
+ texData4[j+2] = 255;
+ texData4[j+3] = 0;
+ }
+ for (i = 0; i < 256; i++) {
+ j = i * 256 * 4 + 255 * 4;
+ texData4[j+0] = 255;
+ texData4[j+1] = 255;
+ texData4[j+2] = 255;
+ texData4[j+3] = 0;
+ }
+
+ ActiveTexture(GL_TEXTURE0_ARB + tex);
+ glBindTexture(GL_TEXTURE_2D, tex + 1);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texData4);
+
+ if (linearFilter) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
+ }
+}
+
+/* Create a simple spotlight pattern and make it the current texture */
+void
+loadSpotlightTexture(void)
+{
+ static int texWidth = 64, texHeight = 64;
+ static GLubyte *texData;
+ GLfloat borderColor[4] =
+ {0.1, 0.1, 0.1, 1.0};
+
+ if (!texData) {
+ GLubyte *p;
+ int i, j;
+
+ texData = (GLubyte *) malloc(texWidth * texHeight * 4 * sizeof(GLubyte));
+
+ p = texData;
+ for (j = 0; j < texHeight; ++j) {
+ float dy = (texHeight * 0.5 - j + 0.5) / (texHeight * 0.5);
+
+ for (i = 0; i < texWidth; ++i) {
+ float dx = (texWidth * 0.5 - i + 0.5) / (texWidth * 0.5);
+ float r = cos(M_PI / 2.0 * sqrt(dx * dx + dy * dy));
+ float c;
+
+ r = (r < 0) ? 0 : r * r;
+ c = 0xff * (r + borderColor[0]);
+ p[0] = (c <= 0xff) ? c : 0xff;
+ c = 0xff * (r + borderColor[1]);
+ p[1] = (c <= 0xff) ? c : 0xff;
+ c = 0xff * (r + borderColor[2]);
+ p[2] = (c <= 0xff) ? c : 0xff;
+ c = 0xff * (r + borderColor[3]);
+ p[3] = (c <= 0xff) ? c : 0xff;
+ p += 4;
+ }
+ }
+ }
+ if (linearFilter) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
+ gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight,
+ GL_RGBA, GL_UNSIGNED_BYTE, texData);
+}
+
+/*****************************************************************/
+
+void
+checkErrors(void)
+{
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ fprintf(stderr, "Error: %s\n", (char *) gluErrorString(error));
+ }
+}
+
+void
+drawCube(void)
+{
+ glBegin(GL_QUADS);
+
+ glNormal3f(-1.0, 0.0, 0.0);
+ glColor3f(0.80, 0.50, 0.50);
+ glVertex3f(-0.5, -0.5, -0.5);
+ glVertex3f(-0.5, -0.5, 0.5);
+ glVertex3f(-0.5, 0.5, 0.5);
+ glVertex3f(-0.5, 0.5, -0.5);
+
+ glNormal3f(1.0, 0.0, 0.0);
+ glColor3f(0.50, 0.80, 0.50);
+ glVertex3f(0.5, 0.5, 0.5);
+ glVertex3f(0.5, -0.5, 0.5);
+ glVertex3f(0.5, -0.5, -0.5);
+ glVertex3f(0.5, 0.5, -0.5);
+
+ glNormal3f(0.0, -1.0, 0.0);
+ glColor3f(0.50, 0.50, 0.80);
+ glVertex3f(-0.5, -0.5, -0.5);
+ glVertex3f(0.5, -0.5, -0.5);
+ glVertex3f(0.5, -0.5, 0.5);
+ glVertex3f(-0.5, -0.5, 0.5);
+
+ glNormal3f(0.0, 1.0, 0.0);
+ glColor3f(0.50, 0.80, 0.80);
+ glVertex3f(0.5, 0.5, 0.5);
+ glVertex3f(0.5, 0.5, -0.5);
+ glVertex3f(-0.5, 0.5, -0.5);
+ glVertex3f(-0.5, 0.5, 0.5);
+
+ glNormal3f(0.0, 0.0, -1.0);
+ glColor3f(0.80, 0.50, 0.80);
+ glVertex3f(-0.5, -0.5, -0.5);
+ glVertex3f(-0.5, 0.5, -0.5);
+ glVertex3f(0.5, 0.5, -0.5);
+ glVertex3f(0.5, -0.5, -0.5);
+
+ glNormal3f(0.0, 0.0, 1.0);
+ glColor3f(1.00, 0.80, 0.50);
+ glVertex3f(0.5, 0.5, 0.5);
+ glVertex3f(-0.5, 0.5, 0.5);
+ glVertex3f(-0.5, -0.5, 0.5);
+ glVertex3f(0.5, -0.5, 0.5);
+ glEnd();
+}
+
+void
+drawDodecahedron(void)
+{
+#define A (0.5 * 1.61803) /* (sqrt(5) + 1) / 2 */
+#define B (0.5 * 0.61803) /* (sqrt(5) - 1) / 2 */
+#define C (0.5 * 1.0)
+ GLfloat vertexes[20][3] =
+ {
+ {-A, 0.0, B},
+ {-A, 0.0, -B},
+ {A, 0.0, -B},
+ {A, 0.0, B},
+ {B, -A, 0.0},
+ {-B, -A, 0.0},
+ {-B, A, 0.0},
+ {B, A, 0.0},
+ {0.0, B, -A},
+ {0.0, -B, -A},
+ {0.0, -B, A},
+ {0.0, B, A},
+ {-C, -C, C},
+ {-C, -C, -C},
+ {C, -C, -C},
+ {C, -C, C},
+ {-C, C, C},
+ {-C, C, -C},
+ {C, C, -C},
+ {C, C, C},
+ };
+#undef A
+#undef B
+#undef C
+ GLint polygons[12][5] =
+ {
+ {0, 12, 10, 11, 16},
+ {1, 17, 8, 9, 13},
+ {2, 14, 9, 8, 18},
+ {3, 19, 11, 10, 15},
+ {4, 14, 2, 3, 15},
+ {5, 12, 0, 1, 13},
+ {6, 17, 1, 0, 16},
+ {7, 19, 3, 2, 18},
+ {8, 17, 6, 7, 18},
+ {9, 14, 4, 5, 13},
+ {10, 12, 5, 4, 15},
+ {11, 19, 7, 6, 16},
+ };
+ int i;
+
+ glColor3f(0.75, 0.75, 0.75);
+ for (i = 0; i < 12; ++i) {
+ GLfloat *p0, *p1, *p2, d;
+ GLfloat u[3], v[3], n[3];
+
+ p0 = &vertexes[polygons[i][0]][0];
+ p1 = &vertexes[polygons[i][1]][0];
+ p2 = &vertexes[polygons[i][2]][0];
+
+ u[0] = p2[0] - p1[0];
+ u[1] = p2[1] - p1[1];
+ u[2] = p2[2] - p1[2];
+
+ v[0] = p0[0] - p1[0];
+ v[1] = p0[1] - p1[1];
+ v[2] = p0[2] - p1[2];
+
+ n[0] = u[1] * v[2] - u[2] * v[1];
+ n[1] = u[2] * v[0] - u[0] * v[2];
+ n[2] = u[0] * v[1] - u[1] * v[0];
+
+ d = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
+ n[0] *= d;
+ n[1] *= d;
+ n[2] *= d;
+
+ glBegin(GL_POLYGON);
+ glNormal3fv(n);
+ glVertex3fv(p0);
+ glVertex3fv(p1);
+ glVertex3fv(p2);
+ glVertex3fv(vertexes[polygons[i][3]]);
+ glVertex3fv(vertexes[polygons[i][4]]);
+ glEnd();
+ }
+}
+
+void
+drawSphere(void)
+{
+ int numMajor = 24;
+ int numMinor = 32;
+ float radius = 0.8;
+ double majorStep = (M_PI / numMajor);
+ double minorStep = (2.0 * M_PI / numMinor);
+ int i, j;
+
+ glColor3f(0.50, 0.50, 0.50);
+ for (i = 0; i < numMajor; ++i) {
+ double a = i * majorStep;
+ double b = a + majorStep;
+ double r0 = radius * sin(a);
+ double r1 = radius * sin(b);
+ GLfloat z0 = radius * cos(a);
+ GLfloat z1 = radius * cos(b);
+
+ glBegin(GL_TRIANGLE_STRIP);
+ for (j = 0; j <= numMinor; ++j) {
+ double c = j * minorStep;
+ GLfloat x = cos(c);
+ GLfloat y = sin(c);
+
+ glNormal3f((x * r0) / radius, (y * r0) / radius, z0 / radius);
+ glTexCoord2f(j / (GLfloat) numMinor, i / (GLfloat) numMajor);
+ glVertex3f(x * r0, y * r0, z0);
+
+ glNormal3f((x * r1) / radius, (y * r1) / radius, z1 / radius);
+ glTexCoord2f(j / (GLfloat) numMinor, (i + 1) / (GLfloat) numMajor);
+ glVertex3f(x * r1, y * r1, z1);
+ }
+ glEnd();
+ }
+}
+
+/*****************************************************************/
+
+float xmin = -0.035, xmax = 0.035;
+float ymin = -0.035, ymax = 0.035;
+float nnear = 0.1;
+float ffar = 1.9;
+float distance = -1.0;
+
+static void
+loadTextureProjection(int texUnit, GLfloat m[16])
+{
+ GLfloat mInverse[4][4];
+
+ /* Should use true inverse, but since m consists only of rotations, we can
+ just use the transpose. */
+ matrixTranspose((GLfloat *) mInverse, m);
+
+ ActiveTexture(GL_TEXTURE0_ARB + texUnit);
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glTranslatef(0.5, 0.5, 0.0);
+ glScalef(0.5, 0.5, 1.0);
+ glFrustum(xmin, xmax, ymin, ymax, nnear, ffar);
+ glTranslatef(0.0, 0.0, distance);
+ glMultMatrixf((GLfloat *) mInverse);
+ glMatrixMode(GL_MODELVIEW);
+}
+
+static void
+drawTextureProjection(void)
+{
+ float t = ffar / nnear;
+ GLfloat n[4][3];
+ GLfloat f[4][3];
+
+ n[0][0] = xmin;
+ n[0][1] = ymin;
+ n[0][2] = -(nnear + distance);
+
+ n[1][0] = xmax;
+ n[1][1] = ymin;
+ n[1][2] = -(nnear + distance);
+
+ n[2][0] = xmax;
+ n[2][1] = ymax;
+ n[2][2] = -(nnear + distance);
+
+ n[3][0] = xmin;
+ n[3][1] = ymax;
+ n[3][2] = -(nnear + distance);
+
+ f[0][0] = xmin * t;
+ f[0][1] = ymin * t;
+ f[0][2] = -(ffar + distance);
+
+ f[1][0] = xmax * t;
+ f[1][1] = ymin * t;
+ f[1][2] = -(ffar + distance);
+
+ f[2][0] = xmax * t;
+ f[2][1] = ymax * t;
+ f[2][2] = -(ffar + distance);
+
+ f[3][0] = xmin * t;
+ f[3][1] = ymax * t;
+ f[3][2] = -(ffar + distance);
+
+ glColor3f(1.0, 1.0, 0.0);
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(n[0]);
+ glVertex3fv(n[1]);
+ glVertex3fv(n[2]);
+ glVertex3fv(n[3]);
+ glVertex3fv(f[3]);
+ glVertex3fv(f[2]);
+ glVertex3fv(f[1]);
+ glVertex3fv(f[0]);
+ glVertex3fv(n[0]);
+ glVertex3fv(n[1]);
+ glVertex3fv(f[1]);
+ glVertex3fv(f[0]);
+ glVertex3fv(f[3]);
+ glVertex3fv(f[2]);
+ glVertex3fv(n[2]);
+ glVertex3fv(n[3]);
+ glEnd();
+}
+
+/*****************************************************************/
+
+void
+initialize(void)
+{
+ GLfloat light0Pos[4] =
+ {0.3, 0.3, 0.0, 1.0};
+ GLfloat matAmb[4] =
+ {0.01, 0.01, 0.01, 1.00};
+ GLfloat matDiff[4] =
+ {0.65, 0.65, 0.65, 1.00};
+ GLfloat matSpec[4] =
+ {0.30, 0.30, 0.30, 1.00};
+ GLfloat matShine = 10.0;
+ GLfloat eyePlaneS[] =
+ {1.0, 0.0, 0.0, 0.0};
+ GLfloat eyePlaneT[] =
+ {0.0, 1.0, 0.0, 0.0};
+ GLfloat eyePlaneR[] =
+ {0.0, 0.0, 1.0, 0.0};
+ GLfloat eyePlaneQ[] =
+ {0.0, 0.0, 0.0, 1.0};
+ int i;
+
+ /* Setup Misc. */
+ glClearColor(0.41, 0.41, 0.31, 0.0);
+
+ glEnable(GL_DEPTH_TEST);
+
+ /* glLineWidth(2.0);*/
+
+ glCullFace(GL_FRONT);
+ glEnable(GL_CULL_FACE);
+
+ glMatrixMode(GL_PROJECTION);
+ glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3);
+ glMatrixMode(GL_MODELVIEW);
+ glTranslatef(0, 0, -2);
+
+ matrixIdentity((GLfloat *) objectXform);
+ for (i = 0; i < NumTextures; i++) {
+ matrixIdentity((GLfloat *) textureXform[i]);
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0, 1, 0, 1, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glRasterPos2i(0, 0);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+
+ /* Setup Lighting */
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmb);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine);
+
+ glEnable(GL_COLOR_MATERIAL);
+
+ glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
+ glEnable(GL_LIGHT0);
+
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
+ glEnable(GL_LIGHTING);
+
+ /* Setup Texture */
+
+ (*loadTexture) ();
+
+
+ for (i = 0; i < NumTextures; i++) {
+ ActiveTexture(GL_TEXTURE0_ARB + i);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(GL_S, GL_EYE_PLANE, eyePlaneS);
+
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(GL_T, GL_EYE_PLANE, eyePlaneT);
+
+ glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(GL_R, GL_EYE_PLANE, eyePlaneR);
+
+ glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(GL_Q, GL_EYE_PLANE, eyePlaneQ);
+ }
+}
+
+void
+display(void)
+{
+ int i;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (textureEnabled) {
+ if (mode == MoveTexture || mode == MoveView) {
+ /* Have OpenGL compute the new transformation (simple but slow). */
+ for (i = 0; i < NumTextures; i++) {
+ glPushMatrix();
+ glLoadIdentity();
+#if 0
+ if (i & 1)
+ glRotatef(angle, axis[0], axis[1], axis[2]);
+ else
+#endif
+ glRotatef(angle*(i+1), axis[0], axis[1], axis[2]);
+
+ glMultMatrixf((GLfloat *) textureXform[i]);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) textureXform[i]);
+ glPopMatrix();
+ }
+ }
+ for (i = 0; i < NumTextures; i++) {
+ loadTextureProjection(i, (GLfloat *) textureXform[i]);
+ }
+
+ if (showProjection) {
+ for (i = 0; i < NumTextures; i++) {
+ ActiveTexture(GL_TEXTURE0_ARB + i);
+ glPushMatrix();
+ glMultMatrixf((GLfloat *) textureXform[i]);
+ glDisable(GL_LIGHTING);
+ drawTextureProjection();
+ glEnable(GL_LIGHTING);
+ glPopMatrix();
+ }
+ }
+ for (i = 0; i < NumTextures; i++) {
+ ActiveTexture(GL_TEXTURE0_ARB + i);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+ glEnable(GL_TEXTURE_GEN_R);
+ glEnable(GL_TEXTURE_GEN_Q);
+ }
+ }
+ if (mode == MoveObject || mode == MoveView) {
+ /* Have OpenGL compute the new transformation (simple but slow). */
+ glPushMatrix();
+ glLoadIdentity();
+ glRotatef(angle, axis[0], axis[1], axis[2]);
+ glMultMatrixf((GLfloat *) objectXform);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) objectXform);
+ glPopMatrix();
+ }
+ glPushMatrix();
+ glMultMatrixf((GLfloat *) objectXform);
+ (*drawObject) ();
+ glPopMatrix();
+
+ for (i = 0; i < NumTextures; i++) {
+ ActiveTexture(GL_TEXTURE0_ARB + i);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_R);
+ glDisable(GL_TEXTURE_GEN_Q);
+ }
+
+ if (zoomFactor > 1.0) {
+ glDisable(GL_DEPTH_TEST);
+ glCopyPixels(0, 0, winWidth / zoomFactor, winHeight / zoomFactor, GL_COLOR);
+ glEnable(GL_DEPTH_TEST);
+ }
+ glFlush();
+ glutSwapBuffers();
+ checkErrors();
+}
+
+/*****************************************************************/
+
+/* simple trackball-like motion control */
+float lastPos[3];
+int lastTime;
+
+void
+ptov(int x, int y, int width, int height, float v[3])
+{
+ float d, a;
+
+ /* project x,y onto a hemi-sphere centered within width, height */
+ v[0] = (2.0 * x - width) / width;
+ v[1] = (height - 2.0 * y) / height;
+ d = sqrt(v[0] * v[0] + v[1] * v[1]);
+ v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0));
+ a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ v[0] *= a;
+ v[1] *= a;
+ v[2] *= a;
+}
+
+void
+startMotion(int x, int y, int but, int time)
+{
+ if (but == GLUT_LEFT_BUTTON) {
+ mode = MoveView;
+ } else if (but == GLUT_MIDDLE_BUTTON) {
+ mode = MoveTexture;
+ } else {
+ return;
+ }
+
+ lastTime = time;
+ ptov(x, y, winWidth, winHeight, lastPos);
+}
+
+void
+animate(void)
+{
+ glutPostRedisplay();
+}
+
+void
+vis(int visible)
+{
+ if (visible == GLUT_VISIBLE) {
+ if (redrawContinuously)
+ glutIdleFunc(animate);
+ } else {
+ if (redrawContinuously)
+ glutIdleFunc(NULL);
+ }
+}
+
+void
+stopMotion(int but, int time)
+{
+ if ((but == GLUT_LEFT_BUTTON && mode == MoveView) ||
+ (but == GLUT_MIDDLE_BUTTON && mode == MoveTexture)) {
+ } else {
+ return;
+ }
+
+ if (time == lastTime) {
+ /* redrawContinuously = GL_TRUE;*/
+ glutIdleFunc(animate);
+ } else {
+ angle = 0.0;
+ redrawContinuously = GL_FALSE;
+ glutIdleFunc(0);
+ }
+ if (!redrawContinuously) {
+ mode = MoveNone;
+ }
+}
+
+void
+trackMotion(int x, int y)
+{
+ float curPos[3], dx, dy, dz;
+
+ ptov(x, y, winWidth, winHeight, curPos);
+
+ dx = curPos[0] - lastPos[0];
+ dy = curPos[1] - lastPos[1];
+ dz = curPos[2] - lastPos[2];
+ angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);
+
+ axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1];
+ axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2];
+ axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0];
+
+ lastTime = glutGet(GLUT_ELAPSED_TIME);
+ lastPos[0] = curPos[0];
+ lastPos[1] = curPos[1];
+ lastPos[2] = curPos[2];
+ glutPostRedisplay();
+}
+
+/*****************************************************************/
+
+void
+object(void)
+{
+ static int object;
+
+ object++;
+ object %= 3;
+ switch (object) {
+ case 0:
+ drawObject = drawCube;
+ break;
+ case 1:
+ drawObject = drawDodecahedron;
+ break;
+ case 2:
+ drawObject = drawSphere;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+nop(void)
+{
+}
+
+void
+texture(void)
+{
+ static int texture = 0;
+
+ texture++;
+ texture %= 3;
+ if (texture == 1 && texFilename == NULL) {
+ /* Skip file texture if not loaded. */
+ texture++;
+ }
+ switch (texture) {
+ case 0:
+ loadTexture = nop;
+ textureEnabled = GL_FALSE;
+ break;
+ case 1:
+ loadTexture = loadImageTextures;
+ (*loadTexture) ();
+ textureEnabled = GL_TRUE;
+ break;
+ case 2:
+ loadTexture = loadSpotlightTexture;
+ (*loadTexture) ();
+ textureEnabled = GL_TRUE;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+help(void)
+{
+ printf("'h' - help\n");
+ printf("'l' - toggle linear/nearest filter\n");
+ printf("'s' - toggle projection frustum\n");
+ printf("'t' - toggle projected texture\n");
+ printf("'o' - toggle object\n");
+ printf("'z' - increase zoom factor\n");
+ printf("'Z' - decrease zoom factor\n");
+ printf("left mouse - move view\n");
+ printf("middle mouse - move projection\n");
+}
+
+/* ARGSUSED1 */
+void
+key(unsigned char key, int x, int y)
+{
+ switch (key) {
+ case '\033':
+ exit(0);
+ break;
+ case 'l':
+ linearFilter = !linearFilter;
+ (*loadTexture) ();
+ break;
+ case 's':
+ showProjection = !showProjection;
+ break;
+ case 't':
+ texture();
+ break;
+ case 'o':
+ object();
+ break;
+ case 'z':
+ zoomFactor += 1.0;
+ glPixelZoom(zoomFactor, zoomFactor);
+ glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
+ break;
+ case 'Z':
+ zoomFactor -= 1.0;
+ if (zoomFactor < 1.0)
+ zoomFactor = 1.0;
+ glPixelZoom(zoomFactor, zoomFactor);
+ glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
+ break;
+ case 'h':
+ help();
+ break;
+ }
+ glutPostRedisplay();
+}
+
+void
+mouse(int button, int state, int x, int y)
+{
+ if (state == GLUT_DOWN)
+ startMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
+ else if (state == GLUT_UP)
+ stopMotion(button, glutGet(GLUT_ELAPSED_TIME));
+ glutPostRedisplay();
+}
+
+void
+reshape(int w, int h)
+{
+ winWidth = w;
+ winHeight = h;
+ glViewport(0, 0, w / zoomFactor, h / zoomFactor);
+}
+
+
+void
+menu(int selection)
+{
+ if (selection == 666) {
+ exit(0);
+ }
+ key((unsigned char) selection, 0, 0);
+}
+
+int
+main(int argc, char **argv)
+{
+ glutInit(&argc, argv);
+
+ if (argc > 1) {
+ NumTextures = atoi(argv[1]);
+ }
+ assert(NumTextures <= MAX_TEX);
+
+ glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
+ (void) glutCreateWindow("projtex");
+
+ loadTexture = loadImageTextures;
+ drawObject = drawCube;
+ initialize();
+ glutDisplayFunc(display);
+ glutKeyboardFunc(key);
+ glutReshapeFunc(reshape);
+ glutMouseFunc(mouse);
+ glutMotionFunc(trackMotion);
+ glutVisibilityFunc(vis);
+ glutCreateMenu(menu);
+ glutAddMenuEntry("Toggle showing projection", 's');
+ glutAddMenuEntry("Switch texture", 't');
+ glutAddMenuEntry("Switch object", 'o');
+ glutAddMenuEntry("Toggle filtering", 'l');
+ glutAddMenuEntry("Quit", 666);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+ texture();
+ glutMainLoop();
+ return 0; /* ANSI C requires main to return int. */
+}
diff --git a/tests/mesa/tests/readrate.c b/tests/mesa/tests/readrate.c
new file mode 100644
index 00000000..42ae62d4
--- /dev/null
+++ b/tests/mesa/tests/readrate.c
@@ -0,0 +1,285 @@
+/*
+ * Test glReadPixels speed
+ * Brian Paul
+ * 9 April 2004
+ *
+ * Compile:
+ * gcc readrate.c -L/usr/X11R6/lib -lglut -lGLU -lGL -lX11 -o readrate
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+/* Hack, to test drawing instead of reading */
+#define DRAW 0
+
+#define MAX_WIDTH 1280
+#define MAX_HEIGHT 1024
+
+#define NUM_WIDTHS 4
+#define NUM_HEIGHTS 4
+static const GLint Widths[] = {256, 512, 1024, 1280};
+static const GLint Heights[] = {4, 32, 256, 512, 768, 1024};
+static int WidthIndex = 1, HeightIndex = 3;
+static GLubyte *Buffer = NULL;
+static GLboolean Benchmark = GL_TRUE;
+
+#define NUM_PBO 2
+
+static GLuint PBObjects[4];
+
+static GLboolean HavePBO = GL_FALSE;
+
+
+struct format_type {
+ const char *Name;
+ GLuint Bytes;
+ GLenum Format;
+ GLenum Type;
+};
+
+static struct format_type Formats[] = {
+ { "GL_RGB, GLubyte", 3, GL_RGB, GL_UNSIGNED_BYTE },
+ { "GL_BGR, GLubyte", 3, GL_BGR, GL_UNSIGNED_BYTE },
+ { "GL_RGBA, GLubyte", 4, GL_RGBA, GL_UNSIGNED_BYTE },
+ { "GL_BGRA, GLubyte", 4, GL_BGRA, GL_UNSIGNED_BYTE },
+ { "GL_ABGR, GLubyte", 4, GL_ABGR_EXT, GL_UNSIGNED_BYTE },
+ { "GL_RGBA, GLuint_8_8_8_8", 4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8 },
+ { "GL_BGRA, GLuint_8_8_8_8", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8 },
+ { "GL_BGRA, GLuint_8_8_8_8_rev", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV },
+#ifdef GL_EXT_packed_depth_stencil
+ { "GL_DEPTH_STENCIL_EXT, GLuint24+8", 4, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT },
+#endif
+ { "GL_DEPTH_COMPONENT, GLfloat", 4, GL_DEPTH_COMPONENT, GL_FLOAT },
+ { "GL_DEPTH_COMPONENT, GLuint", 4, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }
+};
+
+#define NUM_FORMATS (sizeof(Formats) / sizeof(struct format_type))
+
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static void
+MeasureFormat(struct format_type *fmt, GLint width, GLint height, GLuint pbo)
+{
+ double t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
+ double t1;
+ int j;
+
+ for (j = 0; ; j++) {
+
+ glBegin(GL_POINTS);
+ glVertex2f(1,1);
+ glEnd();
+
+#if DRAW
+ glWindowPos2iARB(0,0);
+ glDrawPixels(width, height,
+ fmt->Format, fmt->Type, Buffer);
+ glFinish();
+#else
+ if (pbo) {
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, PBObjects[j % NUM_PBO]);
+ glReadPixels(0, 0, width, height,
+ fmt->Format, fmt->Type, 0);
+ }
+ else {
+ glReadPixels(0, 0, width, height,
+ fmt->Format, fmt->Type, Buffer);
+ }
+#endif
+
+ t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
+ if (t1 - t0 > 2.0) {
+ GLdouble rate = width * height / (1024.0 * 1024.0) * j / (t1 - t0);
+#if DRAW
+ printf("%-32s %.2f draws/sec %.2f MPixels/sec %.2f MBytes/sec\n",
+ fmt->Name, j / (t1-t0), rate, rate * fmt->Bytes);
+#else
+ printf("%-32s %.2f reads/sec %.2f MPixels/sec %.2f MBytes/sec\n",
+ fmt->Name, j / (t1-t0), rate, rate * fmt->Bytes);
+#endif
+ break;
+ }
+
+ if (j == 0) {
+ /* check for error */
+ GLenum err = glGetError();
+ if (err) {
+ printf("GL Error 0x%x for %s\n", err, fmt->Name);
+ return;
+ }
+ }
+ }
+}
+
+
+
+static void
+Draw(void)
+{
+ char str[1000];
+ int width = Widths[WidthIndex];
+ int height = Heights[HeightIndex];
+ int y = MAX_HEIGHT - 50;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glWindowPos2iARB(10, y);
+ sprintf(str, "ReadPixels size: %d x %d", width, height);
+ PrintString(str);
+ y -= 14;
+
+ glWindowPos2iARB(10, y);
+ PrintString("Press up/down/left/right to change image size.");
+ y -= 14;
+
+ glWindowPos2iARB(10, y);
+ PrintString("Press 'b' to run benchmark test.");
+ y -= 14;
+
+ if (Benchmark) {
+ glWindowPos2iARB(10, y);
+ PrintString("Testing...");
+ }
+
+ glutSwapBuffers();
+
+ if (Benchmark) {
+ GLuint i, pbo;
+#if DRAW
+ printf("Draw size: Width=%d Height=%d\n", width, height);
+#else
+ printf("Read size: Width=%d Height=%d\n", width, height);
+#endif
+ for (pbo = 0; pbo <= HavePBO; pbo++) {
+ printf("Pixel Buffer Object: %d\n", pbo);
+
+ if (pbo == 0) {
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);
+ }
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ MeasureFormat(Formats + i, width, height, pbo);
+ }
+ }
+
+ Benchmark = GL_FALSE;
+
+ /* redraw window text */
+ glutPostRedisplay();
+ }
+
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1, 1, -1, 1, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'b':
+ Benchmark = 1;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ if (HeightIndex + 1 < NUM_WIDTHS)
+ HeightIndex++;
+ break;
+ case GLUT_KEY_DOWN:
+ if (HeightIndex > 0)
+ HeightIndex--;
+ break;
+ case GLUT_KEY_LEFT:
+ if (WidthIndex > 0)
+ WidthIndex--;
+ break;
+ case GLUT_KEY_RIGHT:
+ if (WidthIndex + 1 < NUM_HEIGHTS)
+ WidthIndex++;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+ Buffer = malloc(MAX_WIDTH * MAX_HEIGHT * 4);
+ assert(Buffer);
+#if DRAW
+ printf("glDrawPixels test report:\n");
+#else
+ printf("glReadPixels test report:\n");
+#endif
+ printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
+
+ if (glutExtensionSupported("GL_ARB_pixel_buffer_object")) {
+ int i;
+ HavePBO = 1;
+ glGenBuffersARB(NUM_PBO, PBObjects);
+ for (i = 0; i < NUM_PBO; i++) {
+ glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, PBObjects[i]);
+ glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT,
+ MAX_WIDTH * MAX_HEIGHT * 4, NULL, GL_STREAM_READ);
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(MAX_WIDTH, MAX_HEIGHT);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Draw);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/seccolor.c b/tests/mesa/tests/seccolor.c
new file mode 100644
index 00000000..77fd4064
--- /dev/null
+++ b/tests/mesa/tests/seccolor.c
@@ -0,0 +1,145 @@
+/*
+ * Exercise GL_EXT_secondary_color
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static int Width = 600;
+static int Height = 200;
+static GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+ GLfloat t;
+
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ for (t = 0.0; t <= 1.0; t += 0.25) {
+ GLfloat x = t * 10.0 - 5.0;
+ GLfloat g = t;
+
+ /* top row: untextured */
+ glColor3f(1, 0, 0);
+ glPushMatrix();
+ glTranslatef(x, 1.2, 0);
+#if defined(GL_EXT_secondary_color)
+ glSecondaryColor3fEXT(0, g, 0);
+#endif
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+ glPopMatrix();
+
+ /* bottom row: textured */
+ glColor3f(1, 1, 1);
+ glEnable(GL_TEXTURE_2D);
+ glPushMatrix();
+ glTranslatef(x, -1.2, 0);
+#if defined(GL_EXT_secondary_color)
+ glSecondaryColor3fEXT(0, g, 0);
+#endif
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-1, -1);
+ glTexCoord2f(1, 0); glVertex2f( 1, -1);
+ glTexCoord2f(1, 1); glVertex2f( 1, 1);
+ glTexCoord2f(0, 1); glVertex2f(-1, 1);
+ glEnd();
+ glPopMatrix();
+ glDisable(GL_TEXTURE_2D);
+ }
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ GLubyte image[4*4][3];
+ GLint i;
+ if (!glutExtensionSupported("GL_EXT_secondary_color")) {
+ printf("Sorry, this program requires GL_EXT_secondary_color\n");
+ exit(1);
+ }
+
+ /* setup red texture with one back texel */
+ for (i = 0; i < 4*4; i++) {
+ if (i == 0) {
+ image[i][0] = 0;
+ image[i][1] = 0;
+ image[i][2] = 0;
+ }
+ else {
+ image[i][0] = 255;
+ image[i][1] = 0;
+ image[i][2] = 0;
+ }
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, image);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+#if defined(GL_EXT_secondary_color)
+ glEnable(GL_COLOR_SUM_EXT);
+#endif
+ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+
+ printf("Squares should be colored from red -> orange -> yellow.\n");
+ printf("Top row is untextured.\n");
+ printf("Bottom row is textured (red texture with one black texel).\n");
+ printf("Rows should be identical, except for lower-left texel.\n");
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/sharedtex.c b/tests/mesa/tests/sharedtex.c
new file mode 100644
index 00000000..7be90d67
--- /dev/null
+++ b/tests/mesa/tests/sharedtex.c
@@ -0,0 +1,440 @@
+/* $Id: sharedtex.c,v 1.2 2002/01/16 14:32:46 joukj Exp $ */
+
+/*
+ * Test sharing of display lists and texture objects between GLX contests.
+ * Brian Paul
+ * Summer 2000
+ *
+ *
+ * Copyright (C) 2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+
+struct window {
+ char DisplayName[1000];
+ Display *Dpy;
+ Window Win;
+ GLXContext Context;
+ float Angle;
+ int Id;
+};
+
+
+#define MAX_WINDOWS 20
+static struct window Windows[MAX_WINDOWS];
+static int NumWindows = 0;
+
+
+static GLuint Textures[3];
+static GLuint CubeList;
+
+
+
+static void
+Error(const char *display, const char *msg)
+{
+ fprintf(stderr, "Error on display %s - %s\n", display, msg);
+ exit(1);
+}
+
+
+static struct window *
+AddWindow(const char *displayName, int xpos, int ypos,
+ const struct window *shareWindow)
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ XVisualInfo *visinfo;
+ int width = 300, height = 300;
+
+ if (NumWindows >= MAX_WINDOWS)
+ return NULL;
+
+ dpy = XOpenDisplay(displayName);
+ if (!dpy) {
+ Error(displayName, "Unable to open display");
+ return NULL;
+ }
+
+ scrnum = DefaultScreen(dpy);
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, attrib);
+ if (!visinfo) {
+ Error(displayName, "Unable to find RGB, double-buffered visual");
+ return NULL;
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow(dpy, root, xpos, ypos, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+ if (!win) {
+ Error(displayName, "Couldn't create window");
+ return NULL;
+ }
+
+ {
+ XSizeHints sizehints;
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, displayName, displayName,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+
+ ctx = glXCreateContext(dpy, visinfo,
+ shareWindow ? shareWindow->Context : NULL,
+ True);
+ if (!ctx) {
+ Error(displayName, "Couldn't create GLX context");
+ return NULL;
+ }
+
+ XMapWindow(dpy, win);
+
+ if (!glXMakeCurrent(dpy, win, ctx)) {
+ Error(displayName, "glXMakeCurrent failed");
+ printf("glXMakeCurrent failed in Redraw()\n");
+ return NULL;
+ }
+
+ /* save the info for this window */
+ {
+ static int id = 0;
+ struct window *h = &Windows[NumWindows];
+ strcpy(h->DisplayName, displayName);
+ h->Dpy = dpy;
+ h->Win = win;
+ h->Context = ctx;
+ h->Angle = 0.0;
+ h->Id = id++;
+ NumWindows++;
+ return &Windows[NumWindows-1];
+ }
+
+}
+
+
+static void
+InitGLstuff(struct window *h)
+{
+ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
+ Error(h->DisplayName, "glXMakeCurrent failed in InitGLstuff");
+ return;
+ }
+
+ glGenTextures(3, Textures);
+
+ /* setup first texture object */
+ {
+ GLubyte image[16][16][4];
+ GLint i, j;
+ glBindTexture(GL_TEXTURE_2D, Textures[0]);
+
+ /* red/white checkerboard */
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ if ((i ^ j) & 1) {
+ image[i][j][0] = 255;
+ image[i][j][1] = 255;
+ image[i][j][2] = 255;
+ image[i][j][3] = 255;
+ }
+ else {
+ image[i][j][0] = 255;
+ image[i][j][1] = 0;
+ image[i][j][2] = 0;
+ image[i][j][3] = 255;
+ }
+ }
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, image);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+
+ /* setup second texture object */
+ {
+ GLubyte image[8][8][3];
+ GLint i, j;
+ glBindTexture(GL_TEXTURE_2D, Textures[1]);
+
+ /* green/yellow checkerboard */
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ if ((i ^ j) & 1) {
+ image[i][j][0] = 0;
+ image[i][j][1] = 255;
+ image[i][j][2] = 0;
+ }
+ else {
+ image[i][j][0] = 255;
+ image[i][j][1] = 255;
+ image[i][j][2] = 0;
+ }
+ }
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB,
+ GL_UNSIGNED_BYTE, image);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+
+ /* setup second texture object */
+ {
+ GLubyte image[4][4][3];
+ GLint i, j;
+ glBindTexture(GL_TEXTURE_2D, Textures[2]);
+
+ /* blue/gray checkerboard */
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ if ((i ^ j) & 1) {
+ image[i][j][0] = 0;
+ image[i][j][1] = 0;
+ image[i][j][2] = 255;
+ }
+ else {
+ image[i][j][0] = 200;
+ image[i][j][1] = 200;
+ image[i][j][2] = 200;
+ }
+ }
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB,
+ GL_UNSIGNED_BYTE, image);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+
+ /* Now make the cube object display list */
+ CubeList = glGenLists(1);
+ glNewList(CubeList, GL_COMPILE);
+ {
+ glBindTexture(GL_TEXTURE_2D, Textures[0]);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
+ glTexCoord2f(1, 0); glVertex3f(-1, 1, -1);
+ glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
+ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
+ glEnd();
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
+ glTexCoord2f(1, 0); glVertex3f(1, 1, -1);
+ glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
+ glTexCoord2f(0, 1); glVertex3f(1, -1, 1);
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, Textures[1]);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
+ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
+ glTexCoord2f(1, 1); glVertex3f( 1, -1, 1);
+ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
+ glEnd();
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex3f(-1, 1, -1);
+ glTexCoord2f(1, 0); glVertex3f( 1, 1, -1);
+ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
+ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, Textures[2]);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
+ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
+ glTexCoord2f(1, 1); glVertex3f( 1, 1, -1);
+ glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
+ glEnd();
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
+ glTexCoord2f(1, 0); glVertex3f( 1, -1, 1);
+ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
+ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
+ glEnd();
+ }
+ glEndList();
+
+ printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR: %s\n", (char *) glGetString(GL_VENDOR));
+}
+
+
+
+static void
+Redraw(struct window *h)
+{
+ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
+ Error(h->DisplayName, "glXMakeCurrent failed");
+ printf("glXMakeCurrent failed in Redraw()\n");
+ return;
+ }
+
+ h->Angle += 1.0;
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.25, 0.25, 0.25, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_DEPTH_TEST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ glColor3f(1, 1, 1);
+
+ glPushMatrix();
+ if (h->Id == 0)
+ glRotatef(h->Angle, 0, 1, -1);
+ else if (h->Id == 1)
+ glRotatef(-(h->Angle), 0, 1, -1);
+ else if (h->Id == 2)
+ glRotatef(h->Angle, 0, 1, 1);
+ else if (h->Id == 3)
+ glRotatef(-(h->Angle), 0, 1, 1);
+ glCallList(CubeList);
+ glPopMatrix();
+
+ glXSwapBuffers(h->Dpy, h->Win);
+}
+
+
+
+static void
+Resize(const struct window *h, unsigned int width, unsigned int height)
+{
+ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
+ Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
+ return;
+ }
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1, 1, -1, 1, 2, 10);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0, 0, -4.5);
+}
+
+
+
+static void
+EventLoop(void)
+{
+ while (1) {
+ int i;
+ for (i = 0; i < NumWindows; i++) {
+ struct window *h = &Windows[i];
+ while (XPending(h->Dpy) > 0) {
+ XEvent event;
+ XNextEvent(h->Dpy, &event);
+ if (event.xany.window == h->Win) {
+ switch (event.type) {
+ case Expose:
+ Redraw(h);
+ break;
+ case ConfigureNotify:
+ Resize(h, event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ return;
+ default:
+ /*no-op*/ ;
+ }
+ }
+ else {
+ printf("window mismatch\n");
+ }
+ }
+ Redraw(h);
+ }
+ usleep(1);
+ }
+}
+
+
+#if 0
+static void
+PrintInfo(const struct window *h)
+{
+ printf("Name: %s\n", h->DisplayName);
+ printf(" Display: %p\n", (void *) h->Dpy);
+ printf(" Window: 0x%x\n", (int) h->Win);
+ printf(" Context: 0x%x\n", (int) h->Context);
+}
+#endif
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *dpyName = XDisplayName(NULL);
+
+ struct window *h0, *h1, *h2, *h3;
+
+ /* four windows and contexts sharing display lists and texture objects */
+ h0 = AddWindow(dpyName, 10, 10, NULL);
+ h1 = AddWindow(dpyName, 330, 10, h0);
+ h2 = AddWindow(dpyName, 10, 350, h0);
+ h3 = AddWindow(dpyName, 330, 350, h0);
+
+ InitGLstuff(h0);
+
+ EventLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/stencil_wrap.c b/tests/mesa/tests/stencil_wrap.c
new file mode 100644
index 00000000..88cf3809
--- /dev/null
+++ b/tests/mesa/tests/stencil_wrap.c
@@ -0,0 +1,257 @@
+/*
+ * (C) Copyright IBM Corporation 2004
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file stencil_wrap.c
+ *
+ * Simple test of GL_EXT_stencil_wrap functionality. Four squares are drawn
+ * with different stencil modes, but all should be rendered with the same
+ * final color.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+
+static int Width = 550;
+static int Height = 200;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+ GLint max_stencil;
+ GLint stencil_bits;
+ unsigned i;
+
+
+ glGetIntegerv( GL_STENCIL_BITS, & stencil_bits );
+ max_stencil = (1U << stencil_bits) - 1;
+ printf( "Stencil bits = %u, maximum stencil value = 0x%08x\n",
+ stencil_bits, max_stencil );
+
+ glClearStencil( 0 );
+ glClearColor( 0.2, 0.2, 0.8, 0 );
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
+ | GL_STENCIL_BUFFER_BIT );
+
+
+ glPushMatrix();
+
+ /* This is the "reference" square.
+ */
+
+ glDisable(GL_STENCIL_TEST);
+ glTranslatef(-6.0, 0, 0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+ glEnable(GL_STENCIL_TEST);
+
+ /* Draw the first two squares using the two non-wrap (i.e., saturate)
+ * modes.
+ */
+
+ glStencilFunc(GL_ALWAYS, 0, ~0);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+
+ glTranslatef(3.0, 0, 0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.9, 0.9, 0.9 );
+
+ for ( i = 0 ; i < (max_stencil + 5) ; i++ ) {
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ }
+ glEnd();
+
+ glStencilFunc(GL_EQUAL, max_stencil, ~0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+ glStencilFunc(GL_ALWAYS, 0, ~0);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
+
+ glTranslatef(3.0, 0, 0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.9, 0.9, 0.9 );
+
+ for ( i = 0 ; i < (max_stencil + 5) ; i++ ) {
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ }
+ glEnd();
+
+ glStencilFunc(GL_EQUAL, 0, ~0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+
+
+ /* Draw the last two squares using the two wrap modes.
+ */
+
+ glStencilFunc(GL_ALWAYS, 0, ~0);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
+
+ glTranslatef(3.0, 0, 0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.9, 0.9, 0.9 );
+
+ for ( i = 0 ; i < (max_stencil + 5) ; i++ ) {
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ }
+ glEnd();
+
+ glStencilFunc(GL_EQUAL, 4, ~0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+
+ glStencilFunc(GL_ALWAYS, 0, ~0);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP);
+
+ glTranslatef(3.0, 0, 0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.9, 0.9, 0.9 );
+
+ for ( i = 0 ; i < 5 ; i++ ) {
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ }
+ glEnd();
+
+ glStencilFunc(GL_EQUAL, (max_stencil - 4), ~0);
+ glBegin(GL_QUADS);
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+
+
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ if ( !glutExtensionSupported("GL_EXT_stencil_wrap")
+ && (atof( ver_string ) < 1.4) ) {
+ printf("Sorry, this program requires either GL_EXT_stencil_wrap or OpenGL 1.4.\n");
+ exit(1);
+ }
+
+ printf("\nAll 5 squares should be the same color.\n");
+ glEnable( GL_BLEND );
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL );
+ glutCreateWindow( "GL_EXT_stencil_wrap test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/stencilwrap.c b/tests/mesa/tests/stencilwrap.c
new file mode 100644
index 00000000..753375d0
--- /dev/null
+++ b/tests/mesa/tests/stencilwrap.c
@@ -0,0 +1,281 @@
+/* Test GL_EXT_stencil_wrap extension.
+ * This is by no means complete, just a quick check.
+ *
+ * Brian Paul 30 October 2002
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+GLboolean wrapping;
+
+static void RunTest(void)
+{
+ const GLenum prim = GL_QUAD_STRIP;
+ GLubyte val;
+ int bits, max, i;
+ int expected;
+ GLboolean failed;
+
+ glGetIntegerv(GL_STENCIL_BITS, &bits);
+ max = (1 << bits) - 1;
+
+
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 0, ~0);
+
+ /* test GL_KEEP */
+ glClearStencil(max);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ failed = GL_FALSE;
+ printf("Testing GL_KEEP...\n");
+ expected = max;
+ glBegin(prim);
+ glVertex2f(0, 0);
+ glVertex2f(10, 0);
+ glVertex2f(0, 10);
+ glVertex2f(10, 10);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &val);
+ if (val != expected) {
+ printf("Failed GL_KEEP test(got %u, expected %u)\n", val, expected);
+ failed = GL_TRUE;
+ }
+ else
+ printf("OK!\n");
+
+ /* test GL_ZERO */
+ glClearStencil(max);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
+ failed = GL_FALSE;
+ printf("Testing GL_ZERO...\n");
+ expected = 0;
+ glBegin(prim);
+ glVertex2f(0, 0);
+ glVertex2f(10, 0);
+ glVertex2f(0, 10);
+ glVertex2f(10, 10);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &val);
+ if (val != expected) {
+ printf("Failed GL_ZERO test(got %u, expected %u)\n", val, expected);
+ failed = GL_TRUE;
+ }
+ else
+ printf("OK!\n");
+
+ /* test GL_REPLACE */
+ glClearStencil(max);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ failed = GL_FALSE;
+ printf("Testing GL_REPLACE...\n");
+ expected = 0;
+ glBegin(prim);
+ glVertex2f(0, 0);
+ glVertex2f(10, 0);
+ glVertex2f(0, 10);
+ glVertex2f(10, 10);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &val);
+ if (val != expected) {
+ printf("Failed GL_REPLACE test(got %u, expected %u)\n", val, expected);
+ failed = GL_TRUE;
+ }
+ else
+ printf("OK!\n");
+
+ /* test GL_INCR (saturation) */
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+ failed = GL_FALSE;
+ printf("Testing GL_INCR...\n");
+ for (i = 1; i < max+10; i++) {
+ expected = (i > max) ? max : i;
+ glBegin(prim);
+ glVertex2f(0, 0); glVertex2f(10, 0);
+ glVertex2f(0, 10); glVertex2f(10, 10);
+ glEnd();
+
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &val);
+ if (val != expected) {
+ printf( "Failed GL_INCR test on iteration #%u "
+ "(got %u, expected %u)\n", i, val, expected );
+ failed = GL_TRUE;
+ }
+ }
+ if ( !failed )
+ printf("OK!\n");
+
+ /* test GL_DECR (saturation) */
+ glClearStencil(max);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
+ failed = GL_FALSE;
+ printf("Testing GL_DECR...\n");
+ for (i = max-1; i > -10; i--) {
+ expected = (i < 0) ? 0 : i;
+ glBegin(prim);
+ glVertex2f(0, 0); glVertex2f(10, 0);
+ glVertex2f(0, 10); glVertex2f(10, 10);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &val);
+ if (val != expected) {
+ printf( "Failed GL_DECR test on iteration #%u "
+ "(got %u, expected %u)\n", max - i, val, expected );
+ failed = GL_TRUE;
+ }
+ }
+ if ( !failed )
+ printf("OK!\n");
+
+ /* test GL_INVERT */
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
+ failed = GL_FALSE;
+ printf("Testing GL_INVERT...\n");
+ expected = max;
+ glBegin(prim);
+ glVertex2f(0, 0);
+ glVertex2f(10, 0);
+ glVertex2f(0, 10);
+ glVertex2f(10, 10);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &val);
+ if (val != expected) {
+ printf("Failed GL_INVERT test(got %u, expected %u)\n", val, expected);
+ failed = GL_TRUE;
+ }
+ else
+ printf("OK!\n");
+
+ if(wrapping)
+ {
+ /* test GL_INCR_WRAP_EXT (wrap around) */
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT);
+ failed = GL_FALSE;
+ printf("Testing GL_INCR_WRAP_EXT...\n");
+ for (i = 1; i < max+10; i++) {
+ expected = i % (max + 1);
+ glBegin(prim);
+ glVertex2f(0, 0); glVertex2f(10, 0);
+ glVertex2f(0, 10); glVertex2f(10, 10);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &val);
+ if (val != expected) {
+ printf( "Failed GL_INCR_WRAP test on iteration #%u "
+ "(got %u, expected %u)\n", i, val, expected );
+ failed = GL_TRUE;
+ }
+ }
+ if ( !failed )
+ printf("OK!\n");
+
+ /* test GL_DECR_WRAP_EXT (wrap-around) */
+ glClearStencil(max);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT);
+ failed = GL_FALSE;
+ printf("Testing GL_DECR_WRAP_EXT...\n");
+ for (i = max-1; i > -10; i--) {
+ expected = (i < 0) ? max + i + 1: i;
+ glBegin(prim);
+ glVertex2f(0, 0); glVertex2f(10, 0);
+ glVertex2f(0, 10); glVertex2f(10, 10);
+ glEnd();
+ glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &val);
+ if (val != expected) {
+ printf( "Failed GL_DECR_WRAP test on iteration #%u "
+ "(got %u, expected %u)\n", max - i, val, expected );
+ failed = GL_TRUE;
+ }
+ }
+ if ( !failed )
+ printf("OK!\n");
+ }
+
+ glDisable(GL_STENCIL_TEST);
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ RunTest();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho(0, width, 0, height, -1, 1);
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * ver_str;
+ float version;
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+
+
+ /* Check for both the extension string and GL version 1.4 on the
+ * outside chance that some vendor exports version 1.4 but doesn't
+ * export the extension string. The stencil-wrap modes are a required
+ * part of GL 1.4.
+ */
+
+ ver_str = glGetString( GL_VERSION );
+ version = (ver_str == NULL) ? 1.0 : atof( ver_str );
+
+ wrapping = (glutExtensionSupported("GL_EXT_stencil_wrap") || (version >= 1.4));
+ if (!wrapping)
+ printf("GL_EXT_stencil_wrap not supported. Only testing the rest.\n");
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 400, 400 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_STENCIL );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/subtexrate.c b/tests/mesa/tests/subtexrate.c
new file mode 100644
index 00000000..568b68d5
--- /dev/null
+++ b/tests/mesa/tests/subtexrate.c
@@ -0,0 +1,350 @@
+/*
+ * Measure glTexSubImage and glCopyTexSubImage speed
+ *
+ * Brian Paul
+ * 26 Jan 2006
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static GLint WinWidth = 1024, WinHeight = 512;
+static GLint TexWidth = 512, TexHeight = 512;
+
+static GLuint TexObj = 1;
+
+static GLenum IntFormat = GL_RGBA8;
+static GLenum ReadFormat = GL_RGBA; /* for glReadPixels */
+
+static GLboolean DrawQuad = GL_TRUE;
+
+
+/**
+ * draw teapot image, size TexWidth by TexHeight
+ */
+static void
+DrawTestImage(void)
+{
+ GLfloat ar;
+
+ glViewport(0, 0, TexWidth, TexHeight);
+ glScissor(0, 0, TexWidth, TexHeight);
+ glEnable(GL_SCISSOR_TEST);
+
+ glClearColor(0.5, 0.5, 0.5, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ar = (float) TexWidth / TexHeight;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-ar, ar, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+ glFrontFace(GL_CW);
+ glPushMatrix();
+ glRotatef(45, 1, 0, 0);
+ glRotatef(45, 0, 1, 0);
+ glutSolidTeapot(2.3);
+ glPopMatrix();
+ glFrontFace(GL_CCW);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_SCISSOR_TEST);
+
+ glViewport(0, 0, WinWidth, WinHeight);
+ glFinish();
+}
+
+
+/**
+ * Do glCopyTexSubImage2D call (update texture with framebuffer data)
+ * If doSubRect is true, do the copy in four pieces instead of all at once.
+ */
+static void
+DoCopyTex(GLboolean doSubRect)
+{
+ if (doSubRect) {
+ /* copy in four parts */
+ int w = TexWidth / 2, h = TexHeight / 2;
+ int x0 = 0, y0 = 0;
+ int x1 = w, y1 = h;
+#if 1
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, x0, y0, w, h);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x1, y0, x1, y0, w, h);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x0, y1, x0, y1, w, h);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x1, y1, x1, y1, w, h);
+#else
+ /* scramble */
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, x1, y1, w, h);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x1, y0, x0, y1, w, h);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x0, y1, x1, y0, w, h);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x1, y1, x0, y0, w, h);
+#endif
+ }
+ else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TexWidth, TexHeight);
+ }
+}
+
+
+/**
+ * Do glTexSubImage2D (update texture w/ user data)
+ * If doSubRect, do update in four pieces, else all at once.
+ */
+static void
+SubTex(GLboolean doSubRect, const GLubyte *image)
+{
+ if (doSubRect) {
+ /* four pieces */
+ int w = TexWidth / 2, h = TexHeight / 2;
+ int x0 = 0, y0 = 0;
+ int x1 = w, y1 = h;
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, TexWidth);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, y0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, x0);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, w, h,
+ ReadFormat, GL_UNSIGNED_BYTE, image);
+
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, y0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, x1);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x1, y0, w, h,
+ ReadFormat, GL_UNSIGNED_BYTE, image);
+
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, y1);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, x0);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y1, w, h,
+ ReadFormat, GL_UNSIGNED_BYTE, image);
+
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, y1);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, x1);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x1, y1, w, h,
+ ReadFormat, GL_UNSIGNED_BYTE, image);
+ }
+ else {
+ /* all at once */
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TexWidth, TexHeight,
+ ReadFormat, GL_UNSIGNED_BYTE, image);
+ }
+}
+
+
+/**
+ * Measure gl[Copy]TexSubImage rate.
+ * This actually also includes time to render a quad and SwapBuffers.
+ */
+static void
+RunTest(GLboolean copyTex, GLboolean doSubRect)
+{
+ double t0, t1;
+ int iters = 0;
+ float copyRate, mbRate;
+ float rot = 0.0;
+ int bpp, r, g, b, a;
+ int w, h;
+ GLubyte *image = NULL;
+
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, &r);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_GREEN_SIZE, &g);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BLUE_SIZE, &b);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &a);
+ bpp = (r + g + b + a) / 8;
+
+ if (!copyTex) {
+ /* read image from frame buffer */
+ image = (GLubyte *) malloc(TexWidth * TexHeight * bpp);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glReadPixels(0, 0, TexWidth, TexHeight,
+ ReadFormat, GL_UNSIGNED_BYTE, image);
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glViewport(WinWidth / 2, 0, WinWidth / 2, WinHeight);
+
+ t0 = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+
+ do {
+ if (copyTex)
+ /* Framebuffer -> Texture */
+ DoCopyTex(doSubRect);
+ else {
+ /* Main Mem -> Texture */
+ SubTex(doSubRect, image);
+ }
+
+ /* draw textured quad */
+ if (DrawQuad) {
+ glPushMatrix();
+ glRotatef(rot, 0, 0, 1);
+ glTranslatef(1, 0, 0);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-1, -1);
+ glTexCoord2f(1, 0); glVertex2f( 1, -1);
+ glTexCoord2f(1, 1); glVertex2f( 1, 1);
+ glTexCoord2f(0, 1); glVertex2f(-1, 1);
+ glEnd();
+ glPopMatrix();
+ }
+
+ iters++;
+ rot += 2.0;
+
+ t1 = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+ if (DrawQuad) {
+ glutSwapBuffers();
+ }
+ } while (t1 - t0 < 5.0);
+
+ glDisable(GL_TEXTURE_2D);
+ if (image)
+ free(image);
+
+ if (doSubRect) {
+ w = TexWidth / 2;
+ h = TexHeight / 2;
+ iters *= 4;
+ }
+ else {
+ w = TexWidth;
+ h = TexHeight;
+ }
+
+ copyRate = iters / (t1 - t0);
+ mbRate = w * h * bpp * copyRate / (1024 * 1024);
+
+ if (copyTex)
+ printf("glCopyTexSubImage: %d x %d, %d Bpp:\n", w, h, bpp);
+ else
+ printf("glTexSubImage: %d x %d, %d Bpp:\n", w, h, bpp);
+ printf(" %d calls in %.2f = %.2f calls/sec, %.2f MB/s\n",
+ iters, t1-t0, copyRate, mbRate);
+}
+
+
+static void
+Draw(void)
+{
+ glClearColor(0.2, 0.2, 0.8, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ DrawTestImage();
+ if (!DrawQuad) {
+ glutSwapBuffers();
+ }
+
+ RunTest(GL_FALSE, GL_FALSE);
+ RunTest(GL_FALSE, GL_TRUE);
+ RunTest(GL_TRUE, GL_FALSE);
+ RunTest(GL_TRUE, GL_TRUE);
+
+ glutSwapBuffers();
+
+ printf("exiting\n");
+ exit(0);
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -15.0);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ break;
+ case GLUT_KEY_DOWN:
+ break;
+ case GLUT_KEY_LEFT:
+ break;
+ case GLUT_KEY_RIGHT:
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+ /* create initial, empty teximage */
+ glBindTexture(GL_TEXTURE_2D, TexObj);
+ glTexImage2D(GL_TEXTURE_2D, 0, IntFormat, TexWidth, TexHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+}
+
+
+
+static void
+ParseArgs(int argc, char *argv[])
+{
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-nodraw") == 0)
+ DrawQuad = GL_FALSE;
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ GLint mode = GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH;
+ glutInit(&argc, argv);
+
+ ParseArgs(argc, argv);
+
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(WinWidth, WinHeight);
+ glutInitDisplayMode(mode);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Draw);
+
+ printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
+ Init();
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/tex1d.c b/tests/mesa/tests/tex1d.c
new file mode 100644
index 00000000..1fab849d
--- /dev/null
+++ b/tests/mesa/tests/tex1d.c
@@ -0,0 +1,139 @@
+
+/* Exercise 1D textures
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "GL/glut.h"
+
+static GLuint Window = 0;
+static GLuint TexObj[2];
+static GLfloat Angle = 0.0f;
+
+
+static void draw( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glColor3f( 1.0, 1.0, 1.0 );
+
+ /* draw first polygon */
+ glPushMatrix();
+ glTranslatef( -1.0, 0.0, 0.0 );
+ glRotatef( Angle, 0.0, 0.0, 1.0 );
+ glBindTexture( GL_TEXTURE_1D, TexObj[0] );
+ glBegin( GL_POLYGON );
+ glTexCoord1f( 0.0 ); glVertex2f( -1.0, -1.0 );
+ glTexCoord1f( 1.0 ); glVertex2f( 1.0, -1.0 );
+ glTexCoord1f( 1.0 ); glVertex2f( 1.0, 1.0 );
+ glTexCoord1f( 0.0 ); glVertex2f( -1.0, 1.0 );
+ glEnd();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+
+static void idle( void )
+{
+ Angle += 2.0;
+ glutPostRedisplay();
+}
+
+
+
+/* change view Angle, exit upon ESC */
+static void key(unsigned char k, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (k) {
+ case 27:
+ exit(0);
+ }
+}
+
+
+
+/* new window size or exposure */
+static void reshape( int width, int height )
+{
+ glViewport(0, 0, (GLint)width, (GLint)height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ /* glOrtho( -3.0, 3.0, -3.0, 3.0, -10.0, 10.0 );*/
+ glFrustum( -2.0, 2.0, -2.0, 2.0, 6.0, 20.0 );
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -8.0 );
+}
+
+
+static void init( void )
+{
+ GLubyte tex[256][3];
+ GLint i;
+
+
+ glDisable( GL_DITHER );
+
+ /* Setup texturing */
+ glEnable( GL_TEXTURE_1D );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
+
+
+ /* generate texture object IDs */
+ glGenTextures( 2, TexObj );
+
+ /* setup first texture object */
+ glBindTexture( GL_TEXTURE_1D, TexObj[0] );
+
+
+ for (i = 0; i < 256; i++) {
+ GLfloat f;
+
+ /* map 0..255 to -PI .. PI */
+ f = ((i / 255.0) - .5) * (3.141592 * 2);
+
+ f = sin(f);
+
+ /* map -1..1 to 0..255 */
+ tex[i][0] = (f+1.0)/2.0 * 255.0;
+ tex[i][1] = 0;
+ tex[i][2] = 0;
+ }
+
+ glTexImage1D( GL_TEXTURE_1D, 0, 3, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, tex );
+ glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+}
+
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(300, 300);
+ glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
+
+ Window = glutCreateWindow("Texture Objects");
+ if (!Window) {
+ exit(1);
+ }
+
+ init();
+
+ glutReshapeFunc( reshape );
+ glutKeyboardFunc( key );
+/* glutIdleFunc( idle ); */
+ glutDisplayFunc( draw );
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/texcmp.c b/tests/mesa/tests/texcmp.c
new file mode 100644
index 00000000..6e822fb6
--- /dev/null
+++ b/tests/mesa/tests/texcmp.c
@@ -0,0 +1,414 @@
+/*
+ * Compressed texture demo. Written by Daniel Borca.
+ * This program is in the public domain.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#define GL_GLEXT_PROTOTYPES 1
+#include <GL/glut.h>
+
+#include "readtex.c" /* I know, this is a hack. */
+#define TEXTURE_FILE "../images/tree2.rgba"
+
+
+static float Rot = 0.0;
+static GLboolean Anim = 1;
+
+typedef struct {
+ GLubyte *data;
+ GLuint size;
+ GLenum format;
+ GLuint w, h;
+
+ GLenum TC;
+
+ GLubyte *cData;
+ GLuint cSize;
+ GLenum cFormat;
+} TEXTURE;
+
+static TEXTURE *Tx, t1, t2, t3;
+static GLboolean fxt1, dxtc, s3tc;
+
+
+static const char *TextureName (GLenum TC)
+{
+ switch (TC) {
+ case GL_RGB:
+ return "RGB";
+ case GL_RGBA:
+ return "RGBA";
+ case GL_COMPRESSED_RGB:
+ return "COMPRESSED_RGB";
+ case GL_COMPRESSED_RGBA:
+ return "COMPRESSED_RGBA";
+ case GL_COMPRESSED_RGB_FXT1_3DFX:
+ return "GL_COMPRESSED_RGB_FXT1_3DFX";
+ case GL_COMPRESSED_RGBA_FXT1_3DFX:
+ return "GL_COMPRESSED_RGBA_FXT1_3DFX";
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT";
+ case GL_RGB_S3TC:
+ return "GL_RGB_S3TC";
+ case GL_RGB4_S3TC:
+ return "GL_RGB4_S3TC";
+ case GL_RGBA_S3TC:
+ return "GL_RGBA_S3TC";
+ case GL_RGBA4_S3TC:
+ return "GL_RGBA4_S3TC";
+ case 0:
+ return "Invalid format";
+ default:
+ return "Unknown format";
+ }
+}
+
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static void Idle( void )
+{
+ float t = glutGet(GLUT_ELAPSED_TIME) * 0.001; /* in seconds */
+ Rot = t * 360 / 4; /* 1 rotation per 4 seconds */
+ glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+ /* draw background gradient */
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_POLYGON);
+ glColor3f(1.0, 0.0, 0.2); glVertex2f(-1.5, -1.0);
+ glColor3f(1.0, 0.0, 0.2); glVertex2f( 1.5, -1.0);
+ glColor3f(0.0, 0.0, 1.0); glVertex2f( 1.5, 1.0);
+ glColor3f(0.0, 0.0, 1.0); glVertex2f(-1.5, 1.0);
+ glEnd();
+
+ glPushMatrix();
+ glRotatef(Rot, 0, 0, 1);
+
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 1); glVertex2f(-1, -0.5);
+ glTexCoord2f(1, 1); glVertex2f( 1, -0.5);
+ glTexCoord2f(1, 0); glVertex2f( 1, 0.5);
+ glTexCoord2f(0, 0); glVertex2f(-1, 0.5);
+ glEnd();
+
+ glPopMatrix();
+
+ /* info */
+ glColor4f(1, 1, 1, 1);
+
+ glRasterPos3f(-1.2, -0.7, 0);
+ PrintString("Selected: ");
+ PrintString(TextureName(Tx->TC));
+ if (Tx->cData) {
+ char tmp[64];
+ glRasterPos3f(-1.2, -0.8, 0);
+ PrintString("Internal: ");
+ PrintString(TextureName(Tx->cFormat));
+ glRasterPos3f(-1.2, -0.9, 0);
+ PrintString("Size : ");
+ sprintf(tmp, "%d (%d%% of %d)", Tx->cSize, Tx->cSize * 100 / Tx->size, Tx->size);
+ PrintString(tmp);
+ }
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( -1.5, 1.5, -1.0, 1.0, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+static void ReInit( GLenum TC, TEXTURE *Tx )
+{
+ GLint rv;
+
+ if ((Tx->TC == TC) && (Tx->cData != NULL)) {
+ glCompressedTexImage2DARB(GL_TEXTURE_2D, /* target */
+ 0, /* level */
+ Tx->cFormat, /* real format */
+ Tx->w, /* original width */
+ Tx->h, /* original height */
+ 0, /* border */
+ Tx->cSize, /* compressed size*/
+ Tx->cData); /* compressed data*/
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, /* target */
+ 0, /* level */
+ TC, /* internal format */
+ Tx->w, Tx->h, /* width, height */
+ 0, /* border */
+ Tx->format, /* texture format */
+ GL_UNSIGNED_BYTE, /* texture type */
+ Tx->data); /* the texture */
+
+ /* okay, now cache the compressed texture */
+ Tx->TC = TC;
+ if (Tx->cData != NULL) {
+ free(Tx->cData);
+ Tx->cData = NULL;
+ }
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, &rv);
+ if (rv) {
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint *)&Tx->cFormat);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, (GLint *)&Tx->cSize);
+ if ((Tx->cData = malloc(Tx->cSize)) != NULL) {
+ glGetCompressedTexImageARB(GL_TEXTURE_2D, 0, Tx->cData);
+ }
+ }
+ }
+}
+
+
+static void Init( void )
+{
+ /* HEIGHT * WIDTH + 1 (for trailing '\0') */
+ static char pattern[8 * 32 + 1] = {"\
+ \
+ MMM EEEE SSS AAA \
+ M M M E S S A A \
+ M M M EEEE SS A A \
+ M M M E SS AAAAA \
+ M M E S S A A \
+ M M EEEE SSS A A \
+ "
+ };
+
+ GLuint i, j;
+
+ GLubyte (*texture1)[8 * 32][4];
+ GLubyte (*texture2)[256][256][4];
+
+ t1.w = 32;
+ t1.h = 8;
+ t1.size = t1.w * t1.h * 4;
+ t1.data = malloc(t1.size);
+ t1.format = GL_RGBA;
+ t1.TC = GL_RGBA;
+
+ texture1 = (GLubyte (*)[8 * 32][4])t1.data;
+ for (i = 0; i < sizeof(pattern) - 1; i++) {
+ switch (pattern[i]) {
+ default:
+ case ' ':
+ (*texture1)[i][0] = 255;
+ (*texture1)[i][1] = 255;
+ (*texture1)[i][2] = 255;
+ (*texture1)[i][3] = 64;
+ break;
+ case 'M':
+ (*texture1)[i][0] = 255;
+ (*texture1)[i][1] = 0;
+ (*texture1)[i][2] = 0;
+ (*texture1)[i][3] = 255;
+ break;
+ case 'E':
+ (*texture1)[i][0] = 0;
+ (*texture1)[i][1] = 255;
+ (*texture1)[i][2] = 0;
+ (*texture1)[i][3] = 255;
+ break;
+ case 'S':
+ (*texture1)[i][0] = 0;
+ (*texture1)[i][1] = 0;
+ (*texture1)[i][2] = 255;
+ (*texture1)[i][3] = 255;
+ break;
+ case 'A':
+ (*texture1)[i][0] = 255;
+ (*texture1)[i][1] = 255;
+ (*texture1)[i][2] = 0;
+ (*texture1)[i][3] = 255;
+ break;
+ }
+ }
+
+ t2.w = 256;
+ t2.h = 256;
+ t2.size = t2.w * t2.h * 4;
+ t2.data = malloc(t2.size);
+ t2.format = GL_RGBA;
+ t2.TC = GL_RGBA;
+
+ texture2 = (GLubyte (*)[256][256][4])t2.data;
+ for (j = 0; j < t2.h; j++) {
+ for (i = 0; i < t2.w; i++) {
+ (*texture2)[j][i][0] = sqrt(i * j * 255 * 255 / (t2.w * t2.h));
+ (*texture2)[j][i][1] = 0;
+ (*texture2)[j][i][2] = 0;
+ (*texture2)[j][i][3] = 255;
+ }
+ }
+
+ t3.data = LoadRGBImage(TEXTURE_FILE, (GLint *)&t3.w, (GLint *)&t3.h, &t3.format);
+ t3.size = t3.w * t3.h * ((t3.format == GL_RGB) ? 3 : 4);
+ t3.TC = GL_RGBA;
+
+ ReInit(GL_RGBA, Tx = &t1);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ case ' ':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc( Idle );
+ else
+ glutIdleFunc( NULL );
+ break;
+ case 't':
+ if (Tx == &t1) {
+ Tx = &t2;
+ } else if (Tx == &t2) {
+ Tx = &t3;
+ } else {
+ Tx = &t1;
+ }
+ ReInit(Tx->TC, Tx);
+ break;
+ case '9':
+ ReInit(GL_RGB, Tx);
+ break;
+ case '0':
+ ReInit(GL_RGBA, Tx);
+ break;
+ case '1':
+ ReInit(GL_COMPRESSED_RGB, Tx);
+ break;
+ case '2':
+ ReInit(GL_COMPRESSED_RGBA, Tx);
+ break;
+ case '3':
+ if (fxt1) ReInit(GL_COMPRESSED_RGB_FXT1_3DFX, Tx);
+ break;
+ case '4':
+ if (fxt1) ReInit(GL_COMPRESSED_RGBA_FXT1_3DFX, Tx);
+ break;
+ case '5':
+ if (dxtc) ReInit(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, Tx);
+ break;
+ case '6':
+ if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, Tx);
+ break;
+ case '7':
+ if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, Tx);
+ break;
+ case '8':
+ if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, Tx);
+ break;
+ case 'a':
+ if (s3tc) ReInit(GL_RGB_S3TC, Tx);
+ break;
+ case 's':
+ if (s3tc) ReInit(GL_RGB4_S3TC, Tx);
+ break;
+ case 'd':
+ if (s3tc) ReInit(GL_RGBA_S3TC, Tx);
+ break;
+ case 'f':
+ if (s3tc) ReInit(GL_RGBA4_S3TC, Tx);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+int main( int argc, char *argv[] )
+{
+ float gl_version;
+ GLint num_formats;
+ GLint i;
+ GLint formats[64];
+
+
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 400, 300 );
+
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+
+ if (glutCreateWindow(argv[0]) <= 0) {
+ printf("Couldn't create window\n");
+ exit(0);
+ }
+
+ gl_version = atof( (const char *) glGetString( GL_VERSION ) );
+ if ( (gl_version < 1.3)
+ && !glutExtensionSupported("GL_ARB_texture_compression") ) {
+ printf("Sorry, GL_ARB_texture_compression not supported\n");
+ exit(0);
+ }
+ if (glutExtensionSupported("GL_3DFX_texture_compression_FXT1")) {
+ fxt1 = GL_TRUE;
+ }
+ if (glutExtensionSupported("GL_EXT_texture_compression_s3tc")) {
+ dxtc = GL_TRUE;
+ }
+ if (glutExtensionSupported("GL_S3_s3tc")) {
+ s3tc = GL_TRUE;
+ }
+
+ glGetIntegerv( GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, & num_formats );
+
+ (void) memset( formats, 0, sizeof( formats ) );
+ glGetIntegerv( GL_COMPRESSED_TEXTURE_FORMATS_ARB, formats );
+
+ printf( "The following texture formats are supported:\n" );
+ for ( i = 0 ; i < num_formats ; i++ ) {
+ printf( "\t%s\n", TextureName( formats[i] ) );
+ }
+
+ Init();
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc( Idle );
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/texcompress2.c b/tests/mesa/tests/texcompress2.c
new file mode 100644
index 00000000..e2eed756
--- /dev/null
+++ b/tests/mesa/tests/texcompress2.c
@@ -0,0 +1,273 @@
+/*
+ * Test texture compression.
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <assert.h>
+#include <stdio.h>
+#include <GL/glut.h>
+#include <GL/glx.h>
+#include "readtex.c"
+
+#define IMAGE_FILE "../images/arch.rgb"
+
+static int ImgWidth, ImgHeight;
+static GLenum ImgFormat;
+static GLenum CompFormat;
+static GLfloat EyeDist = 5.0;
+static GLfloat Rot = 0.0;
+const GLenum Target = GL_TEXTURE_2D;
+
+
+static void
+CheckError(int line)
+{
+ GLenum err = glGetError();
+ if (err) {
+ printf("GL Error %d at line %d\n", (int) err, line);
+ }
+}
+
+
+static const char *
+LookupFormat(GLenum format)
+{
+ switch (format) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
+ default:
+ return "other";
+ }
+}
+
+
+static void
+TestSubTex(void)
+{
+ GLboolean all = 0*GL_TRUE;
+ GLubyte *buffer;
+ GLint size, fmt;
+ int i;
+
+ glGetTexLevelParameteriv(Target, 0,
+ GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &size);
+ glGetTexLevelParameteriv(Target, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt);
+
+ buffer = (GLubyte *) malloc(size);
+ glGetCompressedTexImageARB(Target, 0, buffer);
+
+ printf("Testing sub-texture replacement\n");
+ if (all)
+ glCompressedTexImage2DARB(Target, 0,
+ fmt, ImgWidth, ImgHeight, 0,
+ size, buffer);
+ else {
+ /* bottom half */
+ glCompressedTexSubImage2DARB(Target, 0,
+ 0, 0, /* pos */
+ ImgWidth, ImgHeight / 2,
+ fmt, size/2, buffer);
+ /* top half */
+ glCompressedTexSubImage2DARB(Target, 0,
+ 0, ImgHeight / 2, /* pos */
+ ImgWidth, ImgHeight / 2,
+ fmt, size/2, buffer + size / 2);
+ }
+
+ free(buffer);
+}
+
+
+static void
+LoadCompressedImage(const char *file)
+{
+ const GLenum filter = GL_LINEAR;
+ GLubyte *image;
+ GLint p;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ /*
+ * Load image and scale if needed.
+ */
+ image = LoadRGBImage( file, &ImgWidth, &ImgHeight, &ImgFormat );
+ if (!image) {
+ printf("Couldn't read %s\n", IMAGE_FILE);
+ exit(0);
+ }
+ printf("Image is %d x %d\n", ImgWidth, ImgHeight);
+
+ /* power of two */
+ assert(ImgWidth == 128 || ImgWidth == 256 || ImgWidth == 512);
+ assert(ImgWidth == 128 || ImgHeight == 256 || ImgHeight == 512);
+
+ if (ImgFormat == GL_RGB)
+ CompFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ else
+ CompFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+
+ if (ImgFormat == GL_RGBA) {
+ int i, numAlpha = 0;
+ for (i = 0; i < ImgWidth * ImgHeight; i++) {
+ if (image[i*4+3] != 0 && image[i*4+3] != 0xff) {
+ numAlpha++;
+ }
+ if (image[i*4+3] == 0)
+ image[i*4+3] = 4 * i / ImgWidth;
+ }
+ printf("Num Alpha !=0,255: %d\n", numAlpha);
+ }
+
+ CompFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+
+
+ /*
+ * Give image to OpenGL and have it compress it.
+ */
+ glTexImage2D(Target, 0, CompFormat, ImgWidth, ImgHeight, 0,
+ ImgFormat, GL_UNSIGNED_BYTE, image);
+ CheckError(__LINE__);
+
+ free(image);
+
+ glGetTexLevelParameteriv(Target, 0, GL_TEXTURE_INTERNAL_FORMAT, &p);
+ printf("Compressed Internal Format: %s (0x%x)\n", LookupFormat(p), p);
+ assert(p == CompFormat);
+
+ printf("Original size: %d bytes\n", ImgWidth * ImgHeight * 3);
+ glGetTexLevelParameteriv(Target, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &p);
+ printf("Compressed size: %d bytes\n", p);
+
+ glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, filter);
+
+ TestSubTex();
+
+}
+
+
+static void
+Init(const char *file)
+{
+ GLint numFormats, formats[100];
+ GLint p;
+
+ if (!glutExtensionSupported("GL_ARB_texture_compression")) {
+ printf("Sorry, GL_ARB_texture_compression is required.\n");
+ exit(1);
+ }
+ if (!glutExtensionSupported("GL_EXT_texture_compression_s3tc")) {
+ printf("Sorry, GL_EXT_texture_compression_s3tc is required.\n");
+ exit(1);
+ }
+
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, &numFormats);
+ glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS_ARB, formats);
+ printf("%d supported compression formats: ", numFormats);
+ for (p = 0; p < numFormats; p++)
+ printf("0x%x ", formats[p]);
+ printf("\n");
+
+ LoadCompressedImage(file);
+
+ glEnable(GL_TEXTURE_2D);
+
+ if (ImgFormat == GL_RGBA) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ }
+}
+
+
+static void
+Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum(-1, 1, -1, 1, 4, 100);
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+static void
+Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'd':
+ EyeDist -= 1.0;
+ if (EyeDist < 4.0)
+ EyeDist = 4.0;
+ break;
+ case 'D':
+ EyeDist += 1.0;
+ break;
+ case 'z':
+ Rot += 5.0;
+ break;
+ case 'Z':
+ Rot -= 5.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Draw( void )
+{
+ glClearColor(0.3, 0.3, .8, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glPushMatrix();
+ glTranslatef(0, 0, -(EyeDist+0.01));
+ glRotatef(Rot, 0, 0, 1);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-1, -1);
+ glTexCoord2f(1, 0); glVertex2f( 1, -1);
+ glTexCoord2f(1, 1); glVertex2f( 1, 1);
+ glTexCoord2f(0, 1); glVertex2f(-1, 1);
+ glEnd();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+int
+main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowSize( 600, 600 );
+
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE);
+
+ glutCreateWindow(argv[0]);
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Draw );
+
+ if (argc > 1)
+ Init(argv[1]);
+ else
+ Init(IMAGE_FILE);
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/texfilt.c b/tests/mesa/tests/texfilt.c
new file mode 100644
index 00000000..6ee4bc4e
--- /dev/null
+++ b/tests/mesa/tests/texfilt.c
@@ -0,0 +1,398 @@
+/*
+ * (C) Copyright IBM Corporation 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glut.h>
+
+const GLenum filter_modes[] = {
+ GL_NEAREST,
+ GL_LINEAR,
+ GL_NEAREST_MIPMAP_NEAREST,
+ GL_NEAREST_MIPMAP_LINEAR,
+ GL_LINEAR_MIPMAP_NEAREST,
+ GL_LINEAR_MIPMAP_LINEAR,
+};
+
+static GLenum min_filter = GL_LINEAR_MIPMAP_LINEAR;
+static GLenum mag_filter = GL_LINEAR;
+
+static unsigned segments = 64;
+static GLfloat * position_data = NULL;
+static GLfloat * texcoord_data = NULL;
+static GLfloat max_anisotropy = 0.0;
+static GLfloat anisotropy = 1.0;
+
+static void generate_tunnel( unsigned num_segs, GLfloat ** pos_data,
+ GLfloat ** tex_data );
+static void generate_textures( unsigned mode );
+
+#define min(a,b) ( (a) < (b) ) ? (a) : (b)
+#define max(a,b) ( (a) > (b) ) ? (a) : (b)
+
+
+static void Display( void )
+{
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter );
+
+ if ( max_anisotropy > 0.0 ) {
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+ anisotropy );
+ }
+
+ glClear( GL_COLOR_BUFFER_BIT );
+ glLoadIdentity();
+ glTranslatef( 0.0f, 0.0f, -19.0f );
+
+ glVertexPointer( 4, GL_FLOAT, 0, position_data );
+ glTexCoordPointer( 2, GL_FLOAT, 0, texcoord_data );
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ glDrawArrays( GL_QUADS, 0, 4 * segments );
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(45.0f, (GLfloat)(width)/(GLfloat)(height), 0.1f, 100.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ GLfloat new_anisotropy = anisotropy;
+
+ (void) x;
+ (void) y;
+
+
+ switch( key ) {
+ case 'a': {
+ new_anisotropy = anisotropy - 1.0;
+ break;
+ }
+
+ case 'A': {
+ new_anisotropy = anisotropy + 1.0;
+ break;
+ }
+
+ case 's': {
+ segments--;
+ if ( segments < 3 ) {
+ segments = 3;
+ }
+ generate_tunnel( segments, & position_data, & texcoord_data );
+ break;
+ }
+
+ case 'S': {
+ segments++;
+ if ( segments > 128 ) {
+ segments = 128;
+ }
+ generate_tunnel( segments, & position_data, & texcoord_data );
+ break;
+ }
+ case 'q':
+ case 'Q':
+ case 27:
+ exit(0);
+ break;
+ }
+
+ new_anisotropy = max( new_anisotropy, 1.0 );
+ new_anisotropy = min( new_anisotropy, max_anisotropy );
+ if ( new_anisotropy != anisotropy ) {
+ anisotropy = new_anisotropy;
+ printf( "Texture anisotropy: %f%s\n", anisotropy,
+ (anisotropy == 1.0) ? " (disabled)" : "" );
+ }
+
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ (void) key;
+ glutPostRedisplay();
+}
+
+
+static void menu_handler( int selection )
+{
+ switch( selection >> 3 ) {
+ case 0:
+ glBindTexture( GL_TEXTURE_2D, selection );
+ break;
+
+ case 1:
+ min_filter = filter_modes[ selection & 7 ];
+ break;
+
+ case 2:
+ mag_filter = filter_modes[ selection & 7 ];
+ break;
+ }
+
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_TEXTURE_2D);
+ glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
+ glShadeModel(GL_SMOOTH);
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+ generate_tunnel( segments, & position_data, & texcoord_data );
+
+ glBindTexture( GL_TEXTURE_2D, 1 );
+ generate_textures(1);
+
+ glBindTexture( GL_TEXTURE_2D, 2 );
+ generate_textures(2);
+
+ glBindTexture( GL_TEXTURE_2D, 3 );
+ generate_textures(3);
+
+ if ( glutExtensionSupported( "GL_EXT_texture_filter_anisotropic" ) ) {
+ glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, & max_anisotropy );
+ }
+
+ printf("Maximum texture anisotropy: %f\n", max_anisotropy );
+
+ /* Create the menus. */
+
+ glutCreateMenu( menu_handler );
+ glutAddMenuEntry( "Min filter: GL_NEAREST", 8 + 0 );
+ glutAddMenuEntry( "Min filter: GL_LINEAR", 8 + 1 );
+ glutAddMenuEntry( "Min filter: GL_NEAREST_MIMMAP_NEAREST", 8 + 2 );
+ glutAddMenuEntry( "Min filter: GL_NEAREST_MIMMAP_LINEAR", 8 + 3 );
+ glutAddMenuEntry( "Min filter: GL_LINEAR_MIMMAP_NEAREST", 8 + 4 );
+ glutAddMenuEntry( "Min filter: GL_LINEAR_MIMMAP_LINEAR", 8 + 5 );
+ glutAddMenuEntry( "Mag filter: GL_NEAREST", 16 + 0 );
+ glutAddMenuEntry( "Mag filter: GL_LINEAR", 16 + 1 );
+ glutAddMenuEntry( "Texture: regular mipmaps", 1 );
+ glutAddMenuEntry( "Texture: blended mipmaps", 2 );
+ glutAddMenuEntry( "Texture: color mipmaps", 3 );
+ glutAttachMenu( GLUT_RIGHT_BUTTON );
+}
+
+
+static void generate_tunnel( unsigned num_segs, GLfloat ** pos_data,
+ GLfloat ** tex_data )
+{
+ const GLfloat far = 20.0f;
+ const GLfloat near = -90.0f;
+ const GLfloat far_tex = 30.0f;
+ const GLfloat near_tex = 0.0f;
+ const GLfloat angle_step = (2 * M_PI) / num_segs;
+ const GLfloat tex_coord_step = 2.0 / num_segs;
+ GLfloat angle = 0.0f;
+ GLfloat tex_coord = 0.0f;
+ unsigned i;
+ GLfloat * position;
+ GLfloat * texture;
+
+
+ position = realloc( *pos_data, sizeof( GLfloat ) * num_segs * 4 * 4 );
+ texture = realloc( *tex_data, sizeof( GLfloat ) * num_segs * 4 * 2 );
+
+ *pos_data = position;
+ *tex_data = texture;
+
+ for ( i = 0 ; i < num_segs ; i++ ) {
+ position[0] = 2.5 * sinf( angle );
+ position[1] = 2.5 * cosf( angle );
+ position[2] = (i & 1) ? far : near;
+ position[3] = 1.0f;
+
+ position[4] = position[0];
+ position[5] = position[1];
+ position[6] = (i & 1) ? near : far;
+ position[7] = 1.0f;
+
+ position += 8;
+
+ texture[0] = tex_coord;
+ texture[1] = (i & 1) ? far_tex : near_tex;
+ texture += 2;
+
+ texture[0] = tex_coord;
+ texture[1] = (i & 1) ? near_tex : far_tex;
+ texture += 2;
+
+ angle += angle_step;
+ tex_coord += tex_coord_step;
+
+ position[0] = 2.5 * sinf( angle );
+ position[1] = 2.5 * cosf( angle );
+ position[2] = (i & 1) ? near : far;
+ position[3] = 1.0f;
+
+ position[4] = position[0];
+ position[5] = position[1];
+ position[6] = (i & 1) ? far : near;
+ position[7] = 1.0f;
+
+ position += 8;
+
+ texture[0] = tex_coord;
+ texture[1] = (i & 1) ? near_tex : far_tex;
+ texture += 2;
+
+ texture[0] = tex_coord;
+ texture[1] = (i & 1) ? far_tex : near_tex;
+ texture += 2;
+ }
+}
+
+
+static void generate_textures( unsigned mode )
+{
+#define LEVEL_COLORS 6
+ const GLfloat colors[LEVEL_COLORS][3] = {
+ { 1.0, 0.0, 0.0 }, /* 32 x 32 */
+ { 0.0, 1.0, 0.0 }, /* 16 x 16 */
+ { 0.0, 0.0, 1.0 }, /* 8 x 8 */
+ { 1.0, 0.0, 1.0 }, /* 4 x 4 */
+ { 1.0, 1.0, 1.0 }, /* 2 x 2 */
+ { 1.0, 1.0, 0.0 } /* 1 x 1 */
+ };
+ const unsigned checkers_per_level = 2;
+ GLfloat * tex;
+ unsigned level;
+ unsigned size;
+ GLint max_size;
+
+
+ glGetIntegerv( GL_MAX_TEXTURE_SIZE, & max_size );
+ if ( max_size > 512 ) {
+ max_size = 512;
+ }
+
+ tex = malloc( sizeof( GLfloat ) * 3 * max_size * max_size );
+
+ level = 0;
+ for ( size = max_size ; size > 0 ; size >>= 1 ) {
+ unsigned divisor = size / checkers_per_level;
+ unsigned i;
+ unsigned j;
+ GLfloat checkers[2][3];
+
+
+ if ((level == 0) || (mode == 1)) {
+ checkers[0][0] = 1.0;
+ checkers[0][1] = 1.0;
+ checkers[0][2] = 1.0;
+ checkers[1][0] = 0.0;
+ checkers[1][1] = 0.0;
+ checkers[1][2] = 0.0;
+ }
+ else if (mode == 2) {
+ checkers[0][0] = colors[level % LEVEL_COLORS][0];
+ checkers[0][1] = colors[level % LEVEL_COLORS][1];
+ checkers[0][2] = colors[level % LEVEL_COLORS][2];
+ checkers[1][0] = colors[level % LEVEL_COLORS][0] * 0.5;
+ checkers[1][1] = colors[level % LEVEL_COLORS][1] * 0.5;
+ checkers[1][2] = colors[level % LEVEL_COLORS][2] * 0.5;
+ }
+ else {
+ checkers[0][0] = colors[level % LEVEL_COLORS][0];
+ checkers[0][1] = colors[level % LEVEL_COLORS][1];
+ checkers[0][2] = colors[level % LEVEL_COLORS][2];
+ checkers[1][0] = colors[level % LEVEL_COLORS][0];
+ checkers[1][1] = colors[level % LEVEL_COLORS][1];
+ checkers[1][2] = colors[level % LEVEL_COLORS][2];
+ }
+
+ if ( divisor == 0 ) {
+ divisor = 1;
+
+ checkers[0][0] = (checkers[0][0] + checkers[1][0]) / 2;
+ checkers[0][1] = (checkers[0][0] + checkers[1][0]) / 2;
+ checkers[0][2] = (checkers[0][0] + checkers[1][0]) / 2;
+ checkers[1][0] = checkers[0][0];
+ checkers[1][1] = checkers[0][1];
+ checkers[1][2] = checkers[0][2];
+ }
+
+
+ for ( i = 0 ; i < size ; i++ ) {
+ for ( j = 0 ; j < size ; j++ ) {
+ const unsigned idx = ((i ^ j) / divisor) & 1;
+
+ tex[ ((i * size) + j) * 3 + 0] = checkers[ idx ][0];
+ tex[ ((i * size) + j) * 3 + 1] = checkers[ idx ][1];
+ tex[ ((i * size) + j) * 3 + 2] = checkers[ idx ][2];
+ }
+ }
+
+ glTexImage2D( GL_TEXTURE_2D, level, GL_RGB, size, size, 0,
+ GL_RGB, GL_FLOAT, tex );
+ level++;
+ }
+
+ free( tex );
+}
+
+
+int main( int argc, char ** argv )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 800, 600 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow( "Texture Filter Test" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+
+ Init();
+
+ printf("\nUse the right-button menu to select the texture and filter mode.\n");
+ printf("Use 'A' and 'a' to increase and decrease the aniotropy.\n");
+ printf("Use 'S' and 's' to increase and decrease the number of cylinder segments.\n");
+ printf("Use 'q' to exit.\n\n");
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/texgenmix.c b/tests/mesa/tests/texgenmix.c
new file mode 100644
index 00000000..be8f6775
--- /dev/null
+++ b/tests/mesa/tests/texgenmix.c
@@ -0,0 +1,640 @@
+
+/*
+ * Demonstrates mixed texgen/non-texgen texture coordinates.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <GL/glut.h>
+
+#undef max
+#undef min
+#define max( a, b ) ((a) >= (b) ? (a) : (b))
+#define min( a, b ) ((a) <= (b) ? (a) : (b))
+
+GLfloat labelColor0[4] = { 1.0, 1.0, 1.0, 1.0 };
+GLfloat labelColor1[4] = { 1.0, 1.0, 0.4, 1.0 };
+GLfloat *labelInfoColor = labelColor0;
+
+GLboolean doubleBuffered = GL_TRUE;
+GLboolean drawTextured = GL_TRUE;
+
+int textureWidth = 64;
+int textureHeight = 64;
+
+int winWidth = 580, winHeight = 720;
+
+const GLfloat texmat_swap_rq[16] = { 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0, 0.0};
+
+const GLfloat nullPlane[4] = { 0.0, 0.0, 0.0, 0.0 };
+const GLfloat ObjPlaneS1[4] = { 1.0, 0.0, 1.0, 0.0 };
+const GLfloat ObjPlaneS2[4] = { 0.5, 0.0, 0.0, 0.0 };
+const GLfloat ObjPlaneS3[4] = { 1.0, 0.0, 0.0, 0.0 };
+const GLfloat ObjPlaneT[4] = { 0.0, 1.0, 0.0, 0.0 };
+const GLfloat ObjPlaneT2[4] = { 0.0, 0.5, 0.0, 0.0 };
+const GLfloat ObjPlaneT3[4] = { 0.0, 1.0, 0.0, 0.0 };
+const GLfloat ObjPlaneR[4] = { 0.0, 0.0, 1.0, 0.0 };
+const GLfloat ObjPlaneQ[4] = { 0.0, 0.0, 0.0, 0.5 };
+
+
+static void checkErrors( void )
+{
+ GLenum error;
+
+ while ( (error = glGetError()) != GL_NO_ERROR ) {
+ fprintf( stderr, "Error: %s\n", (char *) gluErrorString( error ) );
+ }
+}
+
+static void drawString( const char *string, GLfloat x, GLfloat y,
+ const GLfloat color[4] )
+{
+ glColor4fv( color );
+ glRasterPos2f( x, y );
+
+ while ( *string ) {
+ glutBitmapCharacter( GLUT_BITMAP_TIMES_ROMAN_10, *string );
+ string++;
+ }
+}
+
+static void begin2D( int width, int height )
+{
+ glMatrixMode( GL_PROJECTION );
+
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho( 0, width, 0, height, -1, 1 );
+ glMatrixMode( GL_MODELVIEW );
+
+ glPushMatrix();
+ glLoadIdentity();
+}
+
+static void end2D( void )
+{
+ glMatrixMode( GL_PROJECTION );
+ glPopMatrix();
+ glMatrixMode( GL_MODELVIEW );
+ glPopMatrix();
+}
+
+static void initialize( void )
+{
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+
+ glOrtho( -1.5, 1.5, -1.5, 1.5, -1.5, 1.5 );
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glShadeModel( GL_FLAT );
+}
+
+/* ARGSUSED1 */
+static void keyboard( unsigned char c, int x, int y )
+{
+ switch ( c ) {
+ case 't':
+ drawTextured = !drawTextured;
+ break;
+ case 27: /* Escape key should force exit. */
+ exit(0);
+ break;
+ default:
+ break;
+ }
+ glutPostRedisplay();
+}
+
+/* ARGSUSED1 */
+static void special( int key, int x, int y )
+{
+ switch ( key ) {
+ case GLUT_KEY_DOWN:
+ break;
+ case GLUT_KEY_UP:
+ break;
+ case GLUT_KEY_LEFT:
+ break;
+ case GLUT_KEY_RIGHT:
+ break;
+ default:
+ break;
+ }
+ glutPostRedisplay();
+}
+
+static void
+reshape( int w, int h )
+{
+ winWidth = w;
+ winHeight = h;
+ /* No need to call glViewPort here since "draw" calls it! */
+}
+
+static void loadTexture( int width, int height )
+{
+ int alphaSize = 1;
+ int rgbSize = 3;
+ GLubyte *texImage, *p;
+ int elementsPerGroup, elementSize, groupSize, rowSize;
+ int i, j;
+
+
+ elementsPerGroup = alphaSize + rgbSize;
+ elementSize = sizeof(GLubyte);
+ groupSize = elementsPerGroup * elementSize;
+ rowSize = width * groupSize;
+
+ if ( (texImage = (GLubyte *) malloc( height * rowSize ) ) == NULL ) {
+ fprintf( stderr, "texture malloc failed\n" );
+ return;
+ }
+
+ for ( i = 0 ; i < height ; i++ )
+ {
+ p = texImage + i * rowSize;
+
+ for ( j = 0 ; j < width ; j++ )
+ {
+ if ( rgbSize > 0 )
+ {
+ /**
+ ** +-----+-----+
+ ** | | |
+ ** | R | G |
+ ** | | |
+ ** +-----+-----+
+ ** | | |
+ ** | Y | B |
+ ** | | |
+ ** +-----+-----+
+ **/
+ if ( i > height / 2 ) {
+ if ( j < width / 2 ) {
+ p[0] = 0xff;
+ p[1] = 0x00;
+ p[2] = 0x00;
+ } else {
+ p[0] = 0x00;
+ p[1] = 0xff;
+ p[2] = 0x00;
+ }
+ } else {
+ if ( j < width / 2 ) {
+ p[0] = 0xff;
+ p[1] = 0xff;
+ p[2] = 0x00;
+ } else {
+ p[0] = 0x00;
+ p[1] = 0x00;
+ p[2] = 0xff;
+ }
+ }
+ p += 3 * elementSize;
+ }
+
+ if ( alphaSize > 0 )
+ {
+ /**
+ ** +-----------+
+ ** | W |
+ ** | +-----+ |
+ ** | | | |
+ ** | | B | |
+ ** | | | |
+ ** | +-----+ |
+ ** | |
+ ** +-----------+
+ **/
+ int i2 = i - height / 2;
+ int j2 = j - width / 2;
+ int h8 = height / 8;
+ int w8 = width / 8;
+ if ( -h8 <= i2 && i2 <= h8 && -w8 <= j2 && j2 <= w8 ) {
+ p[0] = 0x00;
+ } else if ( -2 * h8 <= i2 && i2 <= 2 * h8 && -2 * w8 <= j2 && j2 <= 2 * w8 ) {
+ p[0] = 0x55;
+ } else if ( -3 * h8 <= i2 && i2 <= 3 * h8 && -3 * w8 <= j2 && j2 <= 3 * w8 ) {
+ p[0] = 0xaa;
+ } else {
+ p[0] = 0xff;
+ }
+ p += elementSize;
+ }
+ }
+ }
+
+ glTexImage2D( GL_TEXTURE_2D, 0,
+ GL_RGBA, width, height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texImage );
+
+ free( texImage );
+}
+
+
+static void drawSample( int x, int y, int w, int h,
+ int texgenenabled, int coordnr )
+{
+ char buf[255];
+
+ glViewport( x, y, w, h );
+ glScissor( x, y, w, h );
+
+ glClearColor( 0.1, 0.1, 0.1, 1.0 );
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ begin2D( w, h );
+ if (texgenenabled == 2) {
+ sprintf( buf, "TexCoord%df", coordnr);
+ drawString( buf, 10, h - 15, labelInfoColor );
+ sprintf( buf, "texgen enabled for %s coordinate(s)", coordnr == 2 ? "S" : "S/T");
+ drawString( buf, 10, 5, labelInfoColor );
+ }
+ else if (texgenenabled == 0) {
+ sprintf( buf, "TexCoord%df", coordnr);
+ drawString( buf, 10, h - 15, labelInfoColor );
+ drawString( "no texgen", 10, 5, labelInfoColor );
+ }
+ else if (texgenenabled == 1) {
+ drawString( "no TexCoord", 10, h - 15, labelInfoColor );
+ sprintf( buf, "texgen enabled for %s coordinate(s)",
+ coordnr == 2 ? "S/T" : (coordnr == 3 ? "S/T/R" : "S/T/R/Q"));
+ drawString( buf, 10, 5, labelInfoColor );
+ }
+
+ end2D();
+
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
+
+ loadTexture( textureWidth, textureHeight );
+
+ if ( drawTextured ) {
+ glEnable( GL_TEXTURE_2D );
+ }
+
+ glDisable( GL_TEXTURE_GEN_S );
+ glDisable( GL_TEXTURE_GEN_T );
+ glDisable( GL_TEXTURE_GEN_R );
+ glDisable( GL_TEXTURE_GEN_Q );
+
+ glMatrixMode( GL_TEXTURE );
+ glLoadIdentity();
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+
+ switch (coordnr) {
+ case 2:
+ switch (texgenenabled) {
+ case 0:
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0.0, 0.0 );
+ glVertex2f( -0.8, -0.8 );
+
+ glTexCoord2f( 1.0, 0.0 );
+ glVertex2f( 0.8, -0.8 );
+
+ glTexCoord2f( 1.0, 1.0 );
+ glVertex2f( 0.8, 0.8 );
+
+ glTexCoord2f( 0.0, 1.0 );
+ glVertex2f( -0.8, 0.8 );
+ glEnd();
+ break;
+ case 1:
+ glTranslatef( -0.8, -0.8, 0.0 );
+ glScalef( 1.6, 1.6, 1.0 );
+ glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, ObjPlaneS3);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, ObjPlaneT3);
+ glTexGenfv(GL_R, GL_OBJECT_PLANE, nullPlane);
+ glTexGenfv(GL_Q, GL_OBJECT_PLANE, nullPlane);
+
+ glEnable( GL_TEXTURE_GEN_S );
+ glEnable( GL_TEXTURE_GEN_T );
+
+ /* Issue a texcoord here to be sure Q isn't left over from a
+ * previous sample.
+ */
+ glTexCoord1f( 0.0 );
+ glBegin( GL_QUADS );
+ glVertex2f( 0.0, 0.0 );
+ glVertex2f( 1.0, 0.0 );
+ glVertex2f( 1.0, 1.0 );
+ glVertex2f( 0.0, 1.0 );
+ glEnd();
+ break;
+ case 2:
+ /* make sure that texgen T and non-texgen S coordinate are wrong */
+ glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, ObjPlaneS1);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, nullPlane);
+ glTexGenfv(GL_R, GL_OBJECT_PLANE, nullPlane);
+ glTexGenfv(GL_Q, GL_OBJECT_PLANE, nullPlane);
+
+ glEnable( GL_TEXTURE_GEN_S );
+
+ glBegin( GL_QUADS );
+ /* use z coordinate to get correct texgen values... */
+ glTexCoord2f( 0.0, 0.0 );
+ glVertex3f( -0.8, -0.8, 0.8 );
+
+ glTexCoord2f( 0.0, 0.0 );
+ glVertex3f( 0.8, -0.8, 0.2 );
+
+ glTexCoord2f( 0.0, 1.0 );
+ glVertex3f( 0.8, 0.8, 0.2 );
+
+ glTexCoord2f( 0.0, 1.0 );
+ glVertex3f( -0.8, 0.8, 0.8 );
+ glEnd();
+ break;
+ }
+ break;
+ case 3:
+ glMatrixMode( GL_TEXTURE );
+ glLoadMatrixf( texmat_swap_rq );
+ glMatrixMode( GL_MODELVIEW );
+ glTranslatef( -0.8, -0.8, 0.0 );
+ glScalef( 1.6, 1.6, 1.0 );
+ switch (texgenenabled) {
+ case 0:
+ glBegin( GL_QUADS );
+ glTexCoord3f( 0.0, 0.0, 0.5 );
+ glVertex2f( 0.0, 0.0 );
+
+ glTexCoord3f( 0.5, 0.0, 0.5 );
+ glVertex2f( 1.0, 0.0 );
+
+ glTexCoord3f( 0.5, 0.5, 0.5 );
+ glVertex2f( 1.0, 1.0 );
+
+ glTexCoord3f( 0.0, 0.5, 0.5 );
+ glVertex2f( 0.0, 1.0 );
+ glEnd();
+ break;
+ case 1:
+ glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, ObjPlaneS2);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, ObjPlaneT2);
+ glTexGenfv(GL_R, GL_OBJECT_PLANE, ObjPlaneR);
+ glTexGenfv(GL_Q, GL_OBJECT_PLANE, nullPlane);
+
+ glEnable( GL_TEXTURE_GEN_S );
+ glEnable( GL_TEXTURE_GEN_T );
+ glEnable( GL_TEXTURE_GEN_R );
+
+ glTexCoord1f( 0.0 ); /* to make sure Q is 1.0 */
+ glBegin( GL_QUADS );
+ glVertex3f( 0.0, 0.0, 0.5 );
+ glVertex3f( 1.0, 0.0, 0.5 );
+ glVertex3f( 1.0, 1.0, 0.5 );
+ glVertex3f( 0.0, 1.0, 0.5 );
+ glEnd();
+ break;
+ case 2:
+ /* make sure that texgen R/Q and non-texgen S/T coordinates are wrong */
+ glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, ObjPlaneS2);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, ObjPlaneT2);
+ glTexGenfv(GL_R, GL_OBJECT_PLANE, nullPlane);
+ glTexGenfv(GL_Q, GL_OBJECT_PLANE, nullPlane);
+
+ glEnable( GL_TEXTURE_GEN_S );
+ glEnable( GL_TEXTURE_GEN_T );
+
+ glBegin( GL_QUADS );
+ glTexCoord3f( 0.0, 0.0, 0.5 );
+ glVertex2f( 0.0, 0.0);
+
+ glTexCoord3f( 0.0, 0.0, 0.5 );
+ glVertex2f( 1.0, 0.0);
+
+ glTexCoord3f( 0.0, 0.0, 0.5 );
+ glVertex2f( 1.0, 1.0);
+
+ glTexCoord3f( 0.0, 0.0, 0.5 );
+ glVertex2f( 0.0, 1.0);
+ glEnd();
+ break;
+ }
+ break;
+ case 4:
+ switch (texgenenabled) {
+ case 0:
+ glBegin( GL_QUADS );
+ /* don't need r coordinate but still setting it I'm mean */
+ glTexCoord4f( 0.0, 0.0, 0.0, 0.5 );
+ glVertex2f( -0.8, -0.8 );
+
+ glTexCoord4f( 0.5, 0.0, 0.2, 0.5 );
+ glVertex2f( 0.8, -0.8 );
+
+ glTexCoord4f( 0.5, 0.5, 0.5, 0.5 );
+ glVertex2f( 0.8, 0.8 );
+
+ glTexCoord4f( 0.0, 0.5, 0.5, 0.5 );
+ glVertex2f( -0.8, 0.8 );
+ glEnd();
+ break;
+ case 1:
+ glTranslatef( -0.8, -0.8, 0.0 );
+ glScalef( 1.6, 1.6, 1.0 );
+ /* make sure that texgen R/Q and non-texgen S/T coordinates are wrong */
+ glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, ObjPlaneS2);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, ObjPlaneT2);
+ glTexGenfv(GL_R, GL_OBJECT_PLANE, ObjPlaneR);
+ glTexGenfv(GL_Q, GL_OBJECT_PLANE, ObjPlaneQ);
+
+ glEnable( GL_TEXTURE_GEN_S );
+ glEnable( GL_TEXTURE_GEN_T );
+ glEnable( GL_TEXTURE_GEN_R );
+ glEnable( GL_TEXTURE_GEN_Q );
+
+ glBegin( GL_QUADS );
+ glVertex2f( 0.0, 0.0 );
+ glVertex2f( 1.0, 0.0 );
+ glVertex2f( 1.0, 1.0 );
+ glVertex2f( 0.0, 1.0 );
+ glEnd();
+ break;
+ case 2:
+ glTranslatef( -0.8, -0.8, 0.0 );
+ glScalef( 1.6, 1.6, 1.0 );
+ /* make sure that texgen R/Q and non-texgen S/T coordinates are wrong */
+ glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, ObjPlaneS2);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, ObjPlaneT2);
+ glTexGenfv(GL_R, GL_OBJECT_PLANE, nullPlane);
+ glTexGenfv(GL_Q, GL_OBJECT_PLANE, nullPlane);
+
+ glEnable( GL_TEXTURE_GEN_S );
+ glEnable( GL_TEXTURE_GEN_T );
+
+ glBegin( GL_QUADS );
+ glTexCoord4f( 0.0, 0.0, 0.0, 0.5 );
+ glVertex2f( 0.0, 0.0 );
+
+ glTexCoord4f( 0.0, 0.0, 0.2, 0.5 );
+ glVertex2f( 1.0, 0.0 );
+
+ glTexCoord4f( 0.0, 0.0, 0.5, 0.5 );
+ glVertex2f( 1.0, 1.0 );
+
+ glTexCoord4f( 0.0, 0.0, 0.75, 0.5 );
+ glVertex2f( 0.0, 1.0 );
+ glEnd();
+ break;
+ }
+ break;
+ }
+
+ glPopMatrix();
+ glDisable( GL_TEXTURE_2D );
+
+}
+
+static void display( void )
+{
+ int numX = 3, numY = 3;
+ float xBase = (float) winWidth * 0.01;
+ float xOffset = (winWidth - xBase) / numX;
+ float xSize = max( xOffset - xBase, 1 );
+ float yBase = (float) winHeight * 0.01;
+ float yOffset = (winHeight - yBase) / numY;
+ float ySize = max( yOffset - yBase, 1 );
+ float x, y;
+ int i, j;
+
+ glViewport( 0, 0, winWidth, winHeight );
+ glDisable( GL_SCISSOR_TEST );
+ glClearColor( 0.0, 0.0, 0.0, 0.0 );
+ glClear( GL_COLOR_BUFFER_BIT );
+ glEnable( GL_SCISSOR_TEST );
+
+ x = xBase;
+ y = (winHeight - 1) - yOffset;
+
+ for ( i = 0 ; i < numY ; i++ )
+ {
+
+ labelInfoColor = labelColor1;
+
+
+ for ( j = 0 ; j < numX ; j++ ) {
+ drawSample( x, y, xSize, ySize, i, j+2 );
+ x += xOffset;
+ }
+
+ x = xBase;
+ y -= yOffset;
+ }
+
+ if ( doubleBuffered ) {
+ glutSwapBuffers();
+ } else {
+ glFlush();
+ }
+
+ checkErrors();
+}
+
+static void usage( char *name )
+{
+ fprintf( stderr, "usage: %s [ options ]\n", name );
+ fprintf( stderr, "\n" );
+ fprintf( stderr, "options:\n" );
+ fprintf( stderr, " -sb single buffered\n" );
+ fprintf( stderr, " -db double buffered\n" );
+ fprintf( stderr, " -info print OpenGL driver info\n" );
+}
+
+static void instructions( void )
+{
+ fprintf( stderr, "texgenmix - mixed texgen/non-texgen texture coordinate test\n" );
+ fprintf( stderr, "all quads should look the same!\n" );
+ fprintf( stderr, "\n" );
+ fprintf( stderr, " [t] - toggle texturing\n" );
+}
+
+int main( int argc, char *argv[] )
+{
+ GLboolean info = GL_FALSE;
+ int i;
+
+ glutInit( &argc, argv );
+
+ for ( i = 1 ; i < argc ; i++ ) {
+ if ( !strcmp( "-sb", argv[i] ) ) {
+ doubleBuffered = GL_FALSE;
+ } else if ( !strcmp( "-db", argv[i] ) ) {
+ doubleBuffered = GL_TRUE;
+ } else if ( !strcmp( "-info", argv[i] ) ) {
+ info = GL_TRUE;
+ } else {
+ usage( argv[0] );
+ exit( 1 );
+ }
+ }
+
+ if ( doubleBuffered ) {
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ } else {
+ glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE );
+ }
+
+ glutInitWindowSize( winWidth, winHeight );
+ glutInitWindowPosition( 0, 0 );
+ glutCreateWindow( "Mixed texgen/non-texgen texture coordinate test" );
+
+ initialize();
+ instructions();
+
+ if ( info ) {
+ printf( "\n" );
+ printf( "GL_RENDERER = %s\n", (char *) glGetString( GL_RENDERER ) );
+ printf( "GL_VERSION = %s\n", (char *) glGetString( GL_VERSION ) );
+ printf( "GL_VENDOR = %s\n", (char *) glGetString( GL_VENDOR ) ) ;
+ printf( "GL_EXTENSIONS = %s\n", (char *) glGetString( GL_EXTENSIONS ) );
+ }
+
+ glutDisplayFunc( display );
+ glutReshapeFunc( reshape );
+ glutKeyboardFunc( keyboard );
+ glutSpecialFunc( special );
+ glutMainLoop();
+
+ return 0;
+}
diff --git a/tests/mesa/tests/texline.c b/tests/mesa/tests/texline.c
new file mode 100644
index 00000000..3d59d9ac
--- /dev/null
+++ b/tests/mesa/tests/texline.c
@@ -0,0 +1,269 @@
+/* $Id: texline.c,v 1.5 2004/01/28 10:07:48 keithw Exp $ */
+
+/*
+ * Test textured lines.
+ *
+ * Brian Paul
+ * September 2000
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+#include "../util/readtex.c" /* I know, this is a hack. */
+
+#define TEXTURE_FILE "../images/girl.rgb"
+
+static GLboolean Antialias = GL_FALSE;
+static GLboolean Animate = GL_FALSE;
+static GLint Texture = 1;
+static GLboolean Stipple = GL_FALSE;
+static GLfloat LineWidth = 1.0;
+
+static GLfloat Xrot = -60.0, Yrot = 0.0, Zrot = 0.0;
+static GLfloat DYrot = 1.0;
+static GLboolean Points = GL_FALSE;
+static GLfloat Scale = 1.0;
+
+static void Idle( void )
+{
+ if (Animate) {
+ Zrot += DYrot;
+ glutPostRedisplay();
+ }
+}
+
+
+static void Display( void )
+{
+ GLfloat x, y, s, t;
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ glScalef(Scale, Scale, Scale);
+
+ if (Texture)
+ glColor3f(1, 1, 1);
+
+ if (Points) {
+ glBegin(GL_POINTS);
+ for (t = 0.0; t <= 1.0; t += 0.025) {
+ for (s = 0.0; s <= 1.0; s += 0.025) {
+ x = s * 2.0 - 1.0;
+ y = t * 2.0 - 1.0;
+ if (!Texture)
+ glColor3f(1, 0, 1);
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, t, s);
+ glTexCoord2f(s, t);
+ glVertex2f(x, y);
+ }
+ }
+ glEnd();
+ }
+ else {
+ glBegin(GL_LINES);
+ for (t = 0.0; t <= 1.0; t += 0.025) {
+ x = t * 2.0 - 1.0;
+ if (!Texture)
+ glColor3f(1, 0, 1);
+ glTexCoord2f(t, 0.0);
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, t);
+ glVertex2f(x, -1.0);
+ if (!Texture)
+ glColor3f(0, 1, 0);
+ glTexCoord2f(t, 1.0);
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0, t);
+ glVertex2f(x, 1.0);
+ }
+ glEnd();
+ }
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, 10.0, 100.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -12.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Antialias = !Antialias;
+ if (Antialias) {
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_POINT_SMOOTH);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_POINT_SMOOTH);
+ glDisable(GL_BLEND);
+ }
+ break;
+ case 't':
+ Texture++;
+ if (Texture > 2)
+ Texture = 0;
+ if (Texture == 0) {
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ glDisable(GL_TEXTURE_2D);
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+ glDisable(GL_TEXTURE_2D);
+ }
+ else if (Texture == 1) {
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ glEnable(GL_TEXTURE_2D);
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+ glDisable(GL_TEXTURE_2D);
+ }
+ else {
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ glEnable(GL_TEXTURE_2D);
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+ glEnable(GL_TEXTURE_2D);
+ }
+ break;
+ case 'w':
+ LineWidth -= 0.25;
+ if (LineWidth < 0.25)
+ LineWidth = 0.25;
+ glLineWidth(LineWidth);
+ glPointSize(LineWidth);
+ break;
+ case 'W':
+ LineWidth += 0.25;
+ if (LineWidth > 8.0)
+ LineWidth = 8.0;
+ glLineWidth(LineWidth);
+ glPointSize(LineWidth);
+ break;
+ case 'p':
+ Points = !Points;
+ break;
+ case 's':
+ Stipple = !Stipple;
+ if (Stipple)
+ glEnable(GL_LINE_STIPPLE);
+ else
+ glDisable(GL_LINE_STIPPLE);
+ break;
+ case ' ':
+ Animate = !Animate;
+ if (Animate)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ printf("LineWidth, PointSize = %f\n", LineWidth);
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( int argc, char *argv[] )
+{
+ GLuint u;
+ for (u = 0; u < 2; u++) {
+ glActiveTextureARB(GL_TEXTURE0_ARB + u);
+ glBindTexture(GL_TEXTURE_2D, 10+u);
+ if (u == 0)
+ glEnable(GL_TEXTURE_2D);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ if (u == 0)
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ else
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image\n");
+ exit(1);
+ }
+ }
+
+ glLineStipple(1, 0xff);
+
+ if (argc > 1 && strcmp(argv[1], "-info")==0) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize( 400, 300 );
+
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+
+ glutCreateWindow(argv[0] );
+
+ Init(argc, argv);
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Animate)
+ glutIdleFunc( Idle );
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/texobjshare.c b/tests/mesa/tests/texobjshare.c
new file mode 100644
index 00000000..2b31cb6c
--- /dev/null
+++ b/tests/mesa/tests/texobjshare.c
@@ -0,0 +1,219 @@
+/*
+ * Create several OpenGL rendering contexts, sharing textures, display
+ * lists, etc. Exercise binding, deleting, etc.
+ *
+ * Brian Paul
+ * 21 December 2004
+ */
+
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <X11/keysym.h>
+
+
+/*
+ * Each display/window/context:
+ */
+struct context {
+ char DisplayName[1000];
+ Display *Dpy;
+ Window Win;
+ GLXContext Context;
+};
+
+
+#define MAX_CONTEXTS 200
+static struct context Contexts[MAX_CONTEXTS];
+static int NumContexts = 0;
+
+
+static void
+Error(const char *display, const char *msg)
+{
+ fprintf(stderr, "Error on display %s - %s\n", display, msg);
+ exit(1);
+}
+
+
+static struct context *
+CreateContext(const char *displayName, const char *name)
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ XVisualInfo *visinfo;
+ int width = 90, height = 90;
+ int xpos = 0, ypos = 0;
+
+ if (NumContexts >= MAX_CONTEXTS)
+ return NULL;
+
+ dpy = XOpenDisplay(displayName);
+ if (!dpy) {
+ Error(displayName, "Unable to open display");
+ return NULL;
+ }
+
+ scrnum = DefaultScreen(dpy);
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, attrib);
+ if (!visinfo) {
+ Error(displayName, "Unable to find RGB, double-buffered visual");
+ return NULL;
+ }
+
+ /* window attributes */
+ xpos = (NumContexts % 10) * 100;
+ ypos = (NumContexts / 10) * 100;
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow(dpy, root, xpos, ypos, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+ if (!win) {
+ Error(displayName, "Couldn't create window");
+ return NULL;
+ }
+
+ {
+ XSizeHints sizehints;
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ if (NumContexts == 0) {
+ ctx = glXCreateContext(dpy, visinfo, NULL, True);
+ }
+ else {
+ /* share textures & dlists with 0th context */
+ ctx = glXCreateContext(dpy, visinfo, Contexts[0].Context, True);
+ }
+ if (!ctx) {
+ Error(displayName, "Couldn't create GLX context");
+ return NULL;
+ }
+
+ XMapWindow(dpy, win);
+
+ if (!glXMakeCurrent(dpy, win, ctx)) {
+ Error(displayName, "glXMakeCurrent failed");
+ return NULL;
+ }
+
+ if (NumContexts == 0) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ }
+
+ /* save the info for this context */
+ {
+ struct context *h = &Contexts[NumContexts];
+ strcpy(h->DisplayName, name);
+ h->Dpy = dpy;
+ h->Win = win;
+ h->Context = ctx;
+ NumContexts++;
+ return &Contexts[NumContexts-1];
+ }
+}
+
+
+static void
+MakeCurrent(int i)
+{
+ if (!glXMakeCurrent(Contexts[i].Dpy, Contexts[i].Win, Contexts[i].Context)) {
+ fprintf(stderr, "glXMakeCurrent failed!\n");
+ }
+}
+
+
+
+static void
+DestroyContext(int i)
+{
+ XDestroyWindow(Contexts[i].Dpy, Contexts[i].Win);
+ glXDestroyContext(Contexts[i].Dpy, Contexts[i].Context);
+ XCloseDisplay(Contexts[i].Dpy);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ char *dpyName = NULL;
+ int i;
+ GLuint t;
+ GLint tb;
+
+ for (i = 0; i < 2; i++) {
+ CreateContext(dpyName, "context");
+ }
+
+ /* Create texture and bind it in context 0 */
+ MakeCurrent(0);
+ glGenTextures(1, &t);
+ printf("Generated texture ID %u\n", t);
+ assert(!glIsTexture(t));
+ glBindTexture(GL_TEXTURE_2D, t);
+ assert(glIsTexture(t));
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
+ assert(tb == t);
+
+ /* Bind texture in context 1 */
+ MakeCurrent(1);
+ assert(glIsTexture(t));
+ glBindTexture(GL_TEXTURE_2D, t);
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
+ assert(tb == t);
+
+ /* Delete texture from context 0 */
+ MakeCurrent(0);
+ glDeleteTextures(1, &t);
+ assert(!glIsTexture(t));
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
+ printf("After delete, binding = %d\n", tb);
+
+ /* Check texture state from context 1 */
+ MakeCurrent(1);
+ assert(!glIsTexture(t));
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
+ printf("In second context, binding = %d\n", tb);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
+ assert(tb == 0);
+
+
+ for (i = 0; i < NumContexts; i++) {
+ DestroyContext(i);
+ }
+
+ printf("Success!\n");
+
+ return 0;
+}
diff --git a/tests/mesa/tests/texrect.c b/tests/mesa/tests/texrect.c
new file mode 100644
index 00000000..61c1fdd6
--- /dev/null
+++ b/tests/mesa/tests/texrect.c
@@ -0,0 +1,360 @@
+/* $Id: texrect.c,v 1.5 2004/05/06 20:27:32 brianp Exp $ */
+
+/* GL_NV_texture_rectangle test
+ *
+ * Brian Paul
+ * 14 June 2002
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <GL/glut.h>
+#include "readtex.h"
+
+#define TEXTURE_0_FILE "../images/girl.rgb"
+#define TEXTURE_1_FILE "../images/reflect.rgb"
+
+#define TEX0 1
+#define TEX7 8
+#define ANIMATE 10
+#define CLAMP 20
+#define CLAMP_TO_EDGE 21
+#define CLAMP_TO_BORDER 22
+#define LINEAR_FILTER 30
+#define NEAREST_FILTER 31
+#define QUIT 100
+
+static GLboolean Animate = GL_FALSE;
+static GLint NumUnits = 2;
+static GLboolean TexEnabled[8];
+static GLint Width[8], Height[8]; /* image sizes */
+static GLenum Format[8];
+
+static GLfloat Xrot = 00.0, Yrot = 00.0, Zrot = 0.0;
+
+
+static void Idle( void )
+{
+ Zrot = glutGet(GLUT_ELAPSED_TIME) * 0.01;
+ glutPostRedisplay();
+}
+
+
+static void DrawObject(void)
+{
+ GLint i;
+ GLfloat d = 10; /* so we can see how borders are handled */
+
+ glColor3f(.1, .1, .1); /* modulate this */
+
+ glPushMatrix();
+
+ glRotatef(Zrot, 0, 0, 1);
+
+ glBegin(GL_QUADS);
+
+ for (i = 0; i < NumUnits; i++)
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB + i, -d, -d);
+ glVertex2f(-1.0, -1.0);
+
+ for (i = 0; i < NumUnits; i++)
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB + i, Width[i]+d, -d);
+ glVertex2f(1.0, -1.0);
+
+ for (i = 0; i < NumUnits; i++)
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB + i, Width[i]+d, Height[i]+d);
+ glVertex2f(1.0, 1.0);
+
+ for (i = 0; i < NumUnits; i++)
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB + i, -d, Height[i]+d);
+ glVertex2f(-1.0, 1.0);
+
+ glEnd();
+ glPopMatrix();
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ glScalef(5.0, 5.0, 5.0);
+ DrawObject();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 100.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -35.0 );
+}
+
+
+static void ModeMenu(int entry)
+{
+ GLint i;
+ if (entry >= TEX0 && entry < TEX0 + NumUnits) {
+ /* toggle */
+ i = entry - TEX0;
+ TexEnabled[i] = !TexEnabled[i];
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ if (TexEnabled[i]) {
+ glEnable(GL_TEXTURE_RECTANGLE_NV);
+ }
+ else {
+ glDisable(GL_TEXTURE_RECTANGLE_NV);
+ }
+ printf("Enabled: ");
+ for (i = 0; i < NumUnits; i++)
+ printf("%d ", (int) TexEnabled[i]);
+ printf("\n");
+ }
+ else if (entry==ANIMATE) {
+ Animate = !Animate;
+ if (Animate)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ }
+ else if (entry==CLAMP) {
+ for (i = 0; i < NumUnits; i++) {
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ }
+ }
+ else if (entry==CLAMP_TO_EDGE) {
+ for (i = 0; i < NumUnits; i++) {
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ }
+ else if (entry==CLAMP_TO_BORDER) {
+ for (i = 0; i < NumUnits; i++) {
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ }
+ }
+ else if (entry==NEAREST_FILTER) {
+ for (i = 0; i < NumUnits; i++) {
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+ }
+ else if (entry==LINEAR_FILTER) {
+ for (i = 0; i < NumUnits; i++) {
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ }
+
+ else if (entry==QUIT) {
+ exit(0);
+ }
+
+ glutPostRedisplay();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'z':
+ Zrot -= 1.0;
+ break;
+ case 'Z':
+ Zrot += 1.0;
+ break;
+ case 'a':
+ Animate = !Animate;
+ if (Animate)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( int argc, char *argv[] )
+{
+ const GLenum wrap = GL_CLAMP;
+ GLuint texObj[8];
+ GLint size, i;
+
+ if (!glutExtensionSupported("GL_ARB_multitexture")) {
+ printf("Sorry, GL_ARB_multitexture needed by this program\n");
+ exit(1);
+ }
+
+ if (!glutExtensionSupported("GL_NV_texture_rectangle")) {
+ printf("Sorry, GL_NV_texture_rectangle needed by this program\n");
+ exit(1);
+ }
+
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &NumUnits);
+ printf("%d texture units supported, using 2.\n", NumUnits);
+ if (NumUnits > 2)
+ NumUnits = 2;
+
+ glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, &size);
+ printf("%d x %d max texture rectangle size\n", size, size);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ for (i = 0; i < NumUnits; i++) {
+ TexEnabled[i] = GL_TRUE;
+ }
+
+ /* allocate two texture objects */
+ glGenTextures(NumUnits, texObj);
+
+ /* setup the texture objects */
+ for (i = 0; i < NumUnits; i++) {
+
+ glActiveTextureARB(GL_TEXTURE0_ARB + i);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_NV, texObj[i]);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV,
+ GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV,
+ GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, wrap);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, wrap);
+
+ if (i == 0) {
+ GLubyte *img = LoadRGBImage(TEXTURE_0_FILE, &Width[0], &Height[0],
+ &Format[0]);
+ if (!img) {
+ printf("Error: couldn't load texture image\n");
+ exit(1);
+ }
+ printf("Texture %d: %s (%d x %d)\n", i,
+ TEXTURE_0_FILE, Width[0], Height[0]);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGB,
+ Width[0], Height[0], 0,
+ Format[0], GL_UNSIGNED_BYTE, img);
+ }
+ else {
+ GLubyte *img = LoadRGBImage(TEXTURE_1_FILE, &Width[1], &Height[1],
+ &Format[1]);
+ if (!img) {
+ printf("Error: couldn't load texture image\n");
+ exit(1);
+ }
+ printf("Texture %d: %s (%d x %d)\n", i,
+ TEXTURE_1_FILE, Width[1], Height[1]);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGB,
+ Width[1], Height[1], 0,
+ Format[1], GL_UNSIGNED_BYTE, img);
+ }
+
+ if (i < 1)
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
+ else
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
+
+ if (TexEnabled[i])
+ glEnable(GL_TEXTURE_RECTANGLE_NV);
+ }
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.3, 0.3, 0.4, 1.0);
+
+ if (argc > 1 && strcmp(argv[1], "-info")==0) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ GLint i;
+
+ glutInit( &argc, argv );
+ glutInitWindowSize( 300, 300 );
+ glutInitWindowPosition( 0, 0 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0] );
+
+ Init( argc, argv );
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Animate)
+ glutIdleFunc( Idle );
+
+ glutCreateMenu(ModeMenu);
+
+ for (i = 0; i < NumUnits; i++) {
+ char s[100];
+ sprintf(s, "Toggle Texture %d", i);
+ glutAddMenuEntry(s, TEX0 + i);
+ }
+ glutAddMenuEntry("Toggle Animation", ANIMATE);
+ glutAddMenuEntry("GL_CLAMP", CLAMP);
+ glutAddMenuEntry("GL_CLAMP_TO_EDGE", CLAMP_TO_EDGE);
+ glutAddMenuEntry("GL_CLAMP_TO_BORDER", CLAMP_TO_BORDER);
+ glutAddMenuEntry("GL_NEAREST", NEAREST_FILTER);
+ glutAddMenuEntry("GL_LINEAR", LINEAR_FILTER);
+ glutAddMenuEntry("Quit", QUIT);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/texwrap.c b/tests/mesa/tests/texwrap.c
new file mode 100644
index 00000000..6e9fbe0c
--- /dev/null
+++ b/tests/mesa/tests/texwrap.c
@@ -0,0 +1,304 @@
+/* $Id: texwrap.c,v 1.8 2005/08/25 03:09:12 brianp Exp $ */
+
+/*
+ * Test texture wrap modes.
+ * Press 'b' to toggle texture image borders. You should see the same
+ * rendering whether or not you're using borders.
+ *
+ * Brian Paul March 2001
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+#ifndef GL_CLAMP_TO_BORDER
+#define GL_CLAMP_TO_BORDER 0x812D
+#endif
+
+#ifndef GL_MIRRORED_REPEAT
+#define GL_MIRRORED_REPEAT 0x8370
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_MIRROR_CLAMP_EXT 0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743
+#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912
+#endif
+
+#define BORDER_TEXTURE 1
+#define NO_BORDER_TEXTURE 2
+
+#define SIZE 8
+static GLubyte BorderImage[SIZE+2][SIZE+2][4];
+static GLubyte NoBorderImage[SIZE][SIZE][4];
+static GLuint Border = 0;
+
+#define TILE_SIZE 110
+
+#define WRAP_MODE(m) { m , # m, GL_TRUE, 1.0, { NULL, NULL } }
+#define WRAP_EXT(m,e1,e2,v) { m , # m, GL_FALSE, v, { e1, e2 } }
+
+struct wrap_mode {
+ GLenum mode;
+ const char * name;
+ GLboolean supported;
+ GLfloat version;
+ const char * extension_names[2];
+};
+
+static struct wrap_mode modes[] = {
+ WRAP_MODE( GL_REPEAT ),
+ WRAP_MODE( GL_CLAMP ),
+ WRAP_EXT ( GL_CLAMP_TO_EDGE, "GL_EXT_texture_edge_clamp",
+ "GL_SGIS_texture_edge_clamp",
+ 1.2 ),
+ WRAP_EXT ( GL_CLAMP_TO_BORDER, "GL_ARB_texture_border_clamp",
+ "GL_SGIS_texture_border_clamp",
+ 1.3 ),
+ WRAP_EXT ( GL_MIRRORED_REPEAT, "GL_ARB_texture_mirrored_repeat",
+ "GL_IBM_texture_mirrored_repeat",
+ 1.4 ),
+ WRAP_EXT ( GL_MIRROR_CLAMP_EXT, "GL_ATI_texture_mirror_once",
+ "GL_EXT_texture_mirror_clamp",
+ 999.0 ),
+ WRAP_EXT ( GL_MIRROR_CLAMP_TO_BORDER_EXT, "GL_EXT_texture_mirror_clamp",
+ NULL,
+ 999.0 ),
+ WRAP_EXT ( GL_MIRROR_CLAMP_TO_EDGE_EXT, "GL_ATI_texture_mirror_once",
+ "GL_EXT_texture_mirror_clamp",
+ 999.0 ),
+ { 0 }
+};
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static void Display( void )
+{
+ GLenum i, j;
+ GLint offset;
+ GLfloat version;
+
+ /* Fill in the extensions that are supported.
+ */
+
+ version = atof( (char *) glGetString( GL_VERSION ) );
+ for ( i = 0 ; modes[i].mode != 0 ; i++ ) {
+ if ( ((modes[i].extension_names[0] != NULL)
+ && glutExtensionSupported(modes[i].extension_names[0]))
+ || ((modes[i].extension_names[1] != NULL)
+ && glutExtensionSupported(modes[i].extension_names[1])) ) {
+ modes[i].supported = GL_TRUE;
+ }
+ else if ( !modes[i].supported && (modes[i].version <= version) ) {
+ fprintf( stderr, "WARNING: OpenGL library meets minimum version\n"
+ " requirement for %s, but the\n"
+ " extension string is not advertised.\n"
+ " (%s%s%s)\n",
+ modes[i].name,
+ modes[i].extension_names[0],
+ (modes[i].extension_names[1] != NULL)
+ ? " or " : "",
+ (modes[i].extension_names[1] != NULL)
+ ? modes[i].extension_names[1] : "" );
+ modes[i].supported = GL_TRUE;
+ }
+ }
+
+
+ glClearColor(0.5, 0.5, 0.5, 1.0);
+ glClear( GL_COLOR_BUFFER_BIT );
+
+#if 0
+ /* draw texture as image */
+ glDisable(GL_TEXTURE_2D);
+ glWindowPos2iARB(1, 1);
+ glDrawPixels(6, 6, GL_RGBA, GL_UNSIGNED_BYTE, (void *) TexImage);
+#endif
+
+ glBindTexture(GL_TEXTURE_2D, Border ? BORDER_TEXTURE : NO_BORDER_TEXTURE);
+
+
+ /* loop over min/mag filters */
+ for (i = 0; i < 2; i++) {
+ offset = 0;
+
+ if (i) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+
+ /* loop over border modes */
+ for (j = 0; modes[j].mode != 0; j++) {
+ const GLfloat x0 = 0, y0 = 0, x1 = (TILE_SIZE - 10), y1 = (TILE_SIZE - 10);
+ const GLfloat b = 1.2;
+ const GLfloat s0 = -b, t0 = -b, s1 = 1.0+b, t1 = 1.0+b;
+
+ if ( modes[j].supported != GL_TRUE )
+ continue;
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, modes[j].mode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, modes[j].mode);
+
+ glPushMatrix();
+ glTranslatef(offset * TILE_SIZE + 10, i * TILE_SIZE + 40, 0);
+ offset++;
+
+ glEnable(GL_TEXTURE_2D);
+ glColor3f(1, 1, 1);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(s0, t0); glVertex2f(x0, y0);
+ glTexCoord2f(s1, t0); glVertex2f(x1, y0);
+ glTexCoord2f(s1, t1); glVertex2f(x1, y1);
+ glTexCoord2f(s0, t1); glVertex2f(x0, y1);
+ glEnd();
+
+ /* draw red outline showing bounds of texture at s=0,1 and t=0,1 */
+ glDisable(GL_TEXTURE_2D);
+ glColor3f(1, 0, 0);
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(x0 + b * (x1-x0) / (s1-s0), y0 + b * (y1-y0) / (t1-t0));
+ glVertex2f(x1 - b * (x1-x0) / (s1-s0), y0 + b * (y1-y0) / (t1-t0));
+ glVertex2f(x1 - b * (x1-x0) / (s1-s0), y1 - b * (y1-y0) / (t1-t0));
+ glVertex2f(x0 + b * (x1-x0) / (s1-s0), y1 - b * (y1-y0) / (t1-t0));
+ glEnd();
+
+ glPopMatrix();
+ }
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glColor3f(1, 1, 1);
+ offset = 0;
+ for (i = 0; modes[i].mode != 0; i++) {
+ if ( modes[i].supported ) {
+ glWindowPos2iARB( offset * TILE_SIZE + 10, 5 + ((offset & 1) * 15) );
+ PrintString(modes[i].name);
+ offset++;
+ }
+ }
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho(0, width, 0, height, -1, 1);
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'b':
+ Border = !Border;
+ printf("Texture Border Size = %d\n", Border);
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ static const GLubyte border[4] = { 0, 255, 0, 255 };
+ static const GLfloat borderf[4] = { 0, 1.0, 0, 1.0 };
+ GLint i, j;
+
+ for (i = 0; i < SIZE+2; i++) {
+ for (j = 0; j < SIZE+2; j++) {
+ if (i == 0 || j == 0 || i == SIZE+1 || j == SIZE+1) {
+ /* border color */
+ BorderImage[i][j][0] = border[0];
+ BorderImage[i][j][1] = border[1];
+ BorderImage[i][j][2] = border[2];
+ BorderImage[i][j][3] = border[3];
+ }
+ else if ((i + j) & 1) {
+ /* white */
+ BorderImage[i][j][0] = 255;
+ BorderImage[i][j][1] = 255;
+ BorderImage[i][j][2] = 255;
+ BorderImage[i][j][3] = 255;
+ }
+ else {
+ /* black */
+ BorderImage[i][j][0] = 0;
+ BorderImage[i][j][1] = 0;
+ BorderImage[i][j][2] = 0;
+ BorderImage[i][j][3] = 0;
+ }
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, BORDER_TEXTURE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SIZE+2, SIZE+2, 1,
+ GL_RGBA, GL_UNSIGNED_BYTE, (void *) BorderImage);
+
+ for (i = 0; i < SIZE; i++) {
+ for (j = 0; j < SIZE; j++) {
+ if ((i + j) & 1) {
+ /* white */
+ NoBorderImage[i][j][0] = 255;
+ NoBorderImage[i][j][1] = 255;
+ NoBorderImage[i][j][2] = 255;
+ NoBorderImage[i][j][3] = 255;
+ }
+ else {
+ /* black */
+ NoBorderImage[i][j][0] = 0;
+ NoBorderImage[i][j][1] = 0;
+ NoBorderImage[i][j][2] = 0;
+ NoBorderImage[i][j][3] = 0;
+ }
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, NO_BORDER_TEXTURE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SIZE, SIZE, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, (void *) NoBorderImage);
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderf);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 1000, 270 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/vao-01.c b/tests/mesa/tests/vao-01.c
new file mode 100644
index 00000000..c2d70885
--- /dev/null
+++ b/tests/mesa/tests/vao-01.c
@@ -0,0 +1,177 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file vao-01.c
+ *
+ * Simple test of APPLE_vertex_array_object functionality. This test creates
+ * a VAO, pushed it (via \c glPushClientAttrib), modifies the VAO, then pops
+ * it (via \c glPopClientAttrib). After popping, the state of the VAO is
+ * examined.
+ *
+ * According the the APPLE_vertex_array_object spec, the contents of the VAO
+ * should be restored to the values that they had when pushed.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef __darwin__
+#include <GLUT/glut.h>
+
+typedef void (* PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (* PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (* PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (* PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+
+#else
+#include <GL/glut.h>
+#endif
+
+static PFNGLBINDVERTEXARRAYAPPLEPROC bind_vertex_array = NULL;
+static PFNGLGENVERTEXARRAYSAPPLEPROC gen_vertex_arrays = NULL;
+static PFNGLDELETEVERTEXARRAYSAPPLEPROC delete_vertex_arrays = NULL;
+static PFNGLISVERTEXARRAYAPPLEPROC is_vertex_array = NULL;
+
+static int Width = 400;
+static int Height = 200;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+}
+
+
+static void Idle( void )
+{
+}
+
+
+static void Visible( int vis )
+{
+ if ( vis == GLUT_VISIBLE ) {
+ glutIdleFunc( Idle );
+ }
+ else {
+ glutIdleFunc( NULL );
+ }
+}
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+ GLuint obj;
+ int pass = 1;
+ void * ptr;
+
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n\n", ver_string);
+
+ if ( !glutExtensionSupported("GL_APPLE_vertex_array_object") ) {
+ printf("Sorry, this program requires GL_APPLE_vertex_array_object\n");
+ exit(2);
+ }
+
+ bind_vertex_array = glutGetProcAddress( "glBindVertexArrayAPPLE" );
+ gen_vertex_arrays = glutGetProcAddress( "glGenVertexArraysAPPLE" );
+ delete_vertex_arrays = glutGetProcAddress( "glDeleteVertexArraysAPPLE" );
+ is_vertex_array = glutGetProcAddress( "glIsVertexArrayAPPLE" );
+
+
+ (*gen_vertex_arrays)( 1, & obj );
+ (*bind_vertex_array)( obj );
+ glVertexPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, (void *) 0xDEADBEEF);
+ glEnableClientState( GL_VERTEX_ARRAY );
+
+ glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
+
+ glVertexPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, (void *) 0xBADDC0DE);
+ glDisableClientState( GL_VERTEX_ARRAY );
+
+ glPopClientAttrib();
+
+ if ( ! glIsEnabled( GL_VERTEX_ARRAY ) ) {
+ printf( "Array state is incorrectly disabled.\n" );
+ pass = 0;
+ }
+
+ glGetPointerv( GL_VERTEX_ARRAY_POINTER, & ptr );
+ if ( ptr != (void *) 0xDEADBEEF ) {
+ printf( "Array pointer is incorrectly set to 0x%p.\n", ptr );
+ pass = 0;
+ }
+
+ if ( ! pass ) {
+ printf( "FAIL!\n" );
+ exit(1);
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB );
+ glutCreateWindow( "GL_APPLE_vertex_array_object demo" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ glutVisibilityFunc( Visible );
+
+ Init();
+
+ return 0;
+}
diff --git a/tests/mesa/tests/vao-02.c b/tests/mesa/tests/vao-02.c
new file mode 100644
index 00000000..993bc368
--- /dev/null
+++ b/tests/mesa/tests/vao-02.c
@@ -0,0 +1,205 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file vao-02.c
+ *
+ * Simple test of APPLE_vertex_array_object functionality. This test creates
+ * a VAO, pushed it (via \c glPushClientAttrib), deletes the VAO, then pops
+ * it (via \c glPopClientAttrib). After popping, the state of the VAO is
+ * examined.
+ *
+ * According the the APPLE_vertex_array_object spec, the contents of the VAO
+ * should be restored to the values that they had when pushed.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef __darwin__
+#include <GLUT/glut.h>
+
+typedef void (* PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (* PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (* PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (* PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+
+#else
+#include <GL/glut.h>
+#endif
+
+static PFNGLBINDVERTEXARRAYAPPLEPROC bind_vertex_array = NULL;
+static PFNGLGENVERTEXARRAYSAPPLEPROC gen_vertex_arrays = NULL;
+static PFNGLDELETEVERTEXARRAYSAPPLEPROC delete_vertex_arrays = NULL;
+static PFNGLISVERTEXARRAYAPPLEPROC is_vertex_array = NULL;
+
+static int Width = 400;
+static int Height = 200;
+static const GLfloat Near = 5.0, Far = 25.0;
+
+
+static void Display( void )
+{
+}
+
+
+static void Idle( void )
+{
+}
+
+
+static void Visible( int vis )
+{
+ if ( vis == GLUT_VISIBLE ) {
+ glutIdleFunc( Idle );
+ }
+ else {
+ glutIdleFunc( NULL );
+ }
+}
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+ GLuint obj;
+ int pass = 1;
+ void * ptr;
+ GLenum err;
+
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n\n", ver_string);
+
+ if ( !glutExtensionSupported("GL_APPLE_vertex_array_object") ) {
+ printf("Sorry, this program requires GL_APPLE_vertex_array_object\n");
+ exit(2);
+ }
+
+ bind_vertex_array = glutGetProcAddress( "glBindVertexArrayAPPLE" );
+ gen_vertex_arrays = glutGetProcAddress( "glGenVertexArraysAPPLE" );
+ delete_vertex_arrays = glutGetProcAddress( "glDeleteVertexArraysAPPLE" );
+ is_vertex_array = glutGetProcAddress( "glIsVertexArrayAPPLE" );
+
+
+ (*gen_vertex_arrays)( 1, & obj );
+ (*bind_vertex_array)( obj );
+ glVertexPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, (void *) 0xDEADBEEF);
+ glEnableClientState( GL_VERTEX_ARRAY );
+
+ glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
+
+ (*delete_vertex_arrays)( 1, & obj );
+
+ err = glGetError();
+ if (err) {
+ printf( "glGetError incorrectly returned 0x%04x.\n", err );
+ pass = 0;
+ }
+
+ if ( (*is_vertex_array)( obj ) ) {
+ printf( "Array object is incorrectly still valid.\n" );
+ pass = 0;
+ }
+
+ err = glGetError();
+ if (err) {
+ printf( "glGetError incorrectly returned 0x%04x.\n", err );
+ pass = 0;
+ }
+
+ glPopClientAttrib();
+
+ err = glGetError();
+ if (err) {
+ printf( "glGetError incorrectly returned 0x%04x.\n", err );
+ pass = 0;
+ }
+
+ if ( ! (*is_vertex_array)( obj ) ) {
+ printf( "Array object is incorrectly invalid.\n" );
+ pass = 0;
+ }
+
+ if ( ! glIsEnabled( GL_VERTEX_ARRAY ) ) {
+ printf( "Array state is incorrectly disabled.\n" );
+ pass = 0;
+ }
+
+ glGetPointerv( GL_VERTEX_ARRAY_POINTER, & ptr );
+ if ( ptr != (void *) 0xDEADBEEF ) {
+ printf( "Array pointer is incorrectly set to 0x%p.\n", ptr );
+ pass = 0;
+ }
+
+ if ( ! pass ) {
+ printf( "FAIL!\n" );
+ exit(1);
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB );
+ glutCreateWindow( "GL_APPLE_vertex_array_object demo" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ glutVisibilityFunc( Visible );
+
+ Init();
+
+ return 0;
+}
diff --git a/tests/mesa/tests/vparray.c b/tests/mesa/tests/vparray.c
new file mode 100644
index 00000000..580a670f
--- /dev/null
+++ b/tests/mesa/tests/vparray.c
@@ -0,0 +1,294 @@
+/*
+ * Test vertex arrays with GL_NV_vertex_program
+ *
+ * Based on a stripped-down version of the isosurf demo.
+ * The vertex program is trivial: compute the resulting
+ * RGB color as a linear function of vertex XYZ.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include "GL/glut.h"
+
+#define MAXVERTS 10000
+static float data[MAXVERTS][6];
+static GLint numverts;
+
+static GLfloat xrot;
+static GLfloat yrot;
+static GLboolean useArrays = GL_TRUE;
+static GLboolean useProgram = GL_TRUE;
+static GLboolean useList = GL_FALSE;
+
+
+static void read_surface( char *filename )
+{
+ FILE *f;
+
+ f = fopen(filename,"r");
+ if (!f) {
+ printf("couldn't read %s\n", filename);
+ exit(1);
+ }
+
+ numverts = 0;
+ while (!feof(f) && numverts < MAXVERTS) {
+ fscanf( f, "%f %f %f %f %f %f",
+ &data[numverts][0], &data[numverts][1], &data[numverts][2],
+ &data[numverts][3], &data[numverts][4], &data[numverts][5] );
+ numverts++;
+ }
+ numverts--;
+
+ printf("%d vertices, %d triangles\n", numverts, numverts-2);
+ printf("data = %p\n", (void *) data);
+ fclose(f);
+}
+
+
+
+
+static void Display(void)
+{
+ if (useProgram)
+ glEnable(GL_VERTEX_PROGRAM_NV);
+ else
+ glDisable(GL_VERTEX_PROGRAM_NV);
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(xrot, 1, 0, 0);
+ glRotatef(yrot, 0, 1, 0);
+ glScalef(2, 2, 2);
+ if (useArrays) {
+ if (useProgram) {
+ glVertexAttribPointerNV( 0, 3, GL_FLOAT, 6 * sizeof(GLfloat), data );
+ glEnableClientState( GL_VERTEX_ATTRIB_ARRAY0_NV );
+ glVertexAttribPointerNV( 2, 3, GL_FLOAT, 6 * sizeof(GLfloat), ((GLfloat *) data) + 3);
+ glEnableClientState( GL_VERTEX_ATTRIB_ARRAY2_NV);
+ }
+ else {
+ glVertexPointer( 3, GL_FLOAT, 6 * sizeof(GLfloat), data );
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glNormalPointer( GL_FLOAT, 6 * sizeof(GLfloat), ((GLfloat *) data) + 3);
+ glEnableClientState( GL_NORMAL_ARRAY );
+ }
+
+ if (useList) {
+ /* dumb, but a good test */
+ glNewList(1,GL_COMPILE);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, numverts);
+ glEndList();
+ glCallList(1);
+ }
+ else {
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, numverts);
+ }
+
+ glDisableClientState( GL_VERTEX_ATTRIB_ARRAY0_NV );
+ glDisableClientState( GL_VERTEX_ATTRIB_ARRAY2_NV);
+ glDisableClientState( GL_VERTEX_ARRAY );
+ glDisableClientState( GL_NORMAL_ARRAY );
+ }
+ else {
+ int i;
+ glBegin(GL_TRIANGLE_STRIP);
+ for (i = 0; i < numverts; i++) {
+ glNormal3fv( data[i] + 3 );
+ glVertex3fv( data[i] + 0 );
+ }
+ glEnd();
+ }
+ glPopMatrix();
+
+ if (glGetError())
+ printf("Error!\n");
+
+ glutSwapBuffers();
+}
+
+
+static void InitMaterials(void)
+{
+ static float ambient[] = {0.1, 0.1, 0.1, 1.0};
+ static float diffuse[] = {0.5, 1.0, 1.0, 1.0};
+ static float position0[] = {0.0, 0.0, 20.0, 0.0};
+ static float position1[] = {0.0, 0.0, -20.0, 0.0};
+ static float front_mat_shininess[] = {60.0};
+ static float front_mat_specular[] = {0.2, 0.2, 0.2, 1.0};
+ static float front_mat_diffuse[] = {0.5, 0.28, 0.38, 1.0};
+ /*
+ static float back_mat_shininess[] = {60.0};
+ static float back_mat_specular[] = {0.5, 0.5, 0.2, 1.0};
+ static float back_mat_diffuse[] = {1.0, 1.0, 0.2, 1.0};
+ */
+ static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0};
+ static float lmodel_twoside[] = {GL_FALSE};
+
+ glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+ glLightfv(GL_LIGHT0, GL_POSITION, position0);
+ glEnable(GL_LIGHT0);
+
+ glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
+ glLightfv(GL_LIGHT1, GL_POSITION, position1);
+ glEnable(GL_LIGHT1);
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+ glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse);
+ glEnable(GL_LIGHTING);
+}
+
+
+static void init_program(void)
+{
+ /*
+ * c[0..3] = modelview matrix
+ * c[4..7] = inverse modelview matrix
+ * c[30] = color scale
+ * c[31] = color bias
+ */
+ static const char prog[] =
+ "!!VP1.0\n"
+
+ "# RGB is proportional to XYZ \n"
+
+ "MUL R0, v[OPOS], c[30]; \n"
+ "ADD o[COL0], R0, c[31]; \n"
+
+ "# Continue with typical modelview/projection\n"
+ "MOV R3, v[OPOS]; \n"
+ "DP4 o[HPOS].x, c[0], R3 ; # object x MVP -> clip\n"
+ "DP4 o[HPOS].y, c[1], R3 ;\n"
+ "DP4 o[HPOS].z, c[2], R3 ;\n"
+ "DP4 o[HPOS].w, c[3], R3 ;\n"
+
+ "END";
+
+ static const GLfloat scale[4] = {2.0, 2.0, 2.0, 0.0};
+ static const GLfloat bias[4] = {1.0, 1.0, 1.0, 0.0};
+
+ if (!glutExtensionSupported("GL_NV_vertex_program")) {
+ printf("Sorry, this program requires GL_NV_vertex_program");
+ exit(1);
+ }
+
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 1,
+ strlen(prog), (const GLubyte *) prog);
+ assert(glIsProgramNV(1));
+ glBindProgramNV(GL_VERTEX_PROGRAM_NV, 1);
+
+ /* Load the program registers */
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV);
+
+ glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 30, scale);
+ glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, 31, bias);
+}
+
+
+static void init(void)
+{
+ xrot = 0;
+ yrot = 0;
+ glClearColor(0.0, 0.0, 1.0, 0.0);
+ glEnable( GL_DEPTH_TEST );
+ glEnable(GL_NORMALIZE);
+ InitMaterials();
+ read_surface( "../demos/isosurf.dat" );
+ init_program();
+}
+
+
+static void Reshape(int width, int height)
+{
+ glViewport(0, 0, (GLint)width, (GLint)height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5, 25 );
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0, 0, -15);
+}
+
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ case 'a':
+ useArrays = !useArrays;
+ printf("use arrays: %s\n", useArrays ? "yes" : "no");
+ break;
+ case 'l':
+ useList = !useList;
+ printf("use list: %s\n", useList ? "yes" : "no");
+ break;
+ case 'p':
+ useProgram = !useProgram;
+ printf("use program: %s\n", useProgram ? "yes" : "no");
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_LEFT:
+ yrot -= 15.0;
+ break;
+ case GLUT_KEY_RIGHT:
+ yrot += 15.0;
+ break;
+ case GLUT_KEY_UP:
+ xrot += 15.0;
+ break;
+ case GLUT_KEY_DOWN:
+ xrot -= 15.0;
+ break;
+ default:
+ return;
+ }
+ glutPostRedisplay();
+}
+
+
+
+int main(int argc, char **argv)
+{
+ glutInit(&argc, argv);
+ glutInitDisplayMode( GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE );
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(400, 400);
+ if (glutCreateWindow("Isosurface") <= 0) {
+ exit(0);
+ }
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Display);
+
+ init();
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/vpeval.c b/tests/mesa/tests/vpeval.c
new file mode 100644
index 00000000..8b6996d3
--- /dev/null
+++ b/tests/mesa/tests/vpeval.c
@@ -0,0 +1,231 @@
+/*
+ * Vertex program evaluators test.
+ * Based on book/bezmesh.c
+ *
+ * Brian Paul
+ * 22 June 2002
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+
+/*
+ * Transform position by modelview/projection.
+ * Square incoming color.
+ */
+static const char prog[] =
+"!!VP1.0\n"
+
+"# Typical modelview/projection\n"
+"DP4 o[HPOS].x, c[0], v[OPOS] ; # object x MVP -> clip\n"
+"DP4 o[HPOS].y, c[1], v[OPOS] ;\n"
+"DP4 o[HPOS].z, c[2], v[OPOS] ;\n"
+"DP4 o[HPOS].w, c[3], v[OPOS] ;\n"
+
+"MOV R0, v[COL0];\n # square the color\n"
+"MUL R0, R0, R0;\n"
+"MOV o[COL0], R0;\n # store output color\n"
+
+"END";
+
+
+static int program = 1;
+
+
+GLfloat ctrlpoints[4][4][4] =
+{
+ {
+ {-1.5, -1.5, 4.0, 1.0},
+ {-0.5, -1.5, 2.0, 1.0},
+ {0.5, -1.5, -1.0, 1.0},
+ {1.5, -1.5, 2.0, 1.0}},
+ {
+ {-1.5, -0.5, 1.0, 1.0},
+ {-0.5, -0.5, 3.0, 1.0},
+ {0.5, -0.5, 0.0, 1.0},
+ {1.5, -0.5, -1.0, 1.0}},
+ {
+ {-1.5, 0.5, 4.0, 1.0},
+ {-0.5, 0.5, 0.0, 1.0},
+ {0.5, 0.5, 3.0, 1.0},
+ {1.5, 0.5, 4.0, 1.0}},
+ {
+ {-1.5, 1.5, -2.0, 1.0},
+ {-0.5, 1.5, -2.0, 1.0},
+ {0.5, 1.5, 0.0, 1.0},
+ {1.5, 1.5, -1.0, 1.0}}
+};
+
+/*
+ * +-------------+
+ * |green |yellow
+ * | |
+ * | |
+ * |black |red
+ * +-------------+
+ */
+GLfloat colorPoints[4][4][4] =
+{
+ {
+ {0.0, 0.0, 0.0, 1.0},
+ {0.3, 0.0, 0.0, 1.0},
+ {0.6, 0.0, 0.0, 1.0},
+ {1.0, 0.0, 0.0, 1.0}},
+ {
+ {0.0, 0.3, 0.0, 1.0},
+ {0.3, 0.3, 0.0, 1.0},
+ {0.6, 0.3, 0.0, 1.0},
+ {1.0, 0.3, 0.0, 1.0}},
+ {
+ {0.0, 0.6, 0.0, 1.0},
+ {0.3, 0.6, 0.0, 1.0},
+ {0.6, 0.6, 0.0, 1.0},
+ {1.0, 0.6, 0.0, 1.0}},
+ {
+ {0.0, 1.0, 0.0, 1.0},
+ {0.3, 1.0, 0.0, 1.0},
+ {0.6, 1.0, 0.0, 1.0},
+ {1.0, 1.0, 0.0, 1.0}}
+};
+
+
+void
+initlights(void)
+{
+ GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0};
+ GLfloat position[] = {0.0, 0.0, 2.0, 1.0};
+ GLfloat mat_diffuse[] = {0.6, 0.6, 0.6, 1.0};
+ GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
+ GLfloat mat_shininess[] = {50.0};
+
+#if 0 /* no lighting for now */
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+
+ glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+ glLightfv(GL_LIGHT0, GL_POSITION, position);
+
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
+ glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
+ glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
+#endif
+}
+
+void
+display(void)
+{
+ glClearColor(.3, .3, .3, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glPushMatrix();
+#if 1
+ glRotatef(85.0, 1.0, 1.0, 1.0);
+#endif
+ glEvalMesh2(GL_FILL, 0, 8, 0, 8);
+ glPopMatrix();
+ glFlush();
+}
+
+void
+myinit(int argc, char *argv[])
+{
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glEnable(GL_DEPTH_TEST);
+
+ initlights(); /* for lighted version only */
+
+ glMapGrid2f(8, 0.0, 1.0, 8, 0.0, 1.0);
+
+ if (argc > 1)
+ program = 0;
+
+ printf("Using vertex program attribs? %s\n", program ? "yes" : "no");
+
+ if (!program) {
+ glMap2f(GL_MAP2_VERTEX_4,
+ 0.0, 1.0, 4, 4,
+ 0.0, 1.0, 16, 4, &ctrlpoints[0][0][0]);
+ glMap2f(GL_MAP2_COLOR_4,
+ 0.0, 1.0, 4, 4,
+ 0.0, 1.0, 16, 4, &colorPoints[0][0][0]);
+ glEnable(GL_MAP2_VERTEX_4);
+ glEnable(GL_MAP2_COLOR_4);
+ /*
+ glEnable(GL_AUTO_NORMAL);
+ glEnable(GL_NORMALIZE);
+ */
+ }
+ else {
+ glMap2f(GL_MAP2_VERTEX_ATTRIB0_4_NV,
+ 0.0, 1.0, 4, 4,
+ 0.0, 1.0, 16, 4, &ctrlpoints[0][0][0]);
+ glMap2f(GL_MAP2_VERTEX_ATTRIB3_4_NV,
+ 0.0, 1.0, 4, 4,
+ 0.0, 1.0, 16, 4, &colorPoints[0][0][0]);
+ glEnable(GL_MAP2_VERTEX_ATTRIB0_4_NV);
+ glEnable(GL_MAP2_VERTEX_ATTRIB3_4_NV);
+
+ /*
+ glEnable(GL_AUTO_NORMAL);
+ glEnable(GL_NORMALIZE);
+ */
+
+ /* vertex program init */
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 1,
+ strlen(prog), (const GLubyte *) prog);
+ assert(glIsProgramNV(1));
+ glBindProgramNV(GL_VERTEX_PROGRAM_NV, 1);
+
+ /* track matrices */
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
+ glEnable(GL_VERTEX_PROGRAM_NV);
+ }
+}
+
+void
+myReshape(int w, int h)
+{
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ if (w <= h)
+ glOrtho(-4.0, 4.0, -4.0 * (GLfloat) h / (GLfloat) w,
+ 4.0 * (GLfloat) h / (GLfloat) w, -4.0, 4.0);
+ else
+ glOrtho(-4.0 * (GLfloat) w / (GLfloat) h,
+ 4.0 * (GLfloat) w / (GLfloat) h, -4.0, 4.0, -4.0, 4.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+ switch (k) {
+ case 27: /* Escape */
+ exit(0);
+ break;
+ default:
+ return;
+ }
+ glutPostRedisplay();
+}
+
+int
+main(int argc, char **argv)
+{
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
+ glutInitWindowPosition(0, 0);
+ glutCreateWindow(argv[0]);
+ myinit(argc, argv);
+ glutReshapeFunc(myReshape);
+ glutDisplayFunc(display);
+ glutKeyboardFunc(key);
+ glutMainLoop();
+ return 0; /* ANSI C requires main to return int. */
+}
diff --git a/tests/mesa/tests/vptest1.c b/tests/mesa/tests/vptest1.c
new file mode 100644
index 00000000..560df2c3
--- /dev/null
+++ b/tests/mesa/tests/vptest1.c
@@ -0,0 +1,170 @@
+/* Test glGenProgramsNV(), glIsProgramNV(), glLoadProgramNV() */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+
+ glBegin(GL_POLYGON);
+ glVertexAttrib2fNV(0, -1, -1);
+ glVertexAttrib2fNV(0, 1, -1);
+ glVertexAttrib2fNV(0, 0, 1);
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ static const char *prog1 =
+ "!!VP1.0\n"
+ "MUL o[COL0].xyz, R0, c[35]; \n"
+ "END\n";
+ static const char *prog2 =
+ "!!VP1.0\n"
+ "#\n"
+ "# c[0-3] = modelview projection (composite) matrix\n"
+ "# c[32] = normalized light direction in object-space\n"
+ "# c[35] = yellow diffuse material, (1.0, 1.0, 0.0, 1.0)\n"
+ "# c[64].x = 0.0\n"
+ "# c[64].z = 0.125, a scaling factor\n"
+ "#\n"
+ "# outputs diffuse illumination for color and perturbed position\n"
+ "#\n"
+ "DP3 R0, c[32], v[NRML]; # light direction DOT normal\n"
+ "MUL o[COL0].xyz, R0, c[35]; \n"
+ "MAX R0, c[64].x, R0; \n"
+ "MUL R0, R0, v[NRML]; \n"
+ "MUL R0, R0, c[64].z; \n"
+ "ADD R1, v[OPOS], -R0; # perturb object space position\n"
+ "DP4 o[HPOS].x, c[0], R1; \n"
+ "DP4 o[HPOS].y, c[1], R1; \n"
+ "DP4 o[HPOS].z, c[2], R1; \n"
+ "DP4 o[HPOS].w, c[3], R1; \n"
+ "END\n";
+ static const char *prog3 =
+ "!!VP1.0\n"
+ "DP4 o[HPOS].x, c[0], v[OPOS];\n"
+ "DP4 o[HPOS].y, c[1], v[OPOS];\n"
+ "DP4 o[HPOS].z, c[2], v[OPOS];\n"
+ "DP4 o[HPOS].w, c[3], v[OPOS];\n"
+ "DP3 R0.x, c[4], v[NRML];\n"
+ "DP3 R0.y, c[5], v[NRML]; \n"
+ "DP3 R0.z, c[6], v[NRML]; # R0 = n' = transformed normal\n"
+ "DP3 R1.x, c[32], R0; # R1.x = Lpos DOT n'\n"
+ "DP3 R1.y, c[33], R0; # R1.y = hHat DOT n'\n"
+ "MOV R1.w, c[38].x; # R1.w = specular power\n"
+ "LIT R2, R1; # Compute lighting values\n"
+ "MAD R3, c[35].x, R2.y, c[35].y; # diffuse + emissive\n"
+ "MAD o[COL0].xyz, c[36], R2.z, R3; # + specular\n"
+ "END\n";
+ static const char *prog4 =
+ "!!VP1.0\n"
+ "DP4 R2, R3, c[A0.x];\n"
+ "DP4 R2, R3, c[A0.x + 5];\n"
+ "DP4 o[HPOS], R3, c[A0.x - 4];\n"
+ "END\n";
+ static const char *prog5 =
+ "!!VSP1.0\n"
+ "DP4 R2, R3, c[A0.x];\n"
+ "DP4 R2, R3, v[0];\n"
+ "DP4 c[3], R3, R2;\n"
+ "END\n";
+
+
+ GLuint progs[5];
+
+ glGenProgramsNV(2, progs);
+ assert(progs[0]);
+ assert(progs[1]);
+ assert(progs[0] != progs[1]);
+
+ glGenProgramsNV(3, progs + 2);
+ assert(progs[2]);
+ assert(progs[3]);
+ assert(progs[2] != progs[3]);
+ assert(progs[0] != progs[2]);
+
+
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 1,
+ strlen(prog1),
+ (const GLubyte *) prog1);
+ assert(!glIsProgramNV(1));
+
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 2,
+ strlen(prog2),
+ (const GLubyte *) prog2);
+ assert(glIsProgramNV(2));
+
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 3,
+ strlen(prog3),
+ (const GLubyte *) prog3);
+ assert(glIsProgramNV(3));
+
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 4,
+ strlen(prog4),
+ (const GLubyte *) prog4);
+ assert(glIsProgramNV(4));
+
+ glLoadProgramNV(GL_VERTEX_STATE_PROGRAM_NV, 5,
+ strlen(prog5),
+ (const GLubyte *) prog5);
+ assert(glIsProgramNV(5));
+
+ printf("glGetError = %d\n", (int) glGetError());
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/vptest2.c b/tests/mesa/tests/vptest2.c
new file mode 100644
index 00000000..2158e07f
--- /dev/null
+++ b/tests/mesa/tests/vptest2.c
@@ -0,0 +1,151 @@
+/* Test vertex state program execution */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ glPushMatrix();
+ glutSolidCube(2.0);
+ glPopMatrix();
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Test1( void )
+{
+ static const GLfloat p[4] = {9, 8, 7, 6};
+ GLfloat q[4];
+ /* test addition */
+ static const char *prog =
+ "!!VSP1.0\n"
+ "MOV R0, c[0];\n"
+ "MOV R1, c[1];\n"
+ "ADD c[2], R0, R1;\n"
+ "END\n";
+
+ glLoadProgramNV(GL_VERTEX_STATE_PROGRAM_NV, 1,
+ strlen(prog),
+ (const GLubyte *) prog);
+ assert(glIsProgramNV(1));
+
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 0, 1, 2, 3, 4);
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 1, 10, 20, 30, 40);
+
+ glExecuteProgramNV(GL_VERTEX_STATE_PROGRAM_NV, 1, p);
+
+ glGetProgramParameterfvNV(GL_VERTEX_PROGRAM_NV, 2, GL_PROGRAM_PARAMETER_NV, q);
+ printf("Result c[2] = %g %g %g %g (should be 11 22 33 44)\n",
+ q[0], q[1], q[2], q[3]);
+}
+
+
+static void Test2( void )
+{
+ static const GLfloat p[4] = {9, 8, 7, 6};
+ GLfloat q[4];
+ /* test swizzling */
+ static const char *prog =
+ "!!VSP1.0\n"
+ "MOV R0, c[0].wzyx;\n"
+ "MOV R1, c[1].wzyx;\n"
+ "ADD c[2], R0, R1;\n"
+ "END\n";
+
+ glLoadProgramNV(GL_VERTEX_STATE_PROGRAM_NV, 1,
+ strlen(prog),
+ (const GLubyte *) prog);
+ assert(glIsProgramNV(1));
+
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 0, 1, 2, 3, 4);
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 1, 10, 20, 30, 40);
+
+ glExecuteProgramNV(GL_VERTEX_STATE_PROGRAM_NV, 1, p);
+
+ glGetProgramParameterfvNV(GL_VERTEX_PROGRAM_NV, 2, GL_PROGRAM_PARAMETER_NV, q);
+ printf("Result c[2] = %g %g %g %g (should be 44 33 22 11)\n",
+ q[0], q[1], q[2], q[3]);
+}
+
+
+static void Test3( void )
+{
+ static const GLfloat p[4] = {0, 0, 0, 0};
+ GLfloat q[4];
+ /* normalize vector */
+ static const char *prog =
+ "!!VSP1.0\n"
+ "# c[0] = (nx,ny,nz)\n"
+ "# R0.xyz = normalize(R1)\n"
+ "# R0.w = 1/sqrt(nx*nx + ny*ny + nz*nz)\n"
+ "# c[2] = R0\n"
+ "DP3 R0.w, c[0], c[0];\n"
+ "RSQ R0.w, R0.w;\n"
+ "MUL R0.xyz, c[0], R0.w;\n"
+ "MOV c[2], R0;\n"
+ "END\n";
+
+ glLoadProgramNV(GL_VERTEX_STATE_PROGRAM_NV, 1,
+ strlen(prog),
+ (const GLubyte *) prog);
+ assert(glIsProgramNV(1));
+
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 0, 0, 10, 0, 0);
+
+ glExecuteProgramNV(GL_VERTEX_STATE_PROGRAM_NV, 1, p);
+
+ glGetProgramParameterfvNV(GL_VERTEX_PROGRAM_NV, 2, GL_PROGRAM_PARAMETER_NV, q);
+ printf("Result c[2] = %g %g %g %g (should be 0, 1, 0, 0.1)\n",
+ q[0], q[1], q[2], q[3]);
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 50, 50 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Test1();
+ Test2();
+ Test3();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/vptest3.c b/tests/mesa/tests/vptest3.c
new file mode 100644
index 00000000..2c5c8000
--- /dev/null
+++ b/tests/mesa/tests/vptest3.c
@@ -0,0 +1,120 @@
+/* Test glGenProgramsNV(), glIsProgramNV(), glLoadProgramNV() */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Zrot = 0.0;
+
+
+static void Display( void )
+{
+ glClearColor(0.3, 0.3, 0.3, 1);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glEnable(GL_VERTEX_PROGRAM_NV);
+
+ glLoadIdentity();
+ glRotatef(Zrot, 0, 0, 1);
+
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW, GL_IDENTITY_NV);
+ glPushMatrix();
+
+ glVertexAttrib3fNV(3, 1, 0.5, 0.25);
+ glBegin(GL_TRIANGLES);
+#if 1
+ glVertexAttrib3fNV(3, 1.0, 0.0, 0.0);
+ glVertexAttrib2fNV(0, -0.5, -0.5);
+ glVertexAttrib3fNV(3, 0.0, 1.0, 0.0);
+ glVertexAttrib2fNV(0, 0.5, -0.5);
+ glVertexAttrib3fNV(3, 0.0, 0.0, 1.0);
+ glVertexAttrib2fNV(0, 0, 0.5);
+#else
+ glVertex2f( -1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 0, 1);
+#endif
+ glEnd();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ /* glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
+ glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ /*glTranslatef( 0.0, 0.0, -15.0 );*/
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'z':
+ Zrot -= 5.0;
+ break;
+ case 'Z':
+ Zrot += 5.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ static const char *prog1 =
+ "!!VP1.0\n"
+ "MOV o[COL0], v[COL0];\n"
+#if 0
+ "MOV o[HPOS], v[OPOS];\n"
+#else
+ "DP4 o[HPOS].x, v[OPOS], c[0];\n"
+ "DP4 o[HPOS].y, v[OPOS], c[1];\n"
+ "DP4 o[HPOS].z, v[OPOS], c[2];\n"
+ "DP4 o[HPOS].w, v[OPOS], c[3];\n"
+#endif
+ "END\n";
+
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 1,
+ strlen(prog1),
+ (const GLubyte *) prog1);
+ assert(glIsProgramNV(1));
+
+ glBindProgramNV(GL_VERTEX_PROGRAM_NV, 1);
+
+ printf("glGetError = %d\n", (int) glGetError());
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/vptorus.c b/tests/mesa/tests/vptorus.c
new file mode 100644
index 00000000..764dea4e
--- /dev/null
+++ b/tests/mesa/tests/vptorus.c
@@ -0,0 +1,174 @@
+/*
+ * A lit, rotating torus via vertex program
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Xrot = 0.0, Yrot = 0.0, Zrot = 0.0;
+static GLboolean Anim = GL_TRUE;
+
+
+static void Idle( void )
+{
+ Xrot += .3;
+ Yrot += .4;
+ Zrot += .2;
+ glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+ glutSolidTorus(0.75, 2.0, 10, 20);
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -12.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case ' ':
+ Xrot = Yrot = Zrot = 0;
+ break;
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'z':
+ Zrot -= 5.0;
+ break;
+ case 'Z':
+ Zrot += 5.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ /* borrowed from an nvidia demo:
+ * c[0..3] = modelview matrix
+ * c[4..7] = inverse modelview matrix
+ * c[32] = light pos
+ * c[35] = diffuse color
+ */
+ static const char prog[] =
+ "!!VP1.0\n"
+ "#Simple transform and diffuse lighting\n"
+ "\n"
+ "DP4 o[HPOS].x, c[0], v[OPOS] ; # object x MVP -> clip\n"
+ "DP4 o[HPOS].y, c[1], v[OPOS] ;\n"
+ "DP4 o[HPOS].z, c[2], v[OPOS] ;\n"
+ "DP4 o[HPOS].w, c[3], v[OPOS] ;\n"
+
+ "DP3 R1.x, c[4], v[NRML] ; # normal x MV-1T -> lighting normal\n"
+ "DP3 R1.y, c[5], v[NRML] ;\n"
+ "DP3 R1.z, c[6], v[NRML] ;\n"
+
+ "DP3 R0, c[32], R1 ; # L.N\n"
+ "MUL o[COL0].xyz, R0, c[35] ; # col = L.N * diffuse\n"
+ "MOV o[TEX0], v[TEX0];\n"
+ "END";
+
+ if (!glutExtensionSupported("GL_NV_vertex_program")) {
+ printf("Sorry, this program requires GL_NV_vertex_program");
+ exit(1);
+ }
+
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 1,
+ strlen(prog), (const GLubyte *) prog);
+ assert(glIsProgramNV(1));
+ glBindProgramNV(GL_VERTEX_PROGRAM_NV, 1);
+
+ /* Load the program registers */
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV);
+
+ /* Light position */
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 32, 2, 2, 4, 1);
+ /* Diffuse material color */
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 35, 0.25, 0, 0.25, 1);
+
+ glEnable(GL_VERTEX_PROGRAM_NV);
+ glEnable(GL_DEPTH_TEST);
+ glClearColor(0.3, 0.3, 0.3, 1);
+
+ printf("glGetError = %d\n", (int) glGetError());
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/vpwarpmesh.c b/tests/mesa/tests/vpwarpmesh.c
new file mode 100644
index 00000000..56aa8200
--- /dev/null
+++ b/tests/mesa/tests/vpwarpmesh.c
@@ -0,0 +1,236 @@
+/*
+ * Warp a triangle mesh with a vertex program.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Xrot = -60.0, Yrot = 0.0, Zrot = 0.0;
+static GLboolean Anim = GL_TRUE;
+static GLfloat Phi = 0.0;
+
+
+static void Idle( void )
+{
+ Phi += 0.01;
+ glutPostRedisplay();
+}
+
+
+static void DrawMesh( int rows, int cols )
+{
+ static const GLfloat colorA[3] = { 0, 1, 0 };
+ static const GLfloat colorB[3] = { 0, 0, 1 };
+ const float dx = 2.0 / (cols - 1);
+ const float dy = 2.0 / (rows - 1);
+ float x, y;
+ int i, j;
+
+#if 1
+#define COLOR3FV(c) glVertexAttrib3fvNV(3, c)
+#define VERTEX2F(x, y) glVertexAttrib2fNV(0, x, y)
+#else
+#define COLOR3FV(c) glColor3fv(c)
+#define VERTEX2F(x, y) glVertex2f(x, y)
+#endif
+
+ y = -1.0;
+ for (i = 0; i < rows - 1; i++) {
+ glBegin(GL_QUAD_STRIP);
+ x = -1.0;
+ for (j = 0; j < cols; j++) {
+ if ((i + j) & 1)
+ COLOR3FV(colorA);
+ else
+ COLOR3FV(colorB);
+ VERTEX2F(x, y);
+ VERTEX2F(x, y + dy);
+ x += dx;
+ }
+ glEnd();
+ y += dy;
+ }
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+
+ /* Position the gravity source */
+ {
+ GLfloat x, y, z, r = 0.5;
+ x = r * cos(Phi);
+ y = r * sin(Phi);
+ z = 1.0;
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 30, x, y, z, 1);
+ glDisable(GL_VERTEX_PROGRAM_NV);
+ glBegin(GL_POINTS);
+ glColor3f(1,1,1);
+ glVertex3f(x, y, z);
+ glEnd();
+ }
+
+ glEnable(GL_VERTEX_PROGRAM_NV);
+ DrawMesh(8, 8);
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ float ar = (float) width / (float) height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0 * ar, 1.0 * ar, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -12.0 );
+ glScalef(2, 2, 2);
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'p':
+ Phi += 0.2;
+ break;
+ case 'z':
+ Zrot -= 5.0;
+ break;
+ case 'Z':
+ Zrot += 5.0;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ /*
+ * c[0..3] = modelview matrix
+ * c[4..7] = inverse modelview matrix
+ * c[30] = gravity source location
+ * c[31] = gravity source strength
+ * c[32] = light pos
+ * c[35] = diffuse color
+ */
+ static const char prog[] =
+ "!!VP1.0\n"
+
+ "# Compute distance from vertex to gravity source\n"
+ "ADD R1, c[30], -v[OPOS]; # vector from vertex to gravity\n"
+ "DP3 R2, R1, R1; # dot product\n"
+ "RSQ R2, R2.x; # square root = distance\n"
+ "MUL R2, R2, c[31].xxxx; # scale by the gravity factor\n"
+
+ "# Displace vertex by gravity factor along R1 vector\n"
+ "MAD R3, R1, R2, v[OPOS];\n"
+
+ "# Continue with typical modelview/projection\n"
+ "DP4 o[HPOS].x, c[0], R3 ; # object x MVP -> clip\n"
+ "DP4 o[HPOS].y, c[1], R3 ;\n"
+ "DP4 o[HPOS].z, c[2], R3 ;\n"
+ "DP4 o[HPOS].w, c[3], R3 ;\n"
+
+ "MOV o[COL0], v[COL0];\n # copy input color to output color\n"
+
+ "END";
+
+ if (!glutExtensionSupported("GL_NV_vertex_program")) {
+ printf("Sorry, this program requires GL_NV_vertex_program\n");
+ exit(1);
+ }
+
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 1,
+ strlen(prog), (const GLubyte *) prog);
+ assert(glIsProgramNV(1));
+ glBindProgramNV(GL_VERTEX_PROGRAM_NV, 1);
+
+ /* Load the program registers */
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV);
+
+ /* Light position */
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 32, 2, 2, 4, 1);
+ /* Diffuse material color */
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 35, 0.25, 0, 0.25, 1);
+
+ /* Gravity strength */
+ glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 31, .5, 0, 0, 0);
+
+ glEnable(GL_DEPTH_TEST);
+ glClearColor(0.3, 0.3, 0.3, 1);
+ glShadeModel(GL_FLAT);
+ glPointSize(3);
+ printf("glGetError = %d\n", (int) glGetError());
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 250, 250 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/yuvrect.c b/tests/mesa/tests/yuvrect.c
new file mode 100644
index 00000000..acef4060
--- /dev/null
+++ b/tests/mesa/tests/yuvrect.c
@@ -0,0 +1,193 @@
+/*
+ * Test the GL_NV_texture_rectangle and GL_MESA_ycrcb_texture extensions.
+ *
+ * Brian Paul 13 September 2002
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+#include "../util/readtex.c" /* I know, this is a hack. */
+
+#define TEXTURE_FILE "../images/girl.rgb"
+
+static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
+static GLint ImgWidth, ImgHeight;
+static GLushort *ImageYUV = NULL;
+
+
+static void DrawObject(void)
+{
+ glBegin(GL_QUADS);
+
+ glTexCoord2f(0, 0);
+ glVertex2f(-1.0, -1.0);
+
+ glTexCoord2f(ImgWidth, 0);
+ glVertex2f(1.0, -1.0);
+
+ glTexCoord2f(ImgWidth, ImgHeight);
+ glVertex2f(1.0, 1.0);
+
+ glTexCoord2f(0, ImgHeight);
+ glVertex2f(-1.0, 1.0);
+
+ glEnd();
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ DrawObject();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+
+static void Init( int argc, char *argv[] )
+{
+ GLuint texObj = 100;
+ const char *file;
+
+ if (!glutExtensionSupported("GL_NV_texture_rectangle")) {
+ printf("Sorry, GL_NV_texture_rectangle is required\n");
+ exit(0);
+ }
+
+ if (!glutExtensionSupported("GL_MESA_ycbcr_texture")) {
+ printf("Sorry, GL_MESA_ycbcr_texture is required\n");
+ exit(0);
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_NV, texObj);
+#ifdef LINEAR_FILTER
+ /* linear filtering looks much nicer but is much slower for Mesa */
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#else
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#endif
+
+ if (argc > 1)
+ file = argv[1];
+ else
+ file = TEXTURE_FILE;
+
+ ImageYUV = LoadYUVImage(file, &ImgWidth, &ImgHeight);
+ if (!ImageYUV) {
+ printf("Couldn't read %s\n", TEXTURE_FILE);
+ exit(0);
+ }
+
+ printf("Image: %dx%d\n", ImgWidth, ImgHeight);
+
+ glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0,
+ GL_YCBCR_MESA, ImgWidth, ImgHeight, 0,
+ GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, ImageYUV);
+
+ assert(glGetError() == GL_NO_ERROR);
+ glTexSubImage2D(GL_TEXTURE_RECTANGLE_NV, 0,
+ 0, 0, ImgWidth, ImgHeight,
+ GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, ImageYUV);
+
+ assert(glGetError() == GL_NO_ERROR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glEnable(GL_TEXTURE_RECTANGLE_NV);
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.3, 0.3, 0.4, 1.0);
+
+ if (argc > 1 && strcmp(argv[1], "-info")==0) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowSize( 300, 300 );
+ glutInitWindowPosition( 0, 0 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0] );
+
+ Init( argc, argv );
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/yuvsquare.c b/tests/mesa/tests/yuvsquare.c
new file mode 100644
index 00000000..3601e7a3
--- /dev/null
+++ b/tests/mesa/tests/yuvsquare.c
@@ -0,0 +1,232 @@
+/*
+ * Test the GL_NV_texture_rectangle and GL_MESA_ycrcb_texture extensions.
+ *
+ * Brian Paul 13 September 2002
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+#include "../util/readtex.c" /* I know, this is a hack. */
+
+#define TEXTURE_FILE "../images/tile.rgb"
+
+static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
+static GLint ImgWidth, ImgHeight;
+static GLushort *ImageYUV = NULL;
+static GLubyte *ImageRGB = NULL;
+static const GLuint yuvObj = 100;
+static const GLuint rgbObj = 101;
+
+
+static void DrawObject(void)
+{
+ glBegin(GL_QUADS);
+
+ glTexCoord2f(0, 0);
+ glVertex2f(-1.0, -1.0);
+
+ glTexCoord2f(1, 0);
+ glVertex2f(1.0, -1.0);
+
+ glTexCoord2f(1, 1);
+ glVertex2f(1.0, 1.0);
+
+ glTexCoord2f(0, 1);
+ glVertex2f(-1.0, 1.0);
+
+ glEnd();
+}
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glTranslatef( -1.1, 0.0, -15.0 );
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ glBindTexture(GL_TEXTURE_2D, yuvObj);
+ DrawObject();
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef( 1.1, 0.0, -15.0 );
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ glBindTexture(GL_TEXTURE_2D, rgbObj);
+ DrawObject();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.1, 1.1, -1.1, 1.1, 10.0, 100.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void SpecialKey( int key, int x, int y )
+{
+ float step = 3.0;
+ (void) x;
+ (void) y;
+
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot += step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot -= step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
+
+
+
+/* #define LINEAR_FILTER */
+
+static void Init( int argc, char *argv[] )
+{
+ const char *file;
+ GLenum format;
+
+ if (!glutExtensionSupported("GL_MESA_ycbcr_texture")) {
+ printf("Sorry, GL_MESA_ycbcr_texture is required\n");
+ exit(0);
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ if (argc > 1)
+ file = argv[1];
+ else
+ file = TEXTURE_FILE;
+
+ /* First load the texture as YCbCr.
+ */
+
+ glBindTexture(GL_TEXTURE_2D, yuvObj);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ ImageYUV = LoadYUVImage(file, &ImgWidth, &ImgHeight );
+ if (!ImageYUV) {
+ printf("Couldn't read %s\n", TEXTURE_FILE);
+ exit(0);
+ }
+
+ printf("Image: %dx%d\n", ImgWidth, ImgHeight);
+
+
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_YCBCR_MESA,
+ ImgWidth, ImgHeight, 0,
+ GL_YCBCR_MESA,
+ GL_UNSIGNED_SHORT_8_8_MESA, ImageYUV);
+
+ glEnable(GL_TEXTURE_2D);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+
+
+ /* Now load the texture as RGB.
+ */
+
+ glBindTexture(GL_TEXTURE_2D, rgbObj);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ ImageRGB = LoadRGBImage(file, &ImgWidth, &ImgHeight, &format );
+ if (!ImageRGB) {
+ printf("Couldn't read %s\n", TEXTURE_FILE);
+ exit(0);
+ }
+
+ printf("Image: %dx%d\n", ImgWidth, ImgHeight);
+
+
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ format,
+ ImgWidth, ImgHeight, 0,
+ format,
+ GL_UNSIGNED_BYTE, ImageRGB);
+
+ glEnable(GL_TEXTURE_2D);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.3, 0.3, 0.4, 1.0);
+
+ if (argc > 1 && strcmp(argv[1], "-info")==0) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+
+ printf( "Both images should appear the same.\n" );
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowSize( 300, 300 );
+ glutInitWindowPosition( 0, 0 );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glutCreateWindow(argv[0] );
+
+ Init( argc, argv );
+
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/tests/zreaddraw.c b/tests/mesa/tests/zreaddraw.c
new file mode 100644
index 00000000..e2dacbf7
--- /dev/null
+++ b/tests/mesa/tests/zreaddraw.c
@@ -0,0 +1,116 @@
+/*
+ * Test glRead/DrawPixels for GL_DEPTH_COMPONENT, with pixelzoom.
+ *
+ * Brian Paul
+ * 23 August 2003
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static GLint WinWidth = 500, WinHeight = 500;
+
+
+static void Display(void)
+{
+ GLfloat depth[100 * 100];
+ GLfloat depth2[400 * 400];
+ GLfloat min, max;
+ int i;
+
+ glClearColor(0.5, 0.5, 0.5, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ /* draw a sphere */
+ glViewport(0, 0, 100, 100);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1, 1, -1, 1, -1, 0); /* clip away back half of sphere */
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glutSolidSphere(1.0, 20, 10);
+
+ /* read the depth image */
+ glReadPixels(0, 0, 100, 100, GL_DEPTH_COMPONENT, GL_FLOAT, depth);
+ min = max = depth[0];
+ for (i = 1; i < 100 * 100; i++) {
+ if (depth[i] < min)
+ min = depth[i];
+ if (depth[i] > max)
+ max = depth[i];
+ }
+ printf("Depth value range: [%f, %f]\n", min, max);
+
+ /* draw depth image with scaling (into z buffer) */
+ glPixelZoom(4.0, 4.0);
+ glWindowPos2i(100, 0);
+ glDrawPixels(100, 100, GL_DEPTH_COMPONENT, GL_FLOAT, depth);
+
+ /* read back scaled depth image */
+ glReadPixels(100, 0, 400, 400, GL_DEPTH_COMPONENT, GL_FLOAT, depth2);
+ /* draw as luminance */
+ glPixelZoom(1.0, 1.0);
+ glDrawPixels(400, 400, GL_LUMINANCE, GL_FLOAT, depth2);
+
+ glutSwapBuffers();
+}
+
+
+static void Reshape(int width, int height)
+{
+ WinWidth = width;
+ WinHeight = height;
+ glViewport(0, 0, width, height);
+}
+
+
+static void Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init(void)
+{
+ const GLfloat blue[4] = {.1, .1, 1.0, 0.0};
+ const GLfloat gray[4] = {0.2, 0.2, 0.2, 1.0};
+ const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
+ const GLfloat pos[4] = {0, 0, 10, 0};
+
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, blue);
+ glLightfv(GL_LIGHT0, GL_AMBIENT, gray);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+}
+
+
+int main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(WinWidth, WinHeight);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Display);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/util/CMakeLists.txt b/tests/mesa/util/CMakeLists.txt
new file mode 100644
index 00000000..96b51ae5
--- /dev/null
+++ b/tests/mesa/util/CMakeLists.txt
@@ -0,0 +1,21 @@
+
+include_directories( ${OPENGL_INCLUDE_PATH} )
+link_libraries (
+ ${OPENGL_gl_LIBRARY}
+ ${OPENGL_glu_LIBRARY}
+ ${TIFF_LIBRARY}
+)
+
+add_library (mesautil
+ dumpstate.c
+ glstate.c
+ idproj.c
+ matrix.c
+ readtex.c
+ trackball.c
+ errcheck.c
+ glutskel.c
+ imagesgi.cpp
+ showbuffer.c
+ winpos.c
+)
diff --git a/tests/mesa/util/dumpstate.c b/tests/mesa/util/dumpstate.c
new file mode 100644
index 00000000..0047c942
--- /dev/null
+++ b/tests/mesa/util/dumpstate.c
@@ -0,0 +1,1958 @@
+
+/*
+ *
+ * From: Stephane Rehel <rehel@worldnet.fr>
+ * Date: Mon, 31 May 1999 18:40:54 -0400
+ * To: Paul Brian <brianp@ra.avid.com>
+ * Subject: OpenGL State Dump Function
+ *
+ * Here is a function that dumps the current OpenGL state. I wrote it
+ * some time ago.
+ *
+ * In the attachment:
+ * + the code itself
+ * + its output
+ *
+ * I think Mesa is wrong on some getBooleanv(). For example, GL_VERTEX_ARRAY
+ * is queried by IsEnabled() (cf. p. 196 of the spec). But on page 193
+ * we can read that all the boolean attribs that can be queried by IsEnabled()
+ * can also be queried by IsEnabled().
+ *
+ * I had duplicated all the enums (LOCAL_*) so that the code can run on any
+ * OpenGL version, even if an enum is not recognized.
+ *
+ * The code can be shipped in the public domain.
+ *
+ * Stephane.
+ */
+
+
+/*
+ * Stephane Rehel
+ * Creation: February 5 1999
+ */
+
+#include <stdio.h>
+#include <GL/gl.h>
+
+/***************************************************************************/
+
+enum {
+ /* Data types */
+ LOCAL_GL_BYTE = 0x1400,
+ LOCAL_GL_UNSIGNED_BYTE = 0x1401,
+ LOCAL_GL_SHORT = 0x1402,
+ LOCAL_GL_UNSIGNED_SHORT = 0x1403,
+ LOCAL_GL_INT = 0x1404,
+ LOCAL_GL_UNSIGNED_INT = 0x1405,
+ LOCAL_GL_FLOAT = 0x1406,
+ LOCAL_GL_DOUBLE = 0x140A,
+ LOCAL_GL_2_BYTES = 0x1407,
+ LOCAL_GL_3_BYTES = 0x1408,
+ LOCAL_GL_4_BYTES = 0x1409,
+
+ /* Primitives */
+ LOCAL_GL_LINES = 0x0001,
+ LOCAL_GL_POINTS = 0x0000,
+ LOCAL_GL_LINE_STRIP = 0x0003,
+ LOCAL_GL_LINE_LOOP = 0x0002,
+ LOCAL_GL_TRIANGLES = 0x0004,
+ LOCAL_GL_TRIANGLE_STRIP = 0x0005,
+ LOCAL_GL_TRIANGLE_FAN = 0x0006,
+ LOCAL_GL_QUADS = 0x0007,
+ LOCAL_GL_QUAD_STRIP = 0x0008,
+ LOCAL_GL_POLYGON = 0x0009,
+ LOCAL_GL_EDGE_FLAG = 0x0B43,
+
+ /* Vertex Arrays */
+ LOCAL_GL_VERTEX_ARRAY = 0x8074,
+ LOCAL_GL_NORMAL_ARRAY = 0x8075,
+ LOCAL_GL_COLOR_ARRAY = 0x8076,
+ LOCAL_GL_INDEX_ARRAY = 0x8077,
+ LOCAL_GL_TEXTURE_COORD_ARRAY = 0x8078,
+ LOCAL_GL_EDGE_FLAG_ARRAY = 0x8079,
+ LOCAL_GL_VERTEX_ARRAY_SIZE = 0x807A,
+ LOCAL_GL_VERTEX_ARRAY_TYPE = 0x807B,
+ LOCAL_GL_VERTEX_ARRAY_STRIDE = 0x807C,
+ LOCAL_GL_NORMAL_ARRAY_TYPE = 0x807E,
+ LOCAL_GL_NORMAL_ARRAY_STRIDE = 0x807F,
+ LOCAL_GL_COLOR_ARRAY_SIZE = 0x8081,
+ LOCAL_GL_COLOR_ARRAY_TYPE = 0x8082,
+ LOCAL_GL_COLOR_ARRAY_STRIDE = 0x8083,
+ LOCAL_GL_INDEX_ARRAY_TYPE = 0x8085,
+ LOCAL_GL_INDEX_ARRAY_STRIDE = 0x8086,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_SIZE = 0x8088,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_TYPE = 0x8089,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_STRIDE = 0x808A,
+ LOCAL_GL_EDGE_FLAG_ARRAY_STRIDE = 0x808C,
+ LOCAL_GL_VERTEX_ARRAY_POINTER = 0x808E,
+ LOCAL_GL_NORMAL_ARRAY_POINTER = 0x808F,
+ LOCAL_GL_COLOR_ARRAY_POINTER = 0x8090,
+ LOCAL_GL_INDEX_ARRAY_POINTER = 0x8091,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_POINTER = 0x8092,
+ LOCAL_GL_EDGE_FLAG_ARRAY_POINTER = 0x8093,
+ LOCAL_GL_V2F = 0x2A20,
+ LOCAL_GL_V3F = 0x2A21,
+ LOCAL_GL_C4UB_V2F = 0x2A22,
+ LOCAL_GL_C4UB_V3F = 0x2A23,
+ LOCAL_GL_C3F_V3F = 0x2A24,
+ LOCAL_GL_N3F_V3F = 0x2A25,
+ LOCAL_GL_C4F_N3F_V3F = 0x2A26,
+ LOCAL_GL_T2F_V3F = 0x2A27,
+ LOCAL_GL_T4F_V4F = 0x2A28,
+ LOCAL_GL_T2F_C4UB_V3F = 0x2A29,
+ LOCAL_GL_T2F_C3F_V3F = 0x2A2A,
+ LOCAL_GL_T2F_N3F_V3F = 0x2A2B,
+ LOCAL_GL_T2F_C4F_N3F_V3F = 0x2A2C,
+ LOCAL_GL_T4F_C4F_N3F_V4F = 0x2A2D,
+
+ /* Matrix Mode */
+ LOCAL_GL_MATRIX_MODE = 0x0BA0,
+ LOCAL_GL_MODELVIEW = 0x1700,
+ LOCAL_GL_PROJECTION = 0x1701,
+ LOCAL_GL_TEXTURE = 0x1702,
+
+ /* Points */
+ LOCAL_GL_POINT_SMOOTH = 0x0B10,
+ LOCAL_GL_POINT_SIZE = 0x0B11,
+ LOCAL_GL_POINT_SIZE_GRANULARITY = 0x0B13,
+ LOCAL_GL_POINT_SIZE_RANGE = 0x0B12,
+
+ /* Lines */
+ LOCAL_GL_LINE_SMOOTH = 0x0B20,
+ LOCAL_GL_LINE_STIPPLE = 0x0B24,
+ LOCAL_GL_LINE_STIPPLE_PATTERN = 0x0B25,
+ LOCAL_GL_LINE_STIPPLE_REPEAT = 0x0B26,
+ LOCAL_GL_LINE_WIDTH = 0x0B21,
+ LOCAL_GL_LINE_WIDTH_GRANULARITY = 0x0B23,
+ LOCAL_GL_LINE_WIDTH_RANGE = 0x0B22,
+
+ /* Polygons */
+ LOCAL_GL_POINT = 0x1B00,
+ LOCAL_GL_LINE = 0x1B01,
+ LOCAL_GL_FILL = 0x1B02,
+ LOCAL_GL_CCW = 0x0901,
+ LOCAL_GL_CW = 0x0900,
+ LOCAL_GL_FRONT = 0x0404,
+ LOCAL_GL_BACK = 0x0405,
+ LOCAL_GL_CULL_FACE = 0x0B44,
+ LOCAL_GL_CULL_FACE_MODE = 0x0B45,
+ LOCAL_GL_POLYGON_SMOOTH = 0x0B41,
+ LOCAL_GL_POLYGON_STIPPLE = 0x0B42,
+ LOCAL_GL_FRONT_FACE = 0x0B46,
+ LOCAL_GL_POLYGON_MODE = 0x0B40,
+ LOCAL_GL_POLYGON_OFFSET_FACTOR = 0x8038,
+ LOCAL_GL_POLYGON_OFFSET_UNITS = 0x2A00,
+ LOCAL_GL_POLYGON_OFFSET_POINT = 0x2A01,
+ LOCAL_GL_POLYGON_OFFSET_LINE = 0x2A02,
+ LOCAL_GL_POLYGON_OFFSET_FILL = 0x8037,
+
+ /* Display Lists */
+ LOCAL_GL_COMPILE = 0x1300,
+ LOCAL_GL_COMPILE_AND_EXECUTE = 0x1301,
+ LOCAL_GL_LIST_BASE = 0x0B32,
+ LOCAL_GL_LIST_INDEX = 0x0B33,
+ LOCAL_GL_LIST_MODE = 0x0B30,
+
+ /* Depth buffer */
+ LOCAL_GL_NEVER = 0x0200,
+ LOCAL_GL_LESS = 0x0201,
+ LOCAL_GL_GEQUAL = 0x0206,
+ LOCAL_GL_LEQUAL = 0x0203,
+ LOCAL_GL_GREATER = 0x0204,
+ LOCAL_GL_NOTEQUAL = 0x0205,
+ LOCAL_GL_EQUAL = 0x0202,
+ LOCAL_GL_ALWAYS = 0x0207,
+ LOCAL_GL_DEPTH_TEST = 0x0B71,
+ LOCAL_GL_DEPTH_BITS = 0x0D56,
+ LOCAL_GL_DEPTH_CLEAR_VALUE = 0x0B73,
+ LOCAL_GL_DEPTH_FUNC = 0x0B74,
+ LOCAL_GL_DEPTH_RANGE = 0x0B70,
+ LOCAL_GL_DEPTH_WRITEMASK = 0x0B72,
+ LOCAL_GL_DEPTH_COMPONENT = 0x1902,
+
+ /* Lighting */
+ LOCAL_GL_LIGHTING = 0x0B50,
+ LOCAL_GL_LIGHT0 = 0x4000,
+ LOCAL_GL_LIGHT1 = 0x4001,
+ LOCAL_GL_LIGHT2 = 0x4002,
+ LOCAL_GL_LIGHT3 = 0x4003,
+ LOCAL_GL_LIGHT4 = 0x4004,
+ LOCAL_GL_LIGHT5 = 0x4005,
+ LOCAL_GL_LIGHT6 = 0x4006,
+ LOCAL_GL_LIGHT7 = 0x4007,
+ LOCAL_GL_SPOT_EXPONENT = 0x1205,
+ LOCAL_GL_SPOT_CUTOFF = 0x1206,
+ LOCAL_GL_CONSTANT_ATTENUATION = 0x1207,
+ LOCAL_GL_LINEAR_ATTENUATION = 0x1208,
+ LOCAL_GL_QUADRATIC_ATTENUATION = 0x1209,
+ LOCAL_GL_AMBIENT = 0x1200,
+ LOCAL_GL_DIFFUSE = 0x1201,
+ LOCAL_GL_SPECULAR = 0x1202,
+ LOCAL_GL_SHININESS = 0x1601,
+ LOCAL_GL_EMISSION = 0x1600,
+ LOCAL_GL_POSITION = 0x1203,
+ LOCAL_GL_SPOT_DIRECTION = 0x1204,
+ LOCAL_GL_AMBIENT_AND_DIFFUSE = 0x1602,
+ LOCAL_GL_COLOR_INDEXES = 0x1603,
+ LOCAL_GL_LIGHT_MODEL_TWO_SIDE = 0x0B52,
+ LOCAL_GL_LIGHT_MODEL_LOCAL_VIEWER = 0x0B51,
+ LOCAL_GL_LIGHT_MODEL_AMBIENT = 0x0B53,
+ LOCAL_GL_FRONT_AND_BACK = 0x0408,
+ LOCAL_GL_SHADE_MODEL = 0x0B54,
+ LOCAL_GL_FLAT = 0x1D00,
+ LOCAL_GL_SMOOTH = 0x1D01,
+ LOCAL_GL_COLOR_MATERIAL = 0x0B57,
+ LOCAL_GL_COLOR_MATERIAL_FACE = 0x0B55,
+ LOCAL_GL_COLOR_MATERIAL_PARAMETER = 0x0B56,
+ LOCAL_GL_NORMALIZE = 0x0BA1,
+
+ /* User clipping planes */
+ LOCAL_GL_CLIP_PLANE0 = 0x3000,
+ LOCAL_GL_CLIP_PLANE1 = 0x3001,
+ LOCAL_GL_CLIP_PLANE2 = 0x3002,
+ LOCAL_GL_CLIP_PLANE3 = 0x3003,
+ LOCAL_GL_CLIP_PLANE4 = 0x3004,
+ LOCAL_GL_CLIP_PLANE5 = 0x3005,
+
+ /* Accumulation buffer */
+ LOCAL_GL_ACCUM_RED_BITS = 0x0D58,
+ LOCAL_GL_ACCUM_GREEN_BITS = 0x0D59,
+ LOCAL_GL_ACCUM_BLUE_BITS = 0x0D5A,
+ LOCAL_GL_ACCUM_ALPHA_BITS = 0x0D5B,
+ LOCAL_GL_ACCUM_CLEAR_VALUE = 0x0B80,
+ LOCAL_GL_ACCUM = 0x0100,
+ LOCAL_GL_ADD = 0x0104,
+ LOCAL_GL_LOAD = 0x0101,
+ LOCAL_GL_MULT = 0x0103,
+ LOCAL_GL_RETURN = 0x0102,
+
+ /* Alpha testing */
+ LOCAL_GL_ALPHA_TEST = 0x0BC0,
+ LOCAL_GL_ALPHA_TEST_REF = 0x0BC2,
+ LOCAL_GL_ALPHA_TEST_FUNC = 0x0BC1,
+
+ /* Blending */
+ LOCAL_GL_BLEND = 0x0BE2,
+ LOCAL_GL_BLEND_SRC = 0x0BE1,
+ LOCAL_GL_BLEND_DST = 0x0BE0,
+ LOCAL_GL_ZERO = 0,
+ LOCAL_GL_ONE = 1,
+ LOCAL_GL_SRC_COLOR = 0x0300,
+ LOCAL_GL_ONE_MINUS_SRC_COLOR = 0x0301,
+ LOCAL_GL_DST_COLOR = 0x0306,
+ LOCAL_GL_ONE_MINUS_DST_COLOR = 0x0307,
+ LOCAL_GL_SRC_ALPHA = 0x0302,
+ LOCAL_GL_ONE_MINUS_SRC_ALPHA = 0x0303,
+ LOCAL_GL_DST_ALPHA = 0x0304,
+ LOCAL_GL_ONE_MINUS_DST_ALPHA = 0x0305,
+ LOCAL_GL_SRC_ALPHA_SATURATE = 0x0308,
+ LOCAL_GL_CONSTANT_COLOR = 0x8001,
+ LOCAL_GL_ONE_MINUS_CONSTANT_COLOR = 0x8002,
+ LOCAL_GL_CONSTANT_ALPHA = 0x8003,
+ LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA = 0x8004,
+
+ /* Render Mode */
+ LOCAL_GL_FEEDBACK = 0x1C01,
+ LOCAL_GL_RENDER = 0x1C00,
+ LOCAL_GL_SELECT = 0x1C02,
+
+ /* Feedback */
+ LOCAL_GL_2D = 0x0600,
+ LOCAL_GL_3D = 0x0601,
+ LOCAL_GL_3D_COLOR = 0x0602,
+ LOCAL_GL_3D_COLOR_TEXTURE = 0x0603,
+ LOCAL_GL_4D_COLOR_TEXTURE = 0x0604,
+ LOCAL_GL_POINT_TOKEN = 0x0701,
+ LOCAL_GL_LINE_TOKEN = 0x0702,
+ LOCAL_GL_LINE_RESET_TOKEN = 0x0707,
+ LOCAL_GL_POLYGON_TOKEN = 0x0703,
+ LOCAL_GL_BITMAP_TOKEN = 0x0704,
+ LOCAL_GL_DRAW_PIXEL_TOKEN = 0x0705,
+ LOCAL_GL_COPY_PIXEL_TOKEN = 0x0706,
+ LOCAL_GL_PASS_THROUGH_TOKEN = 0x0700,
+ LOCAL_GL_FEEDBACK_BUFFER_POINTER = 0x0DF0,
+ LOCAL_GL_FEEDBACK_BUFFER_SIZE = 0x0DF1,
+ LOCAL_GL_FEEDBACK_BUFFER_TYPE = 0x0DF2,
+
+ /* Selection */
+ LOCAL_GL_SELECTION_BUFFER_POINTER = 0x0DF3,
+ LOCAL_GL_SELECTION_BUFFER_SIZE = 0x0DF4,
+
+ /* Fog */
+ LOCAL_GL_FOG = 0x0B60,
+ LOCAL_GL_FOG_MODE = 0x0B65,
+ LOCAL_GL_FOG_DENSITY = 0x0B62,
+ LOCAL_GL_FOG_COLOR = 0x0B66,
+ LOCAL_GL_FOG_INDEX = 0x0B61,
+ LOCAL_GL_FOG_START = 0x0B63,
+ LOCAL_GL_FOG_END = 0x0B64,
+ LOCAL_GL_LINEAR = 0x2601,
+ LOCAL_GL_EXP = 0x0800,
+ LOCAL_GL_EXP2 = 0x0801,
+
+ /* Logic Ops */
+ LOCAL_GL_LOGIC_OP = 0x0BF1,
+ LOCAL_GL_INDEX_LOGIC_OP = 0x0BF1,
+ LOCAL_GL_COLOR_LOGIC_OP = 0x0BF2,
+ LOCAL_GL_LOGIC_OP_MODE = 0x0BF0,
+ LOCAL_GL_CLEAR = 0x1500,
+ LOCAL_GL_SET = 0x150F,
+ LOCAL_GL_COPY = 0x1503,
+ LOCAL_GL_COPY_INVERTED = 0x150C,
+ LOCAL_GL_NOOP = 0x1505,
+ LOCAL_GL_INVERT = 0x150A,
+ LOCAL_GL_AND = 0x1501,
+ LOCAL_GL_NAND = 0x150E,
+ LOCAL_GL_OR = 0x1507,
+ LOCAL_GL_NOR = 0x1508,
+ LOCAL_GL_XOR = 0x1506,
+ LOCAL_GL_EQUIV = 0x1509,
+ LOCAL_GL_AND_REVERSE = 0x1502,
+ LOCAL_GL_AND_INVERTED = 0x1504,
+ LOCAL_GL_OR_REVERSE = 0x150B,
+ LOCAL_GL_OR_INVERTED = 0x150D,
+
+ /* Stencil */
+ LOCAL_GL_STENCIL_TEST = 0x0B90,
+ LOCAL_GL_STENCIL_WRITEMASK = 0x0B98,
+ LOCAL_GL_STENCIL_BITS = 0x0D57,
+ LOCAL_GL_STENCIL_FUNC = 0x0B92,
+ LOCAL_GL_STENCIL_VALUE_MASK = 0x0B93,
+ LOCAL_GL_STENCIL_REF = 0x0B97,
+ LOCAL_GL_STENCIL_FAIL = 0x0B94,
+ LOCAL_GL_STENCIL_PASS_DEPTH_PASS = 0x0B96,
+ LOCAL_GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95,
+ LOCAL_GL_STENCIL_CLEAR_VALUE = 0x0B91,
+ LOCAL_GL_STENCIL_INDEX = 0x1901,
+ LOCAL_GL_KEEP = 0x1E00,
+ LOCAL_GL_REPLACE = 0x1E01,
+ LOCAL_GL_INCR = 0x1E02,
+ LOCAL_GL_DECR = 0x1E03,
+
+ /* Buffers, Pixel Drawing/Reading */
+ LOCAL_GL_NONE = 0,
+ LOCAL_GL_LEFT = 0x0406,
+ LOCAL_GL_RIGHT = 0x0407,
+ /*LOCAL_GL_FRONT = 0x0404, */
+ /*LOCAL_GL_BACK = 0x0405, */
+ /*LOCAL_GL_FRONT_AND_BACK = 0x0408, */
+ LOCAL_GL_FRONT_LEFT = 0x0400,
+ LOCAL_GL_FRONT_RIGHT = 0x0401,
+ LOCAL_GL_BACK_LEFT = 0x0402,
+ LOCAL_GL_BACK_RIGHT = 0x0403,
+ LOCAL_GL_AUX0 = 0x0409,
+ LOCAL_GL_AUX1 = 0x040A,
+ LOCAL_GL_AUX2 = 0x040B,
+ LOCAL_GL_AUX3 = 0x040C,
+ LOCAL_GL_COLOR_INDEX = 0x1900,
+ LOCAL_GL_RED = 0x1903,
+ LOCAL_GL_GREEN = 0x1904,
+ LOCAL_GL_BLUE = 0x1905,
+ LOCAL_GL_ALPHA = 0x1906,
+ LOCAL_GL_LUMINANCE = 0x1909,
+ LOCAL_GL_LUMINANCE_ALPHA = 0x190A,
+ LOCAL_GL_ALPHA_BITS = 0x0D55,
+ LOCAL_GL_RED_BITS = 0x0D52,
+ LOCAL_GL_GREEN_BITS = 0x0D53,
+ LOCAL_GL_BLUE_BITS = 0x0D54,
+ LOCAL_GL_INDEX_BITS = 0x0D51,
+ LOCAL_GL_SUBPIXEL_BITS = 0x0D50,
+ LOCAL_GL_AUX_BUFFERS = 0x0C00,
+ LOCAL_GL_READ_BUFFER = 0x0C02,
+ LOCAL_GL_DRAW_BUFFER = 0x0C01,
+ LOCAL_GL_DOUBLEBUFFER = 0x0C32,
+ LOCAL_GL_STEREO = 0x0C33,
+ LOCAL_GL_BITMAP = 0x1A00,
+ LOCAL_GL_COLOR = 0x1800,
+ LOCAL_GL_DEPTH = 0x1801,
+ LOCAL_GL_STENCIL = 0x1802,
+ LOCAL_GL_DITHER = 0x0BD0,
+ LOCAL_GL_RGB = 0x1907,
+ LOCAL_GL_RGBA = 0x1908,
+
+ /* Implementation limits */
+ LOCAL_GL_MAX_LIST_NESTING = 0x0B31,
+ LOCAL_GL_MAX_ATTRIB_STACK_DEPTH = 0x0D35,
+ LOCAL_GL_MAX_MODELVIEW_STACK_DEPTH = 0x0D36,
+ LOCAL_GL_MAX_NAME_STACK_DEPTH = 0x0D37,
+ LOCAL_GL_MAX_PROJECTION_STACK_DEPTH = 0x0D38,
+ LOCAL_GL_MAX_TEXTURE_STACK_DEPTH = 0x0D39,
+ LOCAL_GL_MAX_EVAL_ORDER = 0x0D30,
+ LOCAL_GL_MAX_LIGHTS = 0x0D31,
+ LOCAL_GL_MAX_CLIP_PLANES = 0x0D32,
+ LOCAL_GL_MAX_TEXTURE_SIZE = 0x0D33,
+ LOCAL_GL_MAX_PIXEL_MAP_TABLE = 0x0D34,
+ LOCAL_GL_MAX_VIEWPORT_DIMS = 0x0D3A,
+ LOCAL_GL_MAX_CLIENT_ATTRIB_STACK_DEPTH= 0x0D3B,
+
+ /* Gets */
+ LOCAL_GL_ATTRIB_STACK_DEPTH = 0x0BB0,
+ LOCAL_GL_CLIENT_ATTRIB_STACK_DEPTH = 0x0BB1,
+ LOCAL_GL_COLOR_CLEAR_VALUE = 0x0C22,
+ LOCAL_GL_COLOR_WRITEMASK = 0x0C23,
+ LOCAL_GL_CURRENT_INDEX = 0x0B01,
+ LOCAL_GL_CURRENT_COLOR = 0x0B00,
+ LOCAL_GL_CURRENT_NORMAL = 0x0B02,
+ LOCAL_GL_CURRENT_RASTER_COLOR = 0x0B04,
+ LOCAL_GL_CURRENT_RASTER_DISTANCE = 0x0B09,
+ LOCAL_GL_CURRENT_RASTER_INDEX = 0x0B05,
+ LOCAL_GL_CURRENT_RASTER_POSITION = 0x0B07,
+ LOCAL_GL_CURRENT_RASTER_TEXTURE_COORDS = 0x0B06,
+ LOCAL_GL_CURRENT_RASTER_POSITION_VALID = 0x0B08,
+ LOCAL_GL_CURRENT_TEXTURE_COORDS = 0x0B03,
+ LOCAL_GL_INDEX_CLEAR_VALUE = 0x0C20,
+ LOCAL_GL_INDEX_MODE = 0x0C30,
+ LOCAL_GL_INDEX_WRITEMASK = 0x0C21,
+ LOCAL_GL_MODELVIEW_MATRIX = 0x0BA6,
+ LOCAL_GL_MODELVIEW_STACK_DEPTH = 0x0BA3,
+ LOCAL_GL_NAME_STACK_DEPTH = 0x0D70,
+ LOCAL_GL_PROJECTION_MATRIX = 0x0BA7,
+ LOCAL_GL_PROJECTION_STACK_DEPTH = 0x0BA4,
+ LOCAL_GL_RENDER_MODE = 0x0C40,
+ LOCAL_GL_RGBA_MODE = 0x0C31,
+ LOCAL_GL_TEXTURE_MATRIX = 0x0BA8,
+ LOCAL_GL_TEXTURE_STACK_DEPTH = 0x0BA5,
+ LOCAL_GL_VIEWPORT = 0x0BA2,
+
+
+ /* Evaluators */
+ LOCAL_GL_AUTO_NORMAL = 0x0D80,
+ LOCAL_GL_MAP1_COLOR_4 = 0x0D90,
+ LOCAL_GL_MAP1_GRID_DOMAIN = 0x0DD0,
+ LOCAL_GL_MAP1_GRID_SEGMENTS = 0x0DD1,
+ LOCAL_GL_MAP1_INDEX = 0x0D91,
+ LOCAL_GL_MAP1_NORMAL = 0x0D92,
+ LOCAL_GL_MAP1_TEXTURE_COORD_1 = 0x0D93,
+ LOCAL_GL_MAP1_TEXTURE_COORD_2 = 0x0D94,
+ LOCAL_GL_MAP1_TEXTURE_COORD_3 = 0x0D95,
+ LOCAL_GL_MAP1_TEXTURE_COORD_4 = 0x0D96,
+ LOCAL_GL_MAP1_VERTEX_3 = 0x0D97,
+ LOCAL_GL_MAP1_VERTEX_4 = 0x0D98,
+ LOCAL_GL_MAP2_COLOR_4 = 0x0DB0,
+ LOCAL_GL_MAP2_GRID_DOMAIN = 0x0DD2,
+ LOCAL_GL_MAP2_GRID_SEGMENTS = 0x0DD3,
+ LOCAL_GL_MAP2_INDEX = 0x0DB1,
+ LOCAL_GL_MAP2_NORMAL = 0x0DB2,
+ LOCAL_GL_MAP2_TEXTURE_COORD_1 = 0x0DB3,
+ LOCAL_GL_MAP2_TEXTURE_COORD_2 = 0x0DB4,
+ LOCAL_GL_MAP2_TEXTURE_COORD_3 = 0x0DB5,
+ LOCAL_GL_MAP2_TEXTURE_COORD_4 = 0x0DB6,
+ LOCAL_GL_MAP2_VERTEX_3 = 0x0DB7,
+ LOCAL_GL_MAP2_VERTEX_4 = 0x0DB8,
+ LOCAL_GL_COEFF = 0x0A00,
+ LOCAL_GL_DOMAIN = 0x0A02,
+ LOCAL_GL_ORDER = 0x0A01,
+
+ /* Hints */
+ LOCAL_GL_FOG_HINT = 0x0C54,
+ LOCAL_GL_LINE_SMOOTH_HINT = 0x0C52,
+ LOCAL_GL_PERSPECTIVE_CORRECTION_HINT = 0x0C50,
+ LOCAL_GL_POINT_SMOOTH_HINT = 0x0C51,
+ LOCAL_GL_POLYGON_SMOOTH_HINT = 0x0C53,
+ LOCAL_GL_DONT_CARE = 0x1100,
+ LOCAL_GL_FASTEST = 0x1101,
+ LOCAL_GL_NICEST = 0x1102,
+
+ /* Scissor box */
+ LOCAL_GL_SCISSOR_TEST = 0x0C11,
+ LOCAL_GL_SCISSOR_BOX = 0x0C10,
+
+ /* Pixel Mode / Transfer */
+ LOCAL_GL_MAP_COLOR = 0x0D10,
+ LOCAL_GL_MAP_STENCIL = 0x0D11,
+ LOCAL_GL_INDEX_SHIFT = 0x0D12,
+ LOCAL_GL_INDEX_OFFSET = 0x0D13,
+ LOCAL_GL_RED_SCALE = 0x0D14,
+ LOCAL_GL_RED_BIAS = 0x0D15,
+ LOCAL_GL_GREEN_SCALE = 0x0D18,
+ LOCAL_GL_GREEN_BIAS = 0x0D19,
+ LOCAL_GL_BLUE_SCALE = 0x0D1A,
+ LOCAL_GL_BLUE_BIAS = 0x0D1B,
+ LOCAL_GL_ALPHA_SCALE = 0x0D1C,
+ LOCAL_GL_ALPHA_BIAS = 0x0D1D,
+ LOCAL_GL_DEPTH_SCALE = 0x0D1E,
+ LOCAL_GL_DEPTH_BIAS = 0x0D1F,
+ LOCAL_GL_PIXEL_MAP_S_TO_S_SIZE = 0x0CB1,
+ LOCAL_GL_PIXEL_MAP_I_TO_I_SIZE = 0x0CB0,
+ LOCAL_GL_PIXEL_MAP_I_TO_R_SIZE = 0x0CB2,
+ LOCAL_GL_PIXEL_MAP_I_TO_G_SIZE = 0x0CB3,
+ LOCAL_GL_PIXEL_MAP_I_TO_B_SIZE = 0x0CB4,
+ LOCAL_GL_PIXEL_MAP_I_TO_A_SIZE = 0x0CB5,
+ LOCAL_GL_PIXEL_MAP_R_TO_R_SIZE = 0x0CB6,
+ LOCAL_GL_PIXEL_MAP_G_TO_G_SIZE = 0x0CB7,
+ LOCAL_GL_PIXEL_MAP_B_TO_B_SIZE = 0x0CB8,
+ LOCAL_GL_PIXEL_MAP_A_TO_A_SIZE = 0x0CB9,
+ LOCAL_GL_PIXEL_MAP_S_TO_S = 0x0C71,
+ LOCAL_GL_PIXEL_MAP_I_TO_I = 0x0C70,
+ LOCAL_GL_PIXEL_MAP_I_TO_R = 0x0C72,
+ LOCAL_GL_PIXEL_MAP_I_TO_G = 0x0C73,
+ LOCAL_GL_PIXEL_MAP_I_TO_B = 0x0C74,
+ LOCAL_GL_PIXEL_MAP_I_TO_A = 0x0C75,
+ LOCAL_GL_PIXEL_MAP_R_TO_R = 0x0C76,
+ LOCAL_GL_PIXEL_MAP_G_TO_G = 0x0C77,
+ LOCAL_GL_PIXEL_MAP_B_TO_B = 0x0C78,
+ LOCAL_GL_PIXEL_MAP_A_TO_A = 0x0C79,
+ LOCAL_GL_PACK_ALIGNMENT = 0x0D05,
+ LOCAL_GL_PACK_LSB_FIRST = 0x0D01,
+ LOCAL_GL_PACK_ROW_LENGTH = 0x0D02,
+ LOCAL_GL_PACK_SKIP_PIXELS = 0x0D04,
+ LOCAL_GL_PACK_SKIP_ROWS = 0x0D03,
+ LOCAL_GL_PACK_SWAP_BYTES = 0x0D00,
+ LOCAL_GL_UNPACK_ALIGNMENT = 0x0CF5,
+ LOCAL_GL_UNPACK_LSB_FIRST = 0x0CF1,
+ LOCAL_GL_UNPACK_ROW_LENGTH = 0x0CF2,
+ LOCAL_GL_UNPACK_SKIP_PIXELS = 0x0CF4,
+ LOCAL_GL_UNPACK_SKIP_ROWS = 0x0CF3,
+ LOCAL_GL_UNPACK_SWAP_BYTES = 0x0CF0,
+ LOCAL_GL_ZOOM_X = 0x0D16,
+ LOCAL_GL_ZOOM_Y = 0x0D17,
+
+ /* Texture mapping */
+ LOCAL_GL_TEXTURE_ENV = 0x2300,
+ LOCAL_GL_TEXTURE_ENV_MODE = 0x2200,
+ LOCAL_GL_TEXTURE_1D = 0x0DE0,
+ LOCAL_GL_TEXTURE_2D = 0x0DE1,
+ LOCAL_GL_TEXTURE_WRAP_S = 0x2802,
+ LOCAL_GL_TEXTURE_WRAP_T = 0x2803,
+ LOCAL_GL_TEXTURE_MAG_FILTER = 0x2800,
+ LOCAL_GL_TEXTURE_MIN_FILTER = 0x2801,
+ LOCAL_GL_TEXTURE_ENV_COLOR = 0x2201,
+ LOCAL_GL_TEXTURE_GEN_S = 0x0C60,
+ LOCAL_GL_TEXTURE_GEN_T = 0x0C61,
+ LOCAL_GL_TEXTURE_GEN_MODE = 0x2500,
+ LOCAL_GL_TEXTURE_BORDER_COLOR = 0x1004,
+ LOCAL_GL_TEXTURE_WIDTH = 0x1000,
+ LOCAL_GL_TEXTURE_HEIGHT = 0x1001,
+ LOCAL_GL_TEXTURE_BORDER = 0x1005,
+ LOCAL_GL_TEXTURE_COMPONENTS = 0x1003,
+ LOCAL_GL_TEXTURE_RED_SIZE = 0x805C,
+ LOCAL_GL_TEXTURE_GREEN_SIZE = 0x805D,
+ LOCAL_GL_TEXTURE_BLUE_SIZE = 0x805E,
+ LOCAL_GL_TEXTURE_ALPHA_SIZE = 0x805F,
+ LOCAL_GL_TEXTURE_LUMINANCE_SIZE = 0x8060,
+ LOCAL_GL_TEXTURE_INTENSITY_SIZE = 0x8061,
+ LOCAL_GL_NEAREST_MIPMAP_NEAREST = 0x2700,
+ LOCAL_GL_NEAREST_MIPMAP_LINEAR = 0x2702,
+ LOCAL_GL_LINEAR_MIPMAP_NEAREST = 0x2701,
+ LOCAL_GL_LINEAR_MIPMAP_LINEAR = 0x2703,
+ LOCAL_GL_OBJECT_LINEAR = 0x2401,
+ LOCAL_GL_OBJECT_PLANE = 0x2501,
+ LOCAL_GL_EYE_LINEAR = 0x2400,
+ LOCAL_GL_EYE_PLANE = 0x2502,
+ LOCAL_GL_SPHERE_MAP = 0x2402,
+ LOCAL_GL_DECAL = 0x2101,
+ LOCAL_GL_MODULATE = 0x2100,
+ LOCAL_GL_NEAREST = 0x2600,
+ LOCAL_GL_REPEAT = 0x2901,
+ LOCAL_GL_CLAMP = 0x2900,
+ LOCAL_GL_S = 0x2000,
+ LOCAL_GL_T = 0x2001,
+ LOCAL_GL_R = 0x2002,
+ LOCAL_GL_Q = 0x2003,
+ LOCAL_GL_TEXTURE_GEN_R = 0x0C62,
+ LOCAL_GL_TEXTURE_GEN_Q = 0x0C63,
+
+ /* GL 1.1 texturing */
+ LOCAL_GL_PROXY_TEXTURE_1D = 0x8063,
+ LOCAL_GL_PROXY_TEXTURE_2D = 0x8064,
+ LOCAL_GL_TEXTURE_PRIORITY = 0x8066,
+ LOCAL_GL_TEXTURE_RESIDENT = 0x8067,
+ LOCAL_GL_TEXTURE_BINDING_1D = 0x8068,
+ LOCAL_GL_TEXTURE_BINDING_2D = 0x8069,
+ LOCAL_GL_TEXTURE_INTERNAL_FORMAT = 0x1003,
+
+ /* GL 1.2 texturing */
+ LOCAL_GL_PACK_SKIP_IMAGES = 0x806B,
+ LOCAL_GL_PACK_IMAGE_HEIGHT = 0x806C,
+ LOCAL_GL_UNPACK_SKIP_IMAGES = 0x806D,
+ LOCAL_GL_UNPACK_IMAGE_HEIGHT = 0x806E,
+ LOCAL_GL_TEXTURE_3D = 0x806F,
+ LOCAL_GL_PROXY_TEXTURE_3D = 0x8070,
+ LOCAL_GL_TEXTURE_DEPTH = 0x8071,
+ LOCAL_GL_TEXTURE_WRAP_R = 0x8072,
+ LOCAL_GL_MAX_3D_TEXTURE_SIZE = 0x8073,
+ LOCAL_GL_TEXTURE_BINDING_3D = 0x806A,
+
+ /* Internal texture formats (GL 1.1) */
+ LOCAL_GL_ALPHA4 = 0x803B,
+ LOCAL_GL_ALPHA8 = 0x803C,
+ LOCAL_GL_ALPHA12 = 0x803D,
+ LOCAL_GL_ALPHA16 = 0x803E,
+ LOCAL_GL_LUMINANCE4 = 0x803F,
+ LOCAL_GL_LUMINANCE8 = 0x8040,
+ LOCAL_GL_LUMINANCE12 = 0x8041,
+ LOCAL_GL_LUMINANCE16 = 0x8042,
+ LOCAL_GL_LUMINANCE4_ALPHA4 = 0x8043,
+ LOCAL_GL_LUMINANCE6_ALPHA2 = 0x8044,
+ LOCAL_GL_LUMINANCE8_ALPHA8 = 0x8045,
+ LOCAL_GL_LUMINANCE12_ALPHA4 = 0x8046,
+ LOCAL_GL_LUMINANCE12_ALPHA12 = 0x8047,
+ LOCAL_GL_LUMINANCE16_ALPHA16 = 0x8048,
+ LOCAL_GL_INTENSITY = 0x8049,
+ LOCAL_GL_INTENSITY4 = 0x804A,
+ LOCAL_GL_INTENSITY8 = 0x804B,
+ LOCAL_GL_INTENSITY12 = 0x804C,
+ LOCAL_GL_INTENSITY16 = 0x804D,
+ LOCAL_GL_R3_G3_B2 = 0x2A10,
+ LOCAL_GL_RGB4 = 0x804F,
+ LOCAL_GL_RGB5 = 0x8050,
+ LOCAL_GL_RGB8 = 0x8051,
+ LOCAL_GL_RGB10 = 0x8052,
+ LOCAL_GL_RGB12 = 0x8053,
+ LOCAL_GL_RGB16 = 0x8054,
+ LOCAL_GL_RGBA2 = 0x8055,
+ LOCAL_GL_RGBA4 = 0x8056,
+ LOCAL_GL_RGB5_A1 = 0x8057,
+ LOCAL_GL_RGBA8 = 0x8058,
+ LOCAL_GL_RGB10_A2 = 0x8059,
+ LOCAL_GL_RGBA12 = 0x805A,
+ LOCAL_GL_RGBA16 = 0x805B,
+
+ /* Utility */
+ LOCAL_GL_VENDOR = 0x1F00,
+ LOCAL_GL_RENDERER = 0x1F01,
+ LOCAL_GL_VERSION = 0x1F02,
+ LOCAL_GL_EXTENSIONS = 0x1F03,
+
+ /* Errors */
+ LOCAL_GL_INVALID_VALUE = 0x0501,
+ LOCAL_GL_INVALID_ENUM = 0x0500,
+ LOCAL_GL_INVALID_OPERATION = 0x0502,
+ LOCAL_GL_STACK_OVERFLOW = 0x0503,
+ LOCAL_GL_STACK_UNDERFLOW = 0x0504,
+ LOCAL_GL_OUT_OF_MEMORY = 0x0505,
+
+ /*
+ * Extensions
+ */
+
+ /* LOCAL_GL_EXT_blend_minmax and LOCAL_GL_EXT_blend_color */
+ LOCAL_GL_CONSTANT_COLOR_EXT = 0x8001,
+ LOCAL_GL_ONE_MINUS_CONSTANT_COLOR_EXT = 0x8002,
+ LOCAL_GL_CONSTANT_ALPHA_EXT = 0x8003,
+ LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA_EXT = 0x8004,
+ LOCAL_GL_BLEND_EQUATION_EXT = 0x8009,
+ LOCAL_GL_MIN_EXT = 0x8007,
+ LOCAL_GL_MAX_EXT = 0x8008,
+ LOCAL_GL_FUNC_ADD_EXT = 0x8006,
+ LOCAL_GL_FUNC_SUBTRACT_EXT = 0x800A,
+ LOCAL_GL_FUNC_REVERSE_SUBTRACT_EXT = 0x800B,
+ LOCAL_GL_BLEND_COLOR_EXT = 0x8005,
+
+ /* LOCAL_GL_EXT_polygon_offset */
+ LOCAL_GL_POLYGON_OFFSET_EXT = 0x8037,
+ LOCAL_GL_POLYGON_OFFSET_FACTOR_EXT = 0x8038,
+ LOCAL_GL_POLYGON_OFFSET_BIAS_EXT = 0x8039,
+
+ /* LOCAL_GL_EXT_vertex_array */
+ LOCAL_GL_VERTEX_ARRAY_EXT = 0x8074,
+ LOCAL_GL_NORMAL_ARRAY_EXT = 0x8075,
+ LOCAL_GL_COLOR_ARRAY_EXT = 0x8076,
+ LOCAL_GL_INDEX_ARRAY_EXT = 0x8077,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_EXT = 0x8078,
+ LOCAL_GL_EDGE_FLAG_ARRAY_EXT = 0x8079,
+ LOCAL_GL_VERTEX_ARRAY_SIZE_EXT = 0x807A,
+ LOCAL_GL_VERTEX_ARRAY_TYPE_EXT = 0x807B,
+ LOCAL_GL_VERTEX_ARRAY_STRIDE_EXT = 0x807C,
+ LOCAL_GL_VERTEX_ARRAY_COUNT_EXT = 0x807D,
+ LOCAL_GL_NORMAL_ARRAY_TYPE_EXT = 0x807E,
+ LOCAL_GL_NORMAL_ARRAY_STRIDE_EXT = 0x807F,
+ LOCAL_GL_NORMAL_ARRAY_COUNT_EXT = 0x8080,
+ LOCAL_GL_COLOR_ARRAY_SIZE_EXT = 0x8081,
+ LOCAL_GL_COLOR_ARRAY_TYPE_EXT = 0x8082,
+ LOCAL_GL_COLOR_ARRAY_STRIDE_EXT = 0x8083,
+ LOCAL_GL_COLOR_ARRAY_COUNT_EXT = 0x8084,
+ LOCAL_GL_INDEX_ARRAY_TYPE_EXT = 0x8085,
+ LOCAL_GL_INDEX_ARRAY_STRIDE_EXT = 0x8086,
+ LOCAL_GL_INDEX_ARRAY_COUNT_EXT = 0x8087,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_SIZE_EXT = 0x8088,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_TYPE_EXT = 0x8089,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_STRIDE_EXT = 0x808A,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_COUNT_EXT = 0x808B,
+ LOCAL_GL_EDGE_FLAG_ARRAY_STRIDE_EXT = 0x808C,
+ LOCAL_GL_EDGE_FLAG_ARRAY_COUNT_EXT = 0x808D,
+ LOCAL_GL_VERTEX_ARRAY_POINTER_EXT = 0x808E,
+ LOCAL_GL_NORMAL_ARRAY_POINTER_EXT = 0x808F,
+ LOCAL_GL_COLOR_ARRAY_POINTER_EXT = 0x8090,
+ LOCAL_GL_INDEX_ARRAY_POINTER_EXT = 0x8091,
+ LOCAL_GL_TEXTURE_COORD_ARRAY_POINTER_EXT = 0x8092,
+ LOCAL_GL_EDGE_FLAG_ARRAY_POINTER_EXT = 0x8093,
+
+ /* LOCAL_GL_EXT_texture_object */
+ LOCAL_GL_TEXTURE_PRIORITY_EXT = 0x8066,
+ LOCAL_GL_TEXTURE_RESIDENT_EXT = 0x8067,
+ LOCAL_GL_TEXTURE_1D_BINDING_EXT = 0x8068,
+ LOCAL_GL_TEXTURE_2D_BINDING_EXT = 0x8069,
+
+ /* LOCAL_GL_EXT_texture3D */
+ LOCAL_GL_PACK_SKIP_IMAGES_EXT = 0x806B,
+ LOCAL_GL_PACK_IMAGE_HEIGHT_EXT = 0x806C,
+ LOCAL_GL_UNPACK_SKIP_IMAGES_EXT = 0x806D,
+ LOCAL_GL_UNPACK_IMAGE_HEIGHT_EXT = 0x806E,
+ LOCAL_GL_TEXTURE_3D_EXT = 0x806F,
+ LOCAL_GL_PROXY_TEXTURE_3D_EXT = 0x8070,
+ LOCAL_GL_TEXTURE_DEPTH_EXT = 0x8071,
+ LOCAL_GL_TEXTURE_WRAP_R_EXT = 0x8072,
+ LOCAL_GL_MAX_3D_TEXTURE_SIZE_EXT = 0x8073,
+ LOCAL_GL_TEXTURE_3D_BINDING_EXT = 0x806A,
+
+ /* LOCAL_GL_EXT_paletted_texture */
+ LOCAL_GL_TABLE_TOO_LARGE_EXT = 0x8031,
+ LOCAL_GL_COLOR_TABLE_FORMAT_EXT = 0x80D8,
+ LOCAL_GL_COLOR_TABLE_WIDTH_EXT = 0x80D9,
+ LOCAL_GL_COLOR_TABLE_RED_SIZE_EXT = 0x80DA,
+ LOCAL_GL_COLOR_TABLE_GREEN_SIZE_EXT = 0x80DB,
+ LOCAL_GL_COLOR_TABLE_BLUE_SIZE_EXT = 0x80DC,
+ LOCAL_GL_COLOR_TABLE_ALPHA_SIZE_EXT = 0x80DD,
+ LOCAL_GL_COLOR_TABLE_LUMINANCE_SIZE_EXT = 0x80DE,
+ LOCAL_GL_COLOR_TABLE_INTENSITY_SIZE_EXT = 0x80DF,
+ LOCAL_GL_TEXTURE_INDEX_SIZE_EXT = 0x80ED,
+ LOCAL_GL_COLOR_INDEX1_EXT = 0x80E2,
+ LOCAL_GL_COLOR_INDEX2_EXT = 0x80E3,
+ LOCAL_GL_COLOR_INDEX4_EXT = 0x80E4,
+ LOCAL_GL_COLOR_INDEX8_EXT = 0x80E5,
+ LOCAL_GL_COLOR_INDEX12_EXT = 0x80E6,
+ LOCAL_GL_COLOR_INDEX16_EXT = 0x80E7,
+
+ /* LOCAL_GL_EXT_shared_texture_palette */
+ LOCAL_GL_SHARED_TEXTURE_PALETTE_EXT = 0x81FB,
+
+ /* LOCAL_GL_EXT_point_parameters */
+ LOCAL_GL_POINT_SIZE_MIN_EXT = 0x8126,
+ LOCAL_GL_POINT_SIZE_MAX_EXT = 0x8127,
+ LOCAL_GL_POINT_FADE_THRESHOLD_SIZE_EXT = 0x8128,
+ LOCAL_GL_DISTANCE_ATTENUATION_EXT = 0x8129,
+
+ /* LOCAL_GL_EXT_rescale_normal */
+ LOCAL_GL_RESCALE_NORMAL_EXT = 0x803A,
+
+ /* LOCAL_GL_EXT_abgr */
+ LOCAL_GL_ABGR_EXT = 0x8000,
+
+ /* LOCAL_GL_SGIS_multitexture */
+ LOCAL_GL_SELECTED_TEXTURE_SGIS = 0x835C,
+ LOCAL_GL_SELECTED_TEXTURE_COORD_SET_SGIS = 0x835D,
+ LOCAL_GL_MAX_TEXTURES_SGIS = 0x835E,
+ LOCAL_GL_TEXTURE0_SGIS = 0x835F,
+ LOCAL_GL_TEXTURE1_SGIS = 0x8360,
+ LOCAL_GL_TEXTURE2_SGIS = 0x8361,
+ LOCAL_GL_TEXTURE3_SGIS = 0x8362,
+ LOCAL_GL_TEXTURE_COORD_SET_SOURCE_SGIS = 0x8363,
+
+ /* LOCAL_GL_EXT_multitexture */
+ LOCAL_GL_SELECTED_TEXTURE_EXT = 0x83C0,
+ LOCAL_GL_SELECTED_TEXTURE_COORD_SET_EXT = 0x83C1,
+ LOCAL_GL_SELECTED_TEXTURE_TRANSFORM_EXT = 0x83C2,
+ LOCAL_GL_MAX_TEXTURES_EXT = 0x83C3,
+ LOCAL_GL_MAX_TEXTURE_COORD_SETS_EXT = 0x83C4,
+ LOCAL_GL_TEXTURE_ENV_COORD_SET_EXT = 0x83C5,
+ LOCAL_GL_TEXTURE0_EXT = 0x83C6,
+ LOCAL_GL_TEXTURE1_EXT = 0x83C7,
+ LOCAL_GL_TEXTURE2_EXT = 0x83C8,
+ LOCAL_GL_TEXTURE3_EXT = 0x83C9,
+
+ /* LOCAL_GL_SGIS_texture_edge_clamp */
+ LOCAL_GL_CLAMP_TO_EDGE_SGIS = 0x812F,
+
+ /* OpenGL 1.2 */
+ LOCAL_GL_RESCALE_NORMAL = 0x803A,
+ LOCAL_GL_CLAMP_TO_EDGE = 0x812F,
+ LOCAL_GL_MAX_ELEMENTS_VERTICES = 0xF0E8,
+ LOCAL_GL_MAX_ELEMENTS_INDICES = 0xF0E9,
+ LOCAL_GL_BGR = 0x80E0,
+ LOCAL_GL_BGRA = 0x80E1,
+ LOCAL_GL_UNSIGNED_BYTE_3_3_2 = 0x8032,
+ LOCAL_GL_UNSIGNED_BYTE_2_3_3_REV = 0x8362,
+ LOCAL_GL_UNSIGNED_SHORT_5_6_5 = 0x8363,
+ LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV = 0x8364,
+ LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033,
+ LOCAL_GL_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
+ LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034,
+ LOCAL_GL_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
+ LOCAL_GL_UNSIGNED_INT_8_8_8_8 = 0x8035,
+ LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV = 0x8367,
+ LOCAL_GL_UNSIGNED_INT_10_10_10_2 = 0x8036,
+ LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV = 0x8368,
+ LOCAL_GL_LIGHT_MODEL_COLOR_CONTROL = 0x81F8,
+ LOCAL_GL_SINGLE_COLOR = 0x81F9,
+ LOCAL_GL_SEPARATE_SPECULAR_COLOR = 0x81FA,
+ LOCAL_GL_TEXTURE_MIN_LOD = 0x813A,
+ LOCAL_GL_TEXTURE_MAX_LOD = 0x813B,
+ LOCAL_GL_TEXTURE_BASE_LEVEL = 0x813C,
+ LOCAL_GL_TEXTURE_MAX_LEVEL = 0x813D
+};
+
+typedef struct { GLenum e; const char* name; } ENUM;
+#define EDEF(VAR) { (GLenum)(LOCAL_GL_##VAR), #VAR }
+
+static ENUM enums[] =
+ {
+ EDEF(BYTE),
+ EDEF(UNSIGNED_BYTE),
+ EDEF(SHORT),
+ EDEF(UNSIGNED_SHORT),
+ EDEF(INT),
+ EDEF(UNSIGNED_INT),
+ EDEF(FLOAT),
+ EDEF(DOUBLE),
+ EDEF(2_BYTES),
+ EDEF(3_BYTES),
+ EDEF(4_BYTES),
+/*
+ EDEF(LINES),
+ EDEF(POINTS),
+ EDEF(LINE_STRIP),
+ EDEF(LINE_LOOP),
+ EDEF(TRIANGLES),
+ EDEF(TRIANGLE_STRIP),
+ EDEF(TRIANGLE_FAN),
+ EDEF(QUADS),
+ EDEF(QUAD_STRIP),
+ EDEF(POLYGON),
+ EDEF(EDGE_FLAG),
+*/
+ EDEF(VERTEX_ARRAY),
+ EDEF(NORMAL_ARRAY),
+ EDEF(COLOR_ARRAY),
+ EDEF(INDEX_ARRAY),
+ EDEF(TEXTURE_COORD_ARRAY),
+ EDEF(EDGE_FLAG_ARRAY),
+ EDEF(VERTEX_ARRAY_SIZE),
+ EDEF(VERTEX_ARRAY_TYPE),
+ EDEF(VERTEX_ARRAY_STRIDE),
+ EDEF(NORMAL_ARRAY_TYPE),
+ EDEF(NORMAL_ARRAY_STRIDE),
+ EDEF(COLOR_ARRAY_SIZE),
+ EDEF(COLOR_ARRAY_TYPE),
+ EDEF(COLOR_ARRAY_STRIDE),
+ EDEF(INDEX_ARRAY_TYPE),
+ EDEF(INDEX_ARRAY_STRIDE),
+ EDEF(TEXTURE_COORD_ARRAY_SIZE),
+ EDEF(TEXTURE_COORD_ARRAY_TYPE),
+ EDEF(TEXTURE_COORD_ARRAY_STRIDE),
+ EDEF(EDGE_FLAG_ARRAY_STRIDE),
+ EDEF(VERTEX_ARRAY_POINTER),
+ EDEF(NORMAL_ARRAY_POINTER),
+ EDEF(COLOR_ARRAY_POINTER),
+ EDEF(INDEX_ARRAY_POINTER),
+ EDEF(TEXTURE_COORD_ARRAY_POINTER),
+ EDEF(EDGE_FLAG_ARRAY_POINTER),
+ EDEF(V2F),
+ EDEF(V3F),
+ EDEF(C4UB_V2F),
+ EDEF(C4UB_V3F),
+ EDEF(C3F_V3F),
+ EDEF(N3F_V3F),
+ EDEF(C4F_N3F_V3F),
+ EDEF(T2F_V3F),
+ EDEF(T4F_V4F),
+ EDEF(T2F_C4UB_V3F),
+ EDEF(T2F_C3F_V3F),
+ EDEF(T2F_N3F_V3F),
+ EDEF(T2F_C4F_N3F_V3F),
+ EDEF(T4F_C4F_N3F_V4F),
+ EDEF(MATRIX_MODE),
+ EDEF(MODELVIEW),
+ EDEF(PROJECTION),
+ EDEF(TEXTURE),
+ EDEF(POINT_SMOOTH),
+ EDEF(POINT_SIZE),
+ EDEF(POINT_SIZE_GRANULARITY),
+ EDEF(POINT_SIZE_RANGE),
+ EDEF(LINE_SMOOTH),
+ EDEF(LINE_STIPPLE),
+ EDEF(LINE_STIPPLE_PATTERN),
+ EDEF(LINE_STIPPLE_REPEAT),
+ EDEF(LINE_WIDTH),
+ EDEF(LINE_WIDTH_GRANULARITY),
+ EDEF(LINE_WIDTH_RANGE),
+ EDEF(POINT),
+ EDEF(LINE),
+ EDEF(FILL),
+ EDEF(CCW),
+ EDEF(CW),
+ EDEF(FRONT),
+ EDEF(BACK),
+ EDEF(CULL_FACE),
+ EDEF(CULL_FACE_MODE),
+ EDEF(POLYGON_SMOOTH),
+ EDEF(POLYGON_STIPPLE),
+ EDEF(FRONT_FACE),
+ EDEF(POLYGON_MODE),
+ EDEF(POLYGON_OFFSET_FACTOR),
+ EDEF(POLYGON_OFFSET_UNITS),
+ EDEF(POLYGON_OFFSET_POINT),
+ EDEF(POLYGON_OFFSET_LINE),
+ EDEF(POLYGON_OFFSET_FILL),
+ EDEF(COMPILE),
+ EDEF(COMPILE_AND_EXECUTE),
+ EDEF(LIST_BASE),
+ EDEF(LIST_INDEX),
+ EDEF(LIST_MODE),
+ EDEF(NEVER),
+ EDEF(LESS),
+ EDEF(GEQUAL),
+ EDEF(LEQUAL),
+ EDEF(GREATER),
+ EDEF(NOTEQUAL),
+ EDEF(EQUAL),
+ EDEF(ALWAYS),
+ EDEF(DEPTH_TEST),
+ EDEF(DEPTH_BITS),
+ EDEF(DEPTH_CLEAR_VALUE),
+ EDEF(DEPTH_FUNC),
+ EDEF(DEPTH_RANGE),
+ EDEF(DEPTH_WRITEMASK),
+ EDEF(DEPTH_COMPONENT),
+ EDEF(LIGHTING),
+ EDEF(LIGHT0),
+ EDEF(LIGHT1),
+ EDEF(LIGHT2),
+ EDEF(LIGHT3),
+ EDEF(LIGHT4),
+ EDEF(LIGHT5),
+ EDEF(LIGHT6),
+ EDEF(LIGHT7),
+ EDEF(SPOT_EXPONENT),
+ EDEF(SPOT_CUTOFF),
+ EDEF(CONSTANT_ATTENUATION),
+ EDEF(LINEAR_ATTENUATION),
+ EDEF(QUADRATIC_ATTENUATION),
+ EDEF(AMBIENT),
+ EDEF(DIFFUSE),
+ EDEF(SPECULAR),
+ EDEF(SHININESS),
+ EDEF(EMISSION),
+ EDEF(POSITION),
+ EDEF(SPOT_DIRECTION),
+ EDEF(AMBIENT_AND_DIFFUSE),
+ EDEF(COLOR_INDEXES),
+ EDEF(LIGHT_MODEL_TWO_SIDE),
+ EDEF(LIGHT_MODEL_LOCAL_VIEWER),
+ EDEF(LIGHT_MODEL_AMBIENT),
+ EDEF(FRONT_AND_BACK),
+ EDEF(SHADE_MODEL),
+ EDEF(FLAT),
+ EDEF(SMOOTH),
+ EDEF(COLOR_MATERIAL),
+ EDEF(COLOR_MATERIAL_FACE),
+ EDEF(COLOR_MATERIAL_PARAMETER),
+ EDEF(NORMALIZE),
+ EDEF(CLIP_PLANE0),
+ EDEF(CLIP_PLANE1),
+ EDEF(CLIP_PLANE2),
+ EDEF(CLIP_PLANE3),
+ EDEF(CLIP_PLANE4),
+ EDEF(CLIP_PLANE5),
+ EDEF(ACCUM_RED_BITS),
+ EDEF(ACCUM_GREEN_BITS),
+ EDEF(ACCUM_BLUE_BITS),
+ EDEF(ACCUM_ALPHA_BITS),
+ EDEF(ACCUM_CLEAR_VALUE),
+ EDEF(ACCUM),
+ EDEF(ADD),
+ EDEF(LOAD),
+ EDEF(MULT),
+ EDEF(RETURN),
+ EDEF(ALPHA_TEST),
+ EDEF(ALPHA_TEST_REF),
+ EDEF(ALPHA_TEST_FUNC),
+ EDEF(BLEND),
+ EDEF(BLEND_SRC),
+ EDEF(BLEND_DST),
+ EDEF(ZERO),
+ EDEF(ONE),
+ EDEF(SRC_COLOR),
+ EDEF(ONE_MINUS_SRC_COLOR),
+ EDEF(DST_COLOR),
+ EDEF(ONE_MINUS_DST_COLOR),
+ EDEF(SRC_ALPHA),
+ EDEF(ONE_MINUS_SRC_ALPHA),
+ EDEF(DST_ALPHA),
+ EDEF(ONE_MINUS_DST_ALPHA),
+ EDEF(SRC_ALPHA_SATURATE),
+ EDEF(CONSTANT_COLOR),
+ EDEF(ONE_MINUS_CONSTANT_COLOR),
+ EDEF(CONSTANT_ALPHA),
+ EDEF(ONE_MINUS_CONSTANT_ALPHA),
+ EDEF(FEEDBACK),
+ EDEF(RENDER),
+ EDEF(SELECT),
+ EDEF(2D),
+ EDEF(3D),
+ EDEF(3D_COLOR),
+ EDEF(3D_COLOR_TEXTURE),
+ EDEF(4D_COLOR_TEXTURE),
+ EDEF(POINT_TOKEN),
+ EDEF(LINE_TOKEN),
+ EDEF(LINE_RESET_TOKEN),
+ EDEF(POLYGON_TOKEN),
+ EDEF(BITMAP_TOKEN),
+ EDEF(DRAW_PIXEL_TOKEN),
+ EDEF(COPY_PIXEL_TOKEN),
+ EDEF(PASS_THROUGH_TOKEN),
+ EDEF(FEEDBACK_BUFFER_POINTER),
+ EDEF(FEEDBACK_BUFFER_SIZE),
+ EDEF(FEEDBACK_BUFFER_TYPE),
+ EDEF(SELECTION_BUFFER_POINTER),
+ EDEF(SELECTION_BUFFER_SIZE),
+ EDEF(FOG),
+ EDEF(FOG_MODE),
+ EDEF(FOG_DENSITY),
+ EDEF(FOG_COLOR),
+ EDEF(FOG_INDEX),
+ EDEF(FOG_START),
+ EDEF(FOG_END),
+ EDEF(LINEAR),
+ EDEF(EXP),
+ EDEF(EXP2),
+ EDEF(LOGIC_OP),
+ EDEF(INDEX_LOGIC_OP),
+ EDEF(COLOR_LOGIC_OP),
+ EDEF(LOGIC_OP_MODE),
+ EDEF(CLEAR),
+ EDEF(SET),
+ EDEF(COPY),
+ EDEF(COPY_INVERTED),
+ EDEF(NOOP),
+ EDEF(INVERT),
+ EDEF(AND),
+ EDEF(NAND),
+ EDEF(OR),
+ EDEF(NOR),
+ EDEF(XOR),
+ EDEF(EQUIV),
+ EDEF(AND_REVERSE),
+ EDEF(AND_INVERTED),
+ EDEF(OR_REVERSE),
+ EDEF(OR_INVERTED),
+ EDEF(STENCIL_TEST),
+ EDEF(STENCIL_WRITEMASK),
+ EDEF(STENCIL_BITS),
+ EDEF(STENCIL_FUNC),
+ EDEF(STENCIL_VALUE_MASK),
+ EDEF(STENCIL_REF),
+ EDEF(STENCIL_FAIL),
+ EDEF(STENCIL_PASS_DEPTH_PASS),
+ EDEF(STENCIL_PASS_DEPTH_FAIL),
+ EDEF(STENCIL_CLEAR_VALUE),
+ EDEF(STENCIL_INDEX),
+ EDEF(KEEP),
+ EDEF(REPLACE),
+ EDEF(INCR),
+ EDEF(DECR),
+ EDEF(NONE),
+ EDEF(LEFT),
+ EDEF(RIGHT),
+ EDEF(FRONT_LEFT),
+ EDEF(FRONT_RIGHT),
+ EDEF(BACK_LEFT),
+ EDEF(BACK_RIGHT),
+ EDEF(AUX0),
+ EDEF(AUX1),
+ EDEF(AUX2),
+ EDEF(AUX3),
+ EDEF(COLOR_INDEX),
+ EDEF(RED),
+ EDEF(GREEN),
+ EDEF(BLUE),
+ EDEF(ALPHA),
+ EDEF(LUMINANCE),
+ EDEF(LUMINANCE_ALPHA),
+ EDEF(ALPHA_BITS),
+ EDEF(RED_BITS),
+ EDEF(GREEN_BITS),
+ EDEF(BLUE_BITS),
+ EDEF(INDEX_BITS),
+ EDEF(SUBPIXEL_BITS),
+ EDEF(AUX_BUFFERS),
+ EDEF(READ_BUFFER),
+ EDEF(DRAW_BUFFER),
+ EDEF(DOUBLEBUFFER),
+ EDEF(STEREO),
+ EDEF(BITMAP),
+ EDEF(COLOR),
+ EDEF(DEPTH),
+ EDEF(STENCIL),
+ EDEF(DITHER),
+ EDEF(RGB),
+ EDEF(RGBA),
+ EDEF(MAX_LIST_NESTING),
+ EDEF(MAX_ATTRIB_STACK_DEPTH),
+ EDEF(MAX_MODELVIEW_STACK_DEPTH),
+ EDEF(MAX_NAME_STACK_DEPTH),
+ EDEF(MAX_PROJECTION_STACK_DEPTH),
+ EDEF(MAX_TEXTURE_STACK_DEPTH),
+ EDEF(MAX_EVAL_ORDER),
+ EDEF(MAX_LIGHTS),
+ EDEF(MAX_CLIP_PLANES),
+ EDEF(MAX_TEXTURE_SIZE),
+ EDEF(MAX_PIXEL_MAP_TABLE),
+ EDEF(MAX_VIEWPORT_DIMS),
+ EDEF(MAX_CLIENT_ATTRIB_STACK_DEPTH),
+ EDEF(ATTRIB_STACK_DEPTH),
+ EDEF(CLIENT_ATTRIB_STACK_DEPTH),
+ EDEF(COLOR_CLEAR_VALUE),
+ EDEF(COLOR_WRITEMASK),
+ EDEF(CURRENT_INDEX),
+ EDEF(CURRENT_COLOR),
+ EDEF(CURRENT_NORMAL),
+ EDEF(CURRENT_RASTER_COLOR),
+ EDEF(CURRENT_RASTER_DISTANCE),
+ EDEF(CURRENT_RASTER_INDEX),
+ EDEF(CURRENT_RASTER_POSITION),
+ EDEF(CURRENT_RASTER_TEXTURE_COORDS),
+ EDEF(CURRENT_RASTER_POSITION_VALID),
+ EDEF(CURRENT_TEXTURE_COORDS),
+ EDEF(INDEX_CLEAR_VALUE),
+ EDEF(INDEX_MODE),
+ EDEF(INDEX_WRITEMASK),
+ EDEF(MODELVIEW_MATRIX),
+ EDEF(MODELVIEW_STACK_DEPTH),
+ EDEF(NAME_STACK_DEPTH),
+ EDEF(PROJECTION_MATRIX),
+ EDEF(PROJECTION_STACK_DEPTH),
+ EDEF(RENDER_MODE),
+ EDEF(RGBA_MODE),
+ EDEF(TEXTURE_MATRIX),
+ EDEF(TEXTURE_STACK_DEPTH),
+ EDEF(VIEWPORT),
+ EDEF(AUTO_NORMAL),
+ EDEF(MAP1_COLOR_4),
+ EDEF(MAP1_GRID_DOMAIN),
+ EDEF(MAP1_GRID_SEGMENTS),
+ EDEF(MAP1_INDEX),
+ EDEF(MAP1_NORMAL),
+ EDEF(MAP1_TEXTURE_COORD_1),
+ EDEF(MAP1_TEXTURE_COORD_2),
+ EDEF(MAP1_TEXTURE_COORD_3),
+ EDEF(MAP1_TEXTURE_COORD_4),
+ EDEF(MAP1_VERTEX_3),
+ EDEF(MAP1_VERTEX_4),
+ EDEF(MAP2_COLOR_4),
+ EDEF(MAP2_GRID_DOMAIN),
+ EDEF(MAP2_GRID_SEGMENTS),
+ EDEF(MAP2_INDEX),
+ EDEF(MAP2_NORMAL),
+ EDEF(MAP2_TEXTURE_COORD_1),
+ EDEF(MAP2_TEXTURE_COORD_2),
+ EDEF(MAP2_TEXTURE_COORD_3),
+ EDEF(MAP2_TEXTURE_COORD_4),
+ EDEF(MAP2_VERTEX_3),
+ EDEF(MAP2_VERTEX_4),
+ EDEF(COEFF),
+ EDEF(DOMAIN),
+ EDEF(ORDER),
+ EDEF(FOG_HINT),
+ EDEF(LINE_SMOOTH_HINT),
+ EDEF(PERSPECTIVE_CORRECTION_HINT),
+ EDEF(POINT_SMOOTH_HINT),
+ EDEF(POLYGON_SMOOTH_HINT),
+ EDEF(DONT_CARE),
+ EDEF(FASTEST),
+ EDEF(NICEST),
+ EDEF(SCISSOR_TEST),
+ EDEF(SCISSOR_BOX),
+ EDEF(MAP_COLOR),
+ EDEF(MAP_STENCIL),
+ EDEF(INDEX_SHIFT),
+ EDEF(INDEX_OFFSET),
+ EDEF(RED_SCALE),
+ EDEF(RED_BIAS),
+ EDEF(GREEN_SCALE),
+ EDEF(GREEN_BIAS),
+ EDEF(BLUE_SCALE),
+ EDEF(BLUE_BIAS),
+ EDEF(ALPHA_SCALE),
+ EDEF(ALPHA_BIAS),
+ EDEF(DEPTH_SCALE),
+ EDEF(DEPTH_BIAS),
+ EDEF(PIXEL_MAP_S_TO_S_SIZE),
+ EDEF(PIXEL_MAP_I_TO_I_SIZE),
+ EDEF(PIXEL_MAP_I_TO_R_SIZE),
+ EDEF(PIXEL_MAP_I_TO_G_SIZE),
+ EDEF(PIXEL_MAP_I_TO_B_SIZE),
+ EDEF(PIXEL_MAP_I_TO_A_SIZE),
+ EDEF(PIXEL_MAP_R_TO_R_SIZE),
+ EDEF(PIXEL_MAP_G_TO_G_SIZE),
+ EDEF(PIXEL_MAP_B_TO_B_SIZE),
+ EDEF(PIXEL_MAP_A_TO_A_SIZE),
+ EDEF(PIXEL_MAP_S_TO_S),
+ EDEF(PIXEL_MAP_I_TO_I),
+ EDEF(PIXEL_MAP_I_TO_R),
+ EDEF(PIXEL_MAP_I_TO_G),
+ EDEF(PIXEL_MAP_I_TO_B),
+ EDEF(PIXEL_MAP_I_TO_A),
+ EDEF(PIXEL_MAP_R_TO_R),
+ EDEF(PIXEL_MAP_G_TO_G),
+ EDEF(PIXEL_MAP_B_TO_B),
+ EDEF(PIXEL_MAP_A_TO_A),
+ EDEF(PACK_ALIGNMENT),
+ EDEF(PACK_LSB_FIRST),
+ EDEF(PACK_ROW_LENGTH),
+ EDEF(PACK_SKIP_PIXELS),
+ EDEF(PACK_SKIP_ROWS),
+ EDEF(PACK_SWAP_BYTES),
+ EDEF(UNPACK_ALIGNMENT),
+ EDEF(UNPACK_LSB_FIRST),
+ EDEF(UNPACK_ROW_LENGTH),
+ EDEF(UNPACK_SKIP_PIXELS),
+ EDEF(UNPACK_SKIP_ROWS),
+ EDEF(UNPACK_SWAP_BYTES),
+ EDEF(ZOOM_X),
+ EDEF(ZOOM_Y),
+ EDEF(TEXTURE_ENV),
+ EDEF(TEXTURE_ENV_MODE),
+ EDEF(TEXTURE_1D),
+ EDEF(TEXTURE_2D),
+ EDEF(TEXTURE_WRAP_S),
+ EDEF(TEXTURE_WRAP_T),
+ EDEF(TEXTURE_MAG_FILTER),
+ EDEF(TEXTURE_MIN_FILTER),
+ EDEF(TEXTURE_ENV_COLOR),
+ EDEF(TEXTURE_GEN_S),
+ EDEF(TEXTURE_GEN_T),
+ EDEF(TEXTURE_GEN_MODE),
+ EDEF(TEXTURE_BORDER_COLOR),
+ EDEF(TEXTURE_WIDTH),
+ EDEF(TEXTURE_HEIGHT),
+ EDEF(TEXTURE_BORDER),
+ EDEF(TEXTURE_COMPONENTS),
+ EDEF(TEXTURE_RED_SIZE),
+ EDEF(TEXTURE_GREEN_SIZE),
+ EDEF(TEXTURE_BLUE_SIZE),
+ EDEF(TEXTURE_ALPHA_SIZE),
+ EDEF(TEXTURE_LUMINANCE_SIZE),
+ EDEF(TEXTURE_INTENSITY_SIZE),
+ EDEF(NEAREST_MIPMAP_NEAREST),
+ EDEF(NEAREST_MIPMAP_LINEAR),
+ EDEF(LINEAR_MIPMAP_NEAREST),
+ EDEF(LINEAR_MIPMAP_LINEAR),
+ EDEF(OBJECT_LINEAR),
+ EDEF(OBJECT_PLANE),
+ EDEF(EYE_LINEAR),
+ EDEF(EYE_PLANE),
+ EDEF(SPHERE_MAP),
+ EDEF(DECAL),
+ EDEF(MODULATE),
+ EDEF(NEAREST),
+ EDEF(REPEAT),
+ EDEF(CLAMP),
+ EDEF(S),
+ EDEF(T),
+ EDEF(R),
+ EDEF(Q),
+ EDEF(TEXTURE_GEN_R),
+ EDEF(TEXTURE_GEN_Q),
+ EDEF(PROXY_TEXTURE_1D),
+ EDEF(PROXY_TEXTURE_2D),
+ EDEF(TEXTURE_PRIORITY),
+ EDEF(TEXTURE_RESIDENT),
+ EDEF(TEXTURE_BINDING_1D),
+ EDEF(TEXTURE_BINDING_2D),
+ EDEF(TEXTURE_INTERNAL_FORMAT),
+ EDEF(PACK_SKIP_IMAGES),
+ EDEF(PACK_IMAGE_HEIGHT),
+ EDEF(UNPACK_SKIP_IMAGES),
+ EDEF(UNPACK_IMAGE_HEIGHT),
+ EDEF(TEXTURE_3D),
+ EDEF(PROXY_TEXTURE_3D),
+ EDEF(TEXTURE_DEPTH),
+ EDEF(TEXTURE_WRAP_R),
+ EDEF(MAX_3D_TEXTURE_SIZE),
+ EDEF(TEXTURE_BINDING_3D),
+ EDEF(ALPHA4),
+ EDEF(ALPHA8),
+ EDEF(ALPHA12),
+ EDEF(ALPHA16),
+ EDEF(LUMINANCE4),
+ EDEF(LUMINANCE8),
+ EDEF(LUMINANCE12),
+ EDEF(LUMINANCE16),
+ EDEF(LUMINANCE4_ALPHA4),
+ EDEF(LUMINANCE6_ALPHA2),
+ EDEF(LUMINANCE8_ALPHA8),
+ EDEF(LUMINANCE12_ALPHA4),
+ EDEF(LUMINANCE12_ALPHA12),
+ EDEF(LUMINANCE16_ALPHA16),
+ EDEF(INTENSITY),
+ EDEF(INTENSITY4),
+ EDEF(INTENSITY8),
+ EDEF(INTENSITY12),
+ EDEF(INTENSITY16),
+ EDEF(R3_G3_B2),
+ EDEF(RGB4),
+ EDEF(RGB5),
+ EDEF(RGB8),
+ EDEF(RGB10),
+ EDEF(RGB12),
+ EDEF(RGB16),
+ EDEF(RGBA2),
+ EDEF(RGBA4),
+ EDEF(RGB5_A1),
+ EDEF(RGBA8),
+ EDEF(RGB10_A2),
+ EDEF(RGBA12),
+ EDEF(RGBA16),
+ EDEF(VENDOR),
+ EDEF(RENDERER),
+ EDEF(VERSION),
+ EDEF(EXTENSIONS),
+ EDEF(INVALID_VALUE),
+ EDEF(INVALID_ENUM),
+ EDEF(INVALID_OPERATION),
+ EDEF(STACK_OVERFLOW),
+ EDEF(STACK_UNDERFLOW),
+ EDEF(OUT_OF_MEMORY),
+
+ /* extensions */
+ EDEF(CONSTANT_COLOR_EXT),
+ EDEF(ONE_MINUS_CONSTANT_COLOR_EXT),
+ EDEF(CONSTANT_ALPHA_EXT),
+ EDEF(ONE_MINUS_CONSTANT_ALPHA_EXT),
+ EDEF(BLEND_EQUATION_EXT),
+ EDEF(MIN_EXT),
+ EDEF(MAX_EXT),
+ EDEF(FUNC_ADD_EXT),
+ EDEF(FUNC_SUBTRACT_EXT),
+ EDEF(FUNC_REVERSE_SUBTRACT_EXT),
+ EDEF(BLEND_COLOR_EXT),
+ EDEF(POLYGON_OFFSET_EXT),
+ EDEF(POLYGON_OFFSET_FACTOR_EXT),
+ EDEF(POLYGON_OFFSET_BIAS_EXT),
+ EDEF(VERTEX_ARRAY_EXT),
+ EDEF(NORMAL_ARRAY_EXT),
+ EDEF(COLOR_ARRAY_EXT),
+ EDEF(INDEX_ARRAY_EXT),
+ EDEF(TEXTURE_COORD_ARRAY_EXT),
+ EDEF(EDGE_FLAG_ARRAY_EXT),
+ EDEF(VERTEX_ARRAY_SIZE_EXT),
+ EDEF(VERTEX_ARRAY_TYPE_EXT),
+ EDEF(VERTEX_ARRAY_STRIDE_EXT),
+ EDEF(VERTEX_ARRAY_COUNT_EXT),
+ EDEF(NORMAL_ARRAY_TYPE_EXT),
+ EDEF(NORMAL_ARRAY_STRIDE_EXT),
+ EDEF(NORMAL_ARRAY_COUNT_EXT),
+ EDEF(COLOR_ARRAY_SIZE_EXT),
+ EDEF(COLOR_ARRAY_TYPE_EXT),
+ EDEF(COLOR_ARRAY_STRIDE_EXT),
+ EDEF(COLOR_ARRAY_COUNT_EXT),
+ EDEF(INDEX_ARRAY_TYPE_EXT),
+ EDEF(INDEX_ARRAY_STRIDE_EXT),
+ EDEF(INDEX_ARRAY_COUNT_EXT),
+ EDEF(TEXTURE_COORD_ARRAY_SIZE_EXT),
+ EDEF(TEXTURE_COORD_ARRAY_TYPE_EXT),
+ EDEF(TEXTURE_COORD_ARRAY_STRIDE_EXT),
+ EDEF(TEXTURE_COORD_ARRAY_COUNT_EXT),
+ EDEF(EDGE_FLAG_ARRAY_STRIDE_EXT),
+ EDEF(EDGE_FLAG_ARRAY_COUNT_EXT),
+ EDEF(VERTEX_ARRAY_POINTER_EXT),
+ EDEF(NORMAL_ARRAY_POINTER_EXT),
+ EDEF(COLOR_ARRAY_POINTER_EXT),
+ EDEF(INDEX_ARRAY_POINTER_EXT),
+ EDEF(TEXTURE_COORD_ARRAY_POINTER_EXT),
+ EDEF(EDGE_FLAG_ARRAY_POINTER_EXT),
+ EDEF(TEXTURE_PRIORITY_EXT),
+ EDEF(TEXTURE_RESIDENT_EXT),
+ EDEF(TEXTURE_1D_BINDING_EXT),
+ EDEF(TEXTURE_2D_BINDING_EXT),
+ EDEF(PACK_SKIP_IMAGES_EXT),
+ EDEF(PACK_IMAGE_HEIGHT_EXT),
+ EDEF(UNPACK_SKIP_IMAGES_EXT),
+ EDEF(UNPACK_IMAGE_HEIGHT_EXT),
+ EDEF(TEXTURE_3D_EXT),
+ EDEF(PROXY_TEXTURE_3D_EXT),
+ EDEF(TEXTURE_DEPTH_EXT),
+ EDEF(TEXTURE_WRAP_R_EXT),
+ EDEF(MAX_3D_TEXTURE_SIZE_EXT),
+ EDEF(TEXTURE_3D_BINDING_EXT),
+ EDEF(TABLE_TOO_LARGE_EXT),
+ EDEF(COLOR_TABLE_FORMAT_EXT),
+ EDEF(COLOR_TABLE_WIDTH_EXT),
+ EDEF(COLOR_TABLE_RED_SIZE_EXT),
+ EDEF(COLOR_TABLE_GREEN_SIZE_EXT),
+ EDEF(COLOR_TABLE_BLUE_SIZE_EXT),
+ EDEF(COLOR_TABLE_ALPHA_SIZE_EXT),
+ EDEF(COLOR_TABLE_LUMINANCE_SIZE_EXT),
+ EDEF(COLOR_TABLE_INTENSITY_SIZE_EXT),
+ EDEF(TEXTURE_INDEX_SIZE_EXT),
+ EDEF(COLOR_INDEX1_EXT),
+ EDEF(COLOR_INDEX2_EXT),
+ EDEF(COLOR_INDEX4_EXT),
+ EDEF(COLOR_INDEX8_EXT),
+ EDEF(COLOR_INDEX12_EXT),
+ EDEF(COLOR_INDEX16_EXT),
+ EDEF(SHARED_TEXTURE_PALETTE_EXT),
+ EDEF(POINT_SIZE_MIN_EXT),
+ EDEF(POINT_SIZE_MAX_EXT),
+ EDEF(POINT_FADE_THRESHOLD_SIZE_EXT),
+ EDEF(DISTANCE_ATTENUATION_EXT),
+ EDEF(RESCALE_NORMAL_EXT),
+ EDEF(ABGR_EXT),
+ EDEF(SELECTED_TEXTURE_SGIS),
+ EDEF(SELECTED_TEXTURE_COORD_SET_SGIS),
+ EDEF(MAX_TEXTURES_SGIS),
+ EDEF(TEXTURE0_SGIS),
+ EDEF(TEXTURE1_SGIS),
+ EDEF(TEXTURE2_SGIS),
+ EDEF(TEXTURE3_SGIS),
+ EDEF(TEXTURE_COORD_SET_SOURCE_SGIS),
+ EDEF(SELECTED_TEXTURE_EXT),
+ EDEF(SELECTED_TEXTURE_COORD_SET_EXT),
+ EDEF(SELECTED_TEXTURE_TRANSFORM_EXT),
+ EDEF(MAX_TEXTURES_EXT),
+ EDEF(MAX_TEXTURE_COORD_SETS_EXT),
+ EDEF(TEXTURE_ENV_COORD_SET_EXT),
+ EDEF(TEXTURE0_EXT),
+ EDEF(TEXTURE1_EXT),
+ EDEF(TEXTURE2_EXT),
+ EDEF(TEXTURE3_EXT),
+ EDEF(CLAMP_TO_EDGE_SGIS),
+ EDEF(RESCALE_NORMAL),
+ EDEF(CLAMP_TO_EDGE),
+ EDEF(MAX_ELEMENTS_VERTICES),
+ EDEF(MAX_ELEMENTS_INDICES),
+ EDEF(BGR),
+ EDEF(BGRA),
+ EDEF(UNSIGNED_BYTE_3_3_2),
+ EDEF(UNSIGNED_BYTE_2_3_3_REV),
+ EDEF(UNSIGNED_SHORT_5_6_5),
+ EDEF(UNSIGNED_SHORT_5_6_5_REV),
+ EDEF(UNSIGNED_SHORT_4_4_4_4),
+ EDEF(UNSIGNED_SHORT_4_4_4_4_REV),
+ EDEF(UNSIGNED_SHORT_5_5_5_1),
+ EDEF(UNSIGNED_SHORT_1_5_5_5_REV),
+ EDEF(UNSIGNED_INT_8_8_8_8),
+ EDEF(UNSIGNED_INT_8_8_8_8_REV),
+ EDEF(UNSIGNED_INT_10_10_10_2),
+ EDEF(UNSIGNED_INT_2_10_10_10_REV),
+ EDEF(LIGHT_MODEL_COLOR_CONTROL),
+ EDEF(SINGLE_COLOR),
+ EDEF(SEPARATE_SPECULAR_COLOR),
+ EDEF(TEXTURE_MIN_LOD),
+ EDEF(TEXTURE_MAX_LOD),
+ EDEF(TEXTURE_BASE_LEVEL),
+ EDEF(TEXTURE_MAX_LEVEL)
+};
+
+#undef EDEF
+
+#define N_ENUMS (sizeof(enums) / sizeof(ENUM))
+
+/***************************************************************************/
+
+static void print_enum_name( FILE* OUT, GLenum e )
+{
+ int i, found= 0;
+ for( i= 0; i < N_ENUMS; ++i )
+ {
+ if( enums[i].e == e )
+ {
+ if( found )
+ fprintf( OUT, "/" );
+ found= 1;
+ fprintf( OUT, "%s", enums[i].name );
+ }
+ }
+ if( ! found )
+ fprintf( OUT, "*UNKNOWN* [%04x]", (int)e );
+ fprintf( OUT, "\n" );
+}
+
+#define BOOL_STRING(b) (b ? "true" : "false")
+
+#define VAR_ENUM(VAR) \
+ { \
+ GLint e= 0; \
+ glGetIntegerv(GL_##VAR,&e); \
+ fprintf( OUT, "%s: ", #VAR ); \
+ print_enum_name( OUT, (GLenum) e ); \
+ }
+
+#define VAR_FLOAT4(VAR) \
+ { \
+ GLfloat f[4]; \
+ f[0]= f[1]= f[2]= f[3]= 0.0; \
+ glGetFloatv(GL_##VAR,f); \
+ fprintf( OUT, "%s: [%f %f %f %f]\n", \
+ #VAR, f[0], f[1], f[2], f[3] ); \
+ }
+
+#define VAR_MAT_FLOAT4(VAR) \
+ { \
+ GLfloat f[4]; \
+ f[0]= f[1]= f[2]= f[3]= 0.0; \
+ glGetMaterialfv(GL_FRONT,GL_##VAR,f); \
+ fprintf( OUT, "FRONT_%s: [%f %f %f %f]\n", \
+ #VAR, f[0], f[1], f[2], f[3] ); \
+ glGetMaterialfv(GL_BACK,GL_##VAR,f); \
+ fprintf( OUT, " BACK_%s: [%f %f %f %f]\n", \
+ #VAR, f[0], f[1], f[2], f[3] ); \
+ }
+
+#define VAR_LIGHT_FLOAT4(LIGHT,VAR) \
+ { \
+ GLfloat f[4]; \
+ f[0]= f[1]= f[2]= f[3]= 0.0; \
+ glGetLightfv(GL_LIGHT0+LIGHT,GL_##VAR,f); \
+ fprintf( OUT, "LIGHT%d.%s: [%f %f %f %f]\n", \
+ LIGHT, #VAR, f[0], f[1], f[2], f[3] ); \
+ }
+
+#define VAR_LIGHT_FLOAT3(LIGHT,VAR) \
+ { \
+ GLfloat f[3]; \
+ f[0]= f[1]= f[2]= 0.0; \
+ glGetLightfv(GL_LIGHT0+LIGHT,GL_##VAR,f); \
+ fprintf( OUT, "LIGHT%d.%s: [%f %f %f]\n", \
+ LIGHT, #VAR, f[0], f[1], f[2] ); \
+ }
+
+#define VAR_FLOAT3(VAR) \
+ { \
+ GLfloat f[3]; \
+ f[0]= f[1]= f[2]= 0.0; \
+ glGetFloatv(GL_##VAR,f) ; \
+ fprintf( OUT, "%s: [%f %f %f]\n", \
+ #VAR, f[0], f[1], f[2] ); \
+ }
+#define VAR_FLOAT2(VAR) \
+ { \
+ GLfloat f[2]; \
+ f[0]= f[1]= 0.0; \
+ glGetFloatv(GL_##VAR,f); \
+ fprintf( OUT, "%s: [%f %f]\n", \
+ #VAR, f[0], f[1] ); \
+ }
+
+#define VAR_COLOR(VAR) VAR_FLOAT4(VAR)
+#define VAR_TEXCOORD(VAR) VAR_FLOAT4(VAR)
+#define VAR_NORMAL(VAR) VAR_FLOAT3(VAR)
+
+#define VAR_MAT_COLOR(VAR) VAR_MAT_FLOAT4(VAR)
+#define VAR_LIGHT_COLOR(LIGHT,VAR) VAR_LIGHT_FLOAT4(LIGHT,VAR)
+
+#define VAR_FLOAT(VAR) \
+ { \
+ GLfloat f= 0.0; \
+ glGetFloatv(GL_##VAR,&f); \
+ fprintf( OUT, "%s: %f\n", #VAR, f ); \
+ }
+
+#define VAR_MAT_FLOAT(VAR) \
+ { \
+ GLfloat f= 0.0; \
+ glGetMaterialfv(GL_FRONT,GL_##VAR,&f); \
+ fprintf( OUT, "FRONT_%s: %f\n", #VAR, f ); \
+ glGetMaterialfv(GL_BACK,GL_##VAR,&f); \
+ fprintf( OUT, " BACK_%s: %f\n", #VAR, f ); \
+ }
+
+#define VAR_LIGHT_FLOAT(LIGHT,VAR) \
+ { \
+ GLfloat f= 0.0; \
+ glGetLightfv(GL_LIGHT0+LIGHT,GL_##VAR,&f); \
+ fprintf( OUT, "LIGHT%d.%s: %f\n", \
+ LIGHT, #VAR, f ); \
+ }
+
+#define VAR_INT(VAR) \
+ { \
+ GLint i= 0; \
+ glGetIntegerv(GL_##VAR,&i); \
+ fprintf( OUT, "%s: %d\n", #VAR, (int)i ); \
+ }
+#define VAR_INTEGER(VAR) VAR_INT(VAR)
+#define VAR_INDEX(VAR) VAR_INT(VAR)
+#define VAR_HEXINT(VAR) \
+ { \
+ GLint i= 0; \
+ glGetIntegerv(GL_##VAR,&i); \
+ fprintf( OUT, "%s: 0x%04x\n", #VAR, (int)i ); \
+ }
+#define VAR_INT4(VAR) \
+ { \
+ GLint i[4]; \
+ i[0]= i[1]= i[2]= i[3]= 0; \
+ glGetIntegerv(GL_##VAR,i); \
+ fprintf( OUT, "%s: [%d %d %d %d]\n", \
+ #VAR, (int)i[0], (int)i[1], (int)i[2], (int)i[3] ); \
+ }
+#define VAR_BOOL(VAR) \
+ { \
+ GLboolean b= 0; \
+ glGetBooleanv(GL_##VAR,&b); \
+ fprintf( OUT, "%s: %s\n", #VAR, BOOL_STRING(b) ); \
+ }
+#define VAR_BOOL4(VAR) \
+ { \
+ GLboolean b[4]; \
+ b[0]= b[1]= b[2]= b[3]= 0; \
+ glGetBooleanv(GL_##VAR,b); \
+ fprintf( OUT, "%s: [%s %s %s %s]\n", \
+ #VAR, \
+ BOOL_STRING(b[0]), \
+ BOOL_STRING(b[1]), \
+ BOOL_STRING(b[2]), \
+ BOOL_STRING(b[3]) ); \
+ }
+#define VAR_PTR(VAR) \
+ { \
+ GLvoid* p= 0; \
+ glGetPointerv(GL_##VAR,&p); \
+ fprintf( OUT, "%s: %p\n", #VAR, p ); \
+ }
+#define VAR_MATRIX(VAR) \
+ { \
+ GLfloat m[16]; \
+ int i; \
+ for( i= 0; i < 16; ++i ) m[i]= 0.0; \
+ glGetFloatv(GL_##VAR,m); \
+ fprintf( OUT, \
+ "%s:\n\t[%+.6f %+.6f %+.6f %+.6f]\n\t[%+.6f %+.6f %+.6f%+.6f]\n\t[%+.6f %+.6f %+.6f %+.6f]\n\t[%+.6f %+.6f %+.6f %+.6f]\n", \
+ #VAR, \
+ m[0+0*4], m[0+1*4], m[0+2*4], m[0+3*4], \
+ m[1+0*4], m[1+1*4], m[1+2*4], m[1+3*4], \
+ m[2+0*4], m[2+1*4], m[2+2*4], m[2+3*4], \
+ m[3+0*4], m[3+1*4], m[3+2*4], m[3+3*4] ); \
+ }
+
+/***************************************************************************/
+
+/*
+#define OUT stderr
+*/
+void dump_opengl_state( FILE* OUT )
+{
+ int i;
+ GLint n_lights= 0;
+
+ glGetIntegerv( GL_MAX_LIGHTS, &n_lights );
+
+ VAR_COLOR(CURRENT_COLOR)
+ VAR_INDEX(CURRENT_INDEX)
+ VAR_TEXCOORD(CURRENT_TEXTURE_COORDS)
+ VAR_NORMAL(CURRENT_NORMAL)
+ VAR_FLOAT4(CURRENT_RASTER_POSITION)
+ VAR_FLOAT(CURRENT_RASTER_DISTANCE)
+ VAR_COLOR(CURRENT_RASTER_COLOR)
+ VAR_INDEX(CURRENT_RASTER_INDEX)
+ VAR_TEXCOORD(CURRENT_RASTER_TEXTURE_COORDS)
+ VAR_BOOL(CURRENT_RASTER_POSITION_VALID)
+ VAR_BOOL(EDGE_FLAG)
+
+ VAR_BOOL (VERTEX_ARRAY)
+ VAR_INTEGER(VERTEX_ARRAY_SIZE)
+ VAR_ENUM (VERTEX_ARRAY_TYPE)
+ VAR_INTEGER(VERTEX_ARRAY_STRIDE)
+ VAR_PTR (VERTEX_ARRAY_POINTER)
+
+ VAR_BOOL (NORMAL_ARRAY)
+ VAR_ENUM (NORMAL_ARRAY_TYPE)
+ VAR_INTEGER(NORMAL_ARRAY_STRIDE)
+ VAR_PTR (NORMAL_ARRAY_POINTER)
+
+ VAR_BOOL (COLOR_ARRAY)
+ VAR_INTEGER(COLOR_ARRAY_SIZE)
+ VAR_ENUM (COLOR_ARRAY_TYPE)
+ VAR_INTEGER(COLOR_ARRAY_STRIDE)
+ VAR_PTR (COLOR_ARRAY_POINTER)
+
+ VAR_BOOL (INDEX_ARRAY)
+ VAR_ENUM (INDEX_ARRAY_TYPE)
+ VAR_INTEGER(INDEX_ARRAY_STRIDE)
+ VAR_PTR (INDEX_ARRAY_POINTER)
+
+ VAR_BOOL (TEXTURE_COORD_ARRAY)
+ VAR_INTEGER(TEXTURE_COORD_ARRAY_SIZE)
+ VAR_ENUM (TEXTURE_COORD_ARRAY_TYPE)
+ VAR_INTEGER(TEXTURE_COORD_ARRAY_STRIDE)
+ VAR_PTR (TEXTURE_COORD_ARRAY_POINTER)
+
+ VAR_BOOL (EDGE_FLAG_ARRAY)
+ VAR_INTEGER(EDGE_FLAG_ARRAY_STRIDE)
+ VAR_PTR (EDGE_FLAG_ARRAY_POINTER)
+
+ VAR_MATRIX(MODELVIEW_MATRIX)
+ VAR_MATRIX(PROJECTION_MATRIX)
+ VAR_MATRIX(TEXTURE_MATRIX)
+ VAR_INT4(VIEWPORT)
+ VAR_FLOAT2(DEPTH_RANGE)
+ VAR_INT(MODELVIEW_STACK_DEPTH)
+ VAR_INT(PROJECTION_STACK_DEPTH)
+ VAR_INT(TEXTURE_STACK_DEPTH)
+ VAR_ENUM(MATRIX_MODE)
+ VAR_BOOL(NORMALIZE)
+ VAR_BOOL(RESCALE_NORMAL_EXT)
+ VAR_BOOL(CLIP_PLANE0)
+ VAR_BOOL(CLIP_PLANE1)
+ VAR_BOOL(CLIP_PLANE2)
+ VAR_BOOL(CLIP_PLANE3)
+ VAR_BOOL(CLIP_PLANE4)
+ VAR_BOOL(CLIP_PLANE5)
+ /* + glGetClipPlane() */
+
+ VAR_COLOR(FOG_COLOR)
+ VAR_INDEX(FOG_INDEX)
+ VAR_FLOAT(FOG_DENSITY)
+ VAR_FLOAT(FOG_START)
+ VAR_FLOAT(FOG_END)
+ VAR_ENUM(FOG_MODE)
+ VAR_BOOL(FOG)
+ VAR_ENUM(SHADE_MODEL)
+
+ VAR_BOOL(LIGHTING)
+ VAR_BOOL(COLOR_MATERIAL)
+ VAR_ENUM(COLOR_MATERIAL_PARAMETER)
+ VAR_ENUM(COLOR_MATERIAL_FACE)
+
+ VAR_MAT_COLOR(AMBIENT)
+ VAR_MAT_COLOR(DIFFUSE)
+ VAR_MAT_COLOR(SPECULAR)
+ VAR_MAT_COLOR(EMISSION)
+ VAR_MAT_FLOAT(SHININESS)
+
+ VAR_COLOR(LIGHT_MODEL_AMBIENT)
+ VAR_BOOL(LIGHT_MODEL_LOCAL_VIEWER)
+ VAR_BOOL(LIGHT_MODEL_TWO_SIDE)
+/* VAR_ENUM(LIGHT_MODEL_COLOR_CONTROL)*/
+
+ for( i= 0; i < n_lights; ++i )
+ {
+ GLboolean b= 0;
+
+ glGetBooleanv( GL_LIGHT0 + i, &b );
+ fprintf( OUT, "LIGHT%d: %s\n", i, BOOL_STRING(b) );
+
+ if( ! b )
+ continue;
+
+ VAR_LIGHT_COLOR(i,AMBIENT)
+ VAR_LIGHT_COLOR(i,DIFFUSE)
+ VAR_LIGHT_COLOR(i,SPECULAR)
+ VAR_LIGHT_FLOAT4(i,POSITION)
+ VAR_LIGHT_FLOAT(i,CONSTANT_ATTENUATION)
+ VAR_LIGHT_FLOAT(i,LINEAR_ATTENUATION)
+ VAR_LIGHT_FLOAT(i,QUADRATIC_ATTENUATION)
+ VAR_LIGHT_FLOAT3(i,SPOT_DIRECTION)
+ VAR_LIGHT_FLOAT(i,SPOT_EXPONENT)
+ VAR_LIGHT_FLOAT(i,SPOT_CUTOFF)
+ /* COLOR_INDEXES */
+ }
+
+ VAR_FLOAT(POINT_SIZE)
+ VAR_BOOL(POINT_SMOOTH)
+ VAR_FLOAT(LINE_WIDTH)
+ VAR_BOOL(LINE_SMOOTH)
+ VAR_HEXINT(LINE_STIPPLE_PATTERN)
+ VAR_INT(LINE_STIPPLE_REPEAT)
+ VAR_BOOL(LINE_STIPPLE)
+ VAR_BOOL(CULL_FACE)
+ VAR_ENUM(CULL_FACE_MODE)
+ VAR_ENUM(FRONT_FACE)
+ VAR_BOOL(POLYGON_SMOOTH)
+ VAR_ENUM(POLYGON_MODE)
+ VAR_FLOAT(POLYGON_OFFSET_FACTOR)
+ VAR_FLOAT(POLYGON_OFFSET_UNITS)
+ VAR_BOOL(POLYGON_OFFSET_POINT)
+ VAR_BOOL(POLYGON_OFFSET_LINE)
+ VAR_BOOL(POLYGON_OFFSET_FILL)
+ /* GetPolygonStipple */
+ VAR_BOOL(POLYGON_STIPPLE)
+
+ VAR_BOOL(TEXTURE_1D)
+ VAR_BOOL(TEXTURE_2D)
+/* VAR_BOOL(TEXTURE_3D)*/
+
+ VAR_INT(TEXTURE_BINDING_1D)
+ VAR_INT(TEXTURE_BINDING_2D)
+/* VAR_INT(TEXTURE_BINDING_3D)*/
+
+ /* GetTexImage() */
+ /* GetTexLevelParameter() */
+ /* GetTexEnv() */
+
+ VAR_BOOL(TEXTURE_GEN_S)
+ VAR_BOOL(TEXTURE_GEN_T)
+ VAR_BOOL(TEXTURE_GEN_R)
+ VAR_BOOL(TEXTURE_GEN_Q)
+
+ /* GetTexGen() */
+
+ VAR_BOOL(SCISSOR_TEST)
+ VAR_INT4(SCISSOR_BOX)
+ VAR_BOOL(ALPHA_TEST)
+ VAR_ENUM(ALPHA_TEST_FUNC)
+ VAR_FLOAT(ALPHA_TEST_REF)
+ VAR_BOOL(STENCIL_TEST)
+ VAR_ENUM(STENCIL_FUNC)
+ VAR_HEXINT(STENCIL_VALUE_MASK)
+ VAR_INT(STENCIL_REF)
+ VAR_ENUM(STENCIL_FAIL)
+ VAR_ENUM(STENCIL_PASS_DEPTH_FAIL)
+ VAR_ENUM(STENCIL_PASS_DEPTH_PASS)
+ VAR_BOOL(DEPTH_TEST)
+ VAR_ENUM(DEPTH_FUNC)
+ VAR_BOOL(BLEND)
+ VAR_ENUM(BLEND_SRC)
+ VAR_ENUM(BLEND_DST)
+
+ VAR_BOOL(DITHER)
+ VAR_BOOL(LOGIC_OP) /* INDEX_LOGIC_OP */
+ VAR_BOOL(COLOR_LOGIC_OP)
+
+ VAR_ENUM(DRAW_BUFFER)
+ VAR_INT(INDEX_WRITEMASK)
+ VAR_BOOL4(COLOR_WRITEMASK)
+ VAR_BOOL(DEPTH_WRITEMASK)
+ VAR_HEXINT(STENCIL_WRITEMASK)
+ VAR_COLOR(COLOR_CLEAR_VALUE)
+ VAR_INDEX(INDEX_CLEAR_VALUE)
+ VAR_FLOAT(DEPTH_CLEAR_VALUE)
+ VAR_INT(STENCIL_CLEAR_VALUE)
+ VAR_FLOAT(ACCUM_CLEAR_VALUE)
+
+ VAR_BOOL(UNPACK_SWAP_BYTES)
+ VAR_BOOL(UNPACK_LSB_FIRST)
+#ifdef UNPACK_IMAGE_HEIGHT
+ VAR_INT(UNPACK_IMAGE_HEIGHT)
+#endif
+#ifdef UNPACK_SKIP_IMAGES
+ VAR_INT(UNPACK_SKIP_IMAGES)
+#endif
+ VAR_INT(UNPACK_ROW_LENGTH)
+ VAR_INT(UNPACK_SKIP_ROWS)
+ VAR_INT(UNPACK_SKIP_PIXELS)
+ VAR_INT(UNPACK_ALIGNMENT)
+
+ VAR_BOOL(PACK_SWAP_BYTES)
+ VAR_BOOL(PACK_LSB_FIRST)
+#ifdef PACK_IMAGE_HEIGHT
+ VAR_INT(PACK_IMAGE_HEIGHT)
+#endif
+#ifdef PACK_SKIP_IMAGES
+ VAR_INT(PACK_SKIP_IMAGES)
+#endif
+ VAR_INT(PACK_ROW_LENGTH)
+ VAR_INT(PACK_SKIP_ROWS)
+ VAR_INT(PACK_SKIP_PIXELS)
+ VAR_INT(PACK_ALIGNMENT)
+
+ VAR_BOOL(MAP_COLOR)
+ VAR_BOOL(MAP_STENCIL)
+ VAR_INT(INDEX_SHIFT)
+ VAR_INT(INDEX_OFFSET)
+ VAR_FLOAT(RED_SCALE)
+ VAR_FLOAT(GREEN_SCALE)
+ VAR_FLOAT(BLUE_SCALE)
+ VAR_FLOAT(ALPHA_SCALE)
+ VAR_FLOAT(DEPTH_SCALE)
+ VAR_FLOAT(RED_BIAS)
+ VAR_FLOAT(GREEN_BIAS)
+ VAR_FLOAT(BLUE_BIAS)
+ VAR_FLOAT(ALPHA_BIAS)
+ VAR_FLOAT(DEPTH_BIAS)
+
+ VAR_FLOAT(ZOOM_X)
+ VAR_FLOAT(ZOOM_Y)
+
+ VAR_ENUM(READ_BUFFER)
+
+ VAR_BOOL(AUTO_NORMAL)
+
+ VAR_ENUM(PERSPECTIVE_CORRECTION_HINT)
+ VAR_ENUM(POINT_SMOOTH_HINT)
+ VAR_ENUM(LINE_SMOOTH_HINT)
+ VAR_ENUM(POLYGON_SMOOTH_HINT)
+ VAR_ENUM(FOG_HINT)
+
+ VAR_INT(MAX_LIGHTS)
+ VAR_INT(MAX_CLIP_PLANES)
+ VAR_INT(MAX_MODELVIEW_STACK_DEPTH)
+ VAR_INT(MAX_PROJECTION_STACK_DEPTH)
+ VAR_INT(MAX_TEXTURE_STACK_DEPTH)
+ VAR_INT(SUBPIXEL_BITS)
+#ifdef GL_MAX_3D_TEXTURE_SIZE
+ VAR_INT(MAX_3D_TEXTURE_SIZE)
+#endif
+ VAR_INT(MAX_TEXTURE_SIZE)
+ VAR_INT(MAX_PIXEL_MAP_TABLE)
+ VAR_INT(MAX_NAME_STACK_DEPTH)
+ VAR_INT(MAX_LIST_NESTING)
+ VAR_INT(MAX_EVAL_ORDER)
+ VAR_INT(MAX_VIEWPORT_DIMS)
+ VAR_INT(MAX_ATTRIB_STACK_DEPTH)
+ VAR_INT(MAX_CLIENT_ATTRIB_STACK_DEPTH)
+ VAR_INT(AUX_BUFFERS)
+ VAR_BOOL(RGBA_MODE)
+ VAR_BOOL(INDEX_MODE)
+ VAR_BOOL(DOUBLEBUFFER)
+ VAR_BOOL(STEREO)
+#ifdef GL_ALIASED_POINT_SIZE_RANGE
+ VAR_FLOAT2(ALIASED_POINT_SIZE_RANGE)
+#endif
+#ifdef GL_POINT_SIZE_RANGE
+ VAR_FLOAT2(POINT_SIZE_RANGE) /* SMOOTH_POINT_SIZE_RANGE */
+#endif
+ VAR_FLOAT(POINT_SIZE_GRANULARITY) /* SMOOTH_POINT_SIZE_GRANULARITY */
+#ifdef GL_ALIASED_LINE_WIDTH_RANGE
+ VAR_FLOAT2(ALIASED_LINE_WIDTH_RANGE)
+#endif
+ VAR_FLOAT2(LINE_WIDTH_RANGE) /* SMOOTH_LINE_WIDTH_RANGE */
+ VAR_FLOAT(LINE_WIDTH_GRANULARITY) /* SMOOTH_LINE_WIDTH_GRANULARITY */
+
+#ifdef GL_MAX_ELEMENTS_INDICES
+ VAR_INT(MAX_ELEMENTS_INDICES)
+#endif
+#ifdef GL_MAX_ELEMENTS_VERTICES
+ VAR_INT(MAX_ELEMENTS_VERTICES)
+#endif
+ VAR_INT(RED_BITS)
+ VAR_INT(GREEN_BITS)
+ VAR_INT(BLUE_BITS)
+ VAR_INT(ALPHA_BITS)
+ VAR_INT(INDEX_BITS)
+ VAR_INT(DEPTH_BITS)
+ VAR_INT(STENCIL_BITS)
+ VAR_INT(ACCUM_RED_BITS)
+ VAR_INT(ACCUM_GREEN_BITS)
+ VAR_INT(ACCUM_BLUE_BITS)
+ VAR_INT(ACCUM_ALPHA_BITS)
+
+ VAR_INT(LIST_BASE)
+ VAR_INT(LIST_INDEX)
+ VAR_ENUM(LIST_MODE)
+ VAR_INT(ATTRIB_STACK_DEPTH)
+ VAR_INT(CLIENT_ATTRIB_STACK_DEPTH)
+ VAR_INT(NAME_STACK_DEPTH)
+ VAR_ENUM(RENDER_MODE)
+ VAR_PTR(SELECTION_BUFFER_POINTER)
+ VAR_INT(SELECTION_BUFFER_SIZE)
+ VAR_PTR(FEEDBACK_BUFFER_POINTER)
+ VAR_INT(FEEDBACK_BUFFER_SIZE)
+ VAR_ENUM(FEEDBACK_BUFFER_TYPE)
+
+ /* glGetError() */
+}
+
+/***************************************************************************/
+
+/*#define TEST*/
+#ifdef TEST
+
+#include <GL/glut.h>
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(400, 300);
+ glutInitDisplayMode(GLUT_RGB);
+ glutCreateWindow(argv[0]);
+ dump_opengl_state(stdout);
+ return 0;
+}
+
+#endif
+
diff --git a/tests/mesa/util/errcheck.c b/tests/mesa/util/errcheck.c
new file mode 100644
index 00000000..c88dbcfb
--- /dev/null
+++ b/tests/mesa/util/errcheck.c
@@ -0,0 +1,27 @@
+/* errcheck.c */
+
+
+/*
+ * Call this function in your rendering loop to check for GL errors
+ * during development. Remove from release code.
+ *
+ * Written by Brian Paul and in the public domain.
+ */
+
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <stdio.h>
+
+
+
+GLboolean CheckError( const char *message )
+{
+ GLenum error = glGetError();
+ if (error) {
+ char *err = (char *) gluErrorString( error );
+ fprintf( stderr, "GL Error: %s at %s\n", err, message );
+ return GL_TRUE;
+ }
+ return GL_FALSE;
+}
diff --git a/tests/mesa/util/glstate.c b/tests/mesa/util/glstate.c
new file mode 100644
index 00000000..f3db0cc6
--- /dev/null
+++ b/tests/mesa/util/glstate.c
@@ -0,0 +1,506 @@
+/* $Id: glstate.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Print GL state information (for debugging)
+ * Copyright (C) 1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: glstate.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.4 1999/06/19 01:36:43 brianp
+ * more features added
+ *
+ * Revision 1.3 1999/02/24 05:16:20 brianp
+ * added still more records to EnumTable
+ *
+ * Revision 1.2 1998/11/24 03:47:54 brianp
+ * added more records to EnumTable
+ *
+ * Revision 1.1 1998/11/24 03:41:16 brianp
+ * Initial revision
+ *
+ */
+
+
+
+#include <assert.h>
+#include <GL/gl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "glstate.h"
+
+
+#define FLOAT 1
+#define INT 2
+#define DOUBLE 3
+#define BOOLEAN 4
+#define ENUM 5
+#define VOID 6
+#define LAST_TOKEN ~0
+
+
+struct EnumRecord {
+ GLenum enumerator; /* GLenum constant */
+ const char *string; /* string name */
+ int getType; /* INT, FLOAT, DOUBLE, BOOLEAN, ENUM, or VOID */
+ int getCount; /* number of values returned by the glGet*v() call */
+};
+
+
+/* XXX Lots more records to add here! Help, anyone? */
+
+static struct EnumRecord EnumTable[] = {
+ { GL_ACCUM_RED_BITS, "GL_ACCUM_RED_BITS", INT, 1 },
+ { GL_ACCUM_GREEN_BITS, "GL_ACCUM_GREEN_BITS", INT, 1 },
+ { GL_ACCUM_BLUE_BITS, "GL_ACCUM_BLUE_BITS", INT, 1 },
+ { GL_ACCUM_ALPHA_BITS, "GL_ACCUM_ALPHA_BITS", INT, 1 },
+ { GL_ACCUM_CLEAR_VALUE, "GL_ACCUM_CLEAR_VALUE", FLOAT, 4 },
+ { GL_ALPHA_BIAS, "GL_ALPHA_BIAS", FLOAT, 1 },
+ { GL_ALPHA_BITS, "GL_ALPHA_BITS", INT, 1 },
+ { GL_ALPHA_SCALE, "GL_ALPHA_SCALE", FLOAT, 1 },
+ { GL_ALPHA_TEST, "GL_ALPHA_TEST", BOOLEAN, 1 },
+ { GL_ALPHA_TEST_FUNC, "GL_ALPHA_TEST_FUNC", ENUM, 1 },
+ { GL_ALWAYS, "GL_ALWAYS", ENUM, 0 },
+ { GL_ALPHA_TEST_REF, "GL_ALPHA_TEST_REF", FLOAT, 1 },
+ { GL_ATTRIB_STACK_DEPTH, "GL_ATTRIB_STACK_DEPTH", INT, 1 },
+ { GL_AUTO_NORMAL, "GL_AUTO_NORMAL", BOOLEAN, 1 },
+ { GL_AUX_BUFFERS, "GL_AUX_BUFFERS", INT, 1 },
+ { GL_BLEND, "GL_BLEND", BOOLEAN, 1 },
+ { GL_BLEND_DST, "GL_BLEND_DST", ENUM, 1 },
+ { GL_BLEND_SRC, "GL_BLEND_SRC", ENUM, 1 },
+ { GL_BLUE_BIAS, "GL_BLUE_BIAS", FLOAT, 1 },
+ { GL_BLUE_BITS, "GL_BLUE_BITS", INT, 1 },
+ { GL_BLUE_SCALE, "GL_BLUE_SCALE", FLOAT, 1 },
+
+ { GL_CLAMP_TO_EDGE, "GL_CLAMP_TO_EDGE", ENUM, 0 },
+ { GL_CLEAR, "GL_CLEAR", ENUM, 0 },
+ { GL_CLIENT_ATTRIB_STACK_DEPTH, "GL_CLIENT_ATTRIB_STACK_DEPTH", INT, 1 },
+ { GL_CLIP_PLANE0, "GL_CLIP_PLANE0", BOOLEAN, 1 },
+ { GL_CLIP_PLANE1, "GL_CLIP_PLANE1", BOOLEAN, 1 },
+ { GL_CLIP_PLANE2, "GL_CLIP_PLANE2", BOOLEAN, 1 },
+ { GL_CLIP_PLANE3, "GL_CLIP_PLANE3", BOOLEAN, 1 },
+ { GL_CLIP_PLANE4, "GL_CLIP_PLANE4", BOOLEAN, 1 },
+ { GL_CLIP_PLANE5, "GL_CLIP_PLANE5", BOOLEAN, 1 },
+ { GL_COEFF, "GL_COEEF", ENUM, 0 },
+ { GL_COLOR, "GL_COLOR", ENUM, 0 },
+ { GL_COLOR_BUFFER_BIT, "GL_COLOR_BUFFER_BIT", ENUM, 0 },
+ { GL_COLOR_CLEAR_VALUE, "GL_COLOR_CLEAR_VALUE", FLOAT, 4 },
+ { GL_COLOR_INDEX, "GL_COLOR_INDEX", ENUM, 0 },
+ { GL_COLOR_MATERIAL, "GL_COLOR_MATERIAL", BOOLEAN, 1 },
+ { GL_COLOR_MATERIAL_FACE, "GL_COLOR_MATERIAL_FACE", ENUM, 1 },
+ { GL_COLOR_MATERIAL_PARAMETER, "GL_COLOR_MATERIAL_PARAMETER", ENUM, 1 },
+ { GL_COLOR_WRITEMASK, "GL_COLOR_WRITEMASK", BOOLEAN, 4 },
+ { GL_COMPILE, "GL_COMPILE", ENUM, 0 },
+ { GL_COMPILE_AND_EXECUTE, "GL_COMPILE_AND_EXECUTE", ENUM, 0 },
+ { GL_COPY, "GL_COPY", ENUM, 0 },
+ { GL_COPY_INVERTED, "GL_COPY_INVERTED", ENUM, 0 },
+ { GL_COPY_PIXEL_TOKEN, "GL_COPY_PIXEL_TOKEN", ENUM, 0 },
+ { GL_CULL_FACE, "GL_CULL_FACE", BOOLEAN, 1 },
+ { GL_CULL_FACE_MODE, "GL_CULL_FACE_MODE", ENUM, 1 },
+ { GL_CURRENT_BIT, "GL_CURRENT_BIT", ENUM, 0 },
+ { GL_CURRENT_COLOR, "GL_CURRENT_COLOR", FLOAT, 4 },
+ { GL_CURRENT_INDEX, "GL_CURRENT_INDEX", INT, 1 },
+ { GL_CURRENT_NORMAL, "GL_CURRENT_NORMAL", FLOAT, 3 },
+ { GL_CURRENT_RASTER_COLOR, "GL_CURRENT_RASTER_COLOR", FLOAT, 4 },
+ { GL_CURRENT_RASTER_DISTANCE, "GL_CURRENT_RASTER_DISTANCE", FLOAT, 1 },
+ { GL_CURRENT_RASTER_INDEX, "GL_CURRENT_RASTER_INDEX", INT, 1 },
+ { GL_CURRENT_RASTER_POSITION, "GL_CURRENT_RASTER_POSITION", FLOAT, 4 },
+ { GL_CURRENT_RASTER_TEXTURE_COORDS, "GL_CURRENT_RASTER_TEXTURE_COORDS", FLOAT, 4 },
+ { GL_CURRENT_RASTER_POSITION_VALID, "GL_CURRENT_RASTER_POSITION_VALID", BOOLEAN, 1 },
+ { GL_CURRENT_TEXTURE_COORDS, "GL_CURRENT_TEXTURE_COORDS", FLOAT, 4 },
+ { GL_CW, "GL_CW", ENUM, 0 },
+ { GL_CCW, "GL_CCW", ENUM, 0 },
+
+ { GL_DECAL, "GL_DECAL", ENUM, 0 },
+ { GL_DECR, "GL_DECR", ENUM, 0 },
+ { GL_DEPTH, "GL_DEPTH", ENUM, 0 },
+ { GL_DEPTH_BIAS, "GL_DEPTH_BIAS", FLOAT, 1 },
+ { GL_DEPTH_BITS, "GL_DEPTH_BITS", INT, 1 },
+ { GL_DEPTH_BUFFER_BIT, "GL_DEPTH_BUFFER_BIT", ENUM, 0 },
+ { GL_DEPTH_CLEAR_VALUE, "GL_DEPTH_CLEAR_VALUE", FLOAT, 1 },
+ { GL_DEPTH_COMPONENT, "GL_DEPTH_COMPONENT", ENUM, 0 },
+ { GL_DEPTH_FUNC, "GL_DEPTH_FUNC", ENUM, 1 },
+ { GL_DEPTH_RANGE, "GL_DEPTH_RANGE", FLOAT, 2 },
+ { GL_DEPTH_SCALE, "GL_DEPTH_SCALE", FLOAT, 1 },
+ { GL_DEPTH_TEST, "GL_DEPTH_TEST", ENUM, 1 },
+ { GL_DEPTH_WRITEMASK, "GL_DEPTH_WRITEMASK", BOOLEAN, 1 },
+ { GL_DIFFUSE, "GL_DIFFUSE", ENUM, 0 }, /*XXX*/
+ { GL_DITHER, "GL_DITHER", BOOLEAN, 1 },
+ { GL_DOMAIN, "GL_DOMAIN", ENUM, 0 },
+ { GL_DONT_CARE, "GL_DONT_CARE", ENUM, 0 },
+ { GL_DOUBLE, "GL_DOUBLE", ENUM, 0 },
+ { GL_DOUBLEBUFFER, "GL_DOUBLEBUFFER", BOOLEAN, 1},
+ { GL_DRAW_BUFFER, "GL_DRAW_BUFFER", ENUM, 1 },
+ { GL_DRAW_PIXEL_TOKEN, "GL_DRAW_PIXEL_TOKEN", ENUM, 0 },
+ { GL_DST_ALPHA, "GL_DST_ALPHA", ENUM, 0 },
+ { GL_DST_COLOR, "GL_DST_COLOR", ENUM, 0 },
+
+ { GL_EDGE_FLAG, "GL_EDGE_FLAG", BOOLEAN, 1 },
+ /* XXX GL_EDGE_FLAG_ARRAY_* */
+ { GL_EMISSION, "GL_EMISSION", ENUM, 0 }, /* XXX */
+ { GL_ENABLE_BIT, "GL_ENABLE_BIT", ENUM, 0 },
+ { GL_EQUAL, "GL_EQUAL", ENUM, 0 },
+ { GL_EQUIV, "GL_EQUIV", ENUM, 0 },
+ { GL_EVAL_BIT, "GL_EVAL_BIT", ENUM, 0 },
+ { GL_EXP, "GL_EXP", ENUM, 0 },
+ { GL_EXP2, "GL_EXP2", ENUM, 0 },
+ { GL_EXTENSIONS, "GL_EXTENSIONS", ENUM, 0 },
+ { GL_EYE_LINEAR, "GL_EYE_LINEAR", ENUM, 0 },
+ { GL_EYE_PLANE, "GL_EYE_PLANE", ENUM, 0 },
+
+ { GL_FALSE, "GL_FALSE", ENUM, 0 },
+ { GL_FASTEST, "GL_FASTEST", ENUM, 0 },
+ { GL_FEEDBACK, "GL_FEEDBACK", ENUM, 0 },
+ { GL_FEEDBACK_BUFFER_POINTER, "GL_FEEDBACK_BUFFER_POINTER", VOID, 0 },
+ { GL_FEEDBACK_BUFFER_SIZE, "GL_FEEDBACK_BUFFER_SIZE", INT, 1 },
+ { GL_FEEDBACK_BUFFER_TYPE, "GL_FEEDBACK_BUFFER_TYPE", INT, 1 },
+ { GL_FILL, "GL_FILL", ENUM, 0 },
+ { GL_FLAT, "GL_FLAT", ENUM, 0 },
+ { GL_FLOAT, "GL_FLOAT", ENUM, 0 },
+ { GL_FOG, "GL_FOG", BOOLEAN, 1 },
+ { GL_FOG_BIT, "GL_FOG_BIT", ENUM, 0 },
+ { GL_FOG_COLOR, "GL_FOG_COLOR", FLOAT, 4 },
+ { GL_FOG_DENSITY, "GL_FOG_DENSITY", FLOAT, 1 },
+ { GL_FOG_END, "GL_FOG_END", FLOAT, 1 },
+ { GL_FOG_HINT, "GL_FOG_HINT", ENUM, 1 },
+ { GL_FOG_INDEX, "GL_FOG_INDEX", INT, 1 },
+ { GL_FOG_MODE, "GL_FOG_MODE", ENUM, 1 },
+ { GL_FOG_START, "GL_FOG_START", FLOAT, 1 },
+ { GL_FRONT, "GL_FRONT", ENUM, 0 },
+ { GL_FRONT_AND_BACK, "GL_FRONT_AND_BACK", ENUM, 0 },
+ { GL_FRONT_FACE, "GL_FRONT_FACE", ENUM, 1 },
+ { GL_FRONT_LEFT, "GL_FRONT_LEFT", ENUM, 0 },
+ { GL_FRONT_RIGHT, "GL_FRONT_RIGHT", ENUM, 0 },
+
+ { GL_GEQUAL, "GL_GEQUAL", ENUM, 0 },
+ { GL_GREATER, "GL_GREATER", ENUM, 0 },
+ { GL_GREEN, "GL_GREEN", ENUM, 0 },
+ { GL_GREEN_BIAS, "GL_GREEN_BIAS", FLOAT, 1 },
+ { GL_GREEN_BITS, "GL_GREEN_BITS", INT, 1 },
+ { GL_GREEN_SCALE, "GL_GREEN_SCALE", FLOAT, 1 },
+
+
+
+ { GL_LESS, "GL_LESS", ENUM, 0 },
+ { GL_LEQUAL, "GL_LEQUAL", ENUM, 0 },
+ { GL_LIGHTING, "GL_LIGHTING", BOOLEAN, 1 },
+ { GL_LINE_SMOOTH, "GL_LINE_SMOOTH", BOOLEAN, 1 },
+ { GL_LINE_STIPPLE, "GL_LINE_STIPPLE", BOOLEAN, 1 },
+ { GL_LINE_STIPPLE_PATTERN, "GL_LINE_STIPPLE_PATTERN", INT, 1 },
+ { GL_LINE_STIPPLE_REPEAT, "GL_LINE_STIPPLE_REPEAT", INT, 1 },
+ { GL_LINE_WIDTH, "GL_LINE_WIDTH", FLOAT, 1 },
+
+ { GL_MODELVIEW_MATRIX, "GL_MODELVIEW_MATRIX", DOUBLE, 16 },
+
+ { GL_NEVER, "GL_NEVER", ENUM, 0 },
+ { GL_NOTEQUAL, "GL_NOTEQUAL", ENUM, 0 },
+
+ { GL_PROJECTION_MATRIX, "GL_PROJECTION_MATRIX", FLOAT, 16 },
+
+ { GL_PACK_SWAP_BYTES, "GL_PACK_SWAP_BYTES", INT, 1 },
+ { GL_PACK_LSB_FIRST, "GL_PACK_LSB_FIRST", INT, 1 },
+ { GL_PACK_ROW_LENGTH, "GL_PACK_ROW_LENGTH", INT, 1 },
+ { GL_PACK_SKIP_PIXELS, "GL_PACK_SKIP_PIXELS", INT, 1 },
+ { GL_PACK_SKIP_ROWS, "GL_PACK_SKIP_ROWS", INT, 1 },
+ { GL_PACK_ALIGNMENT, "GL_PACK_ALIGNMENT", INT, 1 },
+
+ { GL_TRUE, "GL_TRUE", ENUM, 0 },
+
+ { GL_UNPACK_SWAP_BYTES, "GL_UNPACK_SWAP_BYTES", INT, 1 },
+ { GL_UNPACK_LSB_FIRST, "GL_UNPACK_LSB_FIRST", INT, 1 },
+ { GL_UNPACK_ROW_LENGTH, "GL_UNPACK_ROW_LENGTH", INT, 1 },
+ { GL_UNPACK_SKIP_PIXELS, "GL_UNPACK_SKIP_PIXELS", INT, 1 },
+ { GL_UNPACK_SKIP_ROWS, "GL_UNPACK_SKIP_ROWS", INT, 1 },
+ { GL_UNPACK_ALIGNMENT, "GL_UNPACK_ALIGNMENT", INT, 1 },
+
+ { GL_VIEWPORT, "GL_VIEWPORT", INT, 4 },
+
+
+ /*
+ * Extensions
+ */
+
+#if defined(GL_EXT_blend_minmax)
+ { GL_BLEND_EQUATION_EXT, "GL_BLEND_EQUATION_EXT", ENUM, 1 },
+#endif
+#if defined(GL_EXT_blend_color)
+ { GL_BLEND_COLOR_EXT, "GL_BLEND_COLOR_EXT", FLOAT, 4 },
+#endif
+#if defined(GL_EXT_point_parameters)
+ { GL_DISTANCE_ATTENUATION_EXT, "GL_DISTANCE_ATTENUATION_EXT", FLOAT, 1 },
+#endif
+#if 0 // problems with GL headers
+#if defined(GL_INGR_blend_func_separate)
+ { GL_BLEND_SRC_RGB_INGR, "GL_BLEND_SRC_RGB_INGR", ENUM, 1 },
+ { GL_BLEND_DST_RGB_INGR, "GL_BLEND_DST_RGB_INGR", ENUM, 1 },
+ { GL_BLEND_SRC_ALPHA_INGR, "GL_BLEND_SRC_ALPHA_INGR", ENUM, 1 },
+ { GL_BLEND_DST_ALPHA_INGR, "GL_BLEND_DST_ALPHA_INGR", ENUM, 1 },
+#endif
+#endif
+
+
+ { LAST_TOKEN, "", 0, 0 }
+};
+
+
+static const struct EnumRecord *FindRecord( GLenum var )
+{
+ int i;
+ for (i = 0; EnumTable[i].enumerator != LAST_TOKEN; i++) {
+ if (EnumTable[i].enumerator == var) {
+ return &EnumTable[i];
+ }
+ }
+ return NULL;
+}
+
+
+
+/*
+ * Return the string label for the given enum.
+ */
+const char *GetEnumString( GLenum var )
+{
+ const struct EnumRecord *rec = FindRecord(var);
+ if (rec)
+ return rec->string;
+ else
+ return NULL;
+}
+
+
+
+/*
+ * Print current value of the given state variable.
+ */
+void PrintState( int indent, GLenum var )
+{
+ const struct EnumRecord *rec = FindRecord(var);
+
+ while (indent-- > 0)
+ putchar(' ');
+
+ if (rec) {
+ if (rec->getCount <= 0) {
+ assert(rec->getType == ENUM);
+ printf("%s is not a state variable\n", rec->string);
+ }
+ else {
+ switch (rec->getType) {
+ case INT:
+ {
+ GLint values[100];
+ int i;
+ glGetIntegerv(rec->enumerator, values);
+ printf("%s = ", rec->string);
+ for (i = 0; i < rec->getCount; i++)
+ printf("%d ", values[i]);
+ printf("\n");
+ }
+ break;
+ case FLOAT:
+ {
+ GLfloat values[100];
+ int i;
+ glGetFloatv(rec->enumerator, values);
+ printf("%s = ", rec->string);
+ for (i = 0; i < rec->getCount; i++)
+ printf("%f ", values[i]);
+ printf("\n");
+ }
+ break;
+ case DOUBLE:
+ {
+ GLdouble values[100];
+ int i;
+ glGetDoublev(rec->enumerator, values);
+ printf("%s = ", rec->string);
+ for (i = 0; i < rec->getCount; i++)
+ printf("%f ", (float) values[i]);
+ printf("\n");
+ }
+ break;
+ case BOOLEAN:
+ {
+ GLboolean values[100];
+ int i;
+ glGetBooleanv(rec->enumerator, values);
+ printf("%s = ", rec->string);
+ for (i = 0; i < rec->getCount; i++)
+ printf("%s ", values[i] ? "GL_TRUE" : "GL_FALSE");
+ printf("\n");
+ }
+ break;
+ case ENUM:
+ {
+ GLint values[100];
+ int i;
+ glGetIntegerv(rec->enumerator, values);
+ printf("%s = ", rec->string);
+ for (i = 0; i < rec->getCount; i++) {
+ const char *str = GetEnumString((GLenum) values[i]);
+ if (str)
+ printf("%s ", str);
+ else
+ printf("??? ");
+ }
+ printf("\n");
+ }
+ break;
+ case VOID:
+ {
+ GLvoid *values[100];
+ int i;
+ glGetPointerv(rec->enumerator, values);
+ printf("%s = ", rec->string);
+ for (i = 0; i < rec->getCount; i++) {
+ printf("%p ", values[i]);
+ }
+ printf("\n");
+ }
+ break;
+ default:
+ printf("fatal error in PrintState()\n");
+ abort();
+ }
+ }
+ }
+ else {
+ printf("Unknown GLenum passed to PrintState()\n");
+ }
+}
+
+
+
+/*
+ * Print all glPixelStore-related state.
+ * NOTE: Should write similar functions for lighting, texturing, etc.
+ */
+void PrintPixelStoreState( void )
+{
+ const GLenum enums[] = {
+ GL_PACK_SWAP_BYTES,
+ GL_PACK_LSB_FIRST,
+ GL_PACK_ROW_LENGTH,
+ GL_PACK_SKIP_PIXELS,
+ GL_PACK_SKIP_ROWS,
+ GL_PACK_ALIGNMENT,
+ GL_UNPACK_SWAP_BYTES,
+ GL_UNPACK_LSB_FIRST,
+ GL_UNPACK_ROW_LENGTH,
+ GL_UNPACK_SKIP_PIXELS,
+ GL_UNPACK_SKIP_ROWS,
+ GL_UNPACK_ALIGNMENT,
+ 0
+ };
+ int i;
+ printf("Pixel pack/unpack state:\n");
+ for (i = 0; enums[i]; i++) {
+ PrintState(3, enums[i]);
+ }
+}
+
+
+
+
+/*
+ * Print all state for the given attribute group.
+ */
+void PrintAttribState( GLbitfield attrib )
+{
+ static const GLenum depth_buffer_enums[] = {
+ GL_DEPTH_FUNC,
+ GL_DEPTH_CLEAR_VALUE,
+ GL_DEPTH_TEST,
+ GL_DEPTH_WRITEMASK,
+ 0
+ };
+ static const GLenum fog_enums[] = {
+ GL_FOG,
+ GL_FOG_COLOR,
+ GL_FOG_DENSITY,
+ GL_FOG_START,
+ GL_FOG_END,
+ GL_FOG_INDEX,
+ GL_FOG_MODE,
+ 0
+ };
+ static const GLenum line_enums[] = {
+ GL_LINE_SMOOTH,
+ GL_LINE_STIPPLE,
+ GL_LINE_STIPPLE_PATTERN,
+ GL_LINE_STIPPLE_REPEAT,
+ GL_LINE_WIDTH,
+ 0
+ };
+
+ const GLenum *enumList = NULL;
+
+ switch (attrib) {
+ case GL_DEPTH_BUFFER_BIT:
+ enumList = depth_buffer_enums;
+ printf("GL_DEPTH_BUFFER_BIT state:\n");
+ break;
+ case GL_FOG_BIT:
+ enumList = fog_enums;
+ printf("GL_FOG_BIT state:\n");
+ break;
+ case GL_LINE_BIT:
+ enumList = line_enums;
+ printf("GL_LINE_BIT state:\n");
+ break;
+ default:
+ printf("Bad value in PrintAttribState()\n");
+ }
+
+ if (enumList) {
+ int i;
+ for (i = 0; enumList[i]; i++)
+ PrintState(3, enumList[i]);
+ }
+}
+
+
+/*#define TEST*/
+#ifdef TEST
+
+#include <GL/glut.h>
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(400, 300);
+ glutInitDisplayMode(GLUT_RGB);
+ glutCreateWindow(argv[0]);
+ PrintAttribState(GL_DEPTH_BUFFER_BIT);
+ PrintAttribState(GL_FOG_BIT);
+ PrintAttribState(GL_LINE_BIT);
+ PrintState(0, GL_ALPHA_BITS);
+ PrintState(0, GL_VIEWPORT);
+ PrintState(0, GL_ALPHA_TEST_FUNC);
+ PrintState(0, GL_MODELVIEW_MATRIX);
+ PrintState(0, GL_ALWAYS);
+ PrintPixelStoreState();
+ return 0;
+}
+
+#endif
diff --git a/tests/mesa/util/glstate.h b/tests/mesa/util/glstate.h
new file mode 100644
index 00000000..1aa4d21d
--- /dev/null
+++ b/tests/mesa/util/glstate.h
@@ -0,0 +1,53 @@
+/* $Id: glstate.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Print GL state information (for debugging)
+ * Copyright (C) 1998 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: glstate.h,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.2 1999/06/19 01:36:43 brianp
+ * more features added
+ *
+ * Revision 1.1 1998/11/24 03:41:16 brianp
+ * Initial revision
+ *
+ */
+
+
+#ifndef GLSTATE_H
+#define GLSTATE_H
+
+
+#include <GL/gl.h>
+
+
+extern const char *GetNameString( GLenum var );
+
+extern void PrintState( int indent, GLenum var );
+
+extern void PrintAttribState( GLbitfield attrib );
+
+extern void PrintPixelStoreState( void );
+
+
+#endif
diff --git a/tests/mesa/util/glutskel.c b/tests/mesa/util/glutskel.c
new file mode 100644
index 00000000..273ed9a2
--- /dev/null
+++ b/tests/mesa/util/glutskel.c
@@ -0,0 +1,139 @@
+/**
+ * A skeleton/template GLUT program
+ *
+ * Written by Brian Paul and in the public domain.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static int Win;
+static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
+static GLboolean Anim = GL_FALSE;
+
+
+static void
+Idle(void)
+{
+ Xrot += 3.0;
+ Yrot += 4.0;
+ Zrot += 2.0;
+ glutPostRedisplay();
+}
+
+
+static void
+Draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+ glRotatef(Zrot, 0, 0, 1);
+
+ glutSolidCube(2.0);
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -15.0);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'z':
+ Zrot -= step;
+ break;
+ case 'Z':
+ Zrot += step;
+ break;
+ case 27:
+ glutDestroyWindow(Win);
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+ const GLfloat step = 3.0;
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+ /* setup lighting, etc */
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(400, 400);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ Win = glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Draw);
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/tests/mesa/util/idproj.c b/tests/mesa/util/idproj.c
new file mode 100644
index 00000000..080755d9
--- /dev/null
+++ b/tests/mesa/util/idproj.c
@@ -0,0 +1,26 @@
+/* idproj.c */
+
+
+/*
+ * Setup an identity projection such that glVertex(x,y) maps to
+ * window coordinate (x,y).
+ *
+ * Written by Brian Paul and in the public domain.
+ */
+
+#include <GL/gl.h>
+
+
+
+void IdentityProjection( GLint x, GLint y, GLsizei width, GLsizei height )
+{
+ glViewport( x, y, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( (GLdouble) x, (GLdouble) y,
+ (GLdouble) width, (GLdouble) height,
+ -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+}
+
diff --git a/tests/mesa/util/imagesgi.cpp b/tests/mesa/util/imagesgi.cpp
new file mode 100644
index 00000000..f5128aab
--- /dev/null
+++ b/tests/mesa/util/imagesgi.cpp
@@ -0,0 +1,369 @@
+/******************************************************************************
+** Filename : imageSgi.cpp
+** UNCLASSIFIED
+**
+** Description : Utility to read SGI image format files. This code was
+** originally a SGI image loading utility provided with the
+** Mesa 3D library @ http://www.mesa3d.org by Brain Paul.
+** This has been extended to read all SGI image formats
+** (e.g. INT, INTA, RGB, RGBA).
+**
+** Revision History:
+** Date Name Description
+** 06/07/99 BRC Initial Release
+**
+** Note:
+**
+** The SGI Image Data (if not RLE)
+**
+** If the image is stored verbatim (without RLE), then image data directly
+** follows the 512 byte header. The data for each scanline of the first
+** channel is written first. If the image has more than 1 channel, all
+** the data for the first channel is written, followed by the remaining
+** channels. If the BPC value is 1, then each scanline is written as XSIZE
+** bytes. If the BPC value is 2, then each scanline is written as XSIZE
+** shorts. These shorts are stored in the byte order described above.
+**
+******************************************************************************/
+#define __IMAGESGI_CPP
+
+#include "imagesgi.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+
+struct sImageSgiRaw
+{
+ struct sImageSgiHeader header;
+ unsigned char *chan0;
+ unsigned char *chan1;
+ unsigned char *chan2;
+ unsigned char *chan3;
+ unsigned int *rowStart;
+ int *rowSize;
+};
+
+// Static routines
+static struct sImageSgiRaw *ImageSgiRawOpen(char const * const fileName);
+static void ImageSgiRawClose(struct sImageSgiRaw *raw);
+static void ImageSgiRawGetRow(struct sImageSgiRaw *raw, unsigned char *buf,
+ int y, int z);
+static void ImageSgiRawGetData(struct sImageSgiRaw *raw, struct sImageSgi
+*final);
+static void *SwitchEndian16(void *value);
+static void *SwitchEndian32(void *value);
+
+// Static variables
+FILE *mFp = NULL;
+unsigned char *mChanTmp = NULL;
+
+
+/*****************************************************************************/
+struct sImageSgi *ImageSgiOpen(char const * const fileName)
+{
+ struct sImageSgiRaw *raw = NULL;
+ struct sImageSgi *final = NULL;
+
+ raw = ImageSgiRawOpen(fileName);
+ final = new struct sImageSgi;
+
+ assert(final);
+ if(final)
+ {
+ final->header = raw->header;
+ final->data = NULL;
+ ImageSgiRawGetData(raw, final);
+ ImageSgiRawClose(raw);
+ }
+
+ return final;
+} // ImageSgiRawOpen
+
+
+/*****************************************************************************/
+void ImageSgiClose(struct sImageSgi *image)
+{
+
+ if(image)
+ {
+ if(image->data)
+ delete[] image->data;
+ image->data = NULL;
+ delete image;
+ }
+ image = NULL;
+
+ return;
+} // ImageSgiClose
+
+
+/*****************************************************************************/
+static struct sImageSgiRaw *ImageSgiRawOpen(char const * const fileName)
+{
+ struct sImageSgiRaw *raw = NULL;
+ int x;
+ int i;
+ bool swapFlag = false;
+ union
+ {
+ int testWord;
+ char testByte[4];
+ } endianTest;
+ endianTest.testWord = 1;
+
+ // Determine endianess of platform.
+ if(endianTest.testByte[0] == 1)
+ swapFlag = true;
+ else
+ swapFlag = false;
+
+ raw = new struct sImageSgiRaw;
+
+ assert(raw);
+ if(raw)
+ {
+ raw->chan0 = NULL;
+ raw->chan1 = NULL;
+ raw->chan2 = NULL;
+ raw->chan3 = NULL;
+ raw->rowStart = NULL;
+ raw->rowSize = NULL;
+ mFp = fopen(fileName, "rb");
+ assert(mFp);
+
+ fread(&raw->header, sizeof(struct sImageSgiHeader), 1, mFp);
+ if(swapFlag == true)
+ {
+ SwitchEndian16(&raw->header.magic);
+ SwitchEndian16(&raw->header.type);
+ SwitchEndian16(&raw->header.dim);
+ SwitchEndian16(&raw->header.xsize);
+ SwitchEndian16(&raw->header.ysize);
+ SwitchEndian16(&raw->header.zsize);
+ }
+
+ mChanTmp = new unsigned char[raw->header.xsize * raw->header.ysize];
+ assert(mChanTmp);
+ switch(raw->header.zsize)
+ {
+ case 4:
+ raw->chan3 = new unsigned char[raw->header.xsize *
+raw->header.ysize];
+ assert(raw->chan3);
+ case 3:
+ raw->chan2 = new unsigned char[raw->header.xsize *
+raw->header.ysize];
+ assert(raw->chan2);
+ case 2:
+ raw->chan1 = new unsigned char[raw->header.xsize *
+raw->header.ysize];
+ assert(raw->chan1);
+ case 1:
+ raw->chan0 = new unsigned char[raw->header.xsize *
+raw->header.ysize];
+ assert(raw->chan0);
+ }
+
+ if(raw->header.type == IMAGE_SGI_TYPE_RLE)
+ {
+ x = raw->header.ysize * raw->header.zsize * sizeof(unsigned int);
+ raw->rowStart = new unsigned int[x];
+ raw->rowSize = new int[x];
+
+ fseek(mFp, sizeof(struct sImageSgiHeader), SEEK_SET);
+ fread(raw->rowStart, 1, x, mFp);
+ fread(raw->rowSize, 1, x, mFp);
+
+ if(swapFlag == true)
+ {
+ for(i=0; i<x/sizeof(unsigned int); i++)
+ SwitchEndian32(&raw->rowStart[i]);
+ for(i=0; i<x/sizeof(int); i++)
+ SwitchEndian32(&raw->rowSize[i]);
+ }
+
+ }
+
+ }
+
+ return raw;
+} // ImageSgiRawOpen
+
+
+/*****************************************************************************/
+static void ImageSgiRawClose(struct sImageSgiRaw *raw)
+{
+
+ fclose(mFp);
+ mFp = NULL;
+
+ if(mChanTmp)
+ delete[] mChanTmp;
+ mChanTmp = NULL;
+
+ if(raw->chan0)
+ delete[] raw->chan0;
+ raw->chan0 = NULL;
+
+ if(raw->chan1)
+ delete[] raw->chan1;
+ raw->chan1 = NULL;
+
+ if(raw->chan2)
+ delete[] raw->chan2;
+ raw->chan2 = NULL;
+
+ if(raw->chan3)
+ delete[] raw->chan3;
+ raw->chan3 = NULL;
+
+ if(raw)
+ delete raw;
+ raw = NULL;
+
+ return;
+} // ImageSgiRawClose
+
+
+/*****************************************************************************/
+static void ImageSgiRawGetRow(struct sImageSgiRaw *raw, unsigned char *buf,
+ int y, int z)
+{
+ unsigned char *iPtr = NULL;
+ unsigned char *oPtr = NULL;
+ unsigned char pixel;
+ int count;
+
+ if((raw->header.type & 0xFF00) == 0x0100)
+ {
+ fseek(mFp, raw->rowStart[y+z*raw->header.ysize], SEEK_SET);
+ fread(mChanTmp, 1, (unsigned int)raw->rowSize[y+z*raw->header.ysize],
+mFp);
+ iPtr = mChanTmp;
+ oPtr = buf;
+ while(1)
+ {
+ pixel = *iPtr++;
+ count = (int)(pixel & 0x7F);
+ if(!count)
+ {
+ return;
+ }
+ if (pixel & 0x80)
+ {
+ while (count--)
+ {
+ *oPtr++ = *iPtr++;
+ }
+ }
+ else
+ {
+ pixel = *iPtr++;
+ while (count--)
+ {
+ *oPtr++ = pixel;
+ }
+ }
+ }
+ }
+ else
+ {
+ fseek(mFp,
+ sizeof(struct sImageSgiHeader)+(y*raw->header.xsize) +
+ (z*raw->header.xsize*raw->header.ysize),
+ SEEK_SET);
+ fread(buf, 1, raw->header.xsize, mFp);
+ }
+
+ return;
+} // ImageSgiRawGetRow
+
+
+/*****************************************************************************/
+static void ImageSgiRawGetData(struct sImageSgiRaw *raw, struct sImageSgi
+*final)
+{
+ unsigned char *ptr = NULL;
+ int i, j;
+
+ final->data =
+ new unsigned
+char[raw->header.xsize*raw->header.ysize*raw->header.zsize];
+ assert(final->data);
+
+ ptr = final->data;
+ for(i=0; i<raw->header.ysize; i++)
+ {
+ switch(raw->header.zsize)
+ {
+ case 1:
+ ImageSgiRawGetRow(raw, raw->chan0, i, 0);
+ for(j=0; j<raw->header.xsize; j++)
+ *(ptr++) = raw->chan0[j];
+ break;
+ case 2:
+ ImageSgiRawGetRow(raw, raw->chan0, i, 0);
+ ImageSgiRawGetRow(raw, raw->chan1, i, 1);
+ for(j=0; j<raw->header.xsize; j++)
+ {
+ *(ptr++) = raw->chan0[j];
+ *(ptr++) = raw->chan1[j];
+ }
+ break;
+ case 3:
+ ImageSgiRawGetRow(raw, raw->chan0, i, 0);
+ ImageSgiRawGetRow(raw, raw->chan1, i, 1);
+ ImageSgiRawGetRow(raw, raw->chan2, i, 2);
+ for(j=0; j<raw->header.xsize; j++)
+ {
+ *(ptr++) = raw->chan0[j];
+ *(ptr++) = raw->chan1[j];
+ *(ptr++) = raw->chan2[j];
+ }
+ break;
+ case 4:
+ ImageSgiRawGetRow(raw, raw->chan0, i, 0);
+ ImageSgiRawGetRow(raw, raw->chan1, i, 1);
+ ImageSgiRawGetRow(raw, raw->chan2, i, 2);
+ ImageSgiRawGetRow(raw, raw->chan3, i, 3);
+ for(j=0; j<raw->header.xsize; j++)
+ {
+ *(ptr++) = raw->chan0[j];
+ *(ptr++) = raw->chan1[j];
+ *(ptr++) = raw->chan2[j];
+ *(ptr++) = raw->chan3[j];
+ }
+ break;
+ }
+ }
+
+ return;
+} // ImageSgiRawGetData
+
+
+/*****************************************************************************/
+static void *SwitchEndian16(void *value)
+{
+ short value16 = *(short *) value;
+ value16 = ((value16 & 0xff00) >> 8L) +
+ ((value16 & 0x00ff) << 8L);
+ *(short *)value = value16;
+ return value;
+} // SwitchEndian16
+
+
+/*****************************************************************************/
+static void *SwitchEndian32(void *value)
+{
+ int value32 = *(int *) value;
+ value32 = ((value32 & 0xff000000) >> 24L) +
+ ((value32 & 0x00ff0000) >> 8) +
+ ((value32 & 0x0000ff00) << 8) +
+ ((value32 & 0x000000ff) << 24L);
+ *(int *)value = value32;
+ return value;
+} // SwitchEndian32
+
diff --git a/tests/mesa/util/imagesgi.h b/tests/mesa/util/imagesgi.h
new file mode 100644
index 00000000..e5ecece4
--- /dev/null
+++ b/tests/mesa/util/imagesgi.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+** Filename : imageSgi.h
+** UNCLASSIFIED
+**
+** Description : Utility to read SGI image format files. This code was
+** originally a SGI image loading utility provided with the
+** Mesa 3D library @ http://www.mesa3d.org by Brain Paul.
+** This has been extended to read all SGI image formats
+** (e.g. INT, INTA, RGB, RGBA).
+**
+** Revision History:
+** Date Name Description
+** 06/08/99 BRC Initial Release
+**
+******************************************************************************/
+
+#ifndef __IMAGESGI_H
+#define __IMAGESGI_H
+
+#define IMAGE_SGI_TYPE_VERBATIM 0
+#define IMAGE_SGI_TYPE_RLE 1
+
+struct sImageSgiHeader // 512 bytes
+{
+ short magic; // IRIS image file magic number (474)
+ char type; // Storage format (e.g. RLE or VERBATIM)
+ char numBytesPerPixelChannel; // Number of bytes per pixel channel
+ unsigned short dim; // Number of dimensions (1 to 3)
+ unsigned short xsize; // Width (in pixels)
+ unsigned short ysize; // Height (in pixels)
+ unsigned short zsize; // Number of channels (1 to 4)
+ int minimumPixelValue; // Minimum pixel value (0 to 255)
+ int maximumPixelValue; // Maximum pixel value (0 to 255)
+ char padding1[4]; // (ignored)
+ char imageName[80]; // Image name
+ int colormap; // colormap ID (0=normal, 0=dithered,
+ // 2=screen, 3=colormap)
+ char padding2[404]; // (ignored)
+};
+
+struct sImageSgi
+{
+ struct sImageSgiHeader header;
+ unsigned char *data;
+};
+
+#ifndef __IMAGESGI_CPP
+
+// RGB image load utility
+extern struct sImageSgi *ImageSgiOpen(char const * const fileName);
+extern void ImageSgiClose(struct sImageSgi *image);
+
+#endif
+
+#endif /* __IMAGESGI_H */
diff --git a/tests/mesa/util/matrix.c b/tests/mesa/util/matrix.c
new file mode 100644
index 00000000..8be2c311
--- /dev/null
+++ b/tests/mesa/util/matrix.c
@@ -0,0 +1,181 @@
+/*
+ * matrix.c
+ *
+ * Some useful matrix functions.
+ *
+ * Brian Paul
+ * 10 Feb 2004
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+
+/**
+ * Pretty-print the given matrix.
+ */
+void
+PrintMatrix(const float p[16])
+{
+ printf("[ %6.3f %6.3f %6.3f %6.3f ]\n", p[0], p[4], p[8], p[12]);
+ printf("[ %6.3f %6.3f %6.3f %6.3f ]\n", p[1], p[5], p[9], p[13]);
+ printf("[ %6.3f %6.3f %6.3f %6.3f ]\n", p[2], p[6], p[10], p[14]);
+ printf("[ %6.3f %6.3f %6.3f %6.3f ]\n", p[3], p[7], p[11], p[15]);
+}
+
+
+/**
+ * Build a glFrustum matrix.
+ */
+void
+Frustum(float left, float right, float bottom, float top, float nearZ, float farZ, float *m)
+{
+ float x = (2.0F*nearZ) / (right-left);
+ float y = (2.0F*nearZ) / (top-bottom);
+ float a = (right+left) / (right-left);
+ float b = (top+bottom) / (top-bottom);
+ float c = -(farZ+nearZ) / ( farZ-nearZ);
+ float d = -(2.0F*farZ*nearZ) / (farZ-nearZ);
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
+ M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
+ M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
+ M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
+#undef M
+}
+
+
+/**
+ * Build a glOrtho marix.
+ */
+void
+Ortho(float left, float right, float bottom, float top, float nearZ, float farZ, float *m)
+{
+#define M(row,col) m[col*4+row]
+ M(0,0) = 2.0F / (right-left);
+ M(0,1) = 0.0F;
+ M(0,2) = 0.0F;
+ M(0,3) = -(right+left) / (right-left);
+
+ M(1,0) = 0.0F;
+ M(1,1) = 2.0F / (top-bottom);
+ M(1,2) = 0.0F;
+ M(1,3) = -(top+bottom) / (top-bottom);
+
+ M(2,0) = 0.0F;
+ M(2,1) = 0.0F;
+ M(2,2) = -2.0F / (farZ-nearZ);
+ M(2,3) = -(farZ+nearZ) / (farZ-nearZ);
+
+ M(3,0) = 0.0F;
+ M(3,1) = 0.0F;
+ M(3,2) = 0.0F;
+ M(3,3) = 1.0F;
+#undef M
+}
+
+
+/**
+ * Decompose a projection matrix to determine original glFrustum or
+ * glOrtho parameters.
+ */
+void
+DecomposeProjection( const float *m,
+ int *isPerspective,
+ float *leftOut, float *rightOut,
+ float *botOut, float *topOut,
+ float *nearOut, float *farOut)
+{
+ if (m[15] == 0.0) {
+ /* perspective */
+ float p[16];
+ const float x = m[0]; /* 2N / (R-L) */
+ const float y = m[5]; /* 2N / (T-B) */
+ const float a = m[8]; /* (R+L) / (R-L) */
+ const float b = m[9]; /* (T+B) / (T-B) */
+ const float c = m[10]; /* -(F+N) / (F-N) */
+ const float d = m[14]; /* -2FN / (F-N) */
+
+ /* These equations found with simple algebra, knowing the arithmetic
+ * use to set up a typical perspective projection matrix in OpenGL.
+ */
+ const float nearZ = -d / (1.0 - c);
+ const float farZ = (c - 1.0) * nearZ / (c + 1.0);
+ const float left = nearZ * (a - 1.0) / x;
+ const float right = 2.0 * nearZ / x + left;
+ const float bottom = nearZ * (b - 1.0) / y;
+ const float top = 2.0 * nearZ / y + bottom;
+
+ *isPerspective = 1;
+ *leftOut = left;
+ *rightOut = right;
+ *botOut = bottom;
+ *topOut = top;
+ *nearOut = nearZ;
+ *farOut = farZ;
+ }
+ else {
+ /* orthographic */
+ const float x = m[0]; /* 2 / (R-L) */
+ const float y = m[5]; /* 2 / (T-B) */
+ const float z = m[10]; /* -2 / (F-N) */
+ const float a = m[12]; /* -(R+L) / (R-L) */
+ const float b = m[13]; /* -(T+B) / (T-B) */
+ const float c = m[14]; /* -(F+N) / (F-N) */
+ /* again, simple algebra */
+ const float right = -(a - 1.0) / x;
+ const float left = right - 2.0 / x;
+ const float top = -(b - 1.0) / y;
+ const float bottom = top - 2.0 / y;
+ const float farZ = (c - 1.0) / z;
+ const float nearZ = farZ + 2.0 / z;
+
+ *isPerspective = 0;
+ *leftOut = left;
+ *rightOut = right;
+ *botOut = bottom;
+ *topOut = top;
+ *nearOut = nearZ;
+ *farOut = farZ;
+ }
+}
+
+
+#if 0
+/* test harness */
+int
+main(int argc, char *argv[])
+{
+ float m[16], p[16];
+ float l, r, b, t, n, f;
+ int persp;
+ int i;
+
+#if 0
+ l = -.9;
+ r = 1.2;
+ b = -0.5;
+ t = 1.4;
+ n = 30;
+ f = 84;
+ printf(" Frustum(%f, %f, %f, %f, %f, %f\n",l+1, r+1.2, b+.5, t+.3, n, f);
+ Frustum(l+1, r+1.2, b+.5, t+.3, n, f, p);
+ DecomposeProjection(p, &persp, &l, &r, &b, &t, &n, &f);
+ printf("glFrustum(%f, %f, %f, %f, %f, %f)\n",
+ l, r, b, t, n, f);
+ PrintMatrix(p);
+#else
+ printf("Ortho(-1, 1, -1, 1, 10, 84)\n");
+ Ortho(-1, 1, -1, 1, 10, 84, m);
+ PrintMatrix(m);
+ DecomposeProjection(m, &persp, &l, &r, &b, &t, &n, &f);
+ printf("Ortho(%f, %f, %f, %f, %f, %f) %d\n", l, r, b, t, n, f, persp);
+#endif
+
+ return 0;
+}
+#endif
diff --git a/tests/mesa/util/mwmborder.c b/tests/mesa/util/mwmborder.c
new file mode 100644
index 00000000..b61ffb50
--- /dev/null
+++ b/tests/mesa/util/mwmborder.c
@@ -0,0 +1,91 @@
+/* mwmborder.c */
+
+
+/*
+ * This function shows how to remove the border, title bar, resize button,
+ * etc from a Motif window frame from inside an Xlib-based application.
+ *
+ * Brian Paul 19 Sep 1995 brianp@ssec.wisc.edu
+ *
+ * This code is in the public domain.
+ */
+
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#define HAVE_MOTIF
+#ifdef HAVE_MOTIF
+
+#include <X11/Xm/MwmUtil.h>
+
+#else
+
+/* bit definitions for MwmHints.flags */
+#define MWM_HINTS_FUNCTIONS (1L << 0)
+#define MWM_HINTS_DECORATIONS (1L << 1)
+#define MWM_HINTS_INPUT_MODE (1L << 2)
+#define MWM_HINTS_STATUS (1L << 3)
+
+/* bit definitions for MwmHints.decorations */
+#define MWM_DECOR_ALL (1L << 0)
+#define MWM_DECOR_BORDER (1L << 1)
+#define MWM_DECOR_RESIZEH (1L << 2)
+#define MWM_DECOR_TITLE (1L << 3)
+#define MWM_DECOR_MENU (1L << 4)
+#define MWM_DECOR_MINIMIZE (1L << 5)
+#define MWM_DECOR_MAXIMIZE (1L << 6)
+
+typedef struct
+{
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+} PropMotifWmHints;
+
+#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+
+#endif
+
+
+
+/*
+ * Specify which Motif window manager border decorations to put on a
+ * top-level window. For example, you can specify that a window is not
+ * resizabe, or omit the titlebar, or completely remove all decorations.
+ * Input: dpy - the X display
+ * w - the X window
+ * flags - bitwise-OR of the MWM_DECOR_xxx symbols in X11/Xm/MwmUtil.h
+ * indicating what decoration elements to enable. Zero would
+ * be no decoration.
+ */
+void set_mwm_border( Display *dpy, Window w, unsigned long flags )
+{
+ PropMotifWmHints motif_hints;
+ Atom prop, proptype;
+
+ /* setup the property */
+ motif_hints.flags = MWM_HINTS_DECORATIONS;
+ motif_hints.decorations = flags;
+
+ /* get the atom for the property */
+ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
+ if (!prop) {
+ /* something went wrong! */
+ return;
+ }
+
+ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
+ proptype = prop;
+
+ XChangeProperty( dpy, w, /* display, window */
+ prop, proptype, /* property, type */
+ 32, /* format: 32-bit datums */
+ PropModeReplace, /* mode */
+ (unsigned char *) &motif_hints, /* data */
+ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
+ );
+}
+
diff --git a/tests/mesa/util/readtex.c b/tests/mesa/util/readtex.c
new file mode 100644
index 00000000..37d5fcd0
--- /dev/null
+++ b/tests/mesa/util/readtex.c
@@ -0,0 +1,454 @@
+/* readtex.c */
+
+/*
+ * Read an SGI .rgb image file and generate a mipmap texture set.
+ * Much of this code was borrowed from SGI's tk OpenGL toolkit.
+ */
+
+
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "readtex.h"
+
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+
+/*
+** RGB Image Structure
+*/
+
+typedef struct _TK_RGBImageRec {
+ GLint sizeX, sizeY;
+ GLint components;
+ unsigned char *data;
+} TK_RGBImageRec;
+
+
+
+/******************************************************************************/
+
+typedef struct _rawImageRec {
+ unsigned short imagic;
+ unsigned short type;
+ unsigned short dim;
+ unsigned short sizeX, sizeY, sizeZ;
+ unsigned long min, max;
+ unsigned long wasteBytes;
+ char name[80];
+ unsigned long colorMap;
+ FILE *file;
+ unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
+ unsigned long rleEnd;
+ GLuint *rowStart;
+ GLint *rowSize;
+} rawImageRec;
+
+/******************************************************************************/
+
+static void ConvertShort(unsigned short *array, long length)
+{
+ unsigned long b1, b2;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)array;
+ while (length--) {
+ b1 = *ptr++;
+ b2 = *ptr++;
+ *array++ = (unsigned short) ((b1 << 8) | (b2));
+ }
+}
+
+static void ConvertLong(GLuint *array, long length)
+{
+ unsigned long b1, b2, b3, b4;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)array;
+ while (length--) {
+ b1 = *ptr++;
+ b2 = *ptr++;
+ b3 = *ptr++;
+ b4 = *ptr++;
+ *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
+ }
+}
+
+static rawImageRec *RawImageOpen(const char *fileName)
+{
+ union {
+ int testWord;
+ char testByte[4];
+ } endianTest;
+ rawImageRec *raw;
+ GLenum swapFlag;
+ int x;
+
+ endianTest.testWord = 1;
+ if (endianTest.testByte[0] == 1) {
+ swapFlag = GL_TRUE;
+ } else {
+ swapFlag = GL_FALSE;
+ }
+
+ raw = (rawImageRec *)calloc(1, sizeof(rawImageRec));
+ if (raw == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ if ((raw->file = fopen(fileName, "rb")) == NULL) {
+ perror(fileName);
+ return NULL;
+ }
+
+ fread(raw, 1, 12, raw->file);
+
+ if (swapFlag) {
+ ConvertShort(&raw->imagic, 6);
+ }
+
+ raw->tmp = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpR = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpG = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpB = (unsigned char *)malloc(raw->sizeX*256);
+ if (raw->sizeZ==4) {
+ raw->tmpA = (unsigned char *)malloc(raw->sizeX*256);
+ }
+ if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL ||
+ raw->tmpB == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+
+ if ((raw->type & 0xFF00) == 0x0100) {
+ x = raw->sizeY * raw->sizeZ * sizeof(GLuint);
+ raw->rowStart = (GLuint *)malloc(x);
+ raw->rowSize = (GLint *)malloc(x);
+ if (raw->rowStart == NULL || raw->rowSize == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ raw->rleEnd = 512 + (2 * x);
+ fseek(raw->file, 512, SEEK_SET);
+ fread(raw->rowStart, 1, x, raw->file);
+ fread(raw->rowSize, 1, x, raw->file);
+ if (swapFlag) {
+ ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
+ ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
+ }
+ }
+ return raw;
+}
+
+static void RawImageClose(rawImageRec *raw)
+{
+ fclose(raw->file);
+ free(raw->tmp);
+ free(raw->tmpR);
+ free(raw->tmpG);
+ free(raw->tmpB);
+ if (raw->rowStart)
+ free(raw->rowStart);
+ if (raw->rowSize)
+ free(raw->rowSize);
+ if (raw->sizeZ>3) {
+ free(raw->tmpA);
+ }
+ free(raw);
+}
+
+static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
+{
+ unsigned char *iPtr, *oPtr, pixel;
+ int count, done = 0;
+
+ if ((raw->type & 0xFF00) == 0x0100) {
+ fseek(raw->file, (long) raw->rowStart[y+z*raw->sizeY], SEEK_SET);
+ fread(raw->tmp, 1, (unsigned int)raw->rowSize[y+z*raw->sizeY],
+ raw->file);
+
+ iPtr = raw->tmp;
+ oPtr = buf;
+ while (!done) {
+ pixel = *iPtr++;
+ count = (int)(pixel & 0x7F);
+ if (!count) {
+ done = 1;
+ return;
+ }
+ if (pixel & 0x80) {
+ while (count--) {
+ *oPtr++ = *iPtr++;
+ }
+ } else {
+ pixel = *iPtr++;
+ while (count--) {
+ *oPtr++ = pixel;
+ }
+ }
+ }
+ } else {
+ fseek(raw->file, 512+(y*raw->sizeX)+(z*raw->sizeX*raw->sizeY),
+ SEEK_SET);
+ fread(buf, 1, raw->sizeX, raw->file);
+ }
+}
+
+
+static void RawImageGetData(rawImageRec *raw, TK_RGBImageRec *final)
+{
+ unsigned char *ptr;
+ int i, j;
+
+ final->data = (unsigned char *)malloc((raw->sizeX+1)*(raw->sizeY+1)*4);
+ if (final->data == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ }
+
+ ptr = final->data;
+ for (i = 0; i < (int)(raw->sizeY); i++) {
+ RawImageGetRow(raw, raw->tmpR, i, 0);
+ RawImageGetRow(raw, raw->tmpG, i, 1);
+ RawImageGetRow(raw, raw->tmpB, i, 2);
+ if (raw->sizeZ>3) {
+ RawImageGetRow(raw, raw->tmpA, i, 3);
+ }
+ for (j = 0; j < (int)(raw->sizeX); j++) {
+ *ptr++ = *(raw->tmpR + j);
+ *ptr++ = *(raw->tmpG + j);
+ *ptr++ = *(raw->tmpB + j);
+ if (raw->sizeZ>3) {
+ *ptr++ = *(raw->tmpA + j);
+ }
+ }
+ }
+}
+
+
+static TK_RGBImageRec *tkRGBImageLoad(const char *fileName)
+{
+ rawImageRec *raw;
+ TK_RGBImageRec *final;
+
+ raw = RawImageOpen(fileName);
+ if (!raw) {
+ fprintf(stderr, "File not found\n");
+ return NULL;
+ }
+ final = (TK_RGBImageRec *)malloc(sizeof(TK_RGBImageRec));
+ if (final == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ final->sizeX = raw->sizeX;
+ final->sizeY = raw->sizeY;
+ final->components = raw->sizeZ;
+ RawImageGetData(raw, final);
+ RawImageClose(raw);
+ return final;
+}
+
+
+static void FreeImage( TK_RGBImageRec *image )
+{
+ free(image->data);
+ free(image);
+}
+
+
+/*
+ * Load an SGI .rgb file and generate a set of 2-D mipmaps from it.
+ * Input: imageFile - name of .rgb to read
+ * intFormat - internal texture format to use, or number of components
+ * Return: GL_TRUE if success, GL_FALSE if error.
+ */
+GLboolean LoadRGBMipmaps( const char *imageFile, GLint intFormat )
+{
+ GLint w, h;
+ return LoadRGBMipmaps2( imageFile, GL_TEXTURE_2D, intFormat, &w, &h );
+}
+
+
+
+GLboolean LoadRGBMipmaps2( const char *imageFile, GLenum target,
+ GLint intFormat, GLint *width, GLint *height )
+{
+ GLint error;
+ GLenum format;
+ TK_RGBImageRec *image;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return GL_FALSE;
+ }
+
+ if (image->components==3) {
+ format = GL_RGB;
+ }
+ else if (image->components==4) {
+ format = GL_RGBA;
+ }
+ else {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadRGBMipmaps %d-component images not implemented\n",
+ image->components );
+ return GL_FALSE;
+ }
+
+ error = gluBuild2DMipmaps( target,
+ intFormat,
+ image->sizeX, image->sizeY,
+ format,
+ GL_UNSIGNED_BYTE,
+ image->data );
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ FreeImage(image);
+
+ return error ? GL_FALSE : GL_TRUE;
+}
+
+
+
+/*
+ * Load an SGI .rgb file and return a pointer to the image data.
+ * Input: imageFile - name of .rgb to read
+ * Output: width - width of image
+ * height - height of image
+ * format - format of image (GL_RGB or GL_RGBA)
+ * Return: pointer to image data or NULL if error
+ */
+GLubyte *LoadRGBImage( const char *imageFile, GLint *width, GLint *height,
+ GLenum *format )
+{
+ TK_RGBImageRec *image;
+ GLint bytes;
+ GLubyte *buffer;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return NULL;
+ }
+
+ if (image->components==3) {
+ *format = GL_RGB;
+ }
+ else if (image->components==4) {
+ *format = GL_RGBA;
+ }
+ else {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadRGBImage %d-component images not implemented\n",
+ image->components );
+ return NULL;
+ }
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ bytes = image->sizeX * image->sizeY * image->components;
+ buffer = (GLubyte *) malloc(bytes);
+ if (!buffer)
+ return NULL;
+
+ memcpy( (void *) buffer, (void *) image->data, bytes );
+
+ FreeImage(image);
+
+ return buffer;
+}
+
+#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
+
+
+static void ConvertRGBtoYUV(GLint w, GLint h, GLint texel_bytes,
+ const GLubyte *src,
+ GLushort *dest)
+{
+ GLint i, j;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ const GLfloat r = (src[0]) / 255.0;
+ const GLfloat g = (src[1]) / 255.0;
+ const GLfloat b = (src[2]) / 255.0;
+ GLfloat y, cr, cb;
+ GLint iy, icr, icb;
+
+ y = r * 65.481 + g * 128.553 + b * 24.966 + 16;
+ cb = r * -37.797 + g * -74.203 + b * 112.0 + 128;
+ cr = r * 112.0 + g * -93.786 + b * -18.214 + 128;
+ /*printf("%f %f %f -> %f %f %f\n", r, g, b, y, cb, cr);*/
+ iy = (GLint) CLAMP(y, 0, 254);
+ icb = (GLint) CLAMP(cb, 0, 254);
+ icr = (GLint) CLAMP(cr, 0, 254);
+
+ if (j & 1) {
+ /* odd */
+ *dest = (iy << 8) | icr;
+ }
+ else {
+ /* even */
+ *dest = (iy << 8) | icb;
+ }
+ dest++;
+ src += texel_bytes;
+ }
+ }
+}
+
+
+/*
+ * Load an SGI .rgb file and return a pointer to the image data, converted
+ * to 422 yuv.
+ *
+ * Input: imageFile - name of .rgb to read
+ * Output: width - width of image
+ * height - height of image
+ * Return: pointer to image data or NULL if error
+ */
+GLushort *LoadYUVImage( const char *imageFile, GLint *width, GLint *height )
+{
+ TK_RGBImageRec *image;
+ GLushort *buffer;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return NULL;
+ }
+
+ if (image->components != 3 && image->components !=4 ) {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadYUVImage %d-component images not implemented\n",
+ image->components );
+ return NULL;
+ }
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ buffer = (GLushort *) malloc( image->sizeX * image->sizeY * 2 );
+
+ if (buffer)
+ ConvertRGBtoYUV( image->sizeX,
+ image->sizeY,
+ image->components,
+ image->data,
+ buffer );
+
+
+ FreeImage(image);
+ return buffer;
+}
+
diff --git a/tests/mesa/util/readtex.h b/tests/mesa/util/readtex.h
new file mode 100644
index 00000000..6c9a3828
--- /dev/null
+++ b/tests/mesa/util/readtex.h
@@ -0,0 +1,26 @@
+/* readtex.h */
+
+#ifndef READTEX_H
+#define READTEX_H
+
+
+#include <GL/gl.h>
+
+
+extern GLboolean
+LoadRGBMipmaps( const char *imageFile, GLint intFormat );
+
+
+extern GLboolean
+LoadRGBMipmaps2( const char *imageFile, GLenum target,
+ GLint intFormat, GLint *width, GLint *height );
+
+
+extern GLubyte *
+LoadRGBImage( const char *imageFile,
+ GLint *width, GLint *height, GLenum *format );
+
+extern GLushort *
+LoadYUVImage( const char *imageFile, GLint *width, GLint *height );
+
+#endif
diff --git a/tests/mesa/util/showbuffer.c b/tests/mesa/util/showbuffer.c
new file mode 100644
index 00000000..17f84dc6
--- /dev/null
+++ b/tests/mesa/util/showbuffer.c
@@ -0,0 +1,192 @@
+/* showbuffer.c */
+
+
+/*
+ * Copy the depth buffer to the color buffer as a grayscale image.
+ * Useful for inspecting the depth buffer values.
+ *
+ * This program is in the public domain.
+ *
+ * Brian Paul November 4, 1998
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <GL/gl.h>
+#include "showbuffer.h"
+
+
+
+/*
+ * Copy the depth buffer values into the current color buffer as a
+ * grayscale image.
+ * Input: winWidth, winHeight - size of the window
+ * zBlack - the Z value which should map to black (usually 1)
+ * zWhite - the Z value which should map to white (usually 0)
+ */
+void
+ShowDepthBuffer( GLsizei winWidth, GLsizei winHeight,
+ GLfloat zBlack, GLfloat zWhite )
+{
+ GLfloat *depthValues;
+
+ assert(zBlack >= 0.0);
+ assert(zBlack <= 1.0);
+ assert(zWhite >= 0.0);
+ assert(zWhite <= 1.0);
+ assert(zBlack != zWhite);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ /* Read depth values */
+ depthValues = (GLfloat *) malloc(winWidth * winHeight * sizeof(GLfloat));
+ assert(depthValues);
+ glReadPixels(0, 0, winWidth, winHeight, GL_DEPTH_COMPONENT,
+ GL_FLOAT, depthValues);
+
+ /* Map Z values from [zBlack, zWhite] to gray levels in [0, 1] */
+ /* Not using glPixelTransfer() because it's broke on some systems! */
+ if (zBlack != 0.0 || zWhite != 1.0) {
+ GLfloat scale = 1.0 / (zWhite - zBlack);
+ GLfloat bias = -zBlack * scale;
+ int n = winWidth * winHeight;
+ int i;
+ for (i = 0; i < n; i++)
+ depthValues[i] = depthValues[i] * scale + bias;
+ }
+
+ /* save GL state */
+ glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT |
+ GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);
+
+ /* setup raster pos for glDrawPixels */
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho(0.0, (GLdouble) winWidth, 0.0, (GLdouble) winHeight, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glRasterPos2f(0, 0);
+
+ glDrawPixels(winWidth, winHeight, GL_LUMINANCE, GL_FLOAT, depthValues);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ free(depthValues);
+
+ glPopAttrib();
+}
+
+
+
+
+/*
+ * Copy the alpha channel values into the current color buffer as a
+ * grayscale image.
+ * Input: winWidth, winHeight - size of the window
+ */
+void
+ShowAlphaBuffer( GLsizei winWidth, GLsizei winHeight )
+{
+ GLubyte *alphaValues;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ /* Read alpha values */
+ alphaValues = (GLubyte *) malloc(winWidth * winHeight * sizeof(GLubyte));
+ assert(alphaValues);
+ glReadPixels(0, 0, winWidth, winHeight, GL_ALPHA, GL_UNSIGNED_BYTE, alphaValues);
+
+ /* save GL state */
+ glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL |
+ GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);
+
+ /* setup raster pos for glDrawPixels */
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho(0.0, (GLdouble) winWidth, 0.0, (GLdouble) winHeight, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glRasterPos2f(0, 0);
+
+ glDrawPixels(winWidth, winHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, alphaValues);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ free(alphaValues);
+
+ glPopAttrib();
+}
+
+
+
+/*
+ * Copy the stencil buffer values into the current color buffer as a
+ * grayscale image.
+ * Input: winWidth, winHeight - size of the window
+ * scale, bias - scale and bias to apply to stencil values for display
+ */
+void
+ShowStencilBuffer( GLsizei winWidth, GLsizei winHeight,
+ GLfloat scale, GLfloat bias )
+{
+ GLubyte *stencilValues;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ /* Read stencil values */
+ stencilValues = (GLubyte *) malloc(winWidth * winHeight * sizeof(GLubyte));
+ assert(stencilValues);
+ glReadPixels(0, 0, winWidth, winHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilValues);
+
+ /* save GL state */
+ glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT |
+ GL_PIXEL_MODE_BIT | GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);
+
+ /* setup raster pos for glDrawPixels */
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho(0.0, (GLdouble) winWidth, 0.0, (GLdouble) winHeight, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glRasterPos2f(0, 0);
+
+ glPixelTransferf(GL_RED_SCALE, scale);
+ glPixelTransferf(GL_RED_BIAS, bias);
+ glPixelTransferf(GL_GREEN_SCALE, scale);
+ glPixelTransferf(GL_GREEN_BIAS, bias);
+ glPixelTransferf(GL_BLUE_SCALE, scale);
+ glPixelTransferf(GL_BLUE_BIAS, bias);
+
+ glDrawPixels(winWidth, winHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, stencilValues);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ free(stencilValues);
+
+ glPopAttrib();
+}
diff --git a/tests/mesa/util/showbuffer.h b/tests/mesa/util/showbuffer.h
new file mode 100644
index 00000000..63533d8e
--- /dev/null
+++ b/tests/mesa/util/showbuffer.h
@@ -0,0 +1,36 @@
+/* showbuffer. h*/
+
+/*
+ * Copy the depth buffer to the color buffer as a grayscale image.
+ * Useful for inspecting the depth buffer values.
+ *
+ * This program is in the public domain.
+ *
+ * Brian Paul November 4, 1998
+ */
+
+
+#ifndef SHOWBUFFER_H
+#define SHOWBUFFER_H
+
+
+#include <GL/gl.h>
+
+
+
+extern void
+ShowDepthBuffer( GLsizei winWidth, GLsizei winHeight,
+ GLfloat zBlack, GLfloat zWhite );
+
+
+extern void
+ShowAlphaBuffer( GLsizei winWidth, GLsizei winHeight );
+
+
+extern void
+ShowStencilBuffer( GLsizei winWidth, GLsizei winHeight,
+ GLfloat scale, GLfloat bias );
+
+
+
+#endif
diff --git a/tests/mesa/util/trackball.c b/tests/mesa/util/trackball.c
new file mode 100644
index 00000000..a6c4c60d
--- /dev/null
+++ b/tests/mesa/util/trackball.c
@@ -0,0 +1,338 @@
+#include <stdio.h>
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States. Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/*
+ * Trackball code:
+ *
+ * Implementation of a virtual trackball.
+ * Implemented by Gavin Bell, lots of ideas from Thant Tessman and
+ * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
+ *
+ * Vector manip code:
+ *
+ * Original code from:
+ * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
+ *
+ * Much mucking with by:
+ * Gavin Bell
+ */
+#if defined(_WIN32)
+#pragma warning (disable:4244) /* disable bogus conversion warnings */
+#endif
+#include <math.h>
+#include "trackball.h"
+
+/*
+ * This size should really be based on the distance from the center of
+ * rotation to the point on the object underneath the mouse. That
+ * point would then track the mouse as closely as possible. This is a
+ * simple example, though, so that is left as an Exercise for the
+ * Programmer.
+ */
+#define TRACKBALLSIZE (0.8f)
+
+/*
+ * Local function prototypes (not defined in trackball.h)
+ */
+static float tb_project_to_sphere(float, float, float);
+static void normalize_quat(float [4]);
+
+static void
+vzero(float v[3])
+{
+ v[0] = 0.0;
+ v[1] = 0.0;
+ v[2] = 0.0;
+}
+
+static void
+vset(float v[3], float x, float y, float z)
+{
+ v[0] = x;
+ v[1] = y;
+ v[2] = z;
+}
+
+static void
+vsub(const float src1[3], const float src2[3], float dst[3])
+{
+ dst[0] = src1[0] - src2[0];
+ dst[1] = src1[1] - src2[1];
+ dst[2] = src1[2] - src2[2];
+}
+
+static void
+vcopy(const float v1[3], float v2[3])
+{
+ register int i;
+ for (i = 0 ; i < 3 ; i++)
+ v2[i] = v1[i];
+}
+
+static void
+vcross(const float v1[3], const float v2[3], float cross[3])
+{
+ float temp[3];
+
+ temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
+ temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
+ temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
+ vcopy(temp, cross);
+}
+
+static float
+vlength(const float v[3])
+{
+ return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+}
+
+static void
+vscale(float v[3], float div)
+{
+ v[0] *= div;
+ v[1] *= div;
+ v[2] *= div;
+}
+
+static void
+vnormal(float v[3])
+{
+ vscale(v,1.0/vlength(v));
+}
+
+static float
+vdot(const float v1[3], const float v2[3])
+{
+ return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+static void
+vadd(const float src1[3], const float src2[3], float dst[3])
+{
+ dst[0] = src1[0] + src2[0];
+ dst[1] = src1[1] + src2[1];
+ dst[2] = src1[2] + src2[2];
+}
+
+/*
+ * Ok, simulate a track-ball. Project the points onto the virtual
+ * trackball, then figure out the axis of rotation, which is the cross
+ * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
+ * Note: This is a deformed trackball-- is a trackball in the center,
+ * but is deformed into a hyperbolic sheet of rotation away from the
+ * center. This particular function was chosen after trying out
+ * several variations.
+ *
+ * It is assumed that the arguments to this routine are in the range
+ * (-1.0 ... 1.0)
+ */
+void
+trackball(float q[4], float p1x, float p1y, float p2x, float p2y)
+{
+ float a[3]; /* Axis of rotation */
+ float phi; /* how much to rotate about axis */
+ float p1[3], p2[3], d[3];
+ float t;
+
+ if (p1x == p2x && p1y == p2y) {
+ /* Zero rotation */
+ vzero(q);
+ q[3] = 1.0;
+ return;
+ }
+
+ /*
+ * First, figure out z-coordinates for projection of P1 and P2 to
+ * deformed sphere
+ */
+ vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
+ vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
+
+ /*
+ * Now, we want the cross product of P1 and P2
+ */
+ vcross(p2,p1,a);
+
+ /*
+ * Figure out how much to rotate around that axis.
+ */
+ vsub(p1,p2,d);
+ t = vlength(d) / (2.0*TRACKBALLSIZE);
+
+ /*
+ * Avoid problems with out-of-control values...
+ */
+ if (t > 1.0) t = 1.0;
+ if (t < -1.0) t = -1.0;
+ phi = 2.0 * asin(t);
+
+ axis_to_quat(a,phi,q);
+}
+
+/*
+ * Given an axis and angle, compute quaternion.
+ */
+void
+axis_to_quat(const float a[3], float phi, float q[4])
+{
+ vcopy(a,q);
+ vnormal(q);
+ vscale(q, sin(phi/2.0));
+ q[3] = cos(phi/2.0);
+}
+
+/*
+ * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
+ * if we are away from the center of the sphere.
+ */
+static float
+tb_project_to_sphere(float r, float x, float y)
+{
+ float d, t, z;
+
+ d = sqrt(x*x + y*y);
+ if (d < r * 0.70710678118654752440) { /* Inside sphere */
+ z = sqrt(r*r - d*d);
+ } else { /* On hyperbola */
+ t = r / 1.41421356237309504880;
+ z = t*t / d;
+ }
+ return z;
+}
+
+/*
+ * Given two rotations, e1 and e2, expressed as quaternion rotations,
+ * figure out the equivalent single rotation and stuff it into dest.
+ *
+ * This routine also normalizes the result every RENORMCOUNT times it is
+ * called, to keep error from creeping in.
+ *
+ * NOTE: This routine is written so that q1 or q2 may be the same
+ * as dest (or each other).
+ */
+
+#define RENORMCOUNT 97
+
+void
+add_quats(const float q1[4], const float q2[4], float dest[4])
+{
+ static int count=0;
+ float t1[4], t2[4], t3[4];
+ float tf[4];
+
+#if 0
+printf("q1 = %f %f %f %f\n", q1[0], q1[1], q1[2], q1[3]);
+printf("q2 = %f %f %f %f\n", q2[0], q2[1], q2[2], q2[3]);
+#endif
+
+ vcopy(q1,t1);
+ vscale(t1,q2[3]);
+
+ vcopy(q2,t2);
+ vscale(t2,q1[3]);
+
+ vcross(q2,q1,t3);
+ vadd(t1,t2,tf);
+ vadd(t3,tf,tf);
+ tf[3] = q1[3] * q2[3] - vdot(q1,q2);
+
+#if 0
+printf("tf = %f %f %f %f\n", tf[0], tf[1], tf[2], tf[3]);
+#endif
+
+ dest[0] = tf[0];
+ dest[1] = tf[1];
+ dest[2] = tf[2];
+ dest[3] = tf[3];
+
+ if (++count > RENORMCOUNT) {
+ count = 0;
+ normalize_quat(dest);
+ }
+}
+
+/*
+ * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
+ * If they don't add up to 1.0, dividing by their magnitued will
+ * renormalize them.
+ *
+ * Note: See the following for more information on quaternions:
+ *
+ * - Shoemake, K., Animating rotation with quaternion curves, Computer
+ * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
+ * - Pletinckx, D., Quaternion calculus as a basic tool in computer
+ * graphics, The Visual Computer 5, 2-13, 1989.
+ */
+static void
+normalize_quat(float q[4])
+{
+ int i;
+ float mag;
+
+ mag = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
+ for (i = 0; i < 4; i++)
+ q[i] /= mag;
+}
+
+/*
+ * Build a rotation matrix, given a quaternion rotation.
+ *
+ */
+void
+build_rotmatrix(float m[4][4], const float q[4])
+{
+ m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
+ m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
+ m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
+ m[0][3] = 0.0;
+
+ m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
+ m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
+ m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
+ m[1][3] = 0.0;
+
+ m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
+ m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
+ m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
+ m[2][3] = 0.0;
+
+ m[3][0] = 0.0;
+ m[3][1] = 0.0;
+ m[3][2] = 0.0;
+ m[3][3] = 1.0;
+}
+
diff --git a/tests/mesa/util/trackball.h b/tests/mesa/util/trackball.h
new file mode 100644
index 00000000..9b278640
--- /dev/null
+++ b/tests/mesa/util/trackball.h
@@ -0,0 +1,84 @@
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States. Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/*
+ * trackball.h
+ * A virtual trackball implementation
+ * Written by Gavin Bell for Silicon Graphics, November 1988.
+ */
+
+#ifndef TRACKBALL_H
+#define TRACKBALL_H
+
+
+/*
+ * Pass the x and y coordinates of the last and current positions of
+ * the mouse, scaled so they are from (-1.0 ... 1.0).
+ *
+ * The resulting rotation is returned as a quaternion rotation in the
+ * first paramater.
+ */
+void
+trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
+
+/*
+ * Given two quaternions, add them together to get a third quaternion.
+ * Adding quaternions to get a compound rotation is analagous to adding
+ * translations to get a compound translation. When incrementally
+ * adding rotations, the first argument here should be the new
+ * rotation, the second and third the total rotation (which will be
+ * over-written with the resulting new total rotation).
+ */
+void
+add_quats(const float q1[4], const float q2[4], float dest[4]);
+
+/*
+ * A useful function, builds a rotation matrix in Matrix based on
+ * given quaternion.
+ */
+void
+build_rotmatrix(float m[4][4], const float q[4]);
+
+/*
+ * This function computes a quaternion based on an axis (defined by
+ * the given vector) and an angle about which to rotate. The angle is
+ * expressed in radians. The result is put into the third argument.
+ */
+void
+axis_to_quat(const float a[3], float phi, float q[4]);
+
+
+#endif /* TRACKBALL_H */
diff --git a/tests/mesa/util/winpos.c b/tests/mesa/util/winpos.c
new file mode 100644
index 00000000..820ea29e
--- /dev/null
+++ b/tests/mesa/util/winpos.c
@@ -0,0 +1,43 @@
+/* winpos.c */
+
+
+/*
+ * Set the current raster position to a specific window
+ * coordinate. Also see the GL_MESA_window_pos extension.
+ *
+ * Written by Brian Paul and in the public domain.
+ */
+
+#include <GL/gl.h>
+
+void WindowPos( GLfloat x, GLfloat y, GLfloat z )
+{
+ GLfloat fx, fy;
+
+ /* Push current matrix mode and viewport attributes */
+ glPushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT );
+
+ /* Setup projection parameters */
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDepthRange( z, z );
+ glViewport( (int) x - 1, (int) y - 1, 2, 2 );
+
+ /* set the raster (window) position */
+ fx = x - (int) x;
+ fy = y - (int) y;
+ glRasterPos3f( fx, fy, 0.0 );
+
+ /* restore matrices, viewport and matrix mode */
+ glPopMatrix();
+ glMatrixMode( GL_PROJECTION );
+ glPopMatrix();
+
+ glPopAttrib();
+}
+
diff --git a/tests/r300.tests b/tests/r300.tests
new file mode 100644
index 00000000..1f2547c7
--- /dev/null
+++ b/tests/r300.tests
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+#
+# Testing the r300 DRI driver
+#
+
+execfile(__dir__ + '/all.tests')
+
+# Potentially serious problem, but workaround for now
+GleanTest.globalParams += [ '--visuals', 'id != 0x4b' ]
+Test.ignoreErrors.append('3D driver claims to not support')
+
+# Debug info
+Test.ignoreErrors.append('Try R300_SPAN_DISABLE_LOCKING env var if this hangs.')
+
+
+# glean/blendFunc
+# R300 blending hardware appears to be bad
+env = tests['glean']['blendFunc'].env
+env['GLEAN_BLEND_RGB_TOLERANCE'] = 1.9
+env['GLEAN_BLEND_ALPHA_TOLERANCE'] = 2.0
+
+# glean/exactRGBA
+# insane OpenGL spec requirements
+env = tests['glean']['exactRGBA'].env
+env['GLEAN_EXACTRGBA_ROUNDING'] = 1
+
diff --git a/tests/sanity.tests b/tests/sanity.tests
new file mode 100644
index 00000000..d591c71f
--- /dev/null
+++ b/tests/sanity.tests
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+#
+# Minimal tests to check whether the installation is working
+#
+
+glean = Group()
+glean['basic'] = GleanTest('basic')
+
+tests = Group()
+tests['glean'] = glean
diff --git a/tests/shaders/CMakeLists.txt b/tests/shaders/CMakeLists.txt
new file mode 100644
index 00000000..1aa68528
--- /dev/null
+++ b/tests/shaders/CMakeLists.txt
@@ -0,0 +1,24 @@
+
+include_directories(
+ ${OPENGL_INCLUDE_PATH}
+ ${GLUT_INCLUDE_DIR}
+ ${piglit_SOURCE_DIR}/tests/mesa/util
+)
+
+link_directories (
+ ${piglit_SOURCE_DIR}/tests/mesa/util
+)
+
+link_libraries (
+ ${OPENGL_gl_LIBRARY}
+ ${OPENGL_glu_LIBRARY}
+ ${GLUT_glut_LIBRARY}
+ ${TIFF_LIBRARY}
+ mesautil
+)
+
+add_executable (trinity-fp1 trinity-fp1.c)
+add_executable (fp-lit-mask fp-lit-mask.c)
+add_executable (fp-fragment-position fp-fragment-position.c)
+add_executable (fp-kil fp-kil.c)
+add_executable (fp-incomplete-tex fp-incomplete-tex.c)
diff --git a/tests/shaders/fp-fragment-position.c b/tests/shaders/fp-fragment-position.c
new file mode 100644
index 00000000..961c337c
--- /dev/null
+++ b/tests/shaders/fp-fragment-position.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) The Piglit project 2007
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Test fragment.position.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static void CheckFail(const char* cond);
+
+#define check(cond) do { if (!(cond)) CheckFail(#cond); } while(0)
+
+
+#define NUM_PROGRAMS 4
+
+static GLuint FragProg[NUM_PROGRAMS];
+
+static const char* const ProgramText[NUM_PROGRAMS] = {
+ "!!ARBfp1.0\n"
+ "PARAM factor = { 0.01, 0.01, 1.0, 0.2 };\n"
+ "MUL result.color, fragment.position, factor;\n"
+ "END",
+
+ "!!ARBfp1.0\n"
+ "TEMP r0;\n"
+ "ALIAS scaled = r0;\n"
+ "MUL r0.xy, fragment.position, 0.01;\n"
+ "TEX result.color, scaled, texture[1], 2D;\n"
+ "END",
+
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.position, texture[0], RECT;\n"
+ "END",
+
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.position, texture[1], 2D;\n"
+ "MOV result.color.w, 0.5;\n"
+ "END",
+};
+
+static int Automatic = 0;
+
+static int Width = 200, Height = 200;
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC pglProgramLocalParameter4fvARB;
+static PFNGLPROGRAMLOCALPARAMETER4DARBPROC pglProgramLocalParameter4dARB;
+static PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC pglGetProgramLocalParameterdvARB;
+static PFNGLGENPROGRAMSARBPROC pglGenProgramsARB;
+static PFNGLPROGRAMSTRINGARBPROC pglProgramStringARB;
+static PFNGLBINDPROGRAMARBPROC pglBindProgramARB;
+static PFNGLISPROGRAMARBPROC pglIsProgramARB;
+static PFNGLDELETEPROGRAMSARBPROC pglDeleteProgramsARB;
+
+
+static void DoFrame(void)
+{
+ int mask;
+
+ printf("rgba: %i %i %i %i\n",
+ glutGet(GLUT_WINDOW_RED_SIZE),
+ glutGet(GLUT_WINDOW_GREEN_SIZE),
+ glutGet(GLUT_WINDOW_BLUE_SIZE),
+ glutGet(GLUT_WINDOW_ALPHA_SIZE));
+
+ glClearColor(0.3, 0.3, 0.3, 0.3);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[0]);
+
+ glBegin(GL_QUADS);
+ glVertex3f(0, 0, 0);
+ glVertex3f(1, 0, 1);
+ glVertex3f(1, 1, 2);
+ glVertex3f(0, 1, 1);
+ glEnd();
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[1]);
+
+ glBegin(GL_QUADS);
+ glVertex2f(0, 1);
+ glVertex2f(1, 1);
+ glVertex2f(1, 2);
+ glVertex2f(0, 2);
+ glEnd();
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[2]);
+
+ glBegin(GL_QUADS);
+ glVertex2f(1, 0);
+ glVertex2f(2, 0);
+ glVertex2f(2, 1);
+ glVertex2f(1, 1);
+ glEnd();
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[3]);
+
+ glBegin(GL_QUADS);
+ glVertex2f(1, 1);
+ glVertex2f(2, 1);
+ glVertex2f(2, 2);
+ glVertex2f(1, 2);
+ glEnd();
+
+ glutSwapBuffers();
+}
+
+static const struct {
+ const char* name;
+ float x, y;
+ float expected[4];
+} Probes[] = {
+ // Program 0
+ {
+ "basic #1",
+ 0.2, 0.2,
+ { 0.2, 0.2, (0.4+2)/8, 0.2 }
+ },
+ {
+ "basic #2",
+ 0.8, 0.2,
+ { 0.8, 0.2, (1.0+2)/8, 0.2 }
+ },
+ {
+ "basic #3",
+ 0.8, 0.8,
+ { 0.8, 0.8, (1.6+2)/8, 0.2 }
+ },
+ {
+ "basic #4",
+ 0.2, 0.8,
+ { 0.2, 0.8, (1.0+2)/8, 0.2 }
+ },
+
+ // Program 1
+ {
+ "tex2d scaled #1",
+ 0.2, 1.2,
+ { 0.8, 0.2, 0.2, 0.2 }
+ },
+ {
+ "tex2d scaled #2",
+ 0.8, 1.2,
+ { 0.2, 0.2, 0.8, 0.5 }
+ },
+ {
+ "tex2d scaled #3",
+ 0.8, 1.8,
+ { 0.2, 0.8, 0.8, 0.8 }
+ },
+ {
+ "tex2d scaled #4",
+ 0.2, 1.8,
+ { 0.8, 0.8, 0.2, 0.5 }
+ },
+
+ // Program 2
+ {
+ "texrect #1",
+ 1.2, 0.2,
+ { 0.53, 0.47, 0.08, 0.27 }
+ },
+ {
+ "texrect #2",
+ 1.8, 0.2,
+ { 0.29, 0.70, 0.08, 0.40 }
+ },
+ {
+ "texrect #1",
+ 1.8, 0.8,
+ { 0.29, 0.70, 0.31, 0.51 }
+ },
+ {
+ "texrect #1",
+ 1.2, 0.8,
+ { 0.53, 0.47, 0.31, 0.39 }
+ },
+
+ // Program 3
+ {
+ "tex2d unscaled #1",
+ 1.2, 1.2,
+ { 1.0, 0.5, 0.5, 0.5 }
+ },
+ {
+ "tex2d unscaled #2",
+ 1.8, 1.2,
+ { 1.0, 0.5, 0.5, 0.5 }
+ },
+ {
+ "tex2d unscaled #3",
+ 1.8, 1.8,
+ { 1.0, 0.5, 0.5, 0.5 }
+ },
+ {
+ "tex2d unscaled #4",
+ 1.2, 1.8,
+ { 1.0, 0.5, 0.5, 0.5 }
+ },
+
+ // Sentinel!
+ {
+ 0,
+ 0, 0,
+ { 0, 0, 0, 0 }
+ }
+};
+
+static int DoTest( void )
+{
+ int idx;
+ GLfloat dmax;
+
+ glReadBuffer( GL_FRONT );
+ dmax = 0;
+
+ idx = 0;
+ while(Probes[idx].name) {
+ GLfloat probe[4];
+ GLfloat delta[4];
+ int i;
+
+ glReadPixels((int)(Probes[idx].x*Width/2),
+ (int)(Probes[idx].y*Height/2),
+ 1, 1,
+ GL_RGBA, GL_FLOAT, probe);
+
+ printf("%20s (%3.1f,%3.1f): %f,%f,%f,%f",
+ Probes[idx].name,
+ Probes[idx].x, Probes[idx].y,
+ probe[0], probe[1], probe[2], probe[3]);
+
+ for(i = 0; i < 4; ++i) {
+ delta[i] = probe[i] - Probes[idx].expected[i];
+
+ if (delta[i] > dmax) dmax = delta[i];
+ else if (-delta[i] > dmax) dmax = -delta[i];
+ }
+
+ printf(" Delta: %f,%f,%f,%f\n", delta[0], delta[1], delta[2], delta[3]);
+
+ idx++;
+ }
+
+ printf("Max delta: %f\n", dmax);
+
+ if (dmax >= 0.02)
+ return 0;
+ else
+ return 1;
+}
+
+
+static void Redisplay(void)
+{
+ int succ;
+
+ DoFrame();
+ succ = DoTest();
+
+ if (Automatic) {
+ printf("\nPIGLIT: { 'result': '%s' }\n", succ ? "pass" : "fail");
+ exit(0);
+ }
+}
+
+
+static void Reshape(int width, int height)
+{
+ Width = width;
+ Height = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, 2.0, 0.0, 2.0, -2.0, 6.0);
+ glScalef(1.0, 1.0, -1.0); // flip z-axis
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+/* A helper for finding errors in program strings */
+static int FindLine(const char *program, int position)
+{
+ int i, line = 1;
+ for (i = 0; i < position; i++) {
+ if (program[i] == '\n')
+ line++;
+ }
+ return line;
+}
+
+
+static void Init(void)
+{
+ int i, x, y;
+ GLubyte rectangle[200][200][4];
+ GLubyte tex[256*256][4];
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ fprintf(stderr, "Sorry, this demo requires GL_ARB_fragment_program\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+
+ /*
+ * Get extension function pointers.
+ */
+ pglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
+ assert(pglProgramLocalParameter4fvARB);
+
+ pglProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
+ assert(pglProgramLocalParameter4dARB);
+
+ pglGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
+ assert(pglGetProgramLocalParameterdvARB);
+
+ pglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
+ assert(pglGenProgramsARB);
+
+ pglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
+ assert(pglProgramStringARB);
+
+ pglBindProgramARB = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
+ assert(pglBindProgramARB);
+
+ pglIsProgramARB = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
+ assert(pglIsProgramARB);
+
+ pglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
+ assert(pglDeleteProgramsARB);
+
+ /*
+ * Fragment programs
+ */
+ pglGenProgramsARB(NUM_PROGRAMS, FragProg);
+
+ for(i = 0; i < NUM_PROGRAMS; ++i) {
+ GLint errorPos;
+
+ check(FragProg[i]);
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[i]);
+ pglProgramStringARB(
+ GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(ProgramText[i]),
+ (const GLubyte *)ProgramText[i]);
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ if (glGetError() != GL_NO_ERROR || errorPos != -1) {
+ int l = FindLine(ProgramText[i], errorPos);
+ int a;
+
+ fprintf(stderr, "%i: Fragment Program Error (pos=%d line=%d): %s\n",
+ i, errorPos, l,
+ (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+
+ for (a=-10; a<10; a++)
+ {
+ if (errorPos+a < 0)
+ continue;
+ if (errorPos+a >= strlen(ProgramText[i]))
+ break;
+ fprintf(stderr, "%c", ProgramText[i][errorPos+a]);
+ }
+ fprintf(stderr, "\n");
+
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ if (!pglIsProgramARB(FragProg[i])) {
+ fprintf(stderr, "pglIsProgramARB failed\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ }
+
+ /*
+ * Textures
+ */
+ for(y = 0; y < 200; ++y) {
+ for(x = 0; x < 200; ++x) {
+ rectangle[y][x][0] = 255-x;
+ rectangle[y][x][1] = x;
+ rectangle[y][x][2] = y;
+ rectangle[y][x][3] = (x+y)/2;
+ }
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 1);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 200, 200, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, rectangle);
+
+ for(y = 0; y < 256; ++y) {
+ for(x = 0; x < 256; ++x) {
+ tex[256*y+x][0] = 255-x;
+ tex[256*y+x][1] = y;
+ tex[256*y+x][2] = x;
+ tex[256*y+x][3] = (x+y)/2;
+ }
+ }
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, 2);
+ gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, 256, 256,
+ GL_RGBA, GL_UNSIGNED_BYTE, tex);
+
+ // Overwrite higher mipmap levels
+ for(x = 0; x < 4; ++x) {
+ tex[x][0] = 255;
+ tex[x][1] = 128;
+ tex[x][2] = 128;
+ tex[x][3] = 255;
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 7, GL_RGBA, 2, 2, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, tex);
+ glTexImage2D(GL_TEXTURE_2D, 8, GL_RGBA, 1, 1, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, tex);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ Reshape(Width,Height);
+}
+
+static void CheckFail(const char* cond)
+{
+ fprintf(stderr, "Check failed: %s\n", cond);
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ abort();
+}
+
+int main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ if (argc == 2 && !strcmp(argv[1], "-auto"))
+ Automatic = 1;
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Redisplay);
+ Init();
+ glutMainLoop();
+ return 0;
+}
+
+
diff --git a/tests/shaders/fp-incomplete-tex.c b/tests/shaders/fp-incomplete-tex.c
new file mode 100644
index 00000000..f8c465d7
--- /dev/null
+++ b/tests/shaders/fp-incomplete-tex.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) The Piglit project 2007
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * According to the ARB_fragment_program spec, section 3.11.6,
+ * sampling an incomplete texture image yields (0,0,0,1).
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static void CheckFail(const char* cond);
+
+#define check(cond) do { if (!(cond)) CheckFail(#cond); } while(0)
+
+
+#define NUM_PROGRAMS 5
+
+static GLuint FragProg[NUM_PROGRAMS];
+
+static const char* const ProgramText[NUM_PROGRAMS] = {
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.color, texture[0], 2D;\n"
+ "END",
+
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.color, texture[0], 3D;\n"
+ "END",
+
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.color, texture[0], 1D;\n"
+ "END",
+
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.color, texture[0], CUBE;\n"
+ "END",
+
+ "!!ARBfp1.0\n"
+ "TEX result.color, fragment.color, texture[0], RECT;\n"
+ "END"
+};
+
+static int Automatic = 0;
+
+static int Width = 300, Height = 200;
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC pglProgramLocalParameter4fvARB;
+static PFNGLPROGRAMLOCALPARAMETER4DARBPROC pglProgramLocalParameter4dARB;
+static PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC pglGetProgramLocalParameterdvARB;
+static PFNGLGENPROGRAMSARBPROC pglGenProgramsARB;
+static PFNGLPROGRAMSTRINGARBPROC pglProgramStringARB;
+static PFNGLBINDPROGRAMARBPROC pglBindProgramARB;
+static PFNGLISPROGRAMARBPROC pglIsProgramARB;
+static PFNGLDELETEPROGRAMSARBPROC pglDeleteProgramsARB;
+
+
+static void DoFrame(void)
+{
+ int mask;
+ int i;
+
+ glClearColor(0.3, 0.3, 0.3, 0.3);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ for(i = 0; i < NUM_PROGRAMS; ++i) {
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[i]);
+
+ glPushMatrix();
+ glTranslatef(i/2, i%2, 0);
+ glBegin(GL_QUADS);
+ glVertex2f(0, 0);
+ glVertex2f(1, 0);
+ glVertex2f(1, 1);
+ glVertex2f(0, 1);
+ glEnd();
+ glPopMatrix();
+ }
+
+ glutSwapBuffers();
+}
+
+static const struct {
+ const char* name;
+ float x, y;
+ float expected[4];
+} Probes[] = {
+ {
+ "incomplete 2D",
+ 0.5, 0.5,
+ { 0,0,0,1 }
+ },
+ {
+ "incomplete 3D",
+ 0.5, 1.5,
+ { 0,0,0,1 }
+ },
+ {
+ "incomplete 1D",
+ 1.5, 0.5,
+ { 0,0,0,1 }
+ },
+ {
+ "incomplete CUBE",
+ 1.5, 1.5,
+ { 0,0,0,1 }
+ },
+ {
+ "incomplete RECT",
+ 2.5, 0.5,
+ { 0,0,0,1 }
+ },
+
+ {
+ "sanity",
+ 2.5, 1.5,
+ { 0.3,0.3,0.3,0.3 }
+ },
+
+ // Sentinel!
+ {
+ 0,
+ 0, 0,
+ { 0, 0, 0, 0 }
+ }
+};
+
+static int DoTest( void )
+{
+ int idx;
+ GLfloat dmax;
+
+ glReadBuffer( GL_FRONT );
+ dmax = 0;
+
+ idx = 0;
+ while(Probes[idx].name) {
+ GLfloat probe[4];
+ GLfloat delta[4];
+ int i;
+
+ glReadPixels((int)(Probes[idx].x*Width/3),
+ (int)(Probes[idx].y*Height/2),
+ 1, 1,
+ GL_RGBA, GL_FLOAT, probe);
+
+ printf("%20s (%3.1f,%3.1f): %f,%f,%f,%f",
+ Probes[idx].name,
+ Probes[idx].x, Probes[idx].y,
+ probe[0], probe[1], probe[2], probe[3]);
+
+ for(i = 0; i < 4; ++i) {
+ delta[i] = probe[i] - Probes[idx].expected[i];
+
+ if (delta[i] > dmax) dmax = delta[i];
+ else if (-delta[i] > dmax) dmax = -delta[i];
+ }
+
+ printf(" Delta: %f,%f,%f,%f\n", delta[0], delta[1], delta[2], delta[3]);
+
+ idx++;
+ }
+
+ printf("Max delta: %f\n", dmax);
+
+ if (dmax >= 0.02)
+ return 0;
+ else
+ return 1;
+}
+
+
+static void Redisplay(void)
+{
+ int succ;
+
+ DoFrame();
+ succ = DoTest();
+
+ if (Automatic) {
+ printf("\nPIGLIT: { 'result': '%s' }\n", succ ? "pass" : "fail");
+ exit(0);
+ }
+}
+
+
+static void Reshape(int width, int height)
+{
+ Width = width;
+ Height = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, 3.0, 0.0, 2.0, -2.0, 6.0);
+ glScalef(1.0, 1.0, -1.0); // flip z-axis
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+/* A helper for finding errors in program strings */
+static int FindLine(const char *program, int position)
+{
+ int i, line = 1;
+ for (i = 0; i < position; i++) {
+ if (program[i] == '\n')
+ line++;
+ }
+ return line;
+}
+
+
+static void Init(void)
+{
+ int i, x, y;
+ GLubyte rectangle[200][200][4];
+ GLubyte tex[256][256][4];
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ fprintf(stderr, "Sorry, this demo requires GL_ARB_fragment_program\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+
+ /*
+ * Get extension function pointers.
+ */
+ pglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
+ assert(pglProgramLocalParameter4fvARB);
+
+ pglProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
+ assert(pglProgramLocalParameter4dARB);
+
+ pglGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
+ assert(pglGetProgramLocalParameterdvARB);
+
+ pglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
+ assert(pglGenProgramsARB);
+
+ pglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
+ assert(pglProgramStringARB);
+
+ pglBindProgramARB = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
+ assert(pglBindProgramARB);
+
+ pglIsProgramARB = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
+ assert(pglIsProgramARB);
+
+ pglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
+ assert(pglDeleteProgramsARB);
+
+ /*
+ * Fragment programs
+ */
+ pglGenProgramsARB(NUM_PROGRAMS, FragProg);
+
+ for(i = 0; i < NUM_PROGRAMS; ++i) {
+ GLint errorPos;
+
+ check(FragProg[i]);
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[i]);
+ pglProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(ProgramText[i]),
+ (const GLubyte *)ProgramText[i]);
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ if (glGetError() != GL_NO_ERROR || errorPos != -1) {
+ int l = FindLine(ProgramText[i], errorPos);
+ int a;
+
+ fprintf(stderr, "%i: Fragment Program Error (pos=%d line=%d): %s\n",
+ i, errorPos, l,
+ (char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+
+ for (a=-10; a<10; a++)
+ {
+ if (errorPos+a < 0)
+ continue;
+ if (errorPos+a >= strlen(ProgramText[i]))
+ break;
+ fprintf(stderr, "%c", ProgramText[i][errorPos+a]);
+ }
+ fprintf(stderr, "\n");
+
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ if (!pglIsProgramARB(FragProg[i])) {
+ fprintf(stderr, "pglIsProgramARB failed\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ }
+
+ Reshape(Width,Height);
+}
+
+static void CheckFail(const char* cond)
+{
+ fprintf(stderr, "Check failed: %s\n", cond);
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ abort();
+}
+
+int main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ if (argc == 2 && !strcmp(argv[1], "-auto"))
+ Automatic = 1;
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Redisplay);
+ Init();
+ glutMainLoop();
+ return 0;
+}
+
+
+
diff --git a/tests/shaders/fp-kil.c b/tests/shaders/fp-kil.c
new file mode 100644
index 00000000..31e70e92
--- /dev/null
+++ b/tests/shaders/fp-kil.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) The Piglit project 2007
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Test KIL instruction.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static void CheckFail(const char* cond);
+
+#define check(cond) do { if (!(cond)) CheckFail(#cond); } while(0)
+
+
+#define NUM_PROGRAMS 2
+
+static GLuint FragProg[NUM_PROGRAMS];
+
+static const char* const ProgramText[NUM_PROGRAMS] = {
+ "!!ARBfp1.0\n"
+ "TEMP r0;\n"
+ "MOV result.color, fragment.color;\n"
+ "KIL fragment.texcoord[0];\n"
+ "END",
+
+ "!!ARBfp1.0\n"
+ "TEMP r0;\n"
+ "TEX r0, fragment.texcoord[0], texture[0], 2D;\n"
+ "KIL -r0;\n"
+ "MOV result.color, fragment.color;\n"
+ "END"
+};
+
+static int Automatic = 0;
+
+static int Width = 200, Height = 200; // space for more tests
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC pglProgramLocalParameter4fvARB;
+static PFNGLPROGRAMLOCALPARAMETER4DARBPROC pglProgramLocalParameter4dARB;
+static PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC pglGetProgramLocalParameterdvARB;
+static PFNGLGENPROGRAMSARBPROC pglGenProgramsARB;
+static PFNGLPROGRAMSTRINGARBPROC pglProgramStringARB;
+static PFNGLBINDPROGRAMARBPROC pglBindProgramARB;
+static PFNGLISPROGRAMARBPROC pglIsProgramARB;
+static PFNGLDELETEPROGRAMSARBPROC pglDeleteProgramsARB;
+
+
+static void DoFrame(void)
+{
+ int mask;
+
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[0]);
+
+ glColor3f(0.0, 1.0, 0.0);
+ glBegin(GL_QUADS);
+ glTexCoord2f(-1, -1);
+ glVertex2f(0, 0);
+ glTexCoord2f(1, -1);
+ glVertex2f(1, 0);
+ glTexCoord2f(1, 1);
+ glVertex2f(1, 1);
+ glTexCoord2f(-1, 1);
+ glVertex2f(0, 1);
+ glEnd();
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[1]);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex2f(0, 1);
+ glTexCoord2f(1, 0);
+ glVertex2f(1, 1);
+ glTexCoord2f(1, 1);
+ glVertex2f(1, 2);
+ glTexCoord2f(0, 1);
+ glVertex2f(0, 2);
+ glEnd();
+
+ glutSwapBuffers();
+}
+
+static const struct {
+ const char* name;
+ float x, y;
+ float expected[4];
+} Probes[] = {
+ // Program 0
+ {
+ "basic #1",
+ 0.2, 0.2,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "basic #2",
+ 0.8, 0.2,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "basic #3",
+ 0.8, 0.8,
+ { 0.0, 1.0, 0.0, 1.0 }
+ },
+ {
+ "basic #4",
+ 0.2, 0.8,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+
+ // Program 0
+ {
+ "texture #1",
+ 0.125, 1.125,
+ { 0.0, 1.0, 0.0, 1.0 }
+ },
+ {
+ "texture #2",
+ 0.375, 1.125,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #3",
+ 0.625, 1.125,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #4",
+ 0.875, 1.125,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #5",
+ 0.125, 1.375,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #6",
+ 0.375, 1.375,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #7",
+ 0.625, 1.375,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #8",
+ 0.875, 1.375,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #9",
+ 0.125, 1.625,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #10",
+ 0.375, 1.625,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #11",
+ 0.625, 1.625,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #12",
+ 0.875, 1.625,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #13",
+ 0.125, 1.875,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #14",
+ 0.375, 1.875,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #15",
+ 0.625, 1.875,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+ {
+ "texture #16",
+ 0.875, 1.875,
+ { 0.0, 0.0, 0.0, 1.0 }
+ },
+
+ // Sentinel!
+ {
+ 0,
+ 0, 0,
+ { 0, 0, 0, 0 }
+ }
+};
+
+static int DoTest( void )
+{
+ int idx;
+ GLfloat dmax;
+
+ glReadBuffer( GL_FRONT );
+ dmax = 0;
+
+ idx = 0;
+ while(Probes[idx].name) {
+ GLfloat probe[4];
+ GLfloat delta[4];
+ int i;
+
+ glReadPixels((int)(Probes[idx].x*Width/2),
+ (int)(Probes[idx].y*Height/2),
+ 1, 1,
+ GL_RGBA, GL_FLOAT, probe);
+
+ printf("%20s (%3.1f,%3.1f): %f,%f,%f,%f",
+ Probes[idx].name,
+ Probes[idx].x, Probes[idx].y,
+ probe[0], probe[1], probe[2], probe[3]);
+
+ for(i = 0; i < 4; ++i) {
+ delta[i] = probe[i] - Probes[idx].expected[i];
+
+ if (delta[i] > dmax) dmax = delta[i];
+ else if (-delta[i] > dmax) dmax = -delta[i];
+ }
+
+ printf(" Delta: %f,%f,%f,%f\n", delta[0], delta[1], delta[2], delta[3]);
+
+ idx++;
+ }
+
+ printf("Max delta: %f\n", dmax);
+
+ if (dmax >= 0.02)
+ return 0;
+ else
+ return 1;
+}
+
+
+static void Redisplay(void)
+{
+ int succ;
+
+ DoFrame();
+ succ = DoTest();
+
+ if (Automatic) {
+ printf("\nPIGLIT: { 'result': '%s' }\n", succ ? "pass" : "fail");
+ exit(0);
+ }
+}
+
+
+static void Reshape(int width, int height)
+{
+ Width = width;
+ Height = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, 2.0, 0.0, 2.0, -2.0, 6.0);
+ glScalef(1.0, 1.0, -1.0); // flip z-axis
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+/* A helper for finding errors in program strings */
+static int FindLine(const char *program, int position)
+{
+ int i, line = 1;
+ for (i = 0; i < position; i++) {
+ if (program[i] == '\n')
+ line++;
+ }
+ return line;
+}
+
+
+static void Init(void)
+{
+ int i, x, y;
+ GLubyte tex[4][4][4];
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ fprintf(stderr, "Sorry, this demo requires GL_ARB_fragment_program\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+
+ /*
+ * Get extension function pointers.
+ */
+ pglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
+ assert(pglProgramLocalParameter4fvARB);
+
+ pglProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
+ assert(pglProgramLocalParameter4dARB);
+
+ pglGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
+ assert(pglGetProgramLocalParameterdvARB);
+
+ pglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
+ assert(pglGenProgramsARB);
+
+ pglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
+ assert(pglProgramStringARB);
+
+ pglBindProgramARB = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
+ assert(pglBindProgramARB);
+
+ pglIsProgramARB = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
+ assert(pglIsProgramARB);
+
+ pglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
+ assert(pglDeleteProgramsARB);
+
+ /*
+ * Fragment programs
+ */
+ pglGenProgramsARB(NUM_PROGRAMS, FragProg);
+
+ for(i = 0; i < NUM_PROGRAMS; ++i) {
+ GLint errorPos;
+
+ check(FragProg[i]);
+
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[i]);
+ pglProgramStringARB(
+ GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(ProgramText[i]),
+ (const GLubyte *)ProgramText[i]);
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ if (glGetError() != GL_NO_ERROR || errorPos != -1) {
+ int l = FindLine(ProgramText[i], errorPos);
+ int a;
+
+ fprintf(stderr, "%i: Fragment Program Error (pos=%d line=%d): %s\n",
+ i, errorPos, l,
+ (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+
+ for (a=-10; a<10; a++)
+ {
+ if (errorPos+a < 0)
+ continue;
+ if (errorPos+a >= strlen(ProgramText[i]))
+ break;
+ fprintf(stderr, "%c", ProgramText[i][errorPos+a]);
+ }
+ fprintf(stderr, "\n");
+
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ if (!pglIsProgramARB(FragProg[i])) {
+ fprintf(stderr, "pglIsProgramARB failed\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ }
+
+ /*
+ * Textures
+ */
+ for(y = 0; y < 4; ++y) {
+ for(x = 0; x < 4; ++x) {
+ tex[y][x][0] = (x & 1) ? 255 : 0;
+ tex[y][x][1] = (x & 2) ? 255 : 0;
+ tex[y][x][2] = (y & 1) ? 255 : 0;
+ tex[y][x][3] = (y & 2) ? 255 : 0;
+ }
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, tex);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ Reshape(Width,Height);
+}
+
+static void CheckFail(const char* cond)
+{
+ fprintf(stderr, "Check failed: %s\n", cond);
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ abort();
+}
+
+int main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ if (argc == 2 && !strcmp(argv[1], "-auto"))
+ Automatic = 1;
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Redisplay);
+ Init();
+ glutMainLoop();
+ return 0;
+}
+
+
+
diff --git a/tests/shaders/fp-lit-mask.c b/tests/shaders/fp-lit-mask.c
new file mode 100644
index 00000000..8182d83f
--- /dev/null
+++ b/tests/shaders/fp-lit-mask.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) The Piglit project 2007
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Test whether LIT honours the output mask.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+static GLuint FragProg[15];
+
+static const char fragProgramTemplate[] =
+ "!!ARBfp1.0\n"
+ "PARAM values = { 0.65, 0.9, 0.0, 8.0 }; \n"
+ "PARAM bogus = { 0.8, 0.8, 0.8, 0.8 }; \n"
+ "MOV result.color, bogus; \n"
+ "LIT result.color.%s, values; \n"
+ "END\n";
+static float LitExpected[4] = { 1.0, 0.65, 0.433, 1.0 };
+
+static int Automatic = 0;
+
+static int Width = 200, Height = 200;
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC pglProgramLocalParameter4fvARB;
+static PFNGLPROGRAMLOCALPARAMETER4DARBPROC pglProgramLocalParameter4dARB;
+static PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC pglGetProgramLocalParameterdvARB;
+static PFNGLGENPROGRAMSARBPROC pglGenProgramsARB;
+static PFNGLPROGRAMSTRINGARBPROC pglProgramStringARB;
+static PFNGLBINDPROGRAMARBPROC pglBindProgramARB;
+static PFNGLISPROGRAMARBPROC pglIsProgramARB;
+static PFNGLDELETEPROGRAMSARBPROC pglDeleteProgramsARB;
+
+
+static void DoFrame(void)
+{
+ int mask;
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ for(mask = 1; mask < 16; ++mask) {
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[mask-1]);
+ glPushMatrix();
+ glTranslatef((mask % 4), (mask / 4), 0.0);
+
+ glBegin(GL_QUADS);
+ glVertex2f(0, 0);
+ glVertex2f(1, 0);
+ glVertex2f(1, 1);
+ glVertex2f(0, 1);
+ glEnd();
+
+ glPopMatrix();
+ }
+
+ glutSwapBuffers();
+}
+
+static int DoTest( void )
+{
+ int mask;
+ GLfloat dmax;
+
+ glReadBuffer( GL_FRONT );
+ dmax = 0;
+
+ for(mask = 1; mask < 16; ++mask) {
+ GLfloat probe[4];
+ GLfloat delta[4];
+ int i;
+
+ glReadPixels(Width*(2*(mask%4)+1)/8, Height*(2*(mask/4)+1)/8, 1, 1,
+ GL_RGBA, GL_FLOAT, probe);
+
+ printf("Probe %i: %f,%f,%f,%f\n", mask, probe[0], probe[1], probe[2], probe[3]);
+
+ for(i = 0; i < 4; ++i) {
+ if (mask & (1 << i))
+ delta[i] = probe[i] - LitExpected[i];
+ else
+ delta[i] = probe[i] - 0.8;
+
+ if (delta[i] > dmax) dmax = delta[i];
+ else if (-delta[i] > dmax) dmax = -delta[i];
+ }
+
+ printf(" Delta: %f,%f,%f,%f\n", delta[0], delta[1], delta[2], delta[3]);
+ }
+
+ printf("Max delta: %f\n", dmax);
+
+ if (dmax >= 0.02)
+ return 0;
+ else
+ return 1;
+}
+
+
+static void Redisplay(void)
+{
+ int succ;
+
+ DoFrame();
+ succ = DoTest();
+
+ if (Automatic) {
+ printf("\nPIGLIT: { 'result': '%s' }\n", succ ? "pass" : "fail");
+ exit(0);
+ }
+}
+
+
+static void Reshape(int width, int height)
+{
+ Width = width;
+ Height = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, 4.0, 0.0, 4.0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ pglDeleteProgramsARB(15, FragProg);
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+/* A helper for finding errors in program strings */
+static int FindLine(const char *program, int position)
+{
+ int i, line = 1;
+ for (i = 0; i < position; i++) {
+ if (program[i] == '\n')
+ line++;
+ }
+ return line;
+}
+
+
+static void Init(void)
+{
+ int mask;
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ fprintf(stderr, "Sorry, this demo requires GL_ARB_fragment_program\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+
+ /*
+ * Get extension function pointers.
+ */
+ pglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
+ assert(pglProgramLocalParameter4fvARB);
+
+ pglProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
+ assert(pglProgramLocalParameter4dARB);
+
+ pglGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
+ assert(pglGetProgramLocalParameterdvARB);
+
+ pglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
+ assert(pglGenProgramsARB);
+
+ pglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
+ assert(pglProgramStringARB);
+
+ pglBindProgramARB = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
+ assert(pglBindProgramARB);
+
+ pglIsProgramARB = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
+ assert(pglIsProgramARB);
+
+ pglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
+ assert(pglDeleteProgramsARB);
+
+ /*
+ * Fragment programs
+ */
+ pglGenProgramsARB(15, FragProg);
+
+ for(mask = 1; mask < 16; ++mask) {
+ GLint errorPos;
+ char programText[1024];
+ char maskstring[5];
+
+ maskstring[0] = 0;
+ if (mask & 1) strcat(maskstring, "x");
+ if (mask & 2) strcat(maskstring, "y");
+ if (mask & 4) strcat(maskstring, "z");
+ if (mask & 8) strcat(maskstring, "w");
+ sprintf(programText, fragProgramTemplate, maskstring);
+
+ assert(FragProg[mask-1] > 0);
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg[mask-1]);
+ pglProgramStringARB(
+ GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(programText),
+ (const GLubyte *)programText);
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ if (glGetError() != GL_NO_ERROR || errorPos != -1) {
+ int l = FindLine(programText, errorPos);
+ fprintf(stderr, "Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
+ (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ if (!pglIsProgramARB(FragProg[mask-1])) {
+ fprintf(stderr, "pglIsProgramARB failed\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ }
+
+ Reshape(Width,Height);
+}
+
+
+int main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ if (argc == 2 && !strcmp(argv[1], "-auto"))
+ Automatic = 1;
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Redisplay);
+ Init();
+ glutMainLoop();
+ return 0;
+}
+
diff --git a/tests/shaders/trinity-fp1.c b/tests/shaders/trinity-fp1.c
new file mode 100644
index 00000000..aed2cbcf
--- /dev/null
+++ b/tests/shaders/trinity-fp1.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) The Piglit project 2007
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Test a fragment program that
+ * \sa http://www.mail-archive.com/dri-devel%40lists.sourceforge.net/msg30180.html
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+static GLuint TexDiffuse = 1;
+static GLuint TexNormal = 2;
+static GLuint TexSpecular = 3;
+static GLuint TexLookup = 4;
+
+static GLuint FragProg;
+
+static int Automatic = 0;
+
+static int Width = 200, Height = 100;
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC pglProgramLocalParameter4fvARB;
+static PFNGLPROGRAMLOCALPARAMETER4DARBPROC pglProgramLocalParameter4dARB;
+static PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC pglGetProgramLocalParameterdvARB;
+static PFNGLGENPROGRAMSARBPROC pglGenProgramsARB;
+static PFNGLPROGRAMSTRINGARBPROC pglProgramStringARB;
+static PFNGLBINDPROGRAMARBPROC pglBindProgramARB;
+static PFNGLISPROGRAMARBPROC pglIsProgramARB;
+static PFNGLDELETEPROGRAMSARBPROC pglDeleteProgramsARB;
+
+
+static void DoFrame(void)
+{
+ static float Local[3][4] = {
+ { 1.0, 0.8, 1.0, 1.0 },
+ { 0.5, 0.5, 0.5, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 }
+ };
+ static float Local2[3][4] = {
+ { 0.8, 1.0, 1.0, 1.0 },
+ { 0.5, 0.5, 0.5, 1.0 },
+ { 1.0, 0.0, 1.0, 1.0 }
+ };
+ int i;
+
+ glClearColor(0.8, 0.8, 0.8, 0.8);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, TexDiffuse);
+ glEnable(GL_TEXTURE_2D);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, TexNormal);
+ glEnable(GL_TEXTURE_2D);
+
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, TexSpecular);
+ glEnable(GL_TEXTURE_2D);
+
+ glActiveTexture(GL_TEXTURE3);
+ glBindTexture(GL_TEXTURE_2D, TexLookup);
+ glEnable(GL_TEXTURE_2D);
+
+ glActiveTexture(GL_TEXTURE4);
+ glBindTexture(GL_TEXTURE_2D, TexLookup);
+ glEnable(GL_TEXTURE_2D);
+
+ glActiveTexture(GL_TEXTURE5);
+ glBindTexture(GL_TEXTURE_2D, TexLookup);
+ glEnable(GL_TEXTURE_2D);
+
+ glMultiTexCoord2f(0, 0.0, 0.0);
+ glMultiTexCoord2f(1, 0.0, 0.0);
+ glMultiTexCoord2f(2, 0.0, 0.0);
+ glMultiTexCoord3f(3, 1.0, 0.05, 0.25);
+ glMultiTexCoord3f(4, 4, -3, 0);
+ glMultiTexCoord3f(5, 0, 3, 4);
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ for(i = 0; i < 3; ++i)
+ pglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, Local[i]);
+
+ glBegin(GL_QUADS);
+ glVertex2f(0.75, 0.75);
+ glVertex2f(0.25, 0.75);
+ glVertex2f(0.25, 0.25);
+ glVertex2f(0.75, 0.25);
+ glEnd();
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ for(i = 0; i < 3; ++i)
+ pglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, Local2[i]);
+
+ glBegin(GL_QUADS);
+ glVertex2f(1.75, 0.75);
+ glVertex2f(1.25, 0.75);
+ glVertex2f(1.25, 0.25);
+ glVertex2f(1.75, 0.25);
+ glEnd();
+
+ glutSwapBuffers();
+}
+
+static int DoTest( void )
+{
+ static const float expected[2][3] = {
+ { 0.30, 0.23, 0.40 },
+ { 0.24, 0.29, 0.40 }
+ };
+ int i;
+ GLfloat dmax = 0;
+
+ glReadBuffer( GL_FRONT );
+
+ for(i = 0; i < 2; ++i) {
+ GLfloat probe[4];
+ GLfloat delta[3];
+ int j;
+
+ glReadPixels(Width*(2*i+1)/4, Height/2, 1, 1, GL_RGBA, GL_FLOAT, probe);
+ printf("Probe: %f,%f,%f\n", probe[0], probe[1], probe[2]);
+
+ for(j = 0; j < 3; ++j) {
+ delta[j] = probe[j] - expected[i][j];
+ printf(" Delta: %f,%f,%f\n", delta[0], delta[1], delta[2]);
+ if (delta[j] > dmax) dmax = delta[j];
+ else if (-delta[j] > dmax) dmax = -delta[j];
+ }
+ }
+
+ printf("Max delta: %f\n", dmax);
+
+ if (dmax >= 0.02)
+ return 0;
+ else
+ return 1;
+}
+
+
+static void Redisplay(void)
+{
+ int succ;
+
+ DoFrame();
+ succ = DoTest();
+
+ if (Automatic) {
+ printf("\nPIGLIT: { 'result': '%s' }\n", succ ? "pass" : "fail");
+ exit(0);
+ }
+}
+
+
+static void Reshape(int width, int height)
+{
+ Width = width;
+ Height = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, 2.0, 0.0, 1.0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ pglDeleteProgramsARB(1, &FragProg);
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+/* A helper for finding errors in program strings */
+static int FindLine(const char *program, int position)
+{
+ int i, line = 1;
+ for (i = 0; i < position; i++) {
+ if (program[i] == '\n')
+ line++;
+ }
+ return line;
+}
+
+
+static void Init(void)
+{
+ GLint errorPos;
+ GLubyte data[256][256][4];
+ int x,y;
+
+ static const char *fragProgramText =
+ "!!ARBfp1.0\n"
+ "# $Id$\n"
+ "# Copyright (C) 2006 Oliver McFadden <z3ro.geek@gmail.com>\n"
+ "#\n"
+ "# This program is free software; you can redistribute it and/or modify\n"
+ "# it under the terms of the GNU General Public License as published by\n"
+ "# the Free Software Foundation; either version 2 of the License, or\n"
+ "# (at your option) any later version.\n"
+ "#\n"
+ "# This program is distributed in the hope that it will be useful,\n"
+ "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "# GNU General Public License for more details.\n"
+ "#\n"
+ "# You should have received a copy of the GNU General Public License\n"
+ "# along with this program; if not, write to the Free Software\n"
+ "# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
+
+ "TEMP H, L, N, V, attenuationxy, attenuationz, color, diffuse, dot, specular, tmp;\n"
+
+ "DP3 L.x, fragment.texcoord[4], fragment.texcoord[4];\n"
+ "RSQ L.x, L.x;\n"
+ "MUL L.xyz, L.x, fragment.texcoord[4];\n"
+
+ "DP3 V.x, fragment.texcoord[5], fragment.texcoord[5];\n"
+ "RSQ V.x, V.x;\n"
+ "MUL V.xyz, V.x, fragment.texcoord[5];\n"
+
+ "ADD tmp, L, V;\n"
+ "DP3 H.x, tmp, tmp;\n"
+ "RSQ H.x, H.x;\n"
+ "MUL H.xyz, H.x, tmp;\n"
+
+ "TEX tmp.xyz, fragment.texcoord[1], texture[1], 2D;\n"
+ "MAD tmp.xyz, tmp, 2.0, -1.0;\n"
+ "DP3 N.x, tmp, tmp;\n"
+ "RSQ N.x, N.x;\n"
+ "MUL N.xyz, N.x, tmp;\n"
+
+ "DP3_SAT dot.x, N, L;\n"
+ "MUL dot.xyz, program.local[0], dot.x;\n"
+
+ "TEX diffuse.xyz, fragment.texcoord[0], texture[0], 2D;\n"
+
+ "DP3_SAT tmp.x, N, H;\n"
+ "POW tmp.x, tmp.x, program.local[2].x;\n"
+ "TEX specular.xyz, fragment.texcoord[2], texture[2], 2D;\n"
+ "MUL specular.xyz, specular, program.local[0];\n"
+ "MUL specular.xyz, specular, tmp.x;\n"
+
+ "TEX attenuationxy.xyz, fragment.texcoord[3], texture[3], 2D;\n"
+
+ "MOV tmp.x, fragment.texcoord[3].z;\n"
+ "MOV tmp.y, 0;\n"
+ "TEX attenuationz.xyz, tmp, texture[4], 2D;\n"
+
+ "MOV color, diffuse;\n"
+ "MUL color.xyz, color, dot;\n"
+ "ADD color.xyz, color, specular;\n"
+ "MUL color.xyz, color, attenuationxy;\n"
+ "MUL color.xyz, color, attenuationz;\n"
+ "MUL color.xyz, color, program.local[1].x;\n"
+ "MOV result.color, color;\n"
+
+ "END";
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+ fprintf(stderr, "Sorry, this demo requires GL_ARB_fragment_program\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+
+ /*
+ * Get extension function pointers.
+ */
+ pglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
+ assert(pglProgramLocalParameter4fvARB);
+
+ pglProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
+ assert(pglProgramLocalParameter4dARB);
+
+ pglGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
+ assert(pglGetProgramLocalParameterdvARB);
+
+ pglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
+ assert(pglGenProgramsARB);
+
+ pglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
+ assert(pglProgramStringARB);
+
+ pglBindProgramARB = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
+ assert(pglBindProgramARB);
+
+ pglIsProgramARB = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
+ assert(pglIsProgramARB);
+
+ pglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
+ assert(pglDeleteProgramsARB);
+
+ /*
+ * Fragment program
+ */
+ pglGenProgramsARB(1, &FragProg);
+ assert(FragProg > 0);
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FragProg);
+ pglProgramStringARB(
+ GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(fragProgramText),
+ (const GLubyte *) fragProgramText);
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ if (glGetError() != GL_NO_ERROR || errorPos != -1) {
+ int l = FindLine(fragProgramText, errorPos);
+ fprintf(stderr, "Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
+ (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+ if (!pglIsProgramARB(FragProg)) {
+ fprintf(stderr, "pglIsProgramARB failed\n");
+ if (Automatic)
+ printf("PIGLIT: {'result': 'fail' }\n");
+ exit(1);
+ }
+
+ /*
+ * Initialize textures
+ */
+ // Diffuse
+ for(y = 0; y < 256; ++y) {
+ for(x = 0; x < 256; ++x) {
+ data[y][x][0] = 255; // 1.0
+ data[y][x][1] = 192; // 0.75
+ data[y][x][2] = 255; // 1.0
+ data[y][x][3] = 0;
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, TexDiffuse);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
+
+ // Normal
+ for(y = 0; y < 256; ++y) {
+ for(x = 0; x < 256; ++x) {
+ data[y][x][0] = 255; // 1.0
+ data[y][x][1] = 0; // 0.0
+ data[y][x][2] = 0; // 0.0
+ data[y][x][3] = 0;
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, TexNormal);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
+
+ // Specular
+ for(y = 0; y < 256; ++y) {
+ for(x = 0; x < 256; ++x) {
+ data[y][x][0] = 255; // 1.0
+ data[y][x][1] = 255; // 1.0
+ data[y][x][2] = 192; // 0.75
+ data[y][x][3] = 0;
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, TexSpecular);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
+
+ // Lookup texture
+ for(y = 0; y < 256; ++y) {
+ for(x = 0; x < 256; ++x) {
+ data[y][x][0] = 255-x;
+ data[y][x][1] = 255-y;
+ data[y][x][2] = 255;
+ data[y][x][3] = 0;
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, TexLookup);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
+
+ Reshape(Width,Height);
+}
+
+
+int main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ if (argc == 2 && !strcmp(argv[1], "-auto"))
+ Automatic = 1;
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Redisplay);
+ Init();
+ glutMainLoop();
+ return 0;
+}