DIRECTORY Atom USING [GetPropFromList, PutPropOnList, RemPropFromList], Real USING [LargestNumber, Float, Fix], RealFns USING [SqRt, ArcTanDeg], Rope USING [ROPE], Pixels USING [PixelBuffer, SampleSet, GetSampleSet, Create, Copy, SampleSetSequence, GetScanSeg, GetValue], ThreeDBasics USING [Context, Pair, ShapeInstance, Triple, TripleSequence, VertexInfoProc], ThreeDScenes USING [Create, DisplayFromVM, Error, GetShading, PutShading, ShadeVtx], ThreeDSurfaces USING [PtrPatchSequence], ScanConvert USING [Spot], Vector3d USING [Normalize, Mul], AISAnimation USING [GetAIS], TextureMaps USING [TextureMap, IntSequence, ScanSequence, SummedTexture]; TextureMapsImpl: CEDAR PROGRAM IMPORTS Atom, Real, RealFns, ThreeDScenes, AISAnimation, Pixels, Vector3d EXPORTS TextureMaps = BEGIN Pair: TYPE ~ ThreeDBasics.Pair; -- [ x, y: REAL]; Triple: TYPE ~ ThreeDBasics.Triple; TripleSequence: TYPE ~ ThreeDBasics.TripleSequence; 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.]; }; LoadVtxAux: PUBLIC ThreeDBasics.VertexInfoProc ~ { -- load aux field in vtx input: LIST OF REF ANY _ NARROW[ data ]; auxInfo: REF TripleSequence _ NARROW[ input.first ]; index: INTEGER _ NARROW[ input.rest.first, REF INTEGER ]^; vtx.aux _ NEW[Triple _ auxInfo[index]]; -- load with triple RETURN[ vtx ]; }; LerpVtxAux: PUBLIC ThreeDBasics.VertexInfoProc ~ { -- linear interpolation for texture coords input: LIST OF REF ANY _ NARROW[data]; vtxAux: REF Triple _ NARROW[ vtx.aux ]; vtxa: REF Triple _ NARROW[ input.first ]; vtxb: REF Triple _ NARROW[ input.rest.first ]; a: REAL _ NARROW[input.rest.rest.first, REF REAL]^; b: REAL _ NARROW[input.rest.rest.rest.first, REF REAL]^; vtxAux.x _ vtxa.x*a + vtxb.x*b; vtxAux.y _ vtxa.y*a + vtxb.y*b; RETURN[ vtx ]; }; ShadeVtx: PUBLIC ThreeDBasics.VertexInfoProc ~ { -- special shading function [ [vtx.shade.er, vtx.shade.eg, vtx.shade.eb], vtx.shade.et ] _ ThreeDScenes.ShadeVtx[ context, vtx^, 0.0 ]; RETURN[ vtx ]; }; MakeTxtrCoordsFromVtxNos: PUBLIC PROC[ shape: REF ThreeDBasics.ShapeInstance, vtcesInRow, numberOfRows: NAT, row0col0, rowNcol0, rowNcolM, row0ColM: Pair] ~ { auxInfo: REF TripleSequence _ NEW[ TripleSequence[shape.shade.length] ]; texture: REF TextureMap; args: LIST OF REAL; IF ThreeDScenes.GetShading[ shape, $VertexTextureInFile] # NIL THEN { SIGNAL ThreeDScenes.Error[[$MisMatch, "Overwriting original texture coords, OK?"]]; shape.props _ Atom.RemPropFromList[shape.props, $VertexTextureInFile]; }; 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 ThreeDScenes.Error[[$MisMatch, "Texture mapping dangerously dense"]]; FOR i: NAT IN [0..shape.shade.length) DO lPosX, lPosY, rPosX, rPosY: REAL; auxInfo.element[i].x _ Real.Float[i MOD vtcesInRow] / vtcesInRow; -- pct along row auxInfo.element[i].y _ Real.Float[i / vtcesInRow] / numberOfRows; -- pct across rows lPosX _ row0col0.x + auxInfo.element[i].y * (rowNcol0.x - row0col0.x);-- interp across rows lPosY _ row0col0.y + auxInfo.element[i].y * (rowNcol0.y - row0col0.y); rPosX _ row0ColM.x + auxInfo.element[i].y * (rowNcolM.x - row0ColM.x); rPosY _ row0ColM.y + auxInfo.element[i].y * (rowNcolM.y - row0ColM.y); auxInfo.element[i].x _ lPosX + auxInfo.element[i].x * (rPosX - lPosX); -- interp along row auxInfo.element[i].y _ lPosY + auxInfo.element[i].x * (rPosY - lPosY); auxInfo.element[i].z _ 0.0; ENDLOOP; auxInfo.length _ shape.shade.length; shape.auxInfo _ auxInfo; 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 ThreeDBasics.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] ] ~ { auxInfo: REF TripleSequence _ NEW[ TripleSequence[shape.shade.length] ]; texture: REF TextureMap; args: LIST OF REAL; poly: REF ThreeDSurfaces.PtrPatchSequence _ NARROW[shape.surface]; polyTags: ARRAY [0..8) OF BOOLEAN; IF ThreeDScenes.GetShading[ shape, $VertexTextureInFile] # NIL THEN { SIGNAL ThreeDScenes.Error[[$MisMatch, "Overwriting original texture coords, OK?"]]; shape.props _ Atom.RemPropFromList[shape.props, $VertexTextureInFile]; }; 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); auxInfo.element[vtx].x _ (longitude - lPosX) / (rPosX - lPosX); -- percentage across auxInfo.element[vtx].y _ lPosY + auxInfo.element[vtx].x * (rPosY - lPosY); -- wtd av. % auxInfo.element[vtx].x _ MIN[ 1.0, MAX[0.0, auxInfo.element[vtx].x]]; auxInfo.element[vtx].y _ MIN[ 1.0, MAX[0.0, auxInfo.element[vtx].y]]; IF hypotenuse < 0.00001 THEN polyTags[i] _ TRUE -- catch unstable arithmetic ELSE { polyTags[i] _ FALSE; IF auxInfo.element[vtx].x < minTxtrX THEN minTxtrX _ auxInfo.element[vtx].x; IF auxInfo.element[vtx].x > maxTxtrX THEN maxTxtrX _ auxInfo.element[vtx].x; }; auxInfo.element[vtx].z _ 0.0; ENDLOOP; auxInfo.length _ shape.shade.length; shape.auxInfo _ 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.element[vtx].x _ auxInfo.element[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.element[vtx].x < minTxtrX THEN minTxtrX _ auxInfo.element[vtx].x; IF auxInfo.element[vtx].x > maxTxtrX THEN maxTxtrX _ auxInfo.element[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.element[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.element[vtx].y * (topLeft.x - botLeft.x); lPosY: REAL _ botLeft.y + auxInfo.element[vtx].y * (topLeft.y - botLeft.y); rPosX: REAL _ botRight.x + auxInfo.element[vtx].y * (topRight.x - botRight.x); rPosY: REAL _ botRight.y + auxInfo.element[vtx].y * (topRight.y - botRight.y); auxInfo.element[vtx].x _ lPosX + auxInfo.element[vtx].x * (rPosX - lPosX); auxInfo.element[vtx].y _ lPosY + auxInfo.element[vtx].x * (rPosY - lPosY); IF auxInfo.element[vtx].x < minTxtrX THEN minTxtrX _ auxInfo.element[vtx].x; IF auxInfo.element[vtx].y < minTxtrY THEN minTxtrY _ auxInfo.element[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; 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 ThreeDBasics.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 $FullColor ELSE $Grey; firstBuf: NAT _ IF context.alphaBuffer THEN 1 ELSE 0; bufContext: REF ThreeDBasics.Context _ ThreeDScenes.Create[]; ThreeDScenes.DisplayFromVM[bufContext, width, height, renderMode]; bufContext.props _ context.props; -- bring along working directory, etc. [width, height] _ AISAnimation.GetAIS[ -- load pixelbuffer with AIS bits context: bufContext, fileRoot: fileName, center: FALSE]; IF width > bufContext.display.width OR height > bufContext.display.height THEN { ThreeDScenes.DisplayFromVM[bufContext, width, height, renderMode]; -- get bigger buf [width, height] _ AISAnimation.GetAIS[ -- load it up context: bufContext, fileRoot: fileName, center: FALSE]; }; SELECT bufContext.renderMode FROM $Dithered, $PseudoColor, $Grey => { pixelSizes _ Pixels.GetSampleSet[1]; pixelSizes[0] _ 8; }; $FullColor, $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], [0, 0, width, height] ]; texture.pixels _ buf; texture.type _ type; texture.props _ Atom.PutPropOnList[texture.props, $FileName, fileName]; }; SetTexture: PUBLIC PROC[shape: REF ThreeDBasics.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]; ThreeDScenes.PutShading[shape, $AuxLoad, NEW[ThreeDBasics.VertexInfoProc _ LoadVtxAux]]; ThreeDScenes.PutShading[shape, $AuxLerp, NEW[ThreeDBasics.VertexInfoProc _ LerpVtxAux]]; ThreeDScenes.PutShading[shape, $ShadeVtx, NEW[ThreeDBasics.VertexInfoProc _ ShadeVtx]]; }; SumTexture: PUBLIC PROC[shape: REF ThreeDBasics.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 ThreeDScenes.Error[[$MisMatch, "Need summed area table"]] 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 ThreeDScenes.Error[[$MisMatch, "Wrong no. of samples in texture"]]; 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 ThreeDScenes.Error[[$MisMatch, "Wrong no. of samples in texture"]]; 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 ThreeDScenes.Error[[$MisMatch, "Wrong no. of samples in texture"]]; 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, October 14, 1986 10:01:19 am PDT Internal Declarations Procedures for Auxiliary Clipping and Shading PROC[ context: REF Context, vtx: REF VertexInfo, data: REF ANY _ NIL ] RETURNS[REF VertexInfo]; PROC[ context: REF Context, vtx: REF VertexInfo, data: REF ANY _ NIL ] RETURNS[REF VertexInfo]; PROC[ context: REF Context, vtx: REF VertexInfo, data: REF ANY _ NIL ] RETURNS[REF VertexInfo]; 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™Nšžœ˜N˜—š¡ œžœ! *˜]Jšžœ žœžœžœžœžœžœžœ ™_Jš œžœžœžœžœžœ˜&Mšœžœ žœ ˜'Mšœžœ žœžœ˜)Mšœžœ žœžœ˜.Mš œžœžœžœžœ˜4Mš œžœžœžœžœ˜9Mšœ˜Mšœ˜Nšžœ˜Nšœ˜—š¡œžœ# ˜NJšžœ žœžœžœžœžœžœžœ ™_Nšœx˜xNšžœ˜N˜——šœ,™,Jš ¡œžœžœ žœGžœ˜|šœO˜OJšœ žœžœ'˜HJšœ žœ ˜Jšœžœžœžœ˜šžœ9žœžœ˜EJšžœM˜SJšœF˜FJ˜—šžœ.žœ,žœ-žœ,˜¿JšžœžœF˜Q—šžœžœžœžœ˜)Jšœž˜!Jšœ$žœ ˜RšœB ˜TJ™*—JšœF ˜[JšœG˜GJšœF˜FJšœG˜GJšœF ˜[JšœF˜FJšœ˜Jšžœ˜ —Jšœ$˜$Jšœ˜Jšœ žœ.žœ ˜NJšžœ žœžœ žœ ˜0JšœK˜KJšœžœ žœžœ˜BJšœžœžœ˜BJšœžœžœ˜CJšœžœžœ˜DJšœžœ-žœ˜[JšœA˜AJšœ5˜5Jšœ ˜ —Jš¡œžœžœ žœ˜OšœÅ˜ÅJšœ žœžœ'˜HJšœ žœ ˜Jšœžœžœžœ˜Nšœžœ#žœ˜BJšœ žœžœžœ˜"J˜šžœ9žœžœ˜EJšžœM˜SJšœF˜FJ˜—Jšžœžœžœ) ˜ZJšžœžœžœ*˜KJšžœžœžœ*˜KJšžœžœžœ+˜Kšžœ žœžœžœ˜+Jšœžœ˜.Jšœ žœ˜šžœžœžœž˜-Jš B™BJšœžœ˜'Jšœ žœŸœ3Ÿœ˜UJšœ žœŸœ(Ÿœ˜Nšœ žœŸœŸœ˜DJ™A—Jšœžœ& &˜WJšœžœ&˜1Jšœžœ#  ˜NJšœžœ ˜+JšœA ˜UJšœK  ˜WJšœžœžœ˜EJšœžœžœ˜EJšžœžœžœ ˜Ošžœ˜Jšœžœ˜Jšžœ#žœ#˜LJšžœ#žœ&˜O—Jšœ˜Jšžœ˜—Jšœ$˜$Jšœ˜Jšžœ* &˜Rš žœžœžœžœž˜2Jšœžœ˜'šžœ ˜"Jšžœ6˜:—Jšžœ˜ —Jšœ˜Jšœ˜š žœžœžœžœ ˜Lšžœž ˜Jšœžœ˜'Jšžœ#žœ#˜LJšžœ#žœ#˜LJ˜—Jšžœ˜—š žœžœžœžœ #˜QJšœžœ˜'Jšžœžœžœ5˜OJšžœ˜ —Jšœ*˜*š žœžœžœžœ "˜QJšœžœ˜'JšœžœA˜LJšœžœA˜LJšœžœC˜NJšœžœD˜OJšœK˜KJšœJ˜JJšžœ#žœ#˜LJšžœ#žœ#˜LJšžœ˜ —Jšœ*˜*Jšœ*˜*š žœžœžœžœ ˜FJšœžœ˜'Jšœ,˜,Jšœ,˜,Jšžœ˜ —Jšžœ˜ —Jšœ žœ.žœ ˜NJšžœ žœžœ žœ ˜0JšœL˜LJšœžœ žœžœ˜CJšœžœžœ˜CJšœžœ žœ˜CJšœžœ žœ˜DJšœA˜AJšœ5˜5Jšœ˜——šœ2™2š¡œžœžœ žœ&žœžœžœ žœ˜¤Jšœ'™'Mšœžœ˜Jšœžœžœ˜8Jšœ˜Mš œ žœžœžœ žœ˜?Mš œ žœžœžœžœ˜5Mšœ žœ.˜=MšœB˜BJšœ' &˜MJšœ& &œ6žœ˜‰šžœ"žœ$žœ˜PMšœB ˜UJšœ0 œ;žœ˜J˜—šžœž˜!šœ#˜#JšœA˜A—šœ˜Jšœ(˜(Jšœ4˜4Jšœ˜—Jšžœ˜—Jšœ žœ ˜Jšœ2 ˜NJšœ˜šœ- ˜IJšœ˜Jšœ˜J˜—Jšœ˜Jšœ˜JšœG˜GJšœ˜J˜—š ¡ œžœžœžœ&žœ˜[Jšœ žœžœ0˜Sšžœžœžœ žœ˜-Jšœ#˜#Jšœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ5˜5Jšœ)ž œ,˜aJšœ)ž œ,˜aJšœ*žœ*˜WJšœ˜J˜—š¡ œžœžœžœ!˜Cš ¡ œžœ"žœžœ žœžœ˜pJšžœ žœžœ žœ˜?Jšžœ žœžœ žœ˜BJ˜šžœžœžœž˜!Jšœ˜šžœžœ˜Jšœ0 ˜Bšžœžœ @˜PJšœI˜I—Jšœ˜—šžœžœžœ˜Jšœ1 ˜A—Jšžœ˜—Jšžœ ˜Jšœ˜—Nšœ˜Jšœ žœ˜'Nšœžœ˜!Nšœ žœžœ0˜PN˜Nšžœ žœžœžœ˜Nšœžœžœ˜8Nšœžœ(˜;šžœžœžœžœ˜"Nšœ=˜=šžœžœžœž˜)NšœD˜DNšžœ˜—Nšžœ˜—Jšœ˜Jšœ4˜4J˜J˜——šœ+™+š¡ œž œžœ˜LJšœ žœžœ3˜Sšžœžœž˜šœžœžœ˜6Jšžœžœ:˜EJšžœ"˜&—šœžœžœ˜6Jšžœ"˜&Jšžœ$˜(—Jšžœžœ˜—Jšžœ˜ J˜—J˜š¡ œžœ9žœ˜iš ¡œžœ žœžœžœ˜aNšœ žœ ˜/Jšžœ žœ˜,Jšœ!žœ ˜1Jšžœ žœ˜-J˜—Nšœžœ˜Nš œžœžœ.žœžœ˜LNšœžœ ˜Nšœ?˜?šžœžœ˜ šœ˜Nšœ žœ*˜9Nš žœžœžœžœ*žœ˜INšœ˜—š œžœžœžœžœ˜ NšœD˜DNšžœ˜—JšžœžœR˜d—Jšžœ˜ Jšœ˜—š¡ œžœ"žœžœ˜lJšœ žœ (˜RJšœ žœ )˜QNš œžœžœ.žœžœ˜LNšœžœ ˜Jš œ žœžœžœžœ ˜fJš œ žœžœžœžœžœ˜UJšœžœ4˜>Jšžœ#žœ+žœ˜]Jšžœ#žœ+žœ˜^šžœžœ˜šœ˜Nšœ žœU˜dNšžœžœ˜(Nš žœžœžœžœ*žœ˜INšœ˜—š œžœžœžœžœ˜Nšœ žœU˜dNšœžœ"˜3Nšžœ˜—JšžœžœR˜d—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šžœžœR˜d—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šœ! ˜