title: Texture Scales, Threepoints, etc.
author: tiglari

<u>Enhanced Texture Positioning</u>

Q1/2/3-engine games represent faces by specifying three points
that lie on the plane of the face (the initial three three-tuples
in the representation of a vace in the map-format).
QuArK's 'enhanced texture positioning' also uses these points
to represent the texture positioning information, but there
are several twists and turns in the way.

The basic idea is that the first point is the location in map
space of the origin of the texture space, while the second two
are the locations of the (1,0) and (0,-1) points (1 being
the width/height of a texture tile; 128 is often used instead
of 1)).  Hunh? how did -1 get into it??

That's the first twist.  Presumably due to the unfortunate
identification of the upper-left corner of a texture as the
origin, things seem to work (for faces) as if the vertical
texture coordinate were negative.  This requires sign-flips
at various points in the code, for example in projecting
textures between faces and patches, since the patch texture
coordinates don't have this property.  Confusing.

The next twist is due to the fact that the threepoints
are supposed to express the orientation of the face by
having the cross-product (p1-p0)^(p2-p0) stick outward
from the poly(s) that the face is in.  This makes it
impossible to express 'mirror image' texture scales directly,
since the cross-product would be reversed and point into
the poly.  The solution to this is that faces have a boolean
attribute 'Mirror'.  In the Delphi, the method <tt>Face.GetThreePoints</tt>
fills in the values of three var parameters V1, V2, V3; if Mirror is set, then
V2 is the position of texture (1,0) and V3 the position of
texture (0,-1), otherwise the reverse (this is backwards
from how I would have expected it to be, but there it is).
In the enhanced texture positioning output (written into
a comment at the end of each face), TX1 means that
Mirror is false, TX2 that it's true.

In the Python, the numerical (second) arguments to the face methord
<tt>(set)threepoints</tt> specify whether this
three-point swap is to take place; if this argument is 0 or 2,
it doesn't; if it's 1 or 3, it does.

And finally for the third twist.  In the map format, the
threepoints don't represent the texture size, but rather the
texture scale:  if the distances (p1-p0), (p2-p0) are 128,
then the texture scale is 1:1 (tho it may be sheared).  So
these points will only represent that actual locations of
the texture size is 128x128.  If we want to the threepoints
to be located at the actual texture points, we need to use
<tt>GetThreePointsUserTex</tt> in Delphi, or set
the numerical argument of <tt>(set)threepoints</tt>
to 1 or 3 in Python.

So wrapping all this up, the threepoints info as gotten by
<tt>GetThreePointsUserTex</tt> will have
V3, V2 giving the map space locations of texture (1,0) and
(0,-1), respctively, if Mirror is false, vice versa if it's true.
So what we've got is a pretty direct specification of a
linear mapping from the 'texture plane' (an infinite plane
tiled by the texture) into map space.

<u>Brush Primitives</u>

'Brush primitives' is the new brush format used by Q3Radiant.
Other than a bit of extra wrapping around the brush, its main
new feature (for now at any rate) is an improved methods of
expressing the texture-mapping over the 5 'shift scale rotate'
numbers that come after the texture name in the old
representation.

In BP format, you get something that looks like this coming
after the threeponts info, and before the texture name:
<code>
( ( 0.007813 0 0 ) ( 0 0.007813 0 ) )
</code>
What these are is the top two rows of the 'homogeneous matrix'
mapping the plane of the face, under a special coordinate system
we will get to in a moment, into the texture plane (so it's sort
of the reverse of how QuArK etp works).  Erm, what's a homogeneous
matrix you might ask.

It is 3x3 matrix whose bottom row is (0 0 1).  If you multiply
a homogeneous matrix by a column vector whose z coordinate is
1, you'll see that the equations are exactly those for a
linear mapping followed by a translation: the first two numbers
of the top two rows give a 2x2 matrix describing the linear
transformation, and the last number give a column vector to
be added (to the a column 2-vector) to give the translation.
So what about this coordinate system?

It is one whose axis directions are gotten by rotating the
Y and Z coordinates of map space so that they lie in the
plane.  These direction vectors are computed by function
GetAxisBase in QkMapPoly.pas.  It's essential that q3map
and the editor compute them in the same way; hopefully the
Q3Radiant/Q3map developers won't change it without telling us.
Then of course for a coordinate system you need an origin,
this is gotten by scaling the face's normal vector by its
Dist (-ance from the origin).

So what goes on in GetPXPY is that the (texture-scaled,
etc.) threepoints are converted to the Axis Base coordiante
system, and then these equations are solved for the
coefficients aij making up the matrix (I used Maple V
to get the solution):
<code>
 a11*p0x+a12*p0y+a13 =  0
 a21*p0x+a22*p0y+a23 =  0

 a11*p1x+a12*p1y+a13 =  1
 a21*p1x+a22*p1y+a23 =  0

 a11*p2x+a12*p2y+a13 =  0
 a21*p2x+a22*p2y+a23 = -1
</code>

<u>Bezier Texture Scaling</u>

The routines for Face-Bezier texture projections are
in quarkpy\b2utils, texPlaneFromCph and texcpFromFace.
The former is rather complicated; I think it might be
possible to clean it up using the Axis Base idea, but
anway the code as some comments.
