{ FD> Hey Greg, do you think you could tell me how to access FD> Mode-X, preferably the source, if it's no trouble.... :) not a problem.... Mostly I do Graphics and stuff With C, but when it all comes down to it, whether you use Pascal or C For the outer shell the main Graphics routines are in Assembler (For speed) or use direct hardware port access (again, For speed). The following is a demo of using palette scrolling techniques in Mode 13h (X) to produce a flashy "bouncing bars" effect often seen in demos: } Program PaletteTricks; { Speccy demo in mode 13h (320x200x256) } Uses Crt; Const CGA_CharSet_Seg = $0F000; { Location of BIOS CGA Character set } CGA_CharSet_ofs = $0FA6E; CharLength = 8; { Each Char is 8x8 bits, } NumChars = 256; { and there are 256 Chars } VGA_Segment = $0A000; { Start of VGA memory } NumCycles = 200; { Cycles/lines per screen } Radius = 80; DispStr : String = ' ...THIS IS A LITTLE '+ 'SCROLLY, DESIGNED to TEST SOME GROOVY PASCAL ROUTinES...'+ ' '; { Colours For moving bars... Each bar is 15 pixels thick } { Three colours are palette entries For RGB values... } Colours : Array [1..15*3] of Byte = ( 7, 7, 63, 15, 15, 63, 23, 23, 63, 31, 31, 63, 39, 39, 63, 47, 47, 63, 55, 55, 63, 63, 63, 63, 55, 55, 63, 47, 47, 63, 39, 39, 63, 31, 31, 63, 23, 23, 63, 15, 15, 63, 7, 7, 63 ); Type OneChar = Array [1..CharLength] of Byte; Var CharSet: Array [1..NumChars] of OneChar; Locs: Array [1..NumCycles] of Integer; BarLocs: Array [1..4] of Integer; { Location of each bar } CurrVert, Count: Integer; Key: Char; MemPos: Word; Procedure GetChars; { Read/copy BIOS Character set into Array } Var NumCounter, ByteCounter, MemCounter: Integer; begin MemCounter:=0; For NumCounter:=1 to NumChars do For ByteCounter:=1 to CharLength do begin CharSet[NumCounter][ByteCounter]:=Mem[CGA_CharSet_Seg:CGA_CharSet_ofs+MemCounter]; inC(MemCounter); end; end; Procedure VideoMode ( Mode : Byte ); { Set the video display mode } begin Asm MOV AH,00 MOV AL,Mode inT 10h end; end; Procedure SetColor ( Color, Red, Green, Blue : Byte ); { Update the colour palette, to define a new colour } begin Port[$3C8] := Color; { Colour number to redefine } Port[$3C9] := Red; { Red value of new colour } Port[$3C9] := Green; { Green " " " " } Port[$3C9] := Blue; { Blue " " " " } end; Procedure DispVert ( Var CurrLine : Integer ); { Display next vertical 'chunk' of the Character onscreen } Var Letter: OneChar; VertLine, Count: Integer; begin { Calculate pixel position of start of letter: } Letter := CharSet[ord(DispStr[(CurrLine div 8)+1])+1]; VertLine := (CurrLine-1) Mod 8; { Push the Character, pixel-by-pixel, to the screen: } For Count := 1 to 8 do if Letter[Count] and ($80 Shr VertLine) = 0 then Mem[VGA_Segment:185*320+(Count-1)*320+319] := 0 else Mem[VGa_Segment:185*320+(Count-1)*320+319] := 181; end; Procedure CalcLocs; { Calculate the location of the top of bars, based on sine curve } Var Count: Integer; begin For Count := 1 to NumCycles do Locs[Count] := Round(Radius*Sin((2*Pi/NumCycles)*Count))+Radius+1; end; Procedure DoCycle; { Display the bars on screen, by updating the palette entries to reflect the values from the COLOUR Array, or black For blank lines } Label Wait,Retr,BarLoop,PrevIsLast,Continue1,Continue2,Rep1,Rep2; begin Asm { First, wait For start of vertical retrace: } MOV DX,3DAh Wait: in AL,DX TEST AL,08h JZ Wait Retr: in AL,DX TEST AL,08h JNZ Retr { then do bars: } MOV BX,0 BarLoop: PUSH BX MOV AX,Word PTR BarLocs[BX] MOV BX,AX DEC BX SHL BX,1 MOV AX,Word PTR Locs[BX] PUSH AX CMP BX,0 JE PrevIsLast DEC BX DEC BX MOV AX,Word PTR Locs[BX] JMP Continue1 PrevIsLast: MOV AX,Word PTR Locs[(NumCycles-1)*2] Continue1: MOV DX,03C8h OUT DX,AL inC DX MOV CX,15*3 MOV AL,0 Rep1: OUT DX,AL LOOP Rep1 DEC DX POP AX OUT DX,AL inC DX MOV CX,15*3 xor BX,BX Rep2: MOV AL,Byte Ptr Colours[BX] OUT DX,AL inC BX LOOP Rep2 POP BX inC Word PTR BarLocs[BX] CMP Word PTR BarLocs[BX],NumCycles JNG Continue2 MOV Word PTR BarLocs[BX],1 Continue2: inC BX inC BX CMP BX,8 JNE BarLoop end; end; begin VideoMode($13); { Set video mode 320x200x256 } Port[$3C8] := 1; { Write palette table entry } For Count := 1 to 180 do { Black out the first 180 colours, } SetColor(Count,0,0,0); { one colour will be used per line } { Now colour each scan line using the given palette colour: } MemPos := 0; For Count := 1 to 180 do begin FillChar(Mem[VGA_Segment:MemPos],320,Chr(Count)); MemPos := MemPos + 320; end; SetColor(181,63,63,0); CalcLocs; For Count := 1 to 4 do BarLocs[Count] := Count*10; GetChars; CurrVert := 1; Repeat DoCycle; For Count := 1 to 8 do Move(Mem[VGA_Segment:185*320+(Count-1)*320+1], Mem[VGA_Segment:185*320+(Count-1)*320],319); DispVert(CurrVert); inC(CurrVert); if CurrVert > Length(DispStr) * 8 then CurrVert := 1; Until KeyPressed; { Repeat Until a key is pressed... } Key := ReadKey; { Absorb the key pressed } VideoMode(3); { Reset video mode back to Textmode } end. end.