row0col0, rowNcol0, rowNcolM, row0ColM: Pair] ~ {
texture: REF TextureMap;
args: LIST OF REAL;
IF shape.shade.length #
CARDINAL[vtcesInRow * numberOfRows]
THEN {
SIGNAL TextureMapsError[$WrongNumberOfVertices];
RETURN[];
};
IF row0ColM.x - row0col0.x > .3 * vtcesInRow
OR rowNcolM.x - rowNcol0.x > .3 * vtcesInRow
OR rowNcolM.y - row0ColM.y > .3 * numberOfRows
OR rowNcol0.y - row0col0.y > .3 * numberOfRows
THEN SIGNAL TextureMapsError[$TextureTooDense];
FOR i:
NAT
IN [0..shape.shade.length)
DO
lPosX, lPosY, rPosX, rPosY: REAL;
shape.shade[i].txtrX ← Real.Float[i MOD vtcesInRow] / vtcesInRow; -- pct along row
shape.shade[i].txtrY ← Real.Float[i / vtcesInRow] / numberOfRows;
-- pct across rows
Stretch as indicated by corner coordinates
lPosX ← row0col0.x + shape.shade[i].txtrY * (rowNcol0.x - row0col0.x); -- interp across rows
lPosY ← row0col0.y + shape.shade[i].txtrY * (rowNcol0.y - row0col0.y);
rPosX ← row0ColM.x + shape.shade[i].txtrY * (rowNcolM.x - row0ColM.x);
rPosY ← row0ColM.y + shape.shade[i].txtrY * (rowNcolM.y - row0ColM.y);
shape.shade[i].txtrX ← lPosX + shape.shade[i].txtrX * (rPosX - lPosX); -- interp along row
shape.shade[i].txtrY ← lPosY + shape.shade[i].txtrX * (rPosY - lPosY);
ENDLOOP;
texture ← NARROW[ThreeDScenes.GetShading[shape, $TextureMap], REF TextureMap];
IF texture = NIL THEN texture ← NEW[TextureMap];
texture.props ← Atom.PutPropOnList[texture.props, $CoordType, $FromVtxNos];
args ← CONS[row0ColM.y, NIL]; args ← CONS[row0ColM.x, args];
args ← CONS[rowNcolM.y, args]; args ← CONS[rowNcolM.x, args];
args ← CONS[rowNcol0.y, args]; args ← CONS[rowNcol0.x, args];
args ← CONS[row0col0.y, args]; args ← CONS[row0col0.x, args];
args ← CONS[Real.Float[numberOfRows], args]; args ← CONS[Real.Float[vtcesInRow], args];
texture.props ← Atom.PutPropOnList[texture.props, $Coords, args];
ThreeDScenes.PutShading[shape, $TextureMap, texture];
};
botLeft: Pair ← [0.0, 0.0], topLeft: Pair ← [0.0, 1.0],
topRight: Pair ← [1.0, 1.0], botRight: Pair ← [1.0, 0.0],
sw: Pair ← [-180.0, -90.0], nw: Pair ← [-180.0, 90.0],
ne: Pair ← [180.0, 90.0], se: Pair ← [180.0, -90.0] ] ~ {
texture: REF TextureMap;
args: LIST OF REAL;
poly: REF ThreeDSurfaces.PtrPatchSequence ← NARROW[shape.surface];
polyTags: ARRAY [0..8) OF BOOLEAN;
IF shape.shade.length # shape.vertex.length
THEN {
SIGNAL TextureMapsError[$WrongNumberOfVertices];
RETURN[];
};
IF ABS[nw.y - sw.y] < 0.001 THEN nw.y ← sw.y + Sgn[nw.y - sw.y] * 0.001; -- stop div errs
IF ABS[ne.y - se.y] < 0.001 THEN ne.y ← se.y + Sgn[ne.y - se.y] * 0.001;
IF ABS[sw.x - se.x] < 0.001 THEN sw.x ← se.x + Sgn[sw.x - se.x] * 0.001;
IF ABS[nw.x - ne.x] < 0.001 THEN nw.x ← ne.x + Sgn[nw.x - ne.x] * 0.001;
FOR polyNumber:
NAT
IN [0..poly.length)
DO
minTxtrX, minTxtrY: REAL ← Real.LargestNumber;
maxTxtrX: REAL ← 0.;
FOR i:
NAT
IN [0..poly[polyNumber].nVtces)
DO
Map from sphere to Cartesian coordinates 1st quadrant 0 - 1 range.
vtx: NAT ← poly[polyNumber].vtxPtr[i];
hypotenuse: REAL ← RealFns.SqRt[Sqr[shape.shade[vtx].yn] + Sqr[shape.shade[vtx].xn]];
longitude: REAL ← RealFns.ArcTanDeg[shape.shade[vtx].yn, shape.shade[vtx].xn];
latitude:
REAL ← RealFns.ArcTanDeg
[shape.shade[vtx].zn, hypotenuse
];
Map polar coordinates into quadrilateral given by sw, nw, ne, se
lPosY: REAL ← (latitude - sw.y) / (nw.y - sw.y); -- percentage of distance on left edge
rPosY: REAL ← (latitude - se.y) / (ne.y - se.y);
lPosX: REAL ← sw.x + lPosY * (nw.x - sw.x); -- weighted average of positions
rPosX: REAL ← se.x + rPosY * (ne.x - se.x);
shape.shade[vtx].txtrX ← (longitude - lPosX) / (rPosX - lPosX); -- percentage across
shape.shade[vtx].txtrY ← lPosY + shape.shade[vtx].txtrX * (rPosY - lPosY); -- wtd av. %
shape.shade[vtx].txtrX ← MIN[ 1.0, MAX[0.0, shape.shade[vtx].txtrX]];
shape.shade[vtx].txtrY ← MIN[ 1.0, MAX[0.0, shape.shade[vtx].txtrY]];
IF hypotenuse < 0.00001 THEN polyTags[i] ← TRUE -- catch unstable arithmetic
ELSE {
polyTags[i] ← FALSE;
IF shape.shade[vtx].txtrX < minTxtrX THEN minTxtrX ← shape.shade[vtx].txtrX;
IF shape.shade[vtx].txtrX > maxTxtrX THEN maxTxtrX ← shape.shade[vtx].txtrX;
};
ENDLOOP;
IF maxTxtrX - minTxtrX > .5 -- wrapping around seam, fix up coords
THEN
FOR i:
NAT
IN [0..poly[polyNumber].nVtces)
DO
vtx: NAT ← poly[polyNumber].vtxPtr[i];
IF maxTxtrX - shape.shade[vtx].txtrX > .5
THEN shape.shade[vtx].txtrX ← shape.shade[vtx].txtrX + 1.;
ENDLOOP;
minTxtrX ← Real.LargestNumber;
maxTxtrX ← 0.;
FOR i:
NAT
IN [0..poly[polyNumber].nVtces)
DO
-- get corrected max and min
IF polyTags[i] =
FALSE THEN {
vtx: NAT ← poly[polyNumber].vtxPtr[i];
IF shape.shade[vtx].txtrX < minTxtrX THEN minTxtrX ← shape.shade[vtx].txtrX;
IF shape.shade[vtx].txtrX > maxTxtrX THEN maxTxtrX ← shape.shade[vtx].txtrX;
};
ENDLOOP;
FOR i:
NAT
IN [0..poly[polyNumber].nVtces)
DO
-- fix up unstable vertical normals
vtx: NAT ← poly[polyNumber].vtxPtr[i];
IF polyTags[i] = TRUE THEN shape.shade[vtx].txtrX ← (maxTxtrX + minTxtrX) / 2.;
ENDLOOP;
minTxtrX ← minTxtrY ← Real.LargestNumber;
FOR i:
NAT
IN [0..poly[polyNumber].nVtces)
DO
-- slew according to corner coords
vtx: NAT ← poly[polyNumber].vtxPtr[i];
lPosX: REAL ← botLeft.x + shape.shade[vtx].txtrY * (topLeft.x - botLeft.x);
lPosY: REAL ← botLeft.y + shape.shade[vtx].txtrY * (topLeft.y - botLeft.y);
rPosX: REAL ← botRight.x + shape.shade[vtx].txtrY * (topRight.x - botRight.x);
rPosY: REAL ← botRight.y + shape.shade[vtx].txtrY * (topRight.y - botRight.y);
shape.shade[vtx].txtrX ← lPosX + shape.shade[vtx].txtrX * (rPosX - lPosX);
shape.shade[vtx].txtrY ← lPosY + shape.shade[vtx].txtrX * (rPosY - lPosY);
IF shape.shade[vtx].txtrX < minTxtrX THEN minTxtrX ← shape.shade[vtx].txtrX;
IF shape.shade[vtx].txtrY < minTxtrY THEN minTxtrY ← shape.shade[vtx].txtrY;
ENDLOOP;
minTxtrX ← Real.Float[Real.Fix[minTxtrX]];
minTxtrY ← Real.Float[Real.Fix[minTxtrY]];
FOR i:
NAT
IN [0..poly[polyNumber].nVtces)
DO
-- translate to origin
vtx: NAT ← poly[polyNumber].vtxPtr[i];
shape.shade[vtx].txtrX ← shape.shade[vtx].txtrX - minTxtrX;
shape.shade[vtx].txtrY ← shape.shade[vtx].txtrY - minTxtrY;
ENDLOOP;
ENDLOOP;
texture ← NARROW[ThreeDScenes.GetShading[shape, $TextureMap], REF TextureMap];
IF texture = NIL THEN texture ← NEW[TextureMap];
texture.props ← Atom.PutPropOnList[texture.props, $CoordType, $FromNormals];
args ← CONS[botRight.y, NIL]; args ← CONS[botRight.x, args];
args ← CONS[topRight.y, args]; args ← CONS[topRight.x, args];
args ← CONS[topLeft.y, args]; args ← CONS[topLeft.x, args];
args ← CONS[botLeft.y, args]; args ← CONS[botLeft.x, args];
texture.props ← Atom.PutPropOnList[texture.props, $Coords, args];
ThreeDScenes.PutShading[shape, $TextureMap, texture];
};