-- ShowAis.mesa
-- Last changed by Doug Wyatt, 14-Jul-81 14:27:59
DIRECTORY
CGAis USING [APH, Header, password, RasterPart, UCA, UCACodingType],
JaMFnsDefs USING [GetReal, PopBoolean, PopString, Register],
ColorDisplay,
Directory USING [Error, Lookup],
File USING [Capability, PageCount, PageNumber],
Inline USING [LongMult],
Real USING [RoundC],
RealFns USING [Power],
Space USING [Handle, nullHandle, WindowOrigin, wordsPerPage, virtualMemory,
Create, CreateUniformSwapUnits, Map, Activate, Unmap, Delete, LongPointer];
ShowAis: PROGRAM
IMPORTS JaMFnsDefs, ColorDisplay, Directory, Inline, Real, RealFns, Space = {
OPEN Ais: CGAis;
Color: TYPE = [0..256);
wordsPerPage: CARDINAL = Space.wordsPerPage;
bufferPages: CARDINAL = 32; -- number of pages in buffer
bufferWords: CARDINAL = bufferPages*wordsPerPage;
file: File.Capability; -- the AIS file
rasterBase: File.PageNumber; -- where the raster begins
rasterPages: File.PageCount; -- number of pages in the raster
bufferSpace: Space.Handle; -- space for the buffer
bufferAddress: LONG POINTER; -- buffer starting address
scanCount: CARDINAL; -- number of scan lines in raster
scanLength: CARDINAL; -- pixels per scan line
wordsPerLine: CARDINAL; -- words per scan line
space: Space.Handle ← Space.nullHandle;
header: LONG POINTER TO Ais.Header ← NIL;
part: LONG POINTER TO Ais.APH ← NIL;
rp: LONG POINTER TO Ais.RasterPart ← NIL;
up: LONG POINTER TO Ais.UCA ← NIL;
lines,pixels,wpl,bps: CARDINAL;
rbase,apages,rwords,rpages: CARDINAL;
RGB: TYPE = {r,g,b};
ShowFile: PROC[name: LONG STRING, color: RGB] = {
lp: LONG POINTER;
file ← Directory.Lookup[fileName: name ! Directory.Error => GOTO Punt];
-- may raise Directory.Error
space ← Space.Create[size: bufferPages, parent: Space.virtualMemory];
Space.CreateUniformSwapUnits[size: 4, parent: space];
Space.Map[space: space, window: [file: file, base: 1]];
header ← lp ← Space.LongPointer[space];
IF header.password=Ais.password THEN
part ← LOOPHOLE[header+SIZE[Ais.Header]]
ELSE ERROR; -- Wrong password
apages ← header.attributeLength/wordsPerPage;
rbase ← 1+apages;
IF part.type=raster THEN {
rp ← LOOPHOLE[part]; part ← part+part.length }
ELSE ERROR; -- Raster part missing
IF rp.samplesPerPixel=1 THEN NULL
ELSE ERROR; -- Can't handle multiple samples per pixel
IF rp.codingType=Ais.UCACodingType THEN
up ← LOOPHOLE[rp+SIZE[Ais.RasterPart]]
ELSE ERROR; -- Coding type not UCA
IF up.scanLinesPerBlock=LAST[CARDINAL] THEN NULL
ELSE ERROR; -- Can't handle blocked encoding yet
-- IF rp.scanDirection#3 THEN ERROR; // Unexpected scanDirection
lines ← rp.scanCount;
pixels ← rp.scanLength;
wpl ← up.wordsPerScanLine;
bps ← up.bitsPerSample;
rwords ← lines*wpl;
rpages ← rwords/wordsPerPage;
rasterBase ← rbase; rasterPages ← rpages;
bufferSpace ← space; bufferAddress ← lp;
scanCount ← lines; scanLength ← pixels; wordsPerLine ← wpl;
Space.Unmap[space];
Generate[color];
Space.Delete[space];
EXITS Punt => NULL
};
half: BOOLEAN ← FALSE;
Generate: PROC[color: RGB] = {
h: CARDINAL = ColorDisplay.width;
w: CARDINAL = ColorDisplay.height;
wpl: CARDINAL ← wordsPerLine;
min,max,bot,top: CARDINAL ← 0;
xmin,xmax,ymin,ymax,ybase: CARDINAL;
count: CARDINAL = scanCount; -- lines in image
remain: CARDINAL ← MIN[count,IF half THEN 2*h ELSE h]; -- lines remaining
space: Space.Handle ← bufferSpace;
buffer: LONG POINTER ← bufferAddress;
window: Space.WindowOrigin ← [file: file, base: rasterBase];
offset: [0..wordsPerPage) ← 0;
xbase: LONG POINTER;
xmin ← 0;
xmax ← MIN[scanLength,IF half THEN 2*w ELSE w];
ybase ← 0;
WHILE remain>0 DO -- map successive chunks of the image into the buffer
lines,height,page,word: CARDINAL;
canfit: CARDINAL = (bufferWords-offset)/wpl;
lines ← MIN[canfit,remain];
height ← lines;
ymin ← 0; ymax ← height;
xbase ← buffer+offset;
Space.Map[space,window];
Space.Activate[space];
IF half THEN {
FOR y: CARDINAL ← ymin, y+2 WHILE y<ymax DO
line: LONG POINTER TO ColorDisplay.ByteSeq ← xbase + Inline.LongMult[wpl,y];
yy: CARDINAL ← (h-1)-((ybase+y)/2);
FOR x: CARDINAL ← xmin, x+2 WHILE x<xmax DO
xx: CARDINAL ← x/2;
val: [0..256) ← line[x];
SELECT color FROM
r => ColorDisplay.SetRed[yy,xx,val];
g => ColorDisplay.SetGreen[yy,xx,val];
b => ColorDisplay.SetBlue[yy,xx,val];
ENDCASE;
ENDLOOP;
ENDLOOP;
}
ELSE {
FOR y: CARDINAL IN[ymin..ymax) DO
line: LONG POINTER TO ColorDisplay.ByteSeq ← xbase + Inline.LongMult[wpl,y];
yy: CARDINAL ← (h-1)-(ybase+y);
FOR x: CARDINAL IN[xmin..xmax) DO
val: [0..256) ← line[x];
SELECT color FROM
r => ColorDisplay.SetRed[yy,x,val];
g => ColorDisplay.SetGreen[yy,x,val];
b => ColorDisplay.SetBlue[yy,x,val];
ENDCASE;
ENDLOOP;
ENDLOOP;
};
Space.Unmap[space];
-- prepare for next buffer load
word ← offset+height*wpl;
page ← word/wordsPerPage;
offset ← word MOD wordsPerPage;
window.base ← window.base+page;
remain ← remain-height;
ybase ← ybase + height;
ENDLOOP;
};
gamma: REAL ← 1;
Comp: PROC[val: Color] RETURNS[Color] = {
IF gamma>1 THEN {
r: REAL ← val;
r ← r/LAST[Color];
r ← RealFns.Power[r,1.0/gamma];
r ← r*LAST[Color];
val ← Real.RoundC[r];
};
RETURN[val];
};
SetGamma: PROC = {
gamma ← JaMFnsDefs.GetReal[];
SetMaps[];
};
SetMaps: PROC = {
FOR i: Color IN Color DO
val: Color ← Comp[i];
ColorDisplay.SetRedMap[i,val];
ColorDisplay.SetGreenMap[i,val];
ColorDisplay.SetBlueMap[i,val];
ENDLOOP;
};
Neg: PROC = {
FOR i: Color IN [0..128) DO
j: Color ← 255-i;
a,b: Color;
a ← ColorDisplay.GetRedMap[i]; b ← ColorDisplay.GetRedMap[j];
ColorDisplay.SetRedMap[i,b]; ColorDisplay.SetRedMap[j,a];
a ← ColorDisplay.GetGreenMap[i]; b ← ColorDisplay.GetGreenMap[j];
ColorDisplay.SetGreenMap[i,b]; ColorDisplay.SetGreenMap[j,a];
a ← ColorDisplay.GetBlueMap[i]; b ← ColorDisplay.GetBlueMap[j];
ColorDisplay.SetBlueMap[i,b]; ColorDisplay.SetBlueMap[j,a];
ENDLOOP;
};
ShowR: PROC = {
name: STRING ← [100];
JaMFnsDefs.PopString[name];
ShowFile[name,r];
};
ShowG: PROC = {
name: STRING ← [100];
JaMFnsDefs.PopString[name];
ShowFile[name,g];
};
ShowB: PROC = {
name: STRING ← [100];
JaMFnsDefs.PopString[name];
ShowFile[name,b];
};
Wipe: PROC = {
FOR y: CARDINAL IN[0..ColorDisplay.height) DO
FOR x: CARDINAL IN[0..ColorDisplay.width) DO
ColorDisplay.SetPixel[x,y,0,0,0];
ENDLOOP;
ENDLOOP;
};
SetHalf: PROC = {
half ← JaMFnsDefs.PopBoolean[];
};
-- Initialization...
IF NOT ColorDisplay.SetMode[[full: TRUE, bitsPerPixelA: 0, bitsPerPixelB: 0]] THEN ERROR;
Wipe[];
SetMaps[];
ColorDisplay.TurnOn[];
JaMFnsDefs.Register[".showr",ShowR];
JaMFnsDefs.Register[".showg",ShowG];
JaMFnsDefs.Register[".showb",ShowB];
JaMFnsDefs.Register[".wipe",Wipe];
JaMFnsDefs.Register[".setgamma",SetGamma];
JaMFnsDefs.Register[".sethalf",SetHalf];
JaMFnsDefs.Register[".neg",Neg];
}.