summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAllen Akin <akin@users.sourceforge.net>1999-12-15 01:24:19 +0000
committerAllen Akin <akin@users.sourceforge.net>1999-12-15 01:24:19 +0000
commit402349fd7e464b18882e531f05668125a4a9d73b (patch)
tree0022594e4e0dd82f71b9dcd44c02fe1860f222b7 /src
Initial revision
Diffstat (limited to 'src')
-rw-r--r--src/Makefile5
-rw-r--r--src/glean/Makefile8
-rw-r--r--src/glean/dsurf.cpp205
-rw-r--r--src/glean/dsurf.h83
-rw-r--r--src/glean/environ.cpp150
-rw-r--r--src/glean/environ.h111
-rw-r--r--src/glean/geomutil.cpp52
-rw-r--r--src/glean/geomutil.h55
-rw-r--r--src/glean/glutils.cpp60
-rw-r--r--src/glean/glutils.h52
-rw-r--r--src/glean/main.cpp290
-rw-r--r--src/glean/makefile.win132
-rw-r--r--src/glean/misc.cpp59
-rw-r--r--src/glean/misc.h48
-rw-r--r--src/glean/options.cpp55
-rw-r--r--src/glean/options.h95
-rw-r--r--src/glean/rc.cpp150
-rw-r--r--src/glean/rc.h66
-rw-r--r--src/glean/tbasic.cpp254
-rw-r--r--src/glean/tbasic.h97
-rw-r--r--src/glean/tblend.cpp768
-rw-r--r--src/glean/tblend.h91
-rw-r--r--src/glean/tchgperf.cpp451
-rw-r--r--src/glean/tchgperf.h87
-rw-r--r--src/glean/test.cpp124
-rw-r--r--src/glean/test.h140
-rw-r--r--src/glean/tgetstr.cpp344
-rw-r--r--src/glean/tgetstr.h87
-rw-r--r--src/glean/trgbtris.cpp354
-rw-r--r--src/glean/trgbtris.h85
-rw-r--r--src/glean/version.h47
-rw-r--r--src/glean/winsys.cpp181
-rw-r--r--src/glean/winsys.h111
-rw-r--r--src/glh/Makefile5
-rw-r--r--src/glh/glwrap.h63
-rw-r--r--src/glh/makefile.win12
-rw-r--r--src/libs/Makefile5
-rw-r--r--src/libs/dsurf/Makefile6
-rw-r--r--src/libs/dsurf/dsconfig.cpp767
-rw-r--r--src/libs/dsurf/dsconfig.h203
-rw-r--r--src/libs/dsurf/dsfilt.cpp690
-rw-r--r--src/libs/dsurf/dsfilt.h268
-rw-r--r--src/libs/dsurf/makefile.win131
-rw-r--r--src/libs/image/Makefile6
-rw-r--r--src/libs/image/gl.cpp82
-rw-r--r--src/libs/image/image.h246
-rw-r--r--src/libs/image/makefile.win135
-rw-r--r--src/libs/image/misc.cpp210
-rw-r--r--src/libs/image/pack.cpp262
-rw-r--r--src/libs/image/rdtiff.cpp156
-rw-r--r--src/libs/image/reg.cpp178
-rw-r--r--src/libs/image/unpack.cpp271
-rw-r--r--src/libs/image/wrtiff.cpp134
-rw-r--r--src/libs/lex/Makefile6
-rw-r--r--src/libs/lex/lex.cpp167
-rw-r--r--src/libs/lex/lex.h128
-rw-r--r--src/libs/lex/makefile.win129
-rw-r--r--src/libs/makefile.win78
-rw-r--r--src/libs/rand/Makefile5
-rw-r--r--src/libs/rand/makefile.win12
-rw-r--r--src/libs/rand/rand.h125
-rw-r--r--src/libs/stats/Makefile6
-rw-r--r--src/libs/stats/basic.cpp64
-rw-r--r--src/libs/stats/makefile.win129
-rw-r--r--src/libs/stats/stats.h87
-rw-r--r--src/libs/timer/Makefile6
-rw-r--r--src/libs/timer/makefile.win129
-rw-r--r--src/libs/timer/timer.cpp213
-rw-r--r--src/libs/timer/timer.h71
-rw-r--r--src/makefile.win71
-rw-r--r--src/tools/Makefile5
-rw-r--r--src/tools/difftiff/Makefile6
-rw-r--r--src/tools/difftiff/main.cpp401
-rw-r--r--src/tools/difftiff/makefile.win118
-rw-r--r--src/tools/makefile.win54
-rw-r--r--src/tools/showtiff/Makefile6
-rw-r--r--src/tools/showtiff/main.cpp163
-rw-r--r--src/tools/showtiff/makefile.win118
-rw-r--r--src/tools/showvis/Makefile6
-rw-r--r--src/tools/showvis/main.cpp293
-rw-r--r--src/tools/showvis/makefile.win118
81 files changed, 11441 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..ee983b8
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,5 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+DIRS=glh libs glean tools
+
+include $(GLEAN_ROOT)/make/null.mak
diff --git a/src/glean/Makefile b/src/glean/Makefile
new file mode 100644
index 0000000..09a2149
--- /dev/null
+++ b/src/glean/Makefile
@@ -0,0 +1,8 @@
+# Makefile for glean
+
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=glean
+LIB=-lstats -ldsurf -llex -limage -ltimer -ltiff -lGLU -lGL -lXmu -lXext -lX11
+
+include $(GLEAN_ROOT)/make/app.mak
diff --git a/src/glean/dsurf.cpp b/src/glean/dsurf.cpp
new file mode 100644
index 0000000..4f6126d
--- /dev/null
+++ b/src/glean/dsurf.cpp
@@ -0,0 +1,205 @@
+// 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
+
+
+
+
+// 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):
+ DrawingSurface(ws, c) {
+
+#if defined(__X11__)
+
+#if defined(GLX_VERSION_1_3)
+
+#error "XXX Need GLX 1.3 window-creation code"
+
+#else
+
+ // 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),
+ 0, 0, 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 = 10;
+ sizeHints.y = 10;
+ 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;
+ }
+
+#endif
+
+#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 = 50;
+ r.top = 50;
+ 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);
+#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);
+#endif
+
+} // Window::~Window
+
+///////////////////////////////////////////////////////////////////////////////
+// Utilities
+///////////////////////////////////////////////////////////////////////////////
+void
+Window::swap() {
+# if defined(__X11__)
+ glXSwapBuffers(winSys->dpy, xWindow);
+# elif defined(__WIN__)
+ SwapBuffers(hDC);
+# 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
+
+} // namespace GLEAN
diff --git a/src/glean/dsurf.h b/src/glean/dsurf.h
new file mode 100644
index 0000000..925127d
--- /dev/null
+++ b/src/glean/dsurf.h
@@ -0,0 +1,83 @@
+// 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
+
+
+
+
+// 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
+
+class Window: public DrawingSurface {
+ public:
+ Window(WindowSystem& ws, DrawingSurfaceConfig& c, int w, int h);
+ ~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);
+# endif
+}; // class Window
+
+} // namespace GLEAN
+
+#endif // __dsurf_h__
diff --git a/src/glean/environ.cpp b/src/glean/environ.cpp
new file mode 100644
index 0000000..1856c58
--- /dev/null
+++ b/src/glean/environ.cpp
@@ -0,0 +1,150 @@
+// 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
+
+
+
+
+// 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 (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 {
+ 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 (!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 {
+ 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/src/glean/environ.h b/src/glean/environ.h
new file mode 100644
index 0000000..ed51384
--- /dev/null
+++ b/src/glean/environ.h
@@ -0,0 +1,111 @@
+// 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
+
+
+
+
+// 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/src/glean/geomutil.cpp b/src/glean/geomutil.cpp
new file mode 100644
index 0000000..0ec0f1c
--- /dev/null
+++ b/src/glean/geomutil.cpp
@@ -0,0 +1,52 @@
+// geomutil.cpp: frequently-used geometric operations
+
+#include "geomutil.h"
+#include "rand.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;
+
+ for (int iy = 0; iy < yPoints; ++iy) {
+ double sum = 0.0;
+ int ix;
+ for (ix = 0; ix < xPoints; ++ix) {
+ (*this)(iy, ix)[0] = sum;
+ sum += rand.next();
+ }
+ double scale = (maxX - minX) / (*this)(iy, xPoints - 1)[0];
+ for (ix = 0; ix < xPoints; ++ix) {
+ float* x = (*this)(iy, ix) + 0;
+ *x = scale * *x + minX;
+ }
+ }
+
+ for (int ix = 0; ix < xPoints; ++ix) {
+ double sum = 0.0;
+ int iy;
+ for (iy = 0; iy < yPoints; ++iy) {
+ (*this)(iy, ix)[1] = sum;
+ sum += rand.next();
+ }
+ double scale = (maxY - minY) / (*this)(yPoints - 1, ix)[1];
+ for (iy = 0; iy < yPoints; ++iy) {
+ float* y = (*this)(iy, ix) + 1;
+ *y = scale * *y + minY;
+ }
+ }
+} // RandomMesh2D::RandomMesh2D
+
+RandomMesh2D::~RandomMesh2D() {
+ delete[] m;
+} // RandomMesh2D::~RandomMesh2D
+
+
+} // namespace GLEAN
diff --git a/src/glean/geomutil.h b/src/glean/geomutil.h
new file mode 100644
index 0000000..df476ba
--- /dev/null
+++ b/src/glean/geomutil.h
@@ -0,0 +1,55 @@
+// 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
+
+
+
+
+// geomutil.h: frequently-used geometric operations
+
+#ifndef __geomutil_h__
+#define __geomutil_h__
+
+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
+
+} // namespace GLEAN
+
+#endif // __geomutil_h__
diff --git a/src/glean/glutils.cpp b/src/glean/glutils.cpp
new file mode 100644
index 0000000..5c87789
--- /dev/null
+++ b/src/glean/glutils.cpp
@@ -0,0 +1,60 @@
+// 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
+
+
+
+
+// glutils.cpp: frequently-used OpenGL operations
+
+#include "glwrap.h"
+#include "environ.h"
+
+#include "glutils.h"
+
+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);
+} // useScreenCoords
+
+} // namespace GLUtils
+
+} // namespace GLEAN
diff --git a/src/glean/glutils.h b/src/glean/glutils.h
new file mode 100644
index 0000000..84e6b7a
--- /dev/null
+++ b/src/glean/glutils.h
@@ -0,0 +1,52 @@
+// 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
+
+
+
+
+// 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);
+
+} // namespace GLUtils
+
+} // namespace GLEAN
+
+#endif // __glutils_h__
diff --git a/src/glean/main.cpp b/src/glean/main.cpp
new file mode 100644
index 0000000..5eeaeed
--- /dev/null
+++ b/src/glean/main.cpp
@@ -0,0 +1,290 @@
+// 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
+
+
+
+
+// main.cpp: main program for Glean
+
+#include <assert.h>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include "options.h"
+#include "dsfilt.h"
+#include "environ.h"
+#include "test.h"
+#include "version.h"
+#include "lex.h"
+
+using namespace std;
+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);
+
+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], "-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);
+# 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]);
+
+ // 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))
+ t->compare(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
+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"
+" --visuals 'filter-string' # select subset of visuals (FBConfigs,\n"
+" # pixel formats) to test\n"
+" (-t|--tests) {(+|-)test} # choose tests to include (+) or exclude (-)\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/src/glean/makefile.win b/src/glean/makefile.win
new file mode 100644
index 0000000..2ad3944
--- /dev/null
+++ b/src/glean/makefile.win
@@ -0,0 +1,132 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+#!MESSAGE No configuration specified. Defaulting to release build.
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "difftiff.mak" CFG="release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+LINK32_OBJS= "$(INTDIR)\dsurf.obj" \
+ "$(INTDIR)\environ.obj" \
+ "$(INTDIR)\geomutil.obj" \
+ "$(INTDIR)\glutils.obj" \
+ "$(INTDIR)\main.obj" \
+ "$(INTDIR)\misc.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\rc.obj" \
+ "$(INTDIR)\tbasic.obj" \
+ "$(INTDIR)\tblend.obj" \
+ "$(INTDIR)\tchgperf.obj" \
+ "$(INTDIR)\test.obj" \
+ "$(INTDIR)\tgetstr.obj" \
+ "$(INTDIR)\trgbtris.obj" \
+ "$(INTDIR)\winsys.obj"
+
+LIBS=dsurf.lib image.lib stats.lib timer.lib lex.lib libtiff.lib opengl32.lib glu32.lib glu32.lib glut32.lib kernel32.lib user32.lib gdi32.lib
+
+FTARGET=glean
+TARGET=$(FTARGET).exe
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_BIN_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /Y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=$(LIBS) /nologo /subsystem:console /machine:I386 /include:"__imp__glGetString@4" /out:"$(GLEAN_BIN_DIR)\$(TARGET)" /nodefaultlib:libcd.lib
+
+"$(GLEAN_BIN_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS) $(LIB_DIRS)
+
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_BIN_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(OUTDIR)\$(FTARGET).pdb"
+ -@erase "$(GLEAN_BIN_DIR)\$(FTARGET).ilk"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /Y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=$(LIBS) /nologo /subsystem:console /incremental:yes /pdb:"$(OUTDIR)\$(FTARGET).pdb" /debug /machine:I386 /include:"__imp__glGetString@4" /out:"$(GLEAN_BIN_DIR)\$(TARGET)" /pdbtype:sept $(LIB_DIRS)
+
+"$(GLEAN_BIN_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)
+
+!ENDIF
+
+
diff --git a/src/glean/misc.cpp b/src/glean/misc.cpp
new file mode 100644
index 0000000..3bcb0ea
--- /dev/null
+++ b/src/glean/misc.cpp
@@ -0,0 +1,59 @@
+// 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
+
+
+
+
+// misc.cpp: implementation of miscellaneous functions
+
+#include <cctype>
+#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
+
+
+} // namespace GLEAN
diff --git a/src/glean/misc.h b/src/glean/misc.h
new file mode 100644
index 0000000..24d0485
--- /dev/null
+++ b/src/glean/misc.h
@@ -0,0 +1,48 @@
+// 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
+
+
+
+
+// misc.h: Miscellaneous functions
+
+
+#ifndef __misc_h__
+#define __misc_h__
+
+#include <iostream>
+
+using namespace std;
+
+namespace GLEAN {
+
+void SkipWhitespace(istream& s);
+
+} // namespace GLEAN
+
+#endif // __misc_h__
diff --git a/src/glean/options.cpp b/src/glean/options.cpp
new file mode 100644
index 0000000..e00cb0b
--- /dev/null
+++ b/src/glean/options.cpp
@@ -0,0 +1,55 @@
+// 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
+
+
+
+
+// options.cpp: implementation of global options class
+
+#include "options.h"
+
+namespace GLEAN {
+
+
+
+Options::Options() {
+ mode = notSet;
+ verbosity = 0;
+ db1Name = "results";
+ db2Name = "previous";
+ visFilter = "1";
+ selectedTests.resize(0);
+# if defined(__X11__)
+ dpyName = ":0";
+# elif defined(__WIN__)
+# endif
+} // Options::Options()
+
+
+
+} // namespace GLEAN
diff --git a/src/glean/options.h b/src/glean/options.h
new file mode 100644
index 0000000..88aacd1
--- /dev/null
+++ b/src/glean/options.h
@@ -0,0 +1,95 @@
+// 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
+
+
+
+
+// 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__
+
+#include <string>
+#include <vector>
+
+using namespace std;
+
+namespace GLEAN {
+
+class Options {
+ public:
+ typedef enum {notSet, run, compare} 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.
+
+#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/src/glean/rc.cpp b/src/glean/rc.cpp
new file mode 100644
index 0000000..0172924
--- /dev/null
+++ b/src/glean/rc.cpp
@@ -0,0 +1,150 @@
+// 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
+
+
+
+
+// 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)
+
+# error "XXX Need GLX 1.3 rc constructor code"
+
+# else
+
+ // 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)
+
+# endif
+
+# elif defined(__WIN__)
+
+ rc = create_context(c);
+ if (!rc)
+ 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)
+# error "Need to write GLX 1.3 rc destructor"
+# else
+ glXDestroyContext(winSys->dpy, rc);
+# endif
+# elif defined(__WIN__)
+ wglDeleteContext(rc);
+# endif
+} // RenderingContext::~RenderingContext
+
+
+} // namespace GLEAN
diff --git a/src/glean/rc.h b/src/glean/rc.h
new file mode 100644
index 0000000..e97707d
--- /dev/null
+++ b/src/glean/rc.h
@@ -0,0 +1,66 @@
+// 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
+
+
+
+
+// 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;
+# endif
+
+}; // class RenderingContext
+
+} // namespace GLEAN
+
+#endif // __rc_h__
diff --git a/src/glean/tbasic.cpp b/src/glean/tbasic.cpp
new file mode 100644
index 0000000..bb83dbd
--- /dev/null
+++ b/src/glean/tbasic.cpp
@@ -0,0 +1,254 @@
+// 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
+
+
+
+
+// tbasic.cpp: implementation of example class for basic tests
+
+#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 "tbasic.h"
+#include "misc.h"
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor/Destructor:
+///////////////////////////////////////////////////////////////////////////////
+BasicTest::BasicTest(const char* aName, const char* aFilter,
+ const char* aDescription):
+ Test(aName), filter(aFilter), description(aDescription) {
+} // BasicTest::BasicTest()
+
+BasicTest::~BasicTest() {
+} // BasicTest::~BasicTest
+
+///////////////////////////////////////////////////////////////////////////////
+// run: run tests, save results in a vector and in the results file
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicTest::run(Environment& environment) {
+ // Guard against multiple invocations:
+ if (hasRun)
+ return;
+
+ // Set up environment for use by other functions:
+ env = &environment;
+
+ // Document the test in the log, if requested:
+ logDescription();
+
+ // Compute results and make them available to subsequent tests:
+ WindowSystem& ws = env->winSys;
+ try {
+ // Open the results file:
+ OutputStream os(*this);
+
+ // 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, 258, 258);
+ RenderingContext rc(ws, **p);
+ if (!ws.makeCurrent(rc, w))
+ ; // XXX need to throw exception here
+
+ // Create a result object and run the test:
+ Result *r = new Result;
+ r->config = *p;
+ runOne(*r);
+
+ // Save the result locally and in the results file:
+ results.push_back(r);
+ r->put(os);
+ }
+ }
+ 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';
+
+ // Note that we've completed the run:
+ hasRun = true;
+}
+
+void
+BasicTest::compare(Environment& environment) {
+ // Save the environment for use by other member functions:
+ env = &environment;
+
+ // Display the description if needed:
+ logDescription();
+
+ // Read results from previous runs:
+ Input1Stream is1(*this);
+ vector<Result*> oldR(getResults(is1));
+ Input2Stream is2(*this);
+ vector<Result*> 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 (vector<Result*>::const_iterator p = oldR.begin(); p < oldR.end();
+ ++p)
+ oldConfigs.push_back((*p)->config);
+
+ // Compare results:
+ for (vector<Result*>::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 (vector<Result*>::iterator op = newR.begin(); op < newR.end(); ++op)
+ delete *op;
+ for (vector<Result*>::iterator np = oldR.begin(); np < oldR.end(); ++np)
+ delete *np;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicTest::runOne(Result& r) {
+ r.pass = true;
+ env->log << name << (r.pass? ": PASS ": ": FAIL ")
+ << r.config->conciseDescription() << '\n';
+} // BasicTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicTest::compareOne(Result& oldR, Result& 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");
+ }
+} // BasicTest::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logDescription: Print description on the log file, according to the
+// current verbosity level.
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicTest::logDescription() {
+ if (env->options.verbosity)
+ env->log <<
+"----------------------------------------------------------------------\n"
+ << description << '\n';
+} // BasicTest::logDescription
+
+///////////////////////////////////////////////////////////////////////////////
+// Result I/O functions:
+///////////////////////////////////////////////////////////////////////////////
+void
+BasicTest::Result::put(ostream& s) const {
+ s << config->canonicalDescription() << '\n' << pass << '\n';
+} // BasicTest::Result::put
+
+bool
+BasicTest::Result::get(istream& s) {
+ SkipWhitespace(s);
+ string configDesc;
+ if (!getline(s, configDesc))
+ return false;
+ config = new DrawingSurfaceConfig(configDesc);
+ s >> pass;
+ return s.good();
+} // BasicTest::Result::get
+
+vector<BasicTest::Result*>
+BasicTest::getResults(istream& s) {
+ vector<Result*> v;
+ while (s.good()) {
+ Result* r = new Result();
+ if (r->get(s))
+ v.push_back(r);
+ else {
+ delete r;
+ break;
+ }
+ }
+
+ return v;
+} // BasicTest::getResults
+
+///////////////////////////////////////////////////////////////////////////////
+// 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/src/glean/tbasic.h b/src/glean/tbasic.h
new file mode 100644
index 0000000..9922c5b
--- /dev/null
+++ b/src/glean/tbasic.h
@@ -0,0 +1,97 @@
+// 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
+
+
+
+
+// tbasic.h: Example class for basic tests
+
+// This class (derived from Test) provides a framework for a large set
+// of correctness tests that should be portable (in the sense that
+// they don't contain OS- or window-system-specific code).
+
+// Each basic test includes a drawing surface filter string. The test
+// will 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.
+
+// When comparing two runs, the drawing surface configurations are
+// used to select plausible matches among the results.
+
+
+#ifndef __tbasic_h__
+#define __tbasic_h__
+
+#include "test.h"
+
+class DrawingSurfaceConfig; // Forward reference.
+
+namespace GLEAN {
+
+class BasicTest: public Test {
+ public:
+ BasicTest(const char* testName, const char* filter,
+ const char* description);
+ virtual ~BasicTest();
+
+ const char* filter; // Drawing surface configuration filter.
+ const char* description; // Verbose description of test.
+
+ virtual void run(Environment& env); // Run test, save results.
+
+ virtual void compare(Environment& env);
+ // Compare two previous runs.
+
+ // Class for a single test result. All basic tests have a
+ // drawing surface configuration, plus other information
+ // that's specific to the test.
+ class Result: public Test::Result {
+ public:
+ DrawingSurfaceConfig* config;
+ bool pass;
+
+ virtual void put(ostream& s) const;
+ virtual bool get(istream& s);
+
+ Result() { }
+ virtual ~Result() { }
+ };
+
+ vector<Result*> results;
+
+ virtual void runOne(Result& r);
+ virtual void compareOne(Result& oldR, Result& newR);
+ virtual vector<Result*> getResults(istream& s);
+
+ void logDescription();
+
+}; // class BasicTest
+
+} // namespace GLEAN
+
+#endif // __tbasic_h__
diff --git a/src/glean/tblend.cpp b/src/glean/tblend.cpp
new file mode 100644
index 0000000..a7f2638
--- /dev/null
+++ b/src/glean/tblend.cpp
@@ -0,0 +1,768 @@
+// 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
+
+
+
+
+// tblend.cpp: Test blending functions.
+
+#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 "geomutil.h"
+#include "rand.h"
+#include "stats.h"
+#include "image.h"
+#include "tblend.h"
+#include "misc.h"
+
+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
+
+const int 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.
+
+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 blendErrorBits;};
+
+template <class T> inline T log2(T x) { return 1.4426950408889634 * log(x); }
+
+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;
+}
+
+runFactorsResult
+runFactors(GLenum srcFactor, GLenum dstFactor,
+ GLEAN::DrawingSurfaceConfig& config, GLEAN::Environment& env) {
+ 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.blendErrorBits = 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.blendErrorBits =
+ max(static_cast<double>(result.blendErrorBits),
+ max(errorBits(rError, config.r),
+ max(errorBits(gError, config.g),
+ max(errorBits(bError, config.b),
+ errorBits(aError, config.a)))));
+ if (result.blendErrorBits > 1.0) {
+ 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;
+ }
+ }
+ sRow += actual.rowSizeInBytes();
+ dRow += expected.rowSizeInBytes();
+ }
+
+ return result;
+} // runOneSet
+
+} // anonymous namespace
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor/Destructor:
+///////////////////////////////////////////////////////////////////////////////
+BlendFuncTest::BlendFuncTest(const char* aName, const char* aFilter,
+ const char* aDescription):
+ Test(aName), filter(aFilter), description(aDescription) {
+} // BlendFuncTest::BlendFuncTest()
+
+BlendFuncTest::~BlendFuncTest() {
+} // BlendFuncTest::~BlendFuncTest
+
+///////////////////////////////////////////////////////////////////////////////
+// run: run tests, save results in a vector and in the results file
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncTest::run(Environment& environment) {
+ // Guard against multiple invocations:
+ if (hasRun)
+ return;
+
+ // Set up environment for use by other functions:
+ env = &environment;
+
+ // Document the test in the log, if requested:
+ logDescription();
+
+ // Compute results and make them available to subsequent tests:
+ WindowSystem& ws = env->winSys;
+ try {
+ // Open the results file:
+ OutputStream os(*this);
+
+ // 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, drawingSize + 2, drawingSize + 2);
+ RenderingContext rc(ws, **p);
+ if (!ws.makeCurrent(rc, w))
+ ; // XXX need to throw exception here
+
+ // Create a result object and run the test:
+ Result* r = new Result();
+ r->config = *p;
+ runOne(*r, w);
+
+ // Save the result locally and in the results file:
+ results.push_back(r);
+ r->put(os);
+ }
+ }
+ 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';
+
+ // Note that we've completed the run:
+ hasRun = true;
+}
+
+void
+BlendFuncTest::compare(Environment& environment) {
+ // Save the environment for use by other member functions:
+ env = &environment;
+
+ // Display the description if needed:
+ logDescription();
+
+ // Read results from previous runs:
+ Input1Stream is1(*this);
+ vector<Result*> oldR(getResults(is1));
+ Input2Stream is2(*this);
+ vector<Result*> 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 (vector<Result*>::const_iterator p = oldR.begin(); p < oldR.end();
+ ++p)
+ oldConfigs.push_back((*p)->config);
+
+ // Compare results:
+ for (vector<Result*>::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 (vector<Result*>::iterator np = newR.begin(); np < newR.end(); ++np)
+ delete *np;
+ for (vector<Result*>::iterator op = oldR.begin(); op < oldR.end(); ++op)
+ delete *op;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncTest::runOne(Result& 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
+ };
+
+ 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) {
+
+ Result::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));
+ w.swap();
+
+ p.rbErr = res.readbackErrorBits;
+ p.blErr = res.blendErrorBits;
+ r.results.push_back(p);
+
+ if (p.rbErr > 1.0 || p.blErr > 1.0) {
+ 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; blending had "
+ << p.blErr << " bits in error.\n";
+ allPassed = false;
+ }
+ }
+
+ if (allPassed)
+ env->log << name << ": PASS "
+ << r.config->conciseDescription() << '\n';
+} // BlendFuncTest::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncTest::compareOne(Result& oldR, Result& newR) {
+ BasicStats readbackStats;
+ BasicStats blendStats;
+
+ vector<Result::PartialResult>::const_iterator np;
+ vector<Result::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->blErr - op->blErr);
+ }
+
+ 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
+
+///////////////////////////////////////////////////////////////////////////////
+// logDescription: Print description on the log file, according to the
+// current verbosity level.
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncTest::logDescription() {
+ if (env->options.verbosity)
+ env->log <<
+"----------------------------------------------------------------------\n"
+ << description << '\n';
+} // BlendFuncTest::logDescription
+
+///////////////////////////////////////////////////////////////////////////////
+// Result I/O functions:
+///////////////////////////////////////////////////////////////////////////////
+void
+BlendFuncTest::Result::put(ostream& s) const {
+ s << config->canonicalDescription() << '\n';
+
+ 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->blErr << '\n';
+} // BlendFuncTest::Result::put
+
+bool
+BlendFuncTest::Result::get(istream& s) {
+ SkipWhitespace(s);
+ string configDesc;
+ if (!getline(s, configDesc))
+ return false;
+ config = new DrawingSurfaceConfig(configDesc);
+
+ int n;
+ s >> n;
+ for (int i = 0; i < n; ++i) {
+ PartialResult p;
+ string src;
+ string dst;
+ s >> src >> dst >> p.rbErr >> p.blErr;
+ p.src = nameToFactor(src);
+ p.dst = nameToFactor(dst);
+ results.push_back(p);
+ }
+
+ return s.good();
+} // BlendFuncTest::Result::get
+
+vector<BlendFuncTest::Result*>
+BlendFuncTest::getResults(istream& s) {
+ vector<Result*> v;
+ while (s.good()) {
+ Result* r = new Result();
+ if (r->get(s))
+ v.push_back(r);
+ else {
+ delete r;
+ break;
+ }
+ }
+
+ return v;
+} // BlendFuncTest::getResults
+
+///////////////////////////////////////////////////////////////////////////////
+// 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/src/glean/tblend.h b/src/glean/tblend.h
new file mode 100644
index 0000000..112643e
--- /dev/null
+++ b/src/glean/tblend.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
+
+
+
+
+// tblend.h: Test blending functions.
+
+#ifndef __tblend_h__
+#define __tblend_h__
+
+#include "test.h"
+
+class DrawingSurfaceConfig; // Forward reference.
+class GLEAN::Window;
+
+namespace GLEAN {
+
+class BlendFuncTest: public Test {
+ public:
+ BlendFuncTest(const char* testName, const char* filter,
+ const char* description);
+ virtual ~BlendFuncTest();
+
+ const char* filter; // Drawing surface configuration filter.
+ const char* description; // Verbose description of test.
+
+ virtual void run(Environment& env); // Run test, save results.
+
+ virtual void compare(Environment& env);
+ // Compare two previous runs.
+
+ // Class for a single test result. All basic tests have a
+ // drawing surface configuration, plus other information
+ // that's specific to the test.
+ class Result: public Test::Result {
+ public:
+ DrawingSurfaceConfig* config;
+ struct PartialResult {
+ GLenum src; // Source blend factor.
+ GLenum dst; // Destination blend factor.
+ float rbErr; // Max readback error, in bits.
+ float blErr; // Max blend error, in bits.
+ };
+ vector<PartialResult> results;
+
+ virtual void put(ostream& s) const;
+ virtual bool get(istream& s);
+
+ Result() { }
+ virtual ~Result() { }
+ };
+
+ vector<Result*> results;
+
+ virtual void runOne(Result& r, GLEAN::Window& w);
+ virtual void compareOne(Result& oldR, Result& newR);
+ virtual vector<Result*> getResults(istream& s);
+
+ void logDescription();
+
+}; // class BlendFuncTest
+
+} // namespace GLEAN
+
+#endif // __tblend_h__
diff --git a/src/glean/tchgperf.cpp b/src/glean/tchgperf.cpp
new file mode 100644
index 0000000..4b5e04c
--- /dev/null
+++ b/src/glean/tchgperf.cpp
@@ -0,0 +1,451 @@
+// 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
+
+
+
+
+// tchgperf.cpp: Some basic tests of attribute-change performance.
+#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 "geomutil.h"
+#include "timer.h"
+#include "rand.h"
+#include "image.h"
+#include "tchgperf.h"
+#include "misc.h"
+
+
+namespace {
+
+const int drawingSize = 128; // must be power-of-2, 128 or greater
+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;
+ }
+ }
+} // noBindDraw
+
+void
+logStats(GLEAN::TexBindPerf::Result& 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 {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor/Destructor:
+///////////////////////////////////////////////////////////////////////////////
+TexBindPerf::TexBindPerf(const char* aName, const char* aFilter,
+ const char* aDescription):
+ Test(aName), filter(aFilter), description(aDescription) {
+} // TexBindPerf::TexBindPerf()
+
+TexBindPerf::~TexBindPerf() {
+} // TexBindPerf::~TexBindPerf
+
+///////////////////////////////////////////////////////////////////////////////
+// run: run tests, save results in a vector and in the results file
+///////////////////////////////////////////////////////////////////////////////
+void
+TexBindPerf::run(Environment& environment) {
+ // Guard against multiple invocations:
+ if (hasRun)
+ return;
+
+ // Set up environment for use by other functions:
+ env = &environment;
+
+ // Document the test in the log, if requested:
+ logDescription();
+
+ // Compute results and make them available to subsequent tests:
+ WindowSystem& ws = env->winSys;
+ try {
+ // Open the results file:
+ OutputStream os(*this);
+
+ // 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, drawingSize + 2, drawingSize + 2);
+ RenderingContext rc(ws, **p);
+ if (!ws.makeCurrent(rc, w))
+ ; // XXX need to throw exception here
+
+ // Create a result object and run the test:
+ Result* r = new Result();
+ r->config = *p;
+ runOne(*r, w);
+
+ // Save the result locally and in the results file:
+ results.push_back(r);
+ r->put(os);
+ }
+ }
+ 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';
+
+ // Note that we've completed the run:
+ hasRun = true;
+}
+
+void
+TexBindPerf::compare(Environment& environment) {
+ // Save the environment for use by other member functions:
+ env = &environment;
+
+ // Display the description if needed:
+ logDescription();
+
+ // Read results from previous runs:
+ Input1Stream is1(*this);
+ vector<Result*> oldR(getResults(is1));
+ Input2Stream is2(*this);
+ vector<Result*> 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 (vector<Result*>::const_iterator p = oldR.begin(); p < oldR.end();
+ ++p)
+ oldConfigs.push_back((*p)->config);
+
+ // Compare results:
+ for (vector<Result*>::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 (vector<Result*>::iterator np = newR.begin(); np < newR.end(); ++np)
+ delete *np;
+ for (vector<Result*>::iterator op = oldR.begin(); op < oldR.end(); ++op)
+ delete *op;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+
+typedef void (*TIME_FUNC) ();
+
+void
+TexBindPerf::runOne(Result& r, Window& w) {
+ Timer time;
+ time.calibrate((TIME_FUNC)glFinish, (TIME_FUNC) glFinish);
+
+ 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);
+
+ vector<float> measurements;
+ for (int i = 0; i < 5; ++i) {
+ env->quiesce();
+ double tBind = time.time((TIME_FUNC)glFinish, (TIME_FUNC) bindDraw, (TIME_FUNC) glFinish);
+ w.swap(); // So the user can see something happening.
+
+ env->quiesce();
+ double tNoBind = time.time((TIME_FUNC)glFinish, (TIME_FUNC)noBindDraw, (TIME_FUNC)glFinish);
+ 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[2];
+ r.lowerBound = measurements[1];
+ r.upperBound = measurements[3];
+
+ env->log << name << ": PASS "
+ << r.config->conciseDescription() << '\n';
+ logStats(r, env);
+} // TexBindPerf::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+TexBindPerf::compareOne(Result& oldR, Result& newR) {
+ if (oldR.lowerBound < newR.bindTime && newR.bindTime < oldR.upperBound
+ && newR.lowerBound < oldR.bindTime && oldR.bindTime < newR.upperBound){
+ if (env->options.verbosity)
+ env->log << name << ": SAME "
+ << newR.config->conciseDescription()
+ << "\n\tEach test time falls within the "
+ "valid measurement range of the\n"
+ "\tother test time.\n";
+ } else {
+ env->log << name << ": DIFF "
+ << newR.config->conciseDescription() << '\n';
+ env->log << '\t'
+ << ((oldR.bindTime < newR.bindTime)?
+ env->options.db1Name: env->options.db2Name)
+ << " appears to have higher performance.\n";
+ }
+ if (env->options.verbosity) {
+ env->log << env->options.db1Name << ':';
+ logStats(oldR, env);
+ env->log << env->options.db2Name << ':';
+ logStats(newR, env);
+ }
+} // TexBindPerf::compareOne
+
+///////////////////////////////////////////////////////////////////////////////
+// logDescription: Print description on the log file, according to the
+// current verbosity level.
+///////////////////////////////////////////////////////////////////////////////
+void
+TexBindPerf::logDescription() {
+ if (env->options.verbosity)
+ env->log <<
+"----------------------------------------------------------------------\n"
+ << description << '\n';
+} // TexBindPerf::logDescription
+
+///////////////////////////////////////////////////////////////////////////////
+// Result I/O functions:
+///////////////////////////////////////////////////////////////////////////////
+void
+TexBindPerf::Result::put(ostream& s) const {
+ s << config->canonicalDescription() << '\n';
+
+ s << bindTime << ' ' << lowerBound << ' ' << upperBound << '\n';
+} // TexBindPerf::Result::put
+
+bool
+TexBindPerf::Result::get(istream& s) {
+ SkipWhitespace(s);
+ string configDesc;
+ if (!getline(s, configDesc))
+ return false;
+ config = new DrawingSurfaceConfig(configDesc);
+
+ s >> bindTime >> lowerBound >> upperBound;
+ return s.good();
+} // TexBindPerf::Result::get
+
+vector<TexBindPerf::Result*>
+TexBindPerf::getResults(istream& s) {
+ vector<Result*> v;
+ while (s.good()) {
+ Result* r = new Result();
+ if (r->get(s))
+ v.push_back(r);
+ else {
+ delete r;
+ break;
+ }
+ }
+
+ return v;
+} // TexBindPerf::getResults
+
+///////////////////////////////////////////////////////////////////////////////
+// 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/src/glean/tchgperf.h b/src/glean/tchgperf.h
new file mode 100644
index 0000000..902ecb0
--- /dev/null
+++ b/src/glean/tchgperf.h
@@ -0,0 +1,87 @@
+// 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
+
+
+
+
+// tchgperf.h: Some basic tests of attribute-change performance.
+
+#ifndef __tchgperf_h__
+#define __tchgperf_h__
+
+#include "test.h"
+
+class DrawingSurfaceConfig; // Forward reference.
+class GLEAN::Window;
+
+namespace GLEAN {
+
+class TexBindPerf: public Test {
+ public:
+ TexBindPerf(const char* testName, const char* filter,
+ const char* description);
+ virtual ~TexBindPerf();
+
+ const char* filter; // Drawing surface configuration filter.
+ const char* description; // Verbose description of test.
+
+ virtual void run(Environment& env); // Run test, save results.
+
+ virtual void compare(Environment& env);
+ // Compare two previous runs.
+
+ // Class for a single test result. All basic tests have a
+ // drawing surface configuration, plus other information
+ // that's specific to the test.
+ class Result: public Test::Result {
+ public:
+ DrawingSurfaceConfig* config;
+ float bindTime;
+ float lowerBound;
+ float upperBound;
+
+ virtual void put(ostream& s) const;
+ virtual bool get(istream& s);
+
+ Result() { }
+ virtual ~Result() { }
+ };
+
+ vector<Result*> results;
+
+ virtual void runOne(Result& r, GLEAN::Window& w);
+ virtual void compareOne(Result& oldR, Result& newR);
+ virtual vector<Result*> getResults(istream& s);
+
+ void logDescription();
+
+}; // class TexBindPerf
+
+} // namespace GLEAN
+
+#endif // __tchgperf_h__
diff --git a/src/glean/test.cpp b/src/glean/test.cpp
new file mode 100644
index 0000000..f9ff8cd
--- /dev/null
+++ b/src/glean/test.cpp
@@ -0,0 +1,124 @@
+// 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
+
+
+
+
+// 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):
+ name(testName) {
+ 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/src/glean/test.h b/src/glean/test.h
new file mode 100644
index 0000000..88ea23d
--- /dev/null
+++ b/src/glean/test.h
@@ -0,0 +1,140 @@
+// 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
+
+
+
+
+// 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).
+
+
+
+#ifndef __test_h__
+#define __test_h__
+
+#include <string>
+#include <vector>
+#include <fstream>
+
+using namespace std;
+
+namespace GLEAN {
+
+class Environment; // Mutually-recursive and forward references.
+class DrawingSurfaceConfig;
+
+class Test {
+ public:
+ Test(const char* testName);
+ 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.
+
+ 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;
+ // Compare two previous runs.
+
+ // 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() { }
+ };
+
+
+ // 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.
+ ofstream* s;
+ public:
+ OutputStream(Test& t);
+ ~OutputStream();
+ operator ofstream& ();
+ };
+ class Input1Stream { // Open db #1 input stream for reading results.
+ ifstream* s;
+ public:
+ Input1Stream(Test& t);
+ ~Input1Stream();
+ operator ifstream& ();
+ };
+ class Input2Stream { // Open db #2 input stream for reading results.
+ ifstream* s;
+ public:
+ 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/src/glean/tgetstr.cpp b/src/glean/tgetstr.cpp
new file mode 100644
index 0000000..e970d1b
--- /dev/null
+++ b/src/glean/tgetstr.cpp
@@ -0,0 +1,344 @@
+// 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
+
+
+
+
+// tgetstr.cpp: implementation of OpenGL glGetString() tests
+#ifdef __UNIX__
+#include <unistd.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <algorithm>
+#include "dsconfig.h"
+#include "dsfilt.h"
+#include "dsurf.h"
+#include "winsys.h"
+#include "environ.h"
+#include "rc.h"
+#include "lex.h"
+#include "glutils.h"
+#include "tgetstr.h"
+#include "misc.h"
+
+namespace GLEAN {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor/Destructor:
+///////////////////////////////////////////////////////////////////////////////
+GetStringTest::GetStringTest(const char* aName, const char* aFilter,
+ const char* aDescription):
+ Test(aName), filter(aFilter), description(aDescription) {
+} // GetStringTest::GetStringTest()
+
+GetStringTest::~GetStringTest() {
+} // GetStringTest::~GetStringTest
+
+///////////////////////////////////////////////////////////////////////////////
+// run: run tests, save results in a vector and in the results file
+///////////////////////////////////////////////////////////////////////////////
+void
+GetStringTest::run(Environment& environment) {
+ // Guard against multiple invocations:
+ if (hasRun)
+ return;
+
+ // Set up environment for use by other functions:
+ env = &environment;
+
+ // Document the test in the log, if requested:
+ logDescription();
+
+ // Compute results and make them available to subsequent tests:
+ WindowSystem& ws = env->winSys;
+ try {
+ // Open the results file:
+ OutputStream os(*this);
+
+ // 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, 258, 258);
+ RenderingContext rc(ws, **p);
+ if (!ws.makeCurrent(rc, w))
+ ; // XXX need to throw exception here
+
+ // Create a result object and run the test:
+ Result* r = new Result();
+ r->config = *p;
+ runOne(*r);
+
+ // Save the result locally and in the results file:
+ results.push_back(r);
+ r->put(os);
+ }
+ }
+ 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';
+
+ // Note that we've completed the run:
+ hasRun = true;
+}
+
+void
+GetStringTest::compare(Environment& environment) {
+ // Save the environment for use by other member functions:
+ env = &environment;
+
+ // Display the description if needed:
+ logDescription();
+
+ // Read results from previous runs:
+ Input1Stream is1(*this);
+ vector<Result*> oldR(getResults(is1));
+ Input2Stream is2(*this);
+ vector<Result*> 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 (vector<Result*>::const_iterator p = oldR.begin(); p < oldR.end();
+ ++p)
+ oldConfigs.push_back((*p)->config);
+
+ // Compare results:
+ for (vector<Result*>::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 (vector<Result*>::iterator np = newR.begin(); np < newR.end(); ++np)
+ delete *np;
+ for (vector<Result*>::iterator op = oldR.begin(); op < oldR.end(); ++op)
+ delete *op;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+GetStringTest::runOne(Result& r) {
+ 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));
+ env->log << name << ": PASS " << r.config->conciseDescription()<<'\n';
+ 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::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+GetStringTest::compareOne(Result& oldR, Result& 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
+
+///////////////////////////////////////////////////////////////////////////////
+// logDescription: Print description on the log file, according to the
+// current verbosity level.
+///////////////////////////////////////////////////////////////////////////////
+void
+GetStringTest::logDescription() {
+ if (env->options.verbosity)
+ env->log <<
+"----------------------------------------------------------------------\n"
+ << description << '\n';
+} // GetStringTest::logDescription
+
+///////////////////////////////////////////////////////////////////////////////
+// Result I/O functions:
+///////////////////////////////////////////////////////////////////////////////
+void
+GetStringTest::Result::put(ostream& s) const {
+ s << config->canonicalDescription() << '\n'
+ << vendor << '\n'
+ << renderer << '\n'
+ << version << '\n'
+ << extensions << '\n';
+} // GetStringTest::Result::put
+
+bool
+GetStringTest::Result::get(istream& s) {
+ SkipWhitespace(s);
+ string configDesc;
+ if (!getline(s, configDesc))
+ return false;
+ config = new DrawingSurfaceConfig(configDesc);
+ getline(s, vendor);
+ getline(s, renderer);
+ getline(s, version);
+ getline(s, extensions);
+ return s.good();
+} // GetStringTest::Result::get
+
+vector<GetStringTest::Result*>
+GetStringTest::getResults(istream& s) {
+ vector<Result*> v;
+ while (s.good()) {
+ Result* r = new Result();
+ if (r->get(s))
+ v.push_back(r);
+ else {
+ delete r;
+ break;
+ }
+ }
+
+ return v;
+} // GetStringTest::getResults
+
+///////////////////////////////////////////////////////////////////////////////
+// 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/src/glean/tgetstr.h b/src/glean/tgetstr.h
new file mode 100644
index 0000000..e611cf9
--- /dev/null
+++ b/src/glean/tgetstr.h
@@ -0,0 +1,87 @@
+// 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
+
+
+
+
+// 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 "test.h"
+
+class DrawingSurfaceConfig; // Forward reference.
+
+namespace GLEAN {
+
+class GetStringTest: public Test {
+ public:
+ GetStringTest(const char* testName, const char* filter,
+ const char* description);
+ virtual ~GetStringTest();
+
+ const char* filter; // Drawing surface configuration filter.
+ const char* description; // Verbose description of test.
+
+ virtual void run(Environment& env); // Run test, save results.
+
+ virtual void compare(Environment& env);
+ // Compare two previous runs.
+
+ class Result: public Test::Result {
+ public:
+ DrawingSurfaceConfig* config;
+ string vendor;
+ string renderer;
+ string version;
+ string extensions;
+
+ virtual void put(ostream& s) const;
+ virtual bool get(istream& s);
+
+ Result() { }
+ virtual ~Result() { }
+ };
+
+ vector<Result*> results;
+
+ virtual void runOne(Result& r);
+ virtual void compareOne(Result& oldR, Result& newR);
+ virtual vector<Result*> getResults(istream& s);
+
+ void logDescription();
+
+}; // class GetStringTest
+
+} // namespace GLEAN
+
+#endif // __tgetstr_h__
diff --git a/src/glean/trgbtris.cpp b/src/glean/trgbtris.cpp
new file mode 100644
index 0000000..142224c
--- /dev/null
+++ b/src/glean/trgbtris.cpp
@@ -0,0 +1,354 @@
+// 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
+
+
+
+
+// trgbtris.cpp: example image-based test to show use of TIFF images
+#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 "geomutil.h"
+#include "rand.h"
+#include "stats.h"
+#include "image.h"
+#include "trgbtris.h"
+#include "misc.h"
+
+namespace {
+
+const int drawingSize = 64; // Don't make this too large!
+ // Uncompressed TIFF images demand a lot of
+ // disk space and network bandwidth.
+
+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 {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor/Destructor:
+///////////////////////////////////////////////////////////////////////////////
+RGBTriStripTest::RGBTriStripTest(const char* aName, const char* aFilter,
+ const char* aDescription):
+ Test(aName), filter(aFilter), description(aDescription) {
+} // RGBTriStripTest::RGBTriStripTest()
+
+RGBTriStripTest::~RGBTriStripTest() {
+} // RGBTriStripTest::~RGBTriStripTest
+
+///////////////////////////////////////////////////////////////////////////////
+// run: run tests, save results in a vector and in the results file
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBTriStripTest::run(Environment& environment) {
+ // Guard against multiple invocations:
+ if (hasRun)
+ return;
+
+ // Set up environment for use by other functions:
+ env = &environment;
+
+ // Document the test in the log, if requested:
+ logDescription();
+
+ // Compute results and make them available to subsequent tests:
+ WindowSystem& ws = env->winSys;
+ try {
+ // Open the results file:
+ OutputStream os(*this);
+
+ // 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, drawingSize + 2, drawingSize + 2);
+ RenderingContext rc(ws, **p);
+ if (!ws.makeCurrent(rc, w))
+ ; // XXX need to throw exception here
+
+ // Create a result object and run the test:
+ Result* r = new Result();
+ r->config = *p;
+ r->imageNumber = 1 + (p - configs.begin());
+ runOne(*r, w);
+
+ // Save the result locally and in the results file:
+ results.push_back(r);
+ r->put(os);
+ }
+ }
+ 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';
+
+ // Note that we've completed the run:
+ hasRun = true;
+}
+
+void
+RGBTriStripTest::compare(Environment& environment) {
+ // Save the environment for use by other member functions:
+ env = &environment;
+
+ // Display the description if needed:
+ logDescription();
+
+ // Read results from previous runs:
+ Input1Stream is1(*this);
+ vector<Result*> oldR(getResults(is1));
+ Input2Stream is2(*this);
+ vector<Result*> 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 (vector<Result*>::const_iterator p = oldR.begin(); p < oldR.end();
+ ++p)
+ oldConfigs.push_back((*p)->config);
+
+ // Compare results:
+ for (vector<Result*>::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 (vector<Result*>::iterator np = newR.begin(); np < newR.end(); ++np)
+ delete *np;
+ for (vector<Result*>::iterator op = oldR.begin(); op < oldR.end(); ++op)
+ delete *op;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// runOne: Run a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBTriStripTest::runOne(Result& r, Window& w) {
+ 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));
+
+ 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::runOne
+
+///////////////////////////////////////////////////////////////////////////////
+// compareOne: Compare results for a single test case
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBTriStripTest::compareOne(Result& oldR, Result& 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
+
+///////////////////////////////////////////////////////////////////////////////
+// logDescription: Print description on the log file, according to the
+// current verbosity level.
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBTriStripTest::logDescription() {
+ if (env->options.verbosity)
+ env->log <<
+"----------------------------------------------------------------------\n"
+ << description << '\n';
+} // RGBTriStripTest::logDescription
+
+///////////////////////////////////////////////////////////////////////////////
+// Result I/O functions:
+///////////////////////////////////////////////////////////////////////////////
+void
+RGBTriStripTest::Result::put(ostream& s) const {
+ s << config->canonicalDescription() << '\n';
+
+ s << imageNumber << '\n';
+} // RGBTriStripTest::Result::put
+
+bool
+RGBTriStripTest::Result::get(istream& s) {
+ SkipWhitespace(s);
+ string configDesc;
+ if (!getline(s, configDesc))
+ return false;
+ config = new DrawingSurfaceConfig(configDesc);
+
+ s >> imageNumber;
+ return s.good();
+} // RGBTriStripTest::Result::get
+
+vector<RGBTriStripTest::Result*>
+RGBTriStripTest::getResults(istream& s) {
+ vector<Result*> v;
+ while (s.good()) {
+ Result* r = new Result();
+ if (r->get(s))
+ v.push_back(r);
+ else {
+ delete r;
+ break;
+ }
+ }
+
+ return v;
+} // RGBTriStripTest::getResults
+
+///////////////////////////////////////////////////////////////////////////////
+// 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/src/glean/trgbtris.h b/src/glean/trgbtris.h
new file mode 100644
index 0000000..d7368d0
--- /dev/null
+++ b/src/glean/trgbtris.h
@@ -0,0 +1,85 @@
+// 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
+
+
+
+
+// trgbtris.h: example image-based test to show use of TIFF images
+
+#ifndef __trgbtris_h__
+#define __trgbtris_h__
+
+#include "test.h"
+
+class DrawingSurfaceConfig; // Forward reference.
+class GLEAN::Window;
+
+namespace GLEAN {
+
+class RGBTriStripTest: public Test {
+ public:
+ RGBTriStripTest(const char* testName, const char* filter,
+ const char* description);
+ virtual ~RGBTriStripTest();
+
+ const char* filter; // Drawing surface configuration filter.
+ const char* description; // Verbose description of test.
+
+ virtual void run(Environment& env); // Run test, save results.
+
+ virtual void compare(Environment& env);
+ // Compare two previous runs.
+
+ // Class for a single test result. All basic tests have a
+ // drawing surface configuration, plus other information
+ // that's specific to the test.
+ class Result: public Test::Result {
+ public:
+ DrawingSurfaceConfig* config;
+ int imageNumber;
+
+ virtual void put(ostream& s) const;
+ virtual bool get(istream& s);
+
+ Result() { }
+ virtual ~Result() { }
+ };
+
+ vector<Result*> results;
+
+ virtual void runOne(Result& r, GLEAN::Window& w);
+ virtual void compareOne(Result& oldR, Result& newR);
+ virtual vector<Result*> getResults(istream& s);
+
+ void logDescription();
+
+}; // class RGBTriStripTest
+
+} // namespace GLEAN
+
+#endif // __trgbtris_h__
diff --git a/src/glean/version.h b/src/glean/version.h
new file mode 100644
index 0000000..5204192
--- /dev/null
+++ b/src/glean/version.h
@@ -0,0 +1,47 @@
+// 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
+
+
+
+
+// GLEAN version information
+
+
+#ifndef __version_h__
+#define __version_h__
+
+#define GLEAN_MAJOR_VERSION 1
+#define GLEAN_MINOR_VERSION 0
+
+namespace GLEAN {
+
+const char* versionString = "glean v1.0 8 November 1999";
+
+} // namespace GLEAN
+
+#endif // __version_h__
diff --git a/src/glean/winsys.cpp b/src/glean/winsys.cpp
new file mode 100644
index 0000000..b9c3cbe
--- /dev/null
+++ b/src/glean/winsys.cpp
@@ -0,0 +1,181 @@
+// 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
+
+
+
+
+// winsys.cpp: implementation of window-system services class
+
+#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) {
+ // 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);
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Destructors
+///////////////////////////////////////////////////////////////////////////////
+#if defined(__X11__)
+WindowSystem::~WindowSystem() {
+ XFree(vip);
+} // WindowSystem:: ~WindowSystem
+
+#elif defined(__WIN__)
+WindowSystem::~WindowSystem() {
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// makeCurrent and friends - binding contexts and drawing surfaces
+///////////////////////////////////////////////////////////////////////////////
+
+bool
+WindowSystem::makeCurrent() {
+# if defined(__X11__)
+# if defined(GLX_VERSION_1_3)
+# error "XXX Need to write GLX 1.3 MakeCurrent code"
+# else
+ return glXMakeCurrent(dpy, None, 0);
+# endif
+# elif defined(__WIN__)
+ return wglMakeCurrent(0,0);
+# endif
+} // WindowSystem::makeCurrent
+
+bool
+WindowSystem::makeCurrent(RenderingContext& r, Window& w) {
+# if defined(__X11__)
+# if defined(GLX_VERSION_1_3)
+# error "XXX Need to write GLX 1.3 MakeCurrent code"
+# else
+ return glXMakeCurrent(dpy, w.xWindow, r.rc);
+# endif
+# elif defined(__WIN__)
+ return wglMakeCurrent(w.get_dc(),r.rc);
+# endif
+} // WindowSystem::makeCurrent
+
+void
+WindowSystem::quiesce() {
+# if defined(__X11__)
+ XSync(dpy, False);
+# elif defined(__WIN__)
+# endif
+} // WindowSystem::quiesce
+
+} // namespace GLEAN
diff --git a/src/glean/winsys.h b/src/glean/winsys.h
new file mode 100644
index 0000000..036954e
--- /dev/null
+++ b/src/glean/winsys.h
@@ -0,0 +1,111 @@
+// 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
+
+
+
+
+// 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__
+
+#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__)
+# endif
+
+}; // class WindowSystem
+
+} // namespace GLEAN
+
+#endif // __winsys_h__
diff --git a/src/glh/Makefile b/src/glh/Makefile
new file mode 100644
index 0000000..78a11f8
--- /dev/null
+++ b/src/glh/Makefile
@@ -0,0 +1,5 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+HTARGET=glwrap.h
+
+include $(GLEAN_ROOT)/make/h.mak
diff --git a/src/glh/glwrap.h b/src/glh/glwrap.h
new file mode 100644
index 0000000..da63336
--- /dev/null
+++ b/src/glh/glwrap.h
@@ -0,0 +1,63 @@
+// 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>
+#elif defined(__X11__)
+# include <GL/glx.h>
+ // glx.h covers Xlib.h and gl.h, among others
+# include <GL/glu.h>
+#else
+# error "Improper window system configuration; must be __WIN__ or __X11__."
+#endif
+
+#endif __glwrap_h__
diff --git a/src/glh/makefile.win b/src/glh/makefile.win
new file mode 100644
index 0000000..3400688
--- /dev/null
+++ b/src/glh/makefile.win
@@ -0,0 +1,12 @@
+.SILENT :
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+ALL :
+ echo Copying Header Files
+ copy .\glwrap.h $(GLEAN_INC_DIR)
+
+CLEAN :
+
+
+
diff --git a/src/libs/Makefile b/src/libs/Makefile
new file mode 100644
index 0000000..58b1c5d
--- /dev/null
+++ b/src/libs/Makefile
@@ -0,0 +1,5 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+DIRS=rand timer stats image lex dsurf
+
+include $(GLEAN_ROOT)/make/null.mak
diff --git a/src/libs/dsurf/Makefile b/src/libs/dsurf/Makefile
new file mode 100644
index 0000000..b4ba475
--- /dev/null
+++ b/src/libs/dsurf/Makefile
@@ -0,0 +1,6 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=libdsurf.a
+HTARGET=dsconfig.h dsfilt.h
+
+include $(GLEAN_ROOT)/make/lib.mak
diff --git a/src/libs/dsurf/dsconfig.cpp b/src/libs/dsurf/dsconfig.cpp
new file mode 100644
index 0000000..81fbaba
--- /dev/null
+++ b/src/libs/dsurf/dsconfig.cpp
@@ -0,0 +1,767 @@
+// 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 <string.h>
+#include <map>
+#include <limits.h>
+
+#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;
+
+ 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.
+
+ canWinSysRender = true;
+ // Only guaranteed in early versions of GLX.
+
+ fast = true;
+ conformant = true;
+# if defined(GLX_EXT_visual_rating)
+ if (haveGLXExtension(dpy, "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, "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)
+{
+ if (!mapsInitialized)
+ initializeMaps();
+} // DrawingSurfaceConfig::DrawingSurfaceConfig
+#error "XXX Need to write drawing surface config code for GLX 1.3"
+#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;
+}
+
+#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__)
+# if defined(GLX_VERSION_1_3)
+ s << ", id " << fbcID;
+# else
+ s << ", id " << visID;
+# 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/src/libs/dsurf/dsconfig.h b/src/libs/dsurf/dsconfig.h
new file mode 100644
index 0000000..bc63b74
--- /dev/null
+++ b/src/libs/dsurf/dsconfig.h
@@ -0,0 +1,203 @@
+// 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);
+# 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;
+# 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/src/libs/dsurf/dsfilt.cpp b/src/libs/dsurf/dsfilt.cpp
new file mode 100644
index 0000000..07b6610
--- /dev/null
+++ b/src/libs/dsurf/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);
+# if defined(GLX_VERSION_1_3)
+ EmitKey(VAR_FBCID);
+# else
+ EmitKey(VAR_ID);
+# 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/src/libs/dsurf/dsfilt.h b/src/libs/dsurf/dsfilt.h
new file mode 100644
index 0000000..89c6d58
--- /dev/null
+++ b/src/libs/dsurf/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/src/libs/dsurf/makefile.win b/src/libs/dsurf/makefile.win
new file mode 100644
index 0000000..8e301ef
--- /dev/null
+++ b/src/libs/dsurf/makefile.win
@@ -0,0 +1,131 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "makefile.win" CFG=release
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+FTARGET=dsurf
+TARGET=$(FTARGET).lib
+
+LIB32_OBJS= \
+ "$(INTDIR)\dsconfig.obj" \
+ "$(INTDIR)\dsfilt.obj"
+
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\$(FTARGET).pch"
+ -@deltree /Y $(INTDIR)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+ALL : $(DS_POSTBUILD_DEP)
+
+$(DS_POSTBUILD_DEP) : "$(GLEAN_LIB_DIR)\$(TARGET)"
+ echo Copying Header Files
+ copy .\dsconfig.h $(GLEAN_INC_DIR)
+ copy .\dsfilt.h $(GLEAN_INC_DIR)
+
+
+
+
diff --git a/src/libs/image/Makefile b/src/libs/image/Makefile
new file mode 100644
index 0000000..1f7cb0c
--- /dev/null
+++ b/src/libs/image/Makefile
@@ -0,0 +1,6 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=libimage.a
+HTARGET=image.h
+
+include $(GLEAN_ROOT)/make/lib.mak
diff --git a/src/libs/image/gl.cpp b/src/libs/image/gl.cpp
new file mode 100644
index 0000000..89ca4ae
--- /dev/null
+++ b/src/libs/image/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/src/libs/image/image.h b/src/libs/image/image.h
new file mode 100644
index 0000000..5217f75
--- /dev/null
+++ b/src/libs/image/image.h
@@ -0,0 +1,246 @@
+// 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) { return _invalid & bit; }
+ inline bool valid(int bit) { 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() // Image width, in pixels
+ { return _width; }
+ inline void width(GLsizei w)
+ { _width = w; invalidate(vbRowSizeInBytes); }
+
+ inline GLsizei height() // Image height, in pixels.
+ { return _height; }
+ inline void height(GLsizei h)
+ { _height = h; }
+
+ inline GLenum format() // 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() // 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; }
+ void pixels(char* p);
+
+ inline GLsizei alignment() // 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);
+
+ // 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/src/libs/image/makefile.win b/src/libs/image/makefile.win
new file mode 100644
index 0000000..b49e87e
--- /dev/null
+++ b/src/libs/image/makefile.win
@@ -0,0 +1,135 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "makefile.win" CFG=release
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+FTARGET=image
+TARGET=$(FTARGET).lib
+
+LIB32_OBJS= \
+ "$(INTDIR)\gl.obj" \
+ "$(INTDIR)\misc.obj" \
+ "$(INTDIR)\pack.obj" \
+ "$(INTDIR)\rdtiff.obj" \
+ "$(INTDIR)\reg.obj" \
+ "$(INTDIR)\unpack.obj" \
+ "$(INTDIR)\wrtiff.obj" \
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\$(FTARGET).pch"
+ -@deltree /Y $(INTDIR)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+ALL : $(DS_POSTBUILD_DEP)
+
+$(DS_POSTBUILD_DEP) : "$(GLEAN_LIB_DIR)\$(TARGET)"
+ echo Copying Header Files
+ copy .\image.h $(GLEAN_INC_DIR)
+
+
+
+
+
diff --git a/src/libs/image/misc.cpp b/src/libs/image/misc.cpp
new file mode 100644
index 0000000..adfdc22
--- /dev/null
+++ b/src/libs/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/src/libs/image/pack.cpp b/src/libs/image/pack.cpp
new file mode 100644
index 0000000..11617ef
--- /dev/null
+++ b/src/libs/image/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/src/libs/image/rdtiff.cpp b/src/libs/image/rdtiff.cpp
new file mode 100644
index 0000000..5e5068f
--- /dev/null
+++ b/src/libs/image/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/src/libs/image/reg.cpp b/src/libs/image/reg.cpp
new file mode 100644
index 0000000..da065fe
--- /dev/null
+++ b/src/libs/image/reg.cpp
@@ -0,0 +1,178 @@
+// 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"
+
+#ifdef __WIN__
+#include <cmath> // for fabs
+#endif
+
+
+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/src/libs/image/unpack.cpp b/src/libs/image/unpack.cpp
new file mode 100644
index 0000000..5c0c9a6
--- /dev/null
+++ b/src/libs/image/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/src/libs/image/wrtiff.cpp b/src/libs/image/wrtiff.cpp
new file mode 100644
index 0000000..f4b95ba
--- /dev/null
+++ b/src/libs/image/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/src/libs/lex/Makefile b/src/libs/lex/Makefile
new file mode 100644
index 0000000..0a885ae
--- /dev/null
+++ b/src/libs/lex/Makefile
@@ -0,0 +1,6 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=liblex.a
+HTARGET=lex.h
+
+include $(GLEAN_ROOT)/make/lib.mak
diff --git a/src/libs/lex/lex.cpp b/src/libs/lex/lex.cpp
new file mode 100644
index 0000000..84891f1
--- /dev/null
+++ b/src/libs/lex/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/src/libs/lex/lex.h b/src/libs/lex/lex.h
new file mode 100644
index 0000000..87e24df
--- /dev/null
+++ b/src/libs/lex/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/src/libs/lex/makefile.win b/src/libs/lex/makefile.win
new file mode 100644
index 0000000..09183c3
--- /dev/null
+++ b/src/libs/lex/makefile.win
@@ -0,0 +1,129 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "makefile.win" CFG=release
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+FTARGET=lex
+TARGET=$(FTARGET).lib
+
+LIB32_OBJS= \
+ "$(INTDIR)\lex.obj"
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\$(FTARGET).pch"
+ -@deltree /Y $(INTDIR)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+ALL : $(DS_POSTBUILD_DEP)
+
+$(DS_POSTBUILD_DEP) : "$(GLEAN_LIB_DIR)\$(TARGET)"
+ echo Copying Header Files
+ copy .\lex.h $(GLEAN_INC_DIR)
+
+
+
+
+
diff --git a/src/libs/makefile.win b/src/libs/makefile.win
new file mode 100644
index 0000000..8fa0dfd
--- /dev/null
+++ b/src/libs/makefile.win
@@ -0,0 +1,78 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "makefile.win" CFG=release
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+all :
+ cd rand
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd lex
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd stats
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd dsurf
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd image
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd timer
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+clean :
+ cd dsurf
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd image
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd lex
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd rand
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd stats
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd timer
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+
+
+
+
+
+
+
diff --git a/src/libs/rand/Makefile b/src/libs/rand/Makefile
new file mode 100644
index 0000000..25fa796
--- /dev/null
+++ b/src/libs/rand/Makefile
@@ -0,0 +1,5 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+HTARGET=rand.h
+
+include $(GLEAN_ROOT)/make/h.mak
diff --git a/src/libs/rand/makefile.win b/src/libs/rand/makefile.win
new file mode 100644
index 0000000..2b949c7
--- /dev/null
+++ b/src/libs/rand/makefile.win
@@ -0,0 +1,12 @@
+.SILENT :
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+ALL :
+ echo Copying Header Files
+ copy .\rand.h $(GLEAN_INC_DIR)
+
+CLEAN :
+
+
+
diff --git a/src/libs/rand/rand.h b/src/libs/rand/rand.h
new file mode 100644
index 0000000..b47684d
--- /dev/null
+++ b/src/libs/rand/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/src/libs/stats/Makefile b/src/libs/stats/Makefile
new file mode 100644
index 0000000..5b0d01d
--- /dev/null
+++ b/src/libs/stats/Makefile
@@ -0,0 +1,6 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=libstats.a
+HTARGET=stats.h
+
+include $(GLEAN_ROOT)/make/lib.mak
diff --git a/src/libs/stats/basic.cpp b/src/libs/stats/basic.cpp
new file mode 100644
index 0000000..af317bd
--- /dev/null
+++ b/src/libs/stats/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/src/libs/stats/makefile.win b/src/libs/stats/makefile.win
new file mode 100644
index 0000000..6e19e49
--- /dev/null
+++ b/src/libs/stats/makefile.win
@@ -0,0 +1,129 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "makefile.win" CFG=release
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+FTARGET=stats
+TARGET=$(FTARGET).lib
+
+LIB32_OBJS= \
+ "$(INTDIR)\basic.obj"
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\$(FTARGET).pch"
+ -@deltree /Y $(INTDIR)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+ALL : $(DS_POSTBUILD_DEP)
+
+$(DS_POSTBUILD_DEP) : "$(GLEAN_LIB_DIR)\$(TARGET)"
+ echo Copying Header Files
+ copy .\stats.h $(GLEAN_INC_DIR)
+
+
+
+
+
diff --git a/src/libs/stats/stats.h b/src/libs/stats/stats.h
new file mode 100644
index 0000000..e2f6d30
--- /dev/null
+++ b/src/libs/stats/stats.h
@@ -0,0 +1,87 @@
+// 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>
+
+#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 (std::vector<T>::const_iterator p = v.begin(); p < v.end(); ++p)
+ sample(*p);
+ }
+}; // class BasicStats
+
+} // namespace GLEAN
+
+#endif // __stats_h__
diff --git a/src/libs/timer/Makefile b/src/libs/timer/Makefile
new file mode 100644
index 0000000..dbd923e
--- /dev/null
+++ b/src/libs/timer/Makefile
@@ -0,0 +1,6 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=libtimer.a
+HTARGET=timer.h
+
+include $(GLEAN_ROOT)/make/lib.mak
diff --git a/src/libs/timer/makefile.win b/src/libs/timer/makefile.win
new file mode 100644
index 0000000..60c053f
--- /dev/null
+++ b/src/libs/timer/makefile.win
@@ -0,0 +1,129 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "makefile.win" CFG=release
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+FTARGET=timer
+TARGET=$(FTARGET).lib
+
+LIB32_OBJS= \
+ "$(INTDIR)\timer.obj"
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_LIB_DIR)\$(TARGET)"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\$(FTARGET).pch"
+ -@deltree /Y $(INTDIR)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(GLEAN_LIB_DIR)\$(TARGET)"
+
+"$(GLEAN_LIB_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+!ENDIF
+
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+ALL : $(DS_POSTBUILD_DEP)
+
+$(DS_POSTBUILD_DEP) : "$(GLEAN_LIB_DIR)\$(TARGET)"
+ echo Copying Header Files
+ copy .\timer.h $(GLEAN_INC_DIR)
+
+
+
+
+
diff --git a/src/libs/timer/timer.cpp b/src/libs/timer/timer.cpp
new file mode 100644
index 0000000..d8cff61
--- /dev/null
+++ b/src/libs/timer/timer.cpp
@@ -0,0 +1,213 @@
+// 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
+
+
+
+
+// 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.
+
+#include "timer.h"
+
+#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(void (*initialize)(), void (*finalize)()) {
+ double runTime = chooseRunTime();
+
+ if (initialize)
+ (*initialize)();
+
+ long reps = 0;
+ double current;
+ double start = waitForTick();
+ do {
+ if (finalize)
+ (*finalize)();
+ ++reps;
+ } while ((current = getClock()) < start + runTime);
+
+ overhead = (current - start) / (double) reps;
+} // 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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// 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
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// 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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// time: measure time (in seconds) to perform caller's operation
+///////////////////////////////////////////////////////////////////////////////
+double
+Timer::time(
+ void (*initialize)(),
+ void (*operation)(),
+ void (*finalize)()) {
+
+ if (!operation)
+ return 0.0;
+
+ // 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 (;;) {
+ if (initialize)
+ (*initialize)();
+
+ start = waitForTick();
+
+ for (long i = reps; i > 0; --i)
+ (*operation)();
+
+ if (finalize)
+ (*finalize)();
+
+ 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
+
+} // namespace GLEAN
diff --git a/src/libs/timer/timer.h b/src/libs/timer/timer.h
new file mode 100644
index 0000000..cc7e12a
--- /dev/null
+++ b/src/libs/timer/timer.h
@@ -0,0 +1,71 @@
+// 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
+
+
+
+
+// timer.h: Simple benchmark timing utilities
+
+// 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.
+
+ double chooseRunTime(); // Select a runtime that will reduce random
+ // timing error to an acceptable level.
+
+ public:
+ double getClock(); // Get high resolution wall-clock time, in secs.
+
+ double waitForTick(); // Wait for next clock tick, and return time.
+
+ void calibrate( // Determine measurement overhead.
+ void (*initialize)(),
+ void (*finalize)());
+
+ double time( // Measure rate for a given operation.
+ void (*initialize)(),
+ void (*operation)(),
+ void (*finalize)());
+
+
+ Timer() {overhead = 0.0;}
+}; // class Timer
+
+} // namespace GLEAN
+
+#endif // __timer_h__
diff --git a/src/makefile.win b/src/makefile.win
new file mode 100644
index 0000000..20e2ca2
--- /dev/null
+++ b/src/makefile.win
@@ -0,0 +1,71 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "makefile.win" CFG=release
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+all :
+ if not exist "$(GLEAN_BIN_DIR)/$(NULL)" mkdir "$(GLEAN_BIN_DIR)"
+ if not exist "$(GLEAN_LIB_DIR)/$(NULL)" mkdir "$(GLEAN_LIB_DIR)"
+ if not exist "$(GLEAN_INC_DIR)/$(NULL)" mkdir "$(GLEAN_INC_DIR)"
+
+ cd glh
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd libs
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd tools
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd glean
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+clean :
+ cd glh
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd libs
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd tools
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd glean
+ $(MAKE) /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+
+
+
+
+
+
diff --git a/src/tools/Makefile b/src/tools/Makefile
new file mode 100644
index 0000000..7d8cc0a
--- /dev/null
+++ b/src/tools/Makefile
@@ -0,0 +1,5 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+DIRS=showtiff difftiff showvis
+
+include $(GLEAN_ROOT)/make/null.mak
diff --git a/src/tools/difftiff/Makefile b/src/tools/difftiff/Makefile
new file mode 100644
index 0000000..29d17c9
--- /dev/null
+++ b/src/tools/difftiff/Makefile
@@ -0,0 +1,6 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=difftiff
+LIB=-limage -ltiff -lglut -lGLU -lGL -lXmu -lXext -lXi -lX11
+
+include $(GLEAN_ROOT)/make/app.mak
diff --git a/src/tools/difftiff/main.cpp b/src/tools/difftiff/main.cpp
new file mode 100644
index 0000000..a5c1e53
--- /dev/null
+++ b/src/tools/difftiff/main.cpp
@@ -0,0 +1,401 @@
+// 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 <stdlib.h>
+#include <iostream>
+#include <GL/glut.h>
+#include <cmath> // for fabs
+#include "image.h"
+
+using namespace std;
+
+
+enum {
+ MENU_IMAGE1,
+ MENU_IMAGE2,
+ MENU_DIFF,
+ MENU_DIFF_ON_1,
+ MENU_DIFF_ON_2,
+ MENU_QUIT
+};
+
+enum {
+ SHOW_IMAGE1,
+ SHOW_IMAGE2,
+ SHOW_DIFF,
+ SHOW_DIFF_ON_1,
+ SHOW_DIFF_ON_2
+} Mode = SHOW_DIFF_ON_1;
+
+enum {
+ DIFF_COLOR_MENU_WHITE,
+ DIFF_COLOR_MENU_BLACK,
+ DIFF_COLOR_MENU_RED,
+ DIFF_COLOR_MENU_GREEN,
+ DIFF_COLOR_MENU_BLUE,
+ DIFF_COLOR_MENU_YELLOW,
+ DIFF_COLOR_MENU_MAGENTA,
+ DIFF_COLOR_MENU_CYAN
+};
+
+void ComputeDifference();
+void DiffColorMenu(int item);
+void Draw();
+void Keypress(unsigned char key, int x, int y);
+void Menu(int item);
+void Reshape(int width, int height);
+void ScreenOrthoView(int w, int h);
+void ThreshMenu(int item);
+
+
+char* ApplicationName;
+int WindowHeight;
+int WindowWidth;
+GLEAN::Image Image1;
+GLEAN::Image Image2;
+GLEAN::Image Diff;
+double Threshold = 0.0 / 256.0;
+unsigned char DiffColor[] = {255, 0, 255, 255};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// ComputeDifference - generate the difference image
+///////////////////////////////////////////////////////////////////////////////
+void
+ComputeDifference() {
+ double* rgba1 = new double[4 * Image1.width()];
+ char* row1 = Image1.pixels();
+ double* rgba2 = new double[4 * Image2.width()];
+ char* row2 = Image2.pixels();
+ unsigned char* rowD = reinterpret_cast<unsigned char*>(Diff.pixels());
+
+ for (GLsizei i = 0; i < Diff.height(); ++i) {
+ Image1.unpack(Image1.width(), rgba1, row1);
+ Image2.unpack(Image2.width(), rgba2, row2);
+
+ double* p1 = rgba1;
+ double* p2 = rgba2;
+ unsigned char* pD = rowD;
+
+ for (GLsizei j = 0; j < Diff.width(); ++j) {
+ if (fabs(p1[0] - p2[0]) > Threshold
+ || fabs(p1[1] - p2[1]) > Threshold
+ || fabs(p1[2] - p2[2]) > Threshold
+ || fabs(p1[3] - p2[3]) > Threshold) {
+ pD[0] = DiffColor[0];
+ pD[1] = DiffColor[1];
+ pD[2] = DiffColor[2];
+ pD[3] = DiffColor[3];
+ }
+ else
+ pD[0] = pD[1] = pD[2] = pD[3] = 0;
+
+ p1 += 4;
+ p2 += 4;
+ pD += 4;
+ }
+
+ row1 += Image1.rowSizeInBytes();
+ row2 += Image2.rowSizeInBytes();
+ rowD += Diff.rowSizeInBytes();
+ }
+
+ delete[] rgba1;
+ delete[] rgba2;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DiffColorMenu - handle difference-color menu items
+///////////////////////////////////////////////////////////////////////////////
+void
+DiffColorMenu(int item) {
+ unsigned char c[3];
+
+ switch (item) {
+ case DIFF_COLOR_MENU_WHITE:
+ c[0] = c[1] = c[2] = 255;
+ break;
+ case DIFF_COLOR_MENU_BLACK:
+ c[0] = c[1] = c[2] = 0;
+ break;
+ case DIFF_COLOR_MENU_RED:
+ c[0] = 255;
+ c[1] = c[2] = 0;
+ break;
+ case DIFF_COLOR_MENU_GREEN:
+ c[0] = c[2] = 0;
+ c[1] = 255;
+ break;
+ case DIFF_COLOR_MENU_BLUE:
+ c[0] = c[1] = 0;
+ c[2] = 255;
+ break;
+ case DIFF_COLOR_MENU_YELLOW:
+ c[0] = c[1] = 255;
+ c[2] = 0;
+ break;
+ case DIFF_COLOR_MENU_MAGENTA:
+ c[0] = c[2] = 255;
+ c[1] = 0;
+ break;
+ case DIFF_COLOR_MENU_CYAN:
+ c[0] = 0;
+ c[1] = c[2] = 255;
+ break;
+ }
+
+ if (c[0]!=DiffColor[0] || c[1]!=DiffColor[1] || c[2]!=DiffColor[2]) {
+ DiffColor[0] = c[0];
+ DiffColor[1] = c[1];
+ DiffColor[2] = c[2];
+ ComputeDifference();
+ glutPostRedisplay();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Draw - redraw the scene
+///////////////////////////////////////////////////////////////////////////////
+void
+Draw() {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glRasterPos2f(1, 1);
+ switch (Mode) {
+ case SHOW_IMAGE1:
+ Image1.draw();
+ break;
+ case SHOW_IMAGE2:
+ Image2.draw();
+ break;
+ case SHOW_DIFF:
+ Diff.draw();
+ break;
+ case SHOW_DIFF_ON_1:
+ Image1.draw();
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ Diff.draw();
+ glDisable(GL_BLEND);
+ break;
+ case SHOW_DIFF_ON_2:
+ Image2.draw();
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ Diff.draw();
+ glDisable(GL_BLEND);
+ break;
+ }
+ glutSwapBuffers();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Keypress - handle events from the keyboard
+///////////////////////////////////////////////////////////////////////////////
+void
+Keypress(unsigned char key, int x, int y) {
+ static_cast<void>(x); static_cast<void>(y);
+ switch (key) {
+ case 0x1b /*ESC*/:
+ case 'q':
+ case 'Q':
+ exit(0);
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// main - initialization and callback registration
+///////////////////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[]) {
+ ApplicationName = argv[0];
+
+ if (argc != 3) {
+ cerr << "usage: " << ApplicationName
+ << " tiff-file1 tiff-file2\n";
+ exit(1);
+ }
+
+ try {
+ Image1.readTIFF(argv[1]);
+ }
+ catch (GLEAN::Image::Error) {
+ cerr << "can't open or handle " << argv[1] << "\n";
+ exit(2);
+ }
+
+ try {
+ Image2.readTIFF(argv[2]);
+ }
+ catch (GLEAN::Image::Error) {
+ cerr << "can't open or handle " << argv[2] << "\n";
+ exit(3);
+ }
+
+ if (Image1.width() != Image2.width()
+ || Image1.height() != Image2.height()) {
+ cerr << "image dimensions don't match\n";
+ exit(4);
+ }
+
+ Diff.width(Image1.width());
+ Diff.height(Image1.height());
+ Diff.format(GL_RGBA);
+ Diff.type(GL_UNSIGNED_BYTE);
+ Diff.alignment(1);
+ Diff.reserve();
+ ComputeDifference();
+
+ glutInitWindowSize(Image1.width() + 2, Image1.height() + 2);
+ glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);
+ glutInit(&argc, argv);
+
+ glutCreateWindow("difftiff");
+
+ int diffColorMenu = glutCreateMenu(DiffColorMenu);
+ glutAddMenuEntry("white", DIFF_COLOR_MENU_WHITE);
+ glutAddMenuEntry("black", DIFF_COLOR_MENU_BLACK);
+ glutAddMenuEntry("red", DIFF_COLOR_MENU_RED);
+ glutAddMenuEntry("green", DIFF_COLOR_MENU_GREEN);
+ glutAddMenuEntry("blue", DIFF_COLOR_MENU_BLUE);
+ glutAddMenuEntry("yellow", DIFF_COLOR_MENU_YELLOW);
+ glutAddMenuEntry("magenta", DIFF_COLOR_MENU_MAGENTA);
+ glutAddMenuEntry("cyan", DIFF_COLOR_MENU_CYAN);
+
+ int threshMenu = glutCreateMenu(ThreshMenu);
+ glutAddMenuEntry("1/2", 2);
+ glutAddMenuEntry("1/4", 4);
+ glutAddMenuEntry("1/8", 8);
+ glutAddMenuEntry("1/16", 16);
+ glutAddMenuEntry("1/32", 32);
+ glutAddMenuEntry("1/64", 64);
+ glutAddMenuEntry("1/128", 128);
+ glutAddMenuEntry("1/256", 256);
+ glutAddMenuEntry("0", 0);
+
+ glutCreateMenu(Menu);
+ glutAddMenuEntry("Image 1", MENU_IMAGE1);
+ glutAddMenuEntry("Image 2", MENU_IMAGE2);
+ glutAddMenuEntry("Difference", MENU_DIFF);
+ glutAddMenuEntry("Difference + Image 1", MENU_DIFF_ON_1);
+ glutAddMenuEntry("Difference + Image 2", MENU_DIFF_ON_2);
+ glutAddSubMenu("Threshold", threshMenu);
+ glutAddSubMenu("Difference Highlight Color", diffColorMenu);
+ glutAddMenuEntry("Quit", MENU_QUIT);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+ glutDisplayFunc(Draw);
+ glutKeyboardFunc(Keypress);
+ glutReshapeFunc(Reshape);
+
+ glutMainLoop();
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Menu - handle invocations of menu commands
+///////////////////////////////////////////////////////////////////////////////
+void
+Menu(int item) {
+ switch (item) {
+ case MENU_IMAGE1:
+ Mode = SHOW_IMAGE1;
+ glutPostRedisplay();
+ break;
+ case MENU_IMAGE2:
+ Mode = SHOW_IMAGE2;
+ glutPostRedisplay();
+ break;
+ case MENU_DIFF:
+ Mode = SHOW_DIFF;
+ glutPostRedisplay();
+ break;
+ case MENU_DIFF_ON_1:
+ Mode = SHOW_DIFF_ON_1;
+ glutPostRedisplay();
+ break;
+ case MENU_DIFF_ON_2:
+ Mode = SHOW_DIFF_ON_2;
+ glutPostRedisplay();
+ break;
+ case MENU_QUIT:
+ exit(EXIT_SUCCESS);
+ break;
+ default:
+ cerr << "Internal error; bogus menu item\n";
+ exit(EXIT_FAILURE);
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Reshape - handle window reshape requests
+///////////////////////////////////////////////////////////////////////////////
+void
+Reshape(int width, int height) {
+ WindowWidth = width;
+ WindowHeight = height;
+ glViewport(0, 0, width, height);
+ ScreenOrthoView(width, height);
+ glutPostRedisplay();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ScreenOrthoView - simple parallel view that matches screen pixel coords
+// (using the OpenGL convention for origin at lower left)
+///////////////////////////////////////////////////////////////////////////////
+void
+ScreenOrthoView(int w, int h) {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0,w, 0,h, -1,1);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.375, 0.375, 0.0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ThreshMenu - handle threshold submenu items
+///////////////////////////////////////////////////////////////////////////////
+void
+ThreshMenu(int item) {
+ double newThreshold;
+ if (item == 0)
+ newThreshold = 0.0;
+ else
+ newThreshold = 1.0 / static_cast<double>(item);
+ if (newThreshold != Threshold) {
+ Threshold = newThreshold;
+ ComputeDifference();
+ glutPostRedisplay();
+ }
+}
diff --git a/src/tools/difftiff/makefile.win b/src/tools/difftiff/makefile.win
new file mode 100644
index 0000000..f99a19a
--- /dev/null
+++ b/src/tools/difftiff/makefile.win
@@ -0,0 +1,118 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+#!MESSAGE No configuration specified. Defaulting to release build.
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f makefile.win CFG="release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+LINK32_OBJS= "$(INTDIR)\main.obj"
+
+LIBS=image.lib libtiff.lib opengl32.lib glu32.lib glut32.lib kernel32.lib user32.lib gdi32.lib
+
+FTARGET=difftiff
+TARGET=$(FTARGET).exe
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_BIN_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /Y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=$(LIBS) /nologo /subsystem:console /machine:I386 /include:"__imp__glGetString@4" /out:"$(GLEAN_BIN_DIR)\$(TARGET)" /nodefaultlib:libcd.lib
+
+"$(GLEAN_BIN_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS) $(LIB_DIRS)
+
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_BIN_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(OUTDIR)\$(FTARGET).pdb"
+ -@erase "$(GLEAN_BIN_DIR)\$(FTARGET).ilk"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /Y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=$(LIBS) /nologo /subsystem:console /incremental:yes /pdb:"$(OUTDIR)\$(FTARGET).pdb" /debug /machine:I386 /include:"__imp__glGetString@4" /out:"$(GLEAN_BIN_DIR)\$(TARGET)" /pdbtype:sept $(LIB_DIRS)
+
+"$(GLEAN_BIN_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)
+
+!ENDIF
+
+
diff --git a/src/tools/makefile.win b/src/tools/makefile.win
new file mode 100644
index 0000000..d33e8de
--- /dev/null
+++ b/src/tools/makefile.win
@@ -0,0 +1,54 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "makefile.win" CFG=release
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+all :
+ cd difftiff
+ nmake /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd showtiff
+ nmake /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+ cd showvis
+ nmake /nologo /f makefile.win CFG=$(CFG)
+ cd ..
+
+clean :
+ cd difftiff
+ nmake /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd showtiff
+ nmake /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+ cd showvis
+ nmake /nologo /f makefile.win CFG=$(CFG) clean
+ cd ..
+
+
+
+
+
+
+
+
diff --git a/src/tools/showtiff/Makefile b/src/tools/showtiff/Makefile
new file mode 100644
index 0000000..44d189d
--- /dev/null
+++ b/src/tools/showtiff/Makefile
@@ -0,0 +1,6 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=showtiff
+LIB=-limage -ltiff -lglut -lGLU -lGL -lXmu -lXext -lXi -lX11
+
+include $(GLEAN_ROOT)/make/app.mak
diff --git a/src/tools/showtiff/main.cpp b/src/tools/showtiff/main.cpp
new file mode 100644
index 0000000..fe3cbb6
--- /dev/null
+++ b/src/tools/showtiff/main.cpp
@@ -0,0 +1,163 @@
+// 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 <stdlib.h>
+#include <iostream>
+#include <GL/glut.h>
+#include "image.h"
+
+using namespace std;
+
+#define MENU_QUIT 1
+
+void Draw(void);
+void Keypress(unsigned char key, int x, int y);
+void Menu(int item);
+void Reshape(int width, int height);
+void ScreenOrthoView(int w, int h);
+
+
+char* ApplicationName;
+int WindowHeight;
+int WindowWidth;
+GLEAN::Image Image;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Draw - redraw the scene
+///////////////////////////////////////////////////////////////////////////////
+void
+Draw(void) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glRasterPos2f(1, 1);
+ Image.draw();
+ glutSwapBuffers();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Keypress - handle events from the keyboard
+///////////////////////////////////////////////////////////////////////////////
+void
+Keypress(unsigned char key, int x, int y) {
+ static_cast<void>(x); static_cast<void>(y);
+ switch (key) {
+ case 0x1b /*ESC*/:
+ case 'q':
+ case 'Q':
+ exit(0);
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// main - initialization and callback registration
+///////////////////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[]) {
+ ApplicationName = argv[0];
+
+ if (argc != 2) {
+ cerr << "usage: " << ApplicationName << " tiff-file\n";
+ exit(1);
+ }
+
+ try {
+ Image.readTIFF(argv[1]);
+ }
+ catch (GLEAN::Image::CantOpen) {
+ cerr << "can't open " << argv[1] << "\n";
+ exit(2);
+ }
+ catch (GLEAN::Image::Error) {
+ cerr << "can't handle " << argv[1] << "\n";
+ exit(2);
+ }
+
+ glutInitWindowSize(Image.width() + 2, Image.height() + 2);
+ glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);
+ glutInit(&argc, argv);
+
+ glutCreateWindow("showtiff");
+
+ glutCreateMenu(Menu);
+ glutAddMenuEntry("Quit", MENU_QUIT);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+ glutDisplayFunc(Draw);
+ glutKeyboardFunc(Keypress);
+ glutReshapeFunc(Reshape);
+
+ glutMainLoop();
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Menu - handle invocations of menu commands
+///////////////////////////////////////////////////////////////////////////////
+void
+Menu(int item) {
+ switch (item) {
+ case MENU_QUIT:
+ exit(EXIT_SUCCESS);
+ break;
+ default:
+ cerr << "Internal error; bogus menu item\n";
+ exit(EXIT_FAILURE);
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Reshape - handle window reshape requests
+///////////////////////////////////////////////////////////////////////////////
+void
+Reshape(int width, int height) {
+ WindowWidth = width;
+ WindowHeight = height;
+ glViewport(0, 0, width, height);
+ ScreenOrthoView(width, height);
+ glutPostRedisplay();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ScreenOrthoView - simple parallel view that matches screen pixel coords
+// (using the OpenGL convention for origin at lower left)
+///////////////////////////////////////////////////////////////////////////////
+void
+ScreenOrthoView(int w, int h) {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0,w, 0,h, -1,1);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.375, 0.375, 0.0);
+}
diff --git a/src/tools/showtiff/makefile.win b/src/tools/showtiff/makefile.win
new file mode 100644
index 0000000..3e84c2c
--- /dev/null
+++ b/src/tools/showtiff/makefile.win
@@ -0,0 +1,118 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+#!MESSAGE No configuration specified. Defaulting to release build.
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f makefile.win CFG="release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+LINK32_OBJS= "$(INTDIR)\main.obj"
+
+LIBS=image.lib libtiff.lib opengl32.lib glu32.lib glut32.lib kernel32.lib user32.lib gdi32.lib
+
+FTARGET=showtiff
+TARGET=$(FTARGET).exe
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_BIN_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /Y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=$(LIBS) /nologo /subsystem:console /machine:I386 /include:"__imp__glGetString@4" /out:"$(GLEAN_BIN_DIR)\$(TARGET)" /nodefaultlib:libcd.lib
+
+"$(GLEAN_BIN_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS) $(LIB_DIRS)
+
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_BIN_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(OUTDIR)\$(FTARGET).pdb"
+ -@erase "$(GLEAN_BIN_DIR)\$(FTARGET).ilk"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /Y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=$(LIBS) /nologo /subsystem:console /incremental:yes /pdb:"$(OUTDIR)\$(FTARGET).pdb" /debug /machine:I386 /include:"__imp__glGetString@4" /out:"$(GLEAN_BIN_DIR)\$(TARGET)" /pdbtype:sept $(LIB_DIRS)
+
+"$(GLEAN_BIN_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)
+
+!ENDIF
+
+
diff --git a/src/tools/showvis/Makefile b/src/tools/showvis/Makefile
new file mode 100644
index 0000000..356b622
--- /dev/null
+++ b/src/tools/showvis/Makefile
@@ -0,0 +1,6 @@
+include $(GLEAN_ROOT)/make/common.mak
+
+TARGET=showvis
+LIB=-ldsurf -llex -lGLU -lGL -lXext -lX11
+
+include $(GLEAN_ROOT)/make/app.mak
diff --git a/src/tools/showvis/main.cpp b/src/tools/showvis/main.cpp
new file mode 100644
index 0000000..05bc761
--- /dev/null
+++ b/src/tools/showvis/main.cpp
@@ -0,0 +1,293 @@
+// 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 <stdlib.h>
+#include <iostream>
+#include <string>
+#include "glwrap.h"
+#include "dsconfig.h"
+#include "dsfilt.h"
+
+char* mandatoryArg(int argc, char* argv[], int i);
+void usage(char* appName);
+
+///////////////////////////////////////////////////////////////////////////////
+// showvis - display list of visuals (X11 Visuals, GLX FBConfigs, or
+// Win32 PixelFormatDescriptors) matching user-supplied criteria
+///////////////////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[]) {
+ string criteria;
+ bool canonical = false;
+
+# if defined(__X11__)
+ string displayName(":0");
+# endif
+
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "--help")) {
+ usage(argv[0]);
+ } else if (!strcmp(argv[i], "-c")
+ || !strcmp(argv[i], "--canonical")) {
+ canonical = true;
+# if defined(__X11__)
+ } else if (!strcmp(argv[i], "-display")) {
+ ++i;
+ displayName = mandatoryArg(argc, argv, i);
+# endif
+ } else {
+ // Concatenate all non-option arguments, separating
+ // them with commas, to form a single string of
+ // criteria:
+ if (criteria.size())
+ criteria += ",";
+ criteria += argv[i];
+ }
+ }
+
+ // By default, display all visuals:
+ if (criteria.size() == 0)
+ criteria = "1";
+
+
+# if defined(__X11__) && !defined(GLX_VERSION_1_3)
+ Display* dpy = XOpenDisplay(displayName.c_str());
+
+ if (!dpy) {
+ cerr << "can't open display " << displayName << "\n";
+ exit(2);
+ }
+
+ // Get the list of raw XVisualInfo structures:
+ XVisualInfo t;
+ t.screen = DefaultScreen(dpy);
+ int n;
+ XVisualInfo* vi =
+ XGetVisualInfo(dpy, VisualScreenMask, &t, &n);
+
+ // Construct a vector of DrawingSurfaceConfigs corresponding
+ // to the XVisualInfo structures that indicate they support
+ // OpenGL:
+ vector<GLEAN::DrawingSurfaceConfig*> glxv;
+ for (int i = 0; i < n; ++i) {
+ int supportsOpenGL;
+ glXGetConfig(dpy, &vi[i], GLX_USE_GL, &supportsOpenGL);
+ if (supportsOpenGL)
+ glxv.push_back(new GLEAN::DrawingSurfaceConfig
+ (dpy, &vi[i]));
+ }
+
+ // Create a configuration filter and apply it:
+ try {
+ GLEAN::DrawingSurfaceFilter f(criteria);
+ vector<GLEAN::DrawingSurfaceConfig*> v(f.filter(glxv));
+
+ for(vector<GLEAN::DrawingSurfaceConfig*>::const_iterator
+ p = v.begin(); p < v.end(); ++p)
+ cout << (canonical? (*p)->canonicalDescription()
+ : (*p)->conciseDescription())
+ << "\n";
+
+ exit (v.size() == 0);
+ }
+ catch (GLEAN::DrawingSurfaceFilter::Syntax e) {
+ cerr << "Syntax error:\n'" << criteria << "'\n";
+ for (int i = 0; i < e.position; ++i)
+ cerr << ' ';
+ cerr << "^ " << e.err << "\n";
+ exit(2);
+ }
+
+
+# elif defined(__X11__) && defined(GLX_VERSION_1_3)
+# error "XXX Need to write GLX 1.3 FBConfig code"
+ // Yeah, yeah, it shouldn't be hard. I just don't
+ // have any way to test it yet.
+# elif defined(__WIN__)
+ HDC hDC = GetDC(GetDesktopWindow());
+
+ int n = DescribePixelFormat(hDC,0,sizeof(PIXELFORMATDESCRIPTOR),0);
+
+ PIXELFORMATDESCRIPTOR *pfd = new PIXELFORMATDESCRIPTOR[n+1];
+
+ // Construct a vector of DrawingSurfaceConfigs corresponding
+ // to all available pixelformats
+ vector<GLEAN::DrawingSurfaceConfig*> glxv;
+ for (int j = 1;j <= n;j++) {
+ DescribePixelFormat(hDC,j,sizeof(PIXELFORMATDESCRIPTOR),&pfd[j]);
+ glxv.push_back(new GLEAN::DrawingSurfaceConfig(j,&pfd[j]));
+ }
+
+ ReleaseDC(GetDesktopWindow(),hDC);
+
+ // Create a configuration filter and apply it:
+ try {
+ GLEAN::DrawingSurfaceFilter f(criteria);
+ vector<GLEAN::DrawingSurfaceConfig*> v(f.filter(glxv));
+
+ for(vector<GLEAN::DrawingSurfaceConfig*>::const_iterator
+ p = v.begin(); p < v.end(); ++p)
+ cout << (canonical? (*p)->canonicalDescription()
+ : (*p)->conciseDescription())
+ << "\n";
+
+ exit (v.size() == 0);
+ }
+ catch (GLEAN::DrawingSurfaceFilter::Syntax e) {
+ cerr << "Syntax error:\n'" << criteria << "'\n";
+ for (int i = 0; i < e.position; ++i)
+ cerr << ' ';
+ cerr << "^ " << e.err << "\n";
+ exit(2);
+ }
+
+ return 0;
+
+# endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// mandatoryArg - fetch a required argument from the command line;
+// if it isn't present, print a usage message and die.
+///////////////////////////////////////////////////////////////////////////////
+
+char*
+mandatoryArg(int argc, char* argv[], int i) {
+ if (i < argc && argv[i][0] != '-')
+ return argv[i];
+ usage(argv[0]);
+ /*NOTREACHED*/
+ return 0;
+} // mandatoryArg
+
+///////////////////////////////////////////////////////////////////////////////
+// usage - print usage message, then die
+///////////////////////////////////////////////////////////////////////////////
+void
+usage(char* appName) {
+ cerr << "Usage: " << appName << "[options] {selection-expression}\n"
+"\n"
+"options:\n"
+#if defined(__X11__)
+" -display X11-display-name # select X11 display to use\n"
+#elif defined(__WIN__)
+#endif
+" --help # display usage information\n"
+" (-c|--canonical) # display visuals in canonical form,\n"
+" # rather than abbreviated form\n"
+"\n"
+"selection-expression:\n"
+" Selection expressions are C expressions involving the usual\n"
+" arithmetic and logical operators, plus variables that correspond\n"
+" to attributes of OpenGL-capable visuals (pixel formats).\n"
+" Operators are:\n"
+" ! -(unary) + - * / % == != < <= > >= && || ( )\n"
+" Variables are:\n"
+" r red channel size\n"
+" g green channel size\n"
+" b blue channel size\n"
+" a alpha channel size\n"
+" rgb minimum of r, g, and b\n"
+" rgba minimum of r, g, b, and a\n"
+" ci color index channel size\n"
+" accumr accumulation buffer red channel size\n"
+" accumg accumulation buffer green channel size\n"
+" accumb accumulation buffer blue channel size\n"
+" accuma accumulation buffer alpha channel size\n"
+" accumrgb minimum of accumr, accumg, and accumb\n"
+" accumrgba minimum of accumr, accumg, accumb, and accuma\n"
+" aux number of auxiliary color buffers\n"
+" db nonzero if visual is double-buffered\n"
+" sb nonzero if visual is single-buffered\n"
+" id system-dependent ID number of visual\n"
+" fbcid framebuffer configuration ID (GLX 1.3 only)\n"
+" level <0 if underlay; ==0 if main; >0 if overlay\n"
+" main nonzero if visual is in main planes\n"
+" overlay nonzero if visual is in overlay planes\n"
+" underlay nonzero if visual is in underlay planes\n"
+" mono nonzero if visual is monoscopic\n"
+" stereo nonzero if visual is stereoscopic\n"
+" ms number of multisamples\n"
+" s stencil buffer size\n"
+" z depth (Z) buffer size\n"
+" fast nonzero if visual is accelerated\n"
+" conformant nonzero if visual conforms to OpenGL spec\n"
+" transparent nonzero if visual has a transparent pixel value\n"
+" transr transparent pixel red value (RGBA visuals only)\n"
+" transg transparent pixel green value\n"
+" transb transparent pixel blue value\n"
+" transa transparent pixel alpha value\n"
+" transci transparent pixel color index value (CI visuals\n"
+" only)\n"
+" window nonzero if visual can be used to create windows\n"
+#if defined(__X11__)
+" pixmap nonzero if visual can be used to create pixmaps\n"
+#if defined(GLX_VERSION_1_3)
+" pbuffer nonzero if visual can be used to create pbuffers\n"
+#endif
+#endif
+" glonly nonzero if visual can be used only for OpenGL\n"
+" rendering\n"
+"\n"
+" Selection expressions may also include sort keys, which consist of\n"
+" ``max'' or ``min'' followed by a variable. When multiple visuals\n"
+" meeting the selection criteria are found, those with the largest\n"
+" (for max) or smallest (for min) value of the given variable are\n"
+" listed first.\n"
+"\n"
+" Finally, multiple selection expressions may be provided as separate\n"
+" arguments or separated by commas; in either case, only visuals that\n"
+" meet all the selection expressions are returned.\n"
+"\n"
+" Exit status is 0 (normal) if visuals were found, 1 if no matching\n"
+" visuals were found, and 2 if any error occurred\n"
+"\n"
+"Examples:\n"
+" " << appName << "\n"
+" display all OpenGL-capable visuals\n"
+" " << appName << " db rgb\n"
+" display all double-buffered RGB or RGBA visuals\n"
+" " << appName << " 'r != g || g != b'\n"
+" display all visuals for which the color channels are not all\n"
+" the same size\n"
+" " << appName << " 'max rgba, fast, conformant, accumrgba >= 2*rgba'\n"
+" display all visuals that are accelerated and OpenGL\n"
+" conformant, and for which the accumulation buffer is at\n"
+" least twice as deep as the normal color buffer, sorted with\n"
+" the deepest color buffer first\n"
+" " << appName << " 'r%2 || g%2 || b%2 '\n"
+" display all visuals for which at least one color channel\n"
+" has an odd size\n"
+" " << appName << " 'min ci'\n"
+" display color index visuals, smallest first\n";
+
+ exit(2);
+}
diff --git a/src/tools/showvis/makefile.win b/src/tools/showvis/makefile.win
new file mode 100644
index 0000000..d85d7ac
--- /dev/null
+++ b/src/tools/showvis/makefile.win
@@ -0,0 +1,118 @@
+.SILENT :
+
+!IF "$(CFG)" == ""
+CFG=release
+#!MESSAGE No configuration specified. Defaulting to release build.
+!ENDIF
+
+!IF "$(CFG)" != "release" && "$(CFG)" != "debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f makefile.win CFG="release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "release"
+!MESSAGE "debug"
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!INCLUDE $(GLEAN_ROOT)\make\common.win
+
+LINK32_OBJS= "$(INTDIR)\main.obj"
+
+LIBS=lex.lib dsurf.lib opengl32.lib kernel32.lib user32.lib gdi32.lib
+
+FTARGET=showvis
+TARGET=$(FTARGET).exe
+
+!IF "$(CFG)" == "release"
+
+DEFINES=$(DEFINES) /D "NDEBUG"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(GLEAN_BIN_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /Y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=$(LIBS) /nologo /subsystem:console /machine:I386 /include:"__imp__glGetString@4" /out:"$(GLEAN_BIN_DIR)\$(TARGET)" /nodefaultlib:libcd.lib
+
+"$(GLEAN_BIN_DIR)\$(TARGET)" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS) $(LIB_DIRS)
+
+
+!ELSEIF "$(CFG)" == "debug"
+
+DEFINES=$(DEFINES) /D "_DEBUG"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(GLEAN_BIN_DIR)\$(TARGET)"
+
+CLEAN :
+ -@erase "$(INTDIR)\*.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(OUTDIR)\$(FTARGET).pdb"
+ -@erase "$(GLEAN_BIN_DIR)\$(FTARGET).ilk"
+ -@erase "$(OUTDIR)\$(FTARGET).pch
+ -@deltree /Y "$(OUTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(DEFINES) $(INCLUDE_DIRS) /Fp"$(INTDIR)\$(FTARGET).pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=$(LIBS) /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\$(FTARGET).pdb" /debug /machine:I386 /include:"__imp__glGetString@4" /out:"$(GLEAN_BIN_DIR)\$(TARGET)" /pdbtype:sept $(LIB_DIRS)
+
+"$(GLEAN_BIN_DIR)\showvis.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)
+
+!ENDIF
+
+