// SimpleDisplayStream.bcpl // Last modified April 13, 1982 10:49 AM by Taft get "AltoDefs.d" get "Streams.d" external [ // outgoing procedures CreateSimpleDspStream; SimpleDspSetLMarg; SimpleDspSetRMarg; SimpleDspGetLinePos; SimpleDspSetLinePos SimpleDspGetBitPos; SimpleDspSetBitPos; SimpleDspResetLine SimpleDspEraseBits; SimpleDspDCB; SimpleDspCharWidth // for OEP declaration only: SimpleDspPuts; SimpleDspResets; SimpleDspCloses // incoming procedures Allocate; Free; Zero; SetBlock; DefaultArgs Puts; Resets; BitBlt; SysErr; Min; Max // incoming statics sysZone ] //--------------------------------------------------------------------------- structure SDS: // Simple Display Stream //--------------------------------------------------------------------------- [ @ST dcb @DCB bbt @BBT zone word strikeFont word xPosTable word // -> strikeFont>>Strike.xPosTable leftMargin word // in bits from left edge of bit map rightMargin word // in bits from left edge of bit map ] manifest lSDS = size SDS/16 compileif (offset SDS.dcb & 37B) ne 0 % (offset SDS.bbt & 37B) ne 0 then [ Barf("DCB or BBT not even-word aligned") ] //--------------------------------------------------------------------------- structure Strike: // Strike (old-format) font //--------------------------------------------------------------------------- [ oneBit bit // =1 to mean new style font index bit fixed bit blank bit 13 min word // Lowest char code max word // Highest char code maxWidth word // Maximum width // The rest is called the "strike body", and includes overhead, bitmap, and xPosTable. length word // Number of words in strike body ascent word // above baseline descent word // below baseline xOffset word // for kerning (not implemented, always zero) raster word // # words per scan line bitmap word 0 // bit map begins here: raster*height words // xPosTable ↑min,max word // x-coordinates of the characters in the bit map ] // Public procedures //--------------------------------------------------------------------------- let CreateSimpleDspStream(bitmap, width, height, strikeFont, zone; numargs na) = valof //--------------------------------------------------------------------------- // bitmap is the bit map starting address and must be even. // width is in words and must be even. // height is in scan lines and must be even. // strikeFont must be a pointer to a .strike (non-kerned) font. // Client is responsible for linking DCB into the display list as desired. [ DefaultArgs(lv na, -4, sysZone) let sds = Allocate(zone, lSDS, false, true) // even-word aligned Zero(sds, lSDS) SetBlock(sds, SysErr, lST) sds>>SDS.puts = SimpleDspPuts sds>>SDS.reset = SimpleDspResets sds>>SDS.close = SimpleDspCloses sds>>SDS.dcb.bitmap = bitmap sds>>SDS.dcb.width = width sds>>SDS.dcb.height = height rshift 1 sds>>SDS.bbt.dbca = bitmap sds>>SDS.bbt.dbmr = width sds>>SDS.rightMargin = width lshift 4 sds>>SDS.bbt.dh = strikeFont>>Strike.ascent + strikeFont>>Strike.descent sds>>SDS.bbt.sbca = lv strikeFont>>Strike.bitmap sds>>SDS.bbt.sbmr = strikeFont>>Strike.raster sds>>SDS.zone = zone sds>>SDS.strikeFont = strikeFont sds>>SDS.xPosTable = lv strikeFont>>Strike.bitmap + (strikeFont>>Strike.raster * sds>>SDS.bbt.dh) Resets(sds) resultis sds ] // Setting margins: // Moving margins in from the edges of the bit map causes the regions outside // the margins not to be touched by any subsequent operation besides Resets. // This means that the client has complete freedom in defining the contents // of these regions. //--------------------------------------------------------------------------- and SimpleDspSetLMarg(sds, margin) be sds>>SDS.leftMargin = margin //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- and SimpleDspSetRMarg(sds, margin) be sds>>SDS.rightMargin = margin //--------------------------------------------------------------------------- // Text line operations: // The topmost text line is numbered zero. No bounds checks are done. //--------------------------------------------------------------------------- and SimpleDspGetLinePos(sds) = sds>>SDS.bbt.dty / sds>>SDS.bbt.dh //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- and SimpleDspSetLinePos(sds, line) be //--------------------------------------------------------------------------- // Positions to the left margin of the specified line. // Does not actually modify the line. [ sds>>SDS.bbt.dty = line * sds>>SDS.bbt.dh sds>>SDS.bbt.dlx = sds>>SDS.leftMargin ] // Public procedures (cont'd) // Bit positions are relative to the left edge of the bit map, not relative // to the left margin. No bounds checks are done. //--------------------------------------------------------------------------- and SimpleDspGetBitPos(sds) = sds>>SDS.bbt.dlx //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- and SimpleDspSetBitPos(sds, pos) be sds>>SDS.bbt.dlx = pos //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- and SimpleDspResetLine(sds) be //--------------------------------------------------------------------------- // Erases the current line, and leaves the stream positioned at the left margin. [ sds>>SDS.bbt.dlx = sds>>SDS.rightMargin SimpleDspEraseBits(sds, sds>>SDS.leftMargin - sds>>SDS.rightMargin) ] //--------------------------------------------------------------------------- and SimpleDspEraseBits(sds, nBits, flag; numargs na) be //--------------------------------------------------------------------------- // Erases nBits relative to the current position (positive => right, negative => left) // and adjusts the current position by nBits. No bounds checks are done. // Flag=0 or omitted sets the erased region to zero; flag=1 sets it to all ones; // flag=-1 complements the region. [ if na ls 3 then flag = 0 let newPos = sds>>SDS.bbt.dlx + nBits sds>>SDS.bbt.dlx = Min(sds>>SDS.bbt.dlx, newPos) sds>>SDS.bbt.dw = Max(nBits, -nBits) sds>>SDS.bbt.function = flag ls 0? 16B, 14B // invert, replace SetBlock(lv sds>>SDS.bbt.gray, flag ne 0, 4) BitBlt(lv sds>>SDS.bbt) Zero(lv sds>>SDS.bbt.gray, 4) sds>>SDS.bbt.dlx = newPos ] // Miscellaneous: //--------------------------------------------------------------------------- and SimpleDspDCB(sds) = lv sds>>SDS.dcb //--------------------------------------------------------------------------- // Returns the address of the DCB, which the caller may fiddle with. //--------------------------------------------------------------------------- and SimpleDspCharWidth(sds, char) = valof //--------------------------------------------------------------------------- // Returns the width of the character in the font associated with sds. [ let strikeFont = sds>>SDS.strikeFont let xIndex = char - strikeFont>>Strike.min [ // repeat if xIndex ls 0 % char gr strikeFont>>Strike.max then xIndex = strikeFont>>Strike.max-strikeFont>>Strike.min+1 let width = (sds>>SDS.xPosTable)!(xIndex+1) - (sds>>SDS.xPosTable)!xIndex if width ne 0 then resultis width xIndex = -1 ] repeat ] // Stream object operations //--------------------------------------------------------------------------- and SimpleDspPuts(sds, char) be //--------------------------------------------------------------------------- [ let strikeFont = sds>>SDS.strikeFont switchon char into [ case $*n: [ let newY = sds>>SDS.bbt.dty + sds>>SDS.bbt.dh test (newY + sds>>SDS.bbt.dh) gr (sds>>SDS.dcb.height lshift 1) ifso ScrollUp(sds) ifnot sds>>SDS.bbt.dty = newY SimpleDspResetLine(sds) endcase ] default: [ let xIndex = char - strikeFont>>Strike.min if xIndex ls 0 % char gr strikeFont>>Strike.max then xIndex = strikeFont>>Strike.max-strikeFont>>Strike.min+1 let xOffset = (sds>>SDS.xPosTable)!xIndex let width = (sds>>SDS.xPosTable)!(xIndex+1) - xOffset if width eq 0 then [ char = strikeFont>>Strike.max+1; docase char ] if (sds>>SDS.bbt.dlx + width) gr sds>>SDS.rightMargin then [ Puts(sds, $*n); docase char ] sds>>SDS.bbt.dw = width sds>>SDS.bbt.slx = xOffset sds>>SDS.bbt.function = 1 // paint, from source block BitBlt(lv sds>>SDS.bbt) sds>>SDS.bbt.dlx = sds>>SDS.bbt.dlx + width endcase ] ] ] //--------------------------------------------------------------------------- and SimpleDspResets(sds) be //--------------------------------------------------------------------------- [ Zero(sds>>SDS.dcb.bitmap, sds>>SDS.dcb.width*sds>>SDS.dcb.height*2) sds>>SDS.bbt.dlx = sds>>SDS.leftMargin sds>>SDS.bbt.dty = 0 ] //--------------------------------------------------------------------------- and SimpleDspCloses(sds, char) be //--------------------------------------------------------------------------- // Removes DCB from the display list (if present) and destroys stream. [ let dcb = @displayListHead [ // repeat if dcb eq 0 then break if dcb>>DCB.next eq lv sds>>SDS.dcb then [ dcb>>DCB.next = sds>>SDS.dcb.next; break ] dcb = dcb>>DCB.next ] repeat Free(sds>>SDS.zone, sds) ] // Internal procedures //--------------------------------------------------------------------------- and ScrollUp(sds) be //--------------------------------------------------------------------------- [ let bbt = vec lBBT; bbt = (bbt+1) & -2 Zero(bbt, lBBT) bbt>>BBT.dbca = sds>>SDS.bbt.dbca bbt>>BBT.dbmr = sds>>SDS.bbt.dbmr bbt>>BBT.dlx = sds>>SDS.leftMargin bbt>>BBT.dw = sds>>SDS.rightMargin - sds>>SDS.leftMargin bbt>>BBT.dh = (sds>>SDS.dcb.height lshift 1) - sds>>SDS.bbt.dh bbt>>BBT.sbca = sds>>SDS.bbt.dbca bbt>>BBT.sbmr = sds>>SDS.bbt.dbmr bbt>>BBT.slx = sds>>SDS.leftMargin bbt>>BBT.sty = sds>>SDS.bbt.dh // bbt>>BBT.function = 0 // replace, from source block BitBlt(bbt) ]