-- BuildTRCImpl.mesa
-- Mik Lamming - December 11, 1984 1:22:03 pm PST
DIRECTORY Icons, Convert, Hist, Terminal, Buttons, FS, IO, RealFns, ColorMap, MessageWindow, UserProfile, Commander, Containers, Real, Rope, Rules, TRCViewer, ViewerTools, UPOps, ViewerClasses ;
BuildTRCImpl:
CEDAR MONITOR
IMPORTS Icons, Real, Convert, Terminal, Buttons, Hist, FS, IO, ColorMap, RealFns, MessageWindow, UserProfile, Commander, Containers, Rules, TRCViewer, UPOps, Rope, ViewerTools
SHARES Terminal
= BEGIN
LogFlag: Rope.ROPE ← "Log";
LinFlag: Rope.ROPE ← "Linear";
vt: Terminal.Virtual;
DisplayState: TYPE = {bpp8, bpp24, off};
displayState: DisplayState ← off;
icon: Icons.IconFlavor ← Icons.NewIconFromFile["BuildTRC.icons", 0];
State: TYPE = REF StateRec;
StateRec:
TYPE =
RECORD [
container: ViewerClasses.Viewer,
linBut, logBut, negBut, shiftBut, rotateBut, initBut, simBut: Buttons.Button,
setHistWhite, setHistBlack, setGamma, setInputModeBut, setOutputModeBut: Buttons.Button,
showHistBut, calcHistBut, equaliseBut, histSourceBut, wdBut: Buttons.Button,
trcFileBut, saveTRCBut, getTRCBut: Buttons.Button,
inputScaleTypeIn, outputScaleTypeIn, histSourceTypeIn, wdTypeIn, trcFileTypeIn, whiteTypeIn, blackTypeIn, gammaTypeIn: ViewerClasses.Viewer,
trcViewer: ViewerClasses.Viewer,
wd: Rope.ROPE,
maxInputDens, maxOutputDens: REAL ← 99.0,
inputMode, outputMode: TRCViewer.FeedBackMode ← density,
connectMode: TRCViewer.ConnectMode ← linear,
histoOn: BOOLEAN ← FALSE,
addVertexOnShiftOrRotate: BOOLEAN ← FALSE,
histo: Hist.Histogram ← NIL,
simRed, simGrn, simBlu: BOOLEAN ← TRUE,
gamma: REAL ← 2.2
];
Simulate:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
IF displayState=off
THEN {
vt ← Terminal.Current[];
IF NOT vt.hasColorDisplay THEN displayState ← off
ELSE IF vt.colorMode.full THEN displayState𡤋pp24 ELSE displayState𡤋pp8;
UpdateColorMap[state];
Buttons.SetDisplayStyle[state.simBut, $WhiteOnBlack];
}
ELSE {
Buttons.SetDisplayStyle[state.simBut, $BlackOnWhite];
displayState ← off;
}
};
UpdateColorMap:
PROC [state:State] ~ {
SetMap:
PROC [entry:
NAT, value:
NAT] ~ {
reflectance:REAL;
IF state.outputMode=density
THEN
reflectance ← RealFns.Power[10, - ((255 - value) / 255.0) * maxDensityOut]
ELSE
reflectance ← minROut + rangeR * value / 255.0;
SELECT displayState
FROM
bpp8 => {
ColorMap.SetRGBColor[entry, reflectance, reflectance, reflectance];
};
bpp24 => {
SELECT value
FROM
IN [1..254] => {
reflectance ← RealFns.Power[reflectance, oneOverGamma];
};
ENDCASE;
value ← MAX[MIN[255, Real.RoundC[reflectance*255]], 0];
IF state.simRed THEN Terminal.SetRedMap[vt, entry, value];
IF state.simGrn THEN Terminal.SetGreenMap[vt, entry, value];
IF state.simBlu THEN Terminal.SetBlueMap[vt, entry, value];
};
ENDCASE;
};
minROut, rangeR, maxDensityOut: REAL;
err: BOOLEAN;
oneOverGamma: REAL ;
IF displayState=off THEN RETURN [];
[state.gamma, err] ← GetRealFromViewer[state.gammaTypeIn];
IF err
OR state.gamma <= 0
THEN
{
MessageWindow.Append["Gamma should be > 0", TRUE];
MessageWindow.Blink[];
RETURN [];
};
IF displayState=bpp8 THEN ColorMap.SetGamma[state.gamma]
ELSE oneOverGamma ← 1 / state.gamma;
[maxDensityOut, err] ← GetDensityFromScaleViewer[state.outputScaleTypeIn, state.outputMode];
IF ~err
THEN {
trc: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
minROut ← TRCViewer.DensToRef[maxDensityOut];
rangeR ← 1 - minROut;
FOR i:
NAT
IN [0..255]
DO
SetMap[i, trc[i].out]
ENDLOOP;
};
};
FixUpMap: TRCViewer.ChangeProc ~ {
UpdateColorMap[NARROW[clientData]]
};
StartNewInstance: Commander.CommandProc ~ {
AddButton: PROC [label: Rope.ROPE, proc: Buttons.ButtonProc, left, top: NAT, width:NAT ← 0, clientData: REF ANY ← state]
RETURNS [b: Buttons.Button, right, bottom:
NAT] ~ {
b ← Buttons.Create[
info: [
parent: state.container,
name: label,
wx: left,
wy: top,
ww:width
],
proc: proc,
clientData: clientData
];
RETURN [b, left+b.ww, top+b.wh]
};
AddTypeIn:
PROC [left, top, width, height:
NAT, init:Rope.
ROPE ←
NIL]
RETURNS [t: ViewerClasses.Viewer, right, bottom:
NAT] ~ {
t ← ViewerTools.MakeNewTextViewer[
info:[
wx:left, wy:top, ww:width, wh:height,
parent: state.container,
border: FALSE,
scrollable: FALSE,
data: init]];
RETURN [t, left+t.ww, top+t.wh]
};
pStream: IO.STREAM ← IO.RIS[cmd.commandLine];
empty:BOOLEAN ← FALSE;
p1: Rope.ROPE;
leftMargin: NAT ~ 2; row0: NAT ~ 2; colSep: NAT ~ 2; groupSep: NAT ~ 8; rowSep: NAT ~ 4;
scaleTypeInWidth: NAT ~ 85;
fileTypeInWidth: NAT ~ 160;
wdTypeInWidth: NAT ~ 260;
cardWidth: NAT ~ 40;
fileNameButTab, butHt, nextX, nextY, tempY : NAT ;
state: State ← NEW[StateRec];
p1 ←
IO.GetTokenRope[pStream,
IO.IDProc
!
IO.EndOfStream => {
empty ← TRUE;
CONTINUE;
}].token;
state.simRed ← state.simGrn ← state.simBlu ← TRUE;
IF
NOT empty
AND Rope.Length[p1]>0
THEN {
-- parameter present
SELECT
TRUE
FROM
Rope.Equal[p1, "-B", FALSE] => state.simRed ← state.simGrn ← FALSE;
Rope.Equal[p1, "-R", FALSE] => state.simBlu ← state.simGrn ← FALSE;
Rope.Equal[p1, "-G", FALSE] => state.simRed ← state.simBlu ← FALSE;
ENDCASE
};
ScanProfile[state];
state.container ← Containers.Create[info: [name:Rope.Cat["TRC Builder", p1], scrollable:FALSE, icon:icon]];
state.container.class.paintRectangles ← FALSE; -- disable viewers bug
state.container.class.bltContents ← none;
nextX ← leftMargin; nextY ← row0;
[state.linBut, nextX, tempY] ← AddButton["Linear", SetLinearMode, nextX, nextY];
Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack];
butHt ← tempY - row0;
[state.logBut, nextX, ] ← AddButton["Log", SetLogMode, nextX+colSep, nextY];
[state.negBut, nextX, ] ← AddButton["Negative", Negate, nextX+colSep, nextY];
[state.shiftBut, nextX, ] ← AddButton["Shift", Shift, nextX+colSep, nextY];
[state.rotateBut, nextX, ] ← AddButton["Rotate", Rotate, nextX+colSep, nextY];
[state.initBut, nextX, ] ← AddButton["Init", InitTRC, nextX+colSep, nextY];
[] ← Rules.Create[info:[wx:nextX+groupSep/2-1, wy:0, ww:2, wh:row0+butHt+1, parent:state.container]];
[state.simBut, nextX, ] ← AddButton["Simulate", Simulate, nextX+groupSep, nextY];
[] ← Rules.Create[info:[wx:nextX+groupSep/2-1, wy:0, ww:2, wh:row0+2*(butHt+3), parent:state.container]];
fileNameButTab ← nextX+groupSep;
[state.wdBut, nextX, ] ← AddButton["WD", SelectWD, fileNameButTab, nextY];
[state.wdTypeIn, nextX, nextY] ← AddTypeIn[fileNameButTab+40, nextY, wdTypeInWidth, butHt, state.wd];
FS.SetDefaultWDir[state.wd
!
FS.Error => {
MessageWindow.Append[IO.PutFR["Bad WD: %g is not a local directory", IO.rope[state.wd]], TRUE];
MessageWindow.Blink[];
CONTINUE}];
[] ← Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]];
nextY ← nextY + rowSep;
[state.setInputModeBut, nextX, ] ← AddButton["MaxDIn", SelectInScale, leftMargin, nextY];
[state.inputScaleTypeIn, nextX, ] ← AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[state.maxOutputDens]]];
[state.setOutputModeBut, nextX, ] ← AddButton["MaxDOut", SelectOutScale, nextX+colSep, nextY];
[state.outputScaleTypeIn, nextX, tempY] ← AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[state.maxInputDens]]];
[] ← Rules.Create[info:[wx:nextX+groupSep/2-1, wy:tempY+1, ww:1000, wh:2, parent:state.container]];
[state.trcFileBut, nextX, ] ← AddButton["TRC", SelectTRC, fileNameButTab, nextY];
[state.trcFileTypeIn, nextX, ] ← AddTypeIn[fileNameButTab+40, nextY, fileTypeInWidth, butHt];
[state.saveTRCBut, nextX, ] ← AddButton["Save", SaveTRC, nextX+colSep, nextY];
[state.getTRCBut, nextX, nextY] ← AddButton["Restore", ReadTRC, nextX+colSep, nextY];
[] ← Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]];
nextY ← nextY + rowSep;
[] ← Rules.Create[info:[wx:nextX+groupSep/2-1, wy:tempY+1, ww:2, wh:-2*(butHt+rowSep), parent:state.container]];
[state.setGamma, nextX, ] ← AddButton["Gamma", SelGamma, leftMargin, nextY];
[state.gammaTypeIn, nextX, tempY] ← AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[state.gamma]]];
[] ← Rules.Create[info:[wx:nextX+1, wy:tempY+3, ww:2, wh:-(butHt+5), parent:state.container]];
[state.setHistBlack, nextX, ] ← AddButton["Black", SelBlack, nextX+6, nextY];
[state.blackTypeIn, nextX, ] ← AddTypeIn[nextX+colSep, nextY, cardWidth, butHt, "0"];
[state.setHistWhite, nextX, ] ← AddButton["White", SelWhite, nextX, nextY];
[state.whiteTypeIn, nextX, ] ← AddTypeIn[nextX+colSep, nextY, cardWidth, butHt, "255"];
[state.histSourceBut, nextX, ] ← AddButton["Hist", SelectHist, fileNameButTab, nextY];
[state.histSourceTypeIn, nextX, ] ← AddTypeIn[fileNameButTab+40, nextY, fileTypeInWidth, butHt];
[state.showHistBut, nextX, ] ← AddButton["Off", ToggleHisto, nextX+colSep, nextY];
[state.calcHistBut, nextX, ] ← AddButton["Calc", CalcHisto, nextX+colSep, nextY];
[state.equaliseBut, nextX, nextY] ← AddButton["Eq", Equalise, nextX+colSep, nextY];
[] ← Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]];
state.trcViewer ← ViewerOps.CreateViewer[
flavor: $TRCViewer,
info: [
parent: state.container,
wx: leftMargin, wy: nextY+rowSep, ww:100, wh:100]];
Containers.ChildYBound[state.container, state.trcViewer];
Containers.ChildXBound[state.container, state.trcViewer];
TRCViewer.SetMaxDensityIn[state.trcViewer, state.maxInputDens];
TRCViewer.SetMaxDensityOut[state.trcViewer, state.maxOutputDens];
TRCViewer.RegisterChangeProc[state.trcViewer, FixUpMap, state];
};
ScanProfile:
PROC [state:State] ~ {
tempRope: Rope.ROPE;
state.wd ← UserProfile.Token["BuildTRC.WD", NIL];
IF state.wd=
NIL
THEN
state.wd ← FS.GetDefaultWDir[];
state.maxInputDens ← Convert.RealFromRope[
tempRope ← UserProfile.Token[
"BuildTRC.MaxInputDensity", "3.0"] ! Convert.Error => {
MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.MaxInputDensity: %g is not a valid real number", IO.rope[tempRope]], TRUE];
MessageWindow.Blink[];
state.maxInputDens ← 88.0;
CONTINUE;
}];
state.maxOutputDens ← Convert.RealFromRope[
tempRope ← UserProfile.Token[
"BuildTRC.MaxOutputDensity", "3.0"] ! Convert.Error => {
MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.MaxOutputDensity: %g is not a valid real number", IO.rope[tempRope]], TRUE];
MessageWindow.Blink[];
state.maxOutputDens ← 88.0;
CONTINUE;
}];
state.gamma ← Convert.RealFromRope[
tempRope ← UserProfile.Token[
"BuildTRC.Gamma", "2.2"] ! Convert.Error => {
MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.Gamma: %g is not a valid real number", IO.rope[tempRope]], TRUE];
MessageWindow.Blink[];
state.gamma ← 2.2;
CONTINUE;
}];
};
GetDensityFromScaleViewer:
PROC [
v: ViewerClasses.Viewer,
mode: TRCViewer.FeedBackMode] RETURNS [d:REAL, err:BOOLEAN ← FALSE] ~ {
r: REAL;
[r, err] ← GetRealFromViewer[v];
IF err THEN RETURN;
IF mode=density
THEN {
IF r<0
THEN {
MessageWindow.Append["Scale value should be positive", TRUE];
MessageWindow.Blink[];
err ← TRUE;
}
}
ELSE
IF r<0
OR r>1
THEN {
MessageWindow.Append["Scale value should be [0..1]", TRUE];
MessageWindow.Blink[];
err ← TRUE;
}
ELSE {
d ← TRCViewer.RefToDens[r];
};
};
GetRealFromViewer:
PROC [v: ViewerClasses.Viewer]
RETURNS [r:
REAL, err:
BOOLEAN ←
FALSE] ~ {
rope: Rope.ROPE ← ViewerTools.GetContents[v];
in:IO.STREAM ← IO.RIS[rope];
r ←
IO.GetReal[in !
IO.Error => {
MessageWindow.Append["Invalid format in real number specification", TRUE];
MessageWindow.Blink[];
err ← TRUE;
CONTINUE
};
IO.EndOfStream => {
MessageWindow.Append["Parameter absent", TRUE];
MessageWindow.Blink[];
err ← TRUE;
CONTINUE
}];
};
GetCardFromViewer:
PROC [v: ViewerClasses.Viewer]
RETURNS [r:
NAT, err:
BOOLEAN ←
FALSE] ~ {
rope: Rope.ROPE ← ViewerTools.GetContents[v];
in:IO.STREAM ← IO.RIS[rope];
r ←
IO.GetCard[in !
IO.Error => {
MessageWindow.Append["Invalid format in number specification", TRUE];
MessageWindow.Blink[];
err ← TRUE;
CONTINUE
};
IO.EndOfStream => {
MessageWindow.Append["Parameter absent", TRUE];
MessageWindow.Blink[];
err ← TRUE;
CONTINUE
}];
};
ToggleHisto:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
IF state.histo=
NIL
THEN {
MessageWindow.Append["No histogram has been calculated yet", TRUE];
MessageWindow.Blink[];
Buttons.SetDisplayStyle[state.histSourceBut, $BlackOnWhite];
RETURN [];
};
state.histoOn ← ~state.histoOn;
Buttons.SetDisplayStyle[state.histSourceBut, $WhiteOnBlack];
IF state.histoOn
THEN {
Buttons.ReLabel[state.showHistBut, "On"];
TRCViewer.SetHistogram[state.trcViewer, state.histo];
}
ELSE {
Buttons.ReLabel[state.showHistBut, "Off"];
TRCViewer.SetHistogram[state.trcViewer, NIL];
};
};
ReadTRC:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
SetOutput: TRCViewer.EnumerateProc ~ {
xIndex: NAT ← Real.RoundC[x];
IF ~trc[xIndex].pinned
THEN
trc[xIndex].out ← Real.RoundC[y];
};
state: State ← NARROW[clientData];
trc: Hist.TRCVec;
bomb: BOOLEAN ← FALSE;
pinned: ARRAY [0..255] OF BOOLEAN ← ALL[FALSE];
fileList: LIST OF Rope.ROPE;
dotIndex: INTEGER;
in:IO.STREAM;
modeRope: Rope.ROPE;
prev: NAT ← 0;
fileName: Rope.ROPE ← ViewerTools.GetContents[state.trcFileTypeIn];
IF fileName=
NIL
OR Rope.Length[fileName]=0
THEN {
MessageWindow.Append["Enter a TRC filename in TRC field please", TRUE];
MessageWindow.Blink[];
RETURN []
};
dotIndex ← Rope.Find[fileName, ".", 0, FALSE];
IF dotIndex<0
THEN
fileList ← UPOps.Expand["%g.%k|TRCExtensions|trc|", IO.rope[fileName]]
ELSE
fileList ← LIST[fileName];
IF ~SetWDir[state] THEN RETURN [];
DO {
success:BOOLEAN ← TRUE;
IF fileList =
NIL
THEN {
MessageWindow.Append["Couldn't find specified TRC input file", TRUE];
MessageWindow.Blink[];
RETURN [];
};
in
←
FS.StreamOpen[fileName: fileList.first ! FS.Error => {
success ← FALSE;
CONTINUE
}];
IF success THEN EXIT;
fileList ← fileList.rest
};
ENDLOOP;
-- read the file in
trc ← NEW[Hist.TRCVecRec];
modeRope ← in.GetID[ !
IO.Error => {
MessageWindow.Append["TRC format error - Couldn't find interpolation mode flag", TRUE];
MessageWindow.Blink[];
bomb ← TRUE;
CONTINUE;
}
];
IF bomb THEN RETURN [];
SELECT
TRUE
FROM
Rope.Equal[modeRope, LogFlag,
FALSE] => {
state.connectMode ← log;
Buttons.SetDisplayStyle[state.linBut, $BlackOnWhite];
Buttons.SetDisplayStyle[state.logBut, $WhiteOnBlack];
};
Rope.Equal[modeRope, LinFlag,
FALSE] => {
state.connectMode ← linear;
Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack];
Buttons.SetDisplayStyle[state.logBut, $BlackOnWhite];
};
ENDCASE => {
MessageWindow.Append["TRC format error - Invalid interpolation mode flag", TRUE];
MessageWindow.Blink[];
RETURN [];
};
FOR i:
CARDINAL
IN [0..255]
DO
c: CHAR;
index:CARDINAL;
prev ← index;
index ←
IO.GetCard[in !
IO.EndOfStream => {
bomb ← TRUE; CONTINUE;
};
IO.Error => {
bomb ← TRUE;
MessageWindow.Append[IO.PutFR["TRC format error following vertex %g", IO.card[prev]], TRUE];
MessageWindow.Blink[];
CONTINUE;
}];
prev ← index;
IF bomb THEN EXIT;
trc[index].out ←
IO.GetCard[in !
IO.EndOfStream => {
bomb ← TRUE;
MessageWindow.Append["TRC format error - Unexpected EOF", TRUE];
MessageWindow.Blink[];
CONTINUE;
};
IO.Error => {
bomb ← TRUE;
MessageWindow.Append[IO.PutFR["TRC format error at vertex %g", IO.card[index]], TRUE];
MessageWindow.Blink[];
CONTINUE;
}];
IF bomb THEN EXIT;
trc[index].pinned ← TRUE;
c ← in.GetChar[ !
IO.EndOfStream => {bomb ← TRUE; CONTINUE}];
IF bomb THEN EXIT;
WHILE (c #
IO.
CR)
DO
SELECT c
FROM
'* => {
pinned[index] ← TRUE;
EXIT;
};
IO.BS, IO.TAB, IO.LF, IO.FF, IO.NUL,
IO.SP, IO.DEL, IO.ESC, IO.ControlX, IO.BEL, IO.ControlA => NULL;
ENDCASE => {
bomb ← TRUE;
MessageWindow.Append[IO.PutFR["TRC format error following vertex %g '*' or CR expected", IO.card[prev]], TRUE];
MessageWindow.Blink[];
EXIT;
};
c ← in.GetChar[ !
IO.EndOfStream => {bomb ← TRUE; CONTINUE}];
IF bomb THEN EXIT;
ENDLOOP;
IF bomb THEN EXIT;
ENDLOOP;
in.Close[];
TRCViewer.Set[state.trcViewer, trc, FALSE];
TRCViewer.Enumerate[state.trcViewer, SetOutput, 0, 255];
FOR i:
NAT
IN [0..255]
DO
trc[i].pinned ← pinned[i]
ENDLOOP;
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really
TRCViewer.SetTitle[state.trcViewer, fileList.first];
};
SaveTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
PrintOutput: TRCViewer.EnumerateProc ~ {
xIndex: NAT ← Real.RoundC[x];
out.PutF["%g %g", IO.card[xIndex], IO.card[trc[xIndex].out]];
IF trc[xIndex].pinned THEN out.PutChar['*];
out.PutChar['\n];
};
state: State ← NARROW[clientData];
trc: Hist.TRCVec;
bomb: BOOLEAN ← FALSE;
fileList: LIST OF Rope.ROPE;
dotIndex: INTEGER;
out: IO.STREAM;
fileName: Rope.ROPE ← ViewerTools.GetContents[state.trcFileTypeIn];
IF fileName=
NIL
OR Rope.Length[fileName]=0
THEN {
MessageWindow.Append["Enter a TRC filename in TRC field please", TRUE];
MessageWindow.Blink[];
RETURN []
};
dotIndex ← Rope.Find[fileName, ".", 0, FALSE];
IF dotIndex<0
THEN
fileList ← UPOps.Expand["%g.%k|TRCExtensions|trc|", IO.rope[fileName]]
ELSE
fileList ← LIST[fileName];
IF ~SetWDir[state] THEN RETURN [];
out
←
FS.StreamOpen[fileName: fileList.first, accessOptions:create ! FS.Error => {
bomb ← TRUE;
CONTINUE
}];
IF bomb
THEN {
MessageWindow.Append["Could not create specified TRC file", TRUE];
MessageWindow.Blink[];
RETURN []
};
out.PutF["-- %g \n", IO.rope[fileList.first]];
SELECT state.connectMode
FROM
log => out.PutF["Log\n"];
linear => out.PutF["Linear\n"];
ENDCASE => ERROR;
trc ← TRCViewer.Get[state.trcViewer];
TRCViewer.Enumerate[state.trcViewer, PrintOutput, 0, 255];
out.Close[];
};
SetWDir:
PROC [state: State]
RETURNS [ok:
BOOLEAN ←
TRUE] ~ {
dirName: Rope.ROPE ← ViewerTools.GetContents[state.wdTypeIn];
IF dirName=
NIL
OR Rope.Length[dirName]=0
THEN {
dirName ← FS.GetDefaultWDir[];
MessageWindow.Append[IO.PutFR["Assuming working directory %g", IO.rope[dirName]], TRUE];
MessageWindow.Blink[];
RETURN []
};
FS.SetDefaultWDir[dirName !
FS.Error => {
MessageWindow.Append[IO.PutFR["Funny working directory name: %g", IO.rope[dirName]], TRUE];
MessageWindow.Blink[];
ok ← FALSE;
CONTINUE;
}];
};
CalcHisto:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
fileList: LIST OF Rope.ROPE;
dotIndex: INTEGER;
min, max:NAT;
err:BOOLEAN ← FALSE;
fileName: Rope.ROPE ← ViewerTools.GetContents[state.histSourceTypeIn];
IF fileName=
NIL
OR Rope.Length[fileName]=0
THEN {
MessageWindow.Append["Enter an AIS filename in Hist field please", TRUE];
MessageWindow.Blink[];
RETURN []
};
dotIndex ← Rope.Find[fileName, ".", 0, FALSE];
IF dotIndex<0
THEN
fileList ← UPOps.Expand["%g.%k|AISExtensions|AIS|", IO.rope[fileName]]
ELSE
fileList ← LIST[fileName];
IF ~SetWDir[state] THEN RETURN [];
[min, err] ← GetCardFromViewer[state.blackTypeIn];
IF err
OR min
NOT
IN [0..255]
THEN {
MessageWindow.Append["Invalid value for histogram black value [0..255]", TRUE];
MessageWindow.Blink[];
RETURN []
};
[max, err] ← GetCardFromViewer[state.whiteTypeIn];
IF err
OR max
NOT
IN [0..255]
THEN {
MessageWindow.Append["Invalid value for histogram white value [0..255]", TRUE];
MessageWindow.Blink[];
RETURN []
};
DO {
success:BOOLEAN ← TRUE;
IF fileList =
NIL
THEN {
MessageWindow.Append["Couldn't find specified input file", TRUE];
MessageWindow.Blink[];
state.histo ← NIL;
state.histoOn ← FALSE;
Buttons.SetDisplayStyle[state.histSourceBut, $BlackOnWhite];
Buttons.ReLabel[state.showHistBut, "Off"];
TRCViewer.SetHistogram[state.trcViewer, NIL];
RETURN [];
};
state.histo ← Hist.Calc[fileList.first, min, max ! FS.Error => {
success ← FALSE;
CONTINUE
}];
IF success THEN EXIT;
fileList ← fileList.rest
};
ENDLOOP;
Buttons.SetDisplayStyle[state.histSourceBut, $WhiteOnBlack];
state.histoOn ← TRUE;
Buttons.ReLabel[state.showHistBut, "On"];
TRCViewer.SetHistogram[state.trcViewer, state.histo];
};
Equalise:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
trc: Hist.TRCVec;
IF state.histo=
NIL
THEN {
MessageWindow.Append["No histogram has been calculated yet", TRUE];
MessageWindow.Blink[];
RETURN []
};
trc ← Hist.Equalize[state.histo];
trc[0].pinned ← trc[255].pinned ← TRUE;
TRCViewer.Set[state.trcViewer, trc];
};
SelGamma:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
ViewerTools.SetSelection[NARROW[clientData, State].gammaTypeIn];
UpdateColorMap[state];
};
SelBlack:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
ViewerTools.SetSelection[NARROW[clientData, State].blackTypeIn];
};
SelWhite:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
ViewerTools.SetSelection[NARROW[clientData, State].whiteTypeIn];
};
Shift:
ENTRY Buttons.ButtonProc = {
state: State ← NARROW[clientData];
newVertices: Hist.TRCVec ← NEW[Hist.TRCVecRec];
oldVertices: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
delta: NAT ← 1;
dir: INT ← 1;
IF shift THEN delta ← delta * 16;
IF control THEN delta ← delta * 4;
IF mouseButton=blue THEN dir ← -1;
FOR i:
NAT
IN [0..Hist.MaxPixel]
DO
p:INT ← i+(delta*dir);
SELECT
TRUE
FROM
p<0 => { newVertices[i].out ← oldVertices[0].out};
p>255 => { newVertices[i].out ← oldVertices[255].out};
ENDCASE => newVertices[i] ← oldVertices[p];
ENDLOOP;
IF state.addVertexOnShiftOrRotate
THEN
newVertices[0].pinned ← newVertices[255].pinned ← TRUE;
TRCViewer.Set[state.trcViewer, newVertices];
};
Rotate:
ENTRY Buttons.ButtonProc = {
state: State ← NARROW[clientData];
newVertices: Hist.TRCVec ← NEW[Hist.TRCVecRec];
oldVertices: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
delta: NAT ← 1;
dir: INT ← 1;
IF shift THEN delta ← delta * 16;
IF control THEN delta ← delta * 4;
IF mouseButton=blue THEN dir ← -1;
FOR i:
NAT
IN [0..Hist.MaxPixel]
DO
p:INT ← i+(delta*dir);
newVertices[i] ← oldVertices[(256+p) MOD 256];
ENDLOOP;
IF state.addVertexOnShiftOrRotate
THEN
newVertices[0].pinned ← newVertices[255].pinned ← TRUE;
TRCViewer.Set[state.trcViewer, newVertices];
};
SelectWD:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
ViewerTools.SetSelection[NARROW[clientData, State].wdTypeIn];
};
SelectTRC:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
ViewerTools.SetSelection[NARROW[clientData, State].trcFileTypeIn];
};
SelectHist:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
ViewerTools.SetSelection[NARROW[clientData, State].histSourceTypeIn];
};
SelectInScale:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
d: REAL; err: BOOLEAN;
[d, err] ← GetDensityFromScaleViewer[state.inputScaleTypeIn, state.inputMode];
IF ~err
THEN {
state.maxInputDens ← d;
TRCViewer.SetMaxDensityIn[state.trcViewer, d];
};
IF mouseButton=red
OR mouseButton=blue
THEN {
SELECT state.inputMode
FROM
density => {
state.inputMode ← reflectance;
Buttons.ReLabel[state.setInputModeBut, "MinRIn"];
ViewerTools.SetContents[state.inputScaleTypeIn, IO.PutFR["%g", IO.real[TRCViewer.DensToRef[state.maxInputDens]]]];
};
ENDCASE => {
state.inputMode ← density;
Buttons.ReLabel[state.setInputModeBut, "MaxDIn"];
ViewerTools.SetContents[state.inputScaleTypeIn, IO.PutFR["%g", IO.real[state.maxInputDens]]];
};
TRCViewer.SetFeedBackModes[state.trcViewer, state.inputMode, state.outputMode];
};
ViewerTools.SetSelection[state.inputScaleTypeIn];
};
SelectOutScale:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
d: REAL; err: BOOLEAN;
[d, err] ← GetDensityFromScaleViewer[state.outputScaleTypeIn, state.outputMode];
IF ~err
THEN {
state.maxOutputDens ← d;
TRCViewer.SetMaxDensityOut[state.trcViewer, d];
};
IF mouseButton=red
OR mouseButton=blue
THEN {
SELECT state.outputMode
FROM
density => {
state.outputMode ← reflectance;
Buttons.ReLabel[state.setOutputModeBut, "MinROut"];
ViewerTools.SetContents[state.outputScaleTypeIn, IO.PutFR["%g", IO.real[TRCViewer.DensToRef[state.maxOutputDens]]]];
};
ENDCASE => {
state.outputMode ← density;
Buttons.ReLabel[state.setOutputModeBut, "MaxDOut"];
ViewerTools.SetContents[state.outputScaleTypeIn, IO.PutFR["%g", IO.real[state.maxOutputDens]]];
};
TRCViewer.SetFeedBackModes[state.trcViewer, state.inputMode, state.outputMode];
};
ViewerTools.SetSelection[state.outputScaleTypeIn];
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really
};
SetLinearMode:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
state.connectMode ← linear;
Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack];
Buttons.SetDisplayStyle[state.logBut, $BlackOnWhite];
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode];
};
SetLogMode:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
state.connectMode ← log;
Buttons.SetDisplayStyle[state.linBut, $BlackOnWhite];
Buttons.SetDisplayStyle[state.logBut, $WhiteOnBlack];
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode];
};
InitTRC:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
SetOutput: TRCViewer.EnumerateProc ~ {
trc[Real.RoundC[x]].out ← Real.RoundC[y];
};
state: State ← NARROW[clientData];
trc: Hist.TRCVec ← NEW[Hist.TRCVecRec];
trc[0].pinned ← trc[255].pinned ← TRUE;
trc[0].out ← 0; trc[255].out ← 255;
TRCViewer.Set[state.trcViewer, trc, FALSE];
TRCViewer.Enumerate[state.trcViewer, SetOutput, 0, 255];
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really
};
Negate:
ENTRY Buttons.ButtonProc
-- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
trc: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
FOR i:
NAT
IN [0..Hist.MaxPixel]
DO
trc[i].out ← 255 - trc[i].out;
ENDLOOP;
TRCViewer.Set[state.trcViewer, trc];
};
Register:
PROC ~ {
Commander.Register[key:"BuildTRC", proc:StartNewInstance];
};
Register[];
END.