DIRECTORY Atom USING [GetPropFromList, PutPropOnList], Real USING [LargestNumber, Float, Fix], RealFns USING [SqRt, ArcTanDeg], Rope USING [ROPE], Pixels USING [PixelBuffer, SampleSet, GetSampleSet, Create, Copy, SampleSetSequence, GetScanSeg, GetValue], ThreeDScenes USING [Context, ShapeInstance, Create, PutShading, GetShading], ThreeDSurfaces USING [PtrPatchSequence], ScanConvert USING [Spot], Vector2 USING [VEC], Vector3d USING [Normalize, Mul, Triple], AISAnimation USING [GetAIS], TextureMaps USING [TextureMap, IntSequence, ScanSequence, SummedTexture]; TextureMapsImpl: CEDAR PROGRAM IMPORTS Atom, Real, RealFns, ThreeDScenes, AISAnimation, Pixels, Vector3d EXPORTS TextureMaps = BEGIN TextureMapsError: PUBLIC SIGNAL [reason: ATOM] ~ CODE; Pair: TYPE ~ Vector2.VEC; -- [ x, y: REAL]; Triple: TYPE ~ Vector3d.Triple; TextureMap: TYPE ~ TextureMaps.TextureMap; IntSequence: TYPE ~ TextureMaps.IntSequence; ScanSequence: TYPE ~ TextureMaps.ScanSequence; SummedTexture: TYPE ~ TextureMaps.SummedTexture; Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE { RETURN[number * number]; }; Sgn: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE { IF number < 0. THEN RETURN[-1.] ELSE RETURN[1.]; }; MakeTxtrCoordsFromVtxNos: PUBLIC PROC[ shape: REF ThreeDScenes.ShapeInstance, vtcesInRow, numberOfRows: NAT, 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 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]; }; MakeTxtrCoordsFromNormals: PUBLIC PROC[ shape: REF ThreeDScenes.ShapeInstance, 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 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]; 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]; }; TextureFromAIS: PUBLIC PROC[context: REF ThreeDScenes.Context, fileName: Rope.ROPE, type: ATOM _ $Intensity] RETURNS[texture: REF TextureMap] ~ { width, height: NAT _ 1024; buf: REF Pixels.PixelBuffer _ NEW[ Pixels.PixelBuffer ]; pixelSizes: Pixels.SampleSet; renderMode: ATOM _ IF type = $Color THEN $FullClr ELSE $Grey; firstBuf: NAT _ IF context.alphaBuffer THEN 1 ELSE 0; bufContext: REF ThreeDScenes.Context _ ThreeDScenes.Create[width, height, renderMode]; bufContext.props _ context.props; -- bring along working directory, etc. [width, height] _ AISAnimation.GetAIS[bufContext, fileName]; -- load it with AIS bits IF width > bufContext.display.width OR height > bufContext.display.height THEN { bufContext _ ThreeDScenes.Create[width, height, renderMode]; bufContext.props _ context.props; -- bring along working directory, etc. [width, height] _ AISAnimation.GetAIS[bufContext, fileName]; }; SELECT bufContext.renderMode FROM $Dithered, $PseudoClr, $Grey => { pixelSizes _ Pixels.GetSampleSet[1]; pixelSizes[0] _ 8; }; $FullClr, $Dorado24 => { pixelSizes _ Pixels.GetSampleSet[3]; pixelSizes[0] _ pixelSizes[1] _ pixelSizes[2] _ 8; }; ENDCASE; texture _ NEW[TextureMap]; buf^ _ Pixels.Create[width, height, pixelSizes]; -- get properly sized buffer texture.pixels _ buf; Pixels.Copy[buf^, bufContext.display, -- copy texture pixels to it [0, 0, width, height], [ (bufContext.display.width - width) / 2, (bufContext.display.height - height) / 2, width, height ] ]; texture.pixels _ buf; texture.type _ type; texture.props _ Atom.PutPropOnList[texture.props, $FileName, fileName]; }; SetTexture: PUBLIC PROC[shape: REF ThreeDScenes.ShapeInstance, texture: REF TextureMap] ~ { oldTexture: REF TextureMap _ NARROW[ ThreeDScenes.GetShading[shape, $TextureMap] ]; IF oldTexture # NIL AND texture # NIL THEN { oldTexture.pixels _ texture.pixels; oldTexture.type _ texture.type; oldTexture.props _ Atom.PutPropOnList[ oldTexture.props, $FileName, Atom.GetPropFromList[texture.props, $FileName] ]; texture _ oldTexture; }; ThreeDScenes.PutShading[shape, $TextureMap, texture]; }; SumTexture: PUBLIC PROC[shape: REF ThreeDScenes.ShapeInstance] ~ { SumOneLine: PROC[ line: Pixels.SampleSet, sumMap: REF ScanSequence, y: NAT ] RETURNS[REF ScanSequence] ~ { IF sumMap = NIL THEN sumMap _ NEW[ ScanSequence[buf.height] ]; IF sumMap[y] = NIL THEN sumMap[y] _ NEW[ IntSequence[buf.width] ]; FOR x: NAT IN [0..line.length) DO sumMap[y][x] _ line[x]; IF x > 0 THEN { sumMap[y][x] _ sumMap[y][x] + sumMap[y][x - 1]; --add area to left IF y > 0 THEN -- x > 0 and y > 0: add area below minus area below and to left sumMap[y][x] _ sumMap[y][x] + (sumMap[y - 1][x] - sumMap[y - 1][x - 1]); } ELSE IF y > 0 THEN sumMap[y][x] _ sumMap[y][x] + sumMap[y - 1][x]; --add area below ENDLOOP; RETURN[sumMap]; }; buf: Pixels.PixelBuffer; scanLine: REF Pixels.SampleSetSequence; summedTexture: REF SummedTexture; texture: REF TextureMap _ NARROW[ ThreeDScenes.GetShading[shape, $TextureMap] ]; IF texture = NIL THEN RETURN[]; buf _ NARROW[ texture.pixels, REF Pixels.PixelBuffer ]^; summedTexture _ NEW[ SummedTexture[buf.samplesPerPixel] ]; FOR y: NAT IN [0..buf.height) DO scanLine _ Pixels.GetScanSeg[buf, 0, y, buf.width, scanLine]; FOR i: NAT IN [0..buf.samplesPerPixel) DO summedTexture[i] _ SumOneLine[ scanLine[i], summedTexture[i], y ]; ENDLOOP; ENDLOOP; texture.pixels _ summedTexture; ThreeDScenes.PutShading[shape, $TextureMap, texture] }; GetTxtrAt: PUBLIC PROC[spot: ScanConvert.Spot] RETURNS[ScanConvert.Spot] ~ { texture: REF TextureMap _ NARROW[ Atom.GetPropFromList[spot.props, $TextureMap] ]; WITH texture.pixels SELECT FROM buf: REF Pixels.PixelBuffer => IF texture.type = $Bump THEN SIGNAL TextureMapsError[$SumYourTexture] ELSE spot _ SimpleTexture[spot, buf^]; sumMap: REF SummedTexture => IF texture.type = $Bump THEN spot _ BumpTexture[spot, sumMap] ELSE spot _ SumMapTexture[spot, sumMap]; ENDCASE => ERROR; RETURN[spot]; }; SimpleTexture: PROC[spot: ScanConvert.Spot, map: Pixels.PixelBuffer] RETURNS[ScanConvert.Spot] ~ { GetTxtrAddress: PROC[buf: Pixels.PixelBuffer, x, y: REAL] RETURNS[ txtrX, txtrY: INTEGER ] ~ { txtrX _ Real.Fix[x * buf.width] MOD buf.width; IF txtrX < 0 THEN txtrX _ txtrX + buf.width; txtrY _ Real.Fix[y * buf.height] MOD buf.height; IF txtrY < 0 THEN txtrY _ txtrY + buf.height; }; x, y: INTEGER; txtrX: NAT ~ NARROW[ Atom.GetPropFromList[spot.props, $MapVals], REF NAT ]^; txtrY: NAT ~ txtrX+1; [x, y] _ GetTxtrAddress[map, spot.val[txtrX], spot.val[txtrY]]; SELECT map.samplesPerPixel FROM 1,2 => { txtrValue: REAL _ Pixels.GetValue[map, x, y, 0] / 256.0 ; FOR i: NAT IN [0..3) DO spot.val[i] _ spot.val[i] * txtrValue; ENDLOOP; }; 3,4 => FOR i: NAT IN [0..3) DO spot.val[i] _ spot.val[i] * Pixels.GetValue[map, x, y, i] / 256.0; ENDLOOP; ENDCASE => SIGNAL TextureMapsError[$BadTextureSize]; RETURN[spot]; }; SumMapTexture: PROC[spot: ScanConvert.Spot, txtrSum: REF SummedTexture] RETURNS[ScanConvert.Spot] ~ { maxTxtrX: REAL _ txtrSum[0][0].length; -- width (thus max x address) of texture maxTxtrY: REAL _ txtrSum[0].length; -- height (thus max y address) of texture txtrX: NAT ~ NARROW[ Atom.GetPropFromList[spot.props, $MapVals], REF NAT ]^; txtrY: NAT ~ txtrX+1; txtrXIncr: REAL _ MAX[ .001, ABS[spot.yIncr[txtrX]], ABS[spot.xIncr[txtrX]] ] / 2.0; -- incmnts in x&y txtrYIncr: REAL _ MAX[ .001, ABS[spot.yIncr[txtrY]], ABS[spot.xIncr[txtrY]] ] / 2.0; area: REAL _ 4 * txtrXIncr * maxTxtrX * txtrYIncr * maxTxtrY; WHILE spot.val[txtrX] - txtrXIncr < 0.0 DO spot.val[txtrX] _ spot.val[txtrX] + 1.0; ENDLOOP; WHILE spot.val[txtrY] - txtrYIncr < 0.0 DO spot.val[txtrY] _ spot.val[txtrY] + 1.0; ENDLOOP; SELECT txtrSum.length FROM 1 => { txtrValue: REAL _ SumValues[spot, txtrSum[0], txtrX, txtrY, txtrXIncr, txtrYIncr, area] / 256.0; IF txtrValue < 0.0 THEN txtrValue _ 0.0; FOR i: NAT IN [0..3) DO spot.val[i] _ spot.val[i] * txtrValue; ENDLOOP; }; 3 => FOR i: NAT IN [0..3) DO txtrValue: REAL _ SumValues[spot, txtrSum[i], txtrX, txtrY, txtrXIncr, txtrYIncr, area] / 256.0; spot.val[i] _ MAX[ 0.0, spot.val[i] * txtrValue]; ENDLOOP; ENDCASE => SIGNAL TextureMapsError[$BadTextureSize]; RETURN[spot]; }; BumpTexture: PROC[spot: ScanConvert.Spot, pixels: REF] RETURNS[ScanConvert.Spot] ~ { txtrX: NAT ~ NARROW[ Atom.GetPropFromList[spot.props, $MapVals], REF NAT ]^; txtrY: NAT ~ txtrX+1; Positivize: PROC[] ~ { WHILE spot.val[txtrX] - txtrXIncr < 0.0 DO spot.val[txtrX] _ spot.val[txtrX] + 1.0; ENDLOOP; WHILE spot.val[txtrY] - txtrYIncr < 0.0 DO spot.val[txtrY] _ spot.val[txtrY] + 1.0; ENDLOOP; }; txtrSum: REF SummedTexture _ NARROW[pixels, REF SummedTexture]; maxTxtrX: REAL _ txtrSum[0][0].length; -- width (thus max x address) of texture maxTxtrY: REAL _ txtrSum[0].length; -- height (thus max y address) of texture txtrXIncr: REAL _ MAX[ .001, ABS[spot.yIncr[txtrX]], ABS[spot.xIncr[txtrX]] ] / 2.0; txtrYIncr: REAL _ MAX[ .001, ABS[spot.yIncr[txtrY]], ABS[spot.xIncr[txtrY]] ] / 2.0; area: REAL _ 4 * txtrXIncr * maxTxtrX * txtrYIncr * maxTxtrY; nmlX: NAT ~ 4; nmlY: NAT ~ nmlX + 1; nmlZ: NAT ~ nmlX + 2; nmlXIncr: Triple _ Vector3d.Normalize[ [ spot.xIncr[nmlX], spot.xIncr[nmlY], spot.xIncr[nmlZ] ] ]; nmlYIncr: Triple _ Vector3d.Normalize[ [ spot.yIncr[nmlX], spot.yIncr[nmlY], spot.yIncr[nmlZ] ] ]; SELECT txtrSum.length FROM 1 => { txtrValue, txtrValueX, txtrValueY: REAL; Positivize[]; -- ensure positive texture coordinate values txtrValue _ SumValues[spot, txtrSum[0], txtrX, txtrY, txtrXIncr, txtrYIncr, area] / 256.0; spot.val[txtrX] _ spot.val[txtrX] + spot.xIncr[txtrX]; -- get txtr offset one pixel to right spot.val[txtrY] _ spot.val[txtrY] + spot.xIncr[txtrY]; Positivize[]; txtrValueX _ SumValues[spot, txtrSum[0], txtrX, txtrY, txtrXIncr, txtrYIncr, area] / 256.0; spot.val[txtrX] _ spot.val[txtrX] - spot.xIncr[txtrX]; -- get original texture value back spot.val[txtrY] _ spot.val[txtrY] - spot.xIncr[txtrY]; spot.val[txtrX] _ spot.val[txtrX] + spot.yIncr[txtrX]; -- get txtr offset one pixel above spot.val[txtrY] _ spot.val[txtrY] + spot.yIncr[txtrY]; Positivize[]; txtrValueY _ SumValues[spot, txtrSum[0], txtrX, txtrY, txtrXIncr, txtrYIncr, area] / 256.0; nmlXIncr _ Vector3d.Mul[ nmlXIncr, txtrValueX - txtrValue]; -- perturb in x nmlYIncr _ Vector3d.Mul[ nmlYIncr, txtrValueY - txtrValue]; -- perturb in y spot.val[nmlX] _ spot.val[nmlX] + nmlXIncr.x + nmlYIncr.x; spot.val[nmlY] _ spot.val[nmlY] + nmlXIncr.y + nmlYIncr.y; spot.val[nmlZ] _ spot.val[nmlZ] + nmlXIncr.z + nmlYIncr.z; }; ENDCASE => SIGNAL TextureMapsError[$BadTextureSize]; RETURN[spot]; }; GetLerpedValue: PROC[ llVal, ulVal, urVal, lrVal: INT, xPos, yPos: REAL ] RETURNS[ REAL ] ~ { lowerValue: REAL _ llVal + xPos * (lrVal - llVal); upperValue: REAL _ ulVal + xPos * (urVal - ulVal); RETURN [ lowerValue + yPos * (upperValue - lowerValue) ]; }; CorrectSum: PROC[txtrSum: REF ScanSequence, x, y: NAT] RETURNS[INT] ~ { maxTxtrX: NAT _ txtrSum[0].length-1; maxTxtrY: NAT _ txtrSum.length-1; IF x < txtrSum[0].length AND y < txtrSum.length THEN { RETURN[ txtrSum[y][x] ] } ELSE IF x >= txtrSum[0].length AND y >= txtrSum.length THEN { x _ x - txtrSum[0].length; y _ y - txtrSum.length; RETURN[ CorrectSum[txtrSum, x, y] + txtrSum[maxTxtrY][maxTxtrX] + CorrectSum[txtrSum, x, maxTxtrY] + CorrectSum[txtrSum, maxTxtrX, y] ]; } ELSE IF x >= txtrSum[0].length THEN { x _ x - txtrSum[0].length; RETURN[ CorrectSum[txtrSum, x, y] + txtrSum[y][maxTxtrX] ]; } ELSE { -- IF y >= txtrSum.length y _ y - txtrSum.length; RETURN[ CorrectSum[txtrSum, x, y] + txtrSum[maxTxtrY][x] ]; }; }; GetValueAt: PROC[txtrSum: REF ScanSequence, x, y: REAL] RETURNS[ REAL ] ~ { xPos, yPos: REAL; lX, lY, rX, uY: NAT; xPos _ x * txtrSum[0].length; lX _ Real.Fix[xPos]; rX _ lX + 1; yPos _ y * txtrSum.length; lY _ Real.Fix[yPos]; uY _ lY + 1; xPos _ xPos - Real.Fix[xPos]; -- get fractional part yPos _ yPos - Real.Fix[yPos]; RETURN [ GetLerpedValue[ CorrectSum[txtrSum, lX, lY], CorrectSum[txtrSum, lX, uY], CorrectSum[txtrSum, rX, uY], CorrectSum[txtrSum, rX, lY], xPos, yPos ] ]; }; SumValues: PROC[ spot: ScanConvert.Spot, txtrSum: REF ScanSequence, txtrX, txtrY: NAT, txtrXIncr, txtrYIncr, area: REAL ] RETURNS[ txtrValue: REAL ] ~ { txtrValue _ GetValueAt[ txtrSum, spot.val[txtrX] + txtrXIncr, spot.val[txtrY] + txtrYIncr ] + GetValueAt[ txtrSum, spot.val[txtrX] - txtrXIncr, spot.val[txtrY] - txtrYIncr ] - GetValueAt[ txtrSum, spot.val[txtrX] + txtrXIncr, spot.val[txtrY] - txtrYIncr ] - GetValueAt[ txtrSum, spot.val[txtrX] - txtrXIncr, spot.val[txtrY] + txtrYIncr ]; txtrValue _ txtrValue / area; }; END. ,TextureMapsImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Last Edited by: Crow, May 27, 1986 4:52:28 pm PDT Internal Declarations Procedures for Computing Texture Coordinates Stretch as indicated by corner coordinates Map from sphere to Cartesian coordinates 1st quadrant 0 - 1 range. Map polar coordinates into quadrilateral given by sw, nw, ne, se Procedures for Reading and Preparing Texture Files Create context and load texture into it Procedures for Evaluating Texture at a Spot Support Procedures for Summed Textures Κ ˜Iheadšœ™šœ Οmœ1™ ˜Všžœ"žœ$žœ˜PJšœ<˜Jšžœ#žœ+žœ˜]Jšžœ#žœ+žœ˜^šžœžœ˜šœ˜Nšœ žœU˜dNšžœžœ˜(Nš žœžœžœžœ*žœ˜INšœ˜—š œžœžœžœžœ˜Nšœ žœU˜dNšœžœ"˜3Nšžœ˜—Jšžœžœ#˜5—Jšžœ˜ J˜—š‘ œžœ!žœžœ˜TNš œžœžœ.žœžœ˜LNšœžœ ˜š‘ œžœ˜Jšžœ#žœ+žœ˜]Jšžœ#žœ+žœ˜]N˜—Nšœ žœžœ žœ˜?Jšœ žœ (˜RJšœ žœ *˜RJš œ žœžœžœžœ˜TJš œ žœžœžœžœžœ˜TJšœžœ4˜>Jšœžœžœžœ ˜@Jšœm˜mJšœn˜nšžœžœ˜šœ˜Nšœ#ž˜(Nšœ ,˜BNšœZ˜ZNšœ7 &˜]Nšœ6˜6Nšœ ˜ Nšœ[˜[Nšœ7 #˜ZNšœ6˜6Nšœ7 #˜ZNšœ6˜6Nšœ ˜ Nšœ[˜[Nšœ< ˜KNšœ< ˜KNšœ:˜:Nšœ:˜:Nšœ:˜:Nšœ˜—Jšžœžœ#˜5—Jšžœ˜ J˜——šœ&™&š‘œžœžœžœ˜JJšžœžœ˜Jšœ žœ#˜3Jšœ žœ"˜2Jšžœ3˜9J˜—š ‘ œžœ žœžœžœžœ˜HJšœ žœ˜$Jšœ žœ˜!šžœžœžœ˜7Jšžœ˜J˜—šžœžœžœžœ˜=Jšœ3˜3Jšžœ?˜EJšœM˜MJ˜—šžœžœžœ˜%Jšœ˜Jšžœ5˜;Jšœ˜—šžœ ˜+Jšœ˜Jšžœ5˜;Jšœ˜—Jšœ˜—š ‘ œžœ žœžœžœžœ˜MJšœ žœž˜'Jšœ˜Jšœ&˜&Jšœ˜Jšœ%˜%Jšœ! ˜