DIRECTORY IODefs USING[WriteLine,WriteString,WriteDecimal,ReadDecimal,ReadChar], Storage USING[Node], InlineDefs USING[LowHalf], MiscDefs USING[Zero,SetBlock], BitBltDefs, KeyDefs, AltoDisplay, RandomCard USING[InitRandom,Choose], SystemDefs USING[Even], ProcessDefs USING[Pause,MsecToTicks]; Triblt: PROGRAM IMPORTS RandomCard,InlineDefs,MiscDefs,IODefs,ProcessDefs,Storage,BitBltDefs,SystemDefs = BEGIN OPEN InlineDefs,RandomCard,MiscDefs,AltoDisplay,IODefs,ProcessDefs, Storage,BitBltDefs,SystemDefs; debug: INTEGER _ 0; numberofscanlines: INTEGER = 400; numberofblanklines: INTEGER = 100; seed: INTEGER _ 6561; random: BOOLEAN _ FALSE; nonstop: BOOLEAN _ FALSE; output: BOOLEAN _ TRUE; i,numbtri: INTEGER; Double: TYPE = RECORD[ int : INTEGER, num : INTEGER]; Pdouble: TYPE = POINTER TO Double; Point: TYPE = RECORD[ y: INTEGER, x: Double, on: BOOLEAN _ TRUE]; Ppoint: TYPE = POINTER TO Point; top,left,right: Point; t,l,r: Ppoint; Line: TYPE = RECORD[ start: Point, end: Point]; first,second,third: Line; Slope: TYPE = RECORD[ val: Double, den: INTEGER, had: INTEGER]; Pslope: TYPE = POINTER TO Slope; leftslope,rightslope: Slope; ls: Pslope = @leftslope; rs: Pslope = @rightslope; slxv,srxv: Double; slx: Pdouble = @slxv; srx: Pdouble = @srxv; offset: RECORD[x: INTEGER _ 0 ,y: INTEGER _ 0 ]; Direction: TYPE = {up,down}; move: Direction _ down; bltptr: BBptr = AlignedBBTable[Node[SIZE[BBTable]+1]]; blank,source,mine,bottom: ARRAY [0..SIZE[DCB]] OF UNSPECIFIED; blankp,sourcep,minep,mesadisp,bottomp: AltoDisplay.DCBHandle; sourcebits: POINTER TO ARRAY[0..76) OF CARDINAL; mybits: POINTER TO ARRAY[0..38*numberofscanlines) OF CARDINAL; mousebut: POINTER TO KeyDefs.MouseBits = LOOPHOLE[177030B]; mousepos: POINTER TO AltoDisplay.Coordinate = LOOPHOLE[424B]; error: BOOLEAN; BtoC: PROCEDURE[a:BOOLEAN] RETURNS[INTEGER] = {IF a THEN RETURN[1] ELSE RETURN[-1];}; Round: PROCEDURE[p:Pdouble,q:Pslope] RETURNS[INTEGER] = BEGIN WHILE ABS[p.num] >= q.had DO SELECT p.num FROM < -q.had => BEGIN p.int_p.int-1; p.num_p.num+q.den; END; > q.had => BEGIN p.int_p.int+1; p.num_p.num-q.den; END; = q.had => BEGIN p.int_p.int+1; p.num_-q.had; RETURN[p.int];END; = -q.had => RETURN[p.int]; ENDCASE; ENDLOOP; RETURN[p.int]; END; Update: PROCEDURE[p:Pdouble,q:Pslope] RETURNS[INTEGER] = BEGIN p.int _ p.int + q.val.int; p.num _ p.num + q.val.num; RETURN[Round[p,q]]; END; HalfUpdate: PROCEDURE[p:Pdouble,q:Pslope] RETURNS[INTEGER] = BEGIN IF ABS[q.val.int] MOD 2 = 1 THEN {p.int _ p.int + q.val.int/2; p.num _ p.num +q.val.num/2; IF q.val.int > 0 THEN p.num _ p.num +q.had ELSE p.num _ p.num -q.had;} ELSE {p.int _ p.int + q.val.int/2; p.num _ p.num +q.val.num/2 ;}; RETURN[Round[p,q]]; END; HalfNUpdate: PROCEDURE[p:Pdouble,q:Pslope] RETURNS[INTEGER] = BEGIN IF ABS[q.val.int] MOD 2 = 1 THEN {p.int _ p.int - q.val.int/2; IF q.val.int > 0 THEN p.num _ p.num +q.val.num/2 -q.had ELSE p.num _ p.num +q.val.num/2 +q.had;} ELSE {p.int _ p.int - q.val.int/2; p.num _ p.num -q.val.num/2 ;}; RETURN[Round[p,q]]; END; FindSlope: PROCEDURE[p:Pslope, a,b: Ppoint] RETURNS[BOOLEAN] = BEGIN dx: INTEGER; p.den_b.y-a.y; dx _ b.x.int-a.x.int; p.val.int _ dx/p.den; IF p.den MOD 2 = 1 THEN {p.den_p.den+p.den; dx_dx+dx;}; p.val.num _ dx MOD p.den; p.had _ p.den/2; IF debug MOD 2 = 1 THEN BEGIN WriteString["slope "]; WriteDecimal[p.val.int]; WriteString[" "]; WriteDecimal[p.val.num]; WriteString["/"]; WriteDecimal[p.den]; WriteString[" half den is"]; WriteDecimal[p.had]; WriteString[" slope is "]; IF p.val.int >0 OR (p.val.int = 0 AND p.val.num >=0) THEN WriteLine["positive"] ELSE WriteLine["negative"]; END; RETURN[p.val.int>0 OR (p.val.int = 0 AND p.val.num >=0)]; END; ReadPoint: PROCEDURE[] RETURNS[p:Point] = BEGIN IF random THEN RETURN[RRpoint[]]; IF debug < 2 THEN BEGIN WriteLine["Waiting for coordinates of Vertex via mouse"]; WHILE mousebut.buttons=None DO ENDLOOP; IF mousebut.buttons=Blue THEN BEGIN ChangeParms[];RETURN[ReadPoint[]]; END; IF mousebut.buttons=Yellow THEN p.on _ FALSE; p.x.int _ mousepos.x; p.y _ mousepos.y - numberofblanklines; Pause[MsecToTicks[17]]; END ELSE BEGIN WriteLine["Specify coordinates of vertex (y,x) separated by a space"]; p.y _ ReadDecimal[]; IF p.y < 0 THEN BEGIN ChangeParms[]; RETURN[ReadPoint[]]; END; WriteString[" "]; p.x.int _ ReadDecimal[]; END; Wpoint[" VERTEX",p.y,p.x.int]; p.x.num _ 0; RETURN[p]; END; RRpoint: PROCEDURE[] RETURNS[p:Point] = BEGIN p.y _ Choose[0,numberofscanlines-1]; p.x.int_Choose[0,599]; p.x.num _ 0; Wpoint[" VERTEX",p.y,p.x.int]; RETURN[p]; END; ReadLine: PROCEDURE[] RETURNS[p:Line] = BEGIN WriteLine["Waiting for coordinates of Line via mouse"]; p.start _ ReadPoint[]; p.end _ ReadPoint[]; END; ChangeParms: PROCEDURE[] RETURNS[] = BEGIN WriteLine[" Specify which parameters you would like to change "]; SELECT ReadChar[] FROM 'd => BEGIN WriteLine["new value of debug "]; debug _ ReadDecimal[]; END; 'r => random _ NOT random; 'n => nonstop _ NOT nonstop; 'o => output _ NOT output; ENDCASE; END; Wpoint: PROCEDURE[t: STRING, x,y: INTEGER] RETURNS[] = BEGIN IF NOT output THEN RETURN[]; WriteString[t]; WriteString[" is ("]; WriteDecimal[x]; WriteString[","]; WriteDecimal[y]; WriteLine[")"]; END; ReadOffset: PROCEDURE[] RETURNS[] = BEGIN IF random THEN {offset.x _ offset.y _ 0; RETURN[]}; IF debug < 2 THEN BEGIN WriteLine[" Set two points to act as the offset "]; WHILE mousebut.buttons = None DO ENDLOOP; offset.x _ mousepos.x; offset.y _ mousepos.y; Pause[MsecToTicks[200]]; WHILE mousebut.buttons = None DO ENDLOOP; offset.x _ mousepos.x - offset.x; offset.y _ mousepos.y - offset.y; END ELSE BEGIN WriteLine["Specify coordinates of offset (y,x) separated by a space"]; offset.y _ ReadDecimal[]; WriteString[" "]; offset.x _ ReadDecimal[]; END; IF offset.y < 0 THEN move _ up ELSE move _ down; Wpoint["OFFSET",offset.y,offset.x]; END; Swap: PROCEDURE[a,b:Ppoint] RETURNS[] = {temp: Point _ a^;a^_b^;b^_temp;}; Posarea: PROCEDURE[a,b,c:Ppoint] RETURNS[BOOLEAN] = {ai,bi,ci,di: LONG INTEGER; ai_a.x.int - c.x.int; bi_b.y-c.y ; ci_b.x.int-c.x.int ; di_a.y-c.y ; RETURN[ai*bi>ci*di];}; GetInput: PROCEDURE[] RETURNS[] = BEGIN top_Inc[first]; left_Inc[second]; right_Inc[third]; t_@top; l_@left; r_@right; offset.x _ offset.y _ 0; IF move = up THEN BEGIN t.y _ -t.y; l.y _ -l.y; r.y _ -r.y; END; IF l^.y < t^.y OR (t^.y = l^.y AND t^.x.int r^.x.int) THEN Swap[t,r]; IF t^.y = l^.y THEN {Swap[r,l]; Swap[r,t];}; IF Posarea[t,l,r] THEN Swap[l,r]; IF move=down THEN bltptr.dty_t^.y + offset.y ELSE bltptr.dty_offset.y-t^.y; bltptr.slx _ slx.int _ t^.x.int; slx.num _ 0; IF t^.y = r^.y THEN srx.int _ r^.x.int ELSE srx.int _ t^.x.int; srx.num _ 0; error _ FALSE; -- Wpoint["top ",t.y,t.x.int]; -- Wpoint["left ",l.y,l.x.int]; -- Wpoint["right ",r.y,r.x.int]; END; Inc: PROCEDURE[p:Line] RETURNS[q:Point] = BEGIN a,b: LONG INTEGER; a _ p.start.x.int ; b _ p.end.x.int ; q.x.int _ LowHalf[(a*(numbtri-i) + b*(i-1))/(numbtri-1)]; a _ p.start.y ; b _ p.end.y ; q.y _ LowHalf[(a*(numbtri-i) + b*(i-1))/(numbtri-1)]; q.x.num _ 0; RETURN[q]; END; NewBlt: PROCEDURE[iter:INTEGER] RETURNS[] = BEGIN count: INTEGER; FOR count IN [1..iter] DO BEGIN bltptr.slx _ Update[slx,ls]; [] _ Update[srx,rs]; Blt[]; END; ENDLOOP; END; Blt: PROCEDURE[] RETURNS[] = BEGIN bltptr.dw _ srx.int - bltptr.slx + 1; bltptr.dlx _ bltptr.slx + offset.x; IF bltptr.dty>numberofscanlines OR bltptr.dlx+bltptr.dw >606 THEN {WriteLine[" address out of bounds"]; error _ TRUE;} ELSE BITBLT[bltptr]; IF debug MOD 2 = 1 OR error THEN {Wpoint["source start ",bltptr.sty,bltptr.slx]; WriteString[" length is "]; WriteDecimal[bltptr.dw]; WriteLine[" "]; Wpoint["destination start ",bltptr.dty,bltptr.dlx]; Wpoint["destination 1stpoint ",slx.int,slx.num]; Wpoint["destination endpoint ",srx.int,srx.num];}; bltptr.dty _ bltptr.dty + BtoC[move=down]; END; AllocateScreen: PROCEDURE[] RETURNS[] = BEGIN bltptr^_[]; bltptr.dbca _ mybits _Even[Node[38*numberofscanlines+1]]; bltptr.sbca _ sourcebits _ Even[Node[77]]; bltptr.dbmr _ bltptr.sbmr _ 38; bltptr.dh _ 1; bltptr.sty _ 1; bltptr.function _ invert; sourcep _ Even[@source]; minep _ Even[@mine]; bottomp _ Even[@bottom]; mesadisp _ DCBchainHead^; DCBchainHead^ _ blankp _ Even[@blank]; blankp^_DCB[ next: sourcep, resolution: high, background: white, indenting: 0, width: 0, bitmap: NIL, height: numberofblanklines/2]; sourcep^_DCB[ next: minep, resolution: high, background: white, indenting: 0, width: 38, bitmap: sourcebits, height: 1]; minep^_DCB[ next: bottomp, resolution: high, background: white, indenting: 0, width: 38, bitmap: mybits, height: numberofscanlines/2]; bottomp^_DCB[ next: mesadisp, resolution: high, background: white, indenting: 0, width: 38, bitmap: sourcebits, height: 1]; END; AllocateScreen[]; [] _ InitRandom[seed]; SetBlock[sourcebits,177777B,76]; DO Zero[mybits,38*numberofscanlines]; --clear screen WriteLine["How many triangles would you like"]; numbtri _ ReadDecimal[]; first _ ReadLine[]; second _ ReadLine[]; third _ ReadLine[]; FOR i IN [1..numbtri] DO BEGIN --looping part of program GetInput[]; --read input and sort points IF t.y = r.y AND t.y = l.y THEN {bltptr.slx _ MIN[r.x.int,l.x.int,t.x.int]; srx.int_MAX[r.x.int,l.x.int,t.x.int]; Blt[];} ELSE BEGIN niter: INTEGER; lspos,rspos,apos: BOOLEAN; lspos _ FindSlope[ls,t,l]; rspos _ IF t.y = r.y THEN FindSlope[rs,r,l] ELSE FindSlope[rs,t,r]; IF NOT lspos THEN bltptr.slx _ HalfUpdate [slx,ls]; IF rspos THEN [] _ HalfUpdate[srx,rs]; Blt[]; IF t.y = r.y THEN niter_l.y - t.y -2 ELSE niter _ MIN[l.y,r.y] - t.y -2; IF niter > -1 THEN {bltptr.slx_IF lspos THEN HalfUpdate[slx,ls] ELSE Update[slx,ls]; IF rspos THEN []_Update[srx,rs] ELSE [] _ HalfUpdate[srx,rs]; Blt[]; NewBlt[niter]}; IF l.y # r.y AND r.y # t.y THEN BEGIN IF l.y STOP; 'p => ChangeParms[]; ENDCASE; ENDLOOP; END. -- still to come: -- clean code in a few places -- fix attachment when endpoint is encountered making fractions add -- version of June 26,1981 12:34pm (Dobkin) -- converted to Tioga format by Stolfi - September 14, 1983 2:33 pm -- debug = 1 gives diagnostics debug =2 2 allows for keyboard input -- debug =3 does both -- long number used to gain precision -- defining points -- lines -- slopes -- endpoint and width of scan lines -- offset parameters -- bitblt and screen management definitions -- getting input -- updating scan line endpoints -- procedure for computing slopes -- reading the mouse -- creating random points -- reading lines -- swapping and area calculating routines; -- getting input and sorting points -- someday may want this ReadOffset[]; -- IF debug MOD 2 = 1 THEN -- BEGIN -- END -- output lines to bitblt -- setting up DCBs for blank top of screen, then my area, then MESA's area -- start of main program -- Find higher of left and right endpoints dividing the triangle in two parts -- and outputing the two parts ʤ˜Jšœ™Jšœ™JšœC™CJšœ+™+JšœD™DJ˜šÏk ˜ Jšœœ:˜FJšœœ˜Jšœ œ ˜Jšœ œ˜J˜ J˜J˜ Jšœ œ˜$Jšœ œ˜Jšœ œ˜%J˜—šœ˜JšœQ˜X—J˜J˜šœœ?˜JJ˜J˜—JšœC™CJšœ™Jšœœ˜Jšœœ˜!Jšœœ˜"Jšœœ˜Jšœœœ˜Jšœ œœ˜Jšœœœ˜Jšœ œ˜J˜Jšœ%™%šœœœ˜Jšœœ˜Jšœœ˜—Jšœ œœœ˜"J˜Jšœ™šœœœ˜Jšœœ˜ J˜ Jšœœœ˜—Jšœœœœ˜ J˜J˜J˜Jšœ™šœœœ˜J˜ J˜ —J˜J˜Jšœ ™ šœœœ˜J˜ Jšœœ˜ Jšœœ˜—Jšœœœœ˜ J˜J˜J˜J˜Jšœ#™#J˜J˜J˜J˜Jšœ™Jšœœœ œ˜0Jšœ œ˜J˜J˜Jšœ+™+Jšœ$œ˜6Jš œœœœœ œ˜>J˜=Jš œ œœœœœ˜0Jš œœœœœœ˜>J˜Jšœ™Jšœ œœœ ˜;Jšœ œœœ˜=J˜Jšœœ˜J˜Jš Ïnœ œœœœ˜-Jš œœœœœœ˜'J˜Jšžœ œœœ˜8Jš˜šœœ˜šœ˜Jšœ œ#œ˜8Jšœ œ#œ˜8Jšœ œœœ˜AJšœ œ˜—Jšœœ˜—Jšœ˜Jšœ˜J˜Jšœ™Jšžœ œœœ˜9š˜J˜J˜Jšœ ˜—Jšœ˜J˜Jšž œ œœœ˜=š˜šœœ œ˜šœ˜#J˜šœœ˜*Jšœ˜——Jšœ=˜A—Jšœ ˜—Jšœ˜J˜Jšž œ œœœ˜>š˜šœœ œ˜šœ ˜$šœœ"˜7Jšœ$˜(——Jšœ=˜A—Jšœ ˜—Jšœ˜J˜Jšœ!™!J˜Jšž œ œœœ˜?šœ˜Jšœœ˜ J˜J˜J˜Jšœœœ ˜7Jšœœ ˜J˜šœœœ˜šœ˜J˜J˜J˜J˜J˜J˜J˜J˜J˜šœœœ˜4Jšœœ˜6——Jšœ˜—Jšœ œœ˜9—Jšœ˜J˜Jšœ™Jšž œ œœ ˜)Jš˜Jšœœœ ˜"šœ ˜š˜J˜9Jšœœœ˜'šœœ˜Jšœœœ˜-—Jšœœœ˜-J˜J˜&J˜—Jš˜—š˜š˜J˜FJ˜Jš œ œœœœ˜?J˜J˜—Jšœ˜—J˜J˜ Jšœ˜ Jšœ˜J˜Jšœ™Jšžœ œœ ˜'Jš˜J˜$J˜J˜ J˜Jšœ˜ Jšœ˜J˜Jšœ™Jšžœ œœ ˜'Jš˜J˜7J˜J˜Jšœ˜J˜Jšž œ œœ˜$Jš˜J˜Ašœ ˜šœœ˜ J˜!J˜Jšœ˜—Jšœœ ˜Jšœœ ˜Jšœœ˜—Jšœ˜Jšœ˜J˜Jš žœ œœœœ˜7Jš˜Jšœœœœ˜J˜&J˜J˜J˜J˜Jšœ˜J˜Jšž œ œœ˜#Jš˜Jšœœœ˜3šœ ˜Jš˜—J˜3Jšœœœ˜)J˜J˜J˜Jšœœœ˜)J˜!J˜!Jš˜Jš˜Jš˜J˜FJ˜+J˜Jšœ˜Jšœœ œ ˜0J˜#Jšœ˜J˜Jšœ*™*Jšžœ œ œ˜(J˜"J˜Jšžœ œœœ˜3Jšœœœ˜J˜"J˜"Jšœ˜J˜Jšœ#™#Jšžœ œœ˜!Jš˜J˜J˜J˜J˜ J˜ J˜ J˜Jšœ&™&Jšœ œœ%œ˜@Jšœ œœœ ˜FJšœ œœœ ˜FJšœ œ˜,Jšœœ ˜!Jšœ œœ˜KJ˜-Jšœ œœ˜@J˜ Jšœœ˜Jšœ™šœ™J˜ J˜ J˜ —Jšœ™Jšœ˜J˜Jšžœ œ œ ˜*Jš˜Jšœœœ˜J˜J˜J˜9J˜J˜ J˜5J˜ Jšœ˜ Jšœ˜J˜Jšœ™Jšžœ œœœ˜+Jš˜Jšœœ˜šœœ œ˜Jš˜J˜J˜J˜Jšœ˜—Jšœ˜Jšœ˜J˜Jšžœ œœ˜š˜J˜%J˜#šœœ˜