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