ScaleTxtrCoords:
PUBLIC PROC [ context:
REF Context, shapeName: Rope.
ROPE,
scale:
REAL, xRatio, yRatio:
REAL ← 1.0 ] ~ {
xScale, yScale: REAL;
shape: REF ShapeInstance ← SceneUtilities.FindShape[ context, shapeName ];
auxInfo: REF PairSequence ← NARROW[GetProp[ shape.shadingProps, $AuxiliaryVtxData]];
refTriple: REF Triple ← NARROW[GetProp[shape.shadingProps, $TextureScale]];
IF refTriple = NIL THEN refTriple ← NEW[Triple ← [1.0, 1.0, 1.0]];
IF refTriple.x # 0.0
AND refTriple.y # 0.0
AND refTriple.z # 0.0
THEN {
xScale ← scale*xRatio/(refTriple.x*refTriple.y); -- multiply by new, divide by old values
yScale ← scale*yRatio/(refTriple.x*refTriple.z);
};
refTriple^ ← [scale, xRatio, yRatio];
FOR i:
NAT
IN [0..auxInfo.length)
DO
auxInfo[i].x ← auxInfo[i].x * xScale;
auxInfo[i].y ← auxInfo[i].y * yScale;
ENDLOOP;
shape.shadingProps ← PutProp[shape.shadingProps, $TextureScale, refTriple];
};
row0col0, rowNcol0, rowNcolM, row0ColM: Pair] ~ {
shape: REF ShapeInstance ← SceneUtilities.FindShape[ context, shapeName ];
auxInfo: REF PairSequence ← NARROW[GetProp[shape.shadingProps, $AuxiliaryVtxData]];
args: LIST OF REAL;
IF GetProp[ shape.fixedProps, $VertexTextureInFile] #
NIL
THEN {
SIGNAL ThreeDBasics.Error[[$MisMatch, "Overwriting original texture coords, OK?"]];
shape.shadingProps ← Atom.RemPropFromList[shape.shadingProps, $VertexTextureInFile];
};
IF auxInfo = NIL THEN auxInfo ← NEW[ PairSequence[shape.shade.length] ];
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 ThreeDBasics.Error[[$MisMatch, "Texture mapping dangerously dense"]];
FOR i:
NAT
IN [0..shape.shade.length)
DO
lPosX, lPosY, rPosX, rPosY: REAL;
auxInfo[i].x ← Real.Float[i MOD vtcesInRow] / vtcesInRow; -- pct along row
auxInfo[i].y ← Real.Float[i / vtcesInRow] / numberOfRows;
-- pct across rows
Stretch as indicated by corner coordinates
lPosX ← row0col0.x + auxInfo[i].y * (rowNcol0.x - row0col0.x);-- interp across rows
lPosY ← row0col0.y + auxInfo[i].y * (rowNcol0.y - row0col0.y);
rPosX ← row0ColM.x + auxInfo[i].y * (rowNcolM.x - row0ColM.x);
rPosY ← row0ColM.y + auxInfo[i].y * (rowNcolM.y - row0ColM.y);
auxInfo[i].x ← lPosX + auxInfo[i].x * (rPosX - lPosX); -- interp along row
auxInfo[i].y ← lPosY + auxInfo[i].x * (rPosY - lPosY);
ENDLOOP;
auxInfo.length ← shape.shade.length;
shape.shadingProps ← PutProp[ shape.shadingProps, $AuxiliaryVtxData, auxInfo];
shape.shadingProps ← PutProp[ shape.shadingProps, $TxtrCoordType, $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];
shape.shadingProps ← PutProp[ shape.shadingProps, $TxtrCoordParams, args];
};
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] ] ~ {
shape: REF ShapeInstance ← SceneUtilities.FindShape[ context, shapeName ];
auxInfo: REF PairSequence ← NARROW[GetProp[shape.shadingProps, $AuxiliaryVtxData]];
args: LIST OF REAL;
poly: REF ThreeDBasics.PtrPatchSequence ← NARROW[shape.surface];
polyTags: ARRAY [0..16) OF BOOLEAN;
lngtShift: REAL ← 0.0; -- latitude shift to allow < -180.0 and > 180.0
IF GetProp[shape.fixedProps, $VertexTextureInFile] #
NIL
THEN {
SIGNAL ThreeDBasics.Error[[$MisMatch, "Overwriting original texture coords, OK?"]];
shape.shadingProps ← Atom.RemPropFromList[shape.shadingProps, $VertexTextureInFile];
};
IF auxInfo = NIL THEN auxInfo ← NEW[ PairSequence[shape.shade.length] ];
IF GetProp[shape.shadingProps, $VtxInfoComputed] =
NIL
THEN {
shape.shadingClass.shadingType ← $Smooth; -- smooth shading forces computed normals
SurfaceRender.ValidateContext[context]; -- make sure viewport, etc. is kosher
};
IF
MAX[sw.x, nw.x, se.x, ne.x] -
MIN[sw.x, nw.x, se.x, ne.x] > 360.0
THEN SIGNAL ThreeDBasics.Error[[$MisMatch, "Longitude range exceeds 360 degrees"]];
IF
MIN[sw.x, nw.x, se.x, ne.x] < -180.0
THEN lngtShift ← -180.0 - MIN[sw.x, nw.x, se.x, ne.x] -- positive shift if past -180
ELSE
IF
MAX[sw.x, nw.x, se.x, ne.x] > 180.0
THEN lngtShift ← 180.0 - MAX[sw.x, nw.x, se.x, ne.x]; -- negative shift if past 180
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);
IF longitude > 180.0 - lngtShift
THEN longitude ← -180.0 - (180.0 - longitude)
ELSE
IF longitude < -180.0 - lngtShift
THEN longitude ← 180.0 + (longitude + 180.0);
auxInfo[vtx].x ← (longitude - lPosX) / (rPosX - lPosX); -- percentage across
auxInfo[vtx].y ← lPosY + auxInfo[vtx].x * (rPosY - lPosY); -- wtd av. %
auxInfo[vtx].x ← MIN[ 1.0, MAX[0.0, auxInfo[vtx].x]];
auxInfo[vtx].y ← MIN[ 1.0, MAX[0.0, auxInfo[vtx].y]];
IF hypotenuse < 0.00001 THEN polyTags[i] ← TRUE -- catch unstable arithmetic
ELSE {
polyTags[i] ← FALSE;
IF auxInfo[vtx].x < minTxtrX THEN minTxtrX ← auxInfo[vtx].x;
IF auxInfo[vtx].x > maxTxtrX THEN maxTxtrX ← auxInfo[vtx].x;
};
ENDLOOP;
auxInfo.length ← shape.shade.length;
shape.shadingProps ← PutProp[ shape.shadingProps, $AuxiliaryVtxData, auxInfo];
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 - auxInfo[vtx].x > .5
THEN auxInfo[vtx].x ← auxInfo[vtx].x + 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 auxInfo[vtx].x < minTxtrX THEN minTxtrX ← auxInfo[vtx].x;
IF auxInfo[vtx].x > maxTxtrX THEN maxTxtrX ← auxInfo[vtx].x;
};
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 auxInfo[vtx].x ← (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 + auxInfo[vtx].y * (topLeft.x - botLeft.x);
lPosY: REAL ← botLeft.y + auxInfo[vtx].y * (topLeft.y - botLeft.y);
rPosX: REAL ← botRight.x + auxInfo[vtx].y * (topRight.x - botRight.x);
rPosY: REAL ← botRight.y + auxInfo[vtx].y * (topRight.y - botRight.y);
auxInfo[vtx].x ← lPosX + auxInfo[vtx].x * (rPosX - lPosX);
auxInfo[vtx].y ← lPosY + auxInfo[vtx].x * (rPosY - lPosY);
IF auxInfo[vtx].x < minTxtrX THEN minTxtrX ← auxInfo[vtx].x;
IF auxInfo[vtx].y < minTxtrY THEN minTxtrY ← auxInfo[vtx].y;
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];
auxInfo[vtx].x ← auxInfo[vtx].x - minTxtrX;
auxInfo[vtx].y ← auxInfo[vtx].y - minTxtrY;
ENDLOOP;
ENDLOOP;
shape.shadingProps ← PutProp[ shape.shadingProps, $TxtrCoordType, $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];
args ← CONS[se.y, args]; args ← CONS[se.x, args];
args ← CONS[ne.y, args]; args ← CONS[ne.x, args];
args ← CONS[nw.y, args]; args ← CONS[nw.x, args];
args ← CONS[sw.y, args]; args ← CONS[sw.x, args];
shape.shadingProps ← PutProp[ shape.shadingProps, $TxtrCoordParams, args];
};