; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; > $.Source.VduGrafA ; ; ARTHUR OPERATING SYSTEM - Vdu Drivers ; ======================= ; ; Vdu driver code - Graphics rectangle, triangle ; ; Author R C Manby ; Date 5.9.86 ; ; ***************************************************************************** ; ; GenLineParm - Generate a control block for a line ; ; Internal routine, called by TriangleFill, LowerTri, ParallelogramFill, ; SegmentLineO5, GenArcParmBlk, GenSegParmBlk, LineDraw ; ; in: R0 (X), R1(Y) hold start of line ; R2 (X), R3(Y) hold end of line ; ; out: R0..R6 hold the following control block ; R0 - StartX ; R1 - StartY ; R2 - Bres ; R3 - DeltaX ; R4 - DeltaY ; R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version) ; R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version) ; R7 - EndX ; R8 - EndY ; GenLineParm ROUT MOV R7, R2 ; EndX,EndY - might be worth passing them MOV R8, R3 ; in R7,R8 not R2,R3 SUB R3, R7, R0 ; Crude deltaX SUB R4, R8, R1 ; Crude deltaY CMP R4, R3 MOVLT R2, #0 ; if deltaY >= deltaX R2 := -1 MOVGE R2, #-1 ; else R2 := 0 ; this is used to fudge the bres ; variable so lines of grad -1 are ; the same as lines of grad 1 MOVS R5, R3, ASR #31 ; R5 := SGN(DeltaX) MOVPL R5, #1 RSBMI R3, R3, #0 ; DeltaX := ABS(DeltaX) MOVS R6, R4, ASR #31 ; R6 := SGN(DeltaY) MOVPL R6, #1 RSBMI R4, R4, #0 ; DeltaY := ABS(DeltaY) CMP R4, R3 ; Bres = MAX(DeltaX,DeltaY) + fudge factor ADDPL R2, R4, R2 ADDMI R2, R3, R2 RSB R2, R4, R2, ASR #1 ; Bres = Bres/2 - DeltaY MOV PC, R14 ; Return ; ***************************************************************************** ; ; AdvLineParm - Advance a set of line parameters ; ; Internal routine, called by TrapFill, SegLineStep, ArcLineStep, ; LineDraw, InYWind, InXWind ; ; in: R0..R6, (R7,R8) hold a line parameter block ; ; out: R0 (X), R1 (Y) R2 (Bres) updated ; ; Format of a control block ; R0 - StartX (CurrentX) ; R1 - StartY (CurrentY) ; R2 - Bres ; R3 - DeltaX ; R4 - DeltaY ; R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version) ; R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version) ; R7 - EndX (Not used in this routine, so) ; R8 - EndY (doesnt need to be passed in) ; AdvLineParm ROUT CMP R2, #0 ; If Bres +ve, advance in X dirn only ADDLT R1, R1, R6 ; Advance in Y dirn ADDLTS R2, R2, R3 ; Add DeltaX to Bres ; If new Bres +ve advance X as well ; Advance X SUBGE R2, R2, R4 ; Sub DeltaY from Bres to advance in X dirn ADDGE R0, R0, R5 ; Add or subtract 1 dependent on sign DeltaX MOV PC, R14 ; ***************************************************************************** ; ; AdvLineParm_GE - Macro to advance line in XDirn if flags are GE ; ; Used by Triangles,Parallelograms,Arcs etc ; ; Use: CMP R2,#0 ; AdvLineParm_GE ; ; Instead of: CMP R2,#0 ; BLGE AdvLineParm ; MACRO AdvLineParm_GE SUBGE R2, R2, R4 ADDGE R0, R0, R5 MEND ; ***************************************************************************** ; ; RectangleFill - Fill a rectangle ; ; External routine, and RectFillA entry point used by BlockCopyMove, CLG ; and RectFillB entry point used by PlotMask ; ; in: ICursor & NewPt mark a diagonal of the rectangle ; ; out: R0-R11 corrupt ; ; RectangleFill ROUT ADD R11,WsPtr,#GCsIX ; load ICursor & NewPt LDMIA R11, {R0-R3} RectFillA Push R14 RectFillB SortT R0, R2, R11 ; ensure R0 holds the lesser X value SortT R3, R1, R11 ; ensure R1 holds the higher Y value BL CheckAcceleration BNE RectFillC ; try calling GraphicsV for some acceleration ; R0 = left, R1 = top, R2 = right, R3 = bottom ADD R4, WsPtr, #GWLCol LDMIA R4, {R4-R7} ; GWLCol,GWBRow,GWRCol,GWTRow CMP R6, R0 ; Test xcoords against window CMPGE R2, R4 CMPGE R7, R3 ; Test ycoords against window CMPGE R1, R5 MOVLT PC, R14 ; Quit if above,below,left or right Greatest R0, R0, R4 ; Clip all coords to window Greatest R3, R3, R5 Least R2, R2, R6 Least R1, R1, R7 LDR R4, [WsPtr, #GColAdr] Push "R0-R4" MOV R0, #GVRender_Sync MOV R1, #GVRender_FillRectangle MOV R2, R13 LDR R4, [WsPtr, #CurrentGraphicsVDriver] MOV R4, R4, LSL #24 ORR R4, R4, #GraphicsV_Render BL CallGraphicsV TEQ R4, #GraphicsV_Complete Pull "R0-R4" Pull PC, EQ ; if it didn't claim, we proceed with the pre-clipped coordinates RectFillC MOV R11, R3 ; place end Y out of harm's way 10 BL NewHLine SUB R1, R1, #1 ; step Y down a line CMP R1, R11 BGE %BT10 Pull PC ; ***************************************************************************** ; ; TriangleFill - Triangular area fill ; ; External routine ; ; in: OldCs, ICursor & NewPt are verticies of the triangle ; ; out: R0-R11 corrupt ; TriangleFill ROUT Push R14 ADD R11, WsPtr, #OldCsX ; vertices are OldCs,ICursor LDMIA R11, {R0-R5} ; and NewPt BL LowerTri ; sort vertices and fill the ; lower triangle ADD R11, WsPtr, #Vertex2X ; restart TLine1 to run from LDMIA R11, {R0-R3} ; Vertex2 to Vertex3 ADD R11, WsPtr, #TLine1 TriangleFil5 ; entry point from par fill BL GenLineParm STMIA R11, {R0-R8} ; initialise parameter block STR R8, [WsPtr, #TEndY] ; end Y point for both lines BL TrapFill ; fill the upper trapezoid MOV R0, R9 ; fill top line LeftX,RightX MOV R2, R10 ; leftY already in R1 BL NewHLine Pull PC ; ***************************************************************************** ; ; LowerTri - Sort 3 vertices and fill the lower triangle between the ; points up to but excluding the horizontal through the middle point ; ; Internal routine, called by TriangleFill and ParallelogramFill ; LowerTri ROUT Push R14 CompSwapT R0,R1, R2,R3, R14 ; bubble highest vertex into R4,R5 CompSwapT R2,R3 ,R4,R5, R14 CompSwapT R0,R1, R2,R3, R14 ; place lowest in R0,R1 and middle in R2,R3 ADD R11, WsPtr, #Vertex1X STMIA R11, {R0-R7} ; save all our vertices MOV R9, R0 ; initalise TLeftX,TRightX MOV R10, R0 ; to lowest point BL GenLineParm ; Run TLine1 from lowest to ADD R11, WsPtr, #TLine1 ; middle point STMIA R11, {R0-R8} STR R8, [WsPtr, #TEndY] ; this line ends first ADD R2, WsPtr, #Vertex3X ; run TLine2 from lowest to LDMIA R2, {R2, R3} ; highest point BL GenLineParm ADD R11, WsPtr, #TLine2 STMIA R11, {R0-R8} BL TrapFill ; fill the lower trapezoid Pull PC ; ***************************************************************************** ; ; ParallelogramFill - Fill a parallelogram ; ; External routine ; ; in: OldCs, ICursor & NewPt are 3 vertices of the parallelogram ; ; out: R0-R11 corrupt ; ParallelogramFill ROUT Push R14 ADD R11, WsPtr, #OldCsX ; vertices are OldCs,ICursor LDMIA R11, {R0-R5} ; and NewPt ; now calculate Vertex4 from other three ADD R6, R0, R4 ; Vertex4X := Vertex1X + Vertex3X - Vertex2X SUB R6, R6, R2 ADD R7, R1, R5 ; Vertex4Y := Vertex1Y + Vertex3Y - Vertex2Y SUB R7, R7, R3 CompSwapT R0,R1, R2,R3, R14 ; Bubble the highest point into R6,R7 CompSwapT R2,R3 ,R4,R5, R14 CompSwapT R4,R5 ,R6,R7, R14 BL LowerTri ; sort other vertices and draw lower triangle ADD R11, WsPtr, #Vertex2X ; restart TLine1 to run from LDMIA R11!, {R0-R3} ; Vertex2 to Vertex4 STR R3, [WsPtr, #TEndY] ; and indicate line Vertex1 to LDMIA R11, {R2,R3} ; Vertex3 as the next to finish BL GenLineParm ADD R11, WsPtr, #TLine1 STMIA R11, {R0-R8} ; TLine1 parameter block BL TrapFill ; fill the middle trapezoid ADD R11, WsPtr, #Vertex3X ; restart TLine2 to run from LDMIA R11, {R0-R3} ; Vertex3 to Vertex4 ADD R11, WsPtr, #TLine2 B TriangleFil5 ; Use common code with ; triangles to initialise and ; fill upper trapezoid ; ***************************************************************************** ; ; TrapFill - Fill a trapezoid ; ; Internal routine, called by TriangleFill, LowerTri, ParallelogramFill ; ; in: R9 = TLeftX } the line limits for this scanline ; R10 = TRightX } ; ; out: R9,R10 updated ; TrapFill ROUT Push R14 10 ADD R11, WsPtr, #TLine1 ; Advance TLine1 until currentY about BL TrapLineStep ; to change, or end of line reached ADD R11, WsPtr, #TLine2 ; ditto TLine2 BL TrapLineStep LDR R11, [WsPtr, #TEndY] CMP R11, R1 ; if CurrentY = EndY Pull PC, EQ ; then quit MOV R0, R9 ; LeftX MOV R2, R10 ; RightX ; LeftY already in R1 BL NewHLine ; Plot current scanline ADD R11, WsPtr, #TLine1 ; advance TLine1 to next scanline LDMIA R11, {R0-R6} BL AdvLineParm STMIA R11, {R0-R2} ; save the changes MOV R9, R0 ; assume currentX will be LeftX ADD R11, WsPtr, #TLine2 ; advance TLine2 to next scanline LDMIA R11, {R0-R6} BL AdvLineParm STMIA R11, {R0-R2} ; save the changes CMP R0, R9 ; LeftX=Min(CurrentX,CurrentY) MOVGE R10, R0 ; RightX=Max(CurrentX,CurrentY) MOVLT R10, R9 MOVLT R9, R0 B %BT10 ; continue with next scanline ; ***************************************************************************** ; ; TrapLineStep - Step line parameters until CurrentY about to change ; or end of line reached - compares CurrentX with line limits ; (LeftX,RightX) and widens them if needed ; ; Internal routine, called by TrapFill ; ; in: R9 = LeftX ; R10 = RightX ; R11 = address of parameter block ; ; out: R0-R8 parameter block for this line ; R9, R10 updated ; R11 preserved ; TrapLineStep ROUT Push R14 LDMIA R11, {R0-R8} ; get line parameter block CMP R8, R1 ; if on last scanline MOVEQ R0, R7 ; then set currentX to EndX BEQ TrapLin20 ; (bres unchanged, but who cares) CMP R2, #0 ; else While bres >= 0 do AdvLineParm TrapLin10 ; {step until Y about to change} ADDGE R0, R0, R5 SUBGES R2, R2, R4 BGE TrapLin10 TrapLin20 STMIA R11, {R0-R2} ; update the changes to parameter block CMP R0, R9 ; LeftX=Min(LeftX,CurrentX) MOVLT R9, R0 CMP R0, R10 MOVGT R10, R0 ; RightX=Max(RightX,CurrentX) Pull PC END