Index: src/geometry/TriWallSceneNode.cxx
===================================================================
--- src/geometry/TriWallSceneNode.cxx	(revision 18299)
+++ src/geometry/TriWallSceneNode.cxx	(working copy)
@@ -22,6 +22,7 @@
 
 // common implementation headers
 #include "Intersect.h"
+#include "StateDatabase.h"
 
 // FIXME (SceneRenderer.cxx is in src/bzflag)
 #include "SceneRenderer.h"
@@ -49,6 +50,39 @@
       uv[n][1] = 0.0f + t * vRepeats;
     }
   }
+
+  if (BZDB.isTrue("remapTexCoords")) {
+    const float uLen = sqrtf((uEdge[0] * uEdge[0]) +
+                             (uEdge[1] * uEdge[1]) +
+                             (uEdge[2] * uEdge[2]));
+    const float vLen = sqrtf((vEdge[0] * vEdge[0]) +
+                             (vEdge[1] * vEdge[1]) +
+                             (vEdge[2] * vEdge[2]));
+    const float uScale = 10.0f / floorf(10.0f * uLen / uRepeats);
+    const float vScale = 10.0f / floorf(10.0f * vLen / vRepeats);
+    if (fabsf(normal[2]) > 0.999f) {
+      // horizontal surface
+      for (int i = 0; i < vertex.getSize(); i++) {
+        uv[i][0] = uScale * vertex[i][0];
+        uv[i][1] = vScale * vertex[i][1];
+      }
+    }
+    else {
+      // vertical surface
+      const float nh = sqrtf((normal[0] * normal[0]) + (normal[1] * normal[1]));
+      const float nx = normal[0] / nh;
+      const float ny = normal[1] / nh;
+      const float vs = 1.0f / sqrtf(1.0f - (normal[2] * normal[2]));
+      for (int i = 0; i < vertex.getSize(); i++) {
+        const float* v = vertex[i];
+        const float uGeoScale = (nx * v[1]) - (ny * v[0]);
+        const float vGeoScale = v[2] * vs;
+        uv[i][0] = uScale * uGeoScale;
+        uv[i][1] = vScale * vGeoScale;
+      }
+    }
+  }
+
   triangles = (eCount * eCount);
 }
 
Index: src/geometry/QuadWallSceneNode.cxx
===================================================================
--- src/geometry/QuadWallSceneNode.cxx	(revision 18299)
+++ src/geometry/QuadWallSceneNode.cxx	(working copy)
@@ -21,6 +21,7 @@
 
 // common implementation headers
 #include "Intersect.h"
+#include "StateDatabase.h"
 
 // local implementation headers
 #include "ViewFrustum.h"
@@ -39,7 +40,7 @@
 				const GLfloat vEdge[3],
 				const GLfloat* _normal,
 				float uOffset, float vOffset,
-				float uRepeats, float vRepeats) :
+				float uRepeats, float vRepeats, bool fixedUVs) :
 				wall(_wall),
 				style(0),
 				ds(uCount),
@@ -61,6 +62,39 @@
       uv[n][1] = vOffset + t * vRepeats;
     }
   }
+
+  if (!fixedUVs && BZDB.isTrue("remapTexCoords")) {
+    const float uLen = sqrtf((uEdge[0] * uEdge[0]) +
+                             (uEdge[1] * uEdge[1]) +
+                             (uEdge[2] * uEdge[2]));
+    const float vLen = sqrtf((vEdge[0] * vEdge[0]) +
+                             (vEdge[1] * vEdge[1]) +
+                             (vEdge[2] * vEdge[2]));
+    const float uScale = 10.0f / floorf(10.0f * uLen / uRepeats);
+    const float vScale = 10.0f / floorf(10.0f * vLen / vRepeats);
+    if (fabsf(normal[2]) > 0.999f) {
+      // horizontal surface
+      for (int i = 0; i < vertex.getSize(); i++) {
+        uv[i][0] = uScale * vertex[i][0];
+        uv[i][1] = vScale * vertex[i][1];
+      }
+    }
+    else {
+      // vertical surface
+      const float nh = sqrtf((normal[0] * normal[0]) + (normal[1] * normal[1]));
+      const float nx = normal[0] / nh;
+      const float ny = normal[1] / nh;
+      const float vs = 1.0f / sqrtf(1.0f - (normal[2] * normal[2]));
+      for (int i = 0; i < vertex.getSize(); i++) {
+        const float* v = vertex[i];
+        const float uGeoScale = (nx * v[1]) - (ny * v[0]);
+        const float vGeoScale = v[2] * vs;
+        uv[i][0] = uScale * uGeoScale;
+        uv[i][1] = vScale * vGeoScale;
+      }
+    }
+  }
+
   triangles = 2 * (uCount * vCount);
 }
 
@@ -162,7 +196,7 @@
 				float vRepeats,
 				bool makeLODs)
 {
-  init(base, uEdge, vEdge, uOffset, vOffset, uRepeats, vRepeats, makeLODs);
+  init(base, uEdge, vEdge, uOffset, vOffset, uRepeats, vRepeats, makeLODs, false);
 }
 
 QuadWallSceneNode::QuadWallSceneNode(const GLfloat base[3],
@@ -170,9 +204,9 @@
 				const GLfloat vEdge[3],
 				float uRepeats,
 				float vRepeats,
-				bool makeLODs)
+				bool makeLODs, bool fixedUVs)
 {
-  init(base, uEdge, vEdge, 0.0f, 0.0f, uRepeats, vRepeats, makeLODs);
+  init(base, uEdge, vEdge, 0.0f, 0.0f, uRepeats, vRepeats, makeLODs, fixedUVs);
 }
 
 void			QuadWallSceneNode::init(const GLfloat base[3],
@@ -182,7 +216,8 @@
 				float vOffset,
 				float uRepeats,
 				float vRepeats,
-				bool makeLODs)
+				bool makeLODs,
+				bool fixedUVs)
 {
   // record plane and bounding sphere info
   GLfloat myPlane[4], mySphere[4];
@@ -261,11 +296,11 @@
   nodes[level++] = new Geometry(this, uElements, vElements,
 				base, uEdge, vEdge,
 				getPlane(), uOffset, vOffset,
-				uRepeats, vRepeats);
+				uRepeats, vRepeats, fixedUVs);
   shadowNode = new Geometry(this, uElements, vElements,
 				base, uEdge, vEdge,
 				getPlane(), uOffset, vOffset,
-				uRepeats, vRepeats);
+				uRepeats, vRepeats, fixedUVs);
   shadowNode->setStyle(0);
 
   // make squaring levels if necessary
@@ -280,7 +315,7 @@
 	nodes[level++] = new Geometry(this, uElements, vElements,
 				base, uEdge, vEdge,
 				getPlane(), uOffset, vOffset,
-				uRepeats, vRepeats);
+				uRepeats, vRepeats, fixedUVs);
 
       }
       area /= (float)uElements;
@@ -293,7 +328,7 @@
 	nodes[level++] = new Geometry(this, uElements, vElements,
 				base, uEdge, vEdge,
 				getPlane(), uOffset, vOffset,
-				uRepeats, vRepeats);
+				uRepeats, vRepeats, fixedUVs);
 
       }
       area /= (float)vElements;
@@ -309,7 +344,7 @@
     nodes[level++] = new Geometry(this, uElements, vElements,
 				base, uEdge, vEdge,
 				getPlane(), uOffset, vOffset,
-				uRepeats, vRepeats);
+				uRepeats, vRepeats, fixedUVs);
   }
 
   // record extents info
Index: src/obstacle/BaseSceneNodeGenerator.cxx
===================================================================
--- src/obstacle/BaseSceneNodeGenerator.cxx	(revision 18299)
+++ src/obstacle/BaseSceneNodeGenerator.cxx	(working copy)
@@ -28,11 +28,13 @@
 
 WallSceneNode*	BaseSceneNodeGenerator::getNextNode(float uRepeats, float vRepeats, bool lod)
 {
+  bool fixedUVs = false;
   const float height = base->getHeight() + base->getPosition()[2];
   if(getNodeNumber() >= 1 && height == 0) return NULL;
   if(getNodeNumber() >= 6) return NULL;
   GLfloat bPoint[3], sCorner[3], tCorner[3];
   if (height == 0) {
+    fixedUVs = true;
     incNodeNumber();
     base->getCorner(0, bPoint);
     base->getCorner(3, tCorner);
@@ -40,6 +42,7 @@
   } else {
     switch(incNodeNumber()) {
       case 1:  // This is the top polygon
+        fixedUVs = true;
 	base->getCorner(4, bPoint);
 	base->getCorner(5, sCorner);
 	base->getCorner(7, tCorner);
@@ -65,6 +68,7 @@
 	base->getCorner(7, tCorner);
 	break;
       case 6:  // This is the bottom polygon
+        fixedUVs = true;
 	if (base->getPosition()[2] > 0.0f) {
 	  // Only generate if above ground level
 	  base->getCorner(0, bPoint);
@@ -103,7 +107,7 @@
   tEdge[1] = tCorner[1] - bPoint[1];
   tEdge[2] = tCorner[2] - bPoint[2];
 
-  WallSceneNode *retval = new QuadWallSceneNode(bPoint, sEdge, tEdge, uRepeats, vRepeats, lod);
+  WallSceneNode *retval = new QuadWallSceneNode(bPoint, sEdge, tEdge, uRepeats, vRepeats, lod, fixedUVs);
   retval->setColor(color);
   return retval;
 }
Index: src/bzflag/DisplayMenu.cxx
===================================================================
--- src/bzflag/DisplayMenu.cxx	(revision 18299)
+++ src/bzflag/DisplayMenu.cxx	(working copy)
@@ -100,6 +100,16 @@
 
   option = new HUDuiList;
   option->setFontFace(fontFace);
+  option->setLabel("AntiFlicker:");
+  option->setCallback(callback, (void*)"R");
+  options = &option->getList();
+  options->push_back(std::string("Off"));
+  options->push_back(std::string("On"));
+  option->update();
+  listHUD.push_back(option);
+
+  option = new HUDuiList;
+  option->setFontFace(fontFace);
   option->setLabel("Anisotropic:");
   option->setCallback(callback, (void*)"A");
   options = &option->getList();
@@ -308,6 +318,7 @@
       ((HUDuiList*)listHUD[i++])->setIndex(0);
     }
     ((HUDuiList*)listHUD[i++])->setIndex(tm.getMaxFilter());
+    ((HUDuiList*)listHUD[i++])->setIndex(BZDB.isTrue("remapTexCoords") ? 1 : 0);
     int aniso = BZDB.evalInt("aniso");
     aniso = (aniso < 1) ? 1 : aniso;
     ((HUDuiList*)listHUD[i++])->setIndex(BZDB.evalInt("aniso") - 1);
@@ -391,6 +402,11 @@
     sceneRenderer->notifyStyleChange();
     break;
   }
+  case 'R': {
+    BZDB.setBool("remapTexCoords", list->getIndex() == 1);
+    setSceneDatabase();
+    break;
+  }
   case 'A': {
     int aniso = list->getIndex() + 1;
     BZDB.setInt("aniso", aniso);
Index: src/bzflag/bzflag.cxx
===================================================================
--- src/bzflag/bzflag.cxx	(revision 18299)
+++ src/bzflag/bzflag.cxx	(working copy)
@@ -155,8 +155,11 @@
   }
 
   // optional
+  visual->setStencil(4);
 #if defined(DEBUG_RENDERING)
   visual->setStencil(4);
+#else
+  visual->setStencil(1);
 #endif
   if (BZDB.isTrue("multisample"))
     visual->setMultisample(4);
Index: src/bzflag/playing.cxx
===================================================================
--- src/bzflag/playing.cxx	(revision 18299)
+++ src/bzflag/playing.cxx	(working copy)
@@ -887,6 +887,48 @@
 }
 
 
+static void mouseClamp(const BzfMotionEvent& event)
+{
+  // only clamp when it might be useful
+  if ((myTank == NULL) || !myTank->isAlive() ||
+      myTank->isPaused() || (myTank->getTeam() == ObserverTeam)) {
+    return;
+  }
+
+  // do not clamp if CTRL is being held down
+  bool alt, ctrl, shift;
+  display->getModState(alt, ctrl, shift);
+  if (ctrl) {
+    return;
+  }
+
+  // calculate the max motion size in pixels
+  const int clampFudge = 2;
+  const int w  = mainWindow->getWidth();
+  const int vh = mainWindow->getViewHeight();
+  const float xScale = (float)w  / (float) MinX;
+  const float yScale = (float)vh / (float) MinY;
+  const float scale = (xScale < yScale) ? xScale : yScale;
+  const float effScale =  scale * (0.7f + RENDERER.getMaxMotionFactor() / 16.667f);
+  const int maxMotionSize = (int)((float)MaxMotionSize * effScale);
+  const int pixels = maxMotionSize + clampFudge;
+
+  // calculate the clamp extents
+  const int xc = (w / 2);
+  const int xn = xc - pixels;
+  const int xp = xc + pixels;
+  const int yc = (vh / 2);
+  const int yn = yc - pixels;
+  const int yp = yc + pixels;
+
+  // clamp, as required
+  if (event.x < xn) { mainWindow->getWindow()->warpMouse(xn, event.y); }
+  if (event.x > xp) { mainWindow->getWindow()->warpMouse(xp, event.y); }
+  if (event.y < yn) { mainWindow->getWindow()->warpMouse(event.x, yn); }
+  if (event.y > yp) { mainWindow->getWindow()->warpMouse(event.x, yp); }
+}
+
+
 static void		doEvent(BzfDisplay *disply)
 {
   BzfEvent event;
@@ -987,6 +1029,9 @@
     case BzfEvent::MouseMove:
       if (myTank && myTank->isAlive() && (myTank->getInputMethod() != LocalPlayer::Mouse) && (BZDB.isTrue("allowInputChange")))
 	myTank->setInputMethod(LocalPlayer::Mouse);
+      if (BZDB.isTrue("mouseClamp")) {
+        mouseClamp(event.mouseMove);
+      }
       break;
 
     default:
Index: data/std_ground.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: include/QuadWallSceneNode.h
===================================================================
--- include/QuadWallSceneNode.h	(revision 18299)
+++ include/QuadWallSceneNode.h	(working copy)
@@ -27,7 +27,8 @@
 				const GLfloat tEdge[3],
 				float uRepeats = 1.0,
 				float vRepeats = 1.0,
-				bool makeLODs = true);
+				bool makeLODs = true,
+				bool fixedUVs = false);
 			QuadWallSceneNode(const GLfloat base[3],
 				const GLfloat sEdge[3],
 				const GLfloat tEdge[3],
@@ -60,7 +61,7 @@
 				float vOffset,
 				float uRepeats,
 				float vRepeats,
-				bool makeLODs);
+				bool makeLODs, bool fixedUVs);
 
   protected:
     class Geometry : public RenderNode {
@@ -72,7 +73,8 @@
 				const GLfloat vEdge[3],
 				const GLfloat* normal,
 				float uOffset, float vOffset,
-				float uRepeats, float vRepeats);
+				float uRepeats, float vRepeats,
+				bool fixedUVs);
 			~Geometry();
 	void		setStyle(int _style) { style = _style; }
 	void		render();
