Program CopperExampleNo2; {$G+} { Enable 286 Instructions } { } { Copper Example #2 } { Programmed by David Dahl } { } { THIS EXAMPLE RUNS IN TEXT MODE } { } { This is PUBLIC DOMAIN } { } { This Example Works FLAWLESSLY On My ET4000AX Based VGA Card. } { On My Friend's Trident, However, The Three Sinus Bars Have Snow } { Covering Their Leftmost Sides For About An Inch. This Is Due } { To The Double VGA DAC Set Required To Display Both The Sinus } { Bars And The Smooth Color Transitions Of The Large Text. } Uses CRT; Const MaxRaster = 399; Status1 = $3DA; DACWrite = $3C8; DACData = $3C9; Type CopperRec = Record Color : Byte; Red : Byte; Green : Byte; Blue : Byte; End; CopperArray = Array [0..MaxRaster] of CopperRec; BarArray = Array [0..19] of CopperRec; Var CopperList : CopperArray; Bar : Array[0..2] of BarArray; BarPos : Array[0..2] of Integer; SinTab : Array[0..255] of Integer; {-[ Build Sine Lookup Table ]----------------------------------------------} Procedure MakeSinTab; Var Counter : Integer; Begin For Counter := 0 to 255 do SinTab[Counter] := 115 + Round(90 * Sin(Counter * PI / 128)); End; {-[ Build Colors For Sinus Bars ]------------------------------------------} Procedure MakeBars; Var Counter : Integer; Begin { Clear Colors } FillChar (Bar, SizeOf(Bar), 0); For Counter := 0 to 9 do Begin Bar[0][Counter].Red := Trunc(Counter * (63 / 9)); Bar[1][Counter].Green := Trunc(Counter * (63 / 9)); Bar[2][Counter].Blue := Trunc(Counter * (63 / 9)); If Odd(Counter) Then Begin Bar[0][Counter].Green := Trunc(Counter * (63 / 9)); Bar[1][Counter].Red := Trunc(Counter * (63 / 9)); Bar[1][Counter].Blue := Trunc(Counter * (63 / 9)); Bar[2][Counter].Green := Trunc(Counter * (63 / 9)); End; End; For Counter := 10 to 19 do Begin Bar[0][Counter].Red := Trunc((19-Counter) * (63 / 9)); Bar[1][Counter].Green := Trunc((19-Counter) * (63 / 9)); Bar[2][Counter].Blue := Trunc((19-Counter) * (63 / 9)); If Odd(Counter) Then Begin Bar[0][Counter].Green := Trunc((19-Counter) * (63 / 9)); Bar[1][Counter].Red := Trunc((19-Counter) * (63 / 9)); Bar[1][Counter].Blue := Trunc((19-Counter) * (63 / 9)); Bar[2][Counter].Green := Trunc((19-Counter) * (63 / 9)); End; End; End; {-[ Make COPPER List ]-----------------------------------------------------} Procedure MakeCopperList; Var Counter1 : Integer; Counter2 : Integer; Begin { Clear List } FillChar (CopperList, SizeOf(CopperList), 0); { Make Transition From White To Yellow For } { Color 1 On Scanlines 10 Through 250 } For Counter1 := 10 to 250 do With CopperList[Counter1] do Begin Color := 1; Red := 63; Green := 63; Blue := Round((250 - Counter1) * (63 / 200)); End; { Make Transition From Black To Dark Blue For } { Color 0 On Scanlines 254 Through 274 } For Counter1 := 254 to 254 + 20 do With CopperList[Counter1] do Begin Color := 0; Red := 0; Green := 0; Blue := Counter1 - 254; End; { Make Dark Blue Background (Color 0) For } { Scanlines 275 Through 287 Except Scanline } { 280 Which Is Yellow } For Counter1 := 275 to 287 do With CopperList[Counter1] do Begin Color := 0; Red := 0; Green := 0; If Counter1 = 280 Then Begin Red := 45; Green := 45; End Else Blue := 20; End; { Make Dark Blue Background (Color 0) For } { Scanlines 336 Through 394 Except Scanline } { 343 Which Is Yellow } For Counter1 := 336 to 349 do With CopperList[Counter1] do Begin Color := 0; Red := 0; Green := 0; If Counter1 = 343 Then Begin Red := 45; Green := 45; End Else Blue := 20; End; { Make Transition From Dark Blue To Black } { For Background From Scanline 350 to 370 } For Counter1 := 350 to 350 + 20 do With CopperList[Counter1] do Begin Color := 0; Red := 0; Green := 0; Blue := (350 + 20 - Counter1); End; { Color Text Lines 18, 19, and 20 For Text Color 1 } { As Red -> Yellow (L18), Purple -> White (L20) } For Counter1 := 18 to 20 do For Counter2 := 0 to 15 do With CopperList[Counter2 + (Counter1 * 16)] do Begin Color := 1; Red := 63; Green := Trunc(Counter2 * (63 / 15)); Blue := ((Counter1 - 18) * 31) AND 63; End; End; {-[ Center And Write A String As Solid Chars And Spaces ]------------------} Procedure WSol (StringIn : String); Var Counter : Integer; Begin For Counter := 1 to (40 - (Length(StringIn) DIV 2)) do Write(#32); For Counter := 1 to Length(StringIn) do If StringIn[Counter] <> #32 Then Write (#219) Else Write (#32); Writeln; End; {-[ Put Text On Screen ]---------------------------------------------------} Procedure SetUpScreen; Begin ClrScr; GotoXY (1,5); TextColor (1); WSol(' #### #### ###### ###### ######## ###### '); WSol(' ## ## ## ## ## ## ## ## ## ## ## '); WSol('## ## ## ## ## ## ## ## ## ##'); WSol('## ## ## ## ## ## ## ##### ## ##'); WSol('## ## ## ## ## ## ## ## ## ## '); WSol('## ## ## ###### ###### ## ###### '); WSol(' ## ## ## ## ## ## ## ## ## '); WSol(' #### #### ## ## ######## ## ##'); GotoXY(21, 19); Writeln('Textmode COPPER Example #2 by David Dahl'); GotoXY(27, 21); Writeln('This Program is Public Domain'); End; {-[ Update COPPER ]--------------------------------------------------------} Procedure UpdateCopper; Var Raster : Word; DrawBar : Integer; BarNum : Integer; BarCounter : Integer; Begin Raster := 1; DrawBar := -1; BarNum := 0; Inc(BarPos[0],1); Inc(BarPos[1],1); Inc(BarPos[2],1); { Sorry For All The Assembly Here, But Plain Vanilla Pascal } { Just Isn't Fast Enough To Properly Display BOTH Sinus Bars } { And The Color Transitions For The Large Text. } ASM PUSH DS MOV AX, SEG @Data MOV DS, AX CLI { Wait For End Of Vertical Retrace } MOV DX, Status1 @NotVert: IN AL, DX AND AL, 8 JNZ @NotVert @IsVert: IN AL, DX AND AL, 8 JZ @IsVert @DrawAllBarsLoop: {--- Check For Bars ---} MOV CX, 3 @BarRasterCompare: { Calculate Location of Bar (Start Line Placed In AX) } MOV BX, CX DEC BX SHL BX, 1 MOV BX, word(BarPos[BX]) AND BX, 255 SHL BX, 1 MOV AX, word(SinTab[BX]) { Check If A Bar Is On Current Raster } CMP AX, Raster JNS @BarNotDisplayed MOV BX, AX ADD AX, 20 CMP Raster, AX JNS @BarNotDisplayed { Bar Is On Raster So Mark It } SUB BX, Raster XOR AX, AX SUB AX, BX MOV word(DrawBar), AX MOV word(BarNum), CX DEC word(BarNum) @BarNotDisplayed: @DoneChecking: LOOP @BarRasterCompare {--- Draw Bars ---} MOV BX, DrawBar OR BX, BX JL @NoDrawBar { Build Index To Bar Color Table } SHL BX, 2 MOV AX, word(BarNum) MOV CX, AX SHL AX, 6 SHL CX, 4 ADD AX, CX ADD BX, AX { Set Up Next Scan Line Color } MOV DX, DACWRITE XOR AX, AX OUT DX, AL MOV DX, DACDATA INC BX MOV AL, Byte(Bar[BX]) OUT DX, AL INC BX MOV AL, Byte(Bar[BX]) OUT DX, AL { Wait For End of Horiz Retrace } MOV DX, Status1 @NotHoriz1: IN AL, DX AND AL, 1 JNZ @NotHoriz1 @IsHoriz1: IN AL, DX AND AL, 1 JZ @IsHoriz1 { Send Last Byte Of DAC Reg So Color Is Updated } MOV DX, DACDATA INC BX MOV AL, byte(Bar[BX]) OUT DX, AL { Update Color From Copper Table } MOV DX, DACWRITE MOV BX, Raster SHL BX, 2 MOV AL, Byte(CopperList[BX]) OUT DX, AL MOV DX, DACDATA INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL JMP @Done @NoDrawBar: { Update Color } MOV DX, DACWRITE MOV BX, Raster SHL BX, 2 MOV AL, Byte(CopperList[BX]) OUT DX, AL MOV DX, DACDATA INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL { Wait For End of Horiz Retrace } MOV DX, Status1 @NotHoriz2: IN AL, DX AND AL, 1 JNZ @NotHoriz2 @IsHoriz2: IN AL, DX AND AL, 1 JZ @IsHoriz2 { Update Last } MOV DX, DACDATA INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL @Done: INC Word(Raster) { If Raster <= 250 Then Loop } CMP Word(Raster), 250 JLE @DrawAllBarsLoop {--- Color Background And Text At Bottom of Screen ---} @TextColorLoop: MOV DX, DACWRITE MOV BX, Raster SHL BX, 2 MOV AL, Byte(CopperList[BX]) OUT DX, AL MOV DX, DACDATA INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL MOV DX, Status1 @NotHoriz3: IN AL, DX AND AL, 1 JNZ @NotHoriz3 @IsHoriz3: IN AL, DX AND AL, 1 JZ @IsHoriz3 MOV DX, DACDATA INC BX MOV AL, Byte(CopperList[BX]) OUT DX, AL INC Word(Raster) CMP Word(Raster), MaxRaster JLE @TextColorLoop STI POP DS END; End; {=[ Main Program ]=========================================================} Var Key : Char; Begin TextMode (C80); MakeSinTab; MakeCopperList; MakeBars; SetUpScreen; BarPos[0] := 30; BarPos[1] := 15; BarPos[2] := 0; Repeat UpdateCopper; Until Keypressed; While Keypressed do Key := ReadKey; TextMode (C80); End.