diff options
author | Nicolai Hähnle <nh@annarchy.freedesktop.org> | 2007-03-24 17:20:31 -0700 |
---|---|---|
committer | Nicolai Hähnle <nh@annarchy.freedesktop.org> | 2007-03-24 17:20:31 -0700 |
commit | 22fbbb5e8679ddf91532cb10eaa31be533383b48 (patch) | |
tree | cb43f83fe997f166f297dad671ddf04e2f601be4 |
Initial commit
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. + @@ -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"> </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"> </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; +} |