-- 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]; }.